@zitadel/components 0.1.0-alpha.0 → 0.1.0-alpha.11

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 (110) hide show
  1. package/README.md +76 -55
  2. package/dist/atoms/index.d.mts +1 -1
  3. package/dist/atoms/index.mjs +1 -1
  4. package/dist/{atoms-B9yd0c-i.mjs → atoms-BHSt5lSe.mjs} +229 -88
  5. package/dist/atoms-BHSt5lSe.mjs.map +1 -0
  6. package/dist/default-Cpl78hQN.mjs +6 -0
  7. package/dist/default-Cpl78hQN.mjs.map +1 -0
  8. package/dist/{index-B74_igDN.d.mts → index-Bv62se8F.d.mts} +92 -21
  9. package/dist/index-Bv62se8F.d.mts.map +1 -0
  10. package/dist/{index-Dd8hfOWt.d.mts → index-DVDCrfkv.d.mts} +1515 -827
  11. package/dist/index-DVDCrfkv.d.mts.map +1 -0
  12. package/dist/{index-EJengPPu.d.mts → index-EC-BnGsx.d.mts} +3 -3
  13. package/dist/{index-EJengPPu.d.mts.map → index-EC-BnGsx.d.mts.map} +1 -1
  14. package/dist/index.d.mts +4 -4
  15. package/dist/index.mjs +4 -4
  16. package/dist/manifests.mjs +1 -1
  17. package/dist/orchestrator/index.d.mts +2 -2
  18. package/dist/orchestrator/index.mjs +2 -2
  19. package/dist/{orchestrator-B8eXcPRi.mjs → orchestrator-BeTmVk54.mjs} +486 -173
  20. package/dist/orchestrator-BeTmVk54.mjs.map +1 -0
  21. package/dist/standalone.mjs +12187 -0
  22. package/dist/tokens/index.d.mts +1 -1
  23. package/dist/tokens/index.mjs +1 -1
  24. package/dist/{tokens-TXmurodq.mjs → tokens-C0j4iCrs.mjs} +4 -4
  25. package/dist/tokens-C0j4iCrs.mjs.map +1 -0
  26. package/package.json +8 -16
  27. package/dist/atoms/index.d.ts +0 -9
  28. package/dist/atoms/index.d.ts.map +0 -1
  29. package/dist/atoms/zl-alert.d.ts +0 -56
  30. package/dist/atoms/zl-alert.d.ts.map +0 -1
  31. package/dist/atoms/zl-button.d.ts +0 -83
  32. package/dist/atoms/zl-button.d.ts.map +0 -1
  33. package/dist/atoms/zl-card.d.ts +0 -46
  34. package/dist/atoms/zl-card.d.ts.map +0 -1
  35. package/dist/atoms/zl-field.d.ts +0 -80
  36. package/dist/atoms/zl-field.d.ts.map +0 -1
  37. package/dist/atoms/zl-icon.d.ts +0 -48
  38. package/dist/atoms/zl-icon.d.ts.map +0 -1
  39. package/dist/atoms/zl-page-shell.d.ts +0 -42
  40. package/dist/atoms/zl-page-shell.d.ts.map +0 -1
  41. package/dist/atoms/zl-passkey.d.ts +0 -123
  42. package/dist/atoms/zl-passkey.d.ts.map +0 -1
  43. package/dist/atoms/zl-pill.d.ts +0 -55
  44. package/dist/atoms/zl-pill.d.ts.map +0 -1
  45. package/dist/atoms-B9yd0c-i.mjs.map +0 -1
  46. package/dist/default-DP74t2io.mjs +0 -6
  47. package/dist/default-DP74t2io.mjs.map +0 -1
  48. package/dist/index-B74_igDN.d.mts.map +0 -1
  49. package/dist/index-Dd8hfOWt.d.mts.map +0 -1
  50. package/dist/index.d.ts +0 -16
  51. package/dist/index.d.ts.map +0 -1
  52. package/dist/internal/base64url.d.ts +0 -18
  53. package/dist/internal/base64url.d.ts.map +0 -1
  54. package/dist/internal/unique-id.d.ts +0 -2
  55. package/dist/internal/unique-id.d.ts.map +0 -1
  56. package/dist/manifest.d.ts +0 -36
  57. package/dist/manifest.d.ts.map +0 -1
  58. package/dist/manifests.d.ts +0 -6
  59. package/dist/manifests.d.ts.map +0 -1
  60. package/dist/orchestrator/api-client.d.ts +0 -33
  61. package/dist/orchestrator/api-client.d.ts.map +0 -1
  62. package/dist/orchestrator/branding-to-tokens.d.ts +0 -28
  63. package/dist/orchestrator/branding-to-tokens.d.ts.map +0 -1
  64. package/dist/orchestrator/branding-validator.d.ts +0 -7
  65. package/dist/orchestrator/branding-validator.d.ts.map +0 -1
  66. package/dist/orchestrator/branding.d.ts +0 -76
  67. package/dist/orchestrator/branding.d.ts.map +0 -1
  68. package/dist/orchestrator/font-loader.d.ts +0 -2
  69. package/dist/orchestrator/font-loader.d.ts.map +0 -1
  70. package/dist/orchestrator/index.d.ts +0 -23
  71. package/dist/orchestrator/index.d.ts.map +0 -1
  72. package/dist/orchestrator/liquid.d.ts +0 -31
  73. package/dist/orchestrator/liquid.d.ts.map +0 -1
  74. package/dist/orchestrator/locales/de.d.ts +0 -16
  75. package/dist/orchestrator/locales/de.d.ts.map +0 -1
  76. package/dist/orchestrator/locales/en.d.ts +0 -19
  77. package/dist/orchestrator/locales/en.d.ts.map +0 -1
  78. package/dist/orchestrator/locales/index.d.ts +0 -13
  79. package/dist/orchestrator/locales/index.d.ts.map +0 -1
  80. package/dist/orchestrator/locales/it.d.ts +0 -14
  81. package/dist/orchestrator/locales/it.d.ts.map +0 -1
  82. package/dist/orchestrator/mandatory-gates.d.ts +0 -26
  83. package/dist/orchestrator/mandatory-gates.d.ts.map +0 -1
  84. package/dist/orchestrator/sanitiser.d.ts +0 -6
  85. package/dist/orchestrator/sanitiser.d.ts.map +0 -1
  86. package/dist/orchestrator/template-context.d.ts +0 -55
  87. package/dist/orchestrator/template-context.d.ts.map +0 -1
  88. package/dist/orchestrator/template-names.d.ts +0 -16
  89. package/dist/orchestrator/template-names.d.ts.map +0 -1
  90. package/dist/orchestrator/theme-controller.d.ts +0 -30
  91. package/dist/orchestrator/theme-controller.d.ts.map +0 -1
  92. package/dist/orchestrator/zitadel-login.d.ts +0 -185
  93. package/dist/orchestrator/zitadel-login.d.ts.map +0 -1
  94. package/dist/orchestrator/zitadel-logout.d.ts +0 -86
  95. package/dist/orchestrator/zitadel-logout.d.ts.map +0 -1
  96. package/dist/orchestrator-B8eXcPRi.mjs.map +0 -1
  97. package/dist/styles/base.d.ts +0 -7
  98. package/dist/styles/base.d.ts.map +0 -1
  99. package/dist/styles/focus-ring.d.ts +0 -7
  100. package/dist/styles/focus-ring.d.ts.map +0 -1
  101. package/dist/styles/index.d.ts +0 -5
  102. package/dist/styles/index.d.ts.map +0 -1
  103. package/dist/styles/surface.d.ts +0 -8
  104. package/dist/styles/surface.d.ts.map +0 -1
  105. package/dist/styles/tokens.d.ts +0 -11
  106. package/dist/styles/tokens.d.ts.map +0 -1
  107. package/dist/tokens/index.d.ts +0 -9
  108. package/dist/tokens/index.d.ts.map +0 -1
  109. package/dist/tokens-TXmurodq.mjs.map +0 -1
  110. package/dist/tsconfig.lib.tsbuildinfo +0 -1
@@ -1,21 +1,12 @@
1
- import { _ as __decorate, b as t, v as focusVisibleStyles, y as baseHostStyles } from "./atoms-B9yd0c-i.mjs";
2
- import { r as tokensCss } from "./tokens-TXmurodq.mjs";
3
- import { t as default_default } from "./default-DP74t2io.mjs";
1
+ import { _ as __decorate, b as t, v as focusVisibleStyles, x as emit, y as baseHostStyles } from "./atoms-BHSt5lSe.mjs";
2
+ import { r as tokensCss } from "./tokens-C0j4iCrs.mjs";
3
+ import { t as default_default } from "./default-Cpl78hQN.mjs";
4
4
  import { manifestRegistry } from "./manifests.mjs";
5
5
  import { LitElement, css, html, nothing } from "lit";
6
6
  import { customElement, property, state } from "lit/decorators.js";
7
7
  import { unsafeHTML } from "lit/directives/unsafe-html.js";
8
8
  import { Liquid } from "liquidjs";
9
9
  import DOMPurify from "dompurify";
10
- //#region ../api/dist/runtime/base-url.mjs
11
- let proxyPath = "";
12
- function getProxyPath() {
13
- return proxyPath;
14
- }
15
- function setProxyPath(path) {
16
- proxyPath = path;
17
- }
18
- //#endregion
19
10
  //#region ../api/dist/runtime/auth.mjs
20
11
  /**
21
12
  * Module-global bearer token used by the orval-generated client's
@@ -35,18 +26,6 @@ function setApiAuthToken(token) {
35
26
  apiAuthToken = token;
36
27
  }
37
28
  //#endregion
38
- //#region ../api/dist/chunk-CfYAbeIz.mjs
39
- var __defProp = Object.defineProperty;
40
- var __exportAll = (all, no_symbols) => {
41
- let target = {};
42
- for (var name in all) __defProp(target, name, {
43
- get: all[name],
44
- enumerable: true
45
- });
46
- if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
47
- return target;
48
- };
49
- //#endregion
50
29
  //#region ../api/dist/runtime/fetch.mjs
51
30
  /**
52
31
  * Framework-neutral failure type the orval-generated client throws on
@@ -119,6 +98,57 @@ function safeJsonParse(text) {
119
98
  }
120
99
  }
121
100
  //#endregion
101
+ //#region src/orchestrator/api-client.ts
102
+ const apiRequestInit = { credentials: "include" };
103
+ async function startFlow(api, input) {
104
+ return api.createFlow(input, apiRequestInit);
105
+ }
106
+ async function submitStep(api, id, body) {
107
+ try {
108
+ return await api.submitFlowStep(id, body, apiRequestInit);
109
+ } catch (error) {
110
+ if (error instanceof ApiError && error.status === 400 && isFlowResponse(error.body)) return error.body;
111
+ throw error;
112
+ }
113
+ }
114
+ function isFlowResponse(body) {
115
+ return typeof body === "object" && body !== null && "step" in body;
116
+ }
117
+ async function getCurrentStep(api, id) {
118
+ return api.getFlowStep(id, apiRequestInit);
119
+ }
120
+ /**
121
+ * Exchange a terminal-flow `handoff_token` for an authenticated session.
122
+ * The server sets the `__nextgen_session` HttpOnly cookie on success.
123
+ *
124
+ * Uses the generated `exchangeHandoff` client which handles the
125
+ * `project_id` query parameter via {@link ExchangeHandoffParams}.
126
+ */
127
+ async function exchangeSession(api, body, params) {
128
+ return api.exchangeHandoff(body, params, apiRequestInit);
129
+ }
130
+ //#endregion
131
+ //#region ../api/dist/runtime/base-url.mjs
132
+ let proxyPath = "";
133
+ function getProxyPath() {
134
+ return proxyPath;
135
+ }
136
+ function setProxyPath(path) {
137
+ proxyPath = path;
138
+ }
139
+ //#endregion
140
+ //#region ../api/dist/chunk-CfYAbeIz.mjs
141
+ var __defProp = Object.defineProperty;
142
+ var __exportAll = (all, no_symbols) => {
143
+ let target = {};
144
+ for (var name in all) __defProp(target, name, {
145
+ get: all[name],
146
+ enumerable: true
147
+ });
148
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
149
+ return target;
150
+ };
151
+ //#endregion
122
152
  //#region ../api/dist/generated/endpoints/zitadelNextGen.mjs
123
153
  /**
124
154
  * Generated by orval v8.10.0 🍺
@@ -166,6 +196,7 @@ var zitadelNextGen_exports = /* @__PURE__ */ __exportAll({
166
196
  getGetKeysUrl: () => getGetKeysUrl,
167
197
  getGetLiveUrl: () => getGetLiveUrl,
168
198
  getGetMySessionUrl: () => getGetMySessionUrl,
199
+ getGetMyUserUrl: () => getGetMyUserUrl,
169
200
  getGetOpenIDConfigurationUrl: () => getGetOpenIDConfigurationUrl,
170
201
  getGetProjectUrl: () => getGetProjectUrl,
171
202
  getGetReadyUrl: () => getGetReadyUrl,
@@ -184,6 +215,7 @@ var zitadelNextGen_exports = /* @__PURE__ */ __exportAll({
184
215
  getListUsersUrl: () => getListUsersUrl,
185
216
  getLive: () => getLive,
186
217
  getMySession: () => getMySession,
218
+ getMyUser: () => getMyUser,
187
219
  getOpenIDConfiguration: () => getOpenIDConfiguration,
188
220
  getProject: () => getProject,
189
221
  getReady: () => getReady,
@@ -192,6 +224,7 @@ var zitadelNextGen_exports = /* @__PURE__ */ __exportAll({
192
224
  getRevokeTokenUrl: () => getRevokeTokenUrl,
193
225
  getSchemaById: () => getSchemaById,
194
226
  getSession: () => getSession,
227
+ getSetUserPasswordUrl: () => getSetUserPasswordUrl,
195
228
  getSubmitFlowEventUrl: () => getSubmitFlowEventUrl,
196
229
  getSubmitFlowStepUrl: () => getSubmitFlowStepUrl,
197
230
  getTeam: () => getTeam,
@@ -208,6 +241,7 @@ var zitadelNextGen_exports = /* @__PURE__ */ __exportAll({
208
241
  revokeMySession: () => revokeMySession,
209
242
  revokeSession: () => revokeSession,
210
243
  revokeToken: () => revokeToken,
244
+ setUserPassword: () => setUserPassword,
211
245
  submitFlowEvent: () => submitFlowEvent,
212
246
  submitFlowStep: () => submitFlowStep,
213
247
  updateFlowDefinition: () => updateFlowDefinition,
@@ -333,7 +367,7 @@ const getGetTokenUrl = () => {
333
367
  return `${getProxyPath()}/auth/token`;
334
368
  };
335
369
  /**
336
- * @summary Get accesstoken
370
+ * @summary Get access token
337
371
  */
338
372
  const getToken = async (getTokenBody, options) => {
339
373
  const formUrlEncoded = new URLSearchParams();
@@ -412,7 +446,7 @@ const getCreateUserUrl = (params) => {
412
446
  if (value !== void 0) normalizedParams.append(key, value === null ? "null" : value.toString());
413
447
  });
414
448
  const stringifiedParams = normalizedParams.toString();
415
- return stringifiedParams.length > 0 ? `${getProxyPath()}/user?${stringifiedParams}` : `${getProxyPath()}/user`;
449
+ return stringifiedParams.length > 0 ? `${getProxyPath()}/users?${stringifiedParams}` : `${getProxyPath()}/users`;
416
450
  };
417
451
  /**
418
452
  * @summary Create user
@@ -434,7 +468,7 @@ const getListUsersUrl = (params) => {
434
468
  if (value !== void 0) normalizedParams.append(key, value === null ? "null" : value.toString());
435
469
  });
436
470
  const stringifiedParams = normalizedParams.toString();
437
- return stringifiedParams.length > 0 ? `${getProxyPath()}/user?${stringifiedParams}` : `${getProxyPath()}/user`;
471
+ return stringifiedParams.length > 0 ? `${getProxyPath()}/users?${stringifiedParams}` : `${getProxyPath()}/users`;
438
472
  };
439
473
  /**
440
474
  * @summary List users
@@ -451,7 +485,7 @@ const getGetUserByIDUrl = (userId, params) => {
451
485
  if (value !== void 0) normalizedParams.append(key, value === null ? "null" : value.toString());
452
486
  });
453
487
  const stringifiedParams = normalizedParams.toString();
454
- return stringifiedParams.length > 0 ? `${getProxyPath()}/user/${userId}?${stringifiedParams}` : `${getProxyPath()}/user/${userId}`;
488
+ return stringifiedParams.length > 0 ? `${getProxyPath()}/users/${userId}?${stringifiedParams}` : `${getProxyPath()}/users/${userId}`;
455
489
  };
456
490
  /**
457
491
  * @summary Get user by ID
@@ -462,6 +496,40 @@ const getUserByID = async (userId, params, options) => {
462
496
  method: "GET"
463
497
  });
464
498
  };
499
+ const getSetUserPasswordUrl = (userId, params) => {
500
+ const normalizedParams = new URLSearchParams();
501
+ Object.entries(params || {}).forEach(([key, value]) => {
502
+ if (value !== void 0) normalizedParams.append(key, value === null ? "null" : value.toString());
503
+ });
504
+ const stringifiedParams = normalizedParams.toString();
505
+ return stringifiedParams.length > 0 ? `${getProxyPath()}/users/${userId}/password?${stringifiedParams}` : `${getProxyPath()}/users/${userId}/password`;
506
+ };
507
+ /**
508
+ * @summary Set user password
509
+ */
510
+ const setUserPassword = async (userId, setUserPasswordBody, params, options) => {
511
+ return customFetch(getSetUserPasswordUrl(userId, params), {
512
+ ...options,
513
+ method: "PUT",
514
+ headers: {
515
+ "Content-Type": "application/json",
516
+ ...options?.headers
517
+ },
518
+ body: JSON.stringify(setUserPasswordBody)
519
+ });
520
+ };
521
+ const getGetMyUserUrl = () => {
522
+ return `${getProxyPath()}/users/me`;
523
+ };
524
+ /**
525
+ * @summary Get my user information
526
+ */
527
+ const getMyUser = async (options) => {
528
+ return customFetch(getGetMyUserUrl(), {
529
+ ...options,
530
+ method: "GET"
531
+ });
532
+ };
465
533
  const getCreateFlowUrl = () => {
466
534
  return `${getProxyPath()}/flow`;
467
535
  };
@@ -986,28 +1054,38 @@ const listFlowDefinitions = async (params, options) => {
986
1054
  method: "GET"
987
1055
  });
988
1056
  };
989
- const getGetFlowDefinitionUrl = (id) => {
990
- return `${getProxyPath()}/flow_definitions/${id}`;
1057
+ const getGetFlowDefinitionUrl = (id, params) => {
1058
+ const normalizedParams = new URLSearchParams();
1059
+ Object.entries(params || {}).forEach(([key, value]) => {
1060
+ if (value !== void 0) normalizedParams.append(key, value === null ? "null" : value.toString());
1061
+ });
1062
+ const stringifiedParams = normalizedParams.toString();
1063
+ return stringifiedParams.length > 0 ? `${getProxyPath()}/flow_definitions/${id}?${stringifiedParams}` : `${getProxyPath()}/flow_definitions/${id}`;
991
1064
  };
992
1065
  /**
993
1066
  * Get a flow definition by id
994
1067
  * @summary Get a flow definition by id
995
1068
  */
996
- const getFlowDefinition = async (id, options) => {
997
- return customFetch(getGetFlowDefinitionUrl(id), {
1069
+ const getFlowDefinition = async (id, params, options) => {
1070
+ return customFetch(getGetFlowDefinitionUrl(id, params), {
998
1071
  ...options,
999
1072
  method: "GET"
1000
1073
  });
1001
1074
  };
1002
- const getUpdateFlowDefinitionUrl = (id) => {
1003
- return `${getProxyPath()}/flow_definitions/${id}`;
1075
+ const getUpdateFlowDefinitionUrl = (id, params) => {
1076
+ const normalizedParams = new URLSearchParams();
1077
+ Object.entries(params || {}).forEach(([key, value]) => {
1078
+ if (value !== void 0) normalizedParams.append(key, value === null ? "null" : value.toString());
1079
+ });
1080
+ const stringifiedParams = normalizedParams.toString();
1081
+ return stringifiedParams.length > 0 ? `${getProxyPath()}/flow_definitions/${id}?${stringifiedParams}` : `${getProxyPath()}/flow_definitions/${id}`;
1004
1082
  };
1005
1083
  /**
1006
1084
  * Update a flow definition by id
1007
1085
  * @summary Update a flow definition by id
1008
1086
  */
1009
- const updateFlowDefinition = async (id, updateFlowDefinitionBody, options) => {
1010
- return customFetch(getUpdateFlowDefinitionUrl(id), {
1087
+ const updateFlowDefinition = async (id, updateFlowDefinitionBody, params, options) => {
1088
+ return customFetch(getUpdateFlowDefinitionUrl(id, params), {
1011
1089
  ...options,
1012
1090
  method: "PATCH",
1013
1091
  headers: {
@@ -1017,15 +1095,20 @@ const updateFlowDefinition = async (id, updateFlowDefinitionBody, options) => {
1017
1095
  body: JSON.stringify(updateFlowDefinitionBody)
1018
1096
  });
1019
1097
  };
1020
- const getDeleteFlowDefinitionUrl = (id) => {
1021
- return `${getProxyPath()}/flow_definitions/${id}`;
1098
+ const getDeleteFlowDefinitionUrl = (id, params) => {
1099
+ const normalizedParams = new URLSearchParams();
1100
+ Object.entries(params || {}).forEach(([key, value]) => {
1101
+ if (value !== void 0) normalizedParams.append(key, value === null ? "null" : value.toString());
1102
+ });
1103
+ const stringifiedParams = normalizedParams.toString();
1104
+ return stringifiedParams.length > 0 ? `${getProxyPath()}/flow_definitions/${id}?${stringifiedParams}` : `${getProxyPath()}/flow_definitions/${id}`;
1022
1105
  };
1023
1106
  /**
1024
1107
  * Delete a flow definition by id
1025
1108
  * @summary Delete a flow definition by id
1026
1109
  */
1027
- const deleteFlowDefinition = async (id, options) => {
1028
- return customFetch(getDeleteFlowDefinitionUrl(id), {
1110
+ const deleteFlowDefinition = async (id, params, options) => {
1111
+ return customFetch(getDeleteFlowDefinitionUrl(id, params), {
1029
1112
  ...options,
1030
1113
  method: "DELETE"
1031
1114
  });
@@ -1123,10 +1206,29 @@ function createApi(apiBase) {
1123
1206
  }
1124
1207
  //#endregion
1125
1208
  //#region ../api/dist/runtime/config.mjs
1126
- let currentProject = null;
1209
+ /**
1210
+ * Slot for the configured project, stored on `globalThis` under a
1211
+ * {@link Symbol.for} key. Every copy of this module evaluated in the
1212
+ * same JS realm resolves the symbol through the global symbol registry
1213
+ * to the same identity, so they all read and write a single slot —
1214
+ * needed because the standalone components bundle inlines its own copy
1215
+ * of this file, and dual-package hazards / monorepo duplicates can load
1216
+ * a second copy alongside the app's. With a module-local `let` each
1217
+ * instance kept its own singleton and `configureZitadel()` calls in one
1218
+ * were invisible to `getZitadelConfig()` calls in another. Sharing is
1219
+ * realm-scoped — separate realms (iframes, Node `vm` contexts, worker
1220
+ * threads) have their own registries and are not unified by this.
1221
+ */
1222
+ const PROJECT_SLOT = Symbol.for("@zitadel/api/config:currentProject");
1223
+ function readSlot() {
1224
+ return globalThis[PROJECT_SLOT] ?? null;
1225
+ }
1127
1226
  /**
1128
1227
  * Per-project API client cache. Ensures `getApi(project)` returns the
1129
1228
  * same instance for the same project handle — no re-wrapping on every call.
1229
+ * Module-local on purpose: keyed by the shared frozen `ZitadelProject`
1230
+ * object identity, so cross-instance reads still resolve through the
1231
+ * same key and at worst memoize once per module instance.
1130
1232
  */
1131
1233
  const apiCache = /* @__PURE__ */ new WeakMap();
1132
1234
  /**
@@ -1151,37 +1253,82 @@ function getApi(project) {
1151
1253
  * has not been called yet.
1152
1254
  */
1153
1255
  function getZitadelConfig() {
1154
- return currentProject;
1256
+ return readSlot();
1155
1257
  }
1156
1258
  //#endregion
1157
- //#region src/orchestrator/api-client.ts
1158
- const apiRequestInit = { credentials: "include" };
1159
- async function startFlow(api, input) {
1160
- return api.createFlow(input, apiRequestInit);
1161
- }
1162
- async function submitStep(api, id, body) {
1163
- try {
1164
- return await api.submitFlowStep(id, body, apiRequestInit);
1165
- } catch (error) {
1166
- if (error instanceof ApiError && error.status === 400 && isFlowResponse(error.body)) return error.body;
1167
- throw error;
1259
+ //#region src/orchestrator/resolve-api.ts
1260
+ /** Matches the `configureZitadel()` default so attribute and JS config agree. */
1261
+ const DEFAULT_PROXY_PATH = "/__nextgen";
1262
+ /**
1263
+ * Cache of project handles synthesized from attributes, keyed by their value
1264
+ * tuple. `getApi()` caches its client in a `WeakMap` keyed by the project's
1265
+ * identity, so the same attribute values must yield the *same* frozen object
1266
+ * across the several `resolveApi()` calls a single flow makes — otherwise
1267
+ * every call misses the cache and re-wraps a fresh client. A real page uses a
1268
+ * handful of distinct configs at most; the FIFO bound below is just a guard so
1269
+ * a pathological page that churns through unique configs can't leak memory.
1270
+ */
1271
+ const MAX_SYNTHETIC_PROJECTS = 32;
1272
+ const syntheticProjects = /* @__PURE__ */ new Map();
1273
+ /**
1274
+ * Builds a `ZitadelProject` from declarative attributes, or `undefined` when
1275
+ * no `project-id` was given (nothing to configure). Mirrors
1276
+ * `configureZitadel()`'s proxy-path defaulting so the two config paths are
1277
+ * interchangeable.
1278
+ */
1279
+ function projectFromAttrs({ projectId, proxyPath, url }) {
1280
+ if (!projectId) return void 0;
1281
+ const resolvedProxyPath = proxyPath || DEFAULT_PROXY_PATH;
1282
+ const resolvedUrl = url || void 0;
1283
+ const key = JSON.stringify([
1284
+ projectId,
1285
+ resolvedProxyPath,
1286
+ resolvedUrl ?? ""
1287
+ ]);
1288
+ let project = syntheticProjects.get(key);
1289
+ if (!project) {
1290
+ project = Object.freeze({
1291
+ projectId,
1292
+ proxyPath: resolvedProxyPath,
1293
+ url: resolvedUrl
1294
+ });
1295
+ if (syntheticProjects.size >= MAX_SYNTHETIC_PROJECTS) {
1296
+ const oldest = syntheticProjects.keys().next().value;
1297
+ if (oldest !== void 0) syntheticProjects.delete(oldest);
1298
+ }
1299
+ syntheticProjects.set(key, project);
1168
1300
  }
1169
- }
1170
- function isFlowResponse(body) {
1171
- return typeof body === "object" && body !== null && "step" in body;
1172
- }
1173
- async function getCurrentStep(api, id) {
1174
- return api.getFlowStep(id, apiRequestInit);
1301
+ return project;
1175
1302
  }
1176
1303
  /**
1177
- * Exchange a terminal-flow `handoff_token` for an authenticated session.
1178
- * The server sets the `__nextgen_session` HttpOnly cookie on success.
1304
+ * Resolves the effective SDK project handle and its typed API client for an
1305
+ * orchestrator element. Precedence, highest first:
1179
1306
  *
1180
- * Uses the generated `exchangeHandoff` client which handles the
1181
- * `project_id` query parameter via {@link ExchangeHandoffParams}.
1307
+ * 1. the element's `project` property (an SDK handle set from JS / a framework),
1308
+ * 2. the global handle from `configureZitadel()`,
1309
+ * 3. the `project-id` / `proxy-path` / `url` attributes set declaratively in HTML.
1310
+ *
1311
+ * Both JS paths (property and global) win over the declarative attributes, so a
1312
+ * deliberate `configureZitadel()` is never silently overridden by fallback or
1313
+ * stale HTML attributes; the attributes are the no-JS fallback.
1314
+ *
1315
+ * Both `<zitadel-login>` and `<zitadel-logout>` need the same resolution and
1316
+ * the same "no config" failure, so it lives here rather than being copied
1317
+ * into each element. Callers run this inside their try/catch so a missing
1318
+ * configuration surfaces through the element's normal error path rather than
1319
+ * as an unhandled rejection.
1320
+ *
1321
+ * @param project Optional per-element override handle.
1322
+ * @param attrs Declarative config read from the element's attributes.
1323
+ * @param element Tag name used in the thrown error (e.g. `<zitadel-login>`).
1182
1324
  */
1183
- async function exchangeSession(api, body, params) {
1184
- return api.exchangeHandoff(body, params, apiRequestInit);
1325
+ function resolveApi(project, attrs, element) {
1326
+ const cfg = project ?? getZitadelConfig() ?? projectFromAttrs(attrs);
1327
+ if (!cfg) throw new Error(`${element} requires a configured project: set the \`project-id\` attribute, set the \`project\` property, or call configureZitadel().`);
1328
+ return {
1329
+ project: cfg,
1330
+ api: getApi(cfg)
1331
+ };
1185
1332
  }
1186
1333
  //#endregion
1187
1334
  //#region src/orchestrator/branding-to-tokens.ts
@@ -1425,30 +1572,77 @@ function sanitiseUrl(value, field, issues) {
1425
1572
  //#endregion
1426
1573
  //#region src/orchestrator/font-loader.ts
1427
1574
  /**
1428
- * Inject `branding.font_url` as `<link rel="stylesheet">` inside the
1429
- * `<zitadel-login>` Shadow DOM. Per `docs/design/branding/templates.md`:
1575
+ * Document-level font stylesheet injection for `<zitadel-login>`.
1430
1576
  *
1431
- * "The `font_url` stylesheet is injected by the orchestrator; the template
1432
- * does not emit the `<link>` tag itself."
1577
+ * Two faces can be linked into the host document's `<head>`:
1433
1578
  *
1434
- * Idempotent: calling with the same URL is a no-op; calling with a new URL
1435
- * replaces the previous link. Calling with `null`/`undefined` removes any
1436
- * previously injected link.
1579
+ * - The **design-system default** (`applyDefaultFont`) the brand body face
1580
+ * (Arimo, named first in `--zl-font-family-sans`). The component ships this
1581
+ * so the auth screens render in the brand font out of the box, even when the
1582
+ * server returns no branding. This is the "default users can override" layer.
1583
+ * - The **tenant override** (`applyFontUrl`) — `branding.font_url`, resolved
1584
+ * server-side from the app → team → project branding hierarchy.
1585
+ *
1586
+ * Both must live at document level, not inside the shadow root: browsers ignore
1587
+ * `@font-face` rules declared in shadow-tree stylesheets, so a shadow-scoped
1588
+ * link would never register the font faces and every branded font silently
1589
+ * falls back to the system stack. `font-family` references inside the shadow
1590
+ * tree resolve against document-level faces.
1591
+ *
1592
+ * Both injectors are idempotent: calling with the same URL is a no-op; calling
1593
+ * with a new URL replaces the previous link; calling with `null`/`undefined`
1594
+ * removes any previously injected link.
1595
+ */
1596
+ const TENANT_LINK_ID = "zl-font-link";
1597
+ const DEFAULT_LINK_ID = "zl-default-font-link";
1598
+ /**
1599
+ * Design-system default brand font. Arimo is the Figma body face and leads the
1600
+ * `--zl-font-family-sans` stack; loading it here makes the unbranded auth UI
1601
+ * paint in the brand font instead of the system fallback. Tenants override it
1602
+ * with `branding.font_url`. Exported so a privacy- or offline-sensitive
1603
+ * deployment can self-host the same face and swap this single URL.
1604
+ */
1605
+ const DEFAULT_BRAND_FONT_HREF = "https://fonts.googleapis.com/css2?family=Arimo:ital,wght@0,400;0,500;0,600;0,700;1,400&display=swap";
1606
+ /**
1607
+ * Inject the tenant's `branding.font_url` stylesheet. Pass `null`/`undefined`
1608
+ * to remove it (e.g. when a flow resolves with no tenant font).
1437
1609
  */
1438
- const LINK_ID = "zl-font-link";
1439
1610
  function applyFontUrl(shadowRoot, fontUrl) {
1440
- const existing = shadowRoot.getElementById?.(LINK_ID);
1441
- if (!fontUrl) {
1611
+ applyLinkedStylesheet(shadowRoot, TENANT_LINK_ID, fontUrl);
1612
+ }
1613
+ /**
1614
+ * Inject the design-system default font stylesheet. Defaults to
1615
+ * {@link DEFAULT_BRAND_FONT_HREF}; pass `null` to remove it (the orchestrator
1616
+ * does this when a tenant `font_url` takes over, to avoid a redundant request).
1617
+ */
1618
+ function applyDefaultFont(shadowRoot, href = DEFAULT_BRAND_FONT_HREF) {
1619
+ applyLinkedStylesheet(shadowRoot, DEFAULT_LINK_ID, href);
1620
+ }
1621
+ function applyLinkedStylesheet(shadowRoot, linkId, href) {
1622
+ const ownerDocument = shadowRoot.ownerDocument ?? document;
1623
+ const existing = ownerDocument.head.querySelector(`link#${linkId}`);
1624
+ if (!href) {
1442
1625
  existing?.remove();
1443
1626
  return;
1444
1627
  }
1445
- if (existing && existing.href === fontUrl) return;
1446
- existing?.remove();
1447
- const link = (shadowRoot.ownerDocument ?? document).createElement("link");
1448
- link.id = LINK_ID;
1628
+ const link = existing ?? ownerDocument.createElement("link");
1629
+ link.id = linkId;
1449
1630
  link.rel = "stylesheet";
1450
- link.href = fontUrl;
1451
- shadowRoot.prepend(link);
1631
+ if (link.href !== href) link.href = href;
1632
+ if (!existing) ownerDocument.head.appendChild(link);
1633
+ }
1634
+ //#endregion
1635
+ //#region src/internal/escape-html.ts
1636
+ /**
1637
+ * Escapes the five HTML-significant characters so a string is safe to
1638
+ * interpolate into either element text or a double-quoted attribute value.
1639
+ *
1640
+ * Used for the orchestrator-owned attribution markup, which is appended after
1641
+ * the Liquid output has already been sanitised — so it can't rely on the
1642
+ * DOMPurify pass and must escape its own (tenant-supplied) values.
1643
+ */
1644
+ function escapeHtml(value) {
1645
+ return value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
1452
1646
  }
1453
1647
  //#endregion
1454
1648
  //#region src/orchestrator/mandatory-gates.ts
@@ -1468,17 +1662,14 @@ function patchMandatoryGates(html, step, locale) {
1468
1662
  }
1469
1663
  function collectMissingAtoms(fragment, step, locale) {
1470
1664
  const additions = [];
1471
- if (step.fields) for (const [name, field] of Object.entries(step.fields)) {
1665
+ if (step.fields) for (const field of step.fields) {
1472
1666
  if (!field.required) continue;
1473
- if (hasFieldFor(fragment, name)) continue;
1474
- additions.push(buildField(name, field.text_key, field.type, locale, field.required));
1667
+ if (hasFieldFor(fragment, field.name)) continue;
1668
+ additions.push(buildField(field.name, field.text_key, field.type, locale, field.required));
1475
1669
  }
1476
1670
  if (step.actions && !hasPrimaryButton(fragment)) {
1477
- const primary = Object.entries(step.actions).find(([, action]) => action.primary);
1478
- if (primary) {
1479
- const [name, action] = primary;
1480
- additions.push(buildSubmit(name, action.text_key, locale));
1481
- }
1671
+ const primary = step.actions.find((action) => action.primary);
1672
+ if (primary) additions.push(buildSubmit(primary.name, primary.text_key, locale));
1482
1673
  }
1483
1674
  return additions;
1484
1675
  }
@@ -1663,8 +1854,9 @@ const en = {
1663
1854
  "identifier.description": "Enter your email to continue",
1664
1855
  "identifier.field.email": "Work email",
1665
1856
  "identifier.field.email.placeholder": "you@company.com",
1666
- "identifier.action.submit": "Continue",
1667
- "identifier.action.continue": "Continue",
1857
+ "identifier.field.password": "Password",
1858
+ "identifier.action.submit": "Sign in",
1859
+ "identifier.action.continue": "Sign in",
1668
1860
  "identifier.action.passkey": "Sign in with a passkey",
1669
1861
  "identifier.action.register.lead": "Don't have an account? ",
1670
1862
  "identifier.action.register.link": "Sign up",
@@ -1713,13 +1905,18 @@ const en = {
1713
1905
  "password.action.register.lead": "Don't have an account? ",
1714
1906
  "password.action.register.link": "Sign up",
1715
1907
  "register.title": "Create your account",
1716
- "register.description": "Enter your email to get started",
1908
+ "register.description": "",
1717
1909
  "register.field.email": "Work email",
1718
1910
  "register.field.email.placeholder": "you@company.com",
1719
1911
  "register.field.password": "Password",
1720
1912
  "register.field.password.help": "At least 8 characters, including a symbol and number.",
1913
+ "register.field.givenName": "Given name",
1914
+ "register.field.familyName": "Family name",
1915
+ "register.field.dateOfBirth": "Date of birth",
1916
+ "register.field.dateOfBirth.placeholder": "YYYY-MM-DD",
1917
+ "register.field.dateOfBirth.help": "Use YYYY-MM-DD.",
1721
1918
  "register.action.password": "Continue with password",
1722
- "register.action.passkey": "Register with a passkey",
1919
+ "register.action.passkey": "Continue with a passkey",
1723
1920
  "register.action.submit": "Sign up",
1724
1921
  "register.action.sign_in.lead": "Already have an account? ",
1725
1922
  "register.action.sign_in.link": "Sign in",
@@ -1758,8 +1955,9 @@ const de = {
1758
1955
  "identifier.description": "Gib deine E-Mail-Adresse ein, um fortzufahren",
1759
1956
  "identifier.field.email": "E-Mail",
1760
1957
  "identifier.field.email.placeholder": "du@unternehmen.com",
1761
- "identifier.action.submit": "Weiter",
1762
- "identifier.action.continue": "Weiter",
1958
+ "identifier.field.password": "Passwort",
1959
+ "identifier.action.submit": "Anmelden",
1960
+ "identifier.action.continue": "Anmelden",
1763
1961
  "identifier.action.passkey": "Mit Passkey anmelden",
1764
1962
  "identifier.action.register.lead": "Noch kein Konto? ",
1765
1963
  "identifier.action.register.link": "Registrieren",
@@ -1808,13 +2006,18 @@ const de = {
1808
2006
  "password.action.register.lead": "Noch kein Konto? ",
1809
2007
  "password.action.register.link": "Registrieren",
1810
2008
  "register.title": "Konto erstellen",
1811
- "register.description": "Gib deine E-Mail-Adresse ein, um loszulegen",
2009
+ "register.description": "",
1812
2010
  "register.field.email": "E-Mail",
1813
2011
  "register.field.email.placeholder": "du@unternehmen.com",
1814
2012
  "register.field.password": "Passwort",
1815
2013
  "register.field.password.help": "Mindestens 8 Zeichen, einschließlich eines Sonderzeichens und einer Zahl.",
2014
+ "register.field.givenName": "Vorname",
2015
+ "register.field.familyName": "Nachname",
2016
+ "register.field.dateOfBirth": "Geburtsdatum",
2017
+ "register.field.dateOfBirth.placeholder": "JJJJ-MM-TT",
2018
+ "register.field.dateOfBirth.help": "Verwende JJJJ-MM-TT.",
1816
2019
  "register.action.password": "Mit Passwort fortfahren",
1817
- "register.action.passkey": "Mit Passkey registrieren",
2020
+ "register.action.passkey": "Weiter mit Passkey",
1818
2021
  "register.action.submit": "Registrieren",
1819
2022
  "register.action.sign_in.lead": "Bereits ein Konto? ",
1820
2023
  "register.action.sign_in.link": "Anmelden",
@@ -1852,8 +2055,9 @@ const it = {
1852
2055
  "identifier.description": "Inserisci la tua e-mail per continuare",
1853
2056
  "identifier.field.email": "E-mail aziendale",
1854
2057
  "identifier.field.email.placeholder": "tu@azienda.com",
1855
- "identifier.action.submit": "Continua",
1856
- "identifier.action.continue": "Continua",
2058
+ "identifier.field.password": "Password",
2059
+ "identifier.action.submit": "Accedi",
2060
+ "identifier.action.continue": "Accedi",
1857
2061
  "identifier.action.passkey": "Accedi con passkey",
1858
2062
  "identifier.action.register.lead": "Non hai un account? ",
1859
2063
  "identifier.action.register.link": "Registrati",
@@ -1902,13 +2106,18 @@ const it = {
1902
2106
  "password.action.register.lead": "Non hai un account? ",
1903
2107
  "password.action.register.link": "Registrati",
1904
2108
  "register.title": "Crea il tuo account",
1905
- "register.description": "Inserisci la tua e-mail per iniziare",
2109
+ "register.description": "",
1906
2110
  "register.field.email": "E-mail aziendale",
1907
2111
  "register.field.email.placeholder": "tu@azienda.com",
1908
2112
  "register.field.password": "Password",
1909
2113
  "register.field.password.help": "Almeno 8 caratteri, incluso un simbolo e un numero.",
2114
+ "register.field.givenName": "Nome",
2115
+ "register.field.familyName": "Cognome",
2116
+ "register.field.dateOfBirth": "Data di nascita",
2117
+ "register.field.dateOfBirth.placeholder": "AAAA-MM-GG",
2118
+ "register.field.dateOfBirth.help": "Usa AAAA-MM-GG.",
1910
2119
  "register.action.password": "Continua con password",
1911
- "register.action.passkey": "Registrati con passkey",
2120
+ "register.action.passkey": "Continua con passkey",
1912
2121
  "register.action.submit": "Registrati",
1913
2122
  "register.action.sign_in.lead": "Hai già un account? ",
1914
2123
  "register.action.sign_in.link": "Accedi",
@@ -2035,6 +2244,7 @@ const COMMON_ATTRS = [
2035
2244
  "style",
2036
2245
  "name",
2037
2246
  "for",
2247
+ "data-testid",
2038
2248
  "data-theme",
2039
2249
  "hidden"
2040
2250
  ];
@@ -2092,7 +2302,7 @@ function createSanitiser() {
2092
2302
  }
2093
2303
  //#endregion
2094
2304
  //#region src/orchestrator/templates/layout-chrome.css?inline
2095
- var layout_chrome_default = ":host {\n background: var(--zl-color-surface-default-black, #0f0f11);\n min-height: 100%;\n color: var(--zl-color-text-primary-white, #f4f4f6);\n font-family: var(--zl-font-family-sans, system-ui, sans-serif);\n display: block;\n}\n\n.zl-mount {\n background: inherit;\n min-height: 100vh;\n color: inherit;\n flex-direction: column;\n display: flex;\n}\n\n.zl-mount > zl-page-shell, .zl-mount > [data-zl-template-root] {\n flex: auto;\n}\n\n.zl-attribution {\n background: none;\n justify-content: center;\n align-items: center;\n display: flex;\n}\n\n.zl-attribution[hidden] {\n display: none;\n}\n\n.zl-card-title {\n font-family: var(--zl-font-family-heading, var(--zl-font-family-sans, system-ui, sans-serif));\n letter-spacing: -.02em;\n color: var(--zl-color-text-primary-white, #f4f4f6);\n text-align: left;\n margin: 0;\n font-size: 2rem;\n font-weight: 400;\n line-height: 2.5rem;\n}\n\n.zl-card-subtitle {\n font-family: var(--zl-font-family-sans, system-ui, sans-serif);\n color: var(--zl-color-text-primary-white, #f4f4f6);\n margin: 0;\n font-size: .875rem;\n font-weight: 400;\n line-height: 1.25rem;\n}\n\n.zl-card-nav {\n font-family: var(--zl-font-family-sans, system-ui, sans-serif);\n color: var(--zl-color-text-primary-white, #f4f4f6);\n text-align: left;\n margin: 0;\n font-size: 1rem;\n font-weight: 400;\n line-height: 1.5rem;\n}\n\n.zl-card-nav__link {\n font: inherit;\n line-height: inherit;\n color: var(--zl-color-icon-default-purple, #bba5e4);\n cursor: pointer;\n background: none;\n border: none;\n margin: 0;\n padding: 0;\n text-decoration: none;\n display: inline;\n}\n\n.zl-card-nav__link:hover {\n text-decoration: underline;\n}\n\n.zl-card-nav__link:focus-visible {\n outline: var(--zl-focus-width, 2px) solid var(--zl-focus-color, #f4f4f6);\n outline-offset: var(--zl-focus-offset, 2px);\n}\n\n.zl-card-forgot {\n text-align: left;\n margin: 0;\n}\n\n.zl-card-forgot__link {\n font-family: var(--zl-font-family-sans, system-ui, sans-serif);\n color: var(--zl-color-icon-default-purple, #bba5e4);\n cursor: pointer;\n background: none;\n border: none;\n margin: 0;\n padding: 0;\n font-size: 1rem;\n font-weight: 400;\n line-height: 1.5rem;\n text-decoration: none;\n display: inline;\n}\n\n.zl-card-forgot__link:hover {\n text-decoration: underline;\n}\n\n.zl-card-forgot__link:focus-visible {\n outline: var(--zl-focus-width, 2px) solid var(--zl-focus-color, #f4f4f6);\n outline-offset: var(--zl-focus-offset, 2px);\n}\n";
2305
+ var layout_chrome_default = ":host {\n background: var(--zl-color-surface-default-black, #0f0f11);\n min-height: 100%;\n color: var(--zl-color-text-primary-white, #f4f4f6);\n font-family: var(--zl-font-family-sans, system-ui, sans-serif);\n display: block;\n}\n\n.zl-mount {\n background: inherit;\n min-height: 100vh;\n color: inherit;\n flex-direction: column;\n display: flex;\n}\n\n.zl-mount > zl-page-shell, .zl-mount > [data-zl-template-root] {\n flex: auto;\n}\n\n.zl-attribution {\n background: none;\n justify-content: center;\n align-items: center;\n display: flex;\n}\n\n.zl-attribution[hidden] {\n display: none;\n}\n\n.zl-card-title {\n font-family: var(--zl-font-family-heading, var(--zl-font-family-sans, system-ui, sans-serif));\n letter-spacing: -.02em;\n color: var(--zl-color-text-primary-white, #f4f4f6);\n text-align: left;\n margin: 0;\n font-size: 2rem;\n font-weight: 700;\n line-height: 2.5rem;\n}\n\n.zl-card-subtitle {\n font-family: var(--zl-font-family-sans, system-ui, sans-serif);\n color: var(--zl-color-text-primary-white, #f4f4f6);\n margin: 0;\n font-size: .875rem;\n font-weight: 400;\n line-height: 1.25rem;\n}\n\n.zl-card-nav {\n font-family: var(--zl-font-family-sans, system-ui, sans-serif);\n color: var(--zl-color-text-primary-white, #f4f4f6);\n text-align: left;\n margin: 0;\n font-size: 1rem;\n font-weight: 400;\n line-height: 1.5rem;\n}\n\n.zl-card-nav__link {\n font: inherit;\n line-height: inherit;\n color: var(--zl-color-icon-default-purple, #bba5e4);\n cursor: pointer;\n background: none;\n border: none;\n margin: 0;\n padding: 0;\n text-decoration: none;\n display: inline;\n}\n\n.zl-card-nav__link:hover {\n text-decoration: underline;\n}\n\n.zl-card-nav__link:focus-visible {\n outline: var(--zl-focus-width, 2px) solid var(--zl-focus-color, #f4f4f6);\n outline-offset: var(--zl-focus-offset, 2px);\n}\n\n.zl-card-forgot {\n text-align: left;\n margin: 0;\n}\n\n.zl-card-forgot__link {\n font-family: var(--zl-font-family-sans, system-ui, sans-serif);\n color: var(--zl-color-icon-default-purple, #bba5e4);\n cursor: pointer;\n background: none;\n border: none;\n margin: 0;\n padding: 0;\n font-size: 1rem;\n font-weight: 400;\n line-height: 1.5rem;\n text-decoration: none;\n display: inline;\n}\n\n.zl-card-forgot__link:hover {\n text-decoration: underline;\n}\n\n.zl-card-forgot__link:focus-visible {\n outline: var(--zl-focus-width, 2px) solid var(--zl-focus-color, #f4f4f6);\n outline-offset: var(--zl-focus-offset, 2px);\n}\n";
2096
2306
  //#endregion
2097
2307
  //#region src/orchestrator/theme-controller.ts
2098
2308
  const DARK_QUERY = "(prefers-color-scheme: dark)";
@@ -2175,6 +2385,27 @@ let ZitadelLogin = class ZitadelLogin extends LitElement {
2175
2385
  set project(value) {
2176
2386
  this.#_project_accessor_storage = value;
2177
2387
  }
2388
+ #_projectId_accessor_storage = "";
2389
+ get projectId() {
2390
+ return this.#_projectId_accessor_storage;
2391
+ }
2392
+ set projectId(value) {
2393
+ this.#_projectId_accessor_storage = value;
2394
+ }
2395
+ #_proxyPath_accessor_storage = "";
2396
+ get proxyPath() {
2397
+ return this.#_proxyPath_accessor_storage;
2398
+ }
2399
+ set proxyPath(value) {
2400
+ this.#_proxyPath_accessor_storage = value;
2401
+ }
2402
+ #_url_accessor_storage = "";
2403
+ get url() {
2404
+ return this.#_url_accessor_storage;
2405
+ }
2406
+ set url(value) {
2407
+ this.#_url_accessor_storage = value;
2408
+ }
2178
2409
  #_postSignInUrl_accessor_storage = "";
2179
2410
  get postSignInUrl() {
2180
2411
  return this.#_postSignInUrl_accessor_storage;
@@ -2299,7 +2530,9 @@ let ZitadelLogin = class ZitadelLogin extends LitElement {
2299
2530
  if (root) {
2300
2531
  applyBaseTokens(root);
2301
2532
  applyBrandingTokens(root, this.branding, this.themeController.theme);
2302
- applyFontUrl(root, this.branding?.font_url ?? null);
2533
+ const tenantFontUrl = this.branding?.font_url ?? null;
2534
+ applyDefaultFont(root, tenantFontUrl ? null : void 0);
2535
+ applyFontUrl(root, tenantFontUrl);
2303
2536
  }
2304
2537
  this.dataset.theme = this.themeController.theme;
2305
2538
  this.toggleAttribute("data-theme-dark", this.themeController.theme === "dark");
@@ -2307,10 +2540,21 @@ let ZitadelLogin = class ZitadelLogin extends LitElement {
2307
2540
  }
2308
2541
  updated(changed) {
2309
2542
  if (!changed.has("response")) return;
2310
- requestAnimationFrame(() => {
2311
- this.applyValuesToFields();
2312
- this.moveFocusToFirstField();
2313
- });
2543
+ this.hydrateStepAfterRender();
2544
+ }
2545
+ /**
2546
+ * Apply captured values and move focus once the new step has fully
2547
+ * rendered. This commit produces the step's `zl-field`/`zl-button` atoms,
2548
+ * but those render their own shadow DOM on a later microtask — so await
2549
+ * this element's update *and* the child atoms' first render before touching
2550
+ * them, rather than guessing a frame with `requestAnimationFrame`.
2551
+ */
2552
+ async hydrateStepAfterRender() {
2553
+ await this.updateComplete;
2554
+ const atoms = this.shadowRoot?.querySelectorAll("zl-field, zl-button");
2555
+ if (atoms) await Promise.all(Array.from(atoms).map((atom) => atom.updateComplete));
2556
+ this.applyValuesToFields();
2557
+ this.moveFocusToFirstField();
2314
2558
  }
2315
2559
  render() {
2316
2560
  if (this.startupError) return html`<form class="zl-mount" novalidate>
@@ -2334,6 +2578,10 @@ let ZitadelLogin = class ZitadelLogin extends LitElement {
2334
2578
  * Figma sign-in frame where the pill sits 24px below the card, both
2335
2579
  * centred on the page). It can't be a sibling of the page-shell because
2336
2580
  * the page-shell already occupies the full viewport height.
2581
+ *
2582
+ * This markup is appended AFTER `renderStep` has sanitised the Liquid
2583
+ * output, so it is not run through DOMPurify. It is orchestrator-owned and
2584
+ * any tenant-supplied values (`custom_link`) are escaped via `escapeHtml`.
2337
2585
  */
2338
2586
  injectAttribution(rendered) {
2339
2587
  const html = this.renderAttributionHtml();
@@ -2353,23 +2601,28 @@ let ZitadelLogin = class ZitadelLogin extends LitElement {
2353
2601
  const show = attribution?.show_zitadel !== false;
2354
2602
  const custom = attribution?.custom_link;
2355
2603
  if (!show && !custom) return "";
2356
- if (custom) return `<div slot="footer" part="attribution" class="zl-attribution"><zl-pill tone="neutral" href="${String(custom.href).replace(/"/g, "&quot;")}">${String(custom.label).replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")}</zl-pill></div>`;
2604
+ if (custom) return `<div slot="footer" part="attribution" class="zl-attribution"><zl-pill tone="neutral" href="${escapeHtml(String(custom.href))}">${escapeHtml(String(custom.label))}</zl-pill></div>`;
2357
2605
  return `<div slot="footer" part="attribution" class="zl-attribution"><zl-pill tone="neutral" href="https://zitadel.com" part="attribution-pill" aria-label="Secured with Zitadel">${zitadelAttributionPillInnerHtml()}</zl-pill></div>`;
2358
2606
  }
2607
+ /** Declarative config read from this element's attributes. */
2608
+ get projectAttrs() {
2609
+ return {
2610
+ projectId: this.projectId,
2611
+ proxyPath: this.proxyPath,
2612
+ url: this.url
2613
+ };
2614
+ }
2359
2615
  async startFlow() {
2360
- const cfg = this.project ?? getZitadelConfig();
2361
- const projectId = cfg?.projectId || "";
2362
- if (!cfg) throw new Error("<zitadel-login> requires a `config` prop (from configureZitadel()) or configureZitadel() must be called before use.");
2363
- const api = getApi(cfg);
2364
2616
  this.loading = true;
2365
2617
  this.startupError = null;
2366
2618
  try {
2619
+ const { project: cfg, api } = resolveApi(this.project, this.projectAttrs, "<zitadel-login>");
2367
2620
  let wire;
2368
2621
  if (this.resumeFlowId) wire = await getCurrentStep(api, this.resumeFlowId);
2369
2622
  else {
2370
- if (!projectId) throw new Error("<zitadel-login> requires a `project-id` attribute (or configureZitadel()) to start a flow.");
2623
+ if (!cfg.projectId) throw new Error("<zitadel-login> requires a project id (the `project-id` attribute, `configureZitadel({ projectId })`, or a `project` handle) to start a flow.");
2371
2624
  wire = await startFlow(api, {
2372
- project_id: projectId,
2625
+ project_id: cfg.projectId,
2373
2626
  purpose: this.purpose
2374
2627
  });
2375
2628
  }
@@ -2407,16 +2660,12 @@ let ZitadelLogin = class ZitadelLogin extends LitElement {
2407
2660
  async maybeCompleteFlow(response) {
2408
2661
  const behavior = response.step.complete;
2409
2662
  if (!behavior) return;
2410
- this.dispatchEvent(new CustomEvent("zitadel-flow-complete", {
2411
- bubbles: true,
2412
- composed: true,
2413
- detail: {
2414
- behavior,
2415
- redirect_uri: response.redirect_uri,
2416
- handoff_token: response.handoff_token,
2417
- handoff_token_expires_at: response.handoff_token_expires_at
2418
- }
2419
- }));
2663
+ emit(this, "zitadel-flow-complete", {
2664
+ behavior,
2665
+ redirect_uri: response.redirect_uri,
2666
+ handoff_token: response.handoff_token,
2667
+ handoff_token_expires_at: response.handoff_token_expires_at
2668
+ });
2420
2669
  if (typeof window === "undefined") return;
2421
2670
  if (behavior === "redirect" && response.redirect_uri) {
2422
2671
  window.location.assign(response.redirect_uri);
@@ -2426,9 +2675,8 @@ let ZitadelLogin = class ZitadelLogin extends LitElement {
2426
2675
  if (behavior === "show" && handoffToken && this.postSignInUrl) {
2427
2676
  this.loading = true;
2428
2677
  try {
2429
- const cfg = this.project ?? getZitadelConfig();
2430
- if (!cfg) throw new Error("<zitadel-login> config is required for exchange.");
2431
- await exchangeSession(getApi(cfg), { handoff_token: handoffToken }, { project_id: cfg.projectId });
2678
+ const { project: cfg, api } = resolveApi(this.project, this.projectAttrs, "<zitadel-login>");
2679
+ await exchangeSession(api, { handoff_token: handoffToken }, { project_id: cfg.projectId });
2432
2680
  window.location.assign(this.postSignInUrl);
2433
2681
  } catch (error) {
2434
2682
  this.handleTransportError(error);
@@ -2440,14 +2688,16 @@ let ZitadelLogin = class ZitadelLogin extends LitElement {
2440
2688
  renderStep(step, engine) {
2441
2689
  const tenantSource = typeof this.branding?.liquid_template === "string" && this.branding.liquid_template.length > 0 ? this.branding.liquid_template : null;
2442
2690
  const errors = step.error ? step.error.startsWith("error.") ? [{ text_key: step.error }] : [{ message: step.error }] : [];
2691
+ const fields = step.fields ?? [];
2692
+ const actions = step.actions ?? [];
2443
2693
  const context = {
2444
2694
  step: {
2445
2695
  name: step.name,
2446
2696
  complete: step.complete,
2447
2697
  texts: step.texts ?? {}
2448
2698
  },
2449
- fields: step.fields ?? {},
2450
- actions: step.actions ?? {},
2699
+ fields,
2700
+ actions,
2451
2701
  gates: step.gates ?? {},
2452
2702
  sso_providers: step.sso_providers ?? [],
2453
2703
  challenge: step.challenge ?? null,
@@ -2506,6 +2756,31 @@ let ZitadelLogin = class ZitadelLogin extends LitElement {
2506
2756
  if (field.value !== next) field.value = next;
2507
2757
  }
2508
2758
  }
2759
+ captureValuesFromFields() {
2760
+ const root = this.shadowRoot;
2761
+ if (!root) return this.formValues;
2762
+ const fields = root.querySelectorAll("zl-field");
2763
+ if (fields.length === 0) return this.formValues;
2764
+ const next = { ...this.formValues };
2765
+ let changed = false;
2766
+ for (const field of fields) {
2767
+ const name = field.getAttribute("name");
2768
+ const value = this.currentFieldValue(field);
2769
+ if (!name || value === void 0) continue;
2770
+ if (field.value !== value) field.value = value;
2771
+ if (next[name] !== value) {
2772
+ next[name] = value;
2773
+ changed = true;
2774
+ }
2775
+ }
2776
+ if (changed) this.formValues = next;
2777
+ return next;
2778
+ }
2779
+ currentFieldValue(field) {
2780
+ const native = field.shadowRoot?.querySelector("input");
2781
+ if (native && native.value !== field.value) return native.value;
2782
+ return typeof field.value === "string" ? field.value : void 0;
2783
+ }
2509
2784
  handleAtomInput = (event) => {
2510
2785
  if (!event.detail) return;
2511
2786
  const { name, value } = event.detail;
@@ -2514,15 +2789,23 @@ let ZitadelLogin = class ZitadelLogin extends LitElement {
2514
2789
  ...this.formValues,
2515
2790
  [name]: value
2516
2791
  };
2517
- this.dispatchEvent(new CustomEvent("zitadel-flow-input", {
2518
- bubbles: true,
2519
- composed: true,
2520
- detail: {
2521
- name,
2522
- value
2523
- }
2524
- }));
2792
+ this.syncFieldElementValue(name, value);
2793
+ emit(this, "zitadel-flow-input", {
2794
+ name,
2795
+ value
2796
+ });
2525
2797
  };
2798
+ syncFieldElementValue(name, value) {
2799
+ const root = this.shadowRoot;
2800
+ if (!root) return;
2801
+ const fields = root.querySelectorAll("zl-field");
2802
+ for (const field of fields) {
2803
+ if (field.getAttribute("name") !== name) continue;
2804
+ if (field.value !== value) field.value = value;
2805
+ const native = field.shadowRoot?.querySelector("input");
2806
+ if (native && native.value !== value) native.value = value;
2807
+ }
2808
+ }
2526
2809
  handleAtomSubmit = (event) => {
2527
2810
  if (this.loading) return;
2528
2811
  this.submit(event.detail?.action ?? null);
@@ -2592,21 +2875,20 @@ let ZitadelLogin = class ZitadelLogin extends LitElement {
2592
2875
  moveFocusToFirstField() {
2593
2876
  const root = this.shadowRoot;
2594
2877
  if (!root) return;
2595
- requestAnimationFrame(() => {
2596
- const focusables = root.querySelectorAll("zl-field, zl-button");
2597
- Array.from(focusables).find((el) => !el.hasAttribute("disabled"))?.focus();
2598
- });
2878
+ const focusables = root.querySelectorAll("zl-field, zl-button");
2879
+ Array.from(focusables).find((el) => !el.hasAttribute("disabled"))?.focus();
2599
2880
  }
2600
2881
  async submit(action, challengeResponse) {
2601
2882
  if (!this.response || this.loading) return;
2602
2883
  const { id, session_token } = this.response;
2603
2884
  this.loading = true;
2604
2885
  try {
2605
- const stepFieldKeys = Object.keys(this.response.step.fields ?? {});
2886
+ const formValues = this.captureValuesFromFields();
2887
+ const stepFields = this.response.step.fields ?? [];
2606
2888
  const fields = {};
2607
- for (const key of stepFieldKeys) {
2608
- const value = this.formValues[key];
2609
- if (value !== void 0) fields[key] = value;
2889
+ for (const f of stepFields) {
2890
+ const value = formValues[f.name];
2891
+ if (value !== void 0) fields[f.name] = value;
2610
2892
  }
2611
2893
  const body = {
2612
2894
  session_token,
@@ -2614,15 +2896,10 @@ let ZitadelLogin = class ZitadelLogin extends LitElement {
2614
2896
  fields,
2615
2897
  ...challengeResponse ? { challenge_response: challengeResponse } : {}
2616
2898
  };
2617
- const cfg = this.project ?? getZitadelConfig();
2618
- if (!cfg) throw new Error("<zitadel-login> config is required for submit.");
2619
- const wire = await submitStep(getApi(cfg), id, body);
2899
+ const { api } = resolveApi(this.project, this.projectAttrs, "<zitadel-login>");
2900
+ const wire = await submitStep(api, id, body);
2620
2901
  this.applyResponse(wire);
2621
- this.dispatchEvent(new CustomEvent("zitadel-flow-step", {
2622
- bubbles: true,
2623
- composed: true,
2624
- detail: { step: wire.step }
2625
- }));
2902
+ emit(this, "zitadel-flow-step", { step: wire.step });
2626
2903
  } catch (error) {
2627
2904
  this.handleTransportError(error);
2628
2905
  } finally {
@@ -2633,15 +2910,20 @@ let ZitadelLogin = class ZitadelLogin extends LitElement {
2633
2910
  const message = error instanceof Error ? error.message : "Unexpected error contacting the Flow API.";
2634
2911
  this.startupError = message;
2635
2912
  console.error("[zitadel-login]", error);
2636
- this.dispatchEvent(new CustomEvent("zitadel-flow-error", {
2637
- bubbles: true,
2638
- composed: true,
2639
- detail: { message }
2640
- }));
2913
+ emit(this, "zitadel-flow-error", { message });
2641
2914
  }
2642
2915
  };
2643
2916
  __decorate([property({ type: String })], ZitadelLogin.prototype, "purpose", null);
2644
2917
  __decorate([property({ attribute: false })], ZitadelLogin.prototype, "project", null);
2918
+ __decorate([property({
2919
+ type: String,
2920
+ attribute: "project-id"
2921
+ })], ZitadelLogin.prototype, "projectId", null);
2922
+ __decorate([property({
2923
+ type: String,
2924
+ attribute: "proxy-path"
2925
+ })], ZitadelLogin.prototype, "proxyPath", null);
2926
+ __decorate([property({ type: String })], ZitadelLogin.prototype, "url", null);
2645
2927
  __decorate([property({
2646
2928
  type: String,
2647
2929
  attribute: "post-sign-in-url"
@@ -2661,7 +2943,7 @@ ZitadelLogin = __decorate([customElement("zitadel-login")], ZitadelLogin);
2661
2943
  function collectInitialValues(step) {
2662
2944
  const values = {};
2663
2945
  if (!step.fields) return values;
2664
- for (const [name, field] of Object.entries(step.fields)) values[name] = typeof field.value === "string" ? field.value : "";
2946
+ for (const field of step.fields) values[field.name] = typeof field.value === "string" ? field.value : "";
2665
2947
  return values;
2666
2948
  }
2667
2949
  //#endregion
@@ -2812,6 +3094,27 @@ let ZitadelLogout = class ZitadelLogout extends LitElement {
2812
3094
  set project(value) {
2813
3095
  this.#_project_accessor_storage = value;
2814
3096
  }
3097
+ #_projectId_accessor_storage = "";
3098
+ get projectId() {
3099
+ return this.#_projectId_accessor_storage;
3100
+ }
3101
+ set projectId(value) {
3102
+ this.#_projectId_accessor_storage = value;
3103
+ }
3104
+ #_proxyPath_accessor_storage = "";
3105
+ get proxyPath() {
3106
+ return this.#_proxyPath_accessor_storage;
3107
+ }
3108
+ set proxyPath(value) {
3109
+ this.#_proxyPath_accessor_storage = value;
3110
+ }
3111
+ #_url_accessor_storage = "";
3112
+ get url() {
3113
+ return this.#_url_accessor_storage;
3114
+ }
3115
+ set url(value) {
3116
+ this.#_url_accessor_storage = value;
3117
+ }
2815
3118
  #_postSignOutUrl_accessor_storage = "";
2816
3119
  get postSignOutUrl() {
2817
3120
  return this.#_postSignOutUrl_accessor_storage;
@@ -2943,13 +3246,20 @@ let ZitadelLogout = class ZitadelLogout extends LitElement {
2943
3246
  * clears the cookie via `Set-Cookie: Max-Age=0`. On success this element fires
2944
3247
  * `zitadel-signout` and optionally navigates to `postSignOutUrl`.
2945
3248
  */
3249
+ /** Declarative config read from this element's attributes. */
3250
+ get projectAttrs() {
3251
+ return {
3252
+ projectId: this.projectId,
3253
+ proxyPath: this.proxyPath,
3254
+ url: this.url
3255
+ };
3256
+ }
2946
3257
  async doLogout() {
2947
3258
  this.loading = true;
2948
3259
  this.errorMessage = "";
2949
3260
  try {
2950
- const cfg = this.project ?? getZitadelConfig();
2951
- if (!cfg) throw new Error("<zitadel-logout> requires a `config` prop (from configureZitadel()).");
2952
- await getApi(cfg).revokeMySession({ credentials: "include" });
3261
+ const { api } = resolveApi(this.project, this.projectAttrs, "<zitadel-logout>");
3262
+ await api.revokeMySession({ credentials: "include" });
2953
3263
  } catch (error) {
2954
3264
  const message = error instanceof Error ? error.message : "";
2955
3265
  this.errorMessage = message || "Sign-out failed. Please try again.";
@@ -2958,15 +3268,10 @@ let ZitadelLogout = class ZitadelLogout extends LitElement {
2958
3268
  }
2959
3269
  this.open = false;
2960
3270
  this.loading = false;
2961
- const detail = {
3271
+ emit(this, "zitadel-signout", {
2962
3272
  name: this.displayName,
2963
3273
  email: this.displayEmail
2964
- };
2965
- this.dispatchEvent(new CustomEvent("zitadel-signout", {
2966
- bubbles: true,
2967
- composed: true,
2968
- detail
2969
- }));
3274
+ });
2970
3275
  if (this.postSignOutUrl && typeof window !== "undefined") window.location.href = this.postSignOutUrl;
2971
3276
  }
2972
3277
  /**
@@ -2980,9 +3285,8 @@ let ZitadelLogout = class ZitadelLogout extends LitElement {
2980
3285
  ...this.clientId ? { client_id: this.clientId } : {},
2981
3286
  ...this.postSignOutUrl ? { post_logout_redirect_uri: this.postSignOutUrl } : {}
2982
3287
  };
2983
- const cfg = this.project ?? getZitadelConfig();
2984
- if (!cfg) throw new Error("<zitadel-logout> requires a `config` prop (from configureZitadel()).");
2985
- return getApi(cfg).getEndSessionUrl(params);
3288
+ const { api } = resolveApi(this.project, this.projectAttrs, "<zitadel-logout>");
3289
+ return api.getEndSessionUrl(params);
2986
3290
  }
2987
3291
  handleSignOutClick(event) {
2988
3292
  event.preventDefault();
@@ -3047,6 +3351,15 @@ let ZitadelLogout = class ZitadelLogout extends LitElement {
3047
3351
  }
3048
3352
  };
3049
3353
  __decorate([property({ attribute: false })], ZitadelLogout.prototype, "project", null);
3354
+ __decorate([property({
3355
+ type: String,
3356
+ attribute: "project-id"
3357
+ })], ZitadelLogout.prototype, "projectId", null);
3358
+ __decorate([property({
3359
+ type: String,
3360
+ attribute: "proxy-path"
3361
+ })], ZitadelLogout.prototype, "proxyPath", null);
3362
+ __decorate([property({ type: String })], ZitadelLogout.prototype, "url", null);
3050
3363
  __decorate([property({
3051
3364
  type: String,
3052
3365
  attribute: "post-sign-out-url"
@@ -3077,4 +3390,4 @@ function fillTemplateTokens(fragment, name, email, initial) {
3077
3390
  //#endregion
3078
3391
  export { buildBrandingStylesheet as _, createSanitiser as a, startFlow as b, de as c, MANDATORY_GATES_MARKER as d, mandatoryGatesMarkerComment as f, applyBrandingTokens as g, validateBranding as h, layout_chrome_default as i, en as l, applyFontUrl as m, ZitadelLogin as n, builtinLocales as o, patchMandatoryGates as p, ThemeController as r, it as s, ZitadelLogout as t, TEMPLATE_NAMES as u, resolveTheme as v, submitStep as x, getCurrentStep as y };
3079
3392
 
3080
- //# sourceMappingURL=orchestrator-B8eXcPRi.mjs.map
3393
+ //# sourceMappingURL=orchestrator-BeTmVk54.mjs.map