@zitadel/cli 0.1.0-alpha.13 → 0.1.0-alpha.15
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 +137 -57
- package/SKILLS.md +26 -13
- package/dist/commands/apply.mjs +11 -6
- package/dist/commands/apply.mjs.map +1 -1
- package/dist/commands/doctor.mjs +89 -12
- package/dist/commands/doctor.mjs.map +1 -1
- package/dist/commands/eject.mjs +4 -4
- package/dist/commands/logs.mjs +2 -2
- package/dist/commands/plan.mjs +6 -4
- package/dist/commands/plan.mjs.map +1 -1
- package/dist/commands/reset.mjs +2 -2
- package/dist/commands/schemas/list.mjs +134 -0
- package/dist/commands/schemas/list.mjs.map +1 -0
- package/dist/commands/setup.mjs +158 -23
- package/dist/commands/setup.mjs.map +1 -1
- package/dist/commands/start.mjs +4 -4
- package/dist/commands/status.mjs +3 -3
- package/dist/commands/stop.mjs +3 -3
- package/dist/{docker-Djz6BLp9.mjs → docker-D7BSD5C9.mjs} +3 -3
- package/dist/{docker-Djz6BLp9.mjs.map → docker-D7BSD5C9.mjs.map} +1 -1
- package/dist/{docker-guidance-D-33g1uV.mjs → docker-guidance-mcTT3_0E.mjs} +2 -2
- package/dist/{docker-guidance-D-33g1uV.mjs.map → docker-guidance-mcTT3_0E.mjs.map} +1 -1
- package/dist/environment-BQF7LeCz.mjs +17 -0
- package/dist/environment-BQF7LeCz.mjs.map +1 -0
- package/dist/{oclif-BoUVygsZ.mjs → oclif-Bm-FkF6z.mjs} +66 -13
- package/dist/oclif-Bm-FkF6z.mjs.map +1 -0
- package/dist/{orca-DU8myWGm.mjs → orca-CpXj_XsA.mjs} +46 -94
- package/dist/orca-CpXj_XsA.mjs.map +1 -0
- package/dist/{ports-B09RjuHx.mjs → ports-CxBKS1ga.mjs} +1 -1
- package/dist/{ports-B09RjuHx.mjs.map → ports-CxBKS1ga.mjs.map} +1 -1
- package/dist/{processes-Cw8TO1SY.mjs → processes-BVqYsxT8.mjs} +1 -1
- package/dist/{processes-Cw8TO1SY.mjs.map → processes-BVqYsxT8.mjs.map} +1 -1
- package/dist/{project-B1qVQMKS.mjs → project-Dk7V0xka.mjs} +3 -3
- package/dist/{project-B1qVQMKS.mjs.map → project-Dk7V0xka.mjs.map} +1 -1
- package/dist/{sync-B8Z2it_E.mjs → sync-CYuHVQT5.mjs} +344 -116
- package/dist/sync-CYuHVQT5.mjs.map +1 -0
- package/dist/user-schema-DDz5-lX5.mjs +13 -0
- package/dist/user-schema-DDz5-lX5.mjs.map +1 -0
- package/oclif.manifest.json +106 -1
- package/package.json +6 -5
- package/dist/oclif-BoUVygsZ.mjs.map +0 -1
- package/dist/orca-DU8myWGm.mjs.map +0 -1
- package/dist/sync-B8Z2it_E.mjs.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sync-CYuHVQT5.mjs","names":[],"sources":["../src/lib/flows/env-refs.ts","../src/lib/flows/index.ts","../src/lib/sync/syncers.ts","../src/lib/sync/state.ts","../src/lib/sync/loop.ts","../src/lib/sync/plan-renderer.ts"],"sourcesContent":["import { isObject } from \"../json\";\n\n/**\n * Collects the environment variables a flows document depends on, sorted and\n * de-duplicated. Recognises two reference styles: inline `${VAR}` interpolations\n * inside string values, and keys ending in `_env` whose value names a single\n * variable. `apply`/`plan` use this to fail before contacting the platform when\n * a required variable is absent.\n */\nexport function flowEnvRefs(value: unknown): string[] {\n const refs = new Set<string>();\n const visit = (node: unknown): void => {\n if (typeof node === \"string\") {\n for (const match of node.matchAll(/\\$\\{([A-Za-z_][A-Za-z0-9_]*)\\}/g)) {\n const ref = match[1];\n if (ref) {\n refs.add(ref);\n }\n }\n } else if (Array.isArray(node)) {\n node.forEach(visit);\n } else if (isObject(node)) {\n for (const [key, child] of Object.entries(node)) {\n if (key.endsWith(\"_env\") && typeof child === \"string\" && /^[A-Za-z_][A-Za-z0-9_]*$/.test(child)) {\n refs.add(child);\n } else {\n visit(child);\n }\n }\n }\n };\n visit(value);\n return [...refs].sort();\n}\n","/**\n * Public surface for the flow domain. Every caller outside this module\n * imports from here (not from individual files) so the package\n * boundary stays observable.\n *\n * **Source of truth.** The wire shape lives in\n * `@zitadel/api/generated/model` (orval-generated from the\n * OpenAPI spec). Callers that need the type import\n * `CreateFlowDefinitionBodyFlowDefinition` from there directly;\n * callers that need the runtime validator import\n * `CreateFlowDefinitionBody` from\n * `@zitadel/api/generated/endpoints/zitadelNextGen.zod`. This\n * module owns only the CLI-specific concerns: the password-flow\n * builder, env-var reference scanning, and the file-level\n * `validateFlows` helper that surfaces `E_VALIDATION` errors against\n * the generated Zod.\n *\n * **Dependency rule.** No upward imports (`commands/`, `sync/`, etc.)\n * and no filesystem I/O. It depends sideways only on shared utilities\n * under `apps/cli/src/lib/` — today `lib/errors` (`ZitadelError`).\n */\nexport { buildFlow } from \"./build\";\nexport { validateFlows } from \"./validate\";\nexport { flowEnvRefs } from \"./env-refs\";\n\n/**\n * Relative directory (from the project root) where local flow files\n * live. Owned here so callers (`commands/*`, `sync/syncers.ts`) and\n * tests share a single source of truth for the path; the runtime\n * never depends on it directly because `lib/flows` does not touch\n * the filesystem.\n */\nexport const FLOWS_DIR = \".zitadel/flows\";\n","import type {\n CreateFlowDefinition201,\n CreateFlowDefinitionBodyFlowDefinition,\n UpdateFlowDefinition200,\n UpdateFlowDefinitionBodyFlowDefinition,\n CreateSchemaBody,\n GetSchemaById200,\n GetFlowDefinition200,\n} from \"@zitadel/api/generated/model\";\nimport { consola } from \"consola\";\n\nimport type { ZitadelClient } from \"@zitadel/api/client\";\nimport { DEFAULT_FLOW_SCHEMA_URI } from \"@zitadel/config/defaults\";\nimport { normalizeFlowBody, normalizeSchemaBody } from \"@zitadel/config/normalize\";\nimport { flowConfigSchema, schemaConfigSchema } from \"@zitadel/config/schemas\";\n\nimport { FLOWS_DIR, flowEnvRefs } from \"../flows\";\nimport { SCHEMAS_DIR } from \"../user-schema\";\nimport { ZitadelError } from \"../errors\";\nimport type { ResourceSyncer } from \"./types.js\";\n\n/** Runtime environment lookup used to resolve `${VAR}` / `*_env` references. */\ntype EnvLookup = Record<string, string | undefined>;\n\n/**\n * Build the syncer list with the context every syncer needs: the\n * `project_id` flow creates carry, and the runtime `env` against which\n * each file's `${VAR}` / `*_env` references are checked. Callers (apply /\n * plan / setup) read `project_id` from `.zitadel/secret` and pass the\n * process environment. The returned array is treated as read-only by the\n * sync loop.\n */\nexport function makeSyncers(opts: {\n client: ZitadelClient;\n projectId: string;\n env: EnvLookup;\n}): ReadonlyArray<ResourceSyncer> {\n return [\n new SchemaSyncer(opts.client, opts.projectId, opts.env),\n new FlowDefinitionSyncer(opts.client, opts.projectId, opts.env),\n ];\n}\n\n/**\n * Assert that every env var a resource references — `${VAR}` placeholders and\n * the `*_env` convention — is present in `env`, throwing `E_VALIDATION` listing\n * the missing names. Shared by every syncer so the check is identical for\n * schemas and flows, and runs in the sync engine before any platform call.\n */\nfunction assertEnvRefs(data: object, env: EnvLookup): void {\n const missing = flowEnvRefs(data).filter((name) => !env[name]);\n if (missing.length > 0) {\n throw new ZitadelError(\"E_VALIDATION\", `Missing environment variables: ${missing.join(\", \")}`);\n }\n}\n\nclass SchemaSyncer implements ResourceSyncer {\n readonly kind = \"schema\";\n readonly directory = SCHEMAS_DIR;\n readonly mutable = false;\n readonly revisioned = true;\n readonly normalize = normalizeSchemaBody;\n // Deliberately no `normalizeWrite`: the server stores schema bytes\n // verbatim, so stripping spelled-out x-* defaults from the local file\n // would drop them from the next published revision. Canonical schema\n // bodies are written back as-is; `normalize` is comparison-only.\n\n constructor(\n private readonly client: ZitadelClient,\n private readonly projectId: string,\n private readonly env: EnvLookup,\n ) {}\n\n /**\n * Parse against the generated `CreateSchemaBody` Zod (the orval-emitted\n * equivalent of `api/openapi/endpoints/schemas/user-schema.yaml`). The\n * generated schema is a union of `user-schema` and `schema-url`\n * discriminated on `kind`; both are valid on-disk bodies.\n */\n validate(data: object): void {\n const result = schemaConfigSchema.safeParse(data);\n if (!result.success) {\n throw new ZitadelError(\"E_VALIDATION\", \"Schema file is not a valid Zitadel schema body\", {\n details: { issues: result.error.issues },\n });\n }\n assertEnvRefs(data, this.env);\n }\n\n /**\n * `POST /schemas` mints a new immutable row. The server allocates the\n * opaque id; the CLI records it in state and re-pins flows against it.\n * The create response carries only the id, so the canonical stored body\n * comes from a follow-up fetch; a fetch failure degrades to no\n * write-back rather than failing the create.\n */\n async create(data: object): Promise<{ id: string; canonical?: object }> {\n const result = await this.client.createSchema(data as CreateSchemaBody, {\n project_id: this.projectId,\n });\n try {\n return { id: result.id, canonical: await this.fetch(result.id) };\n } catch (err) {\n consola.debug(`fetch created schema ${result.id} failed:`, err);\n return { id: result.id };\n }\n }\n\n /**\n * Not called by the sync loop: schemas are `revisioned`, so a hash change\n * publishes a new immutable revision through {@link create} rather than\n * mutating an existing row. Kept as a required interface member; throws\n * loudly if a caller reaches it.\n */\n async update(_id: string, _data: object): Promise<{ canonical?: object }> {\n throw new ZitadelError(\"E_NOT_IMPLEMENTED\", \"schemas are revisioned — edit publishes a new revision, not an update\");\n }\n\n async delete(id: string): Promise<void> {\n // Schemas are immutable on the platform: no PATCH, no DELETE in the\n // generated client. The sync loop's delete branch (`loop.ts`) still\n // schedules a delete action when a state entry exists and the\n // on-disk file is gone — `mutable` only gates updates, not deletes.\n // We deliberately fail loud here so the user notices that removing\n // a schema file is not a supported way to retire it.\n throw new ZitadelError(\"E_NOT_IMPLEMENTED\", `schema delete is not supported (${id})`);\n }\n\n async fetch(id: string): Promise<object> {\n const body = await this.client.getSchemaById(encodeURIComponent(id), {\n project_id: this.projectId,\n });\n return body as unknown as GetSchemaById200;\n }\n}\n\nclass FlowDefinitionSyncer implements ResourceSyncer {\n readonly kind = \"flow\";\n readonly directory = FLOWS_DIR;\n readonly mutable = true;\n readonly revisioned = false;\n readonly normalize = normalizeFlowBody;\n // For flows the comparison form doubles as the file form: everything it\n // strips (envelope keys, the empty `audience` echo) is transport noise.\n readonly normalizeWrite = normalizeFlowBody;\n\n constructor(\n private readonly client: ZitadelClient,\n private readonly projectId: string,\n private readonly env: EnvLookup,\n ) {}\n\n /**\n * Validates one flow file against the canonical `flowConfigSchema` (the\n * same Zod `validateFlows` and doctor use), then checks env references.\n */\n validate(data: object): void {\n const result = flowConfigSchema.safeParse(data);\n if (!result.success) {\n throw new ZitadelError(\"E_VALIDATION\", \"Flow file is not a valid Zitadel flow body\", {\n details: { issues: result.error.issues },\n });\n }\n assertEnvRefs(data, this.env);\n }\n\n /**\n * Wraps the bare on-disk flow body in the spec's create-envelope\n * (`api/openapi/components/flows/flow-definition-create-request.yaml`)\n * before sending. The file on disk stays bare so it is human-editable;\n * only the wire request carries `project_id` and the surrounding\n * envelope.\n */\n async create(data: object): Promise<{ id: string; canonical?: object }> {\n const result = (await this.client.createFlowDefinition({\n project_id: this.projectId,\n schema_uri: DEFAULT_FLOW_SCHEMA_URI,\n flow_definition: data as CreateFlowDefinitionBodyFlowDefinition,\n })) as CreateFlowDefinition201;\n return { id: result.id, canonical: result.flow_definition as object };\n }\n\n /**\n * PUT completely replaces the flow definition. The wire request wraps the\n * bare on-disk flow in the `{ flow_definition }` update envelope\n * (`api/openapi/components/flows/flow-definition-update-request.yaml`) and\n * carries `project_id` as a query parameter; the file on disk stays bare so\n * it is human-editable.\n */\n async update(id: string, data: object): Promise<{ canonical?: object }> {\n const result = (await this.client.updateFlowDefinition(\n id,\n { flow_definition: data as UpdateFlowDefinitionBodyFlowDefinition },\n { project_id: this.projectId },\n )) as UpdateFlowDefinition200;\n return { canonical: result.flow_definition as object };\n }\n\n async delete(id: string): Promise<void> {\n await this.client.deleteFlowDefinition(id, { project_id: this.projectId });\n }\n\n /**\n * `GET /flow_definitions/:id` returns a detail envelope with metadata\n * (`id`, `project_id`, `created_at`, `updated_at`) plus `flow_definition`.\n * Return only `flow_definition` so diffs compare with the on-disk bare body.\n */\n async fetch(id: string): Promise<object> {\n const envelope = (await this.client.getFlowDefinition(\n id,\n { project_id: this.projectId },\n )) as GetFlowDefinition200;\n\n return envelope.flow_definition as object;\n }\n}\n","import { readFile, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport type { ResourceEntry, ZitadelState } from \"./types.js\";\n\n/**\n * Read and parse `.zitadel/state.json`. Throws if the file is\n * missing or malformed; callers run `zitadel setup` first to bring\n * the file into existence.\n */\nexport async function readState(cwd: string): Promise<ZitadelState> {\n const raw = await readFile(join(cwd, \".zitadel/state.json\"), \"utf8\");\n return JSON.parse(raw) as ZitadelState;\n}\n\n/**\n * Merge an entry into the state file under `key`, preserving any\n * fields the caller did not override. Reads the file, writes it back\n * with sorted keys disabled (state is engine-managed, not human-\n * authored, so deterministic ordering isn't required here).\n */\nexport async function updateState(\n cwd: string,\n key: string,\n entry: ResourceEntry,\n): Promise<void> {\n const current = await readState(cwd);\n const updated: ZitadelState = {\n ...current,\n resources: {\n ...current.resources,\n [key]: { ...current.resources[key], ...entry },\n },\n };\n await writeFile(join(cwd, \".zitadel/state.json\"), JSON.stringify(updated, null, 2));\n}\n\n/**\n * Remove an entry from the state file. No-op if the key is absent.\n */\nexport async function removeFromState(cwd: string, key: string): Promise<void> {\n const current = await readState(cwd);\n const { [key]: _removed, ...rest } = current.resources;\n const updated: ZitadelState = { ...current, resources: rest };\n await writeFile(join(cwd, \".zitadel/state.json\"), JSON.stringify(updated, null, 2));\n}\n","import { createHash } from \"node:crypto\";\nimport { readdir, readFile, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { consola } from \"consola\";\n\nimport { FLOWS_DIR } from \"../flows\";\nimport { stableStringify } from \"../json\";\nimport { ZitadelError } from \"../errors\";\nimport { readState, removeFromState, updateState } from \"./state.js\";\nimport type { ResourceEntry, ResourceSyncer, SyncAction } from \"./types.js\";\n\n/**\n * Compute the sync plan for `cwd` against the state file and (when\n * `fetchOld` is true) the platform API. The plan is read-only: it\n * decides what create/update/revise/delete operations need to happen but\n * performs none of them. Pass it to {@link runSyncLoop} to execute.\n *\n * Validates every on-disk file (via `syncer.validate`) before planning any\n * work — a single malformed schema or flow aborts the whole run with\n * `E_VALIDATION` before any platform mutation. Both `plan` and `apply`\n * reach this code path.\n *\n * Bearer auth + base URL live in the api package's runtime registries\n * (`runtime/{auth,base-url}`). Callers set them once at command boot;\n * the sync engine doesn't carry a client.\n *\n * @param cwd - Project root.\n * @param syncers - Per-resource adapters. Order is preserved in the output.\n * @param fetchOld - When true, the planner fetches each delete/update target\n * from the platform to populate `oldContent` for diff rendering.\n */\nexport async function buildSyncPlan(\n cwd: string,\n syncers: ReadonlyArray<ResourceSyncer>,\n fetchOld = false,\n): Promise<ReadonlyArray<SyncAction>> {\n const state = await readState(cwd);\n const actions: SyncAction[] = [];\n\n // Walk local flow files once, up front: revisioned schemas need to name every\n // flow whose `user_schema` currently pins the previous revision, so the\n // executor can re-pin those flows after the new revision is published.\n const localFlows = await readLocalFlowUserSchemas(cwd);\n\n // Revisions this plan will publish, keyed by the superseded id. Schema\n // syncers run before the flow syncer (makeSyncers order), so every pending\n // revise is known by the time flow files are planned.\n const pendingRevisions = new Map<string, { schemaPath: string }>();\n\n // Revisions an interrupted earlier run already published (state advanced,\n // `previousId` recorded) whose flows were never rewritten: superseded id →\n // the concrete new id. Lets a rerun finish the re-pin with no new revise.\n const recoveredRevisions = new Map<string, { schemaPath: string; newId: string }>();\n for (const [schemaPath, entry] of Object.entries(state.resources)) {\n if (entry.previousId && entry.id && entry.previousId !== entry.id) {\n recoveredRevisions.set(entry.previousId, { schemaPath, newId: entry.id });\n }\n }\n\n // Every scanned file body, keyed by project-relative path. Schema syncers\n // run before the flow syncer, so by the time a re-pin is planned the new\n // schema revision's content is available for the pre-flight field check.\n const scannedContents = new Map<string, object>();\n\n for (const syncer of syncers) {\n const dirPath = join(cwd, syncer.directory);\n consola.debug(`scanning ${syncer.directory}`);\n const onDisk = await readJsonDir(dirPath);\n\n for (const content of onDisk.values()) {\n syncer.validate(content);\n }\n\n for (const [filePath, entry] of Object.entries(state.resources)) {\n if (!filePath.startsWith(syncer.directory)) {\n continue;\n }\n if (onDisk.has(join(cwd, filePath)) || !entry.id) {\n continue;\n }\n\n let oldContent: object | null = null;\n if (fetchOld && syncer.fetch) {\n try {\n oldContent = await syncer.fetch(entry.id);\n } catch (err) {\n consola.debug(`fetch ${syncer.kind} ${entry.id} failed:`, err);\n }\n }\n actions.push({ kind: \"delete\", path: filePath, syncer, id: entry.id, oldContent });\n }\n\n for (const [absPath, content] of onDisk.entries()) {\n const relPath = absPath.slice(cwd.length + 1);\n scannedContents.set(relPath, content);\n const entry = state.resources[relPath];\n const hash = hashForState(syncer, content);\n\n // A flow pinned to a schema revision superseded in this plan (or by an\n // interrupted earlier run) needs its `user_schema` rewritten — whether\n // the flow is untouched, edited, or brand new (a create in the same\n // run as the revise must not POST the stale id).\n const flowRef = localFlows.get(relPath);\n const pending = flowRef ? pendingRevisions.get(flowRef) : undefined;\n const recovered = flowRef ? recoveredRevisions.get(flowRef) : undefined;\n const repin = pending\n ? { previousId: flowRef as string, schemaPath: pending.schemaPath }\n : recovered\n ? {\n previousId: flowRef as string,\n schemaPath: recovered.schemaPath,\n newId: recovered.newId,\n }\n : undefined;\n if (repin) {\n assertRepinnedFlowFields(\n relPath,\n content,\n repin.schemaPath,\n scannedContents.get(repin.schemaPath),\n );\n }\n\n if (!entry?.id) {\n actions.push({\n kind: \"create\",\n path: relPath,\n syncer,\n content,\n hash,\n ...(repin ? { repin } : {}),\n });\n continue;\n }\n\n // State files written before normalized hashing hold legacy hashes\n // (order-sensitive, un-normalized). Accepting the legacy format —\n // both over the raw file and over its stably-sorted form, since\n // setup-era hashes were computed on sorted keys — keeps an untouched\n // or merely reordered file a skip; a spurious mismatch here would\n // publish a garbage schema revision. Writes always store the new\n // format, so state converges on the next real change.\n const unchanged =\n entry.hash === hash ||\n entry.hash === hashResourceContent(content) ||\n entry.hash === hashResourceContent(JSON.parse(stableStringify(content)) as object);\n if (unchanged && !(repin && syncer.mutable)) {\n actions.push({ kind: \"skip\", path: relPath, reason: \"no-change\" });\n continue;\n }\n\n if (syncer.revisioned) {\n const oldContent = await fetchOldIfAsked(syncer, entry.id, fetchOld);\n pendingRevisions.set(entry.id, { schemaPath: relPath });\n actions.push({\n kind: \"revise\",\n path: relPath,\n syncer,\n content,\n hash,\n previousId: entry.id,\n oldContent,\n affectedPaths: findFlowsPinnedTo(entry.id, localFlows),\n });\n continue;\n }\n\n if (!syncer.mutable) {\n actions.push({ kind: \"skip\", path: relPath, reason: \"immutable\" });\n continue;\n }\n\n const oldContent = await fetchOldIfAsked(syncer, entry.id, fetchOld);\n actions.push({\n kind: \"update\",\n path: relPath,\n syncer,\n id: entry.id,\n content,\n hash,\n oldContent,\n ...(repin ? { repin } : {}),\n });\n }\n }\n\n return actions;\n}\n\n/** Result of {@link runSyncLoop}: the local files the loop rewrote. */\nexport type SyncLoopResult = {\n /**\n * Project-relative paths of files updated from the server's canonical\n * responses (write-back). Surfaced in human and `--json` output so a\n * local rewrite is never silent.\n */\n filesUpdated: string[];\n};\n\n/**\n * Execute every action returned by {@link buildSyncPlan} against the\n * platform. Updates the local state file (`.zitadel/state.json`) as\n * each action completes so an interrupted run can resume. After each\n * mutation, the server's canonical body is written back to the local\n * file (when it differs in normalized form), so repo config matches\n * live state by construction and the next `plan` is empty.\n *\n * The platform target (base URL + bearer auth) lives in the api\n * package's runtime registries; callers set them before invoking this.\n *\n * @param cwd - Project root.\n * @param syncers - Per-resource adapters; same list passed to\n * `buildSyncPlan`.\n */\nexport async function runSyncLoop(\n cwd: string,\n syncers: ReadonlyArray<ResourceSyncer>,\n): Promise<SyncLoopResult> {\n const actions = await buildSyncPlan(cwd, syncers);\n const filesUpdated: string[] = [];\n // Revisions published by this run: superseded id → new id. Update actions\n // carrying a `repin` patch their `user_schema` from here.\n const repinned = new Map<string, string>();\n\n const writeBack = async (\n action: Extract<SyncAction, { kind: \"create\" | \"revise\" | \"update\" }>,\n canonical: object | undefined,\n fallbackHash: string,\n ): Promise<string> => {\n if (!canonical) {\n return fallbackHash;\n }\n const { hash, changed } = await writeBackResource(cwd, action.path, action.syncer, canonical);\n if (changed) {\n filesUpdated.push(action.path);\n consola.info(`Updated ${action.path} from the server's canonical response`);\n }\n return hash;\n };\n\n for (const action of actions) {\n switch (action.kind) {\n case \"create\": {\n let content = action.content;\n const newId = action.repin\n ? (repinned.get(action.repin.previousId) ?? action.repin.newId)\n : undefined;\n if (newId) {\n // A flow created in the same run as (or after an interrupted)\n // schema revise must adopt the new revision — POSTing the stale\n // pin would fail validation, and its canonical echo would revert\n // the re-pinned local file.\n content = { ...(content as Record<string, unknown>), user_schema: newId };\n }\n const { id, canonical } = await action.syncer.create(content);\n const fallbackHash = newId ? hashForState(action.syncer, content) : action.hash;\n const entry: ResourceEntry = { id, hash: await writeBack(action, canonical, fallbackHash) };\n await updateState(cwd, action.path, entry);\n consola.info(\n `Created a new ${action.syncer.kind} on Zitadel from ${action.path} (id ${id})`,\n );\n break;\n }\n case \"revise\": {\n const { id, canonical } = await action.syncer.create(action.content);\n // `previousId` lands in state before the flow files are rewritten:\n // if the process dies in between, the next plan recovers the re-pin\n // from state instead of publishing a duplicate revision.\n const entry: ResourceEntry = {\n id,\n hash: await writeBack(action, canonical, action.hash),\n previousId: action.previousId,\n };\n await updateState(cwd, action.path, entry);\n repinned.set(action.previousId, id);\n consola.info(\n `Published a new ${action.syncer.kind} revision on Zitadel from ${action.path} (id ${id})`,\n );\n for (const flowPath of action.affectedPaths) {\n if (await repinFlowFile(cwd, flowPath, action.previousId, id)) {\n filesUpdated.push(flowPath);\n consola.info(`Re-pinned user_schema in ${flowPath} to ${id}`);\n }\n }\n break;\n }\n case \"update\": {\n let content = action.content;\n const newId = action.repin\n ? (repinned.get(action.repin.previousId) ?? action.repin.newId)\n : undefined;\n if (newId && action.repin) {\n // The plan captured the flow before the revise rewrote its file;\n // patch the pin in memory so the wire request adopts the new\n // revision without re-reading disk. The file rewrite below is a\n // no-op when this run's revise already re-pinned it — it matters\n // for crash recovery, where no revise ran this time.\n content = { ...(content as Record<string, unknown>), user_schema: newId };\n if (await repinFlowFile(cwd, action.path, action.repin.previousId, newId)) {\n filesUpdated.push(action.path);\n consola.info(`Re-pinned user_schema in ${action.path} to ${newId}`);\n }\n }\n const { canonical } = await action.syncer.update(action.id, content);\n const fallbackHash = newId ? hashForState(action.syncer, content) : action.hash;\n await updateState(cwd, action.path, {\n hash: await writeBack(action, canonical, fallbackHash),\n });\n consola.info(`Updated the ${action.syncer.kind} on Zitadel from ${action.path}`);\n break;\n }\n case \"delete\": {\n await action.syncer.delete(action.id);\n await removeFromState(cwd, action.path);\n consola.info(\n `Deleted the ${action.syncer.kind} on Zitadel because ${action.path} was removed locally`,\n );\n break;\n }\n case \"skip\": {\n consola.debug(`Skipped ${action.path} (${action.reason})`);\n break;\n }\n }\n }\n\n // `previousId` exists to recover interrupted re-pins; once no local flow\n // pins the superseded revision, drop it — otherwise a developer who later\n // pins that old revision on purpose would get force-bumped by recovery.\n const remainingPins = new Set((await readLocalFlowUserSchemas(cwd)).values());\n const finalState = await readState(cwd);\n for (const [path, entry] of Object.entries(finalState.resources)) {\n if (entry.previousId && !remainingPins.has(entry.previousId)) {\n await updateState(cwd, path, { previousId: undefined });\n }\n }\n\n return { filesUpdated: [...new Set(filesUpdated)] };\n}\n\n/**\n * Rewrite a flow file's `user_schema` pin from `previousId` to `newId`,\n * lockfile-style. Prefers a targeted text replacement so the author's\n * formatting survives a one-string change; falls back to parse +\n * `stableStringify` when the raw text doesn't contain exactly one pin.\n * Returns false when the file doesn't pin `previousId` (already re-pinned\n * or hand-edited) — never throws for an unreadable file.\n */\nasync function repinFlowFile(\n cwd: string,\n relPath: string,\n previousId: string,\n newId: string,\n): Promise<boolean> {\n const absPath = join(cwd, relPath);\n let raw: string;\n try {\n raw = await readFile(absPath, \"utf8\");\n } catch (err) {\n consola.debug(`read ${relPath} for re-pin failed:`, err);\n return false;\n }\n\n const pinPattern = new RegExp(\n `(\"user_schema\"\\\\s*:\\\\s*)${escapeRegExp(JSON.stringify(previousId))}`,\n \"g\",\n );\n if (raw.match(pinPattern)?.length === 1) {\n await writeFile(\n absPath,\n raw.replace(pinPattern, (_match, prefix: string) => `${prefix}${JSON.stringify(newId)}`),\n );\n return true;\n }\n\n try {\n const doc = JSON.parse(raw) as Record<string, unknown>;\n if (doc.user_schema !== previousId) {\n return false;\n }\n doc.user_schema = newId;\n await writeFile(absPath, `${stableStringify(doc)}\\n`);\n return true;\n } catch (err) {\n consola.debug(`re-pin ${relPath} failed:`, err);\n return false;\n }\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\n/**\n * Reconcile a local file with the server's canonical body. What gets\n * written is the `normalizeWrite` form (strips pure transport noise like\n * the empty `audience` echo; for schemas the canonical body verbatim —\n * spelled-out x-* defaults must survive, or the next apply would publish\n * a revision without them). Equality is judged in the `normalize`\n * comparison form, so the file is rewritten only when it materially\n * differs from live state; hand-formatted files stay untouched otherwise.\n * Returns the state hash of the written form.\n */\nexport async function writeBackResource(\n cwd: string,\n relPath: string,\n syncer: Pick<ResourceSyncer, \"normalize\" | \"normalizeWrite\">,\n canonical: object,\n): Promise<{ hash: string; changed: boolean }> {\n const writeBody = syncer.normalizeWrite?.(canonical) ?? canonical;\n const compare = (body: object) => stableStringify(syncer.normalize?.(body) ?? body);\n const absPath = join(cwd, relPath);\n let changed = true;\n try {\n const onDisk = JSON.parse(await readFile(absPath, \"utf8\")) as object;\n changed = compare(writeBody) !== compare(onDisk);\n } catch (err) {\n consola.debug(`read ${relPath} for write-back failed:`, err);\n }\n if (changed) {\n await writeFile(absPath, `${stableStringify(writeBody)}\\n`);\n }\n return { hash: hashForState(syncer, writeBody), changed };\n}\n\nasync function fetchOldIfAsked(\n syncer: ResourceSyncer,\n id: string,\n fetchOld: boolean,\n): Promise<object | null> {\n if (!fetchOld || !syncer.fetch) {\n return null;\n }\n try {\n return await syncer.fetch(id);\n } catch (err) {\n consola.debug(`fetch ${syncer.kind} ${id} failed:`, err);\n return null;\n }\n}\n\nasync function readJsonDir(dirPath: string): Promise<Map<string, object>> {\n const result = new Map<string, object>();\n let entries: string[];\n try {\n entries = await readdir(dirPath);\n } catch (err) {\n if (typeof err === \"object\" && err !== null && \"code\" in err && err.code === \"ENOENT\") {\n return result;\n }\n throw err;\n }\n for (const entry of entries.filter((e) => e.endsWith(\".json\"))) {\n const filePath = join(dirPath, entry);\n const raw = await readFile(filePath, \"utf8\");\n result.set(filePath, JSON.parse(raw) as object);\n }\n return result;\n}\n\n/**\n * Walk `.zitadel/flows/*.json` once and return each flow's `user_schema` value\n * keyed by project-root-relative path. A flow file without a `user_schema` (or\n * with a non-string one) is skipped: it does not pin a schema revision, so it\n * cannot be affected by one.\n */\nasync function readLocalFlowUserSchemas(cwd: string): Promise<Map<string, string>> {\n const result = new Map<string, string>();\n const flows = await readJsonDir(join(cwd, FLOWS_DIR));\n for (const [absPath, content] of flows.entries()) {\n const relPath = absPath.slice(cwd.length + 1);\n if (\n typeof content === \"object\" &&\n content !== null &&\n \"user_schema\" in content &&\n typeof (content as { user_schema: unknown }).user_schema === \"string\"\n ) {\n result.set(relPath, (content as { user_schema: string }).user_schema);\n }\n }\n return result;\n}\n\n/**\n * Fail fast when a flow that is about to adopt a new schema revision\n * references properties the new revision no longer has (the server would\n * reject the flow update with `flow field: not a property in the user\n * schema`). Runs at plan time, before any platform mutation — otherwise\n * the revise would publish first and the run would die half-applied.\n * Only plain property fields are checked; reserved credential tokens\n * (`x-auth-methods#…`) resolve outside the schema.\n */\nfunction assertRepinnedFlowFields(\n flowPath: string,\n flowContent: object,\n schemaPath: string,\n schemaContent: object | undefined,\n): void {\n if (!schemaContent) {\n return;\n }\n const properties = (schemaContent as { properties?: unknown }).properties;\n if (typeof properties !== \"object\" || properties === null) {\n return;\n }\n const steps = (flowContent as { steps?: Array<{ name?: unknown; fields?: unknown }> }).steps;\n const missing: string[] = [];\n for (const step of Array.isArray(steps) ? steps : []) {\n const fields = Array.isArray(step.fields) ? step.fields : [];\n for (const field of fields) {\n if (typeof field !== \"string\" || field.includes(\"#\")) {\n continue;\n }\n if (!Object.prototype.hasOwnProperty.call(properties, field)) {\n missing.push(`step ${JSON.stringify(step.name ?? \"?\")}: ${JSON.stringify(field)}`);\n }\n }\n }\n if (missing.length > 0) {\n throw new ZitadelError(\n \"E_VALIDATION\",\n `${flowPath} cannot adopt the new revision of ${schemaPath}: ` +\n `flow fields missing from the edited schema — ${missing.join(\", \")}`,\n {\n hint:\n \"Update the flow's steps[].fields to match the edited schema \" +\n \"(or restore the removed/renamed properties), then re-run plan/apply.\",\n },\n );\n }\n}\n\nfunction findFlowsPinnedTo(\n previousId: string,\n localFlows: Map<string, string>,\n): ReadonlyArray<string> {\n const affected: string[] = [];\n for (const [relPath, ref] of localFlows.entries()) {\n if (ref === previousId) {\n affected.push(relPath);\n }\n }\n return affected;\n}\n\n/**\n * Legacy content hash: order-sensitive and normalization-blind. Kept only\n * so state entries written by older CLI versions still match; new hashes\n * come from {@link hashForState}.\n */\nexport function hashResourceContent(data: object): string {\n return createHash(\"sha256\").update(JSON.stringify(data)).digest(\"hex\");\n}\n\n/**\n * The content hash stored in `.zitadel/state.json`: key-order-insensitive\n * (via `stableStringify`) and computed on the syncer's normalized form, so\n * reordering keys or spelling out a meta-schema default does not read as an\n * edit.\n */\nexport function hashForState(\n syncer: Pick<ResourceSyncer, \"normalize\">,\n data: object,\n): string {\n const normalized = syncer.normalize?.(data) ?? data;\n return createHash(\"sha256\").update(stableStringify(normalized)).digest(\"hex\");\n}\n","import { stableStringify } from \"../json\";\nimport type { ResourceSyncer, SyncAction, SyncPlanSummary } from \"./types.js\";\n\n/**\n * Count the non-`skip` actions in a {@link buildSyncPlan} result. Pure; the\n * single source of truth for the plan counts shared by the `plan` /\n * `apply --dry-run` JSON payload and {@link renderPlan}'s summary line.\n */\nexport function summarizePlan(actions: ReadonlyArray<SyncAction>): SyncPlanSummary {\n const active = actions.filter((a) => a.kind !== \"skip\");\n return {\n creates: active.filter((a) => a.kind === \"create\").length,\n updates: active.filter((a) => a.kind === \"update\").length,\n revisions: active.filter((a) => a.kind === \"revise\").length,\n deletes: active.filter((a) => a.kind === \"delete\").length,\n total: active.length,\n };\n}\n\n/**\n * Render a {@link buildSyncPlan} result as a human-readable Terraform-style\n * plan. TTY-aware: colors and bold are emitted only when `tty` is true.\n * Returns the empty-state message when every action is `skip`.\n *\n * @param actions - The action list produced by `buildSyncPlan`. Read-only;\n * the function never mutates the input.\n * @param tty - True when stdout is a TTY; controls ANSI emission.\n */\nexport function renderPlan(actions: ReadonlyArray<SyncAction>, tty: boolean): string {\n const active = actions.filter((a) => a.kind !== \"skip\");\n\n if (active.length === 0) {\n return paint(\n \"No changes. Your Zitadel configuration matches the current state.\",\n A.bold,\n tty,\n );\n }\n\n const out: string[] = [];\n out.push(paint(\"Zitadel will perform the following actions:\", A.bold, tty));\n\n for (const action of active) {\n out.push(\"\");\n out.push(...renderBlock(action, tty));\n }\n\n out.push(\"\");\n\n const { creates, updates, revisions, deletes } = summarizePlan(actions);\n\n const parts: string[] = [];\n if (creates > 0) {\n parts.push(`${creates} to add`);\n }\n if (updates > 0) {\n parts.push(`${updates} to change`);\n }\n if (revisions > 0) {\n parts.push(`${revisions} new revision${revisions === 1 ? \"\" : \"s\"}`);\n }\n if (deletes > 0) {\n parts.push(`${deletes} to destroy`);\n }\n\n out.push(paint(`Plan: ${parts.join(\", \")}.`, A.bold, tty));\n return out.join(\"\\n\");\n}\n\nconst A = {\n reset: \"\\x1b[0m\",\n bold: \"\\x1b[1m\",\n green: \"\\x1b[32m\",\n red: \"\\x1b[31m\",\n yellow: \"\\x1b[33m\",\n} as const;\n\nfunction paint(text: string, code: string, tty: boolean): string {\n return tty ? `${code}${text}${A.reset}` : text;\n}\n\nfunction isPrimitive(v: unknown): v is string | number | boolean | null {\n return v === null || typeof v === \"string\" || typeof v === \"number\" || typeof v === \"boolean\";\n}\n\nfunction isPlainObject(v: unknown): v is Record<string, unknown> {\n return typeof v === \"object\" && v !== null && !Array.isArray(v);\n}\n\nconst KNOWN_AFTER_APPLY = \"(known after apply)\";\n\nfunction escapeString(s: string): string {\n return s\n .replace(/\\\\/g, \"\\\\\\\\\")\n .replace(/\"/g, '\\\\\"')\n .replace(/\\n/g, \"\\\\n\")\n .replace(/\\r/g, \"\\\\r\")\n .replace(/\\t/g, \"\\\\t\");\n}\n\nfunction fmtPrimitive(v: string | number | boolean | null): string {\n if (v === null) {\n return \"null\";\n }\n if (typeof v === \"string\" && v === KNOWN_AFTER_APPLY) {\n return KNOWN_AFTER_APPLY;\n }\n if (typeof v === \"string\") {\n return `\"${escapeString(v)}\"`;\n }\n return String(v);\n}\n\n/**\n * Indentation contract (matches Terraform exactly):\n * prefixCol = column index of the +/-/~ character\n * field content starts at prefixCol + 2 (one space gap after prefix)\n * nested object/array content: prefixCol + 4 for the child prefixCol\n * closing } or ] : prefixCol + 2 columns of plain spaces, no prefix\n */\ntype ChangePrefix = \"+\" | \"-\" | \"~\" | \" \";\n\nfunction prefixAnsi(p: ChangePrefix): string {\n if (p === \"+\") {\n return A.green;\n }\n if (p === \"-\") {\n return A.red;\n }\n if (p === \"~\") {\n return A.yellow;\n }\n return \"\";\n}\n\ninterface RenderCtx {\n tty: boolean;\n deleteMode: boolean;\n}\n\nfunction renderFields(\n obj: Record<string, unknown>,\n prefix: ChangePrefix,\n prefixCol: number,\n ctx: RenderCtx,\n lines: string[],\n): void {\n const pad = \" \".repeat(prefixCol);\n const ansi = prefixAnsi(prefix);\n const col = (s: string) => paint(s, ansi, ctx.tty);\n\n const keys = Object.keys(obj).sort();\n const maxLen = keys.reduce((m, k) => Math.max(m, k.length), 0);\n\n for (const key of keys) {\n const val = obj[key];\n const pk = key.padEnd(maxLen);\n\n if (isPrimitive(val)) {\n const formatted = fmtPrimitive(val);\n const suffix = ctx.deleteMode ? \" -> null\" : \"\";\n lines.push(col(`${pad}${prefix} ${pk} = ${formatted}${suffix}`));\n } else if (Array.isArray(val)) {\n if (val.length === 0) {\n lines.push(col(`${pad}${prefix} ${pk} = []`));\n } else {\n lines.push(col(`${pad}${prefix} ${pk} = [`));\n renderArrayItems(val, prefix, prefixCol + 4, ctx, lines);\n lines.push(col(`${\" \".repeat(prefixCol + 2)}]`));\n }\n } else if (isPlainObject(val)) {\n if (Object.keys(val).length === 0) {\n lines.push(col(`${pad}${prefix} ${pk} = {}`));\n } else {\n lines.push(col(`${pad}${prefix} ${pk} = {`));\n renderFields(val, prefix, prefixCol + 4, ctx, lines);\n lines.push(col(`${\" \".repeat(prefixCol + 2)}}`));\n }\n }\n }\n}\n\n/**\n * Renders the items of an array. Unlike {@link renderFields}, primitive\n * elements never get a trailing ` -> null` suffix even under `deleteMode` —\n * Terraform only annotates scalar object-field removals that way, not array\n * items.\n */\nfunction renderArrayItems(\n arr: ReadonlyArray<unknown>,\n prefix: ChangePrefix,\n prefixCol: number,\n ctx: RenderCtx,\n lines: string[],\n): void {\n const pad = \" \".repeat(prefixCol);\n const ansi = prefixAnsi(prefix);\n const col = (s: string) => paint(s, ansi, ctx.tty);\n\n for (const item of arr) {\n if (isPrimitive(item)) {\n const formatted = fmtPrimitive(item);\n lines.push(col(`${pad}${prefix} ${formatted},`));\n } else if (Array.isArray(item)) {\n if (item.length === 0) {\n lines.push(col(`${pad}${prefix} [],`));\n } else {\n lines.push(col(`${pad}${prefix} [`));\n renderArrayItems(item, prefix, prefixCol + 4, ctx, lines);\n lines.push(col(`${\" \".repeat(prefixCol + 2)}],`));\n }\n } else if (isPlainObject(item)) {\n if (Object.keys(item).length === 0) {\n lines.push(col(`${pad}${prefix} {},`));\n } else {\n lines.push(col(`${pad}${prefix} {`));\n renderFields(item, prefix, prefixCol + 4, ctx, lines);\n lines.push(col(`${\" \".repeat(prefixCol + 2)}},`));\n }\n }\n }\n}\n\n/**\n * Walks both old and new objects, emitting Terraform-style change lines.\n * Returns true if any actual change line (+ / - / ~) was emitted.\n *\n * Edge cases:\n * - Changed arrays render as a full remove + full add (no LCS diff).\n * - Nested objects recurse, and the outer key is only marked `~` if a child\n * actually changed; unchanged children render with the neutral prefix.\n * - A value whose type changed (e.g. string → object) also renders as a\n * remove + add pair.\n */\nfunction renderDiff(\n oldObj: Record<string, unknown>,\n newObj: Record<string, unknown>,\n prefixCol: number,\n tty: boolean,\n lines: string[],\n): boolean {\n const allKeys = [...new Set([...Object.keys(oldObj), ...Object.keys(newObj)])].sort();\n const maxLen = allKeys.reduce((m, k) => Math.max(m, k.length), 0);\n const pad = \" \".repeat(prefixCol);\n let hasChanges = false;\n\n for (const key of allKeys) {\n const pk = key.padEnd(maxLen);\n const hasOld = Object.prototype.hasOwnProperty.call(oldObj, key);\n const hasNew = Object.prototype.hasOwnProperty.call(newObj, key);\n const oldVal = oldObj[key];\n const newVal = newObj[key];\n\n if (!hasOld) {\n hasChanges = true;\n const col = (s: string) => paint(s, A.green, tty);\n if (isPrimitive(newVal)) {\n lines.push(col(`${pad}+ ${pk} = ${fmtPrimitive(newVal)}`));\n } else if (Array.isArray(newVal)) {\n lines.push(col(`${pad}+ ${pk} = [`));\n renderArrayItems(newVal, \"+\", prefixCol + 4, { tty, deleteMode: false }, lines);\n lines.push(col(`${\" \".repeat(prefixCol + 2)}]`));\n } else if (isPlainObject(newVal)) {\n lines.push(col(`${pad}+ ${pk} = {`));\n renderFields(newVal, \"+\", prefixCol + 4, { tty, deleteMode: false }, lines);\n lines.push(col(`${\" \".repeat(prefixCol + 2)}}`));\n }\n } else if (!hasNew) {\n hasChanges = true;\n const col = (s: string) => paint(s, A.red, tty);\n if (isPrimitive(oldVal)) {\n lines.push(col(`${pad}- ${pk} = ${fmtPrimitive(oldVal)} -> null`));\n } else if (Array.isArray(oldVal)) {\n lines.push(col(`${pad}- ${pk} = [`));\n renderArrayItems(oldVal, \"-\", prefixCol + 4, { tty, deleteMode: false }, lines);\n lines.push(col(`${\" \".repeat(prefixCol + 2)}]`));\n } else if (isPlainObject(oldVal)) {\n lines.push(col(`${pad}- ${pk} = {`));\n renderFields(oldVal, \"-\", prefixCol + 4, { tty, deleteMode: true }, lines);\n lines.push(col(`${\" \".repeat(prefixCol + 2)}}`));\n }\n } else if (isPrimitive(oldVal) && isPrimitive(newVal)) {\n if (oldVal === newVal) {\n lines.push(`${pad} ${pk} = ${fmtPrimitive(newVal)}`);\n } else {\n hasChanges = true;\n const col = (s: string) => paint(s, A.yellow, tty);\n lines.push(col(`${pad}~ ${pk} = ${fmtPrimitive(oldVal)} -> ${fmtPrimitive(newVal)}`));\n }\n } else if (Array.isArray(oldVal) && Array.isArray(newVal)) {\n // Key-order-insensitive equality: the server echoes objects in its own\n // field order while local files are stably sorted — that difference is\n // not a change.\n if (stableStringify(oldVal) === stableStringify(newVal)) {\n if (newVal.length === 0) {\n lines.push(`${pad} ${pk} = []`);\n } else {\n lines.push(`${pad} ${pk} = [`);\n renderArrayItems(newVal, \" \", prefixCol + 4, { tty, deleteMode: false }, lines);\n lines.push(`${\" \".repeat(prefixCol + 2)}]`);\n }\n } else {\n hasChanges = true;\n const colR = (s: string) => paint(s, A.red, tty);\n const colA = (s: string) => paint(s, A.green, tty);\n if (oldVal.length === 0) {\n lines.push(colR(`${pad}- ${pk} = []`));\n } else {\n lines.push(colR(`${pad}- ${pk} = [`));\n renderArrayItems(oldVal, \"-\", prefixCol + 4, { tty, deleteMode: false }, lines);\n lines.push(colR(`${\" \".repeat(prefixCol + 2)}]`));\n }\n if (newVal.length === 0) {\n lines.push(colA(`${pad}+ ${pk} = []`));\n } else {\n lines.push(colA(`${pad}+ ${pk} = [`));\n renderArrayItems(newVal, \"+\", prefixCol + 4, { tty, deleteMode: false }, lines);\n lines.push(colA(`${\" \".repeat(prefixCol + 2)}]`));\n }\n }\n } else if (isPlainObject(oldVal) && isPlainObject(newVal)) {\n const childLines: string[] = [];\n const childHasChanges = renderDiff(oldVal, newVal, prefixCol + 4, tty, childLines);\n if (childHasChanges) {\n hasChanges = true;\n const col = (s: string) => paint(s, A.yellow, tty);\n lines.push(col(`${pad}~ ${pk} = {`));\n lines.push(...childLines);\n lines.push(col(`${\" \".repeat(prefixCol + 2)}}`));\n } else if (childLines.length > 0) {\n lines.push(`${pad} ${pk} = {`);\n lines.push(...childLines);\n lines.push(`${\" \".repeat(prefixCol + 2)}}`);\n } else {\n lines.push(`${pad} ${pk} = {}`);\n }\n } else {\n hasChanges = true;\n const colR = (s: string) => paint(s, A.red, tty);\n const colA = (s: string) => paint(s, A.green, tty);\n if (isPrimitive(oldVal)) {\n lines.push(colR(`${pad}- ${pk} = ${fmtPrimitive(oldVal)} -> null`));\n }\n if (isPrimitive(newVal)) {\n lines.push(colA(`${pad}+ ${pk} = ${fmtPrimitive(newVal)}`));\n }\n }\n }\n\n return hasChanges;\n}\n\n/**\n * Column layout (matches Terraform's per-block format):\n * BLOCK_COL = 2 — where the +/-/~ sits on the resource opening line\n * FIELD_COL = 6 — where the +/-/~ sits on first-level field lines\n * closing } — at BLOCK_COL + 2 = 4, no prefix\n */\nconst BLOCK_COL = 2;\nconst FIELD_COL = 6;\n\nfunction resourceName(path: string): string {\n return path.split(\"/\").pop() ?? path;\n}\n\n/**\n * Diff both sides in the syncer's canonical form so server-echoed noise\n * (empty `audience`, spelled-out meta-schema defaults) never renders as a\n * change the author didn't make. Rendering only — upload payloads stay raw.\n */\nfunction normalized(\n syncer: Pick<ResourceSyncer, \"normalize\">,\n content: object,\n): Record<string, unknown> {\n return (syncer.normalize?.(content) ?? content) as Record<string, unknown>;\n}\n\n/**\n * Renders one Terraform-style resource block for a single `SyncAction`.\n *\n * Per-case notes:\n * - **create**: a synthetic `id = (known after apply)` is injected into the\n * rendered fields so it sorts alphabetically alongside the real keys.\n * - **delete**: when `oldContent` is null (the fetch failed), the body\n * collapses to a single `- id = \"<id>\" -> null` line.\n * - **update**: when `oldContent` is null (no read endpoint for this\n * resource kind), the field diff is replaced with a placeholder\n * \"field diff unavailable\" line.\n * - **skip**: omitted from the output entirely, matching Terraform's\n * default of not showing no-change resources.\n */\nfunction renderBlock(action: SyncAction, tty: boolean): string[] {\n const lines: string[] = [];\n const blkPad = \" \".repeat(BLOCK_COL);\n const closePad = \" \".repeat(BLOCK_COL + 2);\n\n switch (action.kind) {\n case \"create\": {\n const header = `${blkPad}# ${action.path} will be created`;\n const opening = `${blkPad}+ resource \"${action.syncer.kind}\" \"${resourceName(action.path)}\" {`;\n lines.push(paint(header, A.bold, tty));\n lines.push(paint(opening, A.green, tty));\n\n const display: Record<string, unknown> = {\n id: KNOWN_AFTER_APPLY,\n ...(action.content as Record<string, unknown>),\n };\n if (action.repin) {\n // The executor POSTs this flow with the new revision id, not the\n // stale pin still in the file — render what will actually be sent.\n display.user_schema = action.repin.newId ?? KNOWN_AFTER_APPLY;\n }\n renderFields(display, \"+\", FIELD_COL, { tty, deleteMode: false }, lines);\n lines.push(`${closePad}}`);\n break;\n }\n\n case \"delete\": {\n const header = `${blkPad}# ${action.path} will be destroyed`;\n const opening = `${blkPad}- resource \"${action.syncer.kind}\" \"${resourceName(action.path)}\" {`;\n lines.push(paint(header, A.bold, tty));\n lines.push(paint(opening, A.red, tty));\n\n if (action.oldContent) {\n const display: Record<string, unknown> = {\n id: action.id,\n ...(action.oldContent as Record<string, unknown>),\n };\n renderFields(display, \"-\", FIELD_COL, { tty, deleteMode: true }, lines);\n } else {\n lines.push(paint(`${\" \".repeat(FIELD_COL)}- id = \"${action.id}\" -> null`, A.red, tty));\n }\n lines.push(`${closePad}}`);\n break;\n }\n\n case \"update\": {\n const headerSuffix = action.repin ? \" (re-pin user_schema)\" : \"\";\n const header = `${blkPad}# ${action.path} will be updated in-place${headerSuffix}`;\n const opening = `${blkPad}~ resource \"${action.syncer.kind}\" \"${resourceName(action.path)}\" {`;\n lines.push(paint(header, A.bold, tty));\n lines.push(paint(opening, A.yellow, tty));\n\n // A repin update ships with `user_schema` rewritten to the revision id\n // the revise mints (or already minted, for crash recovery) — render the\n // content the executor will actually PUT.\n const newContent = action.repin\n ? {\n ...normalized(action.syncer, action.content),\n user_schema: action.repin.newId ?? KNOWN_AFTER_APPLY,\n }\n : normalized(action.syncer, action.content);\n\n if (action.oldContent) {\n renderDiff(normalized(action.syncer, action.oldContent), newContent, FIELD_COL, tty, lines);\n } else if (action.repin) {\n lines.push(\n paint(\n `${\" \".repeat(FIELD_COL)}~ user_schema = \"${action.repin.previousId}\" -> ${action.repin.newId ? `\"${action.repin.newId}\"` : KNOWN_AFTER_APPLY}`,\n A.yellow,\n tty,\n ),\n );\n } else {\n lines.push(\n `${\" \".repeat(FIELD_COL)} # (field diff unavailable — no read endpoint for ${action.syncer.kind})`,\n );\n }\n lines.push(`${closePad}}`);\n break;\n }\n\n case \"revise\": {\n const header = `${blkPad}# ${action.path} will publish a new revision`;\n const opening = `${blkPad}~ resource \"${action.syncer.kind}\" \"${resourceName(action.path)}\" {`;\n lines.push(paint(header, A.bold, tty));\n lines.push(paint(opening, A.yellow, tty));\n\n if (action.oldContent) {\n const oldWithId: Record<string, unknown> = {\n id: action.previousId,\n ...normalized(action.syncer, action.oldContent),\n };\n const newWithId: Record<string, unknown> = {\n id: KNOWN_AFTER_APPLY,\n ...normalized(action.syncer, action.content),\n };\n renderDiff(oldWithId, newWithId, FIELD_COL, tty, lines);\n } else {\n lines.push(\n `${\" \".repeat(FIELD_COL)} # (field diff unavailable — no read endpoint for ${action.syncer.kind})`,\n );\n }\n lines.push(`${closePad}}`);\n if (action.affectedPaths.length > 0) {\n lines.push(\n paint(\n `${blkPad}# user_schema will be re-pinned to the new revision ${KNOWN_AFTER_APPLY} in:`,\n A.yellow,\n tty,\n ),\n );\n for (const path of action.affectedPaths) {\n lines.push(paint(`${blkPad}# - ${path}`, A.yellow, tty));\n }\n }\n break;\n }\n\n case \"skip\":\n break;\n }\n\n return lines;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//#region src/lib/user-schema/index.ts
|
|
2
|
+
/**
|
|
3
|
+
* Relative directory (from the project root) where local user-schema
|
|
4
|
+
* files live. Owned here so callers (`commands/*`, `sync/syncers.ts`)
|
|
5
|
+
* and tests share a single source of truth for the path; the runtime
|
|
6
|
+
* never depends on it directly because `lib/user-schema` does not touch
|
|
7
|
+
* the filesystem. The counterpart of `lib/flows`' `FLOWS_DIR`.
|
|
8
|
+
*/
|
|
9
|
+
const SCHEMAS_DIR = ".zitadel/schemas";
|
|
10
|
+
//#endregion
|
|
11
|
+
export { SCHEMAS_DIR as t };
|
|
12
|
+
|
|
13
|
+
//# sourceMappingURL=user-schema-DDz5-lX5.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"user-schema-DDz5-lX5.mjs","names":[],"sources":["../src/lib/user-schema/index.ts"],"sourcesContent":["/**\n * Public surface for the user-schema domain. Every caller outside this\n * module imports from here (not from individual files), the same\n * discipline as `lib/flows/`.\n *\n * **Source of truth.** The wire shape lives in\n * `@zitadel/api/generated/model` (orval-generated from the\n * OpenAPI spec). Callers that need the type import `CreateSchemaBody`\n * from there directly; callers that need the runtime validator import\n * the matching Zod schema from\n * `@zitadel/api/generated/endpoints/zitadelNextGen.zod`. This\n * module owns only CLI-specific concerns: the builder, the per-field\n * preset catalog, and the two `DEFAULT_*` URI constants.\n *\n * **Dependency rule.** No upward imports (`commands/`, `sync/`, etc.)\n * and no filesystem I/O. Reading and writing local files is the\n * caller's responsibility, served by `apps/cli/src/lib/json-dir.ts`\n * plus this module's {@link SCHEMAS_DIR} constant.\n */\nexport {\n DEFAULT_USER_META_SCHEMA,\n DEFAULT_USER_SCHEMA_ID,\n buildUserSchema,\n} from \"./build\";\n\n/**\n * Relative directory (from the project root) where local user-schema\n * files live. Owned here so callers (`commands/*`, `sync/syncers.ts`)\n * and tests share a single source of truth for the path; the runtime\n * never depends on it directly because `lib/user-schema` does not touch\n * the filesystem. The counterpart of `lib/flows`' `FLOWS_DIR`.\n */\nexport const SCHEMAS_DIR = \".zitadel/schemas\";\n"],"mappings":";;;;;;;;AAgCA,MAAa,cAAc"}
|
package/oclif.manifest.json
CHANGED
|
@@ -970,7 +970,112 @@
|
|
|
970
970
|
"commands",
|
|
971
971
|
"stop.mjs"
|
|
972
972
|
]
|
|
973
|
+
},
|
|
974
|
+
"schemas:list": {
|
|
975
|
+
"aliases": [],
|
|
976
|
+
"args": {},
|
|
977
|
+
"description": "List revisions of a user-schema by objectType.",
|
|
978
|
+
"flags": {
|
|
979
|
+
"json": {
|
|
980
|
+
"description": "Format output as json.",
|
|
981
|
+
"helpGroup": "GLOBAL",
|
|
982
|
+
"name": "json",
|
|
983
|
+
"allowNo": false,
|
|
984
|
+
"type": "boolean"
|
|
985
|
+
},
|
|
986
|
+
"cwd": {
|
|
987
|
+
"char": "c",
|
|
988
|
+
"description": "Project directory to operate on.",
|
|
989
|
+
"name": "cwd",
|
|
990
|
+
"hasDynamicHelp": false,
|
|
991
|
+
"multiple": false,
|
|
992
|
+
"type": "option"
|
|
993
|
+
},
|
|
994
|
+
"server": {
|
|
995
|
+
"char": "s",
|
|
996
|
+
"description": "Override the resolved server URL.",
|
|
997
|
+
"name": "server",
|
|
998
|
+
"hasDynamicHelp": false,
|
|
999
|
+
"multiple": false,
|
|
1000
|
+
"type": "option"
|
|
1001
|
+
},
|
|
1002
|
+
"non-interactive": {
|
|
1003
|
+
"char": "n",
|
|
1004
|
+
"description": "Disable prompts. Required when scripting or running as an agent.",
|
|
1005
|
+
"name": "non-interactive",
|
|
1006
|
+
"allowNo": false,
|
|
1007
|
+
"type": "boolean"
|
|
1008
|
+
},
|
|
1009
|
+
"force": {
|
|
1010
|
+
"char": "f",
|
|
1011
|
+
"description": "Overwrite protected files on conflict.",
|
|
1012
|
+
"name": "force",
|
|
1013
|
+
"allowNo": false,
|
|
1014
|
+
"type": "boolean"
|
|
1015
|
+
},
|
|
1016
|
+
"dry-run": {
|
|
1017
|
+
"description": "Preview without mutating files or the platform.",
|
|
1018
|
+
"name": "dry-run",
|
|
1019
|
+
"allowNo": false,
|
|
1020
|
+
"type": "boolean"
|
|
1021
|
+
},
|
|
1022
|
+
"verbose": {
|
|
1023
|
+
"description": "Verbose logging.",
|
|
1024
|
+
"name": "verbose",
|
|
1025
|
+
"allowNo": false,
|
|
1026
|
+
"type": "boolean"
|
|
1027
|
+
},
|
|
1028
|
+
"debug": {
|
|
1029
|
+
"description": "Debug logging.",
|
|
1030
|
+
"name": "debug",
|
|
1031
|
+
"allowNo": false,
|
|
1032
|
+
"type": "boolean"
|
|
1033
|
+
},
|
|
1034
|
+
"telemetry": {
|
|
1035
|
+
"description": "Send anonymous usage analytics. Disable with --no-telemetry.",
|
|
1036
|
+
"name": "telemetry",
|
|
1037
|
+
"allowNo": true,
|
|
1038
|
+
"type": "boolean"
|
|
1039
|
+
},
|
|
1040
|
+
"object-type": {
|
|
1041
|
+
"char": "t",
|
|
1042
|
+
"description": "Filter revisions by objectType (e.g. human-user).",
|
|
1043
|
+
"name": "object-type",
|
|
1044
|
+
"required": true,
|
|
1045
|
+
"hasDynamicHelp": false,
|
|
1046
|
+
"multiple": false,
|
|
1047
|
+
"type": "option"
|
|
1048
|
+
},
|
|
1049
|
+
"environment": {
|
|
1050
|
+
"char": "e",
|
|
1051
|
+
"description": "Target environment (default: development).",
|
|
1052
|
+
"name": "environment",
|
|
1053
|
+
"hasDynamicHelp": false,
|
|
1054
|
+
"multiple": false,
|
|
1055
|
+
"options": [
|
|
1056
|
+
"development",
|
|
1057
|
+
"preview",
|
|
1058
|
+
"production"
|
|
1059
|
+
],
|
|
1060
|
+
"type": "option"
|
|
1061
|
+
}
|
|
1062
|
+
},
|
|
1063
|
+
"hasDynamicHelp": false,
|
|
1064
|
+
"hiddenAliases": [],
|
|
1065
|
+
"id": "schemas:list",
|
|
1066
|
+
"pluginAlias": "@zitadel/cli",
|
|
1067
|
+
"pluginName": "@zitadel/cli",
|
|
1068
|
+
"pluginType": "core",
|
|
1069
|
+
"strict": true,
|
|
1070
|
+
"enableJsonFlag": true,
|
|
1071
|
+
"isESM": true,
|
|
1072
|
+
"relativePath": [
|
|
1073
|
+
"dist",
|
|
1074
|
+
"commands",
|
|
1075
|
+
"schemas",
|
|
1076
|
+
"list.mjs"
|
|
1077
|
+
]
|
|
973
1078
|
}
|
|
974
1079
|
},
|
|
975
|
-
"version": "0.1.0-alpha.
|
|
1080
|
+
"version": "0.1.0-alpha.15"
|
|
976
1081
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zitadel/cli",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.15",
|
|
4
4
|
"description": "Agent-friendly Zitadel CLI",
|
|
5
5
|
"homepage": "https://github.com/zitadel/nextgen/tree/main/apps/cli#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -60,8 +60,9 @@
|
|
|
60
60
|
"safe-stable-stringify": "^2.5.0",
|
|
61
61
|
"zod": "^4.3.6",
|
|
62
62
|
"picocolors": "^1.1.1",
|
|
63
|
-
"@zitadel/
|
|
64
|
-
"@zitadel/
|
|
63
|
+
"@zitadel/server": "0.1.0-alpha.15",
|
|
64
|
+
"@zitadel/config": "0.1.0-alpha.15",
|
|
65
|
+
"@zitadel/api": "0.1.0-alpha.15"
|
|
65
66
|
},
|
|
66
67
|
"devDependencies": {
|
|
67
68
|
"@types/node": "^25.6.0",
|
|
@@ -69,8 +70,8 @@
|
|
|
69
70
|
"oclif": "^4.17.46",
|
|
70
71
|
"tsdown": "^0.21.10",
|
|
71
72
|
"vitest": "^3.0.0",
|
|
72
|
-
"@zitadel/
|
|
73
|
-
"@zitadel/
|
|
73
|
+
"@zitadel/api-mock": "0.0.0",
|
|
74
|
+
"@zitadel/sdk-next": "0.1.0-alpha.15"
|
|
74
75
|
},
|
|
75
76
|
"scripts": {
|
|
76
77
|
"build": "tsdown",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"oclif-BoUVygsZ.mjs","names":["DISABLED_VALUES","delay"],"sources":["../src/lib/errors.ts","../src/lib/json.ts","../src/lib/paths.ts","../src/lib/public-cli.ts","../src/lib/local-server/runtime.ts","../src/lib/server.ts","../src/lib/telemetry/config.ts","../src/lib/telemetry/consent.ts","../src/lib/telemetry/identity.ts","../src/lib/telemetry/util.ts","../src/lib/telemetry/index.ts","../src/lib/telemetry/dimensions/env-flag.ts","../src/lib/telemetry/dimensions/ci-flag.ts","../src/lib/telemetry/dimensions/ci-provider.ts","../src/lib/telemetry/dimensions/country.ts","../src/lib/telemetry/dimensions/host-agent.ts","../src/lib/telemetry/dimensions/invocation-channel.ts","../src/lib/telemetry/dimensions/operating-system.ts","../src/lib/oclif/server-kind.ts","../src/lib/oclif/command-telemetry.ts","../src/lib/oclif/base.ts"],"sourcesContent":["import { ApiError } from \"@zitadel/api/runtime/fetch\";\n\n/**\n * Closed set of failure categories the CLI can surface. Every error the\n * user sees is funnelled into one of these so messaging, exit codes, and\n * machine-readable output stay consistent regardless of where the failure\n * originated.\n */\nexport type ZitadelErrorCode =\n | \"E_ALREADY_INIT\"\n | \"E_FRAMEWORK_NOT_DETECTED\"\n | \"E_UNSUPPORTED_PROJECT_SHAPE\"\n | \"E_NETWORK\"\n | \"E_AUTH\"\n | \"E_CONFLICT\"\n | \"E_LOCAL_SERVER_NOT_RUNNING\"\n | \"E_PORT_IN_USE\"\n | \"E_VALIDATION\"\n | \"E_NOT_IMPLEMENTED\";\n\n/**\n * Maps each {@link ZitadelErrorCode} to the process exit code the CLI\n * returns. The table is the single source of truth for exit semantics so\n * scripts and CI can branch on stable, documented numbers.\n */\nexport const EXIT_CODES: Record<ZitadelErrorCode, number> = {\n E_ALREADY_INIT: 0,\n E_FRAMEWORK_NOT_DETECTED: 3,\n E_UNSUPPORTED_PROJECT_SHAPE: 3,\n E_NETWORK: 4,\n E_AUTH: 1,\n E_CONFLICT: 5,\n E_LOCAL_SERVER_NOT_RUNNING: 4,\n E_PORT_IN_USE: 5,\n E_VALIDATION: 3,\n E_NOT_IMPLEMENTED: 2,\n};\n\n/**\n * Optional, user-facing extras attached to a {@link ZitadelError}. Kept\n * separate from the message so the renderer can present a hint, suggested\n * follow-up commands, and structured details independently (e.g. as JSON\n * fields) rather than concatenating everything into one string.\n */\nexport type ZitadelErrorOptions = {\n hint?: string;\n nextCommands?: string[];\n details?: unknown;\n};\n\n/**\n * The CLI's single error type. Carries a {@link ZitadelErrorCode} so the\n * top-level handler can derive an exit code and structured output without\n * pattern-matching on messages. Throwing this anywhere guarantees the user\n * gets a categorised, hint-bearing failure instead of a raw stack trace.\n */\nexport class ZitadelError extends Error {\n readonly code: ZitadelErrorCode;\n readonly hint?: string;\n readonly nextCommands?: string[];\n readonly details?: unknown;\n\n constructor(code: ZitadelErrorCode, message: string, opts: ZitadelErrorOptions = {}) {\n super(message);\n this.name = \"ZitadelError\";\n this.code = code;\n this.hint = opts.hint;\n this.nextCommands = opts.nextCommands;\n this.details = opts.details;\n }\n\n get exitCode(): number {\n return EXIT_CODES[this.code] ?? 1;\n }\n}\n\n/**\n * Normalises any thrown value into a {@link ZitadelError}. Inspection is\n * ordered most-specific-first (already-normalised, then errno/filesystem,\n * network, Zod-like, generic `Error`, then a catch-all) so the most\n * actionable category and hint win. This is the boundary that lets the rest\n * of the CLI `throw` plain errors yet still produce consistent, categorised\n * output. The original error shape is preserved under `details` for\n * debugging without leaking it into the user-facing message.\n */\nexport function toZitadelError(error: unknown): ZitadelError {\n if (error instanceof ZitadelError) {\n return error;\n }\n\n if (error instanceof ApiError) {\n // `401`/`403` → bad or missing project secret; `5xx` → transport or\n // server fault; everything else 4xx → the body the CLI sent was\n // rejected (validation, conflict, not-found, …).\n const code: ZitadelErrorCode =\n error.status === 401 || error.status === 403\n ? \"E_AUTH\"\n : error.status >= 500\n ? \"E_NETWORK\"\n : \"E_VALIDATION\";\n return new ZitadelError(code, error.message, {\n details: { status: error.status, url: error.url, body: error.body },\n });\n }\n\n if (isErrnoException(error)) {\n const details = { original: pickErrorShape(error) };\n if (error.code === \"EACCES\" || error.code === \"EPERM\") {\n return new ZitadelError(\"E_AUTH\", `Permission denied: ${error.message}`, {\n hint: \"Check file permissions or run with the right user.\",\n details,\n });\n }\n if (error.code === \"EEXIST\") {\n return new ZitadelError(\"E_CONFLICT\", error.message, {\n hint: \"A file already exists. Use --force to overwrite or remove it first.\",\n details,\n });\n }\n if (error.code === \"ENOENT\") {\n return new ZitadelError(\"E_VALIDATION\", error.message, {\n hint: \"A required file or directory is missing.\",\n details,\n });\n }\n }\n\n if (isNetworkError(error)) {\n return new ZitadelError(\"E_NETWORK\", errorMessage(error), {\n hint: \"Check your connection, ZITADEL_API_BASE, or the configured server URL.\",\n details: { original: pickErrorShape(error as Error) },\n });\n }\n\n if (isZodLikeError(error)) {\n return new ZitadelError(\"E_VALIDATION\", errorMessage(error), {\n details: { issues: (error as { issues: unknown }).issues },\n });\n }\n\n if (error instanceof Error) {\n return new ZitadelError(\"E_VALIDATION\", error.message, {\n details: { original: pickErrorShape(error) },\n });\n }\n\n return new ZitadelError(\"E_VALIDATION\", \"Unknown error\", { details: error });\n}\n\nfunction isErrnoException(error: unknown): error is NodeJS.ErrnoException {\n return error instanceof Error && typeof (error as NodeJS.ErrnoException).code === \"string\";\n}\n\nfunction isNetworkError(error: unknown): boolean {\n if (!(error instanceof Error)) {\n return false;\n }\n if (\n error.name === \"TypeError\" &&\n /fetch failed|network|ECONNREFUSED|ENOTFOUND/i.test(error.message)\n ) {\n return true;\n }\n const cause = (error as { cause?: unknown }).cause;\n if (cause && typeof cause === \"object\" && \"code\" in cause) {\n const code = String((cause as { code: unknown }).code);\n return /^(ECONNREFUSED|ECONNRESET|ENOTFOUND|ETIMEDOUT|EAI_AGAIN|UND_ERR)/i.test(code);\n }\n return false;\n}\n\nfunction isZodLikeError(error: unknown): boolean {\n return (\n typeof error === \"object\" &&\n error !== null &&\n \"issues\" in error &&\n Array.isArray((error as { issues: unknown }).issues)\n );\n}\n\nfunction errorMessage(error: unknown): string {\n if (error instanceof Error) {\n return error.message;\n }\n if (typeof error === \"string\") {\n return error;\n }\n return String(error);\n}\n\nfunction pickErrorShape(error: Error): Record<string, unknown> {\n return {\n name: error.name,\n message: error.message,\n code: (error as NodeJS.ErrnoException).code,\n };\n}\n","import { stringify } from \"safe-stable-stringify\";\n\n/**\n * Serialise a value to pretty-printed JSON with object keys sorted at every\n * depth. Determinism is the point: managed files written by the CLI must be\n * byte-stable across runs so diffs stay clean and content hashes don't churn\n * when only key ordering would otherwise differ. Delegates the deterministic\n * sort to `safe-stable-stringify`, matching `JSON.stringify(value, null, 2)`\n * formatting. The `?? \"null\"` only applies to `undefined`/function inputs,\n * which the CLI never serialises.\n */\nexport function stableStringify(value: unknown): string {\n return stringify(value, null, 2) ?? \"null\";\n}\n\n/**\n * Parse `contents` as JSON and assert the root is a plain object (not an\n * array or scalar). The CLI's config and secret files are always objects, so\n * this guards callers from the `JSON.parse` return type of `any` and produces\n * a `path`-qualified error message pointing at the offending file.\n */\nexport function parseJsonObject(contents: string, path: string): Record<string, unknown> {\n const value = JSON.parse(contents) as unknown;\n if (!value || typeof value !== \"object\" || Array.isArray(value)) {\n throw new Error(`${path} must contain a JSON object`);\n }\n return value as Record<string, unknown>;\n}\n\n/**\n * Narrows an unknown value to a plain (non-array, non-null) object. Shared by\n * the commands and the file-writer that walk parsed JSON, so the predicate\n * isn't reimplemented per call site.\n */\nexport function isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n","import { resolve } from \"node:path\";\n\n/**\n * Resolve the working directory the CLI should operate against, defaulting to\n * the process CWD when no `--cwd` override is given. Always returns an\n * absolute path so downstream `join`/`readFile` calls are unaffected by later\n * `process.chdir` or relative-path ambiguity.\n */\nexport function resolveCwd(cwd?: string): string {\n return resolve(cwd ?? process.cwd());\n}\n\n/**\n * Sentinel comment stamped at the top of every file the CLI generates and\n * owns. Commands like `doctor` and `eject` look for this marker to decide\n * whether a file is safe to touch; the trailing `v1` lets the format evolve\n * without mistaking newer managed files for hand-edited ones.\n */\nexport const MANAGED_MARKER = \"// zitadel-cli: managed-file v1\";\n","const CLI_PACKAGE_NAME = \"@zitadel/cli\";\n\nexport function npmDistTagForCliVersion(cliVersion: string): string {\n const normalized = cliVersion.trim().replace(/^v/, \"\");\n const match = normalized.match(/^\\d+\\.\\d+\\.\\d+-([0-9A-Za-z][0-9A-Za-z-]*)/);\n return match?.[1] ?? \"latest\";\n}\n\nexport function npmSelectorForCliVersion(cliVersion: string): string {\n const normalized = cliVersion.trim().replace(/^v/, \"\");\n if (/^\\d+\\.\\d+\\.\\d+-alpha\\.\\d+$/.test(normalized)) {\n return normalized;\n }\n return npmDistTagForCliVersion(normalized);\n}\n\nexport function publicCliCommand(args: string, cliVersion: string): string {\n const prefix = `npx ${CLI_PACKAGE_NAME}@${npmSelectorForCliVersion(cliVersion)}`;\n return args.length > 0 ? `${prefix} ${args}` : prefix;\n}\n\nexport function normalizePublicCliCommand(command: string, cliVersion: string): string {\n if (command === \"zitadel\") {\n return publicCliCommand(\"\", cliVersion);\n }\n if (command.startsWith(\"zitadel \")) {\n return publicCliCommand(command.slice(\"zitadel \".length), cliVersion);\n }\n return command;\n}\n\nexport function normalizePublicCliCommands(\n commands: ReadonlyArray<string> | undefined,\n cliVersion: string,\n): string[] | undefined {\n return commands?.map((command) => normalizePublicCliCommand(command, cliVersion));\n}\n","import { createHash } from \"node:crypto\";\nimport { access, mkdir, readFile, rm, stat, writeFile } from \"node:fs/promises\";\nimport { constants } from \"node:fs\";\nimport { dirname, join, resolve } from \"node:path\";\n\nimport { ZitadelError } from \"../errors\";\nimport { isObject, parseJsonObject } from \"../json\";\n\nexport const LOCAL_SERVER_IMAGE_NAME = \"ghcr.io/zitadel/nextgen\";\nexport const DEFAULT_LOCAL_SERVER_IMAGE = `${LOCAL_SERVER_IMAGE_NAME}:latest`;\nexport const DEFAULT_LOCAL_SERVER_PORT = 8080;\nexport const DEFAULT_LOCAL_SERVER_URL = \"http://localhost:8080\";\nexport const LOCAL_RUNTIME_DIR = \".zitadel/local\";\nexport const LOCAL_DATA_DIR = \".zitadel/local/nextgen-data\";\nexport const LOCAL_RUNTIME_FILE = \".zitadel/local/runtime.json\";\nexport const LOCAL_SERVER_LOG_FILE = \".zitadel/local/server.log\";\nexport const LOCAL_CONTAINER_PASSWD_FILE = \".zitadel/local/container-passwd\";\nexport const LOCAL_CONTAINER_GROUP_FILE = \".zitadel/local/container-group\";\nexport const CONTAINER_DATA_DIR = \"/var/lib/zitadel/nextgen-data\";\nexport const CONTAINER_HTTP_PORT = 8080;\n\nexport type RuntimeBackend = \"binary\" | \"docker\";\n\ntype RuntimeMetadataBase = {\n schema_version: 1;\n backend: RuntimeBackend;\n port: number;\n server_url: string;\n data_dir: string;\n created_at: string;\n cli_version: string;\n};\n\nexport type BinaryRuntimeMetadata = RuntimeMetadataBase & {\n backend: \"binary\";\n pid: number;\n command: string;\n log_path: string;\n server_package: string;\n server_version: string;\n};\n\nexport type DockerRuntimeMetadata = RuntimeMetadataBase & {\n backend: \"docker\";\n container_name: string;\n container_id: string;\n image: string;\n};\n\nexport type RuntimeMetadata = BinaryRuntimeMetadata | DockerRuntimeMetadata;\n\nexport type LocalRuntimePaths = {\n runtimeDir: string;\n dataDir: string;\n runtimeFile: string;\n logFile: string;\n containerPasswdFile: string;\n containerGroupFile: string;\n};\n\nexport type WritablePathProbe = {\n targetPath: string;\n checkedPath: string;\n};\n\nexport type ContainerIdentity = {\n uid: number;\n gid: number;\n passwdFile: string;\n groupFile: string;\n};\n\nexport function localRuntimePaths(cwd: string): LocalRuntimePaths {\n return {\n runtimeDir: join(cwd, LOCAL_RUNTIME_DIR),\n dataDir: join(cwd, LOCAL_DATA_DIR),\n runtimeFile: join(cwd, LOCAL_RUNTIME_FILE),\n logFile: join(cwd, LOCAL_SERVER_LOG_FILE),\n containerPasswdFile: join(cwd, LOCAL_CONTAINER_PASSWD_FILE),\n containerGroupFile: join(cwd, LOCAL_CONTAINER_GROUP_FILE),\n };\n}\n\nexport function localContainerName(cwd: string): string {\n const hash = createHash(\"sha256\").update(resolve(cwd)).digest(\"hex\").slice(0, 12);\n return `zitadel-server-${hash}`;\n}\n\nexport function localServerUrl(port: number): string {\n return `http://localhost:${port}`;\n}\n\nexport function defaultLocalServerImageForCliVersion(cliVersion: string): string {\n const normalized = cliVersion.trim().replace(/^v/, \"\");\n if (/^\\d+\\.\\d+\\.\\d+-alpha\\.\\d+$/.test(normalized)) {\n return `${LOCAL_SERVER_IMAGE_NAME}:${normalized}`;\n }\n return DEFAULT_LOCAL_SERVER_IMAGE;\n}\n\nexport async function ensureLocalState(cwd: string): Promise<LocalRuntimePaths> {\n const paths = localRuntimePaths(cwd);\n await mkdir(paths.dataDir, { recursive: true, mode: 0o700 });\n await appendGitignoreEntry(cwd, `${LOCAL_RUNTIME_DIR}/`);\n return paths;\n}\n\nexport async function assertLocalStateWritable(cwd: string): Promise<WritablePathProbe> {\n const paths = localRuntimePaths(cwd);\n const checkedPath = await nearestExistingDirectory(paths.dataDir);\n await access(checkedPath, constants.W_OK);\n return { targetPath: paths.dataDir, checkedPath };\n}\n\nexport async function ensureContainerIdentity(\n cwd: string,\n user: { uid?: number; gid?: number },\n): Promise<ContainerIdentity | undefined> {\n if (user.uid === undefined || user.uid <= 0) {\n return undefined;\n }\n const gid = user.gid ?? user.uid;\n const paths = localRuntimePaths(cwd);\n await mkdir(paths.runtimeDir, { recursive: true, mode: 0o700 });\n await writeFile(\n paths.containerPasswdFile,\n [\n \"root:x:0:0:root:/root:/bin/sh\",\n \"nonroot:x:65532:65532:nonroot:/nonexistent:/usr/sbin/nologin\",\n `zitadel-local:x:${String(user.uid)}:${String(gid)}:Zitadel local user:/tmp:/usr/sbin/nologin`,\n \"\",\n ].join(\"\\n\"),\n { mode: 0o644 },\n );\n await writeFile(\n paths.containerGroupFile,\n [\n \"root:x:0:\",\n \"nonroot:x:65532:\",\n `zitadel-local:x:${String(gid)}:`,\n \"\",\n ].join(\"\\n\"),\n { mode: 0o644 },\n );\n return {\n uid: user.uid,\n gid,\n passwdFile: paths.containerPasswdFile,\n groupFile: paths.containerGroupFile,\n };\n}\n\nexport async function readRuntimeMetadata(cwd: string): Promise<RuntimeMetadata | undefined> {\n const paths = localRuntimePaths(cwd);\n let raw: string;\n try {\n raw = await readFile(paths.runtimeFile, \"utf8\");\n } catch (error) {\n if (isErrno(error, \"ENOENT\")) {\n return undefined;\n }\n throw error;\n }\n\n const parsed = parseJsonObject(raw, LOCAL_RUNTIME_FILE);\n return normalizeRuntimeMetadata(parsed);\n}\n\nexport async function writeRuntimeMetadata(cwd: string, metadata: RuntimeMetadata): Promise<void> {\n const paths = localRuntimePaths(cwd);\n await mkdir(paths.runtimeDir, { recursive: true, mode: 0o700 });\n await writeFile(paths.runtimeFile, `${JSON.stringify(metadata, null, 2)}\\n`, { mode: 0o600 });\n}\n\nexport async function removeRuntimeMetadata(cwd: string): Promise<void> {\n await rm(localRuntimePaths(cwd).runtimeFile, { force: true });\n}\n\nexport async function removeLocalData(cwd: string): Promise<void> {\n await rm(localRuntimePaths(cwd).dataDir, { recursive: true, force: true });\n}\n\nexport async function checkLocalServerHealth(serverUrl: string, timeoutMs = 1500): Promise<boolean> {\n try {\n const healthUrl = new URL(\"/healthz\", serverUrl);\n const response = await fetch(healthUrl, { signal: AbortSignal.timeout(timeoutMs) });\n return response.ok;\n } catch {\n return false;\n }\n}\n\nexport async function resolveLocalServer(cwd: string): Promise<string> {\n const runtime = await readRuntimeMetadata(cwd);\n if (runtime) {\n if (await checkLocalServerHealth(runtime.server_url)) {\n return runtime.server_url;\n }\n throw localServerNotRunning(runtime.server_url);\n }\n\n if (await checkLocalServerHealth(DEFAULT_LOCAL_SERVER_URL)) {\n return DEFAULT_LOCAL_SERVER_URL;\n }\n throw localServerNotRunning(DEFAULT_LOCAL_SERVER_URL);\n}\n\nexport function localServerNotRunning(serverUrl: string): ZitadelError {\n return new ZitadelError(\"E_LOCAL_SERVER_NOT_RUNNING\", \"Local Zitadel server is not running\", {\n hint: `No healthy local server responded at ${serverUrl}.`,\n nextCommands: [\"zitadel start\"],\n details: { server_url: serverUrl },\n });\n}\n\nasync function appendGitignoreEntry(cwd: string, entry: string): Promise<void> {\n const path = join(cwd, \".gitignore\");\n let existing = \"\";\n try {\n existing = await readFile(path, \"utf8\");\n } catch (error) {\n if (!isErrno(error, \"ENOENT\")) {\n throw error;\n }\n }\n\n const lines = existing.split(/\\r?\\n/).map((line) => line.trim());\n if (lines.includes(entry)) {\n return;\n }\n const prefix = existing.length === 0 || existing.endsWith(\"\\n\") ? \"\" : \"\\n\";\n await writeFile(path, `${existing}${prefix}${entry}\\n`);\n}\n\nfunction normalizeRuntimeMetadata(input: Record<string, unknown>): RuntimeMetadata {\n if (\n input.schema_version !== 1 ||\n typeof input.port !== \"number\" ||\n !isValidPort(input.port) ||\n typeof input.server_url !== \"string\" ||\n !isValidServerUrl(input.server_url, input.port) ||\n typeof input.data_dir !== \"string\" ||\n typeof input.created_at !== \"string\" ||\n typeof input.cli_version !== \"string\"\n ) {\n throw malformedRuntime(input);\n }\n\n const backend = input.backend === undefined ? \"docker\" : input.backend;\n const base = {\n schema_version: 1 as const,\n port: input.port,\n server_url: input.server_url,\n data_dir: input.data_dir,\n created_at: input.created_at,\n cli_version: input.cli_version,\n };\n\n if (backend === \"binary\") {\n if (\n typeof input.pid !== \"number\" ||\n !Number.isInteger(input.pid) ||\n input.pid <= 0 ||\n typeof input.command !== \"string\" ||\n typeof input.log_path !== \"string\" ||\n typeof input.server_package !== \"string\" ||\n typeof input.server_version !== \"string\"\n ) {\n throw malformedRuntime(input);\n }\n return {\n ...base,\n backend: \"binary\",\n pid: input.pid,\n command: input.command,\n log_path: input.log_path,\n server_package: input.server_package,\n server_version: input.server_version,\n };\n }\n\n if (\n backend !== \"docker\" ||\n typeof input.container_name !== \"string\" ||\n typeof input.container_id !== \"string\" ||\n typeof input.image !== \"string\"\n ) {\n throw malformedRuntime(input);\n }\n return {\n ...base,\n backend: \"docker\",\n container_name: input.container_name,\n container_id: input.container_id,\n image: input.image,\n };\n}\n\nexport async function assertWritableDirectory(path: string): Promise<void> {\n await mkdir(path, { recursive: true, mode: 0o700 });\n await access(path, constants.W_OK);\n}\n\nasync function nearestExistingDirectory(path: string): Promise<string> {\n let current = path;\n while (true) {\n try {\n const info = await stat(current);\n if (!info.isDirectory()) {\n throw new Error(`${current} exists but is not a directory`);\n }\n return current;\n } catch (error) {\n if (!isErrno(error, \"ENOENT\")) {\n throw error;\n }\n const parent = dirname(current);\n if (parent === current) {\n throw error;\n }\n current = parent;\n }\n }\n}\n\nfunction isErrno(error: unknown, code: string): boolean {\n return (\n typeof error === \"object\" &&\n error !== null &&\n \"code\" in error &&\n (error as { code?: unknown }).code === code\n );\n}\n\nexport function runtimeSummary(metadata: RuntimeMetadata | undefined): Record<string, unknown> {\n if (!metadata) {\n return { configured: false };\n }\n const base = {\n configured: true,\n backend: metadata.backend,\n port: metadata.port,\n server_url: metadata.server_url,\n data_dir: metadata.data_dir,\n created_at: metadata.created_at,\n };\n if (metadata.backend === \"binary\") {\n return {\n ...base,\n pid: metadata.pid,\n command: metadata.command,\n log_path: metadata.log_path,\n server_package: metadata.server_package,\n server_version: metadata.server_version,\n };\n }\n return {\n ...base,\n container_name: metadata.container_name,\n container_id: metadata.container_id,\n image: metadata.image,\n };\n}\n\nexport function isRuntimeObject(value: unknown): value is RuntimeMetadata {\n return isObject(value) && value.schema_version === 1;\n}\n\nfunction isValidPort(value: number): boolean {\n return Number.isInteger(value) && value >= 1 && value <= 65_535;\n}\n\nfunction isValidServerUrl(value: string, port: number): boolean {\n try {\n const url = new URL(value);\n return (\n (url.protocol === \"http:\" || url.protocol === \"https:\") &&\n url.hostname.length > 0 &&\n explicitUrlPort(value) === port\n );\n } catch {\n return false;\n }\n}\n\nfunction explicitUrlPort(value: string): number | undefined {\n const match = value.match(/^[a-z][a-z\\d+\\-.]*:\\/\\/(?:\\[[^\\]]+\\]|[^/?#:]+):(\\d+)(?:[/?#]|$)/i);\n if (!match) {\n return undefined;\n }\n const port = Number(match[1]);\n return isValidPort(port) ? port : undefined;\n}\n\nfunction malformedRuntime(input: Record<string, unknown>): ZitadelError {\n return new ZitadelError(\"E_VALIDATION\", `${LOCAL_RUNTIME_FILE} is malformed`, {\n hint: \"Run `zitadel reset --force`, then `zitadel start`.\",\n nextCommands: [\"zitadel reset --force\", \"zitadel start\"],\n details: input,\n });\n}\n","import { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { ZitadelError } from \"./errors\";\nimport { resolveLocalServer } from \"./local-server/runtime\";\nimport { isObject, parseJsonObject } from \"./json\";\n\n/**\n * Server URL used when nothing else resolves. Also surfaced in hints and\n * the interactive setup prompt as the suggested value, so it is exported\n * rather than kept private.\n */\nexport const DEFAULT_SERVER = \"https://api.zitadel.cloud\";\n\n/**\n * The resolved target server plus the source it came from. `origin` is\n * retained (not just the value) so callers can report *why* a server was\n * chosen and so the precedence order stays auditable.\n */\nexport type ResolvedServer = {\n value: string;\n origin: \"flag\" | \"env\" | \"config-env\" | \"config-top\" | \"default\" | \"local\";\n};\n\n/**\n * Inputs to {@link resolveServer}. Passed explicitly (cwd, env) rather\n * than read from globals so resolution is pure and testable. `serverFlag`\n * and `environment` come from the parsed CLI invocation.\n */\nexport type ResolveServerInput = {\n cwd: string;\n env: NodeJS.ProcessEnv;\n serverFlag?: string;\n environment?: string;\n};\n\n/**\n * Resolves which server the CLI should target, applying a fixed\n * precedence: explicit `--server` flag, then `ZITADEL_API_BASE`, then the\n * selected environment block in `zitadel.json`, then the config's\n * top-level `server`, falling back to {@link DEFAULT_SERVER}. Every\n * candidate is validated to a normalised origin; an invalid URL throws a\n * `ZitadelError` rather than silently falling through.\n */\nexport async function resolveServer(input: ResolveServerInput): Promise<ResolvedServer> {\n if (input.serverFlag) {\n return validate(input.cwd, { value: input.serverFlag, origin: \"flag\" });\n }\n const envValue = input.env.ZITADEL_API_BASE;\n if (envValue) {\n return validate(input.cwd, { value: envValue, origin: \"env\" });\n }\n\n const config = await readConfig(input.cwd);\n if (config) {\n const envBranch = readEnvServer(config, input.environment);\n if (envBranch) {\n return validate(input.cwd, { value: envBranch, origin: \"config-env\" });\n }\n if (typeof config.server === \"string\") {\n return validate(input.cwd, { value: config.server, origin: \"config-top\" });\n }\n }\n\n return { value: DEFAULT_SERVER, origin: \"default\" };\n}\n\nasync function validate(cwd: string, resolved: ResolvedServer): Promise<ResolvedServer> {\n if (resolved.value === \"local\") {\n return { value: await resolveLocalServer(cwd), origin: \"local\" };\n }\n\n try {\n const url = new URL(resolved.value);\n if (url.protocol !== \"https:\" && url.protocol !== \"http:\") {\n throw new ZitadelError(\"E_VALIDATION\", `Server URL must use http(s): ${resolved.value}`, {\n hint: `Set \"server\" in zitadel.json to a URL like ${DEFAULT_SERVER}.`,\n });\n }\n return { value: url.origin, origin: resolved.origin };\n } catch (error) {\n if (error instanceof ZitadelError) {\n throw error;\n }\n throw new ZitadelError(\"E_VALIDATION\", `Invalid server \"${resolved.value}\"`, {\n hint: `Use a URL like ${DEFAULT_SERVER}.`,\n details: { origin: resolved.origin },\n });\n }\n}\n\nasync function readConfig(cwd: string): Promise<Record<string, unknown> | undefined> {\n try {\n const contents = await readFile(join(cwd, \"zitadel.json\"), \"utf8\");\n return parseJsonObject(contents, \"zitadel.json\");\n } catch (error) {\n if (\n typeof error === \"object\" &&\n error !== null &&\n \"code\" in error &&\n (error as { code?: string }).code === \"ENOENT\"\n ) {\n return undefined;\n }\n throw error;\n }\n}\n\nfunction readEnvServer(\n config: Record<string, unknown>,\n environment: string | undefined,\n): string | undefined {\n if (!environment) {\n return undefined;\n }\n const envs = config.environments;\n if (!isObject(envs)) {\n return undefined;\n }\n const branch = envs[environment];\n if (!isObject(branch)) {\n return undefined;\n }\n return typeof branch.server === \"string\" ? branch.server : undefined;\n}\n","/**\n * Resolves the Mixpanel ingestion token and API host for a CLI invocation.\n *\n * The token is a *write-only* project token: it can ingest events but cannot\n * read data back, so — unlike the project service-key — it is safe to ship\n * inside the published CLI. This mirrors how Next.js, Astro, and other dev\n * tools embed their telemetry token, and is the only workable model for a CLI\n * (we cannot ask end users to supply one). It is intentionally not a secret.\n *\n * Dev and prod are separate Mixpanel projects (the skill's Phase 2 rule: never\n * track dev traffic into the production project). By default the channel comes\n * from a build-time stamp (see {@link resolveChannel}), so the published CLI\n * routes real user traffic to production without any per-user env var while\n * source/test runs stay on dev — but a runtime `ZITADEL_TELEMETRY_ENV` or\n * `ZITADEL_TELEMETRY_BUILD_CHANNEL` overrides the stamp, and\n * `ZITADEL_TELEMETRY_TOKEN` overrides the token outright.\n */\n\n/**\n * Development project token. Safe to commit (write-only ingestion key). Used\n * when running from source or any non-production build.\n */\nconst DEV_TELEMETRY_TOKEN = \"0fb432b08a9797b87b0eebcbee11706e\";\n\n/**\n * Production project token. Used by the published CLI (the build stamps the\n * production channel) and any `ZITADEL_TELEMETRY_ENV=production` run. Write-only\n * ingestion key, like the dev token — safe to commit.\n */\nconst PROD_TELEMETRY_TOKEN = \"f56fd7315ccd614fba8eecb2a8966152\";\n\n/** Mixpanel API hosts by data-residency region. */\nconst HOSTS = {\n us: \"api.mixpanel.com\",\n eu: \"api-eu.mixpanel.com\",\n} as const;\n\nexport type TelemetryRegion = keyof typeof HOSTS;\n\ndeclare const __ZITADEL_TELEMETRY_CHANNEL__: string | undefined;\n\n/**\n * Channel stamped into the bundle at build time. tsdown's `define` always\n * replaces the bare `__ZITADEL_TELEMETRY_CHANNEL__` identifier — with\n * `\"development\"` by default and `\"production\"` only in the release build — so\n * the shipped CLI routes to the right project with no per-user env var. The\n * identifier is undefined only in unbundled runs (e.g. unit tests importing this\n * module directly); the `typeof` guard returns `\"\"` there so those runs fall\n * through to the dev default without a ReferenceError.\n */\nfunction buildStampedChannel(): string {\n return typeof __ZITADEL_TELEMETRY_CHANNEL__ === \"string\"\n ? __ZITADEL_TELEMETRY_CHANNEL__.trim().toLowerCase()\n : \"\";\n}\n\n/**\n * Decide which project the events belong to. Precedence: an explicit\n * `ZITADEL_TELEMETRY_ENV`, then a `ZITADEL_TELEMETRY_BUILD_CHANNEL` env override\n * (handy for CI/release), then the build-time channel stamp. The default —\n * source/dev/test — is the dev project. Ambient `NODE_ENV` is deliberately NOT\n * consulted: a source build with `NODE_ENV=production` must not route dev\n * traffic to prod, nor a published run with `NODE_ENV=development` to dev.\n */\nfunction resolveChannel(env: NodeJS.ProcessEnv): \"development\" | \"production\" {\n const explicit = (env.ZITADEL_TELEMETRY_ENV ?? \"\").trim().toLowerCase();\n if (explicit === \"production\") {\n return \"production\";\n }\n if (explicit === \"development\") {\n return \"development\";\n }\n const stamp = (env.ZITADEL_TELEMETRY_BUILD_CHANNEL ?? buildStampedChannel()).trim().toLowerCase();\n return stamp === \"production\" ? \"production\" : \"development\";\n}\n\n/**\n * Resolve the ingestion token, or `undefined` when none is configured for the\n * active channel. A `ZITADEL_TELEMETRY_TOKEN` override wins outright; otherwise\n * the channel's baked token is used. An empty string (e.g. the unset prod\n * token) resolves to `undefined`, which the caller treats as \"telemetry off\".\n */\nexport function resolveTelemetryToken(env: NodeJS.ProcessEnv): string | undefined {\n const override = env.ZITADEL_TELEMETRY_TOKEN?.trim();\n if (override) {\n return override;\n }\n const token =\n resolveChannel(env) === \"production\" ? PROD_TELEMETRY_TOKEN : DEV_TELEMETRY_TOKEN;\n return token.length > 0 ? token : undefined;\n}\n\n/**\n * Resolve the Mixpanel API host from `ZITADEL_TELEMETRY_REGION`. Defaults to the\n * EU host, because the Zitadel Mixpanel projects live in the EU data-residency\n * region. Set `ZITADEL_TELEMETRY_REGION=us` for a US-hosted project — events\n * sent to the wrong host are silently dropped, so verify the first event lands\n * in Live View.\n */\nexport function resolveTelemetryHost(env: NodeJS.ProcessEnv): string {\n const region = (env.ZITADEL_TELEMETRY_REGION ?? \"eu\").trim().toLowerCase();\n return region === \"us\" ? HOSTS.us : HOSTS.eu;\n}\n","import { resolveTelemetryToken } from \"./config\";\n\n/**\n * Outcome of resolving whether telemetry may run for this invocation. `reason`\n * is a stable token (handy in tests and `--debug` logs) explaining the\n * decision; it is never sent anywhere.\n */\nexport type Consent = {\n readonly enabled: boolean;\n readonly reason:\n | \"enabled\"\n | \"no-token\"\n | \"do-not-track\"\n | \"env-opt-out\"\n | \"flag-opt-out\"\n | \"test-runner\";\n /** The resolved ingestion token, present only when `enabled` — so the caller never re-resolves it. */\n readonly token?: string;\n};\n\n/** Inputs that can disable telemetry, kept explicit so the matrix is testable. */\nexport type ConsentInput = {\n readonly env: NodeJS.ProcessEnv;\n /** The resolved `--telemetry/--no-telemetry` flag value (default true). */\n readonly flag?: boolean;\n};\n\nconst DISABLED_VALUES = new Set([\"\", \"0\", \"false\", \"off\", \"no\"]);\n\n/**\n * Resolve telemetry consent under an opt-out model: on by default, but any of\n * several explicit signals turns it off, in precedence order.\n *\n * 1. `--no-telemetry` on the command line — the most explicit, per-invocation.\n * 2. An automated test run (`VITEST`/`NODE_ENV=test`) — never emit synthetic\n * traffic or pay the shutdown flush; spawned CLI subprocesses inherit it.\n * 3. `DO_NOT_TRACK` — the cross-tool standard (https://consoledonottrack.com);\n * any value other than `0`/empty disables.\n * 4. `ZITADEL_TELEMETRY` set to a falsey token (`0`/`false`/`off`/`no`).\n * 5. No ingestion token configured for the active channel — nothing to send to,\n * so telemetry is inert regardless of consent.\n *\n * Consent being enabled does not by itself send anything; the caller still\n * builds the client lazily and fails open on any transport error.\n */\nexport function resolveConsent(input: ConsentInput): Consent {\n if (input.flag === false) {\n return { enabled: false, reason: \"flag-opt-out\" };\n }\n\n if (input.env.VITEST || input.env.NODE_ENV === \"test\") {\n return { enabled: false, reason: \"test-runner\" };\n }\n\n const doNotTrack = input.env.DO_NOT_TRACK?.trim();\n if (doNotTrack && doNotTrack !== \"0\") {\n return { enabled: false, reason: \"do-not-track\" };\n }\n\n const explicit = input.env.ZITADEL_TELEMETRY?.trim().toLowerCase();\n if (explicit !== undefined && DISABLED_VALUES.has(explicit)) {\n return { enabled: false, reason: \"env-opt-out\" };\n }\n\n const token = resolveTelemetryToken(input.env);\n if (!token) {\n return { enabled: false, reason: \"no-token\" };\n }\n\n return { enabled: true, reason: \"enabled\", token };\n}\n","import { randomUUID } from \"node:crypto\";\nimport { mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\n\n/**\n * A stable, anonymous identifier for this install. It is a random UUID tied to\n * no account, email, or machine fingerprint — its only job is to let Mixpanel\n * group events from the same install into a funnel. `isFirstRun` is true the\n * one time we mint and persist the id, which drives the one-time consent notice.\n */\nexport type Identity = {\n readonly distinctId: string;\n readonly isFirstRun: boolean;\n};\n\ntype StoredIdentity = { distinctId: string };\n\n/**\n * Resolve the directory the CLI persists cross-invocation state in, honoring\n * the platform conventions: `XDG_CONFIG_HOME` then `~/.config` on Unix, and\n * `%APPDATA%` on Windows. The anonymous id lives here so it survives between\n * runs without touching the user's project tree.\n */\nexport function telemetryConfigDir(env: NodeJS.ProcessEnv): string {\n if (process.platform === \"win32\" && env.APPDATA) {\n return join(env.APPDATA, \"zitadel\", \"cli\");\n }\n const base = env.XDG_CONFIG_HOME?.trim() || join(homedir(), \".config\");\n return join(base, \"zitadel\", \"cli\");\n}\n\n/**\n * Load the persisted anonymous id, minting and storing a new one on first run.\n *\n * Fail-open: if the config dir cannot be resolved, read, or written — including\n * an `os.homedir()` throw in a restricted/containerized environment, a\n * read-only home, a CI sandbox, or a permissions error — fall back to an\n * ephemeral per-process id and report `isFirstRun: false` so we neither crash\n * nor nag the user with the notice on every run. Telemetry is best-effort,\n * never load-bearing.\n */\nexport function loadOrCreateIdentity(env: NodeJS.ProcessEnv): Identity {\n let dir: string;\n try {\n dir = telemetryConfigDir(env);\n } catch {\n return { distinctId: randomUUID(), isFirstRun: false };\n }\n const file = join(dir, \"telemetry.json\");\n\n try {\n const parsed = JSON.parse(readFileSync(file, \"utf8\")) as StoredIdentity;\n if (typeof parsed.distinctId === \"string\" && parsed.distinctId.length > 0) {\n return { distinctId: parsed.distinctId, isFirstRun: false };\n }\n } catch {\n /* fall through to mint a fresh id */\n }\n\n const distinctId = randomUUID();\n try {\n mkdirSync(dir, { recursive: true });\n writeFileSync(file, `${JSON.stringify({ distinctId } satisfies StoredIdentity)}\\n`, {\n mode: 0o600,\n });\n return { distinctId, isFirstRun: true };\n } catch {\n return { distinctId, isFirstRun: false };\n }\n}\n","import type { Properties } from \"mixpanel\";\n\n/**\n * Return a new bag with empty values stripped, per Mixpanel's \"omit, never send\n * null/''\" rule. Pure — the input is never mutated.\n */\nexport function compact(properties: Properties): Properties {\n return Object.fromEntries(\n Object.entries(properties).filter(\n ([, value]) => value !== undefined && value !== null && value !== \"\",\n ),\n );\n}\n","import { randomUUID } from \"node:crypto\";\nimport { setTimeout as delay } from \"node:timers/promises\";\n\nimport mixpanelLib, {\n type Mixpanel as MixpanelClient,\n type Modifiers,\n type Properties,\n} from \"mixpanel\";\n\nimport { resolveTelemetryHost } from \"./config\";\nimport { resolveConsent } from \"./consent\";\nimport { type Identity, loadOrCreateIdentity } from \"./identity\";\nimport { compact } from \"./util\";\n\nexport type { Properties, Modifiers } from \"mixpanel\";\nexport type { TelemetryRegion } from \"./config\";\n\n/** Property bag accepted by {@link Telemetry.track} / {@link Telemetry.profile}. */\nexport type TelemetryProperties = Properties;\n\n/**\n * Inputs to {@link Telemetry.create}. `env` is required; the rest are optional —\n * `flag`/`debug` are set by the production wiring, while `initClient`,\n * `loadIdentity`, and `newId` are test seams that default to the real\n * implementations when omitted.\n */\nexport type TelemetryDeps = {\n readonly env: NodeJS.ProcessEnv;\n /**\n * Resolved telemetry flag (the `--telemetry/--no-telemetry` value). Defaults\n * to `true` (telemetry enabled); `false` opts out. Undefined leaves the\n * decision to the other consent signals.\n */\n readonly flag?: boolean;\n /** Emit each payload to stderr before sending — for `--debug`. */\n readonly debug?: boolean;\n readonly initClient?: (token: string, host: string) => MixpanelClient;\n readonly loadIdentity?: (env: NodeJS.ProcessEnv) => Identity;\n readonly newId?: () => string;\n};\n\n/**\n * A generic, application-agnostic Mixpanel client wrapper for a single short\n * process. It knows nothing about commands, CLIs, or event names — callers\n * supply fully-built property bags. Its only opinions are operational, because\n * telemetry must never degrade the host program:\n *\n * - Never throws — a missing token, opt-out, or transport error all degrade to\n * a silent no-op.\n * - Never blocks beyond {@link shutdown}'s timeout.\n * - Never writes to stdout; the optional debug trace goes to stderr.\n *\n * Inputs are treated as immutable: {@link track}/{@link profile} build a new\n * payload via spread and never mutate the bag they are given.\n */\nexport class Telemetry {\n private readonly pending: Promise<void>[] = [];\n\n private constructor(\n private readonly client: MixpanelClient | undefined,\n readonly distinctId: string,\n readonly isFirstRun: boolean,\n private readonly debug: boolean,\n private readonly newId: () => string,\n ) {}\n\n /** Whether events will actually be sent (consent granted and a token configured). */\n get enabled(): boolean {\n return this.client !== undefined;\n }\n\n /**\n * Resolve consent, identity, token, and host, then build the Mixpanel client\n * lazily — only when consent is granted *and* a token is configured. Any\n * failure along the way yields an inert instance whose methods are no-ops.\n */\n static create(deps: TelemetryDeps): Telemetry {\n const newId = deps.newId ?? randomUUID;\n const debug = deps.debug ?? false;\n const inert = (firstRun: boolean): Telemetry =>\n new Telemetry(undefined, \"\", firstRun, debug, newId);\n\n const consent = resolveConsent({ env: deps.env, flag: deps.flag });\n if (debug) {\n process.stderr.write(`[telemetry] consent: ${consent.reason}\\n`);\n }\n if (!consent.enabled || !consent.token) {\n return inert(false);\n }\n\n const identity = (deps.loadIdentity ?? loadOrCreateIdentity)(deps.env);\n\n let client: MixpanelClient | undefined;\n try {\n client = (deps.initClient ?? defaultInit)(consent.token, resolveTelemetryHost(deps.env));\n } catch {\n return inert(identity.isFirstRun);\n }\n return new Telemetry(client, identity.distinctId, identity.isFirstRun, debug, newId);\n }\n\n /** Send an event with the given properties; `distinct_id`/`$insert_id` are stamped here. */\n track(event: string, properties: TelemetryProperties): void {\n if (!this.client) {\n return;\n }\n const payload = compact({\n ...properties,\n distinct_id: this.distinctId,\n $insert_id: this.newId(),\n });\n if (this.debug) {\n process.stderr.write(`[telemetry] ${event} ${JSON.stringify(payload)}\\n`);\n }\n this.enqueue((client, done) => client.track(event, payload, done));\n }\n\n /** Write a user profile via the People API. `modifiers` carries `$ip` etc. */\n profile(properties: TelemetryProperties, modifiers: Modifiers = {}): void {\n if (!this.client) {\n return;\n }\n const payload = compact(properties);\n if (this.debug) {\n process.stderr.write(`[telemetry] people.set ${JSON.stringify(payload)}\\n`);\n }\n this.enqueue((client, done) => client.people.set(this.distinctId, payload, modifiers, done));\n }\n\n /**\n * Await in-flight sends so a short-lived process does not exit before the\n * requests complete, bounded by `timeoutMs`. The timeout is unref'd so the\n * losing race branch never holds the event loop open or needs a manual clear.\n * Safe to call on an inert instance.\n */\n async shutdown(timeoutMs = 2000): Promise<void> {\n if (this.pending.length === 0) {\n return;\n }\n await Promise.race([\n Promise.allSettled(this.pending),\n delay(timeoutMs, undefined, { ref: false }),\n ]);\n }\n\n /**\n * Enqueue one fire-and-forget send. Resolves (never rejects) on any failure —\n * a synchronous throw or an error callback must not surface to the caller or\n * leak as an unhandled rejection.\n */\n private enqueue(\n send: (client: MixpanelClient, done: () => void) => void,\n ): void {\n const client = this.client;\n if (!client) {\n return;\n }\n this.pending.push(\n new Promise<void>((resolve) => {\n try {\n send(client, () => resolve());\n } catch {\n resolve();\n }\n }),\n );\n }\n}\n\n/** Real Mixpanel client construction, isolated so {@link Telemetry.create} can swap it in tests. */\nfunction defaultInit(token: string, host: string): MixpanelClient {\n return mixpanelLib.init(token, { host, geolocate: false });\n}\n","const DISABLED_VALUES = new Set([\"\", \"0\", \"false\", \"off\", \"no\"]);\n\n/**\n * Whether an environment variable is set to an enabled value. A present-but-\n * falsey string (`CI=false`, `CI=0`) counts as disabled — unlike a bare\n * `Boolean(env.CI)` check, which is true for any non-empty string.\n */\nexport function envEnabled(value: string | undefined): boolean {\n return value !== undefined && !DISABLED_VALUES.has(value.trim().toLowerCase());\n}\n","import type { Property } from \"../property\";\nimport { envEnabled } from \"./env-flag\";\n\n/** Whether the process is running inside an automated CI environment. */\nclass CiFlag implements Property<NodeJS.ProcessEnv, boolean> {\n public value(env: NodeJS.ProcessEnv): boolean {\n return envEnabled(env.CI) || envEnabled(env.GITHUB_ACTIONS) || envEnabled(env.GITLAB_CI);\n }\n}\n\nexport const ciFlag = new CiFlag();\n","import type { Property } from \"../property\";\nimport { envEnabled } from \"./env-flag\";\n\n/** Coarse CI provider name, or `undefined` when not running in CI. */\nclass CiProvider implements Property<NodeJS.ProcessEnv, string | undefined> {\n /** Provider-marker env var → reported name, in match order. */\n private static readonly providers = [\n [\"GITHUB_ACTIONS\", \"github_actions\"],\n [\"GITLAB_CI\", \"gitlab_ci\"],\n [\"CIRCLECI\", \"circleci\"],\n [\"BUILDKITE\", \"buildkite\"],\n [\"JENKINS_URL\", \"jenkins\"],\n ] as const satisfies ReadonlyArray<readonly [string, string]>;\n\n public value(env: NodeJS.ProcessEnv): string | undefined {\n const named = CiProvider.providers.find(([marker]) => envEnabled(env[marker]));\n if (named) {\n return named[1];\n }\n return envEnabled(env.CI) ? \"unknown\" : undefined;\n }\n}\n\nexport const ciProvider = new CiProvider();\n","import type { Property } from \"../property\";\n\n/**\n * ISO 3166-1 alpha-2 country for an IANA timezone, defaulting to the machine's\n * own zone. A curated subset of common zones — any zone not listed (or an\n * unknown/unavailable one) yields `undefined`, since we report no country\n * rather than guess. Derived from the timezone, never the IP, so no city or\n * region is ever inferred. The machine's own zone is resolved once and cached:\n * `Intl.DateTimeFormat` construction loads ICU data and is process-stable.\n */\nclass Country implements Property<string | undefined, string | undefined> {\n private readonly byTimezone: Record<string, string> = {\n \"Africa/Abidjan\": \"CI\",\n \"Africa/Accra\": \"GH\",\n \"Africa/Addis_Ababa\": \"ET\",\n \"Africa/Algiers\": \"DZ\",\n \"Africa/Cairo\": \"EG\",\n \"Africa/Casablanca\": \"MA\",\n \"Africa/Johannesburg\": \"ZA\",\n \"Africa/Lagos\": \"NG\",\n \"Africa/Nairobi\": \"KE\",\n \"Africa/Tunis\": \"TN\",\n \"America/Anchorage\": \"US\",\n \"America/Argentina/Buenos_Aires\": \"AR\",\n \"America/Bogota\": \"CO\",\n \"America/Chicago\": \"US\",\n \"America/Denver\": \"US\",\n \"America/Halifax\": \"CA\",\n \"America/Lima\": \"PE\",\n \"America/Los_Angeles\": \"US\",\n \"America/Mexico_City\": \"MX\",\n \"America/New_York\": \"US\",\n \"America/Phoenix\": \"US\",\n \"America/Santiago\": \"CL\",\n \"America/Sao_Paulo\": \"BR\",\n \"America/Toronto\": \"CA\",\n \"America/Vancouver\": \"CA\",\n \"Asia/Bangkok\": \"TH\",\n \"Asia/Dhaka\": \"BD\",\n \"Asia/Dubai\": \"AE\",\n \"Asia/Hong_Kong\": \"HK\",\n \"Asia/Jakarta\": \"ID\",\n \"Asia/Jerusalem\": \"IL\",\n \"Asia/Karachi\": \"PK\",\n \"Asia/Kolkata\": \"IN\",\n \"Asia/Kuala_Lumpur\": \"MY\",\n \"Asia/Manila\": \"PH\",\n \"Asia/Riyadh\": \"SA\",\n \"Asia/Seoul\": \"KR\",\n \"Asia/Shanghai\": \"CN\",\n \"Asia/Singapore\": \"SG\",\n \"Asia/Taipei\": \"TW\",\n \"Asia/Tehran\": \"IR\",\n \"Asia/Tokyo\": \"JP\",\n \"Australia/Adelaide\": \"AU\",\n \"Australia/Brisbane\": \"AU\",\n \"Australia/Melbourne\": \"AU\",\n \"Australia/Perth\": \"AU\",\n \"Australia/Sydney\": \"AU\",\n \"Europe/Amsterdam\": \"NL\",\n \"Europe/Athens\": \"GR\",\n \"Europe/Berlin\": \"DE\",\n \"Europe/Brussels\": \"BE\",\n \"Europe/Bucharest\": \"RO\",\n \"Europe/Budapest\": \"HU\",\n \"Europe/Copenhagen\": \"DK\",\n \"Europe/Dublin\": \"IE\",\n \"Europe/Helsinki\": \"FI\",\n \"Europe/Istanbul\": \"TR\",\n \"Europe/Kyiv\": \"UA\",\n \"Europe/Lisbon\": \"PT\",\n \"Europe/London\": \"GB\",\n \"Europe/Madrid\": \"ES\",\n \"Europe/Moscow\": \"RU\",\n \"Europe/Oslo\": \"NO\",\n \"Europe/Paris\": \"FR\",\n \"Europe/Prague\": \"CZ\",\n \"Europe/Rome\": \"IT\",\n \"Europe/Stockholm\": \"SE\",\n \"Europe/Vienna\": \"AT\",\n \"Europe/Warsaw\": \"PL\",\n \"Europe/Zurich\": \"CH\",\n \"Pacific/Auckland\": \"NZ\",\n \"Pacific/Honolulu\": \"US\",\n };\n\n private machineZone: string | undefined;\n private machineZoneResolved = false;\n\n public value(timezone: string | undefined): string | undefined {\n const zone = timezone ?? this.resolveMachineZone();\n return zone ? this.byTimezone[zone] : undefined;\n }\n\n private resolveMachineZone(): string | undefined {\n if (!this.machineZoneResolved) {\n this.machineZoneResolved = true;\n try {\n this.machineZone = new Intl.DateTimeFormat().resolvedOptions().timeZone;\n } catch {\n this.machineZone = undefined;\n }\n }\n return this.machineZone;\n }\n}\n\nexport const country = new Country();\n","import type { Property } from \"../property\";\n\n/** Fixed-enum identity of the agent or host driving the process. */\nclass HostAgent implements Property<NodeJS.ProcessEnv, string> {\n /** Predicate → reported name, in match order. */\n private static readonly agents: ReadonlyArray<\n readonly [(env: NodeJS.ProcessEnv) => boolean, string]\n > = [\n [(env) => Boolean(env.CLAUDECODE || env.CLAUDE_CODE_ENTRYPOINT), \"claude_code\"],\n [(env) => Boolean(env.CURSOR_TRACE_ID || env.CURSOR_AGENT), \"cursor\"],\n [(env) => env.TERM_PROGRAM === \"vscode\", \"vscode\"],\n ];\n\n public value(env: NodeJS.ProcessEnv): string {\n return HostAgent.agents.find(([matches]) => matches(env))?.[1] ?? \"unknown\";\n }\n}\n\nexport const hostAgent = new HostAgent();\n","import type { Property } from \"../property\";\n\n/** Package manager that launched the process, read from its user-agent. */\nclass InvocationChannel implements Property<NodeJS.ProcessEnv, string> {\n /** Ordered so a more specific name wins — `pnpm` is matched before the `npm` prefix. */\n private static readonly managers = [\"pnpm\", \"yarn\", \"bun\", \"npm\"] as const;\n\n public value(env: NodeJS.ProcessEnv): string {\n const userAgent = env.npm_config_user_agent ?? \"\";\n return InvocationChannel.managers.find((manager) => userAgent.startsWith(manager)) ?? \"unknown\";\n }\n}\n\nexport const invocationChannel = new InvocationChannel();\n","import type { Property } from \"../property\";\n\n/** Maps `process.platform` to Mixpanel's canonical `$os` label. */\nclass OperatingSystem implements Property<NodeJS.Platform, string> {\n private static readonly labels: Partial<Record<NodeJS.Platform, string>> = {\n darwin: \"Mac OS X\",\n win32: \"Windows\",\n linux: \"Linux\",\n freebsd: \"BSD\",\n openbsd: \"BSD\",\n netbsd: \"BSD\",\n aix: \"AIX\",\n sunos: \"Solaris\",\n };\n\n public value(platform: NodeJS.Platform): string {\n return OperatingSystem.labels[platform] ?? platform;\n }\n}\n\nexport const operatingSystem = new OperatingSystem();\n","import type { Property } from \"../telemetry/property\";\n\n/**\n * Buckets the resolved backend `source` into a coarse kind. The raw URL is never\n * emitted — it can carry an internal/self-hosted hostname — only which kind of\n * backend the command targeted.\n */\nclass ServerKind implements Property<string, \"cloud\" | \"local\" | \"self_hosted\" | \"unknown\"> {\n public value(source: string): \"cloud\" | \"local\" | \"self_hosted\" | \"unknown\" {\n if (source === \"mock\") {\n return \"local\";\n }\n if (!URL.canParse(source)) {\n return \"unknown\";\n }\n const { hostname } = new URL(source);\n if (hostname === \"zitadel.cloud\" || hostname.endsWith(\".zitadel.cloud\")) {\n return \"cloud\";\n }\n if (hostname === \"localhost\" || hostname === \"127.0.0.1\" || hostname === \"::1\") {\n return \"local\";\n }\n return \"self_hosted\";\n }\n}\n\nexport const serverKind = new ServerKind();\n","import type { Properties } from \"../telemetry\";\nimport { ciFlag } from \"../telemetry/dimensions/ci-flag\";\nimport { ciProvider } from \"../telemetry/dimensions/ci-provider\";\nimport { country } from \"../telemetry/dimensions/country\";\nimport { hostAgent } from \"../telemetry/dimensions/host-agent\";\nimport { invocationChannel } from \"../telemetry/dimensions/invocation-channel\";\nimport { operatingSystem } from \"../telemetry/dimensions/operating-system\";\nimport { serverKind } from \"./server-kind\";\nimport type { GlobalOptions } from \"./types\";\n\n/**\n * CLI-specific telemetry glue: the only place that turns a {@link GlobalOptions}\n * invocation into the property bags the generic `Telemetry` client sends,\n * keeping `lib/telemetry` free of CLI coupling.\n */\n\nexport const CLI_COMMAND_STARTED = \"cli_command_started\";\nexport const CLI_COMMAND_COMPLETED = \"cli_command_completed\";\nexport const CLI_COMMAND_FAILED = \"cli_command_failed\";\n\nexport const FIRST_RUN_NOTICE =\n \"Zitadel CLI collects anonymous usage analytics to help improve the tool. \" +\n \"No personal data, project details, server URLs, or file contents are ever \" +\n \"collected. Opt out any time with DO_NOT_TRACK=1, ZITADEL_TELEMETRY=0, or \" +\n \"the --no-telemetry flag.\";\n\n/**\n * Process-stable device facts shared by both the event bag and the user\n * profile, so the two never disagree on the same install's OS/arch/version.\n */\nfunction deviceProperties(meta: GlobalOptions): Properties {\n return {\n $os: operatingSystem.value(process.platform),\n $country_code: country.value(undefined),\n os: process.platform,\n arch: process.arch,\n node_version: process.versions.node,\n cli_version: meta.cliVersion,\n };\n}\n\n/**\n * Build the dimensions shared by every lifecycle event, merged with any\n * per-command `extra`. The allow-list: only enums, booleans, counts, and\n * versions cross the boundary — never URLs, project ids, file paths, emails, or\n * secrets. `extra` is spread first so the canonical base dimensions always win;\n * callers order their own extras so reserved lifecycle fields win over command\n * props.\n */\nexport function commandEventProperties(\n meta: GlobalOptions,\n invocationId: string,\n extra: Properties = {},\n): Properties {\n const { env } = meta;\n return {\n ...extra,\n ...deviceProperties(meta),\n ip: 0,\n invocation_id: invocationId,\n command: meta.command,\n non_interactive: meta.nonInteractive,\n is_tty: meta.isTTY,\n is_ci: ciFlag.value(env),\n ci_provider: ciProvider.value(env),\n host_agent: hostAgent.value(env),\n invocation_channel: invocationChannel.value(env),\n dry_run: meta.dryRun,\n force: meta.force,\n server_kind: serverKind.value(meta.source),\n };\n}\n\n/**\n * Anonymous user-profile properties for this install, so the device appears\n * under Mixpanel \"Users\". Only non-PII device facts; `$name` is a readable,\n * non-identifying label that falls back to the OS when the host agent is\n * unknown. `$ip` is passed separately as a modifier by the caller.\n */\nexport function deviceProfileProperties(meta: GlobalOptions, distinctId: string): Properties {\n const agent = hostAgent.value(meta.env);\n const label = agent === \"unknown\" ? process.platform : agent;\n return {\n ...deviceProperties(meta),\n $name: `${label} · ${distinctId.slice(0, 8)}`,\n host_agent: agent,\n };\n}\n","import { randomUUID } from \"node:crypto\";\n\nimport { Command, Flags } from \"@oclif/core\";\nimport consola from \"consola\";\n\nimport { toZitadelError, type ZitadelError } from \"../errors\";\nimport { isObject } from \"../json\";\nimport { resolveCwd } from \"../paths\";\nimport { normalizePublicCliCommand, normalizePublicCliCommands } from \"../public-cli\";\nimport { resolveServer } from \"../server\";\nimport { type Properties, Telemetry, type TelemetryDeps } from \"../telemetry\";\nimport {\n CLI_COMMAND_COMPLETED,\n CLI_COMMAND_FAILED,\n CLI_COMMAND_STARTED,\n commandEventProperties,\n deviceProfileProperties,\n FIRST_RUN_NOTICE,\n} from \"./command-telemetry\";\nimport type {\n CommandResult,\n ErrorEnvelope,\n EnvelopeMeta,\n GlobalOptions,\n JsonEnvelope,\n} from \"./types\";\n\n/**\n * Base class for every oclif command. Owns the global flags, builds the\n * {@link GlobalOptions} context (including server `source` resolution) the\n * subclass's `run` reads via `this.meta`, and turns the {@link CommandResult}\n * it returns into the JSON envelope (oclif serialises it natively in `--json`\n * mode) or human-facing text. Errors are translated into the failure envelope\n * and the mapped process exit code. Subclasses stay thin: parse flags, call\n * {@link toMeta}, do their work, and `return this.emit(...)`. The agent\n * contract (ADR 004) is preserved — oclif only replaces parsing, dispatch,\n * help, and JSON emission.\n */\nexport abstract class BaseCommand extends Command {\n /** Opt into oclif's native `--json` flag and JSON serialisation of the result. */\n static override enableJsonFlag = true;\n\n /** Flags shared by every command, inherited via oclif `baseFlags`. */\n static override baseFlags = {\n cwd: Flags.string({ char: \"c\", description: \"Project directory to operate on.\" }),\n server: Flags.string({ char: \"s\", description: \"Override the resolved server URL.\" }),\n \"non-interactive\": Flags.boolean({\n char: \"n\",\n description: \"Disable prompts. Required when scripting or running as an agent.\",\n }),\n force: Flags.boolean({ char: \"f\", description: \"Overwrite protected files on conflict.\" }),\n \"dry-run\": Flags.boolean({ description: \"Preview without mutating files or the platform.\" }),\n verbose: Flags.boolean({ description: \"Verbose logging.\" }),\n debug: Flags.boolean({ description: \"Debug logging.\" }),\n telemetry: Flags.boolean({\n default: true,\n allowNo: true,\n description: \"Send anonymous usage analytics. Disable with --no-telemetry.\",\n }),\n };\n\n /** Resolved context for the current invocation; set by {@link toMeta}. */\n protected meta: GlobalOptions = this.fallbackMeta();\n\n /**\n * Anonymous usage analytics for this invocation, created once in\n * {@link toMeta}. Subclasses add command-specific dimensions (framework,\n * counts, `step`, …) via {@link recordTelemetry}; the base class\n * fires the lifecycle events and flushes in {@link finally}.\n */\n protected telemetry?: Telemetry;\n\n /**\n * Per-command dimensions merged onto each lifecycle event emitted *after* they\n * are recorded — typically `completed`/`failed`, since `started` fires from\n * {@link openTelemetry} before a command body runs. Updated immutably via\n * {@link recordTelemetry} — never mutated in place.\n */\n protected telemetryProps: Readonly<Properties> = Object.freeze({});\n\n /** Correlates the started/completed pair; minted at instance construction. */\n private readonly telemetryInvocationId = randomUUID();\n\n /**\n * Wall-clock start used to derive `duration_ms`. Captured at instance\n * construction (before flag parsing and server resolution) so the duration\n * covers the full invocation, even when telemetry is opened late from\n * {@link catch} after an early failure.\n */\n private readonly telemetryStartedAt = Date.now();\n\n /**\n * Merge command-specific dimensions into {@link telemetryProps} immutably: a\n * new frozen bag replaces the previous one, so no shared object is ever\n * mutated. `step` advances by re-recording it at each milestone.\n */\n protected recordTelemetry(patch: Properties): void {\n this.telemetryProps = Object.freeze({ ...this.telemetryProps, ...patch });\n }\n\n /**\n * Builds {@link GlobalOptions} from parsed flags, resolving the server\n * `source` by the documented precedence and storing the result on\n * `this.meta` so the error handler can render a complete envelope.\n */\n protected async toMeta(\n flags: Record<string, unknown>,\n options: { resolveServer?: boolean; source?: string } = {},\n ): Promise<GlobalOptions> {\n const cwd = resolveCwd(typeof flags.cwd === \"string\" ? flags.cwd : undefined);\n const serverFlag = typeof flags.server === \"string\" ? flags.server : undefined;\n const environment = typeof flags.environment === \"string\" ? flags.environment : \"development\";\n const source =\n options.resolveServer === false\n ? { value: options.source ?? \"\", origin: \"default\" as const }\n : await resolveServer({ cwd, env: process.env, serverFlag, environment });\n const json = this.jsonEnabled();\n const isTTY = Boolean(process.stdout.isTTY && process.stdin.isTTY);\n const verbose = Boolean(flags.verbose);\n const debug = Boolean(flags.debug);\n // Default to `info` (3) so users see step-by-step narration (start/info/\n // success/box). `--json` silences consola entirely so the structured\n // envelope is the only thing on stdout. `--debug` raises to 4 (debug);\n // `--verbose` is reserved for richer per-step detail and currently maps\n // to the same level as default.\n consola.level = json ? -999 : debug ? 4 : 3;\n // Drop the right-aligned timestamp the FancyReporter adds by default.\n // Timestamps add no value in a one-off CLI run, wrap awkwardly on long\n // lines (e.g. created-schema URL), and clutter the visual rhythm of the\n // ◐/✔/ℹ glyphs that anchor each step.\n consola.options.formatOptions = {\n ...consola.options.formatOptions,\n date: false,\n colors: true,\n compact: true,\n };\n this.meta = {\n cwd,\n nonInteractive: Boolean(flags[\"non-interactive\"]) || !isTTY || json,\n dryRun: Boolean(flags[\"dry-run\"]),\n force: Boolean(flags.force),\n command: this.id ?? \"(default)\",\n cliVersion: this.config.version,\n source: source.value,\n serverFlag,\n verbose,\n debug,\n env: process.env,\n isTTY,\n };\n this.openTelemetry(typeof flags.telemetry === \"boolean\" ? flags.telemetry : undefined);\n return this.meta;\n }\n\n /**\n * Create telemetry once per invocation and open the lifecycle (started event +\n * anonymous profile + first-run notice), reading every dimension from the\n * current {@link meta}. Guarded so a command that resolves meta more than once\n * does not double-count. Also called from {@link catch} so a failure thrown\n * before {@link toMeta} finished (e.g. server resolution, flag parsing) still\n * records the run. Returns early for an inert (opted-out / no-token /\n * test-runner) instance so a disabled run never builds the property bags —\n * no timezone→country resolution or URL parsing for users who opted out. The\n * anonymous device profile is install-level and stable, so it is written only\n * on first run rather than paying a `people.set` request on every command.\n */\n /**\n * Telemetry factory seam. Production returns the real {@link Telemetry.create};\n * tests override it to inject a recording client and assert the lifecycle\n * ordering and opt-out behaviour that the central Vitest consent guard would\n * otherwise make untestable.\n */\n protected createTelemetry(deps: TelemetryDeps): Telemetry {\n return Telemetry.create(deps);\n }\n\n private openTelemetry(flag: boolean | undefined): void {\n if (this.telemetry) {\n return;\n }\n this.telemetry = this.createTelemetry({ env: process.env, flag, debug: this.meta.debug });\n if (!this.telemetry.enabled) {\n return;\n }\n this.telemetry.track(\n CLI_COMMAND_STARTED,\n commandEventProperties(this.meta, this.telemetryInvocationId, this.telemetryProps),\n );\n if (this.telemetry.isFirstRun) {\n this.telemetry.profile(deviceProfileProperties(this.meta, this.telemetry.distinctId), {\n $ip: 0,\n });\n if (this.isInteractive()) {\n process.stderr.write(`${FIRST_RUN_NOTICE}\\n`);\n }\n }\n }\n\n /**\n * Whether this invocation is an interactive human session, used to gate the\n * one-time first-run notice. Derived from argv + `jsonEnabled()` + TTY rather\n * than `meta.nonInteractive`, so it is correct even on the early-failure path\n * where {@link catch} opens telemetry against a fallback meta that has not yet\n * computed `nonInteractive` from the flags.\n */\n private isInteractive(): boolean {\n if (this.meta.nonInteractive || this.jsonEnabled()) {\n return false;\n }\n const argv = process.argv;\n if (\n argv.includes(\"--json\") ||\n argv.includes(\"--non-interactive\") ||\n argv.includes(\"-n\")\n ) {\n return false;\n }\n return Boolean(process.stdout.isTTY && process.stdin.isTTY);\n }\n\n /**\n * Final step of every command: in human mode it prints the rendered result\n * (oclif suppresses {@link Command.log} under `--json`); it returns the\n * envelope so oclif's `--json` path serialises it.\n */\n protected emit(result: CommandResult): JsonEnvelope {\n const normalized = normalizeCommandResult(result, this.meta);\n if (this.telemetry?.enabled) {\n this.telemetry.track(\n CLI_COMMAND_COMPLETED,\n commandEventProperties(this.meta, this.telemetryInvocationId, {\n ...this.telemetryProps,\n status: result.status,\n duration_ms: Date.now() - this.telemetryStartedAt,\n }),\n );\n }\n this.log(renderPretty(normalized, this.meta));\n return toEnvelope(normalized, this.meta);\n }\n\n /**\n * Renders any thrown error as the failure envelope and exits with its code.\n * A flag-parse error fires before {@link toMeta} runs, so the local `meta`\n * here refreshes `command` from the now-resolved command id to keep the\n * envelope's `command` field accurate. If that early failure left telemetry\n * unopened, {@link openTelemetry} runs here so the failure is still recorded;\n * the flag isn't parsed yet on that path, so `--no-telemetry` is honoured from\n * argv.\n */\n protected override async catch(error: unknown): Promise<never> {\n const meta: GlobalOptions = { ...this.meta, command: this.id ?? this.meta.command };\n const zitadelError = toZitadelError(error);\n this.meta = meta;\n this.openTelemetry(process.argv.includes(\"--no-telemetry\") ? false : undefined);\n if (this.telemetry?.enabled) {\n this.telemetry.track(\n CLI_COMMAND_FAILED,\n commandEventProperties(meta, this.telemetryInvocationId, {\n ...this.telemetryProps,\n status: \"error\",\n reason: zitadelError.code,\n exit_code: zitadelError.exitCode,\n duration_ms: Date.now() - this.telemetryStartedAt,\n }),\n );\n }\n if (this.jsonEnabled()) {\n this.logJson(toErrorEnvelope(zitadelError, meta));\n } else {\n this.logToStderr(renderError(zitadelError, meta));\n }\n return this.exit(zitadelError.exitCode);\n }\n\n /**\n * oclif runs this after `run`/`catch` on every path. We flush pending\n * telemetry so a short-lived CLI process does not exit before the lifecycle\n * event is sent. The await is bounded by the flush budget, so a hung or\n * firewalled network adds at most ~1s.\n *\n * `mixpanel@0.18` always uses keep-alive agents (hardcoded; not configurable)\n * and exposes no request timeout or handle, so a completed *or* hung request\n * leaves a socket that keeps Node's event loop open past the await. The\n * failure path force-exits via oclif's `exit()`, but the success path would\n * otherwise hang, so we arm an unref'd watchdog: it cannot keep the loop alive\n * on a clean exit, but if a telemetry socket is still holding it open after\n * the grace, it force-exits with the resolved code.\n */\n protected override async finally(error: Error | undefined): Promise<void> {\n await this.telemetry?.shutdown(1000);\n if (this.telemetry?.enabled) {\n setTimeout(() => process.exit(process.exitCode ?? 0), 250).unref();\n }\n await super.finally(error);\n }\n\n /**\n * Context used before {@link toMeta} runs, so an error thrown during flag\n * parsing still renders a complete envelope. Version comes from oclif's\n * resolved {@link Command.config}.\n */\n private fallbackMeta(): GlobalOptions {\n return {\n cwd: resolveCwd(undefined),\n nonInteractive: false,\n dryRun: false,\n force: false,\n command: \"(default)\",\n cliVersion: this.config.version,\n source: \"\",\n verbose: false,\n debug: false,\n env: process.env,\n isTTY: Boolean(process.stdout.isTTY && process.stdin.isTTY),\n };\n }\n}\n\nfunction normalizeCommandResult(result: CommandResult, meta: GlobalOptions): CommandResult {\n if (result.status === \"ok\") {\n return {\n ...result,\n data: normalizeDataNextCommands(result.data, meta),\n };\n }\n return {\n ...result,\n data: normalizeDataNextCommands(result.data, meta),\n nextCommands: normalizePublicCliCommands(result.nextCommands, meta.cliVersion),\n };\n}\n\nfunction normalizeDataNextCommands(data: unknown, meta: GlobalOptions): unknown {\n if (!isObject(data) || !Array.isArray(data.next_commands)) {\n return data;\n }\n return {\n ...data,\n next_commands: data.next_commands.map((command) =>\n typeof command === \"string\" ? normalizePublicCliCommand(command, meta.cliVersion) : command,\n ),\n };\n}\n\n/** Wraps a {@link CommandResult} with the invocation metadata into the final envelope. */\nfunction toEnvelope(result: CommandResult, meta: GlobalOptions): JsonEnvelope {\n const base: EnvelopeMeta = {\n cli_version: meta.cliVersion,\n command: meta.command,\n source: meta.source,\n };\n if (result.status === \"ok\") {\n return {\n ...base,\n status: \"ok\",\n data: result.data,\n warnings: result.warnings ? [...result.warnings] : [],\n };\n }\n return {\n ...base,\n status: \"skipped\",\n reason: result.reason,\n data: result.data,\n next_commands: result.nextCommands ? [...result.nextCommands] : undefined,\n };\n}\n\n/** Builds the failure envelope from a {@link ZitadelError} and the invocation metadata. */\nfunction toErrorEnvelope(error: ZitadelError, meta: GlobalOptions): ErrorEnvelope {\n return {\n status: \"error\",\n cli_version: meta.cliVersion,\n command: meta.command,\n source: meta.source,\n code: error.code,\n message: error.message,\n hint: error.hint,\n next_commands: normalizePublicCliCommands(error.nextCommands, meta.cliVersion),\n details: error.details,\n };\n}\n\n/**\n * Renders a {@link CommandResult} as human-facing text for non-JSON mode. A\n * command may supply a bespoke `pretty` string (e.g. the `apply` plan diff);\n * otherwise success payloads are summarised by {@link formatData} and skips are\n * shown with their reason and follow-up commands.\n */\nfunction renderPretty(result: CommandResult, meta: GlobalOptions): string {\n if (result.pretty !== undefined) {\n return result.pretty;\n }\n if (result.status === \"ok\") {\n return formatData(result.data, result.warnings ? [...result.warnings] : [], meta);\n }\n const lines = [`Skipped: ${result.reason}${suffixBlock(meta)}`];\n if (result.nextCommands && result.nextCommands.length > 0) {\n lines.push(\"Next:\");\n for (const cmd of result.nextCommands) {\n lines.push(` $ ${cmd}`);\n }\n }\n return lines.join(\"\\n\");\n}\n\n/**\n * Renders a {@link ZitadelError} as a human-readable block for stderr: the\n * coded message, an optional hint, and any suggested next commands.\n */\nfunction renderError(error: ZitadelError, meta: GlobalOptions): string {\n const lines = [`Error ${error.code}: ${error.message}`];\n if (error.hint) {\n lines.push(error.hint);\n }\n const nextCommands = normalizePublicCliCommands(error.nextCommands, meta.cliVersion);\n if (nextCommands && nextCommands.length > 0) {\n lines.push(\"Next:\");\n for (const cmd of nextCommands) {\n lines.push(` $ ${cmd}`);\n }\n }\n return lines.join(\"\\n\");\n}\n\nfunction formatData(data: unknown, warnings: string[], opts: GlobalOptions): string {\n if (typeof data === \"string\") {\n const suffix = sourceSuffix(opts);\n return suffix ? `${data}\\n${suffix}` : data;\n }\n\n const lines: string[] = [];\n const titleLine =\n isObject(data) && typeof data.title === \"string\"\n ? String(data.title)\n : \"Zitadel command completed.\";\n lines.push(titleLine);\n const suffix = sourceSuffix(opts);\n if (suffix) {\n lines.push(suffix);\n }\n\n if (isObject(data)) {\n renderKnownSections(lines, data);\n\n if (Array.isArray(data.next_actions) && data.next_actions.length > 0) {\n lines.push(\"\");\n lines.push(\"Next:\");\n for (const action of data.next_actions) {\n lines.push(` ${String(action)}`);\n }\n }\n if (Array.isArray(data.next_commands) && data.next_commands.length > 0) {\n if (!Array.isArray(data.next_actions) || data.next_actions.length === 0) {\n lines.push(\"\");\n lines.push(\"Next:\");\n }\n for (const cmd of data.next_commands) {\n lines.push(` $ ${String(cmd)}`);\n }\n }\n }\n\n for (const warning of warnings.filter((warning) => !warningRenderedInChecks(data, warning))) {\n lines.push(`Warning: ${warning}`);\n }\n return lines.join(\"\\n\");\n}\n\nfunction warningRenderedInChecks(data: unknown, warning: string): boolean {\n if (!isObject(data) || !Array.isArray(data.checks)) {\n return false;\n }\n return data.checks.some((check) => {\n if (!isObject(check) || check.status !== \"warn\") {\n return false;\n }\n return warning === `${String(check.name ?? \"check\")}: ${String(check.message ?? \"\")}`;\n });\n}\n\nfunction renderKnownSections(lines: string[], data: Record<string, unknown>): void {\n if (isObject(data.project)) {\n const project = data.project;\n const segments: string[] = [];\n if (typeof project.project_id === \"string\") {\n segments.push(`project=${project.project_id}`);\n }\n if (typeof project.lifecycle === \"string\") {\n segments.push(`lifecycle=${project.lifecycle}`);\n }\n if (typeof project.issuer === \"string\") {\n segments.push(`issuer=${project.issuer}`);\n }\n if (segments.length > 0) {\n lines.push(`Project: ${segments.join(\" \")}`);\n }\n }\n\n if (typeof data.framework === \"string\") {\n lines.push(`framework=${data.framework}`);\n }\n\n if (Array.isArray(data.files_written) || Array.isArray(data.files_skipped)) {\n const written = Array.isArray(data.files_written) ? data.files_written.length : 0;\n const skippedCount = Array.isArray(data.files_skipped) ? data.files_skipped.length : 0;\n lines.push(`Files: ${written} written, ${skippedCount} unchanged`);\n }\n\n if (isObject(data.apply)) {\n const apply = data.apply;\n const bits: string[] = [];\n if (typeof apply.config_version === \"number\") {\n bits.push(`v${apply.config_version}`);\n }\n if (typeof apply.hash === \"string\") {\n bits.push(`hash=${String(apply.hash).slice(0, 12)}`);\n }\n if (typeof apply.environment === \"string\") {\n bits.push(`env=${apply.environment}`);\n }\n if (bits.length > 0) {\n lines.push(`Apply: ${bits.join(\" \")}`);\n }\n }\n\n if (Array.isArray(data.checks) && data.checks.length > 0) {\n lines.push(\"Checks:\");\n for (const check of data.checks) {\n if (!isObject(check)) {\n continue;\n }\n const status = check.status === \"pass\" ? \"ok\" : check.status === \"warn\" ? \"warn\" : \"fail\";\n lines.push(` [${status}] ${String(check.name ?? \"check\")}: ${String(check.message ?? \"\")}`);\n }\n }\n}\n\nfunction sourceSuffix(opts: GlobalOptions): string {\n try {\n const url = new URL(opts.source);\n if (url.host === \"api.zitadel.cloud\") {\n return \"\";\n }\n return `(server: ${url.host})`;\n } catch {\n return \"\";\n }\n}\n\nfunction suffixBlock(opts: GlobalOptions): string {\n const suffix = sourceSuffix(opts);\n return suffix ? ` ${suffix}` : \"\";\n}\n"],"mappings":"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"}
|