@zitadel/config 0.1.0-alpha.18 → 0.1.0-alpha.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +27 -0
- package/defaults/README-branding.md +36 -2
- package/defaults/README-flows.md +21 -4
- package/defaults/README-schemas.md +2 -2
- package/defaults/branding/hero/login.liquid +4 -2
- package/defaults/branding/split/login.liquid +5 -0
- package/defaults/branding/split-right/login.liquid +5 -0
- package/defaults/default-human-user.json +2 -4
- package/defaults/default-login.json +20 -0
- package/defaults/presets/passkey-first/human-user.json +2 -4
- package/defaults/presets/passkey-first/login.json +30 -0
- package/dist/branding-url.d.mts +14 -0
- package/dist/branding-url.d.mts.map +1 -0
- package/dist/branding-url.mjs +23 -0
- package/dist/branding-url.mjs.map +1 -0
- package/dist/{defaults-CXTnFMHj.mjs → defaults-eiGHyI5Y.mjs} +130 -77
- package/dist/{defaults-CXTnFMHj.mjs.map → defaults-eiGHyI5Y.mjs.map} +1 -1
- package/dist/defaults.mjs +1 -1
- package/dist/index.d.mts +2 -1
- package/dist/index.mjs +4 -3
- package/dist/{meta-schemas-B4YiHAX_.mjs → meta-schemas-CSc18JqO.mjs} +27 -34
- package/dist/{meta-schemas-B4YiHAX_.mjs.map → meta-schemas-CSc18JqO.mjs.map} +1 -1
- package/dist/meta-schemas.mjs +1 -1
- package/dist/normalize.d.mts +11 -9
- package/dist/normalize.d.mts.map +1 -1
- package/dist/normalize.mjs +24 -17
- package/dist/normalize.mjs.map +1 -1
- package/dist/schemas.d.mts.map +1 -1
- package/dist/schemas.mjs +8 -6
- package/dist/schemas.mjs.map +1 -1
- package/dist/validate.mjs +70 -11
- package/dist/validate.mjs.map +1 -1
- package/meta-schemas/auth-method.json +2 -7
- package/meta-schemas/branding.json +8 -16
- package/meta-schemas/flow-definition.json +20 -1
- package/meta-schemas/user-property.json +2 -23
- package/package.json +7 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defaults-CXTnFMHj.mjs","names":["defaultHumanUserSchemaTemplate","defaultLoginFlowTemplate","passkeyFirstHumanUserSchemaTemplate","passkeyFirstLoginFlowTemplate"],"sources":["../defaults/default-human-user.json","../defaults/default-login.json","../defaults/presets/passkey-first/human-user.json","../defaults/presets/passkey-first/login.json","../src/readmes.ts","../src/defaults.ts"],"sourcesContent":["","","","","import { readFileSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\n\n/**\n * README content the CLI copies to `.zitadel/schemas/README.md` during setup.\n * Source of truth is `packages/config/defaults/README-schemas.md`; the Go\n * server-side embed reads the same file (see `defaults.go`).\n */\nexport function schemasReadmeContent(): string {\n return readFileSync(readmeUrl(\"README-schemas.md\"), \"utf8\");\n}\n\n/**\n * README content the CLI copies to `.zitadel/flows/README.md` during setup.\n * Source of truth is `packages/config/defaults/README-flows.md`.\n */\nexport function flowsReadmeContent(): string {\n return readFileSync(readmeUrl(\"README-flows.md\"), \"utf8\");\n}\n\n/**\n * README content the CLI copies to `.zitadel/branding/README.md` when a\n * branding design is ejected. Source of truth is\n * `packages/config/defaults/README-branding.md`.\n */\nexport function brandingReadmeContent(): string {\n return readFileSync(readmeUrl(\"README-branding.md\"), \"utf8\");\n}\n\nfunction readmeUrl(filename: string): string {\n return fileURLToPath(new URL(`../defaults/${filename}`, import.meta.url));\n}\n","import { readFileSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\n\nimport type {\n CreateFlowDefinitionBodyFlowDefinition,\n CreateSchemaBody,\n} from \"@zitadel/api/generated/model\";\n\nimport defaultHumanUserSchemaTemplate from \"../defaults/default-human-user.json\" with {\n type: \"json\",\n};\nimport defaultLoginFlowTemplate from \"../defaults/default-login.json\" with {\n type: \"json\",\n};\nimport passkeyFirstHumanUserSchemaTemplate from \"../defaults/presets/passkey-first/human-user.json\" with {\n type: \"json\",\n};\nimport passkeyFirstLoginFlowTemplate from \"../defaults/presets/passkey-first/login.json\" with {\n type: \"json\",\n};\n\nexport { brandingReadmeContent, flowsReadmeContent, schemasReadmeContent } from \"./readmes.js\";\n\nexport const DEFAULT_BUILTIN_SCHEMA_BASE = \"https://nextgen.com/api/schemas\";\nexport const DEFAULT_FLOW_SCHEMA_URI = \"https://nextgen.com/flow-definition.json\";\nexport const DEFAULT_SCHEMA_CONFIG_PATH = \".zitadel/schemas/default-human-user.json\";\nexport const DEFAULT_FLOW_CONFIG_PATH = \".zitadel/flows/default-login.json\";\nexport const DEFAULT_BRANDING_CONFIG_PATH = \".zitadel/branding/branding.json\";\nexport const DEFAULT_BRANDING_TEMPLATE_PATH = \".zitadel/branding/login.liquid\";\n\n/**\n * Named schema+flow bundles `zitadel setup` can scaffold (#448: the prompt\n * fires before any `.zitadel/` file is written; each preset maps to a\n * pre-defined bundle the CLI copies on first setup). `password-first` is\n * today's default; `passkey-first` puts a passkey ceremony on the login\n * entry step with an email→password fallback path.\n */\nexport const SETUP_PRESETS = [\"password-first\", \"passkey-first\"] as const;\n\nexport type SetupPreset = (typeof SETUP_PRESETS)[number];\n\nexport const DEFAULT_SETUP_PRESET: SetupPreset = \"password-first\";\n\nconst PRESET_TEMPLATES: Record<SetupPreset, { schema: unknown; flow: unknown }> = {\n \"password-first\": {\n schema: defaultHumanUserSchemaTemplate,\n flow: defaultLoginFlowTemplate,\n },\n \"passkey-first\": {\n schema: passkeyFirstHumanUserSchemaTemplate,\n flow: passkeyFirstLoginFlowTemplate,\n },\n};\n\nfunction presetTemplates(preset: string): { schema: unknown; flow: unknown } {\n // Own-property check: indexing a plain object with an arbitrary string\n // would let \"__proto__\"/\"constructor\" resolve via the prototype chain\n // and bypass the unknown-preset error.\n if (!Object.hasOwn(PRESET_TEMPLATES, preset)) {\n throw new Error(\n `unknown setup preset ${JSON.stringify(preset)} (known presets: ${SETUP_PRESETS.join(\", \")})`,\n );\n }\n return PRESET_TEMPLATES[preset as SetupPreset];\n}\n\n/**\n * Login-design starting points `zitadel branding eject --design <name>` (and\n * `zitadel setup --design <name>`) scaffold into `.zitadel/branding/`. A\n * design is a full Liquid template plus the descriptor `layout` it degrades\n * to — the wire `layout` enum stays `centered | split`, richer designs are\n * delivered as templates (ADR 040).\n */\nexport const BRANDING_DESIGNS = [\"centered\", \"split\", \"split-right\", \"hero\", \"minimal\"] as const;\n\nexport type BrandingDesign = (typeof BRANDING_DESIGNS)[number];\n\nexport const DEFAULT_BRANDING_DESIGN: BrandingDesign = \"centered\";\n\n/** Descriptor `layout` each design degrades to when its template is rejected. */\nconst DESIGN_LAYOUTS: Record<BrandingDesign, \"centered\" | \"split\"> = {\n centered: \"centered\",\n split: \"split\",\n \"split-right\": \"split\",\n hero: \"split\",\n minimal: \"centered\",\n};\n\nexport type DefaultBrandingConfig = {\n /** The `.zitadel/branding/branding.json` descriptor body (sans `$schema`). */\n branding: {\n layout: \"centered\" | \"split\";\n liquid_template_file: string;\n };\n /** The `.zitadel/branding/login.liquid` template content. */\n template: string;\n};\n\n/**\n * Renders the scaffold files for a branding design. The `centered` template\n * is a drift-tested copy of the bundled default in `@zitadel/components`;\n * the other designs are authored variants of it.\n */\nexport function getDefaultBrandingConfig(\n design: string = DEFAULT_BRANDING_DESIGN,\n): DefaultBrandingConfig {\n if (!Object.hasOwn(DESIGN_LAYOUTS, design)) {\n throw new Error(\n `unknown branding design ${JSON.stringify(design)} (known designs: ${BRANDING_DESIGNS.join(\", \")})`,\n );\n }\n const known = design as BrandingDesign;\n return {\n branding: {\n layout: DESIGN_LAYOUTS[known],\n liquid_template_file: \"./login.liquid\",\n },\n template: readFileSync(packageFilePath(`../defaults/branding/${known}/login.liquid`), \"utf8\"),\n };\n}\n\n/**\n * Resolves a package-relative file to a real filesystem path. Vite-driven\n * runtimes (vitest in dependent packages) rewrite `import.meta.url` to a\n * `/@fs/...` URL, which `fileURLToPath` passes through verbatim — strip the\n * prefix so `readFileSync` gets an actual path.\n */\nfunction packageFilePath(relative: string): string {\n const path = fileURLToPath(new URL(relative, import.meta.url));\n return path.startsWith(\"/@fs/\") ? path.slice(\"/@fs\".length) : path;\n}\n\n/**\n * The second setup axis (#448): *who* signs in, orthogonal to the sign-in\n * preset (*how* they sign in). The sign-in preset owns the flow shape and\n * auth methods; the use case owns which profile fields the schema collects.\n * Composing the two keeps us at one field catalog + one flow-per-preset\n * instead of a bundle per (use case × preset) pair. `minimal` is the\n * default and never blocks non-interactive runs.\n */\nexport const SETUP_USE_CASES = [\"minimal\", \"consumer\", \"business\"] as const;\n\nexport type SetupUseCase = (typeof SETUP_USE_CASES)[number];\n\nexport const DEFAULT_SETUP_USE_CASE: SetupUseCase = \"minimal\";\n\n/**\n * Fields each use case collects, in register/display order. `email` is\n * always first and stays the only required property; the rest are optional\n * profile attributes gathered on the flow's register step. `givenName`/\n * `familyName` are the attributes the backend reads for a user's identity\n * (`internal/domain/user.go`); `companyName` is stored as a plain user\n * attribute today — there is no org/team model behind it yet.\n */\nconst USE_CASE_FIELDS: Record<SetupUseCase, readonly string[]> = {\n minimal: [\"email\"],\n consumer: [\"email\", \"givenName\", \"familyName\"],\n business: [\"email\", \"givenName\", \"familyName\", \"companyName\"],\n};\n\n/**\n * JSON-Schema bodies for the optional profile fields the CLI composes in per\n * use case. The shipped templates are an email-only baseline (shared verbatim\n * with the Go server fallback), so this catalog owns every field beyond\n * `email`. Authored in the templates' style — no `x-claim`, since the backend\n * maps identity by attribute name and the user-property meta-schema defines no\n * claim keyword. `givenName`/`familyName` are the attributes the backend reads\n * for a user's identity (`internal/domain/user.go`).\n */\nconst EXTRA_FIELD_BODIES: Record<string, Record<string, unknown>> = {\n givenName: {\n type: \"string\",\n maxLength: 50,\n description: \"The user's given (first) name.\",\n },\n familyName: {\n type: \"string\",\n maxLength: 50,\n description: \"The user's family (last) name.\",\n },\n companyName: {\n type: \"string\",\n maxLength: 200,\n description: \"The user's company name.\",\n },\n};\n\nfunction useCaseFields(useCase: string): readonly string[] {\n // Own-property check, same rationale as presetTemplates: keep prototype\n // keys (\"__proto__\" etc.) from resolving to a real field list.\n if (!Object.hasOwn(USE_CASE_FIELDS, useCase)) {\n throw new Error(\n `unknown setup use case ${JSON.stringify(useCase)} (known use cases: ${SETUP_USE_CASES.join(\", \")})`,\n );\n }\n return USE_CASE_FIELDS[useCase as SetupUseCase];\n}\n\n/**\n * The body for one use-case field: reuse the template's authored body when it\n * has one (so composed schemas match the shipped defaults for shared fields),\n * else the extra catalog, else a generic editable string so composition stays\n * total for any field a future use case introduces.\n */\nfunction fieldBody(\n field: string,\n templateProps: Record<string, Record<string, unknown>>,\n): Record<string, unknown> {\n if (Object.hasOwn(templateProps, field)) {\n return { ...templateProps[field] };\n }\n if (Object.hasOwn(EXTRA_FIELD_BODIES, field)) {\n return { ...EXTRA_FIELD_BODIES[field] };\n }\n return { type: \"string\", description: `The user's ${field}.` };\n}\n\n/**\n * Narrow a rendered schema to the chosen use case: keep the preset-owned\n * header and `x-auth-methods`, but replace `properties`/`required` with the\n * use case's field set. `email` is the sole required property.\n */\nfunction applyUseCaseToSchema(\n schema: Record<string, unknown>,\n useCase: string,\n): Record<string, unknown> {\n const templateProps = (schema.properties ?? {}) as Record<string, Record<string, unknown>>;\n const properties: Record<string, unknown> = {};\n for (const field of useCaseFields(useCase)) {\n properties[field] = fieldBody(field, templateProps);\n }\n return { ...schema, required: [\"email\"], properties };\n}\n\n/**\n * Derive the flow's register-step fields from the use case rather than\n * copying a hard-coded list into every bundle (#448): the register step\n * collects exactly what the schema defines. Other steps are untouched.\n */\nfunction applyUseCaseToFlow(\n flow: Record<string, unknown>,\n useCase: string,\n): Record<string, unknown> {\n const fields = [...useCaseFields(useCase)];\n const steps = (flow.steps as Array<Record<string, unknown>>).map((step) =>\n step.name === \"register\" ? { ...step, fields } : step,\n );\n return { ...flow, steps };\n}\n\nexport type DefaultConfigRenderOptions = {\n builtinSchemaBase?: string;\n userSchemaUrl?: string;\n /** Which flow/auth bundle to render; defaults to {@link DEFAULT_SETUP_PRESET}. */\n preset?: string;\n /** Which field set to collect; defaults to {@link DEFAULT_SETUP_USE_CASE}. */\n useCase?: string;\n};\n\nexport function defaultHumanUserSchemaUrl(\n builtinSchemaBase = DEFAULT_BUILTIN_SCHEMA_BASE,\n): string {\n return `${trimTrailingSlash(builtinSchemaBase)}/default-human-user.json`;\n}\n\nexport function getDefaultHumanUserSchema(\n options: DefaultConfigRenderOptions = {},\n): CreateSchemaBody {\n const builtinSchemaBase = trimTrailingSlash(\n options.builtinSchemaBase ?? DEFAULT_BUILTIN_SCHEMA_BASE,\n );\n const rendered = renderTemplate(presetTemplates(options.preset ?? DEFAULT_SETUP_PRESET).schema, {\n SERVER_URL: builtinSchemaBase,\n USER_SCHEMA_URL: options.userSchemaUrl ?? defaultHumanUserSchemaUrl(builtinSchemaBase),\n }) as Record<string, unknown>;\n return applyUseCaseToSchema(\n rendered,\n options.useCase ?? DEFAULT_SETUP_USE_CASE,\n ) as CreateSchemaBody;\n}\n\nexport function getDefaultLoginFlow(\n options: DefaultConfigRenderOptions = {},\n): CreateFlowDefinitionBodyFlowDefinition {\n const builtinSchemaBase = trimTrailingSlash(\n options.builtinSchemaBase ?? DEFAULT_BUILTIN_SCHEMA_BASE,\n );\n const rendered = renderTemplate(presetTemplates(options.preset ?? DEFAULT_SETUP_PRESET).flow, {\n SERVER_URL: builtinSchemaBase,\n USER_SCHEMA_URL: options.userSchemaUrl ?? defaultHumanUserSchemaUrl(builtinSchemaBase),\n }) as Record<string, unknown>;\n return applyUseCaseToFlow(\n rendered,\n options.useCase ?? DEFAULT_SETUP_USE_CASE,\n ) as CreateFlowDefinitionBodyFlowDefinition;\n}\n\nfunction renderTemplate(value: unknown, replacements: Record<string, string>): unknown {\n if (Array.isArray(value)) {\n return value.map((item) => renderTemplate(item, replacements));\n }\n if (value !== null && typeof value === \"object\") {\n return Object.fromEntries(\n Object.entries(value).map(([key, item]) => [key, renderTemplate(item, replacements)]),\n );\n }\n if (typeof value === \"string\") {\n return value.replaceAll(/\\$\\{([A-Z_]+)\\}/g, (match, name: string) => {\n return replacements[name] ?? match;\n });\n }\n return value;\n}\n\nfunction trimTrailingSlash(value: string): string {\n let trimmed = value;\n while (trimmed.endsWith(\"/\")) {\n trimmed = trimmed.slice(0, -1);\n }\n return trimmed;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"defaults-eiGHyI5Y.mjs","names":["defaultHumanUserSchemaTemplate","defaultLoginFlowTemplate","passkeyFirstHumanUserSchemaTemplate","passkeyFirstLoginFlowTemplate"],"sources":["../defaults/default-human-user.json","../defaults/default-login.json","../defaults/presets/passkey-first/human-user.json","../defaults/presets/passkey-first/login.json","../src/readmes.ts","../src/defaults.ts"],"sourcesContent":["","","","","import { readFileSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\n\n/**\n * README content the CLI copies to `.zitadel/schemas/README.md` during setup.\n * Source of truth is `packages/config/defaults/README-schemas.md`; the Go\n * server-side embed reads the same file (see `defaults.go`).\n */\nexport function schemasReadmeContent(): string {\n return readFileSync(readmeUrl(\"README-schemas.md\"), \"utf8\");\n}\n\n/**\n * README content the CLI copies to `.zitadel/flows/README.md` during setup.\n * Source of truth is `packages/config/defaults/README-flows.md`.\n */\nexport function flowsReadmeContent(): string {\n return readFileSync(readmeUrl(\"README-flows.md\"), \"utf8\");\n}\n\n/**\n * README content the CLI copies to `.zitadel/branding/README.md` when a\n * branding design is ejected. Source of truth is\n * `packages/config/defaults/README-branding.md`.\n */\nexport function brandingReadmeContent(): string {\n return readFileSync(readmeUrl(\"README-branding.md\"), \"utf8\");\n}\n\nfunction readmeUrl(filename: string): string {\n return fileURLToPath(new URL(`../defaults/${filename}`, import.meta.url));\n}\n","import { readFileSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\n\nimport type {\n CreateFlowDefinitionBodyFlowDefinition,\n CreateSchemaBody,\n} from \"@zitadel/api/generated/model\";\n\nimport defaultHumanUserSchemaTemplate from \"../defaults/default-human-user.json\" with {\n type: \"json\",\n};\nimport defaultLoginFlowTemplate from \"../defaults/default-login.json\" with {\n type: \"json\",\n};\nimport passkeyFirstHumanUserSchemaTemplate from \"../defaults/presets/passkey-first/human-user.json\" with {\n type: \"json\",\n};\nimport passkeyFirstLoginFlowTemplate from \"../defaults/presets/passkey-first/login.json\" with {\n type: \"json\",\n};\n\nexport { brandingReadmeContent, flowsReadmeContent, schemasReadmeContent } from \"./readmes.js\";\n\nexport const DEFAULT_BUILTIN_SCHEMA_BASE = \"https://nextgen.com/api/schemas\";\nexport const DEFAULT_FLOW_SCHEMA_URI = \"https://nextgen.com/flow-definition.json\";\nexport const DEFAULT_SCHEMA_CONFIG_PATH = \".zitadel/schemas/default-human-user.json\";\nexport const DEFAULT_FLOW_CONFIG_PATH = \".zitadel/flows/default-login.json\";\nexport const DEFAULT_BRANDING_CONFIG_PATH = \".zitadel/branding/branding.json\";\nexport const DEFAULT_BRANDING_TEMPLATE_PATH = \".zitadel/branding/login.liquid\";\n\n/**\n * Named schema+flow bundles `zitadel setup` can scaffold (#448: the prompt\n * fires before any `.zitadel/` file is written; each preset maps to a\n * pre-defined bundle the CLI copies on first setup). `password-first` is\n * today's default; `passkey-first` puts a passkey ceremony on the login\n * entry step with an email→password fallback path.\n */\nexport const SETUP_PRESETS = [\"password-first\", \"passkey-first\"] as const;\n\nexport type SetupPreset = (typeof SETUP_PRESETS)[number];\n\nexport const DEFAULT_SETUP_PRESET: SetupPreset = \"password-first\";\n\nconst PRESET_TEMPLATES: Record<SetupPreset, { schema: unknown; flow: unknown }> = {\n \"password-first\": {\n schema: defaultHumanUserSchemaTemplate,\n flow: defaultLoginFlowTemplate,\n },\n \"passkey-first\": {\n schema: passkeyFirstHumanUserSchemaTemplate,\n flow: passkeyFirstLoginFlowTemplate,\n },\n};\n\nfunction presetTemplates(preset: string): { schema: unknown; flow: unknown } {\n // Own-property check: indexing a plain object with an arbitrary string\n // would let \"__proto__\"/\"constructor\" resolve via the prototype chain\n // and bypass the unknown-preset error.\n if (!Object.hasOwn(PRESET_TEMPLATES, preset)) {\n throw new Error(\n `unknown setup preset ${JSON.stringify(preset)} (known presets: ${SETUP_PRESETS.join(\", \")})`,\n );\n }\n return PRESET_TEMPLATES[preset as SetupPreset];\n}\n\n/**\n * Login-design starting points `zitadel branding eject --design <name>` (and\n * `zitadel setup --design <name>`) scaffold into `.zitadel/branding/`. A\n * design is a full Liquid template plus the descriptor `layout` it degrades\n * to — the wire `layout` enum stays `centered | split`, richer designs are\n * delivered as templates (ADR 040).\n */\nexport const BRANDING_DESIGNS = [\"centered\", \"split\", \"split-right\", \"hero\", \"minimal\"] as const;\n\nexport type BrandingDesign = (typeof BRANDING_DESIGNS)[number];\n\nexport const DEFAULT_BRANDING_DESIGN: BrandingDesign = \"centered\";\n\n/** Descriptor `layout` each design degrades to when its template is rejected. */\nconst DESIGN_LAYOUTS: Record<BrandingDesign, \"centered\" | \"split\"> = {\n centered: \"centered\",\n split: \"split\",\n \"split-right\": \"split\",\n hero: \"split\",\n minimal: \"centered\",\n};\n\nexport type DefaultBrandingConfig = {\n /** The `.zitadel/branding/branding.json` descriptor body (sans `$schema`). */\n branding: {\n layout: \"centered\" | \"split\";\n liquid_template_file: string;\n };\n /** The `.zitadel/branding/login.liquid` template content. */\n template: string;\n};\n\n/**\n * Renders the scaffold files for a branding design. The `centered` template\n * is a drift-tested copy of the bundled default in `@zitadel/components`;\n * the other designs are authored variants of it.\n */\nexport function getDefaultBrandingConfig(\n design: string = DEFAULT_BRANDING_DESIGN,\n): DefaultBrandingConfig {\n if (!Object.hasOwn(DESIGN_LAYOUTS, design)) {\n throw new Error(\n `unknown branding design ${JSON.stringify(design)} (known designs: ${BRANDING_DESIGNS.join(\", \")})`,\n );\n }\n const known = design as BrandingDesign;\n return {\n branding: {\n layout: DESIGN_LAYOUTS[known],\n liquid_template_file: \"./login.liquid\",\n },\n template: readFileSync(packageFilePath(`../defaults/branding/${known}/login.liquid`), \"utf8\"),\n };\n}\n\n/**\n * Resolves a package-relative file to a real filesystem path. Vite-driven\n * runtimes (vitest in dependent packages) rewrite `import.meta.url` to a\n * `/@fs/...` URL, which `fileURLToPath` passes through verbatim — strip the\n * prefix so `readFileSync` gets an actual path.\n */\nfunction packageFilePath(relative: string): string {\n const path = fileURLToPath(new URL(relative, import.meta.url));\n return path.startsWith(\"/@fs/\") ? path.slice(\"/@fs\".length) : path;\n}\n\n/**\n * The second setup axis (#448): *who* signs in, orthogonal to the sign-in\n * preset (*how* they sign in). The sign-in preset owns the flow shape and\n * auth methods; the use case owns which profile fields the schema collects.\n * Composing the two keeps us at one field catalog + one flow-per-preset\n * instead of a bundle per (use case × preset) pair. `minimal` is the\n * default and never blocks non-interactive runs.\n */\nexport const SETUP_USE_CASES = [\"minimal\", \"consumer\", \"business\"] as const;\n\nexport type SetupUseCase = (typeof SETUP_USE_CASES)[number];\n\nexport const DEFAULT_SETUP_USE_CASE: SetupUseCase = \"minimal\";\n\n/**\n * Fields each use case collects, in register/display order. `email` is\n * always first and stays the only required property; the rest are optional\n * profile attributes gathered on the flow's register step. `givenName`/\n * `familyName` are the attributes the backend reads for a user's identity\n * (`internal/domain/user.go`); `companyName` is stored as a plain user\n * attribute today — there is no org/team model behind it yet.\n */\nconst USE_CASE_FIELDS: Record<SetupUseCase, readonly string[]> = {\n minimal: [\"email\"],\n consumer: [\"email\", \"givenName\", \"familyName\"],\n business: [\"email\", \"givenName\", \"familyName\", \"companyName\"],\n};\n\n/**\n * JSON-Schema bodies for the optional profile fields the CLI composes in per\n * use case. The shipped templates are an email-only baseline (shared verbatim\n * with the Go server fallback), so this catalog owns every field beyond\n * `email`. Authored in the templates' style — no `x-claim`, since the backend\n * maps identity by attribute name and the user-property meta-schema defines no\n * claim keyword. `givenName`/`familyName` are the attributes the backend reads\n * for a user's identity (`internal/domain/user.go`).\n */\nconst EXTRA_FIELD_BODIES: Record<string, Record<string, unknown>> = {\n givenName: {\n type: \"string\",\n maxLength: 50,\n description: \"The user's given (first) name.\",\n },\n familyName: {\n type: \"string\",\n maxLength: 50,\n description: \"The user's family (last) name.\",\n },\n companyName: {\n type: \"string\",\n maxLength: 200,\n description: \"The user's company name.\",\n },\n};\n\nfunction useCaseFields(useCase: string): readonly string[] {\n // Own-property check, same rationale as presetTemplates: keep prototype\n // keys (\"__proto__\" etc.) from resolving to a real field list.\n if (!Object.hasOwn(USE_CASE_FIELDS, useCase)) {\n throw new Error(\n `unknown setup use case ${JSON.stringify(useCase)} (known use cases: ${SETUP_USE_CASES.join(\", \")})`,\n );\n }\n return USE_CASE_FIELDS[useCase as SetupUseCase];\n}\n\n/**\n * The body for one use-case field: reuse the template's authored body when it\n * has one (so composed schemas match the shipped defaults for shared fields),\n * else the extra catalog, else a generic editable string so composition stays\n * total for any field a future use case introduces.\n */\nfunction fieldBody(\n field: string,\n templateProps: Record<string, Record<string, unknown>>,\n): Record<string, unknown> {\n if (Object.hasOwn(templateProps, field)) {\n return { ...templateProps[field] };\n }\n if (Object.hasOwn(EXTRA_FIELD_BODIES, field)) {\n return { ...EXTRA_FIELD_BODIES[field] };\n }\n return { type: \"string\", description: `The user's ${field}.` };\n}\n\n/**\n * Narrow a rendered schema to the chosen use case: keep the preset-owned\n * header and `x-auth-methods`, but replace `properties`/`required` with the\n * use case's field set. `email` is the sole required property.\n */\nfunction applyUseCaseToSchema(\n schema: Record<string, unknown>,\n useCase: string,\n): Record<string, unknown> {\n const templateProps = (schema.properties ?? {}) as Record<string, Record<string, unknown>>;\n const properties: Record<string, unknown> = {};\n for (const field of useCaseFields(useCase)) {\n properties[field] = fieldBody(field, templateProps);\n }\n return { ...schema, required: [\"email\"], properties };\n}\n\n/**\n * Derive the flow's register-step fields from the use case rather than\n * copying a hard-coded list into every bundle (#448): the register step\n * collects exactly what the schema defines. Other steps are untouched.\n */\nfunction applyUseCaseToFlow(\n flow: Record<string, unknown>,\n useCase: string,\n): Record<string, unknown> {\n const fields = [...useCaseFields(useCase)];\n const steps = (flow.steps as Array<Record<string, unknown>>).map((step) =>\n step.name === \"register\" ? { ...step, fields } : step,\n );\n return { ...flow, steps };\n}\n\nexport type DefaultConfigRenderOptions = {\n builtinSchemaBase?: string;\n userSchemaUrl?: string;\n /** Which flow/auth bundle to render; defaults to {@link DEFAULT_SETUP_PRESET}. */\n preset?: string;\n /** Which field set to collect; defaults to {@link DEFAULT_SETUP_USE_CASE}. */\n useCase?: string;\n};\n\nexport function defaultHumanUserSchemaUrl(\n builtinSchemaBase = DEFAULT_BUILTIN_SCHEMA_BASE,\n): string {\n return `${trimTrailingSlash(builtinSchemaBase)}/default-human-user.json`;\n}\n\nexport function getDefaultHumanUserSchema(\n options: DefaultConfigRenderOptions = {},\n): CreateSchemaBody {\n const builtinSchemaBase = trimTrailingSlash(\n options.builtinSchemaBase ?? DEFAULT_BUILTIN_SCHEMA_BASE,\n );\n const rendered = renderTemplate(presetTemplates(options.preset ?? DEFAULT_SETUP_PRESET).schema, {\n SERVER_URL: builtinSchemaBase,\n USER_SCHEMA_URL: options.userSchemaUrl ?? defaultHumanUserSchemaUrl(builtinSchemaBase),\n }) as Record<string, unknown>;\n return applyUseCaseToSchema(\n rendered,\n options.useCase ?? DEFAULT_SETUP_USE_CASE,\n ) as CreateSchemaBody;\n}\n\nexport function getDefaultLoginFlow(\n options: DefaultConfigRenderOptions = {},\n): CreateFlowDefinitionBodyFlowDefinition {\n const builtinSchemaBase = trimTrailingSlash(\n options.builtinSchemaBase ?? DEFAULT_BUILTIN_SCHEMA_BASE,\n );\n const rendered = renderTemplate(presetTemplates(options.preset ?? DEFAULT_SETUP_PRESET).flow, {\n SERVER_URL: builtinSchemaBase,\n USER_SCHEMA_URL: options.userSchemaUrl ?? defaultHumanUserSchemaUrl(builtinSchemaBase),\n }) as Record<string, unknown>;\n return applyUseCaseToFlow(\n rendered,\n options.useCase ?? DEFAULT_SETUP_USE_CASE,\n ) as CreateFlowDefinitionBodyFlowDefinition;\n}\n\nfunction renderTemplate(value: unknown, replacements: Record<string, string>): unknown {\n if (Array.isArray(value)) {\n return value.map((item) => renderTemplate(item, replacements));\n }\n if (value !== null && typeof value === \"object\") {\n return Object.fromEntries(\n Object.entries(value).map(([key, item]) => [key, renderTemplate(item, replacements)]),\n );\n }\n if (typeof value === \"string\") {\n return value.replaceAll(/\\$\\{([A-Z_]+)\\}/g, (match, name: string) => {\n return replacements[name] ?? match;\n });\n }\n return value;\n}\n\nfunction trimTrailingSlash(value: string): string {\n let trimmed = value;\n while (trimmed.endsWith(\"/\")) {\n trimmed = trimmed.slice(0, -1);\n }\n return trimmed;\n}\n"],"mappings":"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"}
|
package/dist/defaults.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { _ as brandingReadmeContent, a as DEFAULT_BUILTIN_SCHEMA_BASE, c as DEFAULT_SCHEMA_CONFIG_PATH, d as SETUP_PRESETS, f as SETUP_USE_CASES, g as getDefaultLoginFlow, h as getDefaultHumanUserSchema, i as DEFAULT_BRANDING_TEMPLATE_PATH, l as DEFAULT_SETUP_PRESET, m as getDefaultBrandingConfig, n as DEFAULT_BRANDING_CONFIG_PATH, o as DEFAULT_FLOW_CONFIG_PATH, p as defaultHumanUserSchemaUrl, r as DEFAULT_BRANDING_DESIGN, s as DEFAULT_FLOW_SCHEMA_URI, t as BRANDING_DESIGNS, u as DEFAULT_SETUP_USE_CASE, v as flowsReadmeContent, y as schemasReadmeContent } from "./defaults-
|
|
1
|
+
import { _ as brandingReadmeContent, a as DEFAULT_BUILTIN_SCHEMA_BASE, c as DEFAULT_SCHEMA_CONFIG_PATH, d as SETUP_PRESETS, f as SETUP_USE_CASES, g as getDefaultLoginFlow, h as getDefaultHumanUserSchema, i as DEFAULT_BRANDING_TEMPLATE_PATH, l as DEFAULT_SETUP_PRESET, m as getDefaultBrandingConfig, n as DEFAULT_BRANDING_CONFIG_PATH, o as DEFAULT_FLOW_CONFIG_PATH, p as defaultHumanUserSchemaUrl, r as DEFAULT_BRANDING_DESIGN, s as DEFAULT_FLOW_SCHEMA_URI, t as BRANDING_DESIGNS, u as DEFAULT_SETUP_USE_CASE, v as flowsReadmeContent, y as schemasReadmeContent } from "./defaults-eiGHyI5Y.mjs";
|
|
2
2
|
export { BRANDING_DESIGNS, DEFAULT_BRANDING_CONFIG_PATH, DEFAULT_BRANDING_DESIGN, DEFAULT_BRANDING_TEMPLATE_PATH, DEFAULT_BUILTIN_SCHEMA_BASE, DEFAULT_FLOW_CONFIG_PATH, DEFAULT_FLOW_SCHEMA_URI, DEFAULT_SCHEMA_CONFIG_PATH, DEFAULT_SETUP_PRESET, DEFAULT_SETUP_USE_CASE, SETUP_PRESETS, SETUP_USE_CASES, brandingReadmeContent, defaultHumanUserSchemaUrl, flowsReadmeContent, getDefaultBrandingConfig, getDefaultHumanUserSchema, getDefaultLoginFlow, schemasReadmeContent };
|
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { isCanonicalLoopbackHttpUrl } from "./branding-url.mjs";
|
|
1
2
|
import { C as flowsReadmeContent, S as brandingReadmeContent, _ as SetupUseCase, a as DEFAULT_BRANDING_TEMPLATE_PATH, b as getDefaultHumanUserSchema, c as DEFAULT_FLOW_SCHEMA_URI, d as DEFAULT_SETUP_USE_CASE, f as DefaultBrandingConfig, g as SetupPreset, h as SETUP_USE_CASES, i as DEFAULT_BRANDING_DESIGN, l as DEFAULT_SCHEMA_CONFIG_PATH, m as SETUP_PRESETS, n as BrandingDesign, o as DEFAULT_BUILTIN_SCHEMA_BASE, p as DefaultConfigRenderOptions, r as DEFAULT_BRANDING_CONFIG_PATH, s as DEFAULT_FLOW_CONFIG_PATH, t as BRANDING_DESIGNS, u as DEFAULT_SETUP_PRESET, v as defaultHumanUserSchemaUrl, w as schemasReadmeContent, x as getDefaultLoginFlow, y as getDefaultBrandingConfig } from "./defaults-Bh4_xVbh.mjs";
|
|
2
3
|
import { BRANDING_FILE_SCHEMA_REF, FLOW_FILE_SCHEMA_REF, META_SCHEMA_DIR, MetaSchemaFile, metaSchemaFiles } from "./meta-schemas.mjs";
|
|
3
4
|
import { USER_PROPERTY_DEFAULTS, normalizeFlowBody, normalizeSchemaBody } from "./normalize.mjs";
|
|
4
5
|
import { brandingConfigSchema, brandingWireSchema, createFlowDefinitionRequestSchema, flowConfigSchema, schemaConfigSchema } from "./schemas.mjs";
|
|
5
6
|
import { BANNED_TEMPLATE_PATTERNS, MANDATORY_GATES_TAG, MAX_TEMPLATE_BYTES, TEMPLATE_TAGS, TEMPLATE_VALIDATION_RULES, TemplateValidationIssue, TemplateValidationRuleId, TemplateValidationSeverity, validateLoginTemplate } from "./template.mjs";
|
|
6
7
|
import { FLOW_PURPOSES, FLOW_VALIDATION_RULES, FlowValidationIssue, FlowValidationRuleId, FlowValidationSeverity, PURPOSE_FLIP_TARGETS, RESERVED_OUTCOMES, validateFlowDefinition } from "./validate.mjs";
|
|
7
|
-
export { BANNED_TEMPLATE_PATTERNS, BRANDING_DESIGNS, BRANDING_FILE_SCHEMA_REF, BrandingDesign, DEFAULT_BRANDING_CONFIG_PATH, DEFAULT_BRANDING_DESIGN, DEFAULT_BRANDING_TEMPLATE_PATH, DEFAULT_BUILTIN_SCHEMA_BASE, DEFAULT_FLOW_CONFIG_PATH, DEFAULT_FLOW_SCHEMA_URI, DEFAULT_SCHEMA_CONFIG_PATH, DEFAULT_SETUP_PRESET, DEFAULT_SETUP_USE_CASE, DefaultBrandingConfig, DefaultConfigRenderOptions, FLOW_FILE_SCHEMA_REF, FLOW_PURPOSES, FLOW_VALIDATION_RULES, FlowValidationIssue, FlowValidationRuleId, FlowValidationSeverity, MANDATORY_GATES_TAG, MAX_TEMPLATE_BYTES, META_SCHEMA_DIR, MetaSchemaFile, PURPOSE_FLIP_TARGETS, RESERVED_OUTCOMES, SETUP_PRESETS, SETUP_USE_CASES, SetupPreset, SetupUseCase, TEMPLATE_TAGS, TEMPLATE_VALIDATION_RULES, TemplateValidationIssue, TemplateValidationRuleId, TemplateValidationSeverity, USER_PROPERTY_DEFAULTS, brandingConfigSchema, brandingReadmeContent, brandingWireSchema, createFlowDefinitionRequestSchema, defaultHumanUserSchemaUrl, flowConfigSchema, flowsReadmeContent, getDefaultBrandingConfig, getDefaultHumanUserSchema, getDefaultLoginFlow, metaSchemaFiles, normalizeFlowBody, normalizeSchemaBody, schemaConfigSchema, schemasReadmeContent, validateFlowDefinition, validateLoginTemplate };
|
|
8
|
+
export { BANNED_TEMPLATE_PATTERNS, BRANDING_DESIGNS, BRANDING_FILE_SCHEMA_REF, BrandingDesign, DEFAULT_BRANDING_CONFIG_PATH, DEFAULT_BRANDING_DESIGN, DEFAULT_BRANDING_TEMPLATE_PATH, DEFAULT_BUILTIN_SCHEMA_BASE, DEFAULT_FLOW_CONFIG_PATH, DEFAULT_FLOW_SCHEMA_URI, DEFAULT_SCHEMA_CONFIG_PATH, DEFAULT_SETUP_PRESET, DEFAULT_SETUP_USE_CASE, DefaultBrandingConfig, DefaultConfigRenderOptions, FLOW_FILE_SCHEMA_REF, FLOW_PURPOSES, FLOW_VALIDATION_RULES, FlowValidationIssue, FlowValidationRuleId, FlowValidationSeverity, MANDATORY_GATES_TAG, MAX_TEMPLATE_BYTES, META_SCHEMA_DIR, MetaSchemaFile, PURPOSE_FLIP_TARGETS, RESERVED_OUTCOMES, SETUP_PRESETS, SETUP_USE_CASES, SetupPreset, SetupUseCase, TEMPLATE_TAGS, TEMPLATE_VALIDATION_RULES, TemplateValidationIssue, TemplateValidationRuleId, TemplateValidationSeverity, USER_PROPERTY_DEFAULTS, brandingConfigSchema, brandingReadmeContent, brandingWireSchema, createFlowDefinitionRequestSchema, defaultHumanUserSchemaUrl, flowConfigSchema, flowsReadmeContent, getDefaultBrandingConfig, getDefaultHumanUserSchema, getDefaultLoginFlow, isCanonicalLoopbackHttpUrl, metaSchemaFiles, normalizeFlowBody, normalizeSchemaBody, schemaConfigSchema, schemasReadmeContent, validateFlowDefinition, validateLoginTemplate };
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { i as
|
|
1
|
+
import { isCanonicalLoopbackHttpUrl } from "./branding-url.mjs";
|
|
2
|
+
import { _ as brandingReadmeContent, a as DEFAULT_BUILTIN_SCHEMA_BASE, c as DEFAULT_SCHEMA_CONFIG_PATH, d as SETUP_PRESETS, f as SETUP_USE_CASES, g as getDefaultLoginFlow, h as getDefaultHumanUserSchema, i as DEFAULT_BRANDING_TEMPLATE_PATH, l as DEFAULT_SETUP_PRESET, m as getDefaultBrandingConfig, n as DEFAULT_BRANDING_CONFIG_PATH, o as DEFAULT_FLOW_CONFIG_PATH, p as defaultHumanUserSchemaUrl, r as DEFAULT_BRANDING_DESIGN, s as DEFAULT_FLOW_SCHEMA_URI, t as BRANDING_DESIGNS, u as DEFAULT_SETUP_USE_CASE, v as flowsReadmeContent, y as schemasReadmeContent } from "./defaults-eiGHyI5Y.mjs";
|
|
3
|
+
import { i as metaSchemaFiles, n as FLOW_FILE_SCHEMA_REF, r as META_SCHEMA_DIR, t as BRANDING_FILE_SCHEMA_REF } from "./meta-schemas-CSc18JqO.mjs";
|
|
3
4
|
import { USER_PROPERTY_DEFAULTS, normalizeFlowBody, normalizeSchemaBody } from "./normalize.mjs";
|
|
4
5
|
import { brandingConfigSchema, brandingWireSchema, createFlowDefinitionRequestSchema, flowConfigSchema, schemaConfigSchema } from "./schemas.mjs";
|
|
5
6
|
import { BANNED_TEMPLATE_PATTERNS, MANDATORY_GATES_TAG, MAX_TEMPLATE_BYTES, TEMPLATE_TAGS, TEMPLATE_VALIDATION_RULES, validateLoginTemplate } from "./template.mjs";
|
|
6
7
|
import { FLOW_PURPOSES, FLOW_VALIDATION_RULES, PURPOSE_FLIP_TARGETS, RESERVED_OUTCOMES, validateFlowDefinition } from "./validate.mjs";
|
|
7
|
-
export { BANNED_TEMPLATE_PATTERNS, BRANDING_DESIGNS, BRANDING_FILE_SCHEMA_REF, DEFAULT_BRANDING_CONFIG_PATH, DEFAULT_BRANDING_DESIGN, DEFAULT_BRANDING_TEMPLATE_PATH, DEFAULT_BUILTIN_SCHEMA_BASE, DEFAULT_FLOW_CONFIG_PATH, DEFAULT_FLOW_SCHEMA_URI, DEFAULT_SCHEMA_CONFIG_PATH, DEFAULT_SETUP_PRESET, DEFAULT_SETUP_USE_CASE, FLOW_FILE_SCHEMA_REF, FLOW_PURPOSES, FLOW_VALIDATION_RULES, MANDATORY_GATES_TAG, MAX_TEMPLATE_BYTES, META_SCHEMA_DIR, PURPOSE_FLIP_TARGETS, RESERVED_OUTCOMES, SETUP_PRESETS, SETUP_USE_CASES, TEMPLATE_TAGS, TEMPLATE_VALIDATION_RULES, USER_PROPERTY_DEFAULTS, brandingConfigSchema, brandingReadmeContent, brandingWireSchema, createFlowDefinitionRequestSchema, defaultHumanUserSchemaUrl, flowConfigSchema, flowsReadmeContent, getDefaultBrandingConfig, getDefaultHumanUserSchema, getDefaultLoginFlow, metaSchemaFiles, normalizeFlowBody, normalizeSchemaBody, schemaConfigSchema, schemasReadmeContent, validateFlowDefinition, validateLoginTemplate };
|
|
8
|
+
export { BANNED_TEMPLATE_PATTERNS, BRANDING_DESIGNS, BRANDING_FILE_SCHEMA_REF, DEFAULT_BRANDING_CONFIG_PATH, DEFAULT_BRANDING_DESIGN, DEFAULT_BRANDING_TEMPLATE_PATH, DEFAULT_BUILTIN_SCHEMA_BASE, DEFAULT_FLOW_CONFIG_PATH, DEFAULT_FLOW_SCHEMA_URI, DEFAULT_SCHEMA_CONFIG_PATH, DEFAULT_SETUP_PRESET, DEFAULT_SETUP_USE_CASE, FLOW_FILE_SCHEMA_REF, FLOW_PURPOSES, FLOW_VALIDATION_RULES, MANDATORY_GATES_TAG, MAX_TEMPLATE_BYTES, META_SCHEMA_DIR, PURPOSE_FLIP_TARGETS, RESERVED_OUTCOMES, SETUP_PRESETS, SETUP_USE_CASES, TEMPLATE_TAGS, TEMPLATE_VALIDATION_RULES, USER_PROPERTY_DEFAULTS, brandingConfigSchema, brandingReadmeContent, brandingWireSchema, createFlowDefinitionRequestSchema, defaultHumanUserSchemaUrl, flowConfigSchema, flowsReadmeContent, getDefaultBrandingConfig, getDefaultHumanUserSchema, getDefaultLoginFlow, isCanonicalLoopbackHttpUrl, metaSchemaFiles, normalizeFlowBody, normalizeSchemaBody, schemaConfigSchema, schemasReadmeContent, validateFlowDefinition, validateLoginTemplate };
|
|
@@ -3,18 +3,12 @@ var auth_method_default = {
|
|
|
3
3
|
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
4
4
|
title: "AuthMethod",
|
|
5
5
|
type: "object",
|
|
6
|
-
required: ["enabled"
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
"position": {
|
|
13
|
-
"type": "integer",
|
|
14
|
-
"minimum": 0,
|
|
15
|
-
"description": "The position of the authentication method in the list of supported methods"
|
|
16
|
-
}
|
|
17
|
-
}
|
|
6
|
+
required: ["enabled"],
|
|
7
|
+
additionalProperties: false,
|
|
8
|
+
properties: { "enabled": {
|
|
9
|
+
"type": "boolean",
|
|
10
|
+
"description": "Whether the authentication method is enabled or not"
|
|
11
|
+
} }
|
|
18
12
|
};
|
|
19
13
|
//#endregion
|
|
20
14
|
//#region meta-schemas/auth-methods.json
|
|
@@ -49,7 +43,7 @@ var branding_default = {
|
|
|
49
43
|
"type": "string",
|
|
50
44
|
"enum": ["centered", "split"],
|
|
51
45
|
"default": "centered",
|
|
52
|
-
"description": "
|
|
46
|
+
"description": "Degrade preset (`centered` or `split`) the bundled default template branches on, not the complete design catalog. All named designs (`centered`, `split`, `split-right`, `hero`, `minimal`) ship as templates and map onto one of these two values; switch designs with the `branding eject --design <name>` command instead of editing this field. Custom templates may ignore it; the preset is also used when a template fails component-side validation."
|
|
53
47
|
},
|
|
54
48
|
"liquid_template_file": {
|
|
55
49
|
"type": "string",
|
|
@@ -64,14 +58,14 @@ var branding_default = {
|
|
|
64
58
|
"logo_url": {
|
|
65
59
|
"type": "string",
|
|
66
60
|
"format": "uri",
|
|
67
|
-
"pattern": "^[hH][tT][tT][pP][sS]://",
|
|
68
|
-
"description": "Logo URL (https required)."
|
|
61
|
+
"pattern": "^([hH][tT][tT][pP][sS]://|[hH][tT][tT][pP]://([lL][oO][cC][aA][lL][hH][oO][sS][tT]|127\\.(?:(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\\.){2}(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])|\\[::1\\])(?::0*(?:[0-9]|[1-9][0-9]{1,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5]))?([/?#]|$))",
|
|
62
|
+
"description": "Logo URL (https required; canonical loopback http is allowed for local development and renders only on loopback pages)."
|
|
69
63
|
},
|
|
70
64
|
"hero_url": {
|
|
71
65
|
"type": "string",
|
|
72
66
|
"format": "uri",
|
|
73
|
-
"pattern": "^[hH][tT][tT][pP][sS]://",
|
|
74
|
-
"description": "Hero/background image URL (https required), used by split designs."
|
|
67
|
+
"pattern": "^([hH][tT][tT][pP][sS]://|[hH][tT][tT][pP]://([lL][oO][cC][aA][lL][hH][oO][sS][tT]|127\\.(?:(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])\\.){2}(?:25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])|\\[::1\\])(?::0*(?:[0-9]|[1-9][0-9]{1,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5]))?([/?#]|$))",
|
|
68
|
+
"description": "Hero/background image URL (https required; canonical loopback http is allowed for local development and renders only on loopback pages), used by split designs."
|
|
75
69
|
}
|
|
76
70
|
},
|
|
77
71
|
not: { "required": ["liquid_template", "liquid_template_file"] }
|
|
@@ -341,6 +335,19 @@ var flow_definition_default = {
|
|
|
341
335
|
null
|
|
342
336
|
],
|
|
343
337
|
"description": "How to interpret `target`. - Omitted: transition to a step in the current definition. - `switch`: replace the current flow with the target flow. No return; the current flow is discarded. Typical use: navigating between peer flows like login ↔ register. - `pivot`: push the target flow onto the stack. The current flow is paused; when the target flow completes the engine auto-pops back. Typical use: login → recovery → back to login."
|
|
338
|
+
},
|
|
339
|
+
"purpose": {
|
|
340
|
+
"type": ["string", "null"],
|
|
341
|
+
"enum": [
|
|
342
|
+
"login",
|
|
343
|
+
"register",
|
|
344
|
+
"recovery",
|
|
345
|
+
"profiling",
|
|
346
|
+
"reauth",
|
|
347
|
+
"link_account",
|
|
348
|
+
null
|
|
349
|
+
],
|
|
350
|
+
"description": "Local re-purposing. When set, taking this transition changes the flow's current purpose to this value — the dispatch mode a step's challenges run under — while the flow's original purpose stays pinned. Must be a purpose this definition serves, and `target` must be that purpose's entry step. Mutually exclusive with `action`: a transition either re-purposes within this flow or targets another flow, never both. Example: a \"Sign up\" navigation on the login identifier step (`{ \"target\": \"register\", \"purpose\": \"register\" }`)."
|
|
344
351
|
}
|
|
345
352
|
}
|
|
346
353
|
}
|
|
@@ -369,10 +376,6 @@ var user_property_default = {
|
|
|
369
376
|
"const": "https://json-schema.org/draft/2020-12/schema",
|
|
370
377
|
"description": "The JSON Schema version used for this schema."
|
|
371
378
|
},
|
|
372
|
-
"x-verify": {
|
|
373
|
-
"oneOf": [{ "type": "string" }, { "type": "null" }],
|
|
374
|
-
"description": "The verification method for this property, if applicable"
|
|
375
|
-
},
|
|
376
379
|
"x-unique": {
|
|
377
380
|
"oneOf": [{
|
|
378
381
|
"type": "string",
|
|
@@ -388,20 +391,10 @@ var user_property_default = {
|
|
|
388
391
|
"oneOf": [{ "type": "string" }, { "type": "null" }],
|
|
389
392
|
"description": "The claim name for this property, if applicable"
|
|
390
393
|
},
|
|
391
|
-
"x-
|
|
392
|
-
"type": "boolean",
|
|
393
|
-
"default": true,
|
|
394
|
-
"description": "Whether this property is editable by the user or not"
|
|
395
|
-
},
|
|
396
|
-
"x-sensitive": {
|
|
397
|
-
"type": "boolean",
|
|
398
|
-
"default": false,
|
|
399
|
-
"description": "Whether this property contains sensitive information or not"
|
|
400
|
-
},
|
|
401
|
-
"x-mfa": {
|
|
394
|
+
"x-audit": {
|
|
402
395
|
"type": "boolean",
|
|
403
396
|
"default": false,
|
|
404
|
-
"description": "Whether this property
|
|
397
|
+
"description": "Whether this property's value may appear in audit event payloads. Audit payloads are deny-by-default: a property without this annotation contributes its key but never its value."
|
|
405
398
|
},
|
|
406
399
|
"properties": {
|
|
407
400
|
"type": "object",
|
|
@@ -521,4 +514,4 @@ function metaSchemaFiles() {
|
|
|
521
514
|
//#endregion
|
|
522
515
|
export { metaSchemaFiles as i, FLOW_FILE_SCHEMA_REF as n, META_SCHEMA_DIR as r, BRANDING_FILE_SCHEMA_REF as t };
|
|
523
516
|
|
|
524
|
-
//# sourceMappingURL=meta-schemas-
|
|
517
|
+
//# sourceMappingURL=meta-schemas-CSc18JqO.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"meta-schemas-
|
|
1
|
+
{"version":3,"file":"meta-schemas-CSc18JqO.mjs","names":["flowDefinitionMetaSchema","userSchemaMetaSchema","userPropertyMetaSchema","propertyNameMetaSchema","authMethodsMetaSchema","authMethodMetaSchema","brandingMetaSchema"],"sources":["../meta-schemas/auth-method.json","../meta-schemas/auth-methods.json","../meta-schemas/branding.json","../meta-schemas/flow-definition.json","../meta-schemas/property-name.json","../meta-schemas/user-property.json","../meta-schemas/user-schema.json","../src/meta-schemas.ts"],"sourcesContent":["","","","","","","","/**\n * The dialect meta-schemas `zitadel setup` copies into a project's\n * `.zitadel/meta/` so the flow/schema dialect is machine-readable offline:\n * editors validate flow files against `flow-definition.json` via a relative\n * `$schema` pointer, and agents read the dialect files before authoring\n * edits — no docs crawl, no hosted schema required.\n *\n * The files under `meta-schemas/` are committed copies of\n * `api/openapi/endpoints/schemas/*.json` (the source the server embeds);\n * a drift-audit test keeps them byte-identical in the monorepo.\n */\nimport authMethodMetaSchema from \"../meta-schemas/auth-method.json\" with {\n type: \"json\",\n};\nimport authMethodsMetaSchema from \"../meta-schemas/auth-methods.json\" with {\n type: \"json\",\n};\nimport brandingMetaSchema from \"../meta-schemas/branding.json\" with {\n type: \"json\",\n};\nimport flowDefinitionMetaSchema from \"../meta-schemas/flow-definition.json\" with {\n type: \"json\",\n};\nimport propertyNameMetaSchema from \"../meta-schemas/property-name.json\" with {\n type: \"json\",\n};\nimport userPropertyMetaSchema from \"../meta-schemas/user-property.json\" with {\n type: \"json\",\n};\nimport userSchemaMetaSchema from \"../meta-schemas/user-schema.json\" with {\n type: \"json\",\n};\n\n/** Project-relative directory setup writes the meta-schemas to. */\nexport const META_SCHEMA_DIR = \".zitadel/meta\";\n\n/**\n * The `$schema` value scaffolded flow files carry, relative to\n * `.zitadel/flows/` — resolves to `{@link META_SCHEMA_DIR}/flow-definition.json`.\n */\nexport const FLOW_FILE_SCHEMA_REF = \"../meta/flow-definition.json\";\n\n/**\n * The `$schema` value scaffolded branding files carry, relative to\n * `.zitadel/branding/` — resolves to `{@link META_SCHEMA_DIR}/branding.json`.\n */\nexport const BRANDING_FILE_SCHEMA_REF = \"../meta/branding.json\";\n\nexport type MetaSchemaFile = { name: string; body: object };\n\n/**\n * The dialect files to materialize, in write order. `auth-methods.json` and\n * `auth-method.json` are pulled in by `user-schema.json`'s relative `$ref`s —\n * without them the copied dialect cannot resolve offline.\n */\nexport function metaSchemaFiles(): ReadonlyArray<MetaSchemaFile> {\n return [\n { name: \"flow-definition.json\", body: flowDefinitionMetaSchema as object },\n { name: \"user-schema.json\", body: userSchemaMetaSchema as object },\n { name: \"user-property.json\", body: userPropertyMetaSchema as object },\n { name: \"property-name.json\", body: propertyNameMetaSchema as object },\n { name: \"auth-methods.json\", body: authMethodsMetaSchema as object },\n { name: \"auth-method.json\", body: authMethodMetaSchema as object },\n { name: \"branding.json\", body: brandingMetaSchema as object },\n ];\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AOkCA,MAAa,kBAAkB;;;;;AAM/B,MAAa,uBAAuB;;;;;AAMpC,MAAa,2BAA2B;;;;;;AASxC,SAAgB,kBAAiD;AAC/D,QAAO;EACL;GAAE,MAAM;GAAwB,MAAMA;GAAoC;EAC1E;GAAE,MAAM;GAAoB,MAAMC;GAAgC;EAClE;GAAE,MAAM;GAAsB,MAAMC;GAAkC;EACtE;GAAE,MAAM;GAAsB,MAAMC;GAAkC;EACtE;GAAE,MAAM;GAAqB,MAAMC;GAAiC;EACpE;GAAE,MAAM;GAAoB,MAAMC;GAAgC;EAClE;GAAE,MAAM;GAAiB,MAAMC;GAA8B;EAC9D"}
|
package/dist/meta-schemas.mjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as metaSchemaFiles, n as FLOW_FILE_SCHEMA_REF, r as META_SCHEMA_DIR, t as BRANDING_FILE_SCHEMA_REF } from "./meta-schemas-
|
|
1
|
+
import { i as metaSchemaFiles, n as FLOW_FILE_SCHEMA_REF, r as META_SCHEMA_DIR, t as BRANDING_FILE_SCHEMA_REF } from "./meta-schemas-CSc18JqO.mjs";
|
|
2
2
|
export { BRANDING_FILE_SCHEMA_REF, FLOW_FILE_SCHEMA_REF, META_SCHEMA_DIR, metaSchemaFiles };
|
package/dist/normalize.d.mts
CHANGED
|
@@ -5,21 +5,22 @@
|
|
|
5
5
|
* The sync engine compares `.zitadel/**` files against server responses;
|
|
6
6
|
* the server echoes fields the author never wrote (an empty `audience`
|
|
7
7
|
* on flows) and the meta-schema declares defaults an author may or may
|
|
8
|
-
* not spell out (`x-
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* not spell out (`x-audit` on schema properties). Normalizing both
|
|
9
|
+
* sides before hashing or diffing keeps a one-field edit rendering as a
|
|
10
|
+
* one-field diff.
|
|
11
11
|
*
|
|
12
12
|
* Normalized bodies are for COMPARISON. Never upload them, and never
|
|
13
13
|
* write a normalized schema body to a file: the server stores schema
|
|
14
14
|
* bytes verbatim without materializing meta-schema defaults, so a
|
|
15
|
-
* stripped `"x-
|
|
15
|
+
* stripped `"x-audit": false` would vanish from the next published
|
|
16
16
|
* revision. (Flow write-back may reuse {@link normalizeFlowBody} —
|
|
17
17
|
* everything it strips is pure transport noise.)
|
|
18
18
|
*/
|
|
19
19
|
/**
|
|
20
20
|
* Property-level defaults declared by the user-property meta-schema
|
|
21
21
|
* (`api/openapi/endpoints/schemas/user-property.json`). A property that
|
|
22
|
-
* spells one of these out is semantically identical to one that omits it
|
|
22
|
+
* spells one of these out is semantically identical to one that omits it:
|
|
23
|
+
* audit payloads deny by default.
|
|
23
24
|
*/
|
|
24
25
|
declare const USER_PROPERTY_DEFAULTS: Readonly<Record<string, boolean>>;
|
|
25
26
|
/**
|
|
@@ -34,10 +35,11 @@ declare const USER_PROPERTY_DEFAULTS: Readonly<Record<string, boolean>>;
|
|
|
34
35
|
declare function normalizeFlowBody(body: object): object;
|
|
35
36
|
/**
|
|
36
37
|
* Return a deep copy of a user-schema body with meta-schema property
|
|
37
|
-
* defaults stripped: a property carrying
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
38
|
+
* defaults stripped: a property carrying one of the
|
|
39
|
+
* {@link USER_PROPERTY_DEFAULTS} normalizes to one omitting it. Only
|
|
40
|
+
* exact default values are removed; `$id` and every other field pass
|
|
41
|
+
* through untouched. Nested `properties` are descended into, so a leaf
|
|
42
|
+
* of an object property normalizes the same way a top-level one does.
|
|
41
43
|
*/
|
|
42
44
|
declare function normalizeSchemaBody(body: object): object;
|
|
43
45
|
//#endregion
|
package/dist/normalize.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"normalize.d.mts","names":[],"sources":["../src/normalize.ts"],"mappings":";;
|
|
1
|
+
{"version":3,"file":"normalize.d.mts","names":[],"sources":["../src/normalize.ts"],"mappings":";;AAwBA;;;;;AAwCA;;;;;AAoBA;;;;;;;;;;;;cA5Da,sBAAA,EAAwB,QAAA,CAAS,MAAA;;;;;;;;;;iBAwC9B,iBAAA,CAAkB,IAAA;;;;;;;;;iBAoBlB,mBAAA,CAAoB,IAAA"}
|
package/dist/normalize.mjs
CHANGED
|
@@ -5,27 +5,24 @@
|
|
|
5
5
|
* The sync engine compares `.zitadel/**` files against server responses;
|
|
6
6
|
* the server echoes fields the author never wrote (an empty `audience`
|
|
7
7
|
* on flows) and the meta-schema declares defaults an author may or may
|
|
8
|
-
* not spell out (`x-
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* not spell out (`x-audit` on schema properties). Normalizing both
|
|
9
|
+
* sides before hashing or diffing keeps a one-field edit rendering as a
|
|
10
|
+
* one-field diff.
|
|
11
11
|
*
|
|
12
12
|
* Normalized bodies are for COMPARISON. Never upload them, and never
|
|
13
13
|
* write a normalized schema body to a file: the server stores schema
|
|
14
14
|
* bytes verbatim without materializing meta-schema defaults, so a
|
|
15
|
-
* stripped `"x-
|
|
15
|
+
* stripped `"x-audit": false` would vanish from the next published
|
|
16
16
|
* revision. (Flow write-back may reuse {@link normalizeFlowBody} —
|
|
17
17
|
* everything it strips is pure transport noise.)
|
|
18
18
|
*/
|
|
19
19
|
/**
|
|
20
20
|
* Property-level defaults declared by the user-property meta-schema
|
|
21
21
|
* (`api/openapi/endpoints/schemas/user-property.json`). A property that
|
|
22
|
-
* spells one of these out is semantically identical to one that omits it
|
|
22
|
+
* spells one of these out is semantically identical to one that omits it:
|
|
23
|
+
* audit payloads deny by default.
|
|
23
24
|
*/
|
|
24
|
-
const USER_PROPERTY_DEFAULTS = {
|
|
25
|
-
"x-editable": true,
|
|
26
|
-
"x-sensitive": false,
|
|
27
|
-
"x-mfa": false
|
|
28
|
-
};
|
|
25
|
+
const USER_PROPERTY_DEFAULTS = { "x-audit": false };
|
|
29
26
|
/**
|
|
30
27
|
* Keys of the flow-definition detail envelope. `fetch` in the flow syncer
|
|
31
28
|
* already unwraps the envelope; stripping them here as well makes the
|
|
@@ -68,19 +65,29 @@ function normalizeFlowBody(body) {
|
|
|
68
65
|
}
|
|
69
66
|
/**
|
|
70
67
|
* Return a deep copy of a user-schema body with meta-schema property
|
|
71
|
-
* defaults stripped: a property carrying
|
|
72
|
-
*
|
|
73
|
-
*
|
|
74
|
-
*
|
|
68
|
+
* defaults stripped: a property carrying one of the
|
|
69
|
+
* {@link USER_PROPERTY_DEFAULTS} normalizes to one omitting it. Only
|
|
70
|
+
* exact default values are removed; `$id` and every other field pass
|
|
71
|
+
* through untouched. Nested `properties` are descended into, so a leaf
|
|
72
|
+
* of an object property normalizes the same way a top-level one does.
|
|
75
73
|
*/
|
|
76
74
|
function normalizeSchemaBody(body) {
|
|
77
75
|
const result = structuredClone(body);
|
|
78
|
-
|
|
79
|
-
|
|
76
|
+
stripPropertyDefaults(result);
|
|
77
|
+
return result;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Strip {@link USER_PROPERTY_DEFAULTS} from every property of an object
|
|
81
|
+
* schema, descending into nested `properties` so a leaf of an object
|
|
82
|
+
* property normalizes the same way a top-level one does.
|
|
83
|
+
*/
|
|
84
|
+
function stripPropertyDefaults(schema) {
|
|
85
|
+
if (!isPlainObject(schema.properties)) return;
|
|
86
|
+
for (const property of Object.values(schema.properties)) {
|
|
80
87
|
if (!isPlainObject(property)) continue;
|
|
81
88
|
for (const [key, defaultValue] of Object.entries(USER_PROPERTY_DEFAULTS)) if (property[key] === defaultValue) delete property[key];
|
|
89
|
+
stripPropertyDefaults(property);
|
|
82
90
|
}
|
|
83
|
-
return result;
|
|
84
91
|
}
|
|
85
92
|
//#endregion
|
|
86
93
|
export { USER_PROPERTY_DEFAULTS, normalizeFlowBody, normalizeSchemaBody };
|
package/dist/normalize.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"normalize.mjs","names":[],"sources":["../src/normalize.ts"],"sourcesContent":["/**\n * Canonical-form normalizers for the two repo-config resource kinds.\n *\n * The sync engine compares `.zitadel/**` files against server responses;\n * the server echoes fields the author never wrote (an empty `audience`\n * on flows) and the meta-schema declares defaults an author may or may\n * not spell out (`x-
|
|
1
|
+
{"version":3,"file":"normalize.mjs","names":[],"sources":["../src/normalize.ts"],"sourcesContent":["/**\n * Canonical-form normalizers for the two repo-config resource kinds.\n *\n * The sync engine compares `.zitadel/**` files against server responses;\n * the server echoes fields the author never wrote (an empty `audience`\n * on flows) and the meta-schema declares defaults an author may or may\n * not spell out (`x-audit` on schema properties). Normalizing both\n * sides before hashing or diffing keeps a one-field edit rendering as a\n * one-field diff.\n *\n * Normalized bodies are for COMPARISON. Never upload them, and never\n * write a normalized schema body to a file: the server stores schema\n * bytes verbatim without materializing meta-schema defaults, so a\n * stripped `\"x-audit\": false` would vanish from the next published\n * revision. (Flow write-back may reuse {@link normalizeFlowBody} —\n * everything it strips is pure transport noise.)\n */\n\n/**\n * Property-level defaults declared by the user-property meta-schema\n * (`api/openapi/endpoints/schemas/user-property.json`). A property that\n * spells one of these out is semantically identical to one that omits it:\n * audit payloads deny by default.\n */\nexport const USER_PROPERTY_DEFAULTS: Readonly<Record<string, boolean>> = {\n \"x-audit\": false,\n};\n\n/**\n * Keys of the flow-definition detail envelope. `fetch` in the flow syncer\n * already unwraps the envelope; stripping them here as well makes the\n * normalizer safe on raw detail responses.\n */\nconst FLOW_ENVELOPE_KEYS = [\"id\", \"project_id\", \"schema_uri\", \"created_at\", \"updated_at\"];\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * An `audience` counts as empty when it scopes nothing: no keys, or only\n * `team_ids`/`app_ids` that are null or empty arrays. Unknown keys keep\n * the audience — better a noisy diff than a silently dropped scope.\n */\nfunction isEmptyAudience(value: unknown): boolean {\n if (!isPlainObject(value)) {\n return false;\n }\n return Object.entries(value).every(\n ([key, entry]) =>\n (key === \"team_ids\" || key === \"app_ids\") &&\n (entry === null || entry === undefined || (Array.isArray(entry) && entry.length === 0)),\n );\n}\n\n/**\n * Return a deep copy of a bare flow-definition body with server-echoed\n * noise removed: an empty `audience` and any detail-envelope keys. A\n * top-level `$schema` is stripped too — it is a local editor affordance\n * (scaffolded flow files point it at `.zitadel/meta/flow-definition.json`),\n * never part of the resource: the server skips it on decode and omits it\n * from responses, so comparing with it would read every scaffolded file\n * as permanently diverged.\n */\nexport function normalizeFlowBody(body: object): object {\n const result = structuredClone(body) as Record<string, unknown>;\n for (const key of FLOW_ENVELOPE_KEYS) {\n delete result[key];\n }\n delete result.$schema;\n if (\"audience\" in result && isEmptyAudience(result.audience)) {\n delete result.audience;\n }\n return result;\n}\n\n/**\n * Return a deep copy of a user-schema body with meta-schema property\n * defaults stripped: a property carrying one of the\n * {@link USER_PROPERTY_DEFAULTS} normalizes to one omitting it. Only\n * exact default values are removed; `$id` and every other field pass\n * through untouched. Nested `properties` are descended into, so a leaf\n * of an object property normalizes the same way a top-level one does.\n */\nexport function normalizeSchemaBody(body: object): object {\n const result = structuredClone(body) as Record<string, unknown>;\n stripPropertyDefaults(result);\n return result;\n}\n\n/**\n * Strip {@link USER_PROPERTY_DEFAULTS} from every property of an object\n * schema, descending into nested `properties` so a leaf of an object\n * property normalizes the same way a top-level one does.\n */\nfunction stripPropertyDefaults(schema: Record<string, unknown>): void {\n if (!isPlainObject(schema.properties)) {\n return;\n }\n for (const property of Object.values(schema.properties)) {\n if (!isPlainObject(property)) {\n continue;\n }\n for (const [key, defaultValue] of Object.entries(USER_PROPERTY_DEFAULTS)) {\n if (property[key] === defaultValue) {\n delete property[key];\n }\n }\n stripPropertyDefaults(property);\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAwBA,MAAa,yBAA4D,EACvE,WAAW,OACZ;;;;;;AAOD,MAAM,qBAAqB;CAAC;CAAM;CAAc;CAAc;CAAc;CAAa;AAEzF,SAAS,cAAc,OAAkD;AACvE,QAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,MAAM;;;;;;;AAQ7E,SAAS,gBAAgB,OAAyB;AAChD,KAAI,CAAC,cAAc,MAAM,CACvB,QAAO;AAET,QAAO,OAAO,QAAQ,MAAM,CAAC,OAC1B,CAAC,KAAK,YACJ,QAAQ,cAAc,QAAQ,eAC9B,UAAU,QAAQ,UAAU,KAAA,KAAc,MAAM,QAAQ,MAAM,IAAI,MAAM,WAAW,GACvF;;;;;;;;;;;AAYH,SAAgB,kBAAkB,MAAsB;CACtD,MAAM,SAAS,gBAAgB,KAAK;AACpC,MAAK,MAAM,OAAO,mBAChB,QAAO,OAAO;AAEhB,QAAO,OAAO;AACd,KAAI,cAAc,UAAU,gBAAgB,OAAO,SAAS,CAC1D,QAAO,OAAO;AAEhB,QAAO;;;;;;;;;;AAWT,SAAgB,oBAAoB,MAAsB;CACxD,MAAM,SAAS,gBAAgB,KAAK;AACpC,uBAAsB,OAAO;AAC7B,QAAO;;;;;;;AAQT,SAAS,sBAAsB,QAAuC;AACpE,KAAI,CAAC,cAAc,OAAO,WAAW,CACnC;AAEF,MAAK,MAAM,YAAY,OAAO,OAAO,OAAO,WAAW,EAAE;AACvD,MAAI,CAAC,cAAc,SAAS,CAC1B;AAEF,OAAK,MAAM,CAAC,KAAK,iBAAiB,OAAO,QAAQ,uBAAuB,CACtE,KAAI,SAAS,SAAS,aACpB,QAAO,SAAS;AAGpB,wBAAsB,SAAS"}
|
package/dist/schemas.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schemas.d.mts","names":[],"sources":["../src/schemas.ts"],"mappings":";;;
|
|
1
|
+
{"version":3,"file":"schemas.d.mts","names":[],"sources":["../src/schemas.ts"],"mappings":";;;cASa,kBAAA;AAAA,cACA,gBAAA;AAAA,cACA,iCAAA;;cAGA,kBAAA;;;AAJb;;;;cAYa,oBAAA,EAAoB,CAAA,CAAA,SAAA;EAAA;GAuC7B,CAAA,CAAA,IAAA,CAAA,OAAA"}
|
package/dist/schemas.mjs
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { isCanonicalLoopbackHttpUrl } from "./branding-url.mjs";
|
|
2
2
|
import { CreateBrandingBody, CreateFlowDefinitionBody, CreateSchemaBody } from "@zitadel/api/generated/endpoints/zitadelNextGen.zod";
|
|
3
|
+
import { z } from "zod";
|
|
3
4
|
//#region src/schemas.ts
|
|
4
5
|
const schemaConfigSchema = CreateSchemaBody;
|
|
5
6
|
const flowConfigSchema = CreateFlowDefinitionBody.shape.flow_definition;
|
|
@@ -27,10 +28,10 @@ const brandingConfigSchema = z.strictObject({
|
|
|
27
28
|
code: "custom",
|
|
28
29
|
message: "font_url is not writable yet (tenant font delivery needs a safe design, see ADR 040); load fonts from the embedding page instead."
|
|
29
30
|
});
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
validateBrandingAssetUrl(value.logo_url, "logo_url", ctx);
|
|
32
|
+
validateBrandingAssetUrl(value.hero_url, "hero_url", ctx);
|
|
32
33
|
});
|
|
33
|
-
function
|
|
34
|
+
function validateBrandingAssetUrl(value, field, ctx) {
|
|
34
35
|
if (value === void 0 || value === "") return;
|
|
35
36
|
if (/[\s\\]/.test(value)) {
|
|
36
37
|
ctx.addIssue({
|
|
@@ -39,7 +40,7 @@ function requireHttpsUrl(value, field, ctx) {
|
|
|
39
40
|
});
|
|
40
41
|
return;
|
|
41
42
|
}
|
|
42
|
-
if (!/^https
|
|
43
|
+
if (!/^https?:\/\//i.test(value)) {
|
|
43
44
|
ctx.addIssue({
|
|
44
45
|
code: "custom",
|
|
45
46
|
message: `${field} must be an absolute https URL.`
|
|
@@ -56,9 +57,10 @@ function requireHttpsUrl(value, field, ctx) {
|
|
|
56
57
|
});
|
|
57
58
|
return;
|
|
58
59
|
}
|
|
60
|
+
if (parsed.protocol === "http:" && isCanonicalLoopbackHttpUrl(value)) return;
|
|
59
61
|
if (parsed.protocol !== "https:" || parsed.host === "") ctx.addIssue({
|
|
60
62
|
code: "custom",
|
|
61
|
-
message: `${field} must be an absolute https URL.`
|
|
63
|
+
message: `${field} must be an absolute https URL (http is allowed for canonical loopback development hosts only).`
|
|
62
64
|
});
|
|
63
65
|
}
|
|
64
66
|
//#endregion
|
package/dist/schemas.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schemas.mjs","names":[],"sources":["../src/schemas.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"file":"schemas.mjs","names":[],"sources":["../src/schemas.ts"],"sourcesContent":["import {\n CreateBrandingBody,\n CreateFlowDefinitionBody,\n CreateSchemaBody,\n} from \"@zitadel/api/generated/endpoints/zitadelNextGen.zod\";\nimport { z } from \"zod\";\n\nimport { isCanonicalLoopbackHttpUrl } from \"./branding-url.js\";\n\nexport const schemaConfigSchema = CreateSchemaBody;\nexport const flowConfigSchema = CreateFlowDefinitionBody.shape.flow_definition;\nexport const createFlowDefinitionRequestSchema = CreateFlowDefinitionBody;\n\n/** The wire shape of a branding revision (`POST /branding` request body). */\nexport const brandingWireSchema = CreateBrandingBody;\n\n/**\n * The local `.zitadel/branding/*.json` dialect: the wire shape plus\n * `liquid_template_file`, a descriptor-relative path the CLI inlines into\n * `liquid_template` when publishing. Exactly one of the two template carriers\n * may be present (the meta-schema `branding.json` mirrors this).\n */\nexport const brandingConfigSchema = z\n .strictObject({\n // Strict, unlike the generated wire schema: a typo like `hero_urll`\n // must fail plan, not silently pass, get ignored by the server, and\n // vanish on canonical write-back. The editor meta-schema already\n // rejects unknown keys; the CLI gate has to agree.\n ...CreateBrandingBody.shape,\n // Raw strings instead of the generated uri fields: those trim and\n // normalize before refinement runs, hiding exactly the forms the wire\n // body still carries verbatim and Go's url.Parse rejects.\n logo_url: z.string().optional(),\n hero_url: z.string().optional(),\n $schema: z.string().optional(),\n liquid_template_file: z.string().min(1).optional(),\n })\n .superRefine((value, ctx) => {\n if (value.liquid_template !== undefined && value.liquid_template_file !== undefined) {\n ctx.addIssue({\n code: \"custom\",\n message: \"Use either liquid_template_file or an inline liquid_template, not both.\",\n });\n }\n // font_url is read-only in v1: the login component loads it as a\n // document-level stylesheet (shadow-scoped @font-face never registers\n // faces), which would give branding.write arbitrary CSS over the embedding\n // page. The server rejects it too; safe delivery is an ADR 040 follow-up.\n if (value.font_url !== undefined) {\n ctx.addIssue({\n code: \"custom\",\n message:\n \"font_url is not writable yet (tenant font delivery needs a safe design, see ADR 040); load fonts from the embedding page instead.\",\n });\n }\n // Mirror the server's asset URL gate (validateBrandingAssetURL in\n // internal/domain/branding_validator.go) so plan rejects what apply would.\n // Apply mutates schemas and flows before branding, so a late 400 here would\n // leave a half-applied run.\n validateBrandingAssetUrl(value.logo_url, \"logo_url\", ctx);\n validateBrandingAssetUrl(value.hero_url, \"hero_url\", ctx);\n });\n\nfunction validateBrandingAssetUrl(\n value: string | undefined,\n field: \"logo_url\" | \"hero_url\",\n ctx: z.RefinementCtx,\n): void {\n if (value === undefined || value === \"\") {\n return;\n }\n // Stricter-or-equal than the Go gate (validateBrandingAssetURL): the WHATWG\n // parser forgives what Go's url.Parse rejects — `https:example.com`,\n // backslashes, and whitespace all get silently normalized. plan must never\n // accept what apply would reject (the reverse is harmless), so reject the\n // raw forms before parsing.\n if (/[\\s\\\\]/.test(value)) {\n ctx.addIssue({ code: \"custom\", message: `${field} is not a valid URL.` });\n return;\n }\n if (!/^https?:\\/\\//i.test(value)) {\n ctx.addIssue({ code: \"custom\", message: `${field} must be an absolute https URL.` });\n return;\n }\n let parsed: URL;\n try {\n parsed = new URL(value);\n } catch {\n ctx.addIssue({ code: \"custom\", message: `${field} is not a valid URL.` });\n return;\n }\n // Loopback HTTP is the dev-posture carve-out (assets served from the app's\n // own dev server). Check the raw URL so WHATWG normalisation cannot make\n // plan accept a host spelling that the Go save gate rejects.\n if (parsed.protocol === \"http:\" && isCanonicalLoopbackHttpUrl(value)) {\n return;\n }\n if (parsed.protocol !== \"https:\" || parsed.host === \"\") {\n ctx.addIssue({\n code: \"custom\",\n message: `${field} must be an absolute https URL (http is allowed for canonical loopback development hosts only).`,\n });\n }\n}\n"],"mappings":";;;;AASA,MAAa,qBAAqB;AAClC,MAAa,mBAAmB,yBAAyB,MAAM;AAC/D,MAAa,oCAAoC;;AAGjD,MAAa,qBAAqB;;;;;;;AAQlC,MAAa,uBAAuB,EACjC,aAAa;CAKZ,GAAG,mBAAmB;CAItB,UAAU,EAAE,QAAQ,CAAC,UAAU;CAC/B,UAAU,EAAE,QAAQ,CAAC,UAAU;CAC/B,SAAS,EAAE,QAAQ,CAAC,UAAU;CAC9B,sBAAsB,EAAE,QAAQ,CAAC,IAAI,EAAE,CAAC,UAAU;CACnD,CAAC,CACD,aAAa,OAAO,QAAQ;AAC3B,KAAI,MAAM,oBAAoB,KAAA,KAAa,MAAM,yBAAyB,KAAA,EACxE,KAAI,SAAS;EACX,MAAM;EACN,SAAS;EACV,CAAC;AAMJ,KAAI,MAAM,aAAa,KAAA,EACrB,KAAI,SAAS;EACX,MAAM;EACN,SACE;EACH,CAAC;AAMJ,0BAAyB,MAAM,UAAU,YAAY,IAAI;AACzD,0BAAyB,MAAM,UAAU,YAAY,IAAI;EACzD;AAEJ,SAAS,yBACP,OACA,OACA,KACM;AACN,KAAI,UAAU,KAAA,KAAa,UAAU,GACnC;AAOF,KAAI,SAAS,KAAK,MAAM,EAAE;AACxB,MAAI,SAAS;GAAE,MAAM;GAAU,SAAS,GAAG,MAAM;GAAuB,CAAC;AACzE;;AAEF,KAAI,CAAC,gBAAgB,KAAK,MAAM,EAAE;AAChC,MAAI,SAAS;GAAE,MAAM;GAAU,SAAS,GAAG,MAAM;GAAkC,CAAC;AACpF;;CAEF,IAAI;AACJ,KAAI;AACF,WAAS,IAAI,IAAI,MAAM;SACjB;AACN,MAAI,SAAS;GAAE,MAAM;GAAU,SAAS,GAAG,MAAM;GAAuB,CAAC;AACzE;;AAKF,KAAI,OAAO,aAAa,WAAW,2BAA2B,MAAM,CAClE;AAEF,KAAI,OAAO,aAAa,YAAY,OAAO,SAAS,GAClD,KAAI,SAAS;EACX,MAAM;EACN,SAAS,GAAG,MAAM;EACnB,CAAC"}
|