@zitadel/config 1.0.0-alpha.24 → 1.0.0-alpha.25

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 (55) hide show
  1. package/defaults/branding/centered/login.liquid +31 -11
  2. package/defaults/branding/minimal/login.liquid +30 -10
  3. package/dist/branding-contrast.d.mts +28 -21
  4. package/dist/branding-contrast.d.mts.map +1 -1
  5. package/dist/branding-contrast.mjs +1 -1
  6. package/dist/branding-contrast.mjs.map +1 -1
  7. package/dist/branding-url.d.mts +1 -2
  8. package/dist/branding-url.d.mts.map +1 -1
  9. package/dist/branding-url.mjs.map +1 -1
  10. package/dist/css-color.d.mts +5 -10
  11. package/dist/css-color.d.mts.map +1 -1
  12. package/dist/css-color.mjs +1 -1
  13. package/dist/css-color.mjs.map +1 -1
  14. package/dist/{defaults-BnWXllBk.d.mts → defaults-BtKIcWxW.d.mts} +11 -7
  15. package/dist/defaults-BtKIcWxW.d.mts.map +1 -0
  16. package/dist/{defaults-BnRHT7RQ.mjs → defaults-COLBFU3S.mjs} +1 -1
  17. package/dist/defaults-COLBFU3S.mjs.map +1 -0
  18. package/dist/defaults.d.mts +1 -1
  19. package/dist/defaults.mjs +1 -1
  20. package/dist/idp/index.d.mts +2 -0
  21. package/dist/idp/index.mjs +2 -0
  22. package/dist/idp-ByzXQN85.mjs +207 -0
  23. package/dist/idp-ByzXQN85.mjs.map +1 -0
  24. package/dist/idp-connection-CHxGm1Wr.mjs +324 -0
  25. package/dist/idp-connection-CHxGm1Wr.mjs.map +1 -0
  26. package/dist/index-Cuxu-zQD.d.mts +210 -0
  27. package/dist/index-Cuxu-zQD.d.mts.map +1 -0
  28. package/dist/index.d.mts +4 -3
  29. package/dist/index.mjs +5 -4
  30. package/dist/{meta-schemas-K8f7YZYz.mjs → meta-schemas-C03zgFux.mjs} +31 -328
  31. package/dist/meta-schemas-C03zgFux.mjs.map +1 -0
  32. package/dist/meta-schemas.d.mts +5 -6
  33. package/dist/meta-schemas.d.mts.map +1 -1
  34. package/dist/meta-schemas.mjs +1 -1
  35. package/dist/normalize.d.mts +3 -4
  36. package/dist/normalize.d.mts.map +1 -1
  37. package/dist/normalize.mjs.map +1 -1
  38. package/dist/{schemas-7oNU25Qz.mjs → schemas-CUU4Rf8J.mjs} +11 -4
  39. package/dist/schemas-CUU4Rf8J.mjs.map +1 -0
  40. package/dist/schemas.d.mts +361 -9
  41. package/dist/schemas.d.mts.map +1 -1
  42. package/dist/schemas.mjs +2 -2
  43. package/dist/template.d.mts +9 -10
  44. package/dist/template.d.mts.map +1 -1
  45. package/dist/template.mjs.map +1 -1
  46. package/dist/validate.d.mts +15 -13
  47. package/dist/validate.d.mts.map +1 -1
  48. package/dist/validate.mjs +28 -18
  49. package/dist/validate.mjs.map +1 -1
  50. package/meta-schemas/flow-definition.json +81 -6
  51. package/package.json +12 -6
  52. package/dist/defaults-BnRHT7RQ.mjs.map +0 -1
  53. package/dist/defaults-BnWXllBk.d.mts.map +0 -1
  54. package/dist/meta-schemas-K8f7YZYz.mjs.map +0 -1
  55. package/dist/schemas-7oNU25Qz.mjs.map +0 -1
@@ -1,3 +1,4 @@
1
+ import { t as idp_connection_default } from "./idp-connection-CHxGm1Wr.mjs";
1
2
  //#region meta-schemas/auth-method.json
2
3
  var auth_method_default = {
3
4
  $comment: "Code generated by scripts/generate-meta-schemas.ts; DO NOT EDIT.",
@@ -402,7 +403,7 @@ var flow_definition_default = {
402
403
  {
403
404
  "required": ["sso_providers"],
404
405
  "properties": { "sso_providers": { "minItems": 1 } },
405
- "anyOf": [{ "not": { "required": ["transitions"] } }, { "properties": { "transitions": { "not": { "required": ["callback"] } } } }]
406
+ "anyOf": [{ "not": { "required": ["transitions"] } }, { "properties": { "transitions": { "not": { "required": ["sso_authenticated"] } } } }]
406
407
  },
407
408
  {
408
409
  "required": ["complete"],
@@ -436,8 +437,30 @@ var flow_definition_default = {
436
437
  "actions": { "maxItems": 0 },
437
438
  "sso_providers": { "maxItems": 0 },
438
439
  "gates": { "maxProperties": 0 },
439
- "transitions": { "not": { "required": ["callback"] } }
440
+ "transitions": { "not": { "required": ["sso_authenticated"] } }
440
441
  }
442
+ },
443
+ {
444
+ "required": ["transitions"],
445
+ "properties": { "transitions": { "anyOf": [{
446
+ "required": ["sso_authenticated"],
447
+ "properties": { "sso_authenticated": { "anyOf": [{
448
+ "required": ["purpose"],
449
+ "properties": { "purpose": { "type": "string" } }
450
+ }, {
451
+ "required": ["action"],
452
+ "properties": { "action": { "type": "string" } }
453
+ }] } }
454
+ }, {
455
+ "required": ["sso_user_not_found"],
456
+ "properties": { "sso_user_not_found": { "anyOf": [{
457
+ "required": ["purpose"],
458
+ "properties": { "purpose": { "type": "string" } }
459
+ }, {
460
+ "required": ["action"],
461
+ "properties": { "action": { "type": "string" } }
462
+ }] } }
463
+ }] } }
441
464
  }
442
465
  ] },
443
466
  "description": "A step in a flow definition. This is the admin-authored configuration,\nnot the runtime payload sent to the frontend.\n\nSteps are schema-driven: `fields` references properties from the flow's\nuser schema, and the engine resolves field metadata (type, validation,\nimplicit outcomes) from schema annotations at runtime.\n\nA step with only `complete` set is a terminal step. All other steps are\nrendered to the frontend as capability payloads.\n",
@@ -482,8 +505,9 @@ var flow_definition_default = {
482
505
  },
483
506
  "sso_providers": {
484
507
  "type": "array",
485
- "description": "Slugs of the identity provider connections this step offers, in display\norder. Each names the `slug` of a connection under `.zitadel/idps/`; the\nconnection carries the display name and template, so a rename there\nreaches every step without editing the flow. The rendered step the client\nreceives carries the resolved `{id, name, template}` objects instead.\n",
508
+ "description": "Slugs of the identity provider connections this step offers, in display\norder. Each names the `slug` of a connection under `.zitadel/idps/`; the\nconnection carries the display name and template, so a rename there\nreaches every step without editing the flow. The rendered step the client\nreceives carries the resolved `{id, name, template}` objects instead. A\nstep offers at most 20 providers.\n",
486
509
  "uniqueItems": true,
510
+ "maxItems": 20,
487
511
  "items": {
488
512
  "type": "string",
489
513
  "pattern": "^[a-z0-9][a-z0-9_-]*$",
@@ -494,8 +518,8 @@ var flow_definition_default = {
494
518
  },
495
519
  "on_success": {
496
520
  "type": "string",
497
- "enum": ["create_user"],
498
- "description": "Server-side mutation to execute when this step completes successfully.\nRuns after field validation passes, before the transition fires.\n\n- create_user: creates the user record (registration flows)\n",
521
+ "enum": ["create_user", "create_user_with_sso"],
522
+ "description": "Server-side mutation to execute when this step completes successfully.\nRuns after field validation passes, before the transition fires.\n\n- create_user: creates the user record (registration flows)\n- create_user_with_sso: creates the user record from the identity an\n external provider returned, linking it to that identity. Accepted by\n the API so an SSO flow can be authored and stored; the engine handler\n is not wired yet, and a step reaching it fails with a flow integrity\n error rather than creating anything.\n",
499
523
  "examples": ["create_user"]
500
524
  },
501
525
  "complete": {
@@ -506,7 +530,7 @@ var flow_definition_default = {
506
530
  },
507
531
  "transitions": {
508
532
  "type": "object",
509
- "description": "Maps action/outcome names to their transition descriptor.\n\nKeys match action names from the `actions` array. Additional keys\ncome from implicit outcomes based on schema annotations\n(e.g. `user_not_found` from `x-unique` fields) and engine\nevents (e.g. `sso`, `callback`).\n",
533
+ "description": "Maps action/outcome names to their transition descriptor.\n\nKeys match action names from the `actions` array. Additional keys\ncome from implicit outcomes based on schema annotations\n(e.g. `user_not_found` from `x-unique` fields) and engine\nevents (e.g. `sso_authenticated`, `sso_user_not_found`).\n",
510
534
  "additionalProperties": {
511
535
  "type": "object",
512
536
  "required": ["target"],
@@ -625,327 +649,6 @@ var flow_definition_default = {
625
649
  }
626
650
  };
627
651
  //#endregion
628
- //#region meta-schemas/idp-connection.json
629
- var idp_connection_default = {
630
- $comment: "Code generated by scripts/generate-meta-schemas.ts; DO NOT EDIT.",
631
- $schema: "https://json-schema.org/draft/2020-12/schema",
632
- title: "IdentityProviderConnection",
633
- type: "object",
634
- required: [
635
- "slug",
636
- "protocol",
637
- "display_name"
638
- ],
639
- additionalProperties: false,
640
- properties: {
641
- "$schema": {
642
- "type": "string",
643
- "minLength": 1,
644
- "description": "Editor affordance: path or URL of this schema so editors validate and autocomplete the file (scaffolded connection files point at `.zitadel/meta/idp-connection.json`). Ignored by the platform."
645
- },
646
- "slug": {
647
- "type": "string",
648
- "pattern": "^[a-z0-9][a-z0-9_-]*$",
649
- "maxLength": 64,
650
- "description": "Stable identifier, referenced by user schemas (x-auth-methods.sso.providers) and flow steps (sso_providers). Unique within the Project.",
651
- "examples": [
652
- "google",
653
- "github",
654
- "corp_idp"
655
- ]
656
- },
657
- "protocol": {
658
- "type": "string",
659
- "enum": ["oidc", "oauth2"],
660
- "description": "The protocol used by the identity provider."
661
- },
662
- "template": {
663
- "type": "string",
664
- "examples": [
665
- "google",
666
- "github",
667
- "okta"
668
- ],
669
- "description": "Template hint for rendering the provider (logo, colors). Carries no protocol behavior: conduct comes only from the protocol blocks."
670
- },
671
- "display_name": {
672
- "type": "string",
673
- "minLength": 1,
674
- "maxLength": 256,
675
- "description": "Shown to the user on the sign-in button."
676
- },
677
- "subject_claim": {
678
- "type": "string",
679
- "minLength": 1,
680
- "description": "Claim carrying the provider's stable subject identifier. Optional for OIDC (the engine uses `sub` per spec; override where `sub` is pairwise, e.g. Entra `oid`). Required for OAuth2 — no `sub` guarantee."
681
- },
682
- "claim_mapping": {
683
- "type": "object",
684
- "additionalProperties": {
685
- "type": "string",
686
- "pattern": "^[^$]"
687
- },
688
- "description": "Maps user-schema property names (keys) to provider claim names (values). A value is an exact top-level claim key: no path syntax, and a dot is part of the key, so nested claims (OIDC `address`, GitHub `plan`) are not addressable yet. `$`-prefixed strings and non-string values are reserved for future mapping forms. Add properties defined in the user schemas; unmatched entries are ignored."
689
- },
690
- "verified_claims": {
691
- "type": "object",
692
- "additionalProperties": { "anyOf": [
693
- { "const": true },
694
- { "const": "$supplementary_fetch" },
695
- {
696
- "type": "string",
697
- "pattern": "^[^$]"
698
- }
699
- ] },
700
- "description": "Maps a verifiable user-schema property to its verification source: a claim name (read the claim), the literal `true` (trust this provider unconditionally), or the `$`-pointer `\"$supplementary_fetch\"` (verified by the selected supplementary_fetch strategy per its contract - e.g. github_primary_email verifies `email` via primary && verified). Values starting with `$` are reserved; only `$supplementary_fetch` is defined. Distinct from claim_mapping, which carries values, not verification state.",
701
- "examples": [
702
- { "email": "email_verified" },
703
- { "email": true },
704
- { "email": "$supplementary_fetch" }
705
- ]
706
- },
707
- "provisioning": {
708
- "type": "object",
709
- "additionalProperties": false,
710
- "description": "How far this provider's data is trusted. `creation` defines what happens to a subject that has no account yet. With `disabled`, a user is not created. With `auto`, the user is created without a collection step when the mapped claims fill every required property of the schema. A required property with an `x-unique` scope must also arrive verified according to `verified_claims`. When a required property is missing or such a property is unverified, the collection step is shown instead, prefilled with the claims. Gating on other properties will be added when `x-verify` returns to the dialect. The following are deferred and will be added as additive changes. The `auto_only` value creates the user from complete claims or fails without collecting. The linking policy (`is_linking_allowed`, `auto_linking`), together with the account-linking journey. `is_auto_update`, together with per-property verification state.",
711
- "properties": { "creation": {
712
- "type": "string",
713
- "enum": ["disabled", "auto"],
714
- "default": "auto"
715
- } }
716
- },
717
- "oidc": {
718
- "type": "object",
719
- "additionalProperties": false,
720
- "description": "OIDC connection details. Endpoints come from the issuer's discovery document. A provider that exposes no .well-known document names them all instead: authorization_endpoint, token_endpoint, jwks_uri, and userinfo_endpoint unless id_token_mapping is set. Setting some but not all is rejected.",
721
- "required": [
722
- "issuer",
723
- "client_id",
724
- "client_secret",
725
- "scopes"
726
- ],
727
- "properties": {
728
- "issuer": {
729
- "type": "string",
730
- "format": "uri",
731
- "pattern": "^(https://[^\\s/?#]+|http://(localhost|127\\.0\\.0\\.1)(:[0-9]+)?)(/[^\\s?#]*)?$",
732
- "description": "Discovery base. Endpoints are resolved from its .well-known document unless the connection names them all."
733
- },
734
- "jwks_uri": {
735
- "type": "string",
736
- "format": "uri",
737
- "pattern": "^(https://[^\\s/?#]+|http://(localhost|127\\.0\\.0\\.1)(:[0-9]+)?)([/?][^\\s#]*)?$",
738
- "description": "JWKS endpoint, for a provider that exposes no .well-known document. Set together with the other endpoints."
739
- },
740
- "id_token_mapping": {
741
- "type": "boolean",
742
- "default": false,
743
- "description": "Read user claims from the id_token instead of the userinfo endpoint, for providers that populate only the former."
744
- },
745
- "authorization_endpoint": {
746
- "type": "string",
747
- "format": "uri",
748
- "pattern": "^(https://[^\\s/?#]+|http://(localhost|127\\.0\\.0\\.1)(:[0-9]+)?)([/?][^\\s#]*)?$",
749
- "description": "For a provider that exposes no .well-known document. Set together with the other endpoints."
750
- },
751
- "token_endpoint": {
752
- "type": "string",
753
- "format": "uri",
754
- "pattern": "^(https://[^\\s/?#]+|http://(localhost|127\\.0\\.0\\.1)(:[0-9]+)?)([/?][^\\s#]*)?$",
755
- "description": "For a provider that exposes no .well-known document. Set together with the other endpoints."
756
- },
757
- "userinfo_endpoint": {
758
- "type": "string",
759
- "format": "uri",
760
- "pattern": "^(https://[^\\s/?#]+|http://(localhost|127\\.0\\.0\\.1)(:[0-9]+)?)([/?][^\\s#]*)?$",
761
- "description": "For a provider that exposes no .well-known document. Set together with the other endpoints; not needed when id_token_mapping is set."
762
- },
763
- "client_id": {
764
- "type": "string",
765
- "minLength": 1,
766
- "maxLength": 512,
767
- "description": "Either a literal in case the same client is used in all environments, or a `${{ NAME }}` reference to a variable in case of separate clients per environment."
768
- },
769
- "client_secret": {
770
- "type": "string",
771
- "pattern": "^\\$\\{\\{ *[A-Za-z0-9_]+ *\\}\\}$",
772
- "description": "A reference to the variable holding the client secret, never the secret itself. A secret may only be referenced as the entire value: text around the placeholder would be rendered into the resolved credential, so it is rejected. The engine resolves it against the environment serving the request."
773
- },
774
- "token_endpoint_auth_method": {
775
- "type": "string",
776
- "enum": ["client_secret_basic", "client_secret_post"],
777
- "default": "client_secret_basic",
778
- "description": "How the client authenticates at the token endpoint."
779
- },
780
- "scopes": {
781
- "type": "array",
782
- "items": {
783
- "type": "string",
784
- "minLength": 1
785
- },
786
- "uniqueItems": true,
787
- "minItems": 1,
788
- "contains": { "const": "openid" },
789
- "default": [
790
- "openid",
791
- "profile",
792
- "email"
793
- ],
794
- "description": "Must contain `openid` - without it the provider returns no id_token and the connection is not OIDC. Enforced by `required` + `contains`; the `default` is a UI-prefill hint only - validators never inject it, so an omitted `scopes` is rejected regardless."
795
- },
796
- "pkce_enabled": {
797
- "type": "boolean",
798
- "default": true,
799
- "description": "Send PKCE (code_challenge/code_verifier). Providers that do not support PKCE typically ignore the parameters, so `true` is safe and future-proofs; set `false` only for a provider whose token endpoint rejects them."
800
- },
801
- "static_authorize_parameters": {
802
- "type": "object",
803
- "propertyNames": {
804
- "minLength": 1,
805
- "not": { "enum": [
806
- "client_id",
807
- "redirect_uri",
808
- "response_type",
809
- "scope",
810
- "state",
811
- "nonce",
812
- "code_challenge",
813
- "code_challenge_method",
814
- "response_mode",
815
- "request",
816
- "request_uri",
817
- "client_secret",
818
- "client_assertion"
819
- ] }
820
- },
821
- "additionalProperties": { "type": "string" },
822
- "description": "Extra provider-specific authorize parameters (for example `prompt`). Engine-owned protocol parameters are reserved and rejected by `propertyNames`: the engine composes them itself, and an override of `state` or `nonce` would silently defeat CSRF and token binding. `client_secret` and `client_assertion` are rejected as they could be appended to the public authorize URL."
823
- }
824
- }
825
- },
826
- "oauth2": {
827
- "type": "object",
828
- "additionalProperties": false,
829
- "description": "OAuth 2.0 connection details.",
830
- "required": [
831
- "authorization_endpoint",
832
- "token_endpoint",
833
- "userinfo_endpoint",
834
- "client_id",
835
- "client_secret"
836
- ],
837
- "properties": {
838
- "authorization_endpoint": {
839
- "type": "string",
840
- "format": "uri",
841
- "pattern": "^(https://[^\\s/?#]+|http://(localhost|127\\.0\\.0\\.1)(:[0-9]+)?)([/?][^\\s#]*)?$",
842
- "description": "Where the user is sent to authorize."
843
- },
844
- "token_endpoint": {
845
- "type": "string",
846
- "format": "uri",
847
- "pattern": "^(https://[^\\s/?#]+|http://(localhost|127\\.0\\.0\\.1)(:[0-9]+)?)([/?][^\\s#]*)?$",
848
- "description": "Where the authorization code is exchanged."
849
- },
850
- "userinfo_endpoint": {
851
- "type": "string",
852
- "format": "uri",
853
- "pattern": "^(https://[^\\s/?#]+|http://(localhost|127\\.0\\.0\\.1)(:[0-9]+)?)([/?][^\\s#]*)?$",
854
- "description": "Where the authenticated user's profile is fetched."
855
- },
856
- "client_id": {
857
- "type": "string",
858
- "minLength": 1,
859
- "maxLength": 512,
860
- "description": "Either a literal in case the same client is used in all environments, or a `${{ NAME }}` reference to a variable in case of separate clients per environment."
861
- },
862
- "client_secret": {
863
- "type": "string",
864
- "pattern": "^\\$\\{\\{ *[A-Za-z0-9_]+ *\\}\\}$",
865
- "description": "A reference to the variable holding the client secret, never the secret itself. A secret may only be referenced as the entire value: text around the placeholder would be rendered into the resolved credential, so it is rejected. The engine resolves it against the environment serving the request."
866
- },
867
- "token_endpoint_auth_method": {
868
- "type": "string",
869
- "enum": ["client_secret_basic", "client_secret_post"],
870
- "default": "client_secret_basic",
871
- "description": "How the client authenticates at the token endpoint."
872
- },
873
- "scopes": {
874
- "type": "array",
875
- "items": {
876
- "type": "string",
877
- "minLength": 1
878
- },
879
- "uniqueItems": true,
880
- "description": "Provider-specific; OAuth 2.0 defines no universal scope."
881
- },
882
- "pkce_enabled": {
883
- "type": "boolean",
884
- "default": true,
885
- "description": "Send PKCE (code_challenge/code_verifier). Providers that do not support PKCE typically ignore the parameters, so `true` is safe and future-proofs; set `false` only for a provider whose token endpoint rejects them."
886
- },
887
- "static_authorize_parameters": {
888
- "type": "object",
889
- "propertyNames": {
890
- "minLength": 1,
891
- "not": { "enum": [
892
- "client_id",
893
- "redirect_uri",
894
- "response_type",
895
- "scope",
896
- "state",
897
- "nonce",
898
- "code_challenge",
899
- "code_challenge_method",
900
- "response_mode",
901
- "request",
902
- "request_uri",
903
- "client_secret",
904
- "client_assertion"
905
- ] }
906
- },
907
- "additionalProperties": { "type": "string" },
908
- "description": "Extra provider-specific authorize parameters (for example `prompt`). Engine-owned protocol parameters are reserved and rejected by `propertyNames`: the engine composes them itself, and an override of `state` or `nonce` would silently defeat CSRF and token binding. `client_secret` and `client_assertion` are rejected as they could be appended to the public authorize URL."
909
- },
910
- "supplementary_fetch": {
911
- "type": "string",
912
- "enum": ["github_primary_email"],
913
- "description": "Provider-specific follow-up call after userinfo. New values are non-breaking."
914
- }
915
- },
916
- "allOf": [{
917
- "if": {
918
- "properties": { "supplementary_fetch": { "const": "github_primary_email" } },
919
- "required": ["supplementary_fetch"]
920
- },
921
- "then": {
922
- "required": ["scopes"],
923
- "properties": { "scopes": { "contains": { "const": "user:email" } } }
924
- }
925
- }]
926
- }
927
- },
928
- allOf: [{
929
- "if": {
930
- "properties": { "protocol": { "const": "oidc" } },
931
- "required": ["protocol"]
932
- },
933
- "then": {
934
- "required": ["oidc"],
935
- "properties": { "oauth2": false }
936
- }
937
- }, {
938
- "if": {
939
- "properties": { "protocol": { "const": "oauth2" } },
940
- "required": ["protocol"]
941
- },
942
- "then": {
943
- "required": ["oauth2", "subject_claim"],
944
- "properties": { "oidc": false }
945
- }
946
- }]
947
- };
948
- //#endregion
949
652
  //#region meta-schemas/property-name.json
950
653
  var property_name_default = {
951
654
  $comment: "Code generated by scripts/generate-meta-schemas.ts; DO NOT EDIT.",
@@ -1170,4 +873,4 @@ function metaSchemaFiles() {
1170
873
  //#endregion
1171
874
  export { metaSchemaFiles as i, FLOW_FILE_SCHEMA_REF as n, META_SCHEMA_DIR as r, BRANDING_FILE_SCHEMA_REF as t };
1172
875
 
1173
- //# sourceMappingURL=meta-schemas-K8f7YZYz.mjs.map
876
+ //# sourceMappingURL=meta-schemas-C03zgFux.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"meta-schemas-C03zgFux.mjs","names":["flowDefinitionMetaSchema","userSchemaMetaSchema","userPropertyMetaSchema","propertyNameMetaSchema","authMethodsMetaSchema","authMethodMetaSchema","ssoAuthMethodMetaSchema","idpConnectionMetaSchema","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/sso-auth-method.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 generated: `scripts/sync-meta-schemas.mjs`\n * copies them from `api/openapi/endpoints/schemas/*.json` (the files the\n * server embeds) ahead of build, typecheck and test. Those are generated in\n * turn from the OpenAPI YAML by `scripts/generate-meta-schemas.ts` at the repo\n * root, so the YAML is the only thing to edit.\n */\nimport authMethodMetaSchema from \"../meta-schemas/auth-method.json\" with { type: \"json\" };\nimport authMethodsMetaSchema from \"../meta-schemas/auth-methods.json\" with { type: \"json\" };\nimport brandingMetaSchema from \"../meta-schemas/branding.json\" with { type: \"json\" };\nimport flowDefinitionMetaSchema from \"../meta-schemas/flow-definition.json\" with { type: \"json\" };\nimport idpConnectionMetaSchema from \"../meta-schemas/idp-connection.json\" with { type: \"json\" };\nimport propertyNameMetaSchema from \"../meta-schemas/property-name.json\" with { type: \"json\" };\nimport ssoAuthMethodMetaSchema from \"../meta-schemas/sso-auth-method.json\" with { type: \"json\" };\nimport userPropertyMetaSchema from \"../meta-schemas/user-property.json\" with { type: \"json\" };\nimport userSchemaMetaSchema from \"../meta-schemas/user-schema.json\" with { type: \"json\" };\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`,\n * `auth-method.json`, and `sso-auth-method.json` are pulled in by\n * `user-schema.json`'s relative `$ref`s — without them the copied dialect\n * 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: \"sso-auth-method.json\", body: ssoAuthMethodMetaSchema as object },\n { name: \"idp-connection.json\", body: idpConnectionMetaSchema as object },\n { name: \"branding.json\", body: brandingMetaSchema as object },\n ];\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AQwBA,MAAa,kBAAkB;;;;;AAM/B,MAAa,uBAAuB;;;;;AAMpC,MAAa,2BAA2B;;;;;;;AAUxC,SAAgB,kBAAiD;CAC/D,OAAO;EACL;GAAE,MAAM;GAAwB,MAAMA;EAAmC;EACzE;GAAE,MAAM;GAAoB,MAAMC;EAA+B;EACjE;GAAE,MAAM;GAAsB,MAAMC;EAAiC;EACrE;GAAE,MAAM;GAAsB,MAAMC;EAAiC;EACrE;GAAE,MAAM;GAAqB,MAAMC;EAAgC;EACnE;GAAE,MAAM;GAAoB,MAAMC;EAA+B;EACjE;GAAE,MAAM;GAAwB,MAAMC;EAAkC;EACxE;GAAE,MAAM;GAAuB,MAAMC;EAAkC;EACvE;GAAE,MAAM;GAAiB,MAAMC;EAA6B;CAC9D;AACF"}
@@ -1,17 +1,17 @@
1
1
  //#region src/meta-schemas.d.ts
2
2
  /** Project-relative directory setup writes the meta-schemas to. */
3
- declare const META_SCHEMA_DIR = ".zitadel/meta";
3
+ export declare const META_SCHEMA_DIR = ".zitadel/meta";
4
4
  /**
5
5
  * The `$schema` value scaffolded flow files carry, relative to
6
6
  * `.zitadel/flows/` — resolves to `{@link META_SCHEMA_DIR}/flow-definition.json`.
7
7
  */
8
- declare const FLOW_FILE_SCHEMA_REF = "../meta/flow-definition.json";
8
+ export declare const FLOW_FILE_SCHEMA_REF = "../meta/flow-definition.json";
9
9
  /**
10
10
  * The `$schema` value scaffolded branding files carry, relative to
11
11
  * `.zitadel/branding/` — resolves to `{@link META_SCHEMA_DIR}/branding.json`.
12
12
  */
13
- declare const BRANDING_FILE_SCHEMA_REF = "../meta/branding.json";
14
- type MetaSchemaFile = {
13
+ export declare const BRANDING_FILE_SCHEMA_REF = "../meta/branding.json";
14
+ export type MetaSchemaFile = {
15
15
  name: string;
16
16
  body: object;
17
17
  };
@@ -21,7 +21,6 @@ type MetaSchemaFile = {
21
21
  * `user-schema.json`'s relative `$ref`s — without them the copied dialect
22
22
  * cannot resolve offline.
23
23
  */
24
- declare function metaSchemaFiles(): ReadonlyArray<MetaSchemaFile>;
24
+ export declare function metaSchemaFiles(): ReadonlyArray<MetaSchemaFile>;
25
25
  //#endregion
26
- export { BRANDING_FILE_SCHEMA_REF, FLOW_FILE_SCHEMA_REF, META_SCHEMA_DIR, MetaSchemaFile, metaSchemaFiles };
27
26
  //# sourceMappingURL=meta-schemas.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"meta-schemas.d.mts","names":[],"sources":["../src/meta-schemas.ts"],"mappings":";;cA0Ca,eAAA;;;;;cAMA,oBAAA;;;;;cAMA,wBAAA;AAAA,KAED,cAAA;EAAmB,IAAA;EAAc,IAAA;AAAA;AAA7C;;;;;AAQA;AARA,iBAQgB,eAAA,CAAA,GAAmB,aAAA,CAAc,cAAA"}
1
+ {"version":3,"file":"meta-schemas.d.mts","names":[],"sources":["../src/meta-schemas.ts"],"mappings":";;qBAwBa;;;;;qBAMA;;;;;qBAMA;YAED;EAAmB;EAAc;;;;;;;;wBAQ7B,mBAAmB,cAAc"}
@@ -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-K8f7YZYz.mjs";
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-C03zgFux.mjs";
2
2
  export { BRANDING_FILE_SCHEMA_REF, FLOW_FILE_SCHEMA_REF, META_SCHEMA_DIR, metaSchemaFiles };
@@ -22,7 +22,7 @@
22
22
  * spells one of these out is semantically identical to one that omits it:
23
23
  * audit payloads deny by default.
24
24
  */
25
- declare const USER_PROPERTY_DEFAULTS: Readonly<Record<string, boolean>>;
25
+ export declare const USER_PROPERTY_DEFAULTS: Readonly<Record<string, boolean>>;
26
26
  /**
27
27
  * Return a deep copy of a bare flow-definition body with server-echoed
28
28
  * noise removed: an empty `audience` and any detail-envelope keys. A
@@ -32,7 +32,7 @@ declare const USER_PROPERTY_DEFAULTS: Readonly<Record<string, boolean>>;
32
32
  * from responses, so comparing with it would read every scaffolded file
33
33
  * as permanently diverged.
34
34
  */
35
- declare function normalizeFlowBody(body: object): object;
35
+ export declare function normalizeFlowBody(body: object): object;
36
36
  /**
37
37
  * Return a deep copy of a user-schema body with meta-schema property
38
38
  * defaults stripped: a property carrying one of the
@@ -41,7 +41,6 @@ declare function normalizeFlowBody(body: object): object;
41
41
  * through untouched. Nested `properties` are descended into, so a leaf
42
42
  * of an object property normalizes the same way a top-level one does.
43
43
  */
44
- declare function normalizeSchemaBody(body: object): object;
44
+ export declare function normalizeSchemaBody(body: object): object;
45
45
  //#endregion
46
- export { USER_PROPERTY_DEFAULTS, normalizeFlowBody, normalizeSchemaBody };
47
46
  //# sourceMappingURL=normalize.d.mts.map
@@ -1 +1 @@
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"}
1
+ {"version":3,"file":"normalize.d.mts","names":[],"sources":["../src/normalize.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;qBAwBa,wBAAwB,SAAS;;;;;;;;;;wBAwC9B,kBAAkB;;;;;;;;;wBAoBlB,oBAAoB"}
@@ -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-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 response 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\", \"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;CAAa;AAE3E,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"}
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 response 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\", \"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,MACb;;;;;;AAOA,MAAM,qBAAqB;CAAC;CAAM;CAAc;CAAc;AAAY;AAE1E,SAAS,cAAc,OAAkD;CACvE,OAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,KAAK;AAC5E;;;;;;AAOA,SAAS,gBAAgB,OAAyB;CAChD,IAAI,CAAC,cAAc,KAAK,GACtB,OAAO;CAET,OAAO,OAAO,QAAQ,KAAK,CAAC,CAAC,OAC1B,CAAC,KAAK,YACJ,QAAQ,cAAc,QAAQ,eAC9B,UAAU,QAAQ,UAAU,KAAA,KAAc,MAAM,QAAQ,KAAK,KAAK,MAAM,WAAW,EACxF;AACF;;;;;;;;;;AAWA,SAAgB,kBAAkB,MAAsB;CACtD,MAAM,SAAS,gBAAgB,IAAI;CACnC,KAAK,MAAM,OAAO,oBAChB,OAAO,OAAO;CAEhB,OAAO,OAAO;CACd,IAAI,cAAc,UAAU,gBAAgB,OAAO,QAAQ,GACzD,OAAO,OAAO;CAEhB,OAAO;AACT;;;;;;;;;AAUA,SAAgB,oBAAoB,MAAsB;CACxD,MAAM,SAAS,gBAAgB,IAAI;CACnC,sBAAsB,MAAM;CAC5B,OAAO;AACT;;;;;;AAOA,SAAS,sBAAsB,QAAuC;CACpE,IAAI,CAAC,cAAc,OAAO,UAAU,GAClC;CAEF,KAAK,MAAM,YAAY,OAAO,OAAO,OAAO,UAAU,GAAG;EACvD,IAAI,CAAC,cAAc,QAAQ,GACzB;EAEF,KAAK,MAAM,CAAC,KAAK,iBAAiB,OAAO,QAAQ,sBAAsB,GACrE,IAAI,SAAS,SAAS,cACpB,OAAO,SAAS;EAGpB,sBAAsB,QAAQ;CAChC;AACF"}
@@ -1,11 +1,11 @@
1
1
  import { isCanonicalLoopbackHttpUrl } from "./branding-url.mjs";
2
- import { CreateBrandingBody, CreateFlowDefinitionBody, CreateSchemaBody } from "@zitadel/api/generated/endpoints/zitadelNextGen.zod";
2
+ import { CreateBrandingBody, CreateFlowDefinitionBody, CreateIdpBody, CreateSchemaBody } from "@zitadel/api/generated/endpoints/zitadelNextGen.zod";
3
3
  import { z } from "zod";
4
4
  /** Asset URL cap in UTF-8 bytes, like the server's `MaxBrandingURLBytes`. */
5
5
  const MAX_BRANDING_URL_BYTES = 2048;
6
6
  const HEX_COLOR = /^#([0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;
7
7
  /** `url` is absent by construction: it is not a colour function. */
8
- const COLOR_FUNCTIONS = new Set([
8
+ const COLOR_FUNCTIONS = /* @__PURE__ */ new Set([
9
9
  "rgb",
10
10
  "rgba",
11
11
  "hsl",
@@ -74,6 +74,13 @@ function isFontName(family) {
74
74
  const schemaConfigSchema = CreateSchemaBody;
75
75
  const flowConfigSchema = CreateFlowDefinitionBody.shape.flow_definition;
76
76
  const createFlowDefinitionRequestSchema = CreateFlowDefinitionBody;
77
+ /**
78
+ * One `.zitadel/idps/<slug>.json` body: the connection document `POST /idps`
79
+ * carries under `idp`. The generated Zod enforces the contract the meta-schema
80
+ * states, including that `client_secret` is a `${{ NAME }}` reference and
81
+ * never a literal.
82
+ */
83
+ const idpConnectionConfigSchema = CreateIdpBody.shape.idp;
77
84
  /** The wire shape of a branding revision (`POST /branding` request body). */
78
85
  const brandingWireSchema = CreateBrandingBody;
79
86
  /**
@@ -168,6 +175,6 @@ function validateBrandingAssetUrl(value, field, ctx, options = {}) {
168
175
  });
169
176
  }
170
177
  //#endregion
171
- export { localFileReferenceSchema as a, flowConfigSchema as i, brandingWireSchema as n, schemaConfigSchema as o, createFlowDefinitionRequestSchema as r, brandingConfigSchema as t };
178
+ export { idpConnectionConfigSchema as a, flowConfigSchema as i, brandingWireSchema as n, localFileReferenceSchema as o, createFlowDefinitionRequestSchema as r, schemaConfigSchema as s, brandingConfigSchema as t };
172
179
 
173
- //# sourceMappingURL=schemas-7oNU25Qz.mjs.map
180
+ //# sourceMappingURL=schemas-CUU4Rf8J.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schemas-CUU4Rf8J.mjs","names":[],"sources":["../src/branding-css.ts","../src/schemas.ts"],"sourcesContent":["/**\n * Mirror of the server's appearance-value gates\n * (`internal/domain/branding_css.go`), so `plan` rejects what `apply` would.\n *\n * The widget writes these values straight into a CSS declaration, so a value\n * able to close its own declaration can emit rules of its own. Both gates are\n * allowlists: a value is accepted only when it matches a form we recognise,\n * never merely because it avoided the characters someone thought to ban.\n */\n\nexport const MAX_BRANDING_COLOR_LENGTH = 128;\nexport const MAX_BRANDING_FONT_FAMILY_LENGTH = 256;\n/** Asset URL cap in UTF-8 bytes, like the server's `MaxBrandingURLBytes`. */\nexport const MAX_BRANDING_URL_BYTES = 2048;\n\nconst HEX_COLOR = /^#([0-9a-fA-F]{3,4}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/;\n\n/** `url` is absent by construction: it is not a colour function. */\nconst COLOR_FUNCTIONS = new Set([\n \"rgb\",\n \"rgba\",\n \"hsl\",\n \"hsla\",\n \"hwb\",\n \"lab\",\n \"lch\",\n \"oklab\",\n \"oklch\",\n \"color\",\n \"color-mix\",\n]);\n\nconst COLOR_ARGS = /^[0-9a-zA-Z%.,+\\-/ ()#]*$/;\n/**\n * A bare colour name. Which names CSS knows is the browser's business: an\n * unknown one paints nothing, and every name of this shape is inert inside a\n * declaration whatever it spells.\n */\nconst COLOR_NAME = /^[a-zA-Z]{3,24}$/;\nconst FONT_IDENT = /^[A-Za-z0-9_-]+( [A-Za-z0-9_-]+)*$/;\n\nfunction isColorFunction(value: string): boolean {\n const open = value.indexOf(\"(\");\n if (open <= 0 || !value.endsWith(\")\")) return false;\n if (!COLOR_FUNCTIONS.has(value.slice(0, open))) return false;\n\n const args = value.slice(open + 1, -1);\n if (!COLOR_ARGS.test(args)) return false;\n\n // Nesting is legal (`color-mix(in srgb, rgb(1 2 3), red)`), so the\n // parentheses only have to balance, at a bounded depth.\n let depth = 0;\n for (const char of args) {\n if (char === \"(\") {\n depth += 1;\n if (depth > 4) return false;\n } else if (char === \")\") {\n depth -= 1;\n if (depth < 0) return false;\n }\n }\n return depth === 0;\n}\n\n/** Whether a value is hex, a CSS colour name, or a colour function. */\nexport function isBrandingColor(value: string): boolean {\n if (value.length > MAX_BRANDING_COLOR_LENGTH) return false;\n if (value.trim() === \"\") return false;\n // Not trimmed: the value is stored and painted verbatim.\n if (HEX_COLOR.test(value)) return true;\n return COLOR_NAME.test(value) || isColorFunction(value.toLowerCase());\n}\n\n/** Whether a value is a CSS font stack of identifiers and quoted names. */\nexport function isBrandingFontFamily(value: string): boolean {\n if (value.length > MAX_BRANDING_FONT_FAMILY_LENGTH) return false;\n if (value.trim() === \"\") return false;\n return value.split(\",\").every((family) => isFontName(trimSpaces(family)));\n}\n\n/** Spaces around a comma are ordinary; other whitespace is not a separator. */\nfunction trimSpaces(value: string): string {\n return value.replace(/^ +/, \"\").replace(/ +$/, \"\");\n}\n\nfunction isFontName(family: string): boolean {\n if (family === \"\") return false;\n const quote = family[0];\n if (quote === '\"' || quote === \"'\") {\n // A quoted name ends at its matching quote and holds no other, so it\n // cannot leave the string it opened.\n if (family.length < 2 || family.at(-1) !== quote) return false;\n const inner = family.slice(1, -1);\n return !inner.includes(quote) && !/[\\\\;{}]/.test(inner);\n }\n return FONT_IDENT.test(family);\n}\n","import {\n CreateBrandingBody,\n CreateFlowDefinitionBody,\n CreateIdpBody,\n CreateSchemaBody,\n} from \"@zitadel/api/generated/endpoints/zitadelNextGen.zod\";\nimport { z } from \"zod\";\n\nimport { isBrandingColor, isBrandingFontFamily, MAX_BRANDING_URL_BYTES } from \"./branding-css.js\";\nimport { isCanonicalLoopbackHttpUrl } from \"./branding-url.js\";\n\nexport const schemaConfigSchema = CreateSchemaBody;\nexport const flowConfigSchema = CreateFlowDefinitionBody.shape.flow_definition;\nexport const createFlowDefinitionRequestSchema = CreateFlowDefinitionBody;\n\n/**\n * One `.zitadel/idps/<slug>.json` body: the connection document `POST /idps`\n * carries under `idp`. The generated Zod enforces the contract the meta-schema\n * states, including that `client_secret` is a `${{ NAME }}` reference and\n * never a literal.\n */\nexport const idpConnectionConfigSchema = CreateIdpBody.shape.idp;\n\n/** The wire shape of a branding revision (`POST /branding` request body). */\nexport const brandingWireSchema = CreateBrandingBody;\n\n/**\n * `{ \"$file\": \"<path>\" }`, which a `.zitadel/` file may hold in place of a\n * string field the OpenAPI YAML marks `x-local: file`. The path is relative to\n * the file holding it; the CLI inlines the content before publishing.\n */\nexport const localFileReferenceSchema = z.strictObject({ $file: z.string().min(1) });\n\n/**\n * The local `.zitadel/branding/*.json` dialect: the wire shape, where\n * `liquid_template` may also be a `$file` reference to the sibling `.liquid`\n * template (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: z\n .union([CreateBrandingBody.shape.liquid_template.unwrap(), localFileReferenceSchema])\n .optional(),\n })\n .superRefine((value, ctx) => {\n // A stylesheet alone names no face to render in, so the server rejects the\n // pair as a pair (validateBrandingFontURL in\n // internal/domain/branding_validator.go). plan has to agree, or apply\n // fails after schemas and flows have already been written.\n validateBrandingAssetUrl(value.typography?.font_url, \"typography.font_url\", ctx, {\n loopback: false,\n });\n if (value.typography?.font_url !== undefined && value.typography.font_family === undefined) {\n ctx.addIssue({\n code: \"custom\",\n message:\n \"typography.font_url needs a typography.font_family to load; a stylesheet alone names no face to render in.\",\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 validateBrandingAssetUrl(value.theme?.light?.logo_url, \"theme.light.logo_url\", ctx);\n validateBrandingAssetUrl(value.theme?.dark?.logo_url, \"theme.dark.logo_url\", ctx);\n // The appearance values land in a CSS declaration, so the server stores\n // only forms it recognises (ValidateBrandingColor / ValidateBrandingFontFamily\n // in internal/domain/branding_css.go).\n validateBrandingPalette(value.theme?.light?.palette, \"theme.light\", ctx);\n validateBrandingPalette(value.theme?.dark?.palette, \"theme.dark\", ctx);\n if (\n value.typography?.font_family !== undefined &&\n !isBrandingFontFamily(value.typography.font_family)\n ) {\n ctx.addIssue({\n code: \"custom\",\n message:\n 'typography.font_family must be comma-separated font names, each an identifier (Inter, ui-sans-serif) or a quoted name (\"APK Futural\").',\n });\n }\n });\n\nfunction validateBrandingPalette(\n palette: Record<string, unknown> | undefined,\n side: string,\n ctx: z.RefinementCtx,\n): void {\n if (!palette) {\n return;\n }\n for (const [key, colour] of Object.entries(palette)) {\n // A non-string never reaches here: the generated object schema types every\n // palette value as a string, and Zod skips refinements once the base parse\n // has failed. The check is what narrows `unknown` for the call below.\n if (typeof colour !== \"string\") {\n continue;\n }\n if (isBrandingColor(colour)) {\n continue;\n }\n ctx.addIssue({\n code: \"custom\",\n message: `${side}.palette.${key} must be hex (#4F46E5), a CSS colour name, or a colour function such as rgb(), hsl() or oklch().`,\n });\n }\n}\n\nfunction validateBrandingAssetUrl(\n value: string | undefined,\n field: string,\n ctx: z.RefinementCtx,\n options: { loopback?: boolean } = {},\n): void {\n if (value === undefined || value === \"\") {\n return;\n }\n // The server counts bytes (validateBrandingAssetURL), so a URL with\n // non-ASCII characters can be short in characters and still too long.\n if (new TextEncoder().encode(value).length > MAX_BRANDING_URL_BYTES) {\n ctx.addIssue({\n code: \"custom\",\n message: `${field} must be at most ${MAX_BRANDING_URL_BYTES} bytes.`,\n });\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 // Fetched by every visitor's browser, so userinfo in it is a credential in\n // every access log — the server refuses it and so must plan.\n if (parsed.username !== \"\" || parsed.password !== \"\") {\n ctx.addIssue({\n code: \"custom\",\n message: `${field} must not carry credentials; the URL is fetched by every visitor's browser.`,\n });\n return;\n }\n // Loopback HTTP is the dev-posture carve-out (assets served from the app's\n // own dev server), and it covers images only: a stylesheet is styling rather\n // than an image, so it stays https everywhere. Check the raw URL so WHATWG\n // normalisation cannot make plan accept a host spelling that the Go save\n // gate rejects.\n if (\n options.loopback !== false &&\n parsed.protocol === \"http:\" &&\n isCanonicalLoopbackHttpUrl(value)\n ) {\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":"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"}