@zitadel/cli 0.1.0-alpha.17 → 0.1.0-alpha.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/README.md +210 -124
  2. package/SKILLS.md +159 -17
  3. package/dist/branding-cygSBPkV.mjs +79 -0
  4. package/dist/branding-cygSBPkV.mjs.map +1 -0
  5. package/dist/claim-state-DlfD6Res.mjs +66 -0
  6. package/dist/claim-state-DlfD6Res.mjs.map +1 -0
  7. package/dist/commands/apply.mjs +6 -5
  8. package/dist/commands/apply.mjs.map +1 -1
  9. package/dist/commands/branding/eject.mjs +104 -0
  10. package/dist/commands/branding/eject.mjs.map +1 -0
  11. package/dist/commands/claim.mjs +402 -0
  12. package/dist/commands/claim.mjs.map +1 -0
  13. package/dist/commands/doctor.mjs +500 -37
  14. package/dist/commands/doctor.mjs.map +1 -1
  15. package/dist/commands/eject.mjs +4 -4
  16. package/dist/commands/eject.mjs.map +1 -1
  17. package/dist/commands/logs.mjs +2 -2
  18. package/dist/commands/plan.mjs +6 -5
  19. package/dist/commands/plan.mjs.map +1 -1
  20. package/dist/commands/reset.mjs +2 -2
  21. package/dist/commands/schemas/list.mjs +11 -11
  22. package/dist/commands/schemas/list.mjs.map +1 -1
  23. package/dist/commands/setup.mjs +359 -132
  24. package/dist/commands/setup.mjs.map +1 -1
  25. package/dist/commands/start.mjs +3 -3
  26. package/dist/commands/status.mjs +21 -13
  27. package/dist/commands/status.mjs.map +1 -1
  28. package/dist/commands/stop.mjs +3 -3
  29. package/dist/commands/stop.mjs.map +1 -1
  30. package/dist/designs-Ckz18Dpo.mjs +38 -0
  31. package/dist/designs-Ckz18Dpo.mjs.map +1 -0
  32. package/dist/{docker-pGcTrDIY.mjs → docker-DcRGTOJa.mjs} +4 -3
  33. package/dist/docker-DcRGTOJa.mjs.map +1 -0
  34. package/dist/{environment-BQF7LeCz.mjs → environment-rjRVkJjW.mjs} +1 -1
  35. package/dist/{environment-BQF7LeCz.mjs.map → environment-rjRVkJjW.mjs.map} +1 -1
  36. package/dist/{journey-guidance-CYVpQszz.mjs → journey-guidance-BGrOX_gT.mjs} +14 -3
  37. package/dist/{journey-guidance-CYVpQszz.mjs.map → journey-guidance-BGrOX_gT.mjs.map} +1 -1
  38. package/dist/{oclif-BRdjVNne.mjs → oclif-CanO3zdt.mjs} +247 -43
  39. package/dist/oclif-CanO3zdt.mjs.map +1 -0
  40. package/dist/{orca-Dip6DPJ2.mjs → orca-Cu0iW1mv.mjs} +894 -196
  41. package/dist/orca-Cu0iW1mv.mjs.map +1 -0
  42. package/dist/package-manager-DFdLcDx1.mjs +194 -0
  43. package/dist/package-manager-DFdLcDx1.mjs.map +1 -0
  44. package/dist/{ports-V8JfiNgT.mjs → ports-BM20XIZb.mjs} +2 -2
  45. package/dist/{ports-V8JfiNgT.mjs.map → ports-BM20XIZb.mjs.map} +1 -1
  46. package/dist/{processes-BVqYsxT8.mjs → processes-DKHPkU8O.mjs} +1 -1
  47. package/dist/{processes-BVqYsxT8.mjs.map → processes-DKHPkU8O.mjs.map} +1 -1
  48. package/dist/{project-BGgv7Bba.mjs → project-CHhot85s.mjs} +57 -4
  49. package/dist/project-CHhot85s.mjs.map +1 -0
  50. package/dist/{sync-Cd3z7Q1R.mjs → sync-Bd6vASgg.mjs} +549 -75
  51. package/dist/sync-Bd6vASgg.mjs.map +1 -0
  52. package/dist/user-schema-DTuOsdKE.mjs +91 -0
  53. package/dist/user-schema-DTuOsdKE.mjs.map +1 -0
  54. package/oclif.manifest.json +227 -5
  55. package/package.json +9 -6
  56. package/dist/docker-pGcTrDIY.mjs.map +0 -1
  57. package/dist/oclif-BRdjVNne.mjs.map +0 -1
  58. package/dist/orca-Dip6DPJ2.mjs.map +0 -1
  59. package/dist/project-BGgv7Bba.mjs.map +0 -1
  60. package/dist/sync-Cd3z7Q1R.mjs.map +0 -1
  61. package/dist/user-schema-DDz5-lX5.mjs +0 -13
  62. package/dist/user-schema-DDz5-lX5.mjs.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"sync-Cd3z7Q1R.mjs","names":[],"sources":["../src/lib/flows/env-refs.ts","../src/lib/flows/index.ts","../src/lib/sync/syncers.ts","../src/lib/sync/flow-validation.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 { consola } from \"consola\";\n\nimport { validateFlowDefinition, type FlowValidationIssue } from \"@zitadel/config/validate\";\n\nimport { ZitadelError } from \"../errors\";\nimport { FLOWS_DIR } from \"../flows\";\nimport type { ResourceEntry, SyncAction } from \"./types.js\";\n\n/**\n * Pre-flight semantic validation for every flow this plan uploads,\n * mirroring the server-side `ValidateFlowDefinition` (see\n * `@zitadel/config/validate`). Runs inside `buildSyncPlan`, so `plan`\n * reports the violations the server would only reveal on apply — and\n * `apply` fails before any platform mutation instead of half-applied\n * (a schema revision would otherwise publish before the flow update\n * fails).\n *\n * Only actions that upload a flow (create/update, including repin-forced\n * updates) are validated: an unchanged flow is never re-judged, so a\n * validator behavior change cannot break an already-applied project.\n *\n * Warning-severity issues ANNOTATE the actions in place (`action.warnings`)\n * for plan rendering — `actions` is deliberately typed mutable because the\n * caller (`buildSyncPlan`, which owns the array it just built) expects the\n * annotations. Error-severity issues aggregate into one E_VALIDATION\n * carrying every violation.\n *\n * Escape hatch: setting `ZITADEL_SKIP_FLOW_VALIDATION` skips the check —\n * insurance against a port bug rejecting something the server accepts.\n */\nexport function validatePlannedFlows(opts: {\n actions: SyncAction[];\n scannedContents: ReadonlyMap<string, object>;\n stateResources: Readonly<Record<string, ResourceEntry>>;\n}): void {\n if (process.env.ZITADEL_SKIP_FLOW_VALIDATION) {\n consola.warn(\"Flow validation skipped (ZITADEL_SKIP_FLOW_VALIDATION is set)\");\n return;\n }\n\n const failures: Array<{ path: string; issue: FlowValidationIssue }> = [];\n let anyRepin = false;\n\n // The default-swap warning needs plan-wide context: a project's very\n // first flow becoming the default is expected, an additional one\n // silently taking over /login is the footgun.\n const flowCreatePaths = opts.actions\n .filter((a) => a.kind === \"create\" && a.syncer.kind === \"flow\")\n .map((a) => a.path);\n const trackedFlowPaths = Object.keys(opts.stateResources).filter((path) =>\n path.startsWith(`${FLOWS_DIR}/`),\n );\n\n for (const action of opts.actions) {\n if (action.kind !== \"create\" && action.kind !== \"update\") {\n continue;\n }\n if (action.syncer.kind !== \"flow\") {\n continue;\n }\n\n const issues = validateFlowDefinition(\n action.content,\n resolveSchemaContent(action, opts.scannedContents, opts.stateResources),\n );\n const warnings = issues.filter((issue) => issue.severity === \"warning\");\n if (warnings.length > 0) {\n action.warnings = warnings.map(({ rule, message }) => ({ rule, message }));\n }\n for (const issue of issues) {\n if (issue.severity === \"error\") {\n failures.push({ path: action.path, issue });\n anyRepin ||= action.repin !== undefined;\n }\n }\n\n const swapWarning = defaultSwapWarning(action, flowCreatePaths, trackedFlowPaths);\n if (swapWarning !== undefined) {\n action.warnings = [...(action.warnings ?? []), swapWarning];\n }\n }\n\n if (failures.length === 0) {\n return;\n }\n\n const noun = failures.length === 1 ? \"issue\" : \"issues\";\n throw new ZitadelError(\n \"E_VALIDATION\",\n `Flow validation failed (${failures.length} ${noun}):\\n` +\n failures.map(({ path, issue }) => ` - ${path}: ${issue.message}`).join(\"\\n\"),\n {\n hint:\n \"These are the same rules the server enforces on apply. Fix the flow definition(s) and re-run plan.\" +\n (anyRepin\n ? \" A failing flow is adopting an edited schema revision — update its steps[].fields to match the edited schema (or restore the removed/renamed properties).\"\n : \"\"),\n details: {\n issues: failures.map(({ path, issue }) => ({\n path,\n rule: issue.rule,\n message: issue.message,\n ...(issue.step === undefined ? {} : { step: issue.step }),\n })),\n },\n },\n );\n}\n\n/**\n * Warn when applying a NEW active, unscoped flow into a project that\n * already has flows: the engine's default selection is newest-unscoped-\n * wins (ties broken by id), so this flow silently becomes what\n * `<zitadel-login>` renders for its purposes unless the widget pins a\n * `flow-name`. Deliberately engine-level rather than a validator rule:\n * the verdict depends on the action kind and the rest of the plan/state,\n * which `validateFlowDefinition` never sees. A project's first flow is\n * exempt — becoming the default is the point of creating it.\n */\nfunction defaultSwapWarning(\n action: Extract<SyncAction, { kind: \"create\" | \"update\" }>,\n flowCreatePaths: readonly string[],\n trackedFlowPaths: readonly string[],\n): { rule: string; message: string } | undefined {\n if (action.kind !== \"create\") {\n return undefined; // updates keep their created_at; the default cannot move\n }\n const body = action.content as {\n status?: unknown;\n purposes?: Record<string, unknown>;\n audience?: { team_ids?: unknown[]; app_ids?: unknown[] };\n };\n if (body.status !== \"active\") {\n return undefined;\n }\n const scoped =\n (body.audience?.team_ids?.length ?? 0) > 0 || (body.audience?.app_ids?.length ?? 0) > 0;\n if (scoped) {\n return undefined;\n }\n const purposes = Object.keys(body.purposes ?? {});\n if (purposes.length === 0) {\n return undefined;\n }\n const otherFlows =\n trackedFlowPaths.filter((path) => path !== action.path).length +\n flowCreatePaths.filter((path) => path !== action.path).length;\n if (otherFlows === 0) {\n return undefined;\n }\n return {\n rule: \"warn/default-flow-swap\",\n message:\n `once applied, this flow becomes the new default for ${humanList(purposes)}: ` +\n `pages that do not explicitly set flow-name on <zitadel-login> will start rendering it. ` +\n `If that is not intended, scope it with \"audience\" or set flow-name on the pages that should use it.`,\n };\n}\n\n/** [\"login\", \"register\"] → \"login and register\" (Oxford-free prose list). */\nfunction humanList(items: readonly string[]): string {\n if (items.length <= 1) return items[0] ?? \"\";\n return `${items.slice(0, -1).join(\", \")} and ${items[items.length - 1]}`;\n}\n\n/**\n * Locate the local content of the schema a flow's `user_schema` pins.\n * A repin action already names the schema file (the pin is adopting that\n * file's next/new revision); otherwise the pinned id is looked up in\n * state and its file body taken from this scan. Unresolvable refs (e.g.\n * an un-substituted `${USER_SCHEMA_URL}` placeholder or a server-side\n * schema not tracked locally) return undefined — flow-local rules still\n * run, schema-dependent rules are skipped.\n */\nfunction resolveSchemaContent(\n action: Extract<SyncAction, { kind: \"create\" | \"update\" }>,\n scannedContents: ReadonlyMap<string, object>,\n stateResources: Readonly<Record<string, ResourceEntry>>,\n): object | undefined {\n if (action.repin) {\n return scannedContents.get(action.repin.schemaPath);\n }\n const ref = (action.content as { user_schema?: unknown }).user_schema;\n if (typeof ref !== \"string\" || ref === \"\") {\n return undefined;\n }\n for (const [path, entry] of Object.entries(stateResources)) {\n if (entry.id === ref) {\n return scannedContents.get(path);\n }\n }\n consola.debug(`flow validation: no local schema for user_schema ${ref}; flow-local rules only`);\n return undefined;\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 { validatePlannedFlows } from \"./flow-validation.js\";\nimport type { PlanResourceChange } from \"./plan-renderer.js\";\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\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 // Semantic pre-flight over every flow this plan uploads — the rules the\n // server would otherwise enforce mid-apply, after the schema revision\n // already published. Throws E_VALIDATION before any mutation.\n validatePlannedFlows({ actions, scannedContents, stateResources: state.resources });\n\n return actions;\n}\n\n/** Result of {@link runSyncLoop}: what changed on the platform and locally. */\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 * The platform resources this run touched, in execution order. Unlike a\n * plan-time enumeration, `id` carries the resulting platform id (the\n * created id, the newly published revision id, or the id updated or\n * deleted). Feeds the `apply` `--json` `changes` array.\n */\n applied: PlanResourceChange[];\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 for (const action of actions) {\n if (action.kind === \"create\" || action.kind === \"update\") {\n for (const warning of action.warnings ?? []) {\n consola.warn(`${action.path}: ${warning.message}`);\n }\n }\n }\n const filesUpdated: string[] = [];\n const applied: PlanResourceChange[] = [];\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 applied.push({ kind: action.syncer.kind, action: \"create\", file: action.path, id });\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 applied.push({\n kind: action.syncer.kind,\n action: \"revision\",\n file: action.path,\n id,\n previous_id: action.previousId,\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 applied.push({ kind: action.syncer.kind, action: \"update\", file: action.path, id: action.id });\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 applied.push({ kind: action.syncer.kind, action: \"delete\", file: action.path, id: action.id });\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)], applied };\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 let 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 Record<string, unknown>;\n changed = compare(writeBody) !== compare(onDisk);\n // `$schema` is a local editor affordance (points at the dialect spec in\n // .zitadel/meta/); the server never echoes it, so a rewrite would drop\n // it. Carry the on-disk pointer over unless the canonical body has its\n // own (user-schema documents do).\n if (typeof onDisk.$schema === \"string\" && !(\"$schema\" in writeBody)) {\n writeBody = { ...writeBody, $schema: onDisk.$schema };\n }\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\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 * Collect the plan-time validation warnings across all actions, tagged\n * with the file they belong to. Feeds the `plan` / `apply --dry-run`\n * `--json` payload so agents can read warnings structurally.\n */\nexport function collectPlanWarnings(\n actions: ReadonlyArray<SyncAction>,\n): Array<{ path: string; rule: string; message: string }> {\n const out: Array<{ path: string; rule: string; message: string }> = [];\n for (const action of actions) {\n if (action.kind !== \"create\" && action.kind !== \"update\") {\n continue;\n }\n for (const warning of action.warnings ?? []) {\n out.push({ path: action.path, rule: warning.rule, message: warning.message });\n }\n }\n return out;\n}\n\n/**\n * One entry of the `changes` array in the `plan` / `apply` `--json`\n * payloads: which resource an action touches and how. `action` speaks the\n * envelope's public vocabulary (`revision`, matching the `revisions`\n * counter, not the internal `revise`). `id` is the platform id an\n * update/delete targets; `previous_id` is the revision being superseded.\n * The file path is the resource identity, mirroring {@link renderPlan}.\n */\nexport type PlanResourceChange = {\n kind: ResourceSyncer[\"kind\"];\n action: \"create\" | \"update\" | \"revision\" | \"delete\";\n file: string;\n id?: string;\n previous_id?: string;\n};\n\n/**\n * Enumerate the non-`skip` actions of a {@link buildSyncPlan} result as\n * envelope-ready {@link PlanResourceChange} rows. Pure; the structural\n * counterpart of {@link summarizePlan} — counts and rows always agree.\n */\nexport function enumeratePlanResources(\n actions: ReadonlyArray<SyncAction>,\n): PlanResourceChange[] {\n const out: PlanResourceChange[] = [];\n for (const action of actions) {\n switch (action.kind) {\n case \"create\":\n out.push({ kind: action.syncer.kind, action: \"create\", file: action.path });\n break;\n case \"update\":\n out.push({ kind: action.syncer.kind, action: \"update\", file: action.path, id: action.id });\n break;\n case \"revise\":\n out.push({\n kind: action.syncer.kind,\n action: \"revision\",\n file: action.path,\n previous_id: action.previousId,\n });\n break;\n case \"delete\":\n out.push({ kind: action.syncer.kind, action: \"delete\", file: action.path, id: action.id });\n break;\n case \"skip\":\n break;\n }\n }\n return out;\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\n const warningCount = active.reduce(\n (count, action) =>\n count +\n ((action.kind === \"create\" || action.kind === \"update\") && action.warnings\n ? action.warnings.length\n : 0),\n 0,\n );\n if (warningCount > 0) {\n out.push(\n paint(\n `Warnings: ${warningCount} (non-blocking — see the # warning lines above).`,\n A.yellow,\n tty,\n ),\n );\n }\n\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 renderWarnings(action.warnings, blkPad, tty, lines);\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 renderWarnings(action.warnings, blkPad, tty, lines);\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\n/**\n * Emit one yellow `# warning:` comment line per plan-time validation\n * warning, below the action's closing brace (same channel as the revise\n * re-pin announcement). Warnings never block the plan.\n */\nfunction renderWarnings(\n warnings: ReadonlyArray<{ message: string }> | undefined,\n blkPad: string,\n tty: boolean,\n lines: string[],\n): void {\n for (const warning of warnings ?? []) {\n lines.push(paint(`${blkPad}# warning: ${warning.message}`, A.yellow, tty));\n }\n}\n"],"mappings":"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"}
@@ -1,13 +0,0 @@
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
@@ -1 +0,0 @@
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"}