@zitadel/cli 0.1.0-alpha.1 → 0.1.0-alpha.3

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 (33) hide show
  1. package/README.md +47 -31
  2. package/SKILLS.md +34 -14
  3. package/dist/commands/apply.mjs +4 -4
  4. package/dist/commands/doctor.mjs +56 -33
  5. package/dist/commands/doctor.mjs.map +1 -1
  6. package/dist/commands/eject.mjs +4 -4
  7. package/dist/commands/logs.mjs +4 -4
  8. package/dist/commands/logs.mjs.map +1 -1
  9. package/dist/commands/plan.mjs +4 -4
  10. package/dist/commands/reset.mjs +6 -7
  11. package/dist/commands/reset.mjs.map +1 -1
  12. package/dist/commands/setup.mjs +189 -25
  13. package/dist/commands/setup.mjs.map +1 -1
  14. package/dist/commands/start.mjs +13 -17
  15. package/dist/commands/start.mjs.map +1 -1
  16. package/dist/commands/status.mjs +18 -13
  17. package/dist/commands/status.mjs.map +1 -1
  18. package/dist/commands/stop.mjs +5 -6
  19. package/dist/commands/stop.mjs.map +1 -1
  20. package/dist/{docker-C0aVpJqm.mjs → docker-D6pJKCLR.mjs} +6 -5
  21. package/dist/docker-D6pJKCLR.mjs.map +1 -0
  22. package/dist/{oclif-DSPO9Sck.mjs → oclif-D-R4dfQr.mjs} +109 -39
  23. package/dist/oclif-D-R4dfQr.mjs.map +1 -0
  24. package/dist/{orca-DOxshV9n.mjs → orca-BX4AhKLD.mjs} +137 -26
  25. package/dist/{orca-DOxshV9n.mjs.map → orca-BX4AhKLD.mjs.map} +1 -1
  26. package/dist/{project-Dwb9WVAT.mjs → project-DZJfxYKW.mjs} +3 -3
  27. package/dist/{project-Dwb9WVAT.mjs.map → project-DZJfxYKW.mjs.map} +1 -1
  28. package/dist/{sync-DmtTYNmq.mjs → sync-BJ0Sqb8w.mjs} +3 -3
  29. package/dist/{sync-DmtTYNmq.mjs.map → sync-BJ0Sqb8w.mjs.map} +1 -1
  30. package/oclif.manifest.json +7 -1
  31. package/package.json +3 -3
  32. package/dist/docker-C0aVpJqm.mjs.map +0 -1
  33. package/dist/oclif-DSPO9Sck.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"orca-DOxshV9n.mjs","names":[],"sources":["../src/lib/orca/detectors/package-json.ts","../src/lib/orca/detectors/port.ts","../src/lib/orca/detectors/next.ts","../src/lib/orca/detectors/index.ts","../src/lib/orca/patchers/rule/file-writer/index.ts","../src/lib/orca/patchers/rule/reclaim.ts","../src/lib/orca/patchers/rule/base.ts","../src/lib/orca/patchers/rule/next/renderers/lit/index.ts","../src/lib/orca/patchers/rule/next/renderers/react/index.ts","../src/lib/orca/patchers/rule/next/renderers/registry.ts","../src/lib/orca/patchers/rule/next/index.ts","../src/lib/orca/patchers/index.ts","../src/lib/orca/scaffolders/cli.ts","../src/lib/orca/scaffolders/next.ts","../src/lib/orca/scaffolders/index.ts","../src/lib/orca/index.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\n/**\n * Minimal shape of the `package.json` fields detectors read. Intentionally\n * partial: only the keys detection logic depends on are modeled, all optional\n * since a project may omit any of them.\n */\nexport type PackageJson = {\n name?: string;\n scripts?: Record<string, string>;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n};\n\n/**\n * Reads and parses the `package.json` at `cwd`. Rejects if the file is absent\n * or malformed; callers that treat those as \"not a project\" are expected to\n * catch and fall back rather than have detection swallow the error here.\n */\nexport async function readPackageJson(cwd: string): Promise<PackageJson> {\n const contents = await readFile(join(cwd, \"package.json\"), \"utf8\");\n return JSON.parse(contents) as PackageJson;\n}\n\n/**\n * Reports whether `name` appears in either `dependencies` or `devDependencies`.\n * Both are checked because framework packages may legitimately live in either.\n */\nexport function hasDependency(pkg: PackageJson, name: string): boolean {\n return Boolean(pkg.dependencies?.[name] ?? pkg.devDependencies?.[name]);\n}\n","import { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport type { PackageJson } from \"./package-json\";\n\n/**\n * Port assumed when no explicit dev port can be discovered. Matches Next.js's\n * own default so the inferred issuer URL lines up with `next dev`.\n */\nexport const DEFAULT_DEV_PORT = 3000;\n\n/**\n * Determines the local dev-server port for `cwd`. The `dev` script is the most\n * authoritative source, then a `PORT` declaration in an env file, falling back\n * to {@link DEFAULT_DEV_PORT}. Used to derive the local issuer URL.\n */\nexport async function detectDevPort(cwd: string, pkg: PackageJson): Promise<number> {\n const dev = pkg.scripts?.dev;\n const fromScript = typeof dev === \"string\" ? extractPort(dev) : undefined;\n if (fromScript) {\n return fromScript;\n }\n\n const fromEnvFile = await portFromEnvFile(cwd);\n if (fromEnvFile) {\n return fromEnvFile;\n }\n\n return DEFAULT_DEV_PORT;\n}\n\nasync function portFromEnvFile(cwd: string): Promise<number | undefined> {\n for (const candidate of [\".env.local\", \".env\"]) {\n try {\n const contents = await readFile(join(cwd, candidate), \"utf8\");\n const match = contents.match(/^\\s*PORT\\s*=\\s*(\\d+)/m);\n const rawPort = match?.[1];\n if (rawPort) {\n return Number.parseInt(rawPort, 10);\n }\n } catch {\n continue;\n }\n }\n return undefined;\n}\n\n/**\n * Parses a dev port out of an npm `dev` script string, recognizing both flag\n * forms (`-p`/`--port`) and a leading `PORT=` env assignment. Returns\n * `undefined` when no valid positive port is present so callers can fall back.\n */\nexport function extractPort(script: string): number | undefined {\n const inline = script.match(/-p\\s+(\\d+)|--port[=\\s]+(\\d+)/);\n if (inline) {\n const raw = inline[1] ?? inline[2];\n if (!raw) {\n return undefined;\n }\n const value = Number.parseInt(raw, 10);\n if (Number.isFinite(value) && value > 0) {\n return value;\n }\n }\n const env = script.match(/(?:^|\\s)PORT=(\\d+)/);\n const rawEnvPort = env?.[1];\n if (rawEnvPort) {\n return Number.parseInt(rawEnvPort, 10);\n }\n return undefined;\n}\n\n/**\n * Builds the local OIDC issuer URL for a given dev port. Centralized so the\n * `localhost` origin convention is defined in exactly one place.\n */\nexport function issuerFromPort(port: number): string {\n return `http://localhost:${port}`;\n}\n","import { stat } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { ZitadelError } from \"../../errors\";\nimport { hasDependency, readPackageJson } from \"./package-json\";\nimport { detectDevPort, issuerFromPort } from \"./port\";\nimport type { Detector, FrameworkFacts } from \"./types\";\n\n/**\n * Detects a Next.js App Router project and extracts its facts: the App Router\n * directory (`app` vs `src/app`), the dev-server port (parsed from the `dev`\n * script / env file, else 3000), and the derived local issuer URL. Owns every\n * Next-specific assumption so the orchestrator and commands stay generic.\n */\nexport class NextDetector implements Detector {\n readonly framework = \"next\";\n\n /**\n * Returns `null` when `cwd` is not a Next.js project (no `next` dependency),\n * so the orchestrator can try other detectors. Throws\n * `E_UNSUPPORTED_PROJECT_SHAPE` when it is Next.js but lacks an App Router\n * directory (e.g. a Pages Router project), which is a hard error rather than\n * an empty directory to scaffold.\n */\n async detect(cwd: string): Promise<FrameworkFacts | null> {\n const pkg = await readPackageJson(cwd).catch(() => undefined);\n if (!pkg || !hasDependency(pkg, \"next\")) {\n return null;\n }\n\n const appDir = (await dirExists(join(cwd, \"app\")))\n ? \"app\"\n : (await dirExists(join(cwd, \"src/app\")))\n ? \"src/app\"\n : undefined;\n if (!appDir) {\n throw new ZitadelError(\n \"E_UNSUPPORTED_PROJECT_SHAPE\",\n \"Next.js Pages Router projects are not supported in v1\",\n { hint: \"Create an App Router project with an app/ or src/app/ directory.\" },\n );\n }\n\n const devPort = await detectDevPort(cwd, pkg);\n return { id: \"next\", appDir, devPort, url: issuerFromPort(devPort) };\n }\n}\n\nasync function dirExists(path: string): Promise<boolean> {\n try {\n return (await stat(path)).isDirectory();\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 false;\n }\n throw error;\n }\n}\n","import { NextDetector } from \"./next\";\nimport type { Detector } from \"./types\";\n\n/**\n * Active detectors, in probe order. The orchestrator tries each until one\n * recognises the project. Add a framework by appending its detector here — no\n * orchestrator changes needed.\n */\nexport const detectors = [new NextDetector()] as const satisfies ReadonlyArray<Detector>;\n","import { chmod, mkdir, readFile, rename, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\n\nimport { ZitadelError } from \"../../../../errors\";\nimport { isObject, parseJsonObject, stableStringify } from \"../../../../json\";\nimport type { FileOp, ScaffoldPlan, ScaffoldResult } from \"./types\";\n\n/**\n * The executor's private, mutable accumulator. Handlers push into it as each\n * op is applied; {@link scaffold} returns it as the readonly\n * {@link ScaffoldResult} so the public result stays immutable.\n */\ntype ScaffoldAccumulator = {\n dryRun: boolean;\n filesWritten: string[];\n filesSkipped: string[];\n depsAdded: string[];\n};\n\n/**\n * Applies a {@link ScaffoldPlan} to disk, executing its operations in order.\n *\n * Operations are idempotent: writes whose target already matches the desired\n * contents are recorded as skipped rather than rewritten, so re-running setup\n * is safe. With `dryRun` no filesystem changes are made but the result still\n * reflects what would have been written. Existing files are only overwritten\n * when `force` is set; otherwise an `E_CONFLICT` is thrown to protect\n * user-authored content. Paths in the plan are resolved relative to `cwd`.\n */\nexport async function scaffold(\n plan: ScaffoldPlan,\n opts: { cwd: string; dryRun: boolean; force: boolean },\n): Promise<ScaffoldResult> {\n const result: ScaffoldAccumulator = {\n dryRun: opts.dryRun,\n filesWritten: [],\n filesSkipped: [],\n depsAdded: [],\n };\n\n for (const op of plan.ops) {\n await applyOp(op, opts, result);\n }\n\n return result;\n}\n\nasync function applyOp(\n op: FileOp,\n opts: { cwd: string; dryRun: boolean; force: boolean },\n result: ScaffoldAccumulator,\n): Promise<void> {\n switch (op.kind) {\n case \"mkdir\":\n await ensureDir(abs(opts.cwd, op.path), op.mode, opts.dryRun, result);\n break;\n case \"write\":\n await writeText(\n abs(opts.cwd, op.path),\n op.contents,\n { mode: op.mode, force: opts.force, dryRun: opts.dryRun },\n result,\n );\n break;\n case \"append\":\n await appendText(abs(opts.cwd, op.path), op.contents, op.ifMissing, opts.dryRun, result);\n break;\n case \"merge-env\":\n await mergeEnv(abs(opts.cwd, op.path), op.entries, opts.dryRun, result);\n break;\n case \"merge-json\":\n await mergeJson(abs(opts.cwd, op.path), op.patch, opts.dryRun, result);\n break;\n case \"append-gitignore\":\n await appendGitignore(abs(opts.cwd, \".gitignore\"), op.entries, opts.dryRun, result);\n break;\n case \"add-dep\":\n await addDependency(abs(opts.cwd, \"package.json\"), op, opts.dryRun, result);\n break;\n }\n}\n\nasync function ensureDir(\n path: string,\n mode: number | undefined,\n dryRun: boolean,\n result: ScaffoldAccumulator,\n): Promise<void> {\n if (dryRun) {\n result.filesWritten.push(path);\n return;\n }\n await mkdir(path, { recursive: true, mode });\n if (mode) {\n await chmod(path, mode).catch(() => undefined);\n }\n result.filesWritten.push(path);\n}\n\nasync function writeText(\n path: string,\n contents: string,\n opts: { mode?: number; force: boolean; dryRun: boolean },\n result: ScaffoldAccumulator,\n): Promise<void> {\n const existing = await readIfExists(path);\n if (existing === contents) {\n result.filesSkipped.push(path);\n return;\n }\n\n if (existing !== undefined && !opts.force) {\n throw new ZitadelError(\"E_CONFLICT\", `Refusing to overwrite ${path}`, {\n hint: \"Re-run with --force if you want the CLI to replace this file.\",\n details: { path },\n });\n }\n\n if (opts.dryRun) {\n result.filesWritten.push(path);\n return;\n }\n\n await mkdir(dirname(path), { recursive: true });\n const tmp = `${path}.tmp-${process.pid}-${Date.now()}`;\n await writeFile(tmp, contents, { mode: opts.mode });\n if (opts.mode) {\n await chmod(tmp, opts.mode).catch(() => undefined);\n }\n await rename(tmp, path);\n result.filesWritten.push(path);\n}\n\nasync function appendText(\n path: string,\n contents: string,\n ifMissing: string | undefined,\n dryRun: boolean,\n result: ScaffoldAccumulator,\n): Promise<void> {\n const existing = (await readIfExists(path)) ?? \"\";\n if (ifMissing && existing.includes(ifMissing)) {\n result.filesSkipped.push(path);\n return;\n }\n\n const next = `${existing}${existing && !existing.endsWith(\"\\n\") ? \"\\n\" : \"\"}${contents}`;\n if (next === existing) {\n result.filesSkipped.push(path);\n return;\n }\n\n if (dryRun) {\n result.filesWritten.push(path);\n return;\n }\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, next);\n result.filesWritten.push(path);\n}\n\nasync function mergeEnv(\n path: string,\n entries: Readonly<Record<string, string>>,\n dryRun: boolean,\n result: ScaffoldAccumulator,\n): Promise<void> {\n const existing = (await readIfExists(path)) ?? \"\";\n const present = new Set(\n existing\n .split(/\\r?\\n/g)\n .map((line) => line.match(/^\\s*([A-Za-z_][A-Za-z0-9_]*)=/)?.[1])\n .filter((value): value is string => Boolean(value)),\n );\n const additions = Object.entries(entries).filter(([key]) => !present.has(key));\n if (additions.length === 0) {\n result.filesSkipped.push(path);\n return;\n }\n\n const block = additions.map(([key, value]) => `${key}=${value}`).join(\"\\n\");\n const next = `${existing}${existing && !existing.endsWith(\"\\n\") ? \"\\n\" : \"\"}${block}\\n`;\n if (dryRun) {\n result.filesWritten.push(path);\n return;\n }\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, next);\n result.filesWritten.push(path);\n}\n\nasync function mergeJson(\n path: string,\n patch: Readonly<Record<string, unknown>>,\n dryRun: boolean,\n result: ScaffoldAccumulator,\n): Promise<void> {\n const existing = await readIfExists(path);\n const current = existing ? parseJsonObject(existing, path) : {};\n const next = deepMerge(current, patch);\n const contents = `${stableStringify(next)}\\n`;\n if (existing === contents) {\n result.filesSkipped.push(path);\n return;\n }\n if (dryRun) {\n result.filesWritten.push(path);\n return;\n }\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, contents);\n result.filesWritten.push(path);\n}\n\nasync function appendGitignore(\n path: string,\n entries: ReadonlyArray<string>,\n dryRun: boolean,\n result: ScaffoldAccumulator,\n): Promise<void> {\n const existing = (await readIfExists(path)) ?? \"\";\n const lines = new Set(existing.split(/\\r?\\n/g).map((line) => line.trim()));\n const missing = entries.filter((entry) => !lines.has(entry));\n if (missing.length === 0) {\n result.filesSkipped.push(path);\n return;\n }\n const next = `${existing}${existing && !existing.endsWith(\"\\n\") ? \"\\n\" : \"\"}${missing.join(\"\\n\")}\\n`;\n if (dryRun) {\n result.filesWritten.push(path);\n return;\n }\n await writeFile(path, next);\n result.filesWritten.push(path);\n}\n\nasync function addDependency(\n path: string,\n op: { name: string; version: string; dev?: boolean },\n dryRun: boolean,\n result: ScaffoldAccumulator,\n): Promise<void> {\n const existing = await readIfExists(path);\n if (!existing) {\n throw new ZitadelError(\"E_VALIDATION\", \"package.json is required to add Zitadel dependencies\");\n }\n const current = parseJsonObject(existing, path);\n const key = op.dev ? \"devDependencies\" : \"dependencies\";\n const deps = isObject(current[key]) ? (current[key] as Record<string, unknown>) : {};\n if (deps[op.name] === op.version) {\n result.filesSkipped.push(path);\n return;\n }\n current[key] = { ...deps, [op.name]: op.version };\n const contents = `${stableStringify(current)}\\n`;\n if (dryRun) {\n result.filesWritten.push(path);\n result.depsAdded.push(op.name);\n return;\n }\n await writeFile(path, contents);\n result.filesWritten.push(path);\n result.depsAdded.push(op.name);\n}\n\nasync function readIfExists(path: string): Promise<string | undefined> {\n try {\n return await readFile(path, \"utf8\");\n } catch (error) {\n if (typeof error === \"object\" && error !== null && \"code\" in error && error.code === \"ENOENT\") {\n return undefined;\n }\n throw error;\n }\n}\n\nfunction abs(cwd: string, path: string): string {\n return join(cwd, path);\n}\n\nfunction deepMerge(\n target: Record<string, unknown>,\n patch: Readonly<Record<string, unknown>>,\n): Record<string, unknown> {\n const out = { ...target };\n for (const [key, value] of Object.entries(patch)) {\n if (isObject(value) && isObject(out[key])) {\n out[key] = deepMerge(out[key] as Record<string, unknown>, value);\n } else {\n out[key] = value;\n }\n }\n return out;\n}\n","import { MANAGED_MARKER } from \"../../../paths\";\nimport type { FileOp, ScaffoldPlan } from \"./file-writer/types\";\n\n/**\n * The subset of a patcher plan's operations that `doctor --fix` re-applies:\n * env merges, gitignore entries, dependency additions, and marker-bearing\n * managed files (framework routes/middleware). Deliberately excludes the\n * unmarked `.zitadel/` resource writes and `zitadel.json` — those are\n * user-editable and synced by `apply`, so `--fix` must not clobber them.\n *\n * Pure: filters a freshly-allocated list; the input plan is not mutated.\n */\nexport function reclaimableOps(plan: ScaffoldPlan): FileOp[] {\n return plan.ops.filter(\n (op) =>\n op.kind === \"merge-env\" ||\n op.kind === \"append-gitignore\" ||\n op.kind === \"add-dep\" ||\n (op.kind === \"write\" && op.contents.includes(MANAGED_MARKER)),\n );\n}\n","import { stableStringify } from \"../../../json\";\nimport { DEFAULT_SERVER } from \"../../../server\";\nimport { scaffold } from \"./file-writer\";\nimport type { FileOp, ScaffoldPlan } from \"./file-writer/types\";\nimport type {\n EjectActions,\n Patcher,\n PatchContext,\n PatchExecOptions,\n PatchResult,\n PatchView,\n} from \"../types\";\nimport { reclaimableOps } from \"./reclaim\";\n\n/**\n * Base for rule-based (deterministic, template-driven) patchers, as opposed to\n * a future LLM-driven family. It applies the integration by building a\n * file-operation plan and running the file-writer — that strategy stays\n * entirely inside this family, so callers only ever see the family-neutral\n * {@link Patcher} surface. Owns the framework-agnostic `.zitadel/` base files\n * and the shared eject classification; subclasses contribute only their\n * framework-specific routes/middleware.\n */\nexport abstract class AbstractRulePatcher implements Patcher {\n abstract canPatch(framework: string): boolean;\n\n /** Apply the full plan (base `.zitadel/` files + framework routes). */\n async patch(ctx: PatchContext, opts: PatchExecOptions): Promise<PatchResult> {\n return scaffold(this.plan(ctx), opts);\n }\n\n /**\n * Re-apply only the reclaimable subset — env files, gitignore, the SDK\n * dependency, and marker-bearing routes — leaving the user-editable\n * `.zitadel/` resources untouched. Backs `doctor --fix`.\n */\n async repair(ctx: PatchContext, opts: PatchExecOptions): Promise<PatchResult> {\n const plan = this.plan(ctx);\n return scaffold({ ops: reclaimableOps(plan), summary: plan.summary }, opts);\n }\n\n /** Shared base artifacts plus the subclass's marker-bearing route files. */\n artifacts(view: PatchView): EjectActions {\n return {\n markedFiles: this.routeFiles(view),\n rootConfigFiles: [\"zitadel.json\"],\n directories: [\".zitadel\"],\n envBackups: [\".env.local\"],\n dependencies: this.routeDeps(view),\n };\n }\n\n /**\n * The full file-operation plan this patcher would apply. Public so rule-family\n * unit tests can assert the planned ops directly; the generic {@link Patcher}\n * interface deliberately does not expose it (an LLM patcher has no such plan).\n */\n plan(ctx: PatchContext): ScaffoldPlan {\n return {\n ops: [...this.baseOps(ctx), ...this.routeOps(ctx)],\n summary: [this.summary(ctx)],\n };\n }\n\n /**\n * The framework-agnostic `.zitadel/` base files every rule patcher writes:\n * the project secret, `zitadel.json`, env templates, and an empty sync\n * state. The `schemas/` and `flows/` directories are created empty — the\n * server provisions the default user schema and flow definition when the\n * project is created, so nothing is scaffolded into them here. Pure: no\n * filesystem or network.\n */\n private baseOps(ctx: PatchContext): ReadonlyArray<FileOp> {\n return [\n { kind: \"mkdir\", path: \".zitadel\", mode: 0o700 },\n { kind: \"mkdir\", path: \".zitadel/flows\" },\n { kind: \"mkdir\", path: \".zitadel/schemas\" },\n { kind: \"append-gitignore\", entries: [\".zitadel/secret\", \".env*\", \"!.env.example\"] },\n {\n kind: \"write\",\n path: \".zitadel/secret\",\n mode: 0o600,\n contents: `${stableStringify({\n project_id: ctx.project.id,\n project_secret: ctx.project.projectSecret,\n preview_secret: ctx.project.previewSecret,\n preview_origins: ctx.project.previewOrigins,\n created_at: ctx.project.createdAt,\n })}\\n`,\n },\n { kind: \"write\", path: \"zitadel.json\", contents: `${stableStringify(projectConfig(ctx))}\\n` },\n {\n kind: \"merge-env\",\n path: \".env.example\",\n entries: {\n ZITADEL_PROJECT_ID: \"\",\n ZITADEL_ENVIRONMENT: \"\",\n ZITADEL_ISSUER: \"\",\n ZITADEL_URL: \"\",\n NEXT_PUBLIC_ZITADEL_PROJECT_ID: \"\",\n },\n },\n {\n kind: \"merge-env\",\n path: \".env.local\",\n entries: {\n ZITADEL_PROJECT_ID: ctx.project.id,\n ZITADEL_ENVIRONMENT: \"development\",\n ZITADEL_ISSUER: ctx.issuer,\n ZITADEL_URL: ctx.server,\n NEXT_PUBLIC_ZITADEL_PROJECT_ID: ctx.project.id,\n },\n },\n {\n kind: \"write\",\n path: \".zitadel/state.json\",\n contents: `${stableStringify({ framework: ctx.framework.id, resources: {} })}\\n`,\n },\n ];\n }\n\n /** Framework-specific route/middleware write ops plus the SDK dependency. */\n protected abstract routeOps(ctx: PatchContext): ReadonlyArray<FileOp>;\n /** Framework-specific managed (marker-bearing) file paths, for ejection. */\n protected abstract routeFiles(view: PatchView): ReadonlyArray<string>;\n /**\n * The package-manager dependencies the integration added, surfaced in\n * `eject`'s `next_commands` so the user can uninstall them themselves.\n */\n protected abstract routeDeps(view: PatchView): ReadonlyArray<string>;\n /** One-line summary of what the integration scaffolded. */\n protected abstract summary(ctx: PatchContext): { title: string; detail: string };\n}\n\n/** Builds the `zitadel.json` body persisted at the project root. */\nfunction projectConfig(ctx: PatchContext): Record<string, unknown> {\n const environments: Record<string, unknown> = { development: { issuer: ctx.issuer } };\n if (ctx.project.previewOrigins.length > 0) {\n environments.preview = {\n issuer_pattern: ctx.project.previewOrigins.map((origin) => `https://${origin}`),\n };\n }\n return {\n $schema: \"https://schemas.zitadel.com/v2/project.schema.json\",\n project: ctx.project.id,\n server: resolveServerOrigin(ctx.server),\n framework: { id: ctx.framework.id },\n branding: { renderer: ctx.rendererId, attribution: \"visible\" },\n environments,\n };\n}\n\n/** Normalizes a server URL to its origin, falling back to {@link DEFAULT_SERVER}. */\nfunction resolveServerOrigin(source: string): string {\n try {\n return new URL(source).origin;\n } catch {\n return DEFAULT_SERVER;\n }\n}\n","import { MANAGED_MARKER } from \"../../../../../../paths\";\nimport type { RendererSpec } from \"../types\";\n\n/**\n * Placeholder renderer for the `<zitadel-flow>` Lit web component. Declared\n * so the `web-component` renderer id resolves and surfaces a clear\n * \"not yet published\" error, while reserving the integration shape for when\n * `@zitadel/ui-lit` ships. The `authPage` template emits an illustrative\n * page only; this renderer is never selected for real scaffolding because\n * `getRenderer` rejects any `status: \"not-implemented\"` spec.\n */\nexport const litRenderer: RendererSpec = {\n id: \"web-component\",\n displayName: \"Web component (<zitadel-flow>)\",\n status: \"not-implemented\",\n frameworks: [\"next\", \"astro\", \"remix\", \"sveltekit\", \"nuxt\", \"vanilla\"],\n dependency: { name: \"@zitadel/ui-lit\", version: \"workspace:*\" },\n templates: {\n authPage(mode) {\n const purpose = mode === \"login\" ? \"login\" : \"register\";\n return {\n mode,\n contents: `${MANAGED_MARKER}\n// The web component renderer ships a <zitadel-flow> element. Until\n// @zitadel/ui-lit is published, this template only declares the\n// intended integration point. See docs/design/cli/bdui-renderer.md.\nimport \"@zitadel/ui-lit\";\n\nconst environment =\n process.env.ZITADEL_ENVIRONMENT ??\n (process.env.NODE_ENV === \"production\" ? \"production\" : \"development\");\n\nexport default function ${mode === \"login\" ? \"LoginPage\" : \"RegisterPage\"}() {\n return (\n <zitadel-flow\n purpose=\"${purpose}\"\n project-id={process.env.ZITADEL_PROJECT_ID}\n issuer={process.env.ZITADEL_ISSUER}\n environment={environment}\n />\n );\n}\n`,\n };\n },\n },\n};\n","import { MANAGED_MARKER } from \"../../../../../../paths\";\nimport type { RendererSpec } from \"../types\";\n\n/**\n * The Next.js App Router renderer scaffolds `/login`, `/register`, and\n * `/profile` pages that drive the `<zitadel-login>` and `<zitadel-logout>`\n * Lit web components.\n *\n * Each page is a single client component (`\"use client\"`) that, inside a\n * `next/dynamic({ ssr: false })` loader, builds the SDK project handle with\n * `configureZitadel({ projectId, proxyPath: \"/__nextgen\" })` and passes it to\n * the widget via `project={...}`. It also imports\n * `@zitadel/sdk-next/client` for its `customElements.define`\n * side-effect — importing `@zitadel/components` directly would fail on\n * strict-resolution package managers (pnpm, yarn PnP) because the app only\n * declares `sdk-next` as a direct dep. SSR is disabled because Lit's element\n * registration needs a browser.\n *\n * The handle is passed as the `project` DOM property, which relies on React\n * 19's custom-element property binding (the scaffold targets the latest Next /\n * React). The backend URL never reaches the browser: the client talks to the\n * same-origin `/__nextgen` proxy path, and the scaffolded `middleware.ts`\n * forwards it to `ZITADEL_URL` server-side. `NEXT_PUBLIC_ZITADEL_PROJECT_ID` is\n * public — the project id is not sensitive and the widget needs it to start a\n * flow.\n */\nexport const reactRenderer: RendererSpec = {\n id: \"react\",\n displayName: \"React (Next.js App Router)\",\n status: \"available\",\n frameworks: [\"next\"],\n dependency: { name: \"@zitadel/sdk-next\", version: \"latest\" },\n templates: {\n authPage(mode) {\n const componentName = mode === \"login\" ? \"LoginPage\" : \"RegisterPage\";\n const elementName = mode === \"login\" ? \"ZitadelLogin\" : \"ZitadelRegister\";\n return {\n mode,\n contents: `${MANAGED_MARKER}\n\"use client\";\n\nimport dynamic from \"next/dynamic\";\n\nconst ${elementName} = dynamic(\n async () => {\n const { configureZitadel } = await import(\"@zitadel/sdk-next/client\");\n // Build the SDK project handle and pass it to the component via the\n // \\`project\\` prop. The component reads config from this prop directly, so\n // it works regardless of how the SDK packages are bundled. The backend URL\n // stays server-side — requests go through the proxy path \"/__nextgen\",\n // which the scaffolded middleware forwards to the Zitadel server.\n const project = configureZitadel({\n projectId: process.env.NEXT_PUBLIC_ZITADEL_PROJECT_ID ?? \"\",\n proxyPath: \"/__nextgen\",\n });\n return function ${elementName}Element() {\n return (\n <zitadel-login\n project={project}\n purpose=\"${mode}\"\n post-sign-in-url=\"/profile\"\n />\n );\n };\n },\n { ssr: false },\n);\n\nexport default function ${componentName}() {\n return (\n <main style={{ minHeight: \"100vh\", display: \"flex\", alignItems: \"center\", justifyContent: \"center\" }}>\n <${elementName} />\n </main>\n );\n}\n`,\n };\n },\n profilePage() {\n return {\n contents: `${MANAGED_MARKER}\n\"use client\";\n\nimport dynamic from \"next/dynamic\";\n\nconst ZitadelLogout = dynamic(\n async () => {\n const { configureZitadel } = await import(\"@zitadel/sdk-next/client\");\n const project = configureZitadel({\n projectId: process.env.NEXT_PUBLIC_ZITADEL_PROJECT_ID ?? \"\",\n proxyPath: \"/__nextgen\",\n });\n return function ZitadelLogoutElement() {\n return (\n <zitadel-logout\n project={project}\n post-sign-out-url=\"/login\"\n />\n );\n };\n },\n { ssr: false },\n);\n\nexport default function ProfilePage() {\n return (\n <main style={{ padding: \"48px\", maxWidth: \"600px\", margin: \"0 auto\" }}>\n <div style={{ display: \"flex\", alignItems: \"center\", justifyContent: \"space-between\", marginBottom: \"24px\" }}>\n <h1 style={{ fontSize: \"24px\", fontWeight: 700, margin: 0 }}>Signed in</h1>\n <ZitadelLogout />\n </div>\n <p style={{ color: \"#6b7280\" }}>You are signed in. Use the button above to log out.</p>\n </main>\n );\n}\n`,\n };\n },\n customElementsDts() {\n return {\n contents: `${MANAGED_MARKER}\nimport type React from \"react\";\nimport type { ZitadelProject } from \"@zitadel/sdk-next/client\";\n\ndeclare module \"react\" {\n namespace JSX {\n interface IntrinsicElements {\n \"zitadel-login\": React.HTMLAttributes<HTMLElement> & {\n project?: ZitadelProject;\n \"session-exchange-path\"?: string;\n \"post-sign-in-url\"?: string;\n purpose?: string;\n };\n \"zitadel-logout\": React.HTMLAttributes<HTMLElement> & {\n project?: ZitadelProject;\n \"post-sign-out-url\"?: string;\n };\n }\n }\n}\n`,\n };\n },\n },\n};\n","import { ZitadelError } from \"../../../../../errors\";\nimport { litRenderer } from \"./lit\";\nimport { reactRenderer } from \"./react\";\nimport type { RendererId, RendererSpec } from \"./types\";\n\n/**\n * Runtime mirror of the {@link RendererId} union, used by {@link isRendererId}\n * to validate untrusted strings (a TS union has no runtime presence). Must stay\n * in sync with the {@link RendererId} type.\n */\nexport const RENDERER_IDS: RendererId[] = [\"react\", \"web-component\"];\n\n/**\n * Type guard narrowing an arbitrary value to a {@link RendererId}, used to\n * validate renderer ids read from config before indexing {@link RENDERERS}.\n */\nexport function isRendererId(value: unknown): value is RendererId {\n return typeof value === \"string\" && (RENDERER_IDS as string[]).includes(value);\n}\n\n/**\n * The single source of truth mapping each {@link RendererId} to its spec.\n * Keyed by id so {@link getRenderer} can look up and validate a renderer\n * chosen from persisted config (an arbitrary string) at runtime.\n */\nexport const RENDERERS: Record<RendererId, RendererSpec> = {\n react: reactRenderer,\n \"web-component\": litRenderer,\n};\n\n/**\n * Resolves a renderer id (an untrusted string from config) to its spec,\n * throwing a typed {@link ZitadelError} rather than returning `undefined`\n * so callers get an actionable message. Rejects ids that are unknown\n * (`E_VALIDATION`) or declared-but-unpublished (`E_NOT_IMPLEMENTED`),\n * guaranteeing the returned spec is safe to scaffold from.\n */\nexport function getRenderer(id: string): RendererSpec {\n if (!isRendererId(id)) {\n throw new ZitadelError(\"E_VALIDATION\", `Unknown renderer \"${id}\"`, {\n hint: `Available renderers: ${Object.keys(RENDERERS).join(\", \")}`,\n });\n }\n const renderer = RENDERERS[id];\n if (renderer.status === \"not-implemented\") {\n throw new ZitadelError(\n \"E_NOT_IMPLEMENTED\",\n `Renderer \"${id}\" is declared but not yet published`,\n {\n hint: \"Use --renderer react for now; the <zitadel-flow> web component ships in a later package.\",\n },\n );\n }\n return renderer;\n}\n","import { join } from \"node:path\";\n\nimport { MANAGED_MARKER } from \"../../../../paths\";\nimport type { FileOp } from \"../file-writer/types\";\nimport type { PatchContext, PatchView } from \"../../types\";\nimport { AbstractRulePatcher } from \"../base\";\nimport { getRenderer } from \"./renderers/registry\";\nimport type { RendererSpec } from \"./renderers/types\";\n\n/**\n * Next.js `middleware.ts` at the project root. Wires `nextgenMiddleware` so the\n * scaffolded `<zitadel-login api-base=\"/__nextgen\">` requests are same-origin\n * proxied to `ZITADEL_URL` and `/profile` is gated. The `middleware`\n * form (not the Next 16 `proxy` rename) works on every supported Next major.\n * Carries the managed marker so `doctor --fix` reclaims it and `eject` removes it.\n */\nconst middlewareTemplate = `${MANAGED_MARKER}\nimport { nextgenMiddleware } from \"@zitadel/sdk-next/middleware\";\nimport type { NextRequest } from \"next/server\";\n\nexport function middleware(req: NextRequest) {\n return nextgenMiddleware(req, {\n url: process.env.ZITADEL_URL,\n protectedRoutes: [\"/profile\"],\n loginPath: \"/login\",\n });\n}\n\nexport const config = {\n matcher: [\"/__nextgen/:path*\", \"/profile/:path*\"],\n};\n`;\n\n/**\n * Rule-based patcher for the Next.js App Router. Inherits the shared\n * `.zitadel/` base files from {@link AbstractRulePatcher} and contributes the\n * Next routes/middleware whose templates come from the chosen renderer.\n */\nexport class NextPatcher extends AbstractRulePatcher {\n /** Returns true for Next.js projects. */\n canPatch(framework: string): boolean {\n return framework === \"next\";\n }\n\n protected routeOps(ctx: PatchContext): FileOp[] {\n return nextCodeOps(ctx, getRenderer(ctx.rendererId));\n }\n\n protected routeFiles(view: PatchView): ReadonlyArray<string> {\n return nextCodeFilePaths(view.framework.appDir, getRenderer(view.rendererId));\n }\n\n protected routeDeps(view: PatchView): ReadonlyArray<string> {\n return [getRenderer(view.rendererId).dependency.name];\n }\n\n protected summary(ctx: PatchContext): { title: string; detail: string } {\n return {\n title: \"Next.js integration\",\n detail: `Scaffolded login/register/profile routes with renderer \"${ctx.rendererId}\".`,\n };\n }\n}\n\n/**\n * Ordered paths of the framework code files the patcher writes. All carry the\n * managed marker. Shared by {@link NextPatcher.routeOps} (which adds contents)\n * and {@link NextPatcher.routeFiles} (which only needs the paths) so the two\n * cannot drift.\n */\nfunction nextCodeFilePaths(appDir: string, renderer: RendererSpec): ReadonlyArray<string> {\n const paths = [join(appDir, \"login/page.tsx\"), join(appDir, \"register/page.tsx\")];\n if (renderer.templates.profilePage) {\n paths.push(join(appDir, \"profile/page.tsx\"));\n }\n paths.push(join(appDir, \"../middleware.ts\"));\n if (renderer.templates.provider) {\n paths.push(join(appDir, renderer.templates.provider.filename));\n }\n if (renderer.templates.customElementsDts) {\n paths.push(join(appDir, \"../custom-elements.d.ts\"));\n }\n return paths;\n}\n\n/** The Next route/middleware write ops plus the SDK dependency. */\nfunction nextCodeOps(ctx: PatchContext, renderer: RendererSpec): FileOp[] {\n const appDir = ctx.framework.appDir;\n const ops: FileOp[] = [\n {\n kind: \"write\",\n path: join(appDir, \"login/page.tsx\"),\n contents: renderer.templates.authPage(\"login\").contents,\n },\n {\n kind: \"write\",\n path: join(appDir, \"register/page.tsx\"),\n contents: renderer.templates.authPage(\"register\").contents,\n },\n ];\n const profile = renderer.templates.profilePage?.();\n if (profile) {\n ops.push({ kind: \"write\", path: join(appDir, \"profile/page.tsx\"), contents: profile.contents });\n }\n ops.push({ kind: \"write\", path: join(appDir, \"../middleware.ts\"), contents: middlewareTemplate });\n const provider = renderer.templates.provider;\n if (provider) {\n ops.push({ kind: \"write\", path: join(appDir, provider.filename), contents: provider.contents });\n }\n const dts = renderer.templates.customElementsDts?.();\n if (dts) {\n ops.push({\n kind: \"write\",\n path: join(appDir, \"../custom-elements.d.ts\"),\n contents: dts.contents,\n });\n }\n ops.push({\n kind: \"add-dep\",\n name: renderer.dependency.name,\n version: dependencyVersionForCli(ctx.cliVersion, renderer.dependency.version),\n });\n return ops;\n}\n\nfunction dependencyVersionForCli(cliVersion: string, fallback: string): string {\n const prerelease = cliVersion.match(/^\\d+\\.\\d+\\.\\d+-([0-9A-Za-z]+)(?:[.-]|$)/)?.[1];\n return prerelease ?? fallback;\n}\n","import { NextPatcher } from \"./rule/next\";\nimport type { Patcher } from \"./types\";\n\n/**\n * Active patchers, in priority order; the first whose `canPatch` matches wins.\n *\n * Patchers are grouped by family under subdirectories: `rule/` holds the\n * deterministic, template-driven patchers (extending\n * {@link import(\"./rule/base\").AbstractRulePatcher}). A future LLM-driven\n * family lives under `llm/` and registers its concrete patchers here — no\n * orchestrator or command changes needed. Only Next.js is supported today.\n */\nexport const patchers = [new NextPatcher()] as const satisfies ReadonlyArray<Patcher>;\n","import { spawnSync } from \"node:child_process\";\n\nimport { ZitadelError } from \"../../errors\";\nimport type { Scaffolder } from \"./types\";\n\n/**\n * Base for scaffolders that delegate to an external CLI (e.g. create-next-app).\n * Subclasses implement {@link scaffold} and call {@link runCommand}.\n */\nexport abstract class AbstractCLIScaffolder implements Scaffolder {\n abstract readonly displayName: string;\n abstract readonly supportedFrameworks: ReadonlyArray<string>;\n\n /** True when the requested framework is in {@link supportedFrameworks}. */\n canScaffold(framework: string): boolean {\n return this.supportedFrameworks.includes(framework);\n }\n\n abstract scaffold(cwd: string, framework: string): Promise<void>;\n\n /**\n * Runs an external command in `cwd`, throwing a typed {@link ZitadelError} on\n * failure so the cause surfaces as a categorized CLI error. Distinguishes\n * \"binary not on PATH\" (`ENOENT` from the spawn itself) from \"binary ran but\n * exited non-zero\" — the former previously got masked as a generic\n * `exited with status 1`, leaving users to guess. Tests stub\n * `node:child_process` to assert the command without spawning.\n */\n protected runCommand(command: string, args: ReadonlyArray<string>, cwd: string): void {\n const result = spawnSync(command, [...args], { cwd, encoding: \"utf8\" });\n if (result.error) {\n const err = result.error as NodeJS.ErrnoException;\n const notFound = err.code === \"ENOENT\";\n throw new ZitadelError(\n \"E_VALIDATION\",\n notFound\n ? `Command not found: ${command}`\n : `Failed to spawn \"${command}\": ${err.message}`,\n {\n hint: notFound ? `Ensure '${command}' is installed and on PATH.` : undefined,\n details: { command, args: [...args], code: err.code },\n },\n );\n }\n const status = result.status ?? 1;\n if (status !== 0) {\n throw new ZitadelError(\n \"E_VALIDATION\",\n `Command \"${command} ${args.join(\" \")}\" exited with status ${String(status)}`,\n { details: { stderr: result.stderr ?? \"\" } },\n );\n }\n }\n}\n","import { AbstractCLIScaffolder } from \"./cli\";\n\n/** Scaffolds a new Next.js App Router project with `create-next-app`. */\nexport class NextScaffolder extends AbstractCLIScaffolder {\n readonly displayName = \"Next.js\";\n readonly supportedFrameworks: ReadonlyArray<string> = [\"next\"];\n\n /**\n * Runs `npx create-next-app@latest . --ts --app --no-git --yes` in `cwd`,\n * creating a TypeScript App Router project in place. `--yes` accepts all\n * defaults so the command runs unattended.\n */\n async scaffold(cwd: string, _framework: string): Promise<void> {\n this.runCommand(\n \"npx\",\n [\"create-next-app@latest\", \".\", \"--ts\", \"--app\", \"--no-git\", \"--yes\"],\n cwd,\n );\n }\n}\n","import { NextScaffolder } from \"./next\";\nimport type { Scaffolder } from \"./types\";\n\n/**\n * Active scaffolders, in priority order. The framework picker derives its\n * choices from this list. Add a new framework by appending its scaffolder\n * here — no orchestrator changes needed.\n */\nexport const scaffolders = [new NextScaffolder()] as const satisfies ReadonlyArray<Scaffolder>;\n","import { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { ZitadelError } from \"../errors\";\nimport { detectors } from \"./detectors\";\nimport type { Detector, FrameworkFacts } from \"./detectors/types\";\nimport { patchers } from \"./patchers\";\nimport type { Patcher } from \"./patchers/types\";\nimport { scaffolders } from \"./scaffolders\";\nimport type { Scaffolder } from \"./scaffolders/types\";\n\nexport type { Detector, FrameworkFacts } from \"./detectors/types\";\nexport { issuerFromPort } from \"./detectors/port\";\n\n/** One framework the CLI can scaffold from scratch, surfaced to the picker. */\nexport type FrameworkChoice = Readonly<{ id: string; displayName: string }>;\n\n/**\n * Orchestrates the three per-framework strategies — detectors (recognise an\n * existing project and extract its facts), scaffolders (create a project), and\n * patchers (integrate Zitadel) — over their respective registries. It resolves\n * the right strategy for a framework and drives the detect/scaffold lifecycle;\n * how a patcher applies its work (file operations vs an LLM agent) stays\n * internal to that patcher. Registries are injected so tests can supply fakes.\n */\nexport class Orca {\n constructor(\n private readonly detectors: ReadonlyArray<Detector>,\n private readonly scaffolders: ReadonlyArray<Scaffolder>,\n private readonly patchers: ReadonlyArray<Patcher>,\n ) {}\n\n /**\n * Detects the framework in `cwd` and extracts its {@link FrameworkFacts},\n * honouring an explicit `requested` framework. Throws\n * `E_FRAMEWORK_NOT_DETECTED` when nothing matches; a detector's\n * `E_UNSUPPORTED_PROJECT_SHAPE` (recognised but unsupported) propagates.\n */\n async detect(cwd: string, requested?: string): Promise<FrameworkFacts> {\n const candidates = requested\n ? this.detectors.filter((detector) => detector.framework === requested)\n : this.detectors;\n if (requested && candidates.length === 0) {\n throw new ZitadelError(\"E_FRAMEWORK_NOT_DETECTED\", `Unsupported framework \"${requested}\"`, {\n hint: `Supported frameworks: ${this.frameworkIds().join(\", \")}.`,\n });\n }\n for (const detector of candidates) {\n const facts = await detector.detect(cwd);\n if (facts) {\n return facts;\n }\n }\n throw new ZitadelError(\"E_FRAMEWORK_NOT_DETECTED\", \"Could not detect a supported framework\", {\n hint: `Run this from a supported project (${this.frameworkIds().join(\", \")}) or pass --cwd <path>.`,\n });\n }\n\n /**\n * Non-throwing detection: returns `undefined` instead of raising for a\n * project that is absent, unrecognised, or recognised-but-unsupported, so\n * callers (e.g. `eject`) can probe and degrade gracefully.\n */\n async tryDetect(cwd: string): Promise<FrameworkFacts | undefined> {\n try {\n return await this.detect(cwd);\n } catch (error) {\n if (\n error instanceof ZitadelError &&\n (error.code === \"E_FRAMEWORK_NOT_DETECTED\" || error.code === \"E_UNSUPPORTED_PROJECT_SHAPE\")\n ) {\n return undefined;\n }\n throw error;\n }\n }\n\n /**\n * Whether `cwd` has no `package.json`, i.e. it is empty (or non-Node) and\n * should be scaffolded from scratch rather than detected/patched.\n */\n async isEmpty(cwd: string): Promise<boolean> {\n try {\n await readFile(join(cwd, \"package.json\"), \"utf8\");\n return false;\n } catch {\n return true;\n }\n }\n\n /**\n * Creates a new `framework` project in `cwd`, then re-detects it to return\n * the resulting {@link FrameworkFacts}. Throws `E_CONFLICT` when the directory\n * already contains a project (\"already scaffolded\") and `E_VALIDATION` when no\n * scaffolder supports the framework.\n */\n async scaffold(cwd: string, framework: string): Promise<FrameworkFacts> {\n if (!(await this.isEmpty(cwd))) {\n throw new ZitadelError(\"E_CONFLICT\", `Cannot scaffold: ${cwd} already contains a project`, {\n hint: \"Run setup in an empty directory, or integrate the existing project instead.\",\n });\n }\n await this.scaffolderFor(framework).scaffold(cwd, framework);\n return this.detect(cwd, framework);\n }\n\n /**\n * Resolves the scaffolder for a framework, throwing `E_VALIDATION` (with the\n * available list) when none matches.\n */\n scaffolderFor(framework: string): Scaffolder {\n const scaffolder = this.scaffolders.find((candidate) => candidate.canScaffold(framework));\n if (!scaffolder) {\n throw new ZitadelError(\"E_VALIDATION\", `No scaffolder supports \"${framework}\"`, {\n hint: `Available frameworks: ${this.availableFrameworks().map((f) => f.id).join(\", \")}.`,\n });\n }\n return scaffolder;\n }\n\n /**\n * Resolves the patcher for a framework, throwing `E_VALIDATION` when none\n * matches (e.g. a framework that can be scaffolded but not yet integrated).\n */\n patcherFor(framework: string): Patcher {\n const patcher = this.patchers.find((candidate) => candidate.canPatch(framework));\n if (!patcher) {\n throw new ZitadelError(\"E_VALIDATION\", `No patcher supports \"${framework}\"`, {\n hint: \"Zitadel integration currently supports Next.js.\",\n });\n }\n return patcher;\n }\n\n /** The frameworks that can be scaffolded, derived from the scaffolder registry. */\n availableFrameworks(): ReadonlyArray<FrameworkChoice> {\n return this.scaffolders.map((scaffolder) => ({\n id: scaffolder.supportedFrameworks[0] ?? scaffolder.displayName,\n displayName: scaffolder.displayName,\n }));\n }\n\n private frameworkIds(): ReadonlyArray<string> {\n return this.detectors.map((detector) => detector.framework);\n }\n}\n\n/** {@link Orca} wired with the default detector, scaffolder, and patcher registries. */\nexport function createOrca(): Orca {\n return new Orca(detectors, scaffolders, patchers);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"orca-BX4AhKLD.mjs","names":[],"sources":["../src/lib/orca/detectors/package-json.ts","../src/lib/orca/detectors/port.ts","../src/lib/orca/detectors/next.ts","../src/lib/orca/detectors/index.ts","../src/lib/orca/patchers/rule/file-writer/index.ts","../src/lib/orca/patchers/rule/reclaim.ts","../src/lib/orca/patchers/rule/base.ts","../src/lib/orca/patchers/rule/next/renderers/lit/index.ts","../src/lib/orca/patchers/rule/next/renderers/react/index.ts","../src/lib/orca/patchers/rule/next/renderers/registry.ts","../src/lib/orca/patchers/rule/next/index.ts","../src/lib/orca/patchers/index.ts","../src/lib/orca/scaffolders/cli.ts","../src/lib/orca/scaffolders/next.ts","../src/lib/orca/scaffolders/index.ts","../src/lib/orca/index.ts"],"sourcesContent":["import { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\n/**\n * Minimal shape of the `package.json` fields detectors read. Intentionally\n * partial: only the keys detection logic depends on are modeled, all optional\n * since a project may omit any of them.\n */\nexport type PackageJson = {\n name?: string;\n scripts?: Record<string, string>;\n dependencies?: Record<string, string>;\n devDependencies?: Record<string, string>;\n};\n\n/**\n * Reads and parses the `package.json` at `cwd`. Rejects if the file is absent\n * or malformed; callers that treat those as \"not a project\" are expected to\n * catch and fall back rather than have detection swallow the error here.\n */\nexport async function readPackageJson(cwd: string): Promise<PackageJson> {\n const contents = await readFile(join(cwd, \"package.json\"), \"utf8\");\n return JSON.parse(contents) as PackageJson;\n}\n\n/**\n * Reports whether `name` appears in either `dependencies` or `devDependencies`.\n * Both are checked because framework packages may legitimately live in either.\n */\nexport function hasDependency(pkg: PackageJson, name: string): boolean {\n return Boolean(pkg.dependencies?.[name] ?? pkg.devDependencies?.[name]);\n}\n","import { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport type { PackageJson } from \"./package-json\";\n\n/**\n * Port assumed when no explicit dev port can be discovered. Matches Next.js's\n * own default so the inferred issuer URL lines up with `next dev`.\n */\nexport const DEFAULT_DEV_PORT = 3000;\n\n/**\n * Determines the local dev-server port for `cwd`. The `dev` script is the most\n * authoritative source, then a `PORT` declaration in an env file, falling back\n * to {@link DEFAULT_DEV_PORT}. Used to derive the local issuer URL.\n */\nexport async function detectDevPort(cwd: string, pkg: PackageJson): Promise<number> {\n const dev = pkg.scripts?.dev;\n const fromScript = typeof dev === \"string\" ? extractPort(dev) : undefined;\n if (fromScript) {\n return fromScript;\n }\n\n const fromEnvFile = await portFromEnvFile(cwd);\n if (fromEnvFile) {\n return fromEnvFile;\n }\n\n return DEFAULT_DEV_PORT;\n}\n\nasync function portFromEnvFile(cwd: string): Promise<number | undefined> {\n for (const candidate of [\".env.local\", \".env\"]) {\n try {\n const contents = await readFile(join(cwd, candidate), \"utf8\");\n const match = contents.match(/^\\s*PORT\\s*=\\s*(\\d+)/m);\n const rawPort = match?.[1];\n if (rawPort) {\n return Number.parseInt(rawPort, 10);\n }\n } catch {\n continue;\n }\n }\n return undefined;\n}\n\n/**\n * Parses a dev port out of an npm `dev` script string, recognizing both flag\n * forms (`-p`/`--port`) and a leading `PORT=` env assignment. Returns\n * `undefined` when no valid positive port is present so callers can fall back.\n */\nexport function extractPort(script: string): number | undefined {\n const inline = script.match(/-p\\s+(\\d+)|--port[=\\s]+(\\d+)/);\n if (inline) {\n const raw = inline[1] ?? inline[2];\n if (!raw) {\n return undefined;\n }\n const value = Number.parseInt(raw, 10);\n if (Number.isFinite(value) && value > 0) {\n return value;\n }\n }\n const env = script.match(/(?:^|\\s)PORT=(\\d+)/);\n const rawEnvPort = env?.[1];\n if (rawEnvPort) {\n return Number.parseInt(rawEnvPort, 10);\n }\n return undefined;\n}\n\n/**\n * Builds the local OIDC issuer URL for a given dev port. Centralized so the\n * `localhost` origin convention is defined in exactly one place.\n */\nexport function issuerFromPort(port: number): string {\n return `http://localhost:${port}`;\n}\n","import { stat } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { ZitadelError } from \"../../errors\";\nimport { hasDependency, readPackageJson } from \"./package-json\";\nimport { detectDevPort, issuerFromPort } from \"./port\";\nimport type { Detector, FrameworkFacts } from \"./types\";\n\n/**\n * Detects a Next.js App Router project and extracts its facts: the App Router\n * directory (`app` vs `src/app`), the dev-server port (parsed from the `dev`\n * script / env file, else 3000), and the derived local issuer URL. Owns every\n * Next-specific assumption so the orchestrator and commands stay generic.\n */\nexport class NextDetector implements Detector {\n readonly framework = \"next\";\n\n /**\n * Returns `null` when `cwd` is not a Next.js project (no `next` dependency),\n * so the orchestrator can try other detectors. Throws\n * `E_UNSUPPORTED_PROJECT_SHAPE` when it is Next.js but lacks an App Router\n * directory (e.g. a Pages Router project), which is a hard error rather than\n * an empty directory to scaffold.\n */\n async detect(cwd: string): Promise<FrameworkFacts | null> {\n const pkg = await readPackageJson(cwd).catch(() => undefined);\n if (!pkg || !hasDependency(pkg, \"next\")) {\n return null;\n }\n\n const appDir = (await dirExists(join(cwd, \"app\")))\n ? \"app\"\n : (await dirExists(join(cwd, \"src/app\")))\n ? \"src/app\"\n : undefined;\n if (!appDir) {\n throw new ZitadelError(\n \"E_UNSUPPORTED_PROJECT_SHAPE\",\n \"Next.js Pages Router projects are not supported in v1\",\n { hint: \"Create an App Router project with an app/ or src/app/ directory.\" },\n );\n }\n\n const devPort = await detectDevPort(cwd, pkg);\n return { id: \"next\", appDir, devPort, url: issuerFromPort(devPort) };\n }\n}\n\nasync function dirExists(path: string): Promise<boolean> {\n try {\n return (await stat(path)).isDirectory();\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 false;\n }\n throw error;\n }\n}\n","import { NextDetector } from \"./next\";\nimport type { Detector } from \"./types\";\n\n/**\n * Active detectors, in probe order. The orchestrator tries each until one\n * recognises the project. Add a framework by appending its detector here — no\n * orchestrator changes needed.\n */\nexport const detectors = [new NextDetector()] as const satisfies ReadonlyArray<Detector>;\n","import { chmod, mkdir, readFile, rename, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\n\nimport { ZitadelError } from \"../../../../errors\";\nimport { isObject, parseJsonObject, stableStringify } from \"../../../../json\";\nimport type { FileOp, ScaffoldPlan, ScaffoldResult } from \"./types\";\n\n/**\n * The executor's private, mutable accumulator. Handlers push into it as each\n * op is applied; {@link scaffold} returns it as the readonly\n * {@link ScaffoldResult} so the public result stays immutable.\n */\ntype ScaffoldAccumulator = {\n dryRun: boolean;\n filesWritten: string[];\n filesSkipped: string[];\n depsAdded: string[];\n};\n\n/**\n * Applies a {@link ScaffoldPlan} to disk, executing its operations in order.\n *\n * Operations are idempotent: writes whose target already matches the desired\n * contents are recorded as skipped rather than rewritten, so re-running setup\n * is safe. With `dryRun` no filesystem changes are made but the result still\n * reflects what would have been written. Existing files are only overwritten\n * when `force` is set; otherwise an `E_CONFLICT` is thrown to protect\n * user-authored content. Paths in the plan are resolved relative to `cwd`.\n */\nexport async function scaffold(\n plan: ScaffoldPlan,\n opts: { cwd: string; dryRun: boolean; force: boolean },\n): Promise<ScaffoldResult> {\n const result: ScaffoldAccumulator = {\n dryRun: opts.dryRun,\n filesWritten: [],\n filesSkipped: [],\n depsAdded: [],\n };\n\n for (const op of plan.ops) {\n await applyOp(op, opts, result);\n }\n\n return result;\n}\n\nasync function applyOp(\n op: FileOp,\n opts: { cwd: string; dryRun: boolean; force: boolean },\n result: ScaffoldAccumulator,\n): Promise<void> {\n switch (op.kind) {\n case \"mkdir\":\n await ensureDir(abs(opts.cwd, op.path), op.mode, opts.dryRun, result);\n break;\n case \"write\":\n await writeText(\n abs(opts.cwd, op.path),\n op.contents,\n { mode: op.mode, force: opts.force, dryRun: opts.dryRun },\n result,\n );\n break;\n case \"append\":\n await appendText(abs(opts.cwd, op.path), op.contents, op.ifMissing, opts.dryRun, result);\n break;\n case \"merge-env\":\n await mergeEnv(abs(opts.cwd, op.path), op.entries, opts.dryRun, result);\n break;\n case \"merge-json\":\n await mergeJson(abs(opts.cwd, op.path), op.patch, opts.dryRun, result);\n break;\n case \"append-gitignore\":\n await appendGitignore(abs(opts.cwd, \".gitignore\"), op.entries, opts.dryRun, result);\n break;\n case \"add-dep\":\n await addDependency(abs(opts.cwd, \"package.json\"), op, opts.dryRun, result);\n break;\n }\n}\n\nasync function ensureDir(\n path: string,\n mode: number | undefined,\n dryRun: boolean,\n result: ScaffoldAccumulator,\n): Promise<void> {\n if (dryRun) {\n result.filesWritten.push(path);\n return;\n }\n await mkdir(path, { recursive: true, mode });\n if (mode) {\n await chmod(path, mode).catch(() => undefined);\n }\n result.filesWritten.push(path);\n}\n\nasync function writeText(\n path: string,\n contents: string,\n opts: { mode?: number; force: boolean; dryRun: boolean },\n result: ScaffoldAccumulator,\n): Promise<void> {\n const existing = await readIfExists(path);\n if (existing === contents) {\n result.filesSkipped.push(path);\n return;\n }\n\n if (existing !== undefined && !opts.force) {\n throw new ZitadelError(\"E_CONFLICT\", `Refusing to overwrite ${path}`, {\n hint: \"Re-run with --force if you want the CLI to replace this file.\",\n details: { path },\n });\n }\n\n if (opts.dryRun) {\n result.filesWritten.push(path);\n return;\n }\n\n await mkdir(dirname(path), { recursive: true });\n const tmp = `${path}.tmp-${process.pid}-${Date.now()}`;\n await writeFile(tmp, contents, { mode: opts.mode });\n if (opts.mode) {\n await chmod(tmp, opts.mode).catch(() => undefined);\n }\n await rename(tmp, path);\n result.filesWritten.push(path);\n}\n\nasync function appendText(\n path: string,\n contents: string,\n ifMissing: string | undefined,\n dryRun: boolean,\n result: ScaffoldAccumulator,\n): Promise<void> {\n const existing = (await readIfExists(path)) ?? \"\";\n if (ifMissing && existing.includes(ifMissing)) {\n result.filesSkipped.push(path);\n return;\n }\n\n const next = `${existing}${existing && !existing.endsWith(\"\\n\") ? \"\\n\" : \"\"}${contents}`;\n if (next === existing) {\n result.filesSkipped.push(path);\n return;\n }\n\n if (dryRun) {\n result.filesWritten.push(path);\n return;\n }\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, next);\n result.filesWritten.push(path);\n}\n\nasync function mergeEnv(\n path: string,\n entries: Readonly<Record<string, string>>,\n dryRun: boolean,\n result: ScaffoldAccumulator,\n): Promise<void> {\n const existing = (await readIfExists(path)) ?? \"\";\n const present = new Set(\n existing\n .split(/\\r?\\n/g)\n .map((line) => line.match(/^\\s*([A-Za-z_][A-Za-z0-9_]*)=/)?.[1])\n .filter((value): value is string => Boolean(value)),\n );\n const additions = Object.entries(entries).filter(([key]) => !present.has(key));\n if (additions.length === 0) {\n result.filesSkipped.push(path);\n return;\n }\n\n const block = additions.map(([key, value]) => `${key}=${value}`).join(\"\\n\");\n const next = `${existing}${existing && !existing.endsWith(\"\\n\") ? \"\\n\" : \"\"}${block}\\n`;\n if (dryRun) {\n result.filesWritten.push(path);\n return;\n }\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, next);\n result.filesWritten.push(path);\n}\n\nasync function mergeJson(\n path: string,\n patch: Readonly<Record<string, unknown>>,\n dryRun: boolean,\n result: ScaffoldAccumulator,\n): Promise<void> {\n const existing = await readIfExists(path);\n const current = existing ? parseJsonObject(existing, path) : {};\n const next = deepMerge(current, patch);\n const contents = `${stableStringify(next)}\\n`;\n if (existing === contents) {\n result.filesSkipped.push(path);\n return;\n }\n if (dryRun) {\n result.filesWritten.push(path);\n return;\n }\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, contents);\n result.filesWritten.push(path);\n}\n\nasync function appendGitignore(\n path: string,\n entries: ReadonlyArray<string>,\n dryRun: boolean,\n result: ScaffoldAccumulator,\n): Promise<void> {\n const existing = (await readIfExists(path)) ?? \"\";\n const lines = new Set(existing.split(/\\r?\\n/g).map((line) => line.trim()));\n const missing = entries.filter((entry) => !lines.has(entry));\n if (missing.length === 0) {\n result.filesSkipped.push(path);\n return;\n }\n const next = `${existing}${existing && !existing.endsWith(\"\\n\") ? \"\\n\" : \"\"}${missing.join(\"\\n\")}\\n`;\n if (dryRun) {\n result.filesWritten.push(path);\n return;\n }\n await writeFile(path, next);\n result.filesWritten.push(path);\n}\n\nasync function addDependency(\n path: string,\n op: { name: string; version: string; dev?: boolean },\n dryRun: boolean,\n result: ScaffoldAccumulator,\n): Promise<void> {\n const existing = await readIfExists(path);\n if (!existing) {\n throw new ZitadelError(\"E_VALIDATION\", \"package.json is required to add Zitadel dependencies\");\n }\n const current = parseJsonObject(existing, path);\n const key = op.dev ? \"devDependencies\" : \"dependencies\";\n const deps = isObject(current[key]) ? (current[key] as Record<string, unknown>) : {};\n if (deps[op.name] === op.version) {\n result.filesSkipped.push(path);\n return;\n }\n current[key] = { ...deps, [op.name]: op.version };\n const contents = `${stableStringify(current)}\\n`;\n if (dryRun) {\n result.filesWritten.push(path);\n result.depsAdded.push(op.name);\n return;\n }\n await writeFile(path, contents);\n result.filesWritten.push(path);\n result.depsAdded.push(op.name);\n}\n\nasync function readIfExists(path: string): Promise<string | undefined> {\n try {\n return await readFile(path, \"utf8\");\n } catch (error) {\n if (typeof error === \"object\" && error !== null && \"code\" in error && error.code === \"ENOENT\") {\n return undefined;\n }\n throw error;\n }\n}\n\nfunction abs(cwd: string, path: string): string {\n return join(cwd, path);\n}\n\nfunction deepMerge(\n target: Record<string, unknown>,\n patch: Readonly<Record<string, unknown>>,\n): Record<string, unknown> {\n const out = { ...target };\n for (const [key, value] of Object.entries(patch)) {\n if (isObject(value) && isObject(out[key])) {\n out[key] = deepMerge(out[key] as Record<string, unknown>, value);\n } else {\n out[key] = value;\n }\n }\n return out;\n}\n","import { MANAGED_MARKER } from \"../../../paths\";\nimport type { FileOp, ScaffoldPlan } from \"./file-writer/types\";\n\n/**\n * The subset of a patcher plan's operations that `doctor --fix` re-applies:\n * env merges, gitignore entries, dependency additions, and marker-bearing\n * managed files (framework routes/middleware). Deliberately excludes the\n * unmarked `.zitadel/` resource writes and `zitadel.json` — those are\n * user-editable and synced by `apply`, so `--fix` must not clobber them.\n *\n * Pure: filters a freshly-allocated list; the input plan is not mutated.\n */\nexport function reclaimableOps(plan: ScaffoldPlan): FileOp[] {\n return plan.ops.filter(\n (op) =>\n op.kind === \"merge-env\" ||\n op.kind === \"append-gitignore\" ||\n op.kind === \"add-dep\" ||\n (op.kind === \"write\" && op.contents.includes(MANAGED_MARKER)),\n );\n}\n","import { stableStringify } from \"../../../json\";\nimport { DEFAULT_SERVER } from \"../../../server\";\nimport { scaffold } from \"./file-writer\";\nimport type { FileOp, ScaffoldPlan } from \"./file-writer/types\";\nimport type {\n EjectActions,\n Patcher,\n PatchContext,\n PatchExecOptions,\n PatchResult,\n PatchView,\n} from \"../types\";\nimport { reclaimableOps } from \"./reclaim\";\n\n/**\n * Base for rule-based (deterministic, template-driven) patchers, as opposed to\n * a future LLM-driven family. It applies the integration by building a\n * file-operation plan and running the file-writer — that strategy stays\n * entirely inside this family, so callers only ever see the family-neutral\n * {@link Patcher} surface. Owns the framework-agnostic `.zitadel/` base files\n * and the shared eject classification; subclasses contribute only their\n * framework-specific routes/middleware.\n */\nexport abstract class AbstractRulePatcher implements Patcher {\n abstract canPatch(framework: string): boolean;\n\n /** Apply the full plan (base `.zitadel/` files + framework routes). */\n async patch(ctx: PatchContext, opts: PatchExecOptions): Promise<PatchResult> {\n return scaffold(this.plan(ctx), opts);\n }\n\n /**\n * Re-apply only the reclaimable subset — env files, gitignore, the SDK\n * dependency, and marker-bearing routes — leaving the user-editable\n * `.zitadel/` resources untouched. Backs `doctor --fix`.\n */\n async repair(ctx: PatchContext, opts: PatchExecOptions): Promise<PatchResult> {\n const plan = this.plan(ctx);\n return scaffold({ ops: reclaimableOps(plan), summary: plan.summary }, opts);\n }\n\n /** Shared base artifacts plus the subclass's marker-bearing route files. */\n artifacts(view: PatchView): EjectActions {\n return {\n markedFiles: this.routeFiles(view),\n rootConfigFiles: [\"zitadel.json\"],\n directories: [\".zitadel\"],\n envBackups: [\".env.local\"],\n dependencies: this.routeDeps(view),\n };\n }\n\n /**\n * The full file-operation plan this patcher would apply. Public so rule-family\n * unit tests can assert the planned ops directly; the generic {@link Patcher}\n * interface deliberately does not expose it (an LLM patcher has no such plan).\n */\n plan(ctx: PatchContext): ScaffoldPlan {\n return {\n ops: [...this.baseOps(ctx), ...this.routeOps(ctx)],\n summary: [this.summary(ctx)],\n };\n }\n\n /**\n * The framework-agnostic `.zitadel/` base files every rule patcher writes:\n * the project secret, `zitadel.json`, env templates, and an empty sync\n * state. The `schemas/` and `flows/` directories are created empty — the\n * server provisions the default user schema and flow definition when the\n * project is created, so nothing is scaffolded into them here. Pure: no\n * filesystem or network.\n */\n private baseOps(ctx: PatchContext): ReadonlyArray<FileOp> {\n return [\n { kind: \"mkdir\", path: \".zitadel\", mode: 0o700 },\n { kind: \"mkdir\", path: \".zitadel/flows\" },\n { kind: \"mkdir\", path: \".zitadel/schemas\" },\n { kind: \"append-gitignore\", entries: [\".zitadel/secret\", \".env*\", \"!.env.example\"] },\n {\n kind: \"write\",\n path: \".zitadel/secret\",\n mode: 0o600,\n contents: `${stableStringify({\n project_id: ctx.project.id,\n project_secret: ctx.project.projectSecret,\n preview_secret: ctx.project.previewSecret,\n preview_origins: ctx.project.previewOrigins,\n created_at: ctx.project.createdAt,\n })}\\n`,\n },\n { kind: \"write\", path: \"zitadel.json\", contents: `${stableStringify(projectConfig(ctx))}\\n` },\n {\n kind: \"merge-env\",\n path: \".env.example\",\n entries: {\n ZITADEL_PROJECT_ID: \"\",\n ZITADEL_ENVIRONMENT: \"\",\n ZITADEL_ISSUER: \"\",\n ZITADEL_URL: \"\",\n NEXT_PUBLIC_ZITADEL_PROJECT_ID: \"\",\n },\n },\n {\n kind: \"merge-env\",\n path: \".env.local\",\n entries: {\n ZITADEL_PROJECT_ID: ctx.project.id,\n ZITADEL_ENVIRONMENT: \"development\",\n ZITADEL_ISSUER: ctx.issuer,\n ZITADEL_URL: ctx.server,\n NEXT_PUBLIC_ZITADEL_PROJECT_ID: ctx.project.id,\n },\n },\n {\n kind: \"write\",\n path: \".zitadel/state.json\",\n contents: `${stableStringify({ framework: ctx.framework.id, resources: {} })}\\n`,\n },\n ];\n }\n\n /** Framework-specific route/middleware write ops plus the SDK dependency. */\n protected abstract routeOps(ctx: PatchContext): ReadonlyArray<FileOp>;\n /** Framework-specific managed (marker-bearing) file paths, for ejection. */\n protected abstract routeFiles(view: PatchView): ReadonlyArray<string>;\n /**\n * The package-manager dependencies the integration added, surfaced in\n * `eject`'s `next_commands` so the user can uninstall them themselves.\n */\n protected abstract routeDeps(view: PatchView): ReadonlyArray<string>;\n /** One-line summary of what the integration scaffolded. */\n protected abstract summary(ctx: PatchContext): { title: string; detail: string };\n}\n\n/** Builds the `zitadel.json` body persisted at the project root. */\nfunction projectConfig(ctx: PatchContext): Record<string, unknown> {\n const environments: Record<string, unknown> = { development: { issuer: ctx.issuer } };\n if (ctx.project.previewOrigins.length > 0) {\n environments.preview = {\n issuer_pattern: ctx.project.previewOrigins.map((origin) => `https://${origin}`),\n };\n }\n return {\n $schema: \"https://schemas.zitadel.com/v2/project.schema.json\",\n project: ctx.project.id,\n server: resolveServerOrigin(ctx.server),\n framework: { id: ctx.framework.id },\n branding: { renderer: ctx.rendererId, attribution: \"visible\" },\n environments,\n };\n}\n\n/** Normalizes a server URL to its origin, falling back to {@link DEFAULT_SERVER}. */\nfunction resolveServerOrigin(source: string): string {\n try {\n return new URL(source).origin;\n } catch {\n return DEFAULT_SERVER;\n }\n}\n","import { MANAGED_MARKER } from \"../../../../../../paths\";\nimport type { RendererSpec } from \"../types\";\n\n/**\n * Placeholder renderer for the `<zitadel-flow>` Lit web component. Declared\n * so the `web-component` renderer id resolves and surfaces a clear\n * \"not yet published\" error, while reserving the integration shape for when\n * `@zitadel/ui-lit` ships. The `authPage` template emits an illustrative\n * page only; this renderer is never selected for real scaffolding because\n * `getRenderer` rejects any `status: \"not-implemented\"` spec.\n */\nexport const litRenderer: RendererSpec = {\n id: \"web-component\",\n displayName: \"Web component (<zitadel-flow>)\",\n status: \"not-implemented\",\n frameworks: [\"next\", \"astro\", \"remix\", \"sveltekit\", \"nuxt\", \"vanilla\"],\n dependency: { name: \"@zitadel/ui-lit\", version: \"workspace:*\" },\n templates: {\n authPage(mode) {\n const purpose = mode === \"login\" ? \"login\" : \"register\";\n return {\n mode,\n contents: `${MANAGED_MARKER}\n// The web component renderer ships a <zitadel-flow> element. Until\n// @zitadel/ui-lit is published, this template only declares the\n// intended integration point. See docs/design/cli/bdui-renderer.md.\nimport \"@zitadel/ui-lit\";\n\nconst environment =\n process.env.ZITADEL_ENVIRONMENT ??\n (process.env.NODE_ENV === \"production\" ? \"production\" : \"development\");\n\nexport default function ${mode === \"login\" ? \"LoginPage\" : \"RegisterPage\"}() {\n return (\n <zitadel-flow\n purpose=\"${purpose}\"\n project-id={process.env.ZITADEL_PROJECT_ID}\n issuer={process.env.ZITADEL_ISSUER}\n environment={environment}\n />\n );\n}\n`,\n };\n },\n },\n};\n","import { MANAGED_MARKER } from \"../../../../../../paths\";\nimport type { RendererSpec } from \"../types\";\n\n/**\n * The Next.js App Router renderer scaffolds `/login`, `/register`, and\n * `/profile` pages that drive the `<zitadel-login>` and `<zitadel-logout>`\n * Lit web components.\n *\n * Each page is a single client component (`\"use client\"`) that, inside a\n * `next/dynamic({ ssr: false })` loader, builds the SDK project handle with\n * `configureZitadel({ projectId, proxyPath: \"/__nextgen\" })` and passes it to\n * the widget via `project={...}`. It also imports\n * `@zitadel/sdk-next/client` for its `customElements.define`\n * side-effect — importing `@zitadel/components` directly would fail on\n * strict-resolution package managers (pnpm, yarn PnP) because the app only\n * declares `sdk-next` as a direct dep. SSR is disabled because Lit's element\n * registration needs a browser.\n *\n * The handle is passed as the `project` DOM property, which relies on React\n * 19's custom-element property binding (the scaffold targets the latest Next /\n * React). The backend URL never reaches the browser: the client talks to the\n * same-origin `/__nextgen` proxy path, and the scaffolded `middleware.ts`\n * forwards it to `ZITADEL_URL` server-side. `NEXT_PUBLIC_ZITADEL_PROJECT_ID` is\n * public — the project id is not sensitive and the widget needs it to start a\n * flow.\n */\nexport const reactRenderer: RendererSpec = {\n id: \"react\",\n displayName: \"React (Next.js App Router)\",\n status: \"available\",\n frameworks: [\"next\"],\n dependency: { name: \"@zitadel/sdk-next\", version: \"latest\" },\n templates: {\n authPage(mode) {\n const componentName = mode === \"login\" ? \"LoginPage\" : \"RegisterPage\";\n const elementName = mode === \"login\" ? \"ZitadelLogin\" : \"ZitadelRegister\";\n return {\n mode,\n contents: `${MANAGED_MARKER}\n\"use client\";\n\nimport dynamic from \"next/dynamic\";\n\nconst ${elementName} = dynamic(\n async () => {\n const { configureZitadel } = await import(\"@zitadel/sdk-next/client\");\n // Build the SDK project handle and pass it to the component via the\n // \\`project\\` prop. The component reads config from this prop directly, so\n // it works regardless of how the SDK packages are bundled. The backend URL\n // stays server-side — requests go through the proxy path \"/__nextgen\",\n // which the scaffolded middleware forwards to the Zitadel server.\n const project = configureZitadel({\n projectId: process.env.NEXT_PUBLIC_ZITADEL_PROJECT_ID ?? \"\",\n proxyPath: \"/__nextgen\",\n });\n return function ${elementName}Element() {\n return (\n <zitadel-login\n project={project}\n purpose=\"${mode}\"\n post-sign-in-url=\"/profile\"\n />\n );\n };\n },\n { ssr: false },\n);\n\nexport default function ${componentName}() {\n return (\n <main style={{ minHeight: \"100vh\", display: \"flex\", alignItems: \"center\", justifyContent: \"center\" }}>\n <${elementName} />\n </main>\n );\n}\n`,\n };\n },\n profilePage() {\n return {\n contents: `${MANAGED_MARKER}\n\"use client\";\n\nimport dynamic from \"next/dynamic\";\n\nconst ZitadelLogout = dynamic(\n async () => {\n const { configureZitadel } = await import(\"@zitadel/sdk-next/client\");\n const project = configureZitadel({\n projectId: process.env.NEXT_PUBLIC_ZITADEL_PROJECT_ID ?? \"\",\n proxyPath: \"/__nextgen\",\n });\n return function ZitadelLogoutElement() {\n return (\n <zitadel-logout\n project={project}\n post-sign-out-url=\"/login\"\n />\n );\n };\n },\n { ssr: false },\n);\n\nexport default function ProfilePage() {\n return (\n <main style={{ padding: \"48px\", maxWidth: \"600px\", margin: \"0 auto\" }}>\n <div style={{ display: \"flex\", alignItems: \"center\", justifyContent: \"space-between\", marginBottom: \"24px\" }}>\n <h1 style={{ fontSize: \"24px\", fontWeight: 700, margin: 0 }}>Signed in</h1>\n <ZitadelLogout />\n </div>\n <p style={{ color: \"#6b7280\" }}>You are signed in. Use the button above to log out.</p>\n </main>\n );\n}\n`,\n };\n },\n customElementsDts() {\n return {\n contents: `${MANAGED_MARKER}\nimport type React from \"react\";\nimport type { ZitadelProject } from \"@zitadel/sdk-next/client\";\n\ndeclare module \"react\" {\n namespace JSX {\n interface IntrinsicElements {\n \"zitadel-login\": React.HTMLAttributes<HTMLElement> & {\n project?: ZitadelProject;\n \"session-exchange-path\"?: string;\n \"post-sign-in-url\"?: string;\n purpose?: string;\n };\n \"zitadel-logout\": React.HTMLAttributes<HTMLElement> & {\n project?: ZitadelProject;\n \"post-sign-out-url\"?: string;\n };\n }\n }\n}\n`,\n };\n },\n },\n};\n","import { ZitadelError } from \"../../../../../errors\";\nimport { litRenderer } from \"./lit\";\nimport { reactRenderer } from \"./react\";\nimport type { RendererId, RendererSpec } from \"./types\";\n\n/**\n * Runtime mirror of the {@link RendererId} union, used by {@link isRendererId}\n * to validate untrusted strings (a TS union has no runtime presence). Must stay\n * in sync with the {@link RendererId} type.\n */\nexport const RENDERER_IDS: RendererId[] = [\"react\", \"web-component\"];\n\n/**\n * Type guard narrowing an arbitrary value to a {@link RendererId}, used to\n * validate renderer ids read from config before indexing {@link RENDERERS}.\n */\nexport function isRendererId(value: unknown): value is RendererId {\n return typeof value === \"string\" && (RENDERER_IDS as string[]).includes(value);\n}\n\n/**\n * The single source of truth mapping each {@link RendererId} to its spec.\n * Keyed by id so {@link getRenderer} can look up and validate a renderer\n * chosen from persisted config (an arbitrary string) at runtime.\n */\nexport const RENDERERS: Record<RendererId, RendererSpec> = {\n react: reactRenderer,\n \"web-component\": litRenderer,\n};\n\n/**\n * Resolves a renderer id (an untrusted string from config) to its spec,\n * throwing a typed {@link ZitadelError} rather than returning `undefined`\n * so callers get an actionable message. Rejects ids that are unknown\n * (`E_VALIDATION`) or declared-but-unpublished (`E_NOT_IMPLEMENTED`),\n * guaranteeing the returned spec is safe to scaffold from.\n */\nexport function getRenderer(id: string): RendererSpec {\n if (!isRendererId(id)) {\n throw new ZitadelError(\"E_VALIDATION\", `Unknown renderer \"${id}\"`, {\n hint: `Available renderers: ${Object.keys(RENDERERS).join(\", \")}`,\n });\n }\n const renderer = RENDERERS[id];\n if (renderer.status === \"not-implemented\") {\n throw new ZitadelError(\n \"E_NOT_IMPLEMENTED\",\n `Renderer \"${id}\" is declared but not yet published`,\n {\n hint: \"Use --renderer react for now; the <zitadel-flow> web component ships in a later package.\",\n },\n );\n }\n return renderer;\n}\n","import { join } from \"node:path\";\n\nimport { MANAGED_MARKER } from \"../../../../paths\";\nimport type { FileOp } from \"../file-writer/types\";\nimport type { PatchContext, PatchView } from \"../../types\";\nimport { AbstractRulePatcher } from \"../base\";\nimport { getRenderer } from \"./renderers/registry\";\nimport type { RendererSpec } from \"./renderers/types\";\n\n/**\n * Next.js `middleware.ts` at the project root. Wires `nextgenMiddleware` so the\n * scaffolded `<zitadel-login api-base=\"/__nextgen\">` requests are same-origin\n * proxied to `ZITADEL_URL` and `/profile` is gated. The `middleware`\n * form (not the Next 16 `proxy` rename) works on every supported Next major.\n * Carries the managed marker so `doctor --fix` reclaims it and `eject` removes it.\n */\nconst middlewareTemplate = `${MANAGED_MARKER}\nimport { nextgenMiddleware } from \"@zitadel/sdk-next/middleware\";\nimport type { NextRequest } from \"next/server\";\n\nexport function middleware(req: NextRequest) {\n return nextgenMiddleware(req, {\n url: process.env.ZITADEL_URL,\n protectedRoutes: [\"/profile\"],\n loginPath: \"/login\",\n });\n}\n\nexport const config = {\n matcher: [\"/__nextgen/:path*\", \"/profile/:path*\"],\n};\n`;\n\n/**\n * Rule-based patcher for the Next.js App Router. Inherits the shared\n * `.zitadel/` base files from {@link AbstractRulePatcher} and contributes the\n * Next routes/middleware whose templates come from the chosen renderer.\n */\nexport class NextPatcher extends AbstractRulePatcher {\n /** Returns true for Next.js projects. */\n canPatch(framework: string): boolean {\n return framework === \"next\";\n }\n\n protected routeOps(ctx: PatchContext): FileOp[] {\n return nextCodeOps(ctx, getRenderer(ctx.rendererId));\n }\n\n protected routeFiles(view: PatchView): ReadonlyArray<string> {\n return nextCodeFilePaths(view.framework.appDir, getRenderer(view.rendererId));\n }\n\n protected routeDeps(view: PatchView): ReadonlyArray<string> {\n return [getRenderer(view.rendererId).dependency.name];\n }\n\n protected summary(ctx: PatchContext): { title: string; detail: string } {\n return {\n title: \"Next.js integration\",\n detail: `Scaffolded login/register/profile routes with renderer \"${ctx.rendererId}\".`,\n };\n }\n}\n\n/**\n * Ordered paths of the framework code files the patcher writes. All carry the\n * managed marker. Shared by {@link NextPatcher.routeOps} (which adds contents)\n * and {@link NextPatcher.routeFiles} (which only needs the paths) so the two\n * cannot drift.\n */\nfunction nextCodeFilePaths(appDir: string, renderer: RendererSpec): ReadonlyArray<string> {\n const paths = [join(appDir, \"login/page.tsx\"), join(appDir, \"register/page.tsx\")];\n if (renderer.templates.profilePage) {\n paths.push(join(appDir, \"profile/page.tsx\"));\n }\n paths.push(join(appDir, \"../middleware.ts\"));\n if (renderer.templates.provider) {\n paths.push(join(appDir, renderer.templates.provider.filename));\n }\n if (renderer.templates.customElementsDts) {\n paths.push(join(appDir, \"../custom-elements.d.ts\"));\n }\n return paths;\n}\n\n/** The Next route/middleware write ops plus the SDK dependency. */\nfunction nextCodeOps(ctx: PatchContext, renderer: RendererSpec): FileOp[] {\n const appDir = ctx.framework.appDir;\n const ops: FileOp[] = [\n {\n kind: \"write\",\n path: join(appDir, \"login/page.tsx\"),\n contents: renderer.templates.authPage(\"login\").contents,\n },\n {\n kind: \"write\",\n path: join(appDir, \"register/page.tsx\"),\n contents: renderer.templates.authPage(\"register\").contents,\n },\n ];\n const profile = renderer.templates.profilePage?.();\n if (profile) {\n ops.push({ kind: \"write\", path: join(appDir, \"profile/page.tsx\"), contents: profile.contents });\n }\n ops.push({ kind: \"write\", path: join(appDir, \"../middleware.ts\"), contents: middlewareTemplate });\n const provider = renderer.templates.provider;\n if (provider) {\n ops.push({ kind: \"write\", path: join(appDir, provider.filename), contents: provider.contents });\n }\n const dts = renderer.templates.customElementsDts?.();\n if (dts) {\n ops.push({\n kind: \"write\",\n path: join(appDir, \"../custom-elements.d.ts\"),\n contents: dts.contents,\n });\n }\n ops.push({\n kind: \"add-dep\",\n name: renderer.dependency.name,\n version: dependencyVersionForCli(ctx.cliVersion, renderer.dependency.version),\n });\n return ops;\n}\n\nfunction dependencyVersionForCli(cliVersion: string, fallback: string): string {\n const normalized = cliVersion.trim().replace(/^v/, \"\");\n if (/^\\d+\\.\\d+\\.\\d+-alpha\\.\\d+$/.test(normalized)) {\n return normalized;\n }\n const prerelease = normalized.match(/^\\d+\\.\\d+\\.\\d+-([0-9A-Za-z]+)(?:[.-]|$)/)?.[1];\n return prerelease ?? fallback;\n}\n","import { NextPatcher } from \"./rule/next\";\nimport type { Patcher } from \"./types\";\n\n/**\n * Active patchers, in priority order; the first whose `canPatch` matches wins.\n *\n * Patchers are grouped by family under subdirectories: `rule/` holds the\n * deterministic, template-driven patchers (extending\n * {@link import(\"./rule/base\").AbstractRulePatcher}). A future LLM-driven\n * family lives under `llm/` and registers its concrete patchers here — no\n * orchestrator or command changes needed. Only Next.js is supported today.\n */\nexport const patchers = [new NextPatcher()] as const satisfies ReadonlyArray<Patcher>;\n","import { spawnSync } from \"node:child_process\";\n\nimport { ZitadelError } from \"../../errors\";\nimport type { Scaffolder } from \"./types\";\n\n/**\n * Base for scaffolders that delegate to an external CLI (e.g. create-next-app).\n * Subclasses implement {@link scaffold} and call {@link runCommand}.\n */\nexport abstract class AbstractCLIScaffolder implements Scaffolder {\n abstract readonly displayName: string;\n abstract readonly supportedFrameworks: ReadonlyArray<string>;\n\n /** True when the requested framework is in {@link supportedFrameworks}. */\n canScaffold(framework: string): boolean {\n return this.supportedFrameworks.includes(framework);\n }\n\n abstract scaffold(cwd: string, framework: string): Promise<void>;\n\n /**\n * Runs an external command in `cwd`, throwing a typed {@link ZitadelError} on\n * failure so the cause surfaces as a categorized CLI error. Distinguishes\n * \"binary not on PATH\" (`ENOENT` from the spawn itself) from \"binary ran but\n * exited non-zero\" — the former previously got masked as a generic\n * `exited with status 1`, leaving users to guess. Tests stub\n * `node:child_process` to assert the command without spawning.\n */\n protected runCommand(command: string, args: ReadonlyArray<string>, cwd: string): void {\n const result = spawnSync(command, [...args], { cwd, encoding: \"utf8\" });\n if (result.error) {\n const err = result.error as NodeJS.ErrnoException;\n const notFound = err.code === \"ENOENT\";\n throw new ZitadelError(\n \"E_VALIDATION\",\n notFound ? `Command not found: ${command}` : `Failed to spawn \"${command}\": ${err.message}`,\n {\n hint: notFound ? `Ensure '${command}' is installed and on PATH.` : undefined,\n details: { command, args: [...args], code: err.code },\n },\n );\n }\n const status = result.status ?? 1;\n if (status !== 0) {\n const stdout = String(result.stdout ?? \"\");\n const stderr = String(result.stderr ?? \"\");\n const output = truncateCommandOutput([stderr, stdout].filter(Boolean).join(\"\\n\").trim());\n throw new ZitadelError(\n \"E_VALIDATION\",\n `Command \"${command} ${args.join(\" \")}\" exited with status ${String(status)}`,\n {\n hint: output ? `Command output:\\n${output}` : \"Run the command directly for more detail.\",\n details: { command, args: [...args], cwd, stdout, stderr },\n },\n );\n }\n }\n}\n\nfunction truncateCommandOutput(output: string): string {\n const limit = 4000;\n if (output.length <= limit) {\n return output;\n }\n return `${output.slice(0, limit)}\\n... output truncated ...`;\n}\n","import { AbstractCLIScaffolder } from \"./cli\";\n\nconst CREATE_NEXT_APP_VERSION = \"16.2.4\";\n\n/** Scaffolds a new Next.js App Router project with `create-next-app`. */\nexport class NextScaffolder extends AbstractCLIScaffolder {\n readonly displayName = \"Next.js\";\n readonly supportedFrameworks: ReadonlyArray<string> = [\"next\"];\n\n /**\n * Runs the pinned `create-next-app` version in `cwd`, creating a TypeScript\n * App Router project in place. `--yes` accepts all defaults so the command\n * runs unattended, and `--skip-install` leaves dependency installation to the\n * setup command's explicit next step after Zitadel patches package.json.\n */\n async scaffold(cwd: string, _framework: string): Promise<void> {\n this.runCommand(\n \"npx\",\n [\n \"--yes\",\n `create-next-app@${CREATE_NEXT_APP_VERSION}`,\n \".\",\n \"--ts\",\n \"--app\",\n \"--use-npm\",\n \"--disable-git\",\n \"--yes\",\n \"--skip-install\",\n ],\n cwd,\n );\n }\n}\n","import { NextScaffolder } from \"./next\";\nimport type { Scaffolder } from \"./types\";\n\n/**\n * Active scaffolders, in priority order. The framework picker derives its\n * choices from this list. Add a new framework by appending its scaffolder\n * here — no orchestrator changes needed.\n */\nexport const scaffolders = [new NextScaffolder()] as const satisfies ReadonlyArray<Scaffolder>;\n","import { mkdir, readdir, readFile, rename, rm, writeFile } from \"node:fs/promises\";\nimport { basename, dirname, join } from \"node:path\";\n\nimport { ZitadelError } from \"../errors\";\nimport { detectors } from \"./detectors\";\nimport type { Detector, FrameworkFacts } from \"./detectors/types\";\nimport { patchers } from \"./patchers\";\nimport type { Patcher } from \"./patchers/types\";\nimport { scaffolders } from \"./scaffolders\";\nimport type { Scaffolder } from \"./scaffolders/types\";\n\nexport type { Detector, FrameworkFacts } from \"./detectors/types\";\nexport { issuerFromPort } from \"./detectors/port\";\n\n/** One framework the CLI can scaffold from scratch, surfaced to the picker. */\nexport type FrameworkChoice = Readonly<{ id: string; displayName: string }>;\n\nexport type ScaffoldTarget = Readonly<{\n scaffoldable: boolean;\n hasRuntimeOnlyZitadel: boolean;\n reason?: string;\n entries: ReadonlyArray<string>;\n}>;\n\n/**\n * Orchestrates the three per-framework strategies — detectors (recognise an\n * existing project and extract its facts), scaffolders (create a project), and\n * patchers (integrate Zitadel) — over their respective registries. It resolves\n * the right strategy for a framework and drives the detect/scaffold lifecycle;\n * how a patcher applies its work (file operations vs an LLM agent) stays\n * internal to that patcher. Registries are injected so tests can supply fakes.\n */\nexport class Orca {\n constructor(\n private readonly detectors: ReadonlyArray<Detector>,\n private readonly scaffolders: ReadonlyArray<Scaffolder>,\n private readonly patchers: ReadonlyArray<Patcher>,\n ) {}\n\n /**\n * Detects the framework in `cwd` and extracts its {@link FrameworkFacts},\n * honouring an explicit `requested` framework. Throws\n * `E_FRAMEWORK_NOT_DETECTED` when nothing matches; a detector's\n * `E_UNSUPPORTED_PROJECT_SHAPE` (recognised but unsupported) propagates.\n */\n async detect(cwd: string, requested?: string): Promise<FrameworkFacts> {\n const candidates = requested\n ? this.detectors.filter((detector) => detector.framework === requested)\n : this.detectors;\n if (requested && candidates.length === 0) {\n throw new ZitadelError(\"E_FRAMEWORK_NOT_DETECTED\", `Unsupported framework \"${requested}\"`, {\n hint: `Supported frameworks: ${this.frameworkIds().join(\", \")}.`,\n });\n }\n for (const detector of candidates) {\n const facts = await detector.detect(cwd);\n if (facts) {\n return facts;\n }\n }\n throw new ZitadelError(\n \"E_FRAMEWORK_NOT_DETECTED\",\n \"Could not detect a supported app framework\",\n {\n hint: \"Run setup from your app project directory, pass --cwd <path-to-app>, or run setup from an empty directory to scaffold a new app.\",\n },\n );\n }\n\n /**\n * Non-throwing detection: returns `undefined` instead of raising for a\n * project that is absent, unrecognised, or recognised-but-unsupported, so\n * callers (e.g. `eject`) can probe and degrade gracefully.\n */\n async tryDetect(cwd: string): Promise<FrameworkFacts | undefined> {\n try {\n return await this.detect(cwd);\n } catch (error) {\n if (\n error instanceof ZitadelError &&\n (error.code === \"E_FRAMEWORK_NOT_DETECTED\" || error.code === \"E_UNSUPPORTED_PROJECT_SHAPE\")\n ) {\n return undefined;\n }\n throw error;\n }\n }\n\n /** Whether `cwd` is safe for an in-place framework scaffold. */\n async isFreshScaffoldTarget(cwd: string): Promise<boolean> {\n return (await inspectScaffoldTarget(cwd)).scaffoldable;\n }\n\n /**\n * Creates a new `framework` project in `cwd`, then re-detects it to return\n * the resulting {@link FrameworkFacts}. Throws `E_CONFLICT` when the directory\n * already contains a project (\"already scaffolded\") and `E_VALIDATION` when no\n * scaffolder supports the framework.\n */\n async scaffold(cwd: string, framework: string): Promise<FrameworkFacts> {\n const target = await inspectScaffoldTarget(cwd);\n if (!target.scaffoldable) {\n throw new ZitadelError(\"E_CONFLICT\", `Cannot scaffold: ${cwd} is not empty`, {\n hint:\n target.reason ??\n \"Run setup in an empty directory, or run setup from an existing supported app project.\",\n details: { entries: target.entries },\n });\n }\n const stash = target.hasRuntimeOnlyZitadel ? await stashRuntimeOnlyZitadel(cwd) : undefined;\n try {\n await this.scaffolderFor(framework).scaffold(cwd, framework);\n } finally {\n await restoreRuntimeOnlyZitadel(cwd, stash);\n }\n return this.detect(cwd, framework);\n }\n\n /**\n * Resolves the scaffolder for a framework, throwing `E_VALIDATION` (with the\n * available list) when none matches.\n */\n scaffolderFor(framework: string): Scaffolder {\n const scaffolder = this.scaffolders.find((candidate) => candidate.canScaffold(framework));\n if (!scaffolder) {\n throw new ZitadelError(\"E_VALIDATION\", `No scaffolder supports \"${framework}\"`, {\n hint: `Available frameworks: ${this.availableFrameworks()\n .map((f) => f.id)\n .join(\", \")}.`,\n });\n }\n return scaffolder;\n }\n\n /**\n * Resolves the patcher for a framework, throwing `E_VALIDATION` when none\n * matches (e.g. a framework that can be scaffolded but not yet integrated).\n */\n patcherFor(framework: string): Patcher {\n const patcher = this.patchers.find((candidate) => candidate.canPatch(framework));\n if (!patcher) {\n throw new ZitadelError(\"E_VALIDATION\", `No patcher supports \"${framework}\"`, {\n hint: \"Zitadel integration currently supports Next.js.\",\n });\n }\n return patcher;\n }\n\n /** The frameworks that can be scaffolded, derived from the scaffolder registry. */\n availableFrameworks(): ReadonlyArray<FrameworkChoice> {\n return this.scaffolders.map((scaffolder) => ({\n id: scaffolder.supportedFrameworks[0] ?? scaffolder.displayName,\n displayName: scaffolder.displayName,\n }));\n }\n\n private frameworkIds(): ReadonlyArray<string> {\n return this.detectors.map((detector) => detector.framework);\n }\n}\n\n/** {@link Orca} wired with the default detector, scaffolder, and patcher registries. */\nexport function createOrca(): Orca {\n return new Orca(detectors, scaffolders, patchers);\n}\n\nexport async function inspectScaffoldTarget(cwd: string): Promise<ScaffoldTarget> {\n const entries = await readdir(cwd, { withFileTypes: true });\n const names = entries.map((entry) => entry.name).sort();\n let hasRuntimeOnlyZitadel = false;\n\n for (const entry of entries) {\n if (entry.name === \".gitignore\") {\n if (!entry.isFile()) {\n return {\n scaffoldable: false,\n hasRuntimeOnlyZitadel: false,\n reason: \".gitignore exists but is not a file.\",\n entries: names,\n };\n }\n continue;\n }\n\n if (entry.name === \".zitadel\") {\n if (!entry.isDirectory() || !(await isRuntimeOnlyZitadelDir(join(cwd, \".zitadel\")))) {\n return {\n scaffoldable: false,\n hasRuntimeOnlyZitadel: false,\n reason:\n \".zitadel contains project state. Move it aside or run setup from an empty app directory.\",\n entries: names,\n };\n }\n hasRuntimeOnlyZitadel = true;\n continue;\n }\n\n return {\n scaffoldable: false,\n hasRuntimeOnlyZitadel: false,\n reason: `Directory contains ${entry.name}. Run setup from an empty directory to scaffold a new app.`,\n entries: names,\n };\n }\n\n return { scaffoldable: true, hasRuntimeOnlyZitadel, entries: names };\n}\n\nasync function isRuntimeOnlyZitadelDir(path: string): Promise<boolean> {\n const entries = await readdir(path, { withFileTypes: true });\n if (entries.length !== 1 || entries[0]?.name !== \"local\" || !entries[0].isDirectory()) {\n return false;\n }\n return true;\n}\n\nasync function stashRuntimeOnlyZitadel(cwd: string): Promise<string> {\n const source = join(cwd, \".zitadel\");\n const parent = dirname(cwd);\n const prefix = `.${basename(cwd)}.zitadel-local-stash`;\n const stash = join(parent, `${prefix}-${String(process.pid)}-${String(Date.now())}`);\n await rename(source, stash);\n return stash;\n}\n\nasync function restoreRuntimeOnlyZitadel(cwd: string, stash: string | undefined): Promise<void> {\n if (!stash) {\n return;\n }\n const target = join(cwd, \".zitadel\");\n try {\n await rename(stash, target);\n await appendGitignoreEntry(cwd, \".zitadel/local/\");\n return;\n } catch (error) {\n if (!isErrno(error, \"EEXIST\")) {\n throw error;\n }\n }\n\n await mkdir(target, { recursive: true, mode: 0o700 });\n await rename(join(stash, \"local\"), join(target, \"local\"));\n await rm(stash, { recursive: true, force: true });\n await appendGitignoreEntry(cwd, \".zitadel/local/\");\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/g).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 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"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
- import { C as parseJsonObject, S as isObject, T as ZitadelError } from "./oclif-DSPO9Sck.mjs";
2
- import { readFile, stat } from "node:fs/promises";
1
+ import { C as isObject, E as ZitadelError, w as parseJsonObject } from "./oclif-D-R4dfQr.mjs";
3
2
  import { join } from "node:path";
3
+ import { readFile, stat } from "node:fs/promises";
4
4
  //#region src/lib/project.ts
5
5
  /**
6
6
  * Reports whether `cwd` has already been initialized, i.e. a committed
@@ -84,4 +84,4 @@ function isNotFound(error) {
84
84
  //#endregion
85
85
  export { readZitadelConfig as a, readRendererId as i, hasZitadelSecret as n, readZitadelSecret as o, readDevelopmentIssuer as r, hasZitadelConfig as t };
86
86
 
87
- //# sourceMappingURL=project-Dwb9WVAT.mjs.map
87
+ //# sourceMappingURL=project-DZJfxYKW.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"project-Dwb9WVAT.mjs","names":[],"sources":["../src/lib/project.ts"],"sourcesContent":["import { readFile, stat } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { ZitadelError } from \"./errors\";\nimport { isObject, parseJsonObject } from \"./json\";\n\n/**\n * Reports whether `cwd` has already been initialized, i.e. a committed\n * `zitadel.json` exists. Used to decide whether setup should run or skip.\n */\nexport async function hasZitadelConfig(cwd: string): Promise<boolean> {\n return exists(join(cwd, \"zitadel.json\"));\n}\n\n/**\n * Reports whether local secret material (`.zitadel/secret`) is present. Gates\n * commands that need credentials, and signals that secrets were already pulled.\n */\nexport async function hasZitadelSecret(cwd: string): Promise<boolean> {\n return exists(join(cwd, \".zitadel/secret\"));\n}\n\nasync function exists(path: string): Promise<boolean> {\n try {\n await stat(path);\n return true;\n } catch (error) {\n if (isNotFound(error)) {\n return false;\n }\n throw error;\n }\n}\n\n/**\n * Shape of the project secret persisted at `.zitadel/secret`. Holds the\n * project identity plus the credentials used to talk to the platform in\n * preview and production. Validated structurally by {@link readZitadelSecret}.\n */\nexport type ZitadelSecret = {\n project_id: string;\n project_secret: string;\n preview_secret: string;\n preview_origins: string[];\n created_at: string;\n};\n\n/**\n * Reads and parses `zitadel.json` into a plain object. Translates a missing\n * file into an actionable `E_VALIDATION` error pointing at `zitadel setup`;\n * other errors (e.g. malformed JSON) propagate unchanged.\n */\nexport async function readZitadelConfig(cwd: string): Promise<Record<string, unknown>> {\n try {\n return parseJsonObject(await readFile(join(cwd, \"zitadel.json\"), \"utf8\"), \"zitadel.json\");\n } catch (error) {\n if (isNotFound(error)) {\n throw new ZitadelError(\"E_VALIDATION\", \"zitadel.json was not found\", {\n hint: \"Run `zitadel setup` first.\",\n nextCommands: [\"zitadel setup\"],\n });\n }\n throw error;\n }\n}\n\n/**\n * Reads, parses, and structurally validates `.zitadel/secret`, returning it\n * as a {@link ZitadelSecret}. A missing file becomes an actionable\n * `E_VALIDATION` error pointing at `zitadel setup` / `zitadel doctor --fix`;\n * a present-but-incomplete file throws so callers never proceed with partial\n * credentials.\n */\nexport async function readZitadelSecret(cwd: string): Promise<ZitadelSecret> {\n try {\n const secret = parseJsonObject(\n await readFile(join(cwd, \".zitadel/secret\"), \"utf8\"),\n \".zitadel/secret\",\n );\n if (\n typeof secret.project_id !== \"string\" ||\n typeof secret.project_secret !== \"string\" ||\n typeof secret.preview_secret !== \"string\" ||\n !Array.isArray(secret.preview_origins)\n ) {\n throw new Error(\".zitadel/secret is missing required fields\");\n }\n return secret as ZitadelSecret;\n } catch (error) {\n if (isNotFound(error)) {\n throw new ZitadelError(\"E_VALIDATION\", \".zitadel/secret was not found\", {\n hint: \"Run `zitadel setup` first, or restore the project secret with `zitadel doctor --fix`.\",\n nextCommands: [\"zitadel setup\", \"zitadel doctor --fix\"],\n });\n }\n throw error;\n }\n}\n\n/**\n * Reads the configured renderer id from a parsed `zitadel.json`, normalising the\n * legacy `default` alias to `react` and falling back to `react` when unset. The\n * value is validated downstream by `getRenderer`, so callers need not re-check.\n */\nexport function readRendererId(config: Record<string, unknown>): string {\n const branding = isObject(config.branding) ? config.branding : undefined;\n const value = branding && typeof branding.renderer === \"string\" ? branding.renderer : \"react\";\n return value === \"default\" ? \"react\" : value;\n}\n\n/** Reads `environments.development.issuer` from a parsed `zitadel.json`, if present. */\nexport function readDevelopmentIssuer(config: Record<string, unknown>): string | undefined {\n if (isObject(config.environments) && isObject(config.environments.development)) {\n const issuer = config.environments.development.issuer;\n return typeof issuer === \"string\" ? issuer : undefined;\n }\n return undefined;\n}\n\nfunction isNotFound(error: unknown): boolean {\n return (\n typeof error === \"object\" &&\n error !== null &&\n \"code\" in error &&\n (error as { code?: string }).code === \"ENOENT\"\n );\n}\n"],"mappings":";;;;;;;;AAUA,eAAsB,iBAAiB,KAA+B;AACpE,QAAO,OAAO,KAAK,KAAK,eAAe,CAAC;;;;;;AAO1C,eAAsB,iBAAiB,KAA+B;AACpE,QAAO,OAAO,KAAK,KAAK,kBAAkB,CAAC;;AAG7C,eAAe,OAAO,MAAgC;AACpD,KAAI;AACF,QAAM,KAAK,KAAK;AAChB,SAAO;UACA,OAAO;AACd,MAAI,WAAW,MAAM,CACnB,QAAO;AAET,QAAM;;;;;;;;AAsBV,eAAsB,kBAAkB,KAA+C;AACrF,KAAI;AACF,SAAO,gBAAgB,MAAM,SAAS,KAAK,KAAK,eAAe,EAAE,OAAO,EAAE,eAAe;UAClF,OAAO;AACd,MAAI,WAAW,MAAM,CACnB,OAAM,IAAI,aAAa,gBAAgB,8BAA8B;GACnE,MAAM;GACN,cAAc,CAAC,gBAAgB;GAChC,CAAC;AAEJ,QAAM;;;;;;;;;;AAWV,eAAsB,kBAAkB,KAAqC;AAC3E,KAAI;EACF,MAAM,SAAS,gBACb,MAAM,SAAS,KAAK,KAAK,kBAAkB,EAAE,OAAO,EACpD,kBACD;AACD,MACE,OAAO,OAAO,eAAe,YAC7B,OAAO,OAAO,mBAAmB,YACjC,OAAO,OAAO,mBAAmB,YACjC,CAAC,MAAM,QAAQ,OAAO,gBAAgB,CAEtC,OAAM,IAAI,MAAM,6CAA6C;AAE/D,SAAO;UACA,OAAO;AACd,MAAI,WAAW,MAAM,CACnB,OAAM,IAAI,aAAa,gBAAgB,iCAAiC;GACtE,MAAM;GACN,cAAc,CAAC,iBAAiB,uBAAuB;GACxD,CAAC;AAEJ,QAAM;;;;;;;;AASV,SAAgB,eAAe,QAAyC;CACtE,MAAM,WAAW,SAAS,OAAO,SAAS,GAAG,OAAO,WAAW,KAAA;CAC/D,MAAM,QAAQ,YAAY,OAAO,SAAS,aAAa,WAAW,SAAS,WAAW;AACtF,QAAO,UAAU,YAAY,UAAU;;;AAIzC,SAAgB,sBAAsB,QAAqD;AACzF,KAAI,SAAS,OAAO,aAAa,IAAI,SAAS,OAAO,aAAa,YAAY,EAAE;EAC9E,MAAM,SAAS,OAAO,aAAa,YAAY;AAC/C,SAAO,OAAO,WAAW,WAAW,SAAS,KAAA;;;AAKjD,SAAS,WAAW,OAAyB;AAC3C,QACE,OAAO,UAAU,YACjB,UAAU,QACV,UAAU,SACT,MAA4B,SAAS"}
1
+ {"version":3,"file":"project-DZJfxYKW.mjs","names":[],"sources":["../src/lib/project.ts"],"sourcesContent":["import { readFile, stat } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nimport { ZitadelError } from \"./errors\";\nimport { isObject, parseJsonObject } from \"./json\";\n\n/**\n * Reports whether `cwd` has already been initialized, i.e. a committed\n * `zitadel.json` exists. Used to decide whether setup should run or skip.\n */\nexport async function hasZitadelConfig(cwd: string): Promise<boolean> {\n return exists(join(cwd, \"zitadel.json\"));\n}\n\n/**\n * Reports whether local secret material (`.zitadel/secret`) is present. Gates\n * commands that need credentials, and signals that secrets were already pulled.\n */\nexport async function hasZitadelSecret(cwd: string): Promise<boolean> {\n return exists(join(cwd, \".zitadel/secret\"));\n}\n\nasync function exists(path: string): Promise<boolean> {\n try {\n await stat(path);\n return true;\n } catch (error) {\n if (isNotFound(error)) {\n return false;\n }\n throw error;\n }\n}\n\n/**\n * Shape of the project secret persisted at `.zitadel/secret`. Holds the\n * project identity plus the credentials used to talk to the platform in\n * preview and production. Validated structurally by {@link readZitadelSecret}.\n */\nexport type ZitadelSecret = {\n project_id: string;\n project_secret: string;\n preview_secret: string;\n preview_origins: string[];\n created_at: string;\n};\n\n/**\n * Reads and parses `zitadel.json` into a plain object. Translates a missing\n * file into an actionable `E_VALIDATION` error pointing at `zitadel setup`;\n * other errors (e.g. malformed JSON) propagate unchanged.\n */\nexport async function readZitadelConfig(cwd: string): Promise<Record<string, unknown>> {\n try {\n return parseJsonObject(await readFile(join(cwd, \"zitadel.json\"), \"utf8\"), \"zitadel.json\");\n } catch (error) {\n if (isNotFound(error)) {\n throw new ZitadelError(\"E_VALIDATION\", \"zitadel.json was not found\", {\n hint: \"Run `zitadel setup` first.\",\n nextCommands: [\"zitadel setup\"],\n });\n }\n throw error;\n }\n}\n\n/**\n * Reads, parses, and structurally validates `.zitadel/secret`, returning it\n * as a {@link ZitadelSecret}. A missing file becomes an actionable\n * `E_VALIDATION` error pointing at `zitadel setup` / `zitadel doctor --fix`;\n * a present-but-incomplete file throws so callers never proceed with partial\n * credentials.\n */\nexport async function readZitadelSecret(cwd: string): Promise<ZitadelSecret> {\n try {\n const secret = parseJsonObject(\n await readFile(join(cwd, \".zitadel/secret\"), \"utf8\"),\n \".zitadel/secret\",\n );\n if (\n typeof secret.project_id !== \"string\" ||\n typeof secret.project_secret !== \"string\" ||\n typeof secret.preview_secret !== \"string\" ||\n !Array.isArray(secret.preview_origins)\n ) {\n throw new Error(\".zitadel/secret is missing required fields\");\n }\n return secret as ZitadelSecret;\n } catch (error) {\n if (isNotFound(error)) {\n throw new ZitadelError(\"E_VALIDATION\", \".zitadel/secret was not found\", {\n hint: \"Run `zitadel setup` first, or restore the project secret with `zitadel doctor --fix`.\",\n nextCommands: [\"zitadel setup\", \"zitadel doctor --fix\"],\n });\n }\n throw error;\n }\n}\n\n/**\n * Reads the configured renderer id from a parsed `zitadel.json`, normalising the\n * legacy `default` alias to `react` and falling back to `react` when unset. The\n * value is validated downstream by `getRenderer`, so callers need not re-check.\n */\nexport function readRendererId(config: Record<string, unknown>): string {\n const branding = isObject(config.branding) ? config.branding : undefined;\n const value = branding && typeof branding.renderer === \"string\" ? branding.renderer : \"react\";\n return value === \"default\" ? \"react\" : value;\n}\n\n/** Reads `environments.development.issuer` from a parsed `zitadel.json`, if present. */\nexport function readDevelopmentIssuer(config: Record<string, unknown>): string | undefined {\n if (isObject(config.environments) && isObject(config.environments.development)) {\n const issuer = config.environments.development.issuer;\n return typeof issuer === \"string\" ? issuer : undefined;\n }\n return undefined;\n}\n\nfunction isNotFound(error: unknown): boolean {\n return (\n typeof error === \"object\" &&\n error !== null &&\n \"code\" in error &&\n (error as { code?: string }).code === \"ENOENT\"\n );\n}\n"],"mappings":";;;;;;;;AAUA,eAAsB,iBAAiB,KAA+B;AACpE,QAAO,OAAO,KAAK,KAAK,eAAe,CAAC;;;;;;AAO1C,eAAsB,iBAAiB,KAA+B;AACpE,QAAO,OAAO,KAAK,KAAK,kBAAkB,CAAC;;AAG7C,eAAe,OAAO,MAAgC;AACpD,KAAI;AACF,QAAM,KAAK,KAAK;AAChB,SAAO;UACA,OAAO;AACd,MAAI,WAAW,MAAM,CACnB,QAAO;AAET,QAAM;;;;;;;;AAsBV,eAAsB,kBAAkB,KAA+C;AACrF,KAAI;AACF,SAAO,gBAAgB,MAAM,SAAS,KAAK,KAAK,eAAe,EAAE,OAAO,EAAE,eAAe;UAClF,OAAO;AACd,MAAI,WAAW,MAAM,CACnB,OAAM,IAAI,aAAa,gBAAgB,8BAA8B;GACnE,MAAM;GACN,cAAc,CAAC,gBAAgB;GAChC,CAAC;AAEJ,QAAM;;;;;;;;;;AAWV,eAAsB,kBAAkB,KAAqC;AAC3E,KAAI;EACF,MAAM,SAAS,gBACb,MAAM,SAAS,KAAK,KAAK,kBAAkB,EAAE,OAAO,EACpD,kBACD;AACD,MACE,OAAO,OAAO,eAAe,YAC7B,OAAO,OAAO,mBAAmB,YACjC,OAAO,OAAO,mBAAmB,YACjC,CAAC,MAAM,QAAQ,OAAO,gBAAgB,CAEtC,OAAM,IAAI,MAAM,6CAA6C;AAE/D,SAAO;UACA,OAAO;AACd,MAAI,WAAW,MAAM,CACnB,OAAM,IAAI,aAAa,gBAAgB,iCAAiC;GACtE,MAAM;GACN,cAAc,CAAC,iBAAiB,uBAAuB;GACxD,CAAC;AAEJ,QAAM;;;;;;;;AASV,SAAgB,eAAe,QAAyC;CACtE,MAAM,WAAW,SAAS,OAAO,SAAS,GAAG,OAAO,WAAW,KAAA;CAC/D,MAAM,QAAQ,YAAY,OAAO,SAAS,aAAa,WAAW,SAAS,WAAW;AACtF,QAAO,UAAU,YAAY,UAAU;;;AAIzC,SAAgB,sBAAsB,QAAqD;AACzF,KAAI,SAAS,OAAO,aAAa,IAAI,SAAS,OAAO,aAAa,YAAY,EAAE;EAC9E,MAAM,SAAS,OAAO,aAAa,YAAY;AAC/C,SAAO,OAAO,WAAW,WAAW,SAAS,KAAA;;;AAKjD,SAAS,WAAW,OAAyB;AAC3C,QACE,OAAO,UAAU,YACjB,UAAU,QACV,UAAU,SACT,MAA4B,SAAS"}
@@ -1,7 +1,7 @@
1
- import { S as isObject, T as ZitadelError } from "./oclif-DSPO9Sck.mjs";
1
+ import { C as isObject, E as ZitadelError } from "./oclif-D-R4dfQr.mjs";
2
2
  import { consola as consola$1 } from "consola";
3
- import { readFile, readdir, writeFile } from "node:fs/promises";
4
3
  import { join } from "node:path";
4
+ import { readFile, readdir, writeFile } from "node:fs/promises";
5
5
  import { createHash } from "node:crypto";
6
6
  import { z } from "zod";
7
7
  import { CreateFlowDefinitionBody, CreateSchemaBody } from "@zitadel/api/generated/endpoints/zitadelNextGen.zod";
@@ -730,4 +730,4 @@ function renderBlock(action, tty) {
730
730
  //#endregion
731
731
  export { makeSyncers as a, runSyncLoop as i, summarizePlan as n, environmentSchema as o, buildSyncPlan as r, renderPlan as t };
732
732
 
733
- //# sourceMappingURL=sync-DmtTYNmq.mjs.map
733
+ //# sourceMappingURL=sync-BJ0Sqb8w.mjs.map