@zitadel/testing 0.0.0

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.
@@ -0,0 +1,2356 @@
1
+ const require_handshake = require("./handshake-CggSIoxF.cjs");
2
+ require("node:fs");
3
+ require("node:url");
4
+ let node_fs_promises = require("node:fs/promises");
5
+ let node_os = require("node:os");
6
+ let node_path = require("node:path");
7
+ let node_child_process = require("node:child_process");
8
+ let node_module = require("node:module");
9
+ let node_net = require("node:net");
10
+ let node_crypto = require("node:crypto");
11
+ //#region ../api/dist/runtime/base-url.mjs
12
+ let proxyPath = "";
13
+ function getProxyPath() {
14
+ return proxyPath;
15
+ }
16
+ function setProxyPath(path) {
17
+ proxyPath = path;
18
+ }
19
+ //#endregion
20
+ //#region ../api/dist/runtime/auth.mjs
21
+ /**
22
+ * Module-global bearer token used by the orval-generated client's
23
+ * custom fetch. Set once at command boot (the same lifecycle pattern
24
+ * as `base-url.ts`); every generated request reads from here.
25
+ *
26
+ * Keeping the token here means the CLI doesn't have to thread an
27
+ * `Authorization` header through every generated call site; orval's
28
+ * `mutator` wires `runtime/fetch.ts` in, and that file pulls the token
29
+ * from this module.
30
+ */
31
+ let apiAuthToken;
32
+ function getApiAuthToken() {
33
+ return apiAuthToken;
34
+ }
35
+ function setApiAuthToken(token) {
36
+ apiAuthToken = token;
37
+ }
38
+ //#endregion
39
+ //#region ../api/dist/chunk-CfYAbeIz.mjs
40
+ var __defProp = Object.defineProperty;
41
+ var __exportAll = (all, no_symbols) => {
42
+ let target = {};
43
+ for (var name in all) __defProp(target, name, {
44
+ get: all[name],
45
+ enumerable: true
46
+ });
47
+ if (!no_symbols) __defProp(target, Symbol.toStringTag, { value: "Module" });
48
+ return target;
49
+ };
50
+ //#endregion
51
+ //#region ../api/dist/runtime/fetch.mjs
52
+ /**
53
+ * Framework-neutral failure type the orval-generated client throws on
54
+ * any non-2xx response. Carries the HTTP status, the parsed error body
55
+ * (the spec's `{code, message, details?}` envelope when the server
56
+ * returned one), and the request URL — enough for callers to map to
57
+ * their own error taxonomy without re-implementing the fetch layer.
58
+ *
59
+ * Callers that don't care about the distinction can catch `ApiError`
60
+ * generically; callers that do (the CLI's `toZitadelError`) read
61
+ * `status` and decide.
62
+ */
63
+ var ApiError = class extends Error {
64
+ status;
65
+ url;
66
+ body;
67
+ constructor(status, url, body, message) {
68
+ super(message);
69
+ this.name = "ApiError";
70
+ this.status = status;
71
+ this.url = url;
72
+ this.body = body;
73
+ }
74
+ };
75
+ /**
76
+ * The orval `mutator` for the fetch client. Every generated operation
77
+ * routes its request through this function instead of the global
78
+ * `fetch`. We pin three concerns here so generated call sites stay
79
+ * focused on the shape of one HTTP call:
80
+ *
81
+ * - bearer auth — read from `runtime/auth.ts` and attached automatically;
82
+ * - non-2xx → throw — orval's stock client parses the body regardless
83
+ * of status, so callers would have to inspect every response. Throw
84
+ * `ApiError` on `!res.ok` so failures interrupt control flow;
85
+ * - body parsing — return the parsed JSON typed as `T` (the operation's
86
+ * return type, threaded through by orval), or `undefined` for the
87
+ * spec's `204`/`205`/`304` no-body responses.
88
+ */
89
+ async function customFetch(url, options) {
90
+ const token = getApiAuthToken();
91
+ const headers = new Headers(options.headers);
92
+ if (token && !headers.has("authorization")) headers.set("authorization", `Bearer ${token}`);
93
+ const res = await fetch(url, {
94
+ ...options,
95
+ headers
96
+ });
97
+ const rawBody = [
98
+ 204,
99
+ 205,
100
+ 304
101
+ ].includes(res.status) ? "" : await res.text();
102
+ const parsed = rawBody ? safeJsonParse(rawBody) : void 0;
103
+ if (!res.ok) {
104
+ const message = `${options.method ?? "GET"} ${url} returned ${res.status}`;
105
+ throw new ApiError(res.status, url, parsed, message);
106
+ }
107
+ return parsed;
108
+ }
109
+ /**
110
+ * `JSON.parse` wrapped so a non-JSON body (e.g. an HTML 502 from a
111
+ * proxy) becomes `{ raw: "<text>" }` instead of throwing inside
112
+ * `customFetch`. The thrown `ApiError` then carries something useful
113
+ * for the user to see.
114
+ */
115
+ function safeJsonParse(text) {
116
+ try {
117
+ return JSON.parse(text);
118
+ } catch {
119
+ return { raw: text };
120
+ }
121
+ }
122
+ //#endregion
123
+ //#region ../api/dist/generated/endpoints/zitadelNextGen.mjs
124
+ /**
125
+ * Generated by orval v8.10.0 🍺
126
+ * Do not edit manually.
127
+ * Zitadel NextGen
128
+ * This is the next generation of the Zitadel identity platform.
129
+ * OpenAPI spec version: 0.0.1
130
+ */
131
+ var zitadelNextGen_exports = /* @__PURE__ */ __exportAll({
132
+ activateFlowDefinition: () => activateFlowDefinition,
133
+ authorizeDevice: () => authorizeDevice,
134
+ authorizeGet: () => authorizeGet,
135
+ createAuthAttempt: () => createAuthAttempt,
136
+ createBranding: () => createBranding,
137
+ createFlow: () => createFlow,
138
+ createFlowDefinition: () => createFlowDefinition,
139
+ createHandoff: () => createHandoff,
140
+ createProject: () => createProject,
141
+ createSchema: () => createSchema,
142
+ createSession: () => createSession,
143
+ createTeam: () => createTeam,
144
+ createUser: () => createUser,
145
+ deactivateFlowDefinition: () => deactivateFlowDefinition,
146
+ deleteFlowDefinition: () => deleteFlowDefinition,
147
+ deleteUserByID: () => deleteUserByID,
148
+ endSession: () => endSession,
149
+ exchangeHandoff: () => exchangeHandoff,
150
+ getActivateFlowDefinitionUrl: () => getActivateFlowDefinitionUrl,
151
+ getAuthAttempt: () => getAuthAttempt,
152
+ getAuthorizeDeviceUrl: () => getAuthorizeDeviceUrl,
153
+ getAuthorizeGetUrl: () => getAuthorizeGetUrl,
154
+ getBrandingById: () => getBrandingById,
155
+ getCreateAuthAttemptUrl: () => getCreateAuthAttemptUrl,
156
+ getCreateBrandingUrl: () => getCreateBrandingUrl,
157
+ getCreateFlowDefinitionUrl: () => getCreateFlowDefinitionUrl,
158
+ getCreateFlowUrl: () => getCreateFlowUrl,
159
+ getCreateHandoffUrl: () => getCreateHandoffUrl,
160
+ getCreateProjectUrl: () => getCreateProjectUrl,
161
+ getCreateSchemaUrl: () => getCreateSchemaUrl,
162
+ getCreateSessionUrl: () => getCreateSessionUrl,
163
+ getCreateTeamUrl: () => getCreateTeamUrl,
164
+ getCreateUserUrl: () => getCreateUserUrl,
165
+ getDeactivateFlowDefinitionUrl: () => getDeactivateFlowDefinitionUrl,
166
+ getDeleteFlowDefinitionUrl: () => getDeleteFlowDefinitionUrl,
167
+ getDeleteUserByIDUrl: () => getDeleteUserByIDUrl,
168
+ getEndSessionUrl: () => getEndSessionUrl,
169
+ getExchangeHandoffUrl: () => getExchangeHandoffUrl,
170
+ getFlowDefinition: () => getFlowDefinition,
171
+ getFlowStep: () => getFlowStep,
172
+ getGetAuthAttemptUrl: () => getGetAuthAttemptUrl,
173
+ getGetBrandingByIdUrl: () => getGetBrandingByIdUrl,
174
+ getGetFlowDefinitionUrl: () => getGetFlowDefinitionUrl,
175
+ getGetFlowStepUrl: () => getGetFlowStepUrl,
176
+ getGetHealthUrl: () => getGetHealthUrl,
177
+ getGetKeysUrl: () => getGetKeysUrl,
178
+ getGetLiveUrl: () => getGetLiveUrl,
179
+ getGetMySessionUrl: () => getGetMySessionUrl,
180
+ getGetMyUserUrl: () => getGetMyUserUrl,
181
+ getGetOpenIDConfigurationUrl: () => getGetOpenIDConfigurationUrl,
182
+ getGetProjectUrl: () => getGetProjectUrl,
183
+ getGetReadyUrl: () => getGetReadyUrl,
184
+ getGetSchemaByIdUrl: () => getGetSchemaByIdUrl,
185
+ getGetSessionUrl: () => getGetSessionUrl,
186
+ getGetTeamUrl: () => getGetTeamUrl,
187
+ getGetTokenUrl: () => getGetTokenUrl,
188
+ getGetUserByIDUrl: () => getGetUserByIDUrl,
189
+ getGetUserInfoUrl: () => getGetUserInfoUrl,
190
+ getHealth: () => getHealth,
191
+ getIntrospectUrl: () => getIntrospectUrl,
192
+ getIssueChallengeUrl: () => getIssueChallengeUrl,
193
+ getKeys: () => getKeys,
194
+ getListBrandingUrl: () => getListBrandingUrl,
195
+ getListFlowDefinitionsUrl: () => getListFlowDefinitionsUrl,
196
+ getListSchemasUrl: () => getListSchemasUrl,
197
+ getListSessionsUrl: () => getListSessionsUrl,
198
+ getListUserPasskeysUrl: () => getListUserPasskeysUrl,
199
+ getListUsersUrl: () => getListUsersUrl,
200
+ getLive: () => getLive,
201
+ getMySession: () => getMySession,
202
+ getMyUser: () => getMyUser,
203
+ getOpenIDConfiguration: () => getOpenIDConfiguration,
204
+ getPatchProjectUrl: () => getPatchProjectUrl,
205
+ getProject: () => getProject,
206
+ getQueryProjectsUrl: () => getQueryProjectsUrl,
207
+ getReady: () => getReady,
208
+ getRevokeMySessionUrl: () => getRevokeMySessionUrl,
209
+ getRevokeSessionUrl: () => getRevokeSessionUrl,
210
+ getRevokeTokenUrl: () => getRevokeTokenUrl,
211
+ getSchemaById: () => getSchemaById,
212
+ getSession: () => getSession,
213
+ getSetUserPasswordUrl: () => getSetUserPasswordUrl,
214
+ getSubmitFlowEventUrl: () => getSubmitFlowEventUrl,
215
+ getSubmitFlowStepUrl: () => getSubmitFlowStepUrl,
216
+ getTeam: () => getTeam,
217
+ getToken: () => getToken,
218
+ getUpdateFlowDefinitionUrl: () => getUpdateFlowDefinitionUrl,
219
+ getUserByID: () => getUserByID,
220
+ getUserInfo: () => getUserInfo,
221
+ getVerifyChallengeProofUrl: () => getVerifyChallengeProofUrl,
222
+ introspect: () => introspect,
223
+ issueChallenge: () => issueChallenge,
224
+ listBranding: () => listBranding,
225
+ listFlowDefinitions: () => listFlowDefinitions,
226
+ listSchemas: () => listSchemas,
227
+ listSessions: () => listSessions,
228
+ listUserPasskeys: () => listUserPasskeys,
229
+ listUsers: () => listUsers,
230
+ patchProject: () => patchProject,
231
+ queryProjects: () => queryProjects,
232
+ revokeMySession: () => revokeMySession,
233
+ revokeSession: () => revokeSession,
234
+ revokeToken: () => revokeToken,
235
+ setUserPassword: () => setUserPassword,
236
+ submitFlowEvent: () => submitFlowEvent,
237
+ submitFlowStep: () => submitFlowStep,
238
+ updateFlowDefinition: () => updateFlowDefinition,
239
+ verifyChallengeProof: () => verifyChallengeProof
240
+ });
241
+ const getGetOpenIDConfigurationUrl = () => {
242
+ return `${getProxyPath()}/.well-known/openid-configuration`;
243
+ };
244
+ /**
245
+ * Retrieve the OpenID Connect configuration
246
+ * @summary Get OpenID Connect configuration
247
+ */
248
+ const getOpenIDConfiguration = async (options) => {
249
+ return customFetch(getGetOpenIDConfigurationUrl(), {
250
+ ...options,
251
+ method: "GET"
252
+ });
253
+ };
254
+ const getAuthorizeGetUrl = (params) => {
255
+ const normalizedParams = new URLSearchParams();
256
+ Object.entries(params || {}).forEach(([key, value]) => {
257
+ if (value !== void 0) normalizedParams.append(key, value === null ? "null" : value.toString());
258
+ });
259
+ const stringifiedParams = normalizedParams.toString();
260
+ return stringifiedParams.length > 0 ? `${getProxyPath()}/auth/authorize?${stringifiedParams}` : `${getProxyPath()}/auth/authorize`;
261
+ };
262
+ /**
263
+ * @summary Authorize a user
264
+ */
265
+ const authorizeGet = async (params, options) => {
266
+ return customFetch(getAuthorizeGetUrl(params), {
267
+ ...options,
268
+ method: "GET"
269
+ });
270
+ };
271
+ const getAuthorizeDeviceUrl = (params) => {
272
+ const normalizedParams = new URLSearchParams();
273
+ Object.entries(params || {}).forEach(([key, value]) => {
274
+ if (value !== void 0) normalizedParams.append(key, value === null ? "null" : value.toString());
275
+ });
276
+ const stringifiedParams = normalizedParams.toString();
277
+ return stringifiedParams.length > 0 ? `${getProxyPath()}/auth/device-authorization?${stringifiedParams}` : `${getProxyPath()}/auth/device-authorization`;
278
+ };
279
+ /**
280
+ * @summary Authorize a device
281
+ */
282
+ const authorizeDevice = async (params, options) => {
283
+ return customFetch(getAuthorizeDeviceUrl(params), {
284
+ ...options,
285
+ method: "GET"
286
+ });
287
+ };
288
+ const getEndSessionUrl = (params) => {
289
+ const normalizedParams = new URLSearchParams();
290
+ Object.entries(params || {}).forEach(([key, value]) => {
291
+ if (value !== void 0) normalizedParams.append(key, value === null ? "null" : value.toString());
292
+ });
293
+ const stringifiedParams = normalizedParams.toString();
294
+ return stringifiedParams.length > 0 ? `${getProxyPath()}/auth/end-session?${stringifiedParams}` : `${getProxyPath()}/auth/end-session`;
295
+ };
296
+ /**
297
+ * @summary End a session
298
+ */
299
+ const endSession = async (params, options) => {
300
+ return customFetch(getEndSessionUrl(params), {
301
+ ...options,
302
+ method: "GET"
303
+ });
304
+ };
305
+ const getIntrospectUrl = () => {
306
+ return `${getProxyPath()}/auth/introspect`;
307
+ };
308
+ /**
309
+ * @summary Introspect a token
310
+ */
311
+ const introspect = async (introspectBody, options) => {
312
+ const formUrlEncoded = new URLSearchParams();
313
+ formUrlEncoded.append(`token`, introspectBody.token);
314
+ if (introspectBody.token_type_hint !== void 0) formUrlEncoded.append(`token_type_hint`, introspectBody.token_type_hint);
315
+ return customFetch(getIntrospectUrl(), {
316
+ ...options,
317
+ method: "POST",
318
+ headers: {
319
+ "Content-Type": "application/x-www-form-urlencoded",
320
+ ...options?.headers
321
+ },
322
+ body: formUrlEncoded
323
+ });
324
+ };
325
+ const getGetKeysUrl = () => {
326
+ return `${getProxyPath()}/auth/keys`;
327
+ };
328
+ /**
329
+ * @summary Get public keys
330
+ */
331
+ const getKeys = async (options) => {
332
+ return customFetch(getGetKeysUrl(), {
333
+ ...options,
334
+ method: "GET"
335
+ });
336
+ };
337
+ const getRevokeTokenUrl = () => {
338
+ return `${getProxyPath()}/auth/revoke`;
339
+ };
340
+ /**
341
+ * @summary Revoke an access token or refresh token
342
+ */
343
+ const revokeToken = async (revokeTokenBody, options) => {
344
+ const formUrlEncoded = new URLSearchParams();
345
+ if (revokeTokenBody.token !== void 0) formUrlEncoded.append(`token`, revokeTokenBody.token);
346
+ if (revokeTokenBody.token_type_hint !== void 0) formUrlEncoded.append(`token_type_hint`, revokeTokenBody.token_type_hint);
347
+ return customFetch(getRevokeTokenUrl(), {
348
+ ...options,
349
+ method: "POST",
350
+ headers: {
351
+ "Content-Type": "application/x-www-form-urlencoded",
352
+ ...options?.headers
353
+ },
354
+ body: formUrlEncoded
355
+ });
356
+ };
357
+ const getGetTokenUrl = () => {
358
+ return `${getProxyPath()}/auth/token`;
359
+ };
360
+ /**
361
+ * @summary Get access token
362
+ */
363
+ const getToken = async (getTokenBody, options) => {
364
+ const formUrlEncoded = new URLSearchParams();
365
+ if (getTokenBody.code !== void 0) formUrlEncoded.append(`code`, getTokenBody.code);
366
+ if (getTokenBody.client_assertion !== void 0) formUrlEncoded.append(`client_assertion`, getTokenBody.client_assertion);
367
+ if (getTokenBody.client_assertion_type !== void 0) formUrlEncoded.append(`client_assertion_type`, getTokenBody.client_assertion_type);
368
+ if (getTokenBody.client_id !== void 0) formUrlEncoded.append(`client_id`, getTokenBody.client_id);
369
+ if (getTokenBody.client_secret !== void 0) formUrlEncoded.append(`client_secret`, getTokenBody.client_secret);
370
+ if (getTokenBody.code_verifier !== void 0) formUrlEncoded.append(`code_verifier`, getTokenBody.code_verifier);
371
+ if (getTokenBody.grant_type !== void 0) formUrlEncoded.append(`grant_type`, getTokenBody.grant_type);
372
+ if (getTokenBody.redirect_uri !== void 0) formUrlEncoded.append(`redirect_uri`, getTokenBody.redirect_uri);
373
+ return customFetch(getGetTokenUrl(), {
374
+ ...options,
375
+ method: "POST",
376
+ headers: {
377
+ "Content-Type": "application/x-www-form-urlencoded",
378
+ ...options?.headers
379
+ },
380
+ body: formUrlEncoded
381
+ });
382
+ };
383
+ const getGetUserInfoUrl = () => {
384
+ return `${getProxyPath()}/auth/userinfo`;
385
+ };
386
+ /**
387
+ * @summary Get user info
388
+ */
389
+ const getUserInfo = async (options) => {
390
+ return customFetch(getGetUserInfoUrl(), {
391
+ ...options,
392
+ method: "GET"
393
+ });
394
+ };
395
+ const getGetHealthUrl = () => {
396
+ return `${getProxyPath()}/healthz`;
397
+ };
398
+ /**
399
+ * Check whether the server is healthy
400
+ * @summary Check server health
401
+ */
402
+ const getHealth = async (options) => {
403
+ return customFetch(getGetHealthUrl(), {
404
+ ...options,
405
+ method: "GET"
406
+ });
407
+ };
408
+ const getGetLiveUrl = () => {
409
+ return `${getProxyPath()}/livez`;
410
+ };
411
+ /**
412
+ * Check whether the server is started
413
+ * @summary Check server liveness
414
+ */
415
+ const getLive = async (options) => {
416
+ return customFetch(getGetLiveUrl(), {
417
+ ...options,
418
+ method: "GET"
419
+ });
420
+ };
421
+ const getGetReadyUrl = () => {
422
+ return `${getProxyPath()}/readyz`;
423
+ };
424
+ /**
425
+ * Check whether the server is ready to accept requests
426
+ * @summary Check server readiness
427
+ */
428
+ const getReady = async (options) => {
429
+ return customFetch(getGetReadyUrl(), {
430
+ ...options,
431
+ method: "GET"
432
+ });
433
+ };
434
+ const getCreateUserUrl = (params) => {
435
+ const normalizedParams = new URLSearchParams();
436
+ Object.entries(params || {}).forEach(([key, value]) => {
437
+ if (value !== void 0) normalizedParams.append(key, value === null ? "null" : value.toString());
438
+ });
439
+ const stringifiedParams = normalizedParams.toString();
440
+ return stringifiedParams.length > 0 ? `${getProxyPath()}/users?${stringifiedParams}` : `${getProxyPath()}/users`;
441
+ };
442
+ /**
443
+ * @summary Create user
444
+ */
445
+ const createUser = async (createUserBody, params, options) => {
446
+ return customFetch(getCreateUserUrl(params), {
447
+ ...options,
448
+ method: "POST",
449
+ headers: {
450
+ "Content-Type": "application/json",
451
+ ...options?.headers
452
+ },
453
+ body: JSON.stringify(createUserBody)
454
+ });
455
+ };
456
+ const getListUsersUrl = (params) => {
457
+ const normalizedParams = new URLSearchParams();
458
+ Object.entries(params || {}).forEach(([key, value]) => {
459
+ if (value !== void 0) normalizedParams.append(key, value === null ? "null" : value.toString());
460
+ });
461
+ const stringifiedParams = normalizedParams.toString();
462
+ return stringifiedParams.length > 0 ? `${getProxyPath()}/users?${stringifiedParams}` : `${getProxyPath()}/users`;
463
+ };
464
+ /**
465
+ * @summary List users
466
+ */
467
+ const listUsers = async (params, options) => {
468
+ return customFetch(getListUsersUrl(params), {
469
+ ...options,
470
+ method: "GET"
471
+ });
472
+ };
473
+ const getGetUserByIDUrl = (userId, params) => {
474
+ const normalizedParams = new URLSearchParams();
475
+ Object.entries(params || {}).forEach(([key, value]) => {
476
+ if (value !== void 0) normalizedParams.append(key, value === null ? "null" : value.toString());
477
+ });
478
+ const stringifiedParams = normalizedParams.toString();
479
+ return stringifiedParams.length > 0 ? `${getProxyPath()}/users/${userId}?${stringifiedParams}` : `${getProxyPath()}/users/${userId}`;
480
+ };
481
+ /**
482
+ * @summary Get user by ID
483
+ */
484
+ const getUserByID = async (userId, params, options) => {
485
+ return customFetch(getGetUserByIDUrl(userId, params), {
486
+ ...options,
487
+ method: "GET"
488
+ });
489
+ };
490
+ const getDeleteUserByIDUrl = (userId, params) => {
491
+ const normalizedParams = new URLSearchParams();
492
+ Object.entries(params || {}).forEach(([key, value]) => {
493
+ if (value !== void 0) normalizedParams.append(key, value === null ? "null" : value.toString());
494
+ });
495
+ const stringifiedParams = normalizedParams.toString();
496
+ return stringifiedParams.length > 0 ? `${getProxyPath()}/users/${userId}?${stringifiedParams}` : `${getProxyPath()}/users/${userId}`;
497
+ };
498
+ /**
499
+ * @summary Delete user by ID
500
+ */
501
+ const deleteUserByID = async (userId, params, options) => {
502
+ return customFetch(getDeleteUserByIDUrl(userId, params), {
503
+ ...options,
504
+ method: "DELETE"
505
+ });
506
+ };
507
+ const getListUserPasskeysUrl = (userId, params) => {
508
+ const normalizedParams = new URLSearchParams();
509
+ Object.entries(params || {}).forEach(([key, value]) => {
510
+ if (value !== void 0) normalizedParams.append(key, value === null ? "null" : value.toString());
511
+ });
512
+ const stringifiedParams = normalizedParams.toString();
513
+ return stringifiedParams.length > 0 ? `${getProxyPath()}/users/${userId}/passkeys?${stringifiedParams}` : `${getProxyPath()}/users/${userId}/passkeys`;
514
+ };
515
+ /**
516
+ * @summary List user passkeys
517
+ */
518
+ const listUserPasskeys = async (userId, params, options) => {
519
+ return customFetch(getListUserPasskeysUrl(userId, params), {
520
+ ...options,
521
+ method: "GET"
522
+ });
523
+ };
524
+ const getSetUserPasswordUrl = (userId, params) => {
525
+ const normalizedParams = new URLSearchParams();
526
+ Object.entries(params || {}).forEach(([key, value]) => {
527
+ if (value !== void 0) normalizedParams.append(key, value === null ? "null" : value.toString());
528
+ });
529
+ const stringifiedParams = normalizedParams.toString();
530
+ return stringifiedParams.length > 0 ? `${getProxyPath()}/users/${userId}/password?${stringifiedParams}` : `${getProxyPath()}/users/${userId}/password`;
531
+ };
532
+ /**
533
+ * @summary Set user password
534
+ */
535
+ const setUserPassword = async (userId, setUserPasswordBody, params, options) => {
536
+ return customFetch(getSetUserPasswordUrl(userId, params), {
537
+ ...options,
538
+ method: "PUT",
539
+ headers: {
540
+ "Content-Type": "application/json",
541
+ ...options?.headers
542
+ },
543
+ body: JSON.stringify(setUserPasswordBody)
544
+ });
545
+ };
546
+ const getGetMyUserUrl = () => {
547
+ return `${getProxyPath()}/users/me`;
548
+ };
549
+ /**
550
+ * @summary Get my user information
551
+ */
552
+ const getMyUser = async (options) => {
553
+ return customFetch(getGetMyUserUrl(), {
554
+ ...options,
555
+ method: "GET"
556
+ });
557
+ };
558
+ const getCreateFlowUrl = () => {
559
+ return `${getProxyPath()}/flow`;
560
+ };
561
+ /**
562
+ * Resolves a flow definition based on purpose + audience context and returns
563
+ the first capability step. Creates a new session implicitly unless
564
+ `session_id` is provided (for step-up / reauth on an existing session).
565
+
566
+ The response contains an `id` field — the flow handle. Use it as the path
567
+ parameter for all subsequent `/flow/{id}/submit` and `/flow/{id}/event` calls.
568
+
569
+ The response also sets an encrypted `HttpOnly` cookie (`_zflow`) containing
570
+ the flow's orchestration state (current step, collected data, history).
571
+ The server is stateless between requests — all flow state lives in this
572
+ cookie. The browser sends it automatically on subsequent requests.
573
+
574
+ * @summary Start a new flow
575
+ */
576
+ const createFlow = async (createFlowBody, options) => {
577
+ return customFetch(getCreateFlowUrl(), {
578
+ ...options,
579
+ method: "POST",
580
+ headers: {
581
+ "Content-Type": "application/json",
582
+ ...options?.headers
583
+ },
584
+ body: JSON.stringify(createFlowBody)
585
+ });
586
+ };
587
+ const getGetFlowStepUrl = (id) => {
588
+ return `${getProxyPath()}/flow/${id}`;
589
+ };
590
+ /**
591
+ * Returns the current capability step without advancing the state machine.
592
+ Useful for page reloads or re-rendering after a network error.
593
+
594
+ * @summary Get current step (re-render)
595
+ */
596
+ const getFlowStep = async (id, options) => {
597
+ return customFetch(getGetFlowStepUrl(id), {
598
+ ...options,
599
+ method: "GET"
600
+ });
601
+ };
602
+ const getSubmitFlowStepUrl = (id) => {
603
+ return `${getProxyPath()}/flow/${id}/submit`;
604
+ };
605
+ /**
606
+ * Submits user input for the current step. The server validates,
607
+ processes (e.g., verifies a credential), advances the state machine
608
+ through any invisible steps, and returns the next visible step.
609
+
610
+ The response sets an updated encrypted `HttpOnly` cookie (`_zflow`)
611
+ with the new flow state. The server is stateless — all orchestration
612
+ state is carried in this cookie between requests.
613
+
614
+ **Important:** The `id` in the response may differ from the `id` used in
615
+ the request. This happens when a flow pivots (pushes a new flow onto the
616
+ stack) or when a stacked flow completes (auto-pops to the parent flow).
617
+ Always use the `id` from the latest response for the next request.
618
+
619
+ ## Flow completion
620
+
621
+ When `step.type` is `complete`, the flow is terminal. The `step.behavior`
622
+ field tells the frontend what to do:
623
+
624
+ | `behavior` | Action |
625
+ |------------- |------------------------------------------------------------|
626
+ | `redirect` | Navigate to `redirect_uri` (OIDC/SAML auth request done). |
627
+ | `show` | Render the step as a success screen (e.g., registration). |
628
+
629
+ A `complete` step is only returned when the **entire flow stack** is done.
630
+ If a stacked flow (e.g., recovery pivoted from login) finishes, the server
631
+ auto-pops to the parent flow and returns the parent's next step — the
632
+ frontend never sees a `complete` for intermediate flows.
633
+
634
+ * @summary Submit step data and advance
635
+ */
636
+ const submitFlowStep = async (id, submitFlowStepBody, options) => {
637
+ return customFetch(getSubmitFlowStepUrl(id), {
638
+ ...options,
639
+ method: "POST",
640
+ headers: {
641
+ "Content-Type": "application/json",
642
+ ...options?.headers
643
+ },
644
+ body: JSON.stringify(submitFlowStepBody)
645
+ });
646
+ };
647
+ const getSubmitFlowEventUrl = (id) => {
648
+ return `${getProxyPath()}/flow/${id}/event`;
649
+ };
650
+ /**
651
+ * Submits telemetry or fingerprint data from the frontend.
652
+ Does not advance the state machine. Used for risk evaluation.
653
+
654
+ * @summary Submit client-side event
655
+ */
656
+ const submitFlowEvent = async (id, submitFlowEventBody, options) => {
657
+ return customFetch(getSubmitFlowEventUrl(id), {
658
+ ...options,
659
+ method: "POST",
660
+ headers: {
661
+ "Content-Type": "application/json",
662
+ ...options?.headers
663
+ },
664
+ body: JSON.stringify(submitFlowEventBody)
665
+ });
666
+ };
667
+ const getCreateAuthAttemptUrl = () => {
668
+ return `${getProxyPath()}/auth_attempts`;
669
+ };
670
+ /**
671
+ * Starts a new authentication attempt. This is the entry point for the auth_attempts state machine.
672
+
673
+ An attempt is an ephemeral (15-minute TTL) state machine that drives a single authentication round.
674
+ It accepts factor challenges, verifies proofs, and completes into a session or handoff token.
675
+
676
+ Accepts a project_id and challenge_nonce (from POST /bootstrap/challenge). For step-up re-auth,
677
+ also include session_id to add factors to an existing session.
678
+
679
+ * @summary Create a new authentication attempt
680
+ */
681
+ const createAuthAttempt = async (createAuthAttemptBody, options) => {
682
+ return customFetch(getCreateAuthAttemptUrl(), {
683
+ ...options,
684
+ method: "POST",
685
+ headers: {
686
+ "Content-Type": "application/json",
687
+ ...options?.headers
688
+ },
689
+ body: JSON.stringify(createAuthAttemptBody)
690
+ });
691
+ };
692
+ const getGetAuthAttemptUrl = (attemptId) => {
693
+ return `${getProxyPath()}/auth_attempts/${attemptId}`;
694
+ };
695
+ /**
696
+ * Polls the current state of an authentication attempt.
697
+
698
+ Returns the attempt's state, available factors for the next challenge,
699
+ challenges issued so far, and any errors preventing progress.
700
+
701
+ Use this for polling during long-running factor verifications (e.g., waiting for
702
+ a federated IdP callback or a device flow).
703
+
704
+ * @summary Get authentication attempt state
705
+ */
706
+ const getAuthAttempt = async (attemptId, options) => {
707
+ return customFetch(getGetAuthAttemptUrl(attemptId), {
708
+ ...options,
709
+ method: "GET"
710
+ });
711
+ };
712
+ const getIssueChallengeUrl = (attemptId) => {
713
+ return `${getProxyPath()}/auth_attempts/${attemptId}/challenges`;
714
+ };
715
+ /**
716
+ * Issues a single-factor verification challenge within an auth attempt.
717
+
718
+ This advances the authentication state machine by requesting a specific factor method
719
+ (password, passkey, TOTP, OTP via SMS, etc.). The server responds with challenge details
720
+ including method, metadata, and any UI hints. The client then verifies the proof
721
+ by calling POST /auth_attempts/{attempt_id}/challenges/{challenge_id}/verify.
722
+
723
+ * @summary Issue a factor challenge
724
+ */
725
+ const issueChallenge = async (attemptId, issueChallengeBody, options) => {
726
+ return customFetch(getIssueChallengeUrl(attemptId), {
727
+ ...options,
728
+ method: "POST",
729
+ headers: {
730
+ "Content-Type": "application/json",
731
+ ...options?.headers
732
+ },
733
+ body: JSON.stringify(issueChallengeBody)
734
+ });
735
+ };
736
+ const getVerifyChallengeProofUrl = (attemptId, challengeId) => {
737
+ return `${getProxyPath()}/auth_attempts/${attemptId}/challenges/${challengeId}/verify`;
738
+ };
739
+ /**
740
+ * Submits a proof (credential, code, assertion) to verify a factor challenge.
741
+
742
+ The proof format depends on the challenge method. For example:
743
+ - `password` method: { password: "…" }
744
+ - `totp` method: { totp: { code: "123456" } }
745
+ - `passkey` method: { passkey: { assertion: "…" } }
746
+ - `recovery_code` method: { recovery_code: "…" }
747
+
748
+ On successful verification, the factor is written to the auth attempt.
749
+ The attempt moves to the next pending challenge or completes if all required factors are verified.
750
+
751
+ * @summary Verify a factor proof
752
+ */
753
+ const verifyChallengeProof = async (attemptId, challengeId, verifyChallengeProofBody, options) => {
754
+ return customFetch(getVerifyChallengeProofUrl(attemptId, challengeId), {
755
+ ...options,
756
+ method: "POST",
757
+ headers: {
758
+ "Content-Type": "application/json",
759
+ ...options?.headers
760
+ },
761
+ body: JSON.stringify(verifyChallengeProofBody)
762
+ });
763
+ };
764
+ const getCreateHandoffUrl = (attemptId) => {
765
+ return `${getProxyPath()}/auth_attempts/${attemptId}/handoff`;
766
+ };
767
+ /**
768
+ * Completes the authentication attempt and mints a `handoff_token`.
769
+
770
+ Call this after all required factors have been verified and the attempt is in `completed` state.
771
+ The handoff token is short-lived (≤60 seconds) and must be exchanged at
772
+ POST /sessions/exchange to receive the final session and session_token.
773
+
774
+ The handoff token is:
775
+ - Single-use (atomic exchange, no retry)
776
+ - Audience-bound (requires matching project key for exchange)
777
+ - Idempotency-safe within a 5-minute window (see conventions)
778
+
779
+ * @summary Complete authentication and create handoff token
780
+ */
781
+ const createHandoff = async (attemptId, options) => {
782
+ return customFetch(getCreateHandoffUrl(attemptId), {
783
+ ...options,
784
+ method: "POST"
785
+ });
786
+ };
787
+ const getCreateProjectUrl = () => {
788
+ return `${getProxyPath()}/projects`;
789
+ };
790
+ /**
791
+ * @summary Create project
792
+ */
793
+ const createProject = async (createProjectBody, options) => {
794
+ return customFetch(getCreateProjectUrl(), {
795
+ ...options,
796
+ method: "POST",
797
+ headers: {
798
+ "Content-Type": "application/json",
799
+ ...options?.headers
800
+ },
801
+ body: JSON.stringify(createProjectBody)
802
+ });
803
+ };
804
+ const getQueryProjectsUrl = () => {
805
+ return `${getProxyPath()}/projects/query`;
806
+ };
807
+ /**
808
+ * @summary Query projects
809
+ */
810
+ const queryProjects = async (queryProjectsBody, options) => {
811
+ return customFetch(getQueryProjectsUrl(), {
812
+ ...options,
813
+ method: "POST",
814
+ headers: {
815
+ "Content-Type": "application/json",
816
+ ...options?.headers
817
+ },
818
+ body: JSON.stringify(queryProjectsBody)
819
+ });
820
+ };
821
+ const getGetProjectUrl = (projectId) => {
822
+ return `${getProxyPath()}/projects/${projectId}`;
823
+ };
824
+ /**
825
+ * Returns the current state of a project.
826
+
827
+ * @summary Get project
828
+ */
829
+ const getProject = async (projectId, options) => {
830
+ return customFetch(getGetProjectUrl(projectId), {
831
+ ...options,
832
+ method: "GET"
833
+ });
834
+ };
835
+ const getPatchProjectUrl = (projectId) => {
836
+ return `${getProxyPath()}/projects/${projectId}`;
837
+ };
838
+ /**
839
+ * Updates the state of a project.
840
+
841
+ * @summary Update project
842
+ */
843
+ const patchProject = async (projectId, patchProjectBody, options) => {
844
+ return customFetch(getPatchProjectUrl(projectId), {
845
+ ...options,
846
+ method: "PATCH",
847
+ headers: {
848
+ "Content-Type": "application/json",
849
+ ...options?.headers
850
+ },
851
+ body: JSON.stringify(patchProjectBody)
852
+ });
853
+ };
854
+ const getCreateSessionUrl = () => {
855
+ return `${getProxyPath()}/sessions`;
856
+ };
857
+ /**
858
+ * Creates an anonymous session shell with no user and no factors (`state: building`).
859
+
860
+ This is optional — an `auth_attempt` will create a session implicitly if none is provided.
861
+ Use this explicitly when you want to:
862
+ - Pre-allocate a `session_id` before the user is known, so device/telemetry signals
863
+ can be correlated with the eventual authenticated session from the start.
864
+ - Track anonymous state (bot detection, device fingerprint) that survives until authentication.
865
+
866
+ The returned `session_token` authorises GET and DELETE on this session.
867
+ It is superseded when a handoff exchange completes — clients must replace it at that point.
868
+
869
+ Anonymous sessions expire aggressively (10-minute TTL). The TTL resets to the configured
870
+ full session TTL when the first authentication factor is written via a completing `auth_attempt`.
871
+
872
+ * @summary Create an anonymous session shell
873
+ */
874
+ const createSession = async (createSessionBody, options) => {
875
+ return customFetch(getCreateSessionUrl(), {
876
+ ...options,
877
+ method: "POST",
878
+ headers: {
879
+ "Content-Type": "application/json",
880
+ ...options?.headers
881
+ },
882
+ body: JSON.stringify(createSessionBody)
883
+ });
884
+ };
885
+ const getListSessionsUrl = (params) => {
886
+ const normalizedParams = new URLSearchParams();
887
+ Object.entries(params || {}).forEach(([key, value]) => {
888
+ if (value !== void 0) normalizedParams.append(key, value === null ? "null" : value.toString());
889
+ });
890
+ const stringifiedParams = normalizedParams.toString();
891
+ return stringifiedParams.length > 0 ? `${getProxyPath()}/sessions?${stringifiedParams}` : `${getProxyPath()}/sessions`;
892
+ };
893
+ /**
894
+ * Returns a paginated list of sessions for a project.
895
+ Requires a project service key (OAuth2 client credentials).
896
+
897
+ * @summary List sessions
898
+ */
899
+ const listSessions = async (params, options) => {
900
+ return customFetch(getListSessionsUrl(params), {
901
+ ...options,
902
+ method: "GET"
903
+ });
904
+ };
905
+ const getExchangeHandoffUrl = (params) => {
906
+ const normalizedParams = new URLSearchParams();
907
+ Object.entries(params || {}).forEach(([key, value]) => {
908
+ if (value !== void 0) normalizedParams.append(key, value === null ? "null" : value.toString());
909
+ });
910
+ const stringifiedParams = normalizedParams.toString();
911
+ return stringifiedParams.length > 0 ? `${getProxyPath()}/sessions/exchange?${stringifiedParams}` : `${getProxyPath()}/sessions/exchange`;
912
+ };
913
+ /**
914
+ * Consumes a one-time `handoff_token` minted by `POST /auth_attempts/{id}/handoff`
915
+ and returns the resulting session and a `session_token`.
916
+
917
+ The server resolves the originating `auth_attempt` from the token and then:
918
+
919
+ | Originating auth_attempt | Outcome |
920
+ |---|---|
921
+ | No `session_id` | A new authenticated session is **created**. |
922
+ | `session_id` points to an anonymous shell | Existing session is **upgraded** — user and factors written in, TTL reset to full session TTL. |
923
+ | `session_id` points to an active session (step-up) | Existing session is **upgraded** — new factors merged, `assurance_levels[]` expanded. |
924
+
925
+ The response shape is identical in all three cases.
926
+
927
+ The `session_token` supersedes any previously issued `session_token` for the same session.
928
+ Clients must replace their stored token at this point.
929
+
930
+ Requires a project service key (OAuth2 client credentials).
931
+
932
+ * @summary Exchange handoff token for a session
933
+ */
934
+ const exchangeHandoff = async (exchangeHandoffBody, params, options) => {
935
+ return customFetch(getExchangeHandoffUrl(params), {
936
+ ...options,
937
+ method: "POST",
938
+ headers: {
939
+ "Content-Type": "application/json",
940
+ ...options?.headers
941
+ },
942
+ body: JSON.stringify(exchangeHandoffBody)
943
+ });
944
+ };
945
+ const getGetSessionUrl = (sessionId, params) => {
946
+ const normalizedParams = new URLSearchParams();
947
+ Object.entries(params || {}).forEach(([key, value]) => {
948
+ if (value !== void 0) normalizedParams.append(key, value === null ? "null" : value.toString());
949
+ });
950
+ const stringifiedParams = normalizedParams.toString();
951
+ return stringifiedParams.length > 0 ? `${getProxyPath()}/sessions/${sessionId}?${stringifiedParams}` : `${getProxyPath()}/sessions/${sessionId}`;
952
+ };
953
+ /**
954
+ * Returns the current state of a session including its factors and all currently
955
+ satisfied assurance levels.
956
+
957
+ `assurance_levels[]` may shrink over time as factor freshness windows expire,
958
+ without the session itself expiring. Use step-up authentication (a new `auth_attempt`
959
+ against the same `session_id`) to restore a dropped assurance level.
960
+
961
+ * @summary Get session state
962
+ */
963
+ const getSession = async (sessionId, params, options) => {
964
+ return customFetch(getGetSessionUrl(sessionId, params), {
965
+ ...options,
966
+ method: "GET"
967
+ });
968
+ };
969
+ const getRevokeSessionUrl = (sessionId, params) => {
970
+ const normalizedParams = new URLSearchParams();
971
+ Object.entries(params || {}).forEach(([key, value]) => {
972
+ if (value !== void 0) normalizedParams.append(key, value === null ? "null" : value.toString());
973
+ });
974
+ const stringifiedParams = normalizedParams.toString();
975
+ return stringifiedParams.length > 0 ? `${getProxyPath()}/sessions/${sessionId}?${stringifiedParams}` : `${getProxyPath()}/sessions/${sessionId}`;
976
+ };
977
+ /**
978
+ * Revokes the session immediately (`state: revoked`).
979
+
980
+ This is the operator revoke path and requires the `session.delete` scope on a
981
+ project-bound credential. End-user logout with the `__nextgen_session` cookie is
982
+ `DELETE /sessions/me` (`nextgenSession` scheme).
983
+
984
+ After revocation, any tokens derived from this session are invalidated.
985
+
986
+ * @summary Revoke session
987
+ */
988
+ const revokeSession = async (sessionId, params, options) => {
989
+ return customFetch(getRevokeSessionUrl(sessionId, params), {
990
+ ...options,
991
+ method: "DELETE"
992
+ });
993
+ };
994
+ const getGetMySessionUrl = () => {
995
+ return `${getProxyPath()}/sessions/me`;
996
+ };
997
+ /**
998
+ * Returns the current state of the current session including its factors and all currently
999
+ satisfied assurance levels.
1000
+
1001
+ `assurance_levels[]` may shrink over time as factor freshness windows expire,
1002
+ without the session itself expiring. Use step-up authentication (a new `auth_attempt`
1003
+ against the same `session_id`) to restore a dropped assurance level.
1004
+
1005
+ * @summary Get my session state
1006
+ */
1007
+ const getMySession = async (options) => {
1008
+ return customFetch(getGetMySessionUrl(), {
1009
+ ...options,
1010
+ method: "GET"
1011
+ });
1012
+ };
1013
+ const getRevokeMySessionUrl = () => {
1014
+ return `${getProxyPath()}/sessions/me`;
1015
+ };
1016
+ /**
1017
+ * Revokes the session immediately (`state: revoked`). This is the logout operation.
1018
+
1019
+ The __nextgen_session cookie issued at creation (or superseded by a handoff exchange) is required.
1020
+ After revocation, any tokens derived from this session are invalidated including the cookie itself, which is cleared in the response.
1021
+
1022
+ * @summary Revoke my session
1023
+ */
1024
+ const revokeMySession = async (options) => {
1025
+ return customFetch(getRevokeMySessionUrl(), {
1026
+ ...options,
1027
+ method: "DELETE"
1028
+ });
1029
+ };
1030
+ const getCreateSchemaUrl = (params) => {
1031
+ const normalizedParams = new URLSearchParams();
1032
+ Object.entries(params || {}).forEach(([key, value]) => {
1033
+ if (value !== void 0) normalizedParams.append(key, value === null ? "null" : value.toString());
1034
+ });
1035
+ const stringifiedParams = normalizedParams.toString();
1036
+ return stringifiedParams.length > 0 ? `${getProxyPath()}/schemas?${stringifiedParams}` : `${getProxyPath()}/schemas`;
1037
+ };
1038
+ /**
1039
+ * Create a new schema. The schema definition must include a unique $id field,
1040
+ which will be used to identify the schema in future requests. The $id must
1041
+ be a valid URI and should ideally point to the location where the schema
1042
+ can be accessed.
1043
+
1044
+ The schema can either be a concrete schema, e.g. a user schema, or a
1045
+ schema-url which will be resolved by the server.
1046
+
1047
+ * @summary Create new schema
1048
+ */
1049
+ const createSchema = async (createSchemaBody, params, options) => {
1050
+ return customFetch(getCreateSchemaUrl(params), {
1051
+ ...options,
1052
+ method: "POST",
1053
+ headers: {
1054
+ "Content-Type": "application/json",
1055
+ ...options?.headers
1056
+ },
1057
+ body: JSON.stringify(createSchemaBody)
1058
+ });
1059
+ };
1060
+ const getListSchemasUrl = (params) => {
1061
+ const normalizedParams = new URLSearchParams();
1062
+ Object.entries(params || {}).forEach(([key, value]) => {
1063
+ if (value !== void 0) normalizedParams.append(key, value === null ? "null" : value.toString());
1064
+ });
1065
+ const stringifiedParams = normalizedParams.toString();
1066
+ return stringifiedParams.length > 0 ? `${getProxyPath()}/schemas?${stringifiedParams}` : `${getProxyPath()}/schemas`;
1067
+ };
1068
+ /**
1069
+ * Retrieve a list of all schemas available in the system. This endpoint
1070
+ supports pagination and filtering based on schema attributes.
1071
+
1072
+ * @summary List all schemas
1073
+ */
1074
+ const listSchemas = async (params, options) => {
1075
+ return customFetch(getListSchemasUrl(params), {
1076
+ ...options,
1077
+ method: "GET"
1078
+ });
1079
+ };
1080
+ const getGetSchemaByIdUrl = (id, params) => {
1081
+ const normalizedParams = new URLSearchParams();
1082
+ Object.entries(params || {}).forEach(([key, value]) => {
1083
+ if (value !== void 0) normalizedParams.append(key, value === null ? "null" : value.toString());
1084
+ });
1085
+ const stringifiedParams = normalizedParams.toString();
1086
+ return stringifiedParams.length > 0 ? `${getProxyPath()}/schemas/${id}?${stringifiedParams}` : `${getProxyPath()}/schemas/${id}`;
1087
+ };
1088
+ /**
1089
+ * Get a schema by its ID. This will return the default revision of the schema.
1090
+ * @summary Get schema by ID
1091
+ */
1092
+ const getSchemaById = async (id, params, options) => {
1093
+ return customFetch(getGetSchemaByIdUrl(id, params), {
1094
+ ...options,
1095
+ method: "GET"
1096
+ });
1097
+ };
1098
+ const getCreateFlowDefinitionUrl = () => {
1099
+ return `${getProxyPath()}/flow_definitions`;
1100
+ };
1101
+ /**
1102
+ * Creates a new flow definition.
1103
+ Flow definitions are templates that define the sequence of steps (capabilities)
1104
+ for a particular user journey (e.g., registration, login, password reset).
1105
+
1106
+ Flow definitions are created based on the flow definition schema, which includes the flow's purpose, audience, and the steps involved.
1107
+
1108
+ * @summary Create a new flow definition
1109
+ */
1110
+ const createFlowDefinition = async (createFlowDefinitionBody, options) => {
1111
+ return customFetch(getCreateFlowDefinitionUrl(), {
1112
+ ...options,
1113
+ method: "POST",
1114
+ headers: {
1115
+ "Content-Type": "application/json",
1116
+ ...options?.headers
1117
+ },
1118
+ body: JSON.stringify(createFlowDefinitionBody)
1119
+ });
1120
+ };
1121
+ const getListFlowDefinitionsUrl = (params) => {
1122
+ const normalizedParams = new URLSearchParams();
1123
+ Object.entries(params || {}).forEach(([key, value]) => {
1124
+ if (value !== void 0) normalizedParams.append(key, value === null ? "null" : value.toString());
1125
+ });
1126
+ const stringifiedParams = normalizedParams.toString();
1127
+ return stringifiedParams.length > 0 ? `${getProxyPath()}/flow_definitions?${stringifiedParams}` : `${getProxyPath()}/flow_definitions`;
1128
+ };
1129
+ /**
1130
+ * Retrieves a list of all flow definitions.
1131
+ This endpoint can be used to view existing flow definitions and their configurations.
1132
+
1133
+ * @summary List flow definitions
1134
+ */
1135
+ const listFlowDefinitions = async (params, options) => {
1136
+ return customFetch(getListFlowDefinitionsUrl(params), {
1137
+ ...options,
1138
+ method: "GET"
1139
+ });
1140
+ };
1141
+ const getGetFlowDefinitionUrl = (id, params) => {
1142
+ const normalizedParams = new URLSearchParams();
1143
+ Object.entries(params || {}).forEach(([key, value]) => {
1144
+ if (value !== void 0) normalizedParams.append(key, value === null ? "null" : value.toString());
1145
+ });
1146
+ const stringifiedParams = normalizedParams.toString();
1147
+ return stringifiedParams.length > 0 ? `${getProxyPath()}/flow_definitions/${id}?${stringifiedParams}` : `${getProxyPath()}/flow_definitions/${id}`;
1148
+ };
1149
+ /**
1150
+ * Get a flow definition by id
1151
+ * @summary Get a flow definition by id
1152
+ */
1153
+ const getFlowDefinition = async (id, params, options) => {
1154
+ return customFetch(getGetFlowDefinitionUrl(id, params), {
1155
+ ...options,
1156
+ method: "GET"
1157
+ });
1158
+ };
1159
+ const getUpdateFlowDefinitionUrl = (id, params) => {
1160
+ const normalizedParams = new URLSearchParams();
1161
+ Object.entries(params || {}).forEach(([key, value]) => {
1162
+ if (value !== void 0) normalizedParams.append(key, value === null ? "null" : value.toString());
1163
+ });
1164
+ const stringifiedParams = normalizedParams.toString();
1165
+ return stringifiedParams.length > 0 ? `${getProxyPath()}/flow_definitions/${id}?${stringifiedParams}` : `${getProxyPath()}/flow_definitions/${id}`;
1166
+ };
1167
+ /**
1168
+ * Update a flow definition by id. This endpoint replaces the existing flow definition.
1169
+ If `flow_definition.status` is omitted, the current status is preserved
1170
+
1171
+ * @summary Update a flow definition by id
1172
+ */
1173
+ const updateFlowDefinition = async (id, updateFlowDefinitionBody, params, options) => {
1174
+ return customFetch(getUpdateFlowDefinitionUrl(id, params), {
1175
+ ...options,
1176
+ method: "PUT",
1177
+ headers: {
1178
+ "Content-Type": "application/json",
1179
+ ...options?.headers
1180
+ },
1181
+ body: JSON.stringify(updateFlowDefinitionBody)
1182
+ });
1183
+ };
1184
+ const getDeleteFlowDefinitionUrl = (id, params) => {
1185
+ const normalizedParams = new URLSearchParams();
1186
+ Object.entries(params || {}).forEach(([key, value]) => {
1187
+ if (value !== void 0) normalizedParams.append(key, value === null ? "null" : value.toString());
1188
+ });
1189
+ const stringifiedParams = normalizedParams.toString();
1190
+ return stringifiedParams.length > 0 ? `${getProxyPath()}/flow_definitions/${id}?${stringifiedParams}` : `${getProxyPath()}/flow_definitions/${id}`;
1191
+ };
1192
+ /**
1193
+ * Delete a flow definition by id.
1194
+ If the flow definition is currently being used by a flow, the deletion will fail.
1195
+ If the flow definition is the last active flow definition for a given purpose, the deletion will fail to prevent disruption of new flows being started for that purpose.
1196
+
1197
+ * @summary Delete a flow definition by id
1198
+ */
1199
+ const deleteFlowDefinition = async (id, params, options) => {
1200
+ return customFetch(getDeleteFlowDefinitionUrl(id, params), {
1201
+ ...options,
1202
+ method: "DELETE"
1203
+ });
1204
+ };
1205
+ const getActivateFlowDefinitionUrl = (id, params) => {
1206
+ const normalizedParams = new URLSearchParams();
1207
+ Object.entries(params || {}).forEach(([key, value]) => {
1208
+ if (value !== void 0) normalizedParams.append(key, value === null ? "null" : value.toString());
1209
+ });
1210
+ const stringifiedParams = normalizedParams.toString();
1211
+ return stringifiedParams.length > 0 ? `${getProxyPath()}/flow_definitions/${id}/activate?${stringifiedParams}` : `${getProxyPath()}/flow_definitions/${id}/activate`;
1212
+ };
1213
+ /**
1214
+ * Activate a flow definition by transitioning it from a `draft` state to an `active` state.
1215
+ Alternatively, the status of a flow definition can also be set via the `POST /flow_definitions` and `PUT /flow_definitions/{id}` endpoints by setting the `status` attribute in the flow definition payload.
1216
+
1217
+ * @summary Activate a flow definition by ID.
1218
+ */
1219
+ const activateFlowDefinition = async (id, params, options) => {
1220
+ return customFetch(getActivateFlowDefinitionUrl(id, params), {
1221
+ ...options,
1222
+ method: "POST"
1223
+ });
1224
+ };
1225
+ const getDeactivateFlowDefinitionUrl = (id, params) => {
1226
+ const normalizedParams = new URLSearchParams();
1227
+ Object.entries(params || {}).forEach(([key, value]) => {
1228
+ if (value !== void 0) normalizedParams.append(key, value === null ? "null" : value.toString());
1229
+ });
1230
+ const stringifiedParams = normalizedParams.toString();
1231
+ return stringifiedParams.length > 0 ? `${getProxyPath()}/flow_definitions/${id}/deactivate?${stringifiedParams}` : `${getProxyPath()}/flow_definitions/${id}/deactivate`;
1232
+ };
1233
+ /**
1234
+ * Deactivates a flow definition in the `active` state by transitioning it to the `draft` state.
1235
+ Flow definitions in `draft` state cannot be used to start new flows. Existing flows that use the deactivated flow definition must gracefully handle this.
1236
+ Alternatively, the status of a flow definition can also be set via the `POST /flow_definitions` and `PUT /flow_definitions/{id}` endpoints by setting the `status` attribute in the flow definition payload.
1237
+
1238
+ * @summary Deactivate a flow definition by ID.
1239
+ */
1240
+ const deactivateFlowDefinition = async (id, params, options) => {
1241
+ return customFetch(getDeactivateFlowDefinitionUrl(id, params), {
1242
+ ...options,
1243
+ method: "POST"
1244
+ });
1245
+ };
1246
+ const getCreateTeamUrl = (params) => {
1247
+ const normalizedParams = new URLSearchParams();
1248
+ Object.entries(params || {}).forEach(([key, value]) => {
1249
+ if (value !== void 0) normalizedParams.append(key, value === null ? "null" : value.toString());
1250
+ });
1251
+ const stringifiedParams = normalizedParams.toString();
1252
+ return stringifiedParams.length > 0 ? `${getProxyPath()}/teams?${stringifiedParams}` : `${getProxyPath()}/teams`;
1253
+ };
1254
+ /**
1255
+ * @summary Create team
1256
+ */
1257
+ const createTeam = async (createTeamBody, params, options) => {
1258
+ return customFetch(getCreateTeamUrl(params), {
1259
+ ...options,
1260
+ method: "POST",
1261
+ headers: {
1262
+ "Content-Type": "application/json",
1263
+ ...options?.headers
1264
+ },
1265
+ body: JSON.stringify(createTeamBody)
1266
+ });
1267
+ };
1268
+ const getGetTeamUrl = (teamId, params) => {
1269
+ const normalizedParams = new URLSearchParams();
1270
+ Object.entries(params || {}).forEach(([key, value]) => {
1271
+ if (value !== void 0) normalizedParams.append(key, value === null ? "null" : value.toString());
1272
+ });
1273
+ const stringifiedParams = normalizedParams.toString();
1274
+ return stringifiedParams.length > 0 ? `${getProxyPath()}/teams/${teamId}?${stringifiedParams}` : `${getProxyPath()}/teams/${teamId}`;
1275
+ };
1276
+ /**
1277
+ * Returns the current state of a team.
1278
+
1279
+ * @summary Get team
1280
+ */
1281
+ const getTeam = async (teamId, params, options) => {
1282
+ return customFetch(getGetTeamUrl(teamId, params), {
1283
+ ...options,
1284
+ method: "GET"
1285
+ });
1286
+ };
1287
+ const getCreateBrandingUrl = (params) => {
1288
+ const normalizedParams = new URLSearchParams();
1289
+ Object.entries(params || {}).forEach(([key, value]) => {
1290
+ if (value !== void 0) normalizedParams.append(key, value === null ? "null" : value.toString());
1291
+ });
1292
+ const stringifiedParams = normalizedParams.toString();
1293
+ return stringifiedParams.length > 0 ? `${getProxyPath()}/branding?${stringifiedParams}` : `${getProxyPath()}/branding`;
1294
+ };
1295
+ /**
1296
+ * Publishes a new immutable branding revision for the project. Branding
1297
+ revisions cannot be updated or deleted; every edit publishes a new
1298
+ revision, and flow responses resolve the latest revision per project
1299
+ (see ADR 040).
1300
+
1301
+ The `liquid_template` is validated lexically on save (size, encoding,
1302
+ banned patterns such as `<script>` tags, inline event handlers, and the
1303
+ `| raw` filter). Authoritative LiquidJS validation runs at authoring
1304
+ time via `zitadel plan` / `zitadel apply`.
1305
+
1306
+ * @summary Publish a new branding revision
1307
+ */
1308
+ const createBranding = async (createBrandingBody, params, options) => {
1309
+ return customFetch(getCreateBrandingUrl(params), {
1310
+ ...options,
1311
+ method: "POST",
1312
+ headers: {
1313
+ "Content-Type": "application/json",
1314
+ ...options?.headers
1315
+ },
1316
+ body: JSON.stringify(createBrandingBody)
1317
+ });
1318
+ };
1319
+ const getListBrandingUrl = (params) => {
1320
+ const normalizedParams = new URLSearchParams();
1321
+ Object.entries(params || {}).forEach(([key, value]) => {
1322
+ if (value !== void 0) normalizedParams.append(key, value === null ? "null" : value.toString());
1323
+ });
1324
+ const stringifiedParams = normalizedParams.toString();
1325
+ return stringifiedParams.length > 0 ? `${getProxyPath()}/branding?${stringifiedParams}` : `${getProxyPath()}/branding`;
1326
+ };
1327
+ /**
1328
+ * Lists branding revisions for the project, newest first, capped at the
1329
+ 100 most recent. The first entry is the revision flow responses
1330
+ currently resolve. Deliberately unpaginated in v1 — list endpoints
1331
+ gain a real query mechanism together (ADR 031); advertising pagination
1332
+ parameters the server ignores would be worse than none.
1333
+
1334
+ * @summary List branding revisions
1335
+ */
1336
+ const listBranding = async (params, options) => {
1337
+ return customFetch(getListBrandingUrl(params), {
1338
+ ...options,
1339
+ method: "GET"
1340
+ });
1341
+ };
1342
+ const getGetBrandingByIdUrl = (id, params) => {
1343
+ const normalizedParams = new URLSearchParams();
1344
+ Object.entries(params || {}).forEach(([key, value]) => {
1345
+ if (value !== void 0) normalizedParams.append(key, value === null ? "null" : value.toString());
1346
+ });
1347
+ const stringifiedParams = normalizedParams.toString();
1348
+ return stringifiedParams.length > 0 ? `${getProxyPath()}/branding/${id}?${stringifiedParams}` : `${getProxyPath()}/branding/${id}`;
1349
+ };
1350
+ /**
1351
+ * Retrieves a single branding revision, including its stored configuration.
1352
+ * @summary Get a branding revision by ID
1353
+ */
1354
+ const getBrandingById = async (id, params, options) => {
1355
+ return customFetch(getGetBrandingByIdUrl(id, params), {
1356
+ ...options,
1357
+ method: "GET"
1358
+ });
1359
+ };
1360
+ //#endregion
1361
+ //#region ../api/dist/runtime/api-factory.mjs
1362
+ /**
1363
+ * Factory for the typed Zitadel client every consumer reaches for.
1364
+ *
1365
+ * Wraps the orval-generated endpoints in a {@link Proxy} so each
1366
+ * generated function sees the right base URL and (optionally) the
1367
+ * right bearer token at call time — without the caller having to
1368
+ * thread either through every operation, and without exposing the
1369
+ * module-globals (`setProxyPath` / `setApiAuthToken`) as part of the
1370
+ * public API.
1371
+ *
1372
+ * Per-instance isolation: multiple clients can coexist in one process
1373
+ * (different servers, different tokens). Their Proxy `get` traps set
1374
+ * the globals synchronously before invoking the underlying generated
1375
+ * function, which reads them at the top of `customFetch` before any
1376
+ * `await`. Two clients running interleaved within a single JS turn
1377
+ * are safe; two clients running in parallel across awaits could
1378
+ * clobber each other — not a pattern any current consumer uses.
1379
+ */
1380
+ /**
1381
+ * Build a typed Zitadel client pre-bound to a base URL and (optionally)
1382
+ * a bearer token. Every method on the returned object mirrors a
1383
+ * generated orval function:
1384
+ *
1385
+ * const client = createZitadelClient({ baseUrl, token });
1386
+ * await client.createProject({ previewOrigins: [] });
1387
+ * await client.createSchema(body, { project_id });
1388
+ */
1389
+ function createZitadelClient(opts) {
1390
+ let baseUrl = opts.baseUrl;
1391
+ while (baseUrl.endsWith("/")) baseUrl = baseUrl.slice(0, -1);
1392
+ return new Proxy(zitadelNextGen_exports, { get(target, prop, receiver) {
1393
+ const value = Reflect.get(target, prop, receiver);
1394
+ if (typeof value !== "function") return value;
1395
+ return (...args) => {
1396
+ setProxyPath(baseUrl);
1397
+ setApiAuthToken(opts.token);
1398
+ return value(...args);
1399
+ };
1400
+ } });
1401
+ }
1402
+ //#endregion
1403
+ //#region ../config/dist/defaults-CXTnFMHj.mjs
1404
+ var default_human_user_default = {
1405
+ title: "DefaultHumanUserSchema",
1406
+ $schema: "https://json-schema.org/draft/2020-12/schema",
1407
+ metaSchema: "${SERVER_URL}/user-schema.json",
1408
+ $id: "${USER_SCHEMA_URL}",
1409
+ objectType: "human-user",
1410
+ kind: "user-schema",
1411
+ type: "object",
1412
+ description: "The default editable schema for human users.",
1413
+ "x-auth-methods": {
1414
+ "password": {
1415
+ "enabled": true,
1416
+ "position": 1
1417
+ },
1418
+ "passkey": {
1419
+ "enabled": true,
1420
+ "position": 2
1421
+ }
1422
+ },
1423
+ required: ["email"],
1424
+ properties: { "email": {
1425
+ "type": "string",
1426
+ "format": "email",
1427
+ "x-unique": "project",
1428
+ "description": "The user's email address."
1429
+ } }
1430
+ };
1431
+ var default_login_default = {
1432
+ $schema: "../meta/flow-definition.json",
1433
+ name: "default-login",
1434
+ status: "active",
1435
+ user_schema: "${USER_SCHEMA_URL}",
1436
+ purposes: {
1437
+ "login": "identifier",
1438
+ "register": "register"
1439
+ },
1440
+ steps: [
1441
+ {
1442
+ "name": "identifier",
1443
+ "fields": ["email"],
1444
+ "actions": [{
1445
+ "name": "submit",
1446
+ "kind": "submit",
1447
+ "primary": true,
1448
+ "text_key": "identifier.action.continue"
1449
+ }, {
1450
+ "name": "passkey",
1451
+ "kind": "passkey",
1452
+ "primary": false,
1453
+ "text_key": "identifier.action.passkey"
1454
+ }],
1455
+ "transitions": {
1456
+ "submit": { "target": "password" },
1457
+ "passkey": { "target": "done" },
1458
+ "user_not_found": { "target": "register" }
1459
+ }
1460
+ },
1461
+ {
1462
+ "name": "password",
1463
+ "fields": ["x-auth-methods#password"],
1464
+ "actions": [{
1465
+ "name": "submit",
1466
+ "kind": "submit",
1467
+ "primary": true,
1468
+ "text_key": "password.action.signin"
1469
+ }, {
1470
+ "name": "passkey",
1471
+ "kind": "passkey",
1472
+ "primary": false,
1473
+ "text_key": "password.action.passkey"
1474
+ }],
1475
+ "transitions": {
1476
+ "submit": { "target": "done" },
1477
+ "passkey": { "target": "done" }
1478
+ }
1479
+ },
1480
+ {
1481
+ "name": "register",
1482
+ "fields": ["email"],
1483
+ "actions": [{
1484
+ "name": "submit",
1485
+ "kind": "submit",
1486
+ "primary": true,
1487
+ "text_key": "register.action.password"
1488
+ }, {
1489
+ "name": "passkey_register",
1490
+ "kind": "passkey_register",
1491
+ "primary": false,
1492
+ "text_key": "register.action.passkey"
1493
+ }],
1494
+ "transitions": {
1495
+ "submit": { "target": "register-password" },
1496
+ "passkey_register": { "target": "done" },
1497
+ "user_already_exists": { "target": "password" }
1498
+ }
1499
+ },
1500
+ {
1501
+ "name": "register-password",
1502
+ "fields": ["x-auth-methods#password"],
1503
+ "actions": [{
1504
+ "name": "submit",
1505
+ "kind": "submit",
1506
+ "primary": true,
1507
+ "text_key": "register-password.action.submit"
1508
+ }],
1509
+ "on_success": "create_user",
1510
+ "transitions": {
1511
+ "submit": { "target": "done" },
1512
+ "user_already_exists": { "target": "password" }
1513
+ }
1514
+ },
1515
+ {
1516
+ "name": "done",
1517
+ "complete": "show"
1518
+ }
1519
+ ]
1520
+ };
1521
+ var human_user_default = {
1522
+ title: "DefaultHumanUserSchema",
1523
+ $schema: "https://json-schema.org/draft/2020-12/schema",
1524
+ metaSchema: "${SERVER_URL}/user-schema.json",
1525
+ $id: "${USER_SCHEMA_URL}",
1526
+ objectType: "human-user",
1527
+ kind: "user-schema",
1528
+ type: "object",
1529
+ description: "The default editable schema for human users (passkey-first sign-in).",
1530
+ "x-auth-methods": {
1531
+ "passkey": {
1532
+ "enabled": true,
1533
+ "position": 1
1534
+ },
1535
+ "password": {
1536
+ "enabled": true,
1537
+ "position": 2
1538
+ }
1539
+ },
1540
+ required: ["email"],
1541
+ properties: { "email": {
1542
+ "type": "string",
1543
+ "format": "email",
1544
+ "x-unique": "project",
1545
+ "description": "The user's email address."
1546
+ } }
1547
+ };
1548
+ var login_default = {
1549
+ $schema: "../meta/flow-definition.json",
1550
+ name: "default-login",
1551
+ status: "active",
1552
+ user_schema: "${USER_SCHEMA_URL}",
1553
+ purposes: {
1554
+ "login": "passkey-first",
1555
+ "register": "register"
1556
+ },
1557
+ steps: [
1558
+ {
1559
+ "name": "passkey-first",
1560
+ "fields": [],
1561
+ "actions": [{
1562
+ "name": "passkey",
1563
+ "kind": "passkey",
1564
+ "primary": true,
1565
+ "text_key": "passkey-first.action.passkey"
1566
+ }, {
1567
+ "name": "email_fallback",
1568
+ "kind": "navigate",
1569
+ "primary": false,
1570
+ "text_key": "passkey-first.action.email_fallback"
1571
+ }],
1572
+ "transitions": {
1573
+ "passkey": { "target": "done" },
1574
+ "email_fallback": { "target": "identifier" },
1575
+ "user_not_found": { "target": "register" }
1576
+ }
1577
+ },
1578
+ {
1579
+ "name": "identifier",
1580
+ "fields": ["email"],
1581
+ "actions": [{
1582
+ "name": "submit",
1583
+ "kind": "submit",
1584
+ "primary": true,
1585
+ "text_key": "identifier.action.continue"
1586
+ }, {
1587
+ "name": "passkey",
1588
+ "kind": "passkey",
1589
+ "primary": false,
1590
+ "text_key": "identifier.action.passkey"
1591
+ }],
1592
+ "transitions": {
1593
+ "submit": { "target": "password" },
1594
+ "passkey": { "target": "done" },
1595
+ "user_not_found": { "target": "register" }
1596
+ }
1597
+ },
1598
+ {
1599
+ "name": "password",
1600
+ "fields": ["x-auth-methods#password"],
1601
+ "actions": [{
1602
+ "name": "submit",
1603
+ "kind": "submit",
1604
+ "primary": true,
1605
+ "text_key": "password.action.signin"
1606
+ }, {
1607
+ "name": "passkey",
1608
+ "kind": "passkey",
1609
+ "primary": false,
1610
+ "text_key": "password.action.passkey"
1611
+ }],
1612
+ "transitions": {
1613
+ "submit": { "target": "done" },
1614
+ "passkey": { "target": "done" }
1615
+ }
1616
+ },
1617
+ {
1618
+ "name": "register",
1619
+ "fields": ["email"],
1620
+ "actions": [{
1621
+ "name": "passkey_register",
1622
+ "kind": "passkey_register",
1623
+ "primary": true,
1624
+ "text_key": "register.action.passkey"
1625
+ }, {
1626
+ "name": "submit",
1627
+ "kind": "submit",
1628
+ "primary": false,
1629
+ "text_key": "register.action.password"
1630
+ }],
1631
+ "transitions": {
1632
+ "passkey_register": { "target": "done" },
1633
+ "submit": { "target": "register-password" },
1634
+ "user_already_exists": { "target": "password" }
1635
+ }
1636
+ },
1637
+ {
1638
+ "name": "register-password",
1639
+ "fields": ["x-auth-methods#password"],
1640
+ "actions": [{
1641
+ "name": "submit",
1642
+ "kind": "submit",
1643
+ "primary": true,
1644
+ "text_key": "register-password.action.submit"
1645
+ }],
1646
+ "on_success": "create_user",
1647
+ "transitions": {
1648
+ "submit": { "target": "done" },
1649
+ "user_already_exists": { "target": "password" }
1650
+ }
1651
+ },
1652
+ {
1653
+ "name": "done",
1654
+ "complete": "show"
1655
+ }
1656
+ ]
1657
+ };
1658
+ const DEFAULT_BUILTIN_SCHEMA_BASE = "https://nextgen.com/api/schemas";
1659
+ const DEFAULT_FLOW_SCHEMA_URI = "https://nextgen.com/flow-definition.json";
1660
+ /**
1661
+ * Named schema+flow bundles `zitadel setup` can scaffold (#448: the prompt
1662
+ * fires before any `.zitadel/` file is written; each preset maps to a
1663
+ * pre-defined bundle the CLI copies on first setup). `password-first` is
1664
+ * today's default; `passkey-first` puts a passkey ceremony on the login
1665
+ * entry step with an email→password fallback path.
1666
+ */
1667
+ const SETUP_PRESETS = ["password-first", "passkey-first"];
1668
+ const PRESET_TEMPLATES = {
1669
+ "password-first": {
1670
+ schema: default_human_user_default,
1671
+ flow: default_login_default
1672
+ },
1673
+ "passkey-first": {
1674
+ schema: human_user_default,
1675
+ flow: login_default
1676
+ }
1677
+ };
1678
+ function presetTemplates(preset) {
1679
+ if (!Object.hasOwn(PRESET_TEMPLATES, preset)) throw new Error(`unknown setup preset ${JSON.stringify(preset)} (known presets: ${SETUP_PRESETS.join(", ")})`);
1680
+ return PRESET_TEMPLATES[preset];
1681
+ }
1682
+ /**
1683
+ * The second setup axis (#448): *who* signs in, orthogonal to the sign-in
1684
+ * preset (*how* they sign in). The sign-in preset owns the flow shape and
1685
+ * auth methods; the use case owns which profile fields the schema collects.
1686
+ * Composing the two keeps us at one field catalog + one flow-per-preset
1687
+ * instead of a bundle per (use case × preset) pair. `minimal` is the
1688
+ * default and never blocks non-interactive runs.
1689
+ */
1690
+ const SETUP_USE_CASES = [
1691
+ "minimal",
1692
+ "consumer",
1693
+ "business"
1694
+ ];
1695
+ /**
1696
+ * Fields each use case collects, in register/display order. `email` is
1697
+ * always first and stays the only required property; the rest are optional
1698
+ * profile attributes gathered on the flow's register step. `givenName`/
1699
+ * `familyName` are the attributes the backend reads for a user's identity
1700
+ * (`internal/domain/user.go`); `companyName` is stored as a plain user
1701
+ * attribute today — there is no org/team model behind it yet.
1702
+ */
1703
+ const USE_CASE_FIELDS = {
1704
+ minimal: ["email"],
1705
+ consumer: [
1706
+ "email",
1707
+ "givenName",
1708
+ "familyName"
1709
+ ],
1710
+ business: [
1711
+ "email",
1712
+ "givenName",
1713
+ "familyName",
1714
+ "companyName"
1715
+ ]
1716
+ };
1717
+ /**
1718
+ * JSON-Schema bodies for the optional profile fields the CLI composes in per
1719
+ * use case. The shipped templates are an email-only baseline (shared verbatim
1720
+ * with the Go server fallback), so this catalog owns every field beyond
1721
+ * `email`. Authored in the templates' style — no `x-claim`, since the backend
1722
+ * maps identity by attribute name and the user-property meta-schema defines no
1723
+ * claim keyword. `givenName`/`familyName` are the attributes the backend reads
1724
+ * for a user's identity (`internal/domain/user.go`).
1725
+ */
1726
+ const EXTRA_FIELD_BODIES = {
1727
+ givenName: {
1728
+ type: "string",
1729
+ maxLength: 50,
1730
+ description: "The user's given (first) name."
1731
+ },
1732
+ familyName: {
1733
+ type: "string",
1734
+ maxLength: 50,
1735
+ description: "The user's family (last) name."
1736
+ },
1737
+ companyName: {
1738
+ type: "string",
1739
+ maxLength: 200,
1740
+ description: "The user's company name."
1741
+ }
1742
+ };
1743
+ function useCaseFields(useCase) {
1744
+ if (!Object.hasOwn(USE_CASE_FIELDS, useCase)) throw new Error(`unknown setup use case ${JSON.stringify(useCase)} (known use cases: ${SETUP_USE_CASES.join(", ")})`);
1745
+ return USE_CASE_FIELDS[useCase];
1746
+ }
1747
+ /**
1748
+ * The body for one use-case field: reuse the template's authored body when it
1749
+ * has one (so composed schemas match the shipped defaults for shared fields),
1750
+ * else the extra catalog, else a generic editable string so composition stays
1751
+ * total for any field a future use case introduces.
1752
+ */
1753
+ function fieldBody(field, templateProps) {
1754
+ if (Object.hasOwn(templateProps, field)) return { ...templateProps[field] };
1755
+ if (Object.hasOwn(EXTRA_FIELD_BODIES, field)) return { ...EXTRA_FIELD_BODIES[field] };
1756
+ return {
1757
+ type: "string",
1758
+ description: `The user's ${field}.`
1759
+ };
1760
+ }
1761
+ /**
1762
+ * Narrow a rendered schema to the chosen use case: keep the preset-owned
1763
+ * header and `x-auth-methods`, but replace `properties`/`required` with the
1764
+ * use case's field set. `email` is the sole required property.
1765
+ */
1766
+ function applyUseCaseToSchema(schema, useCase) {
1767
+ const templateProps = schema.properties ?? {};
1768
+ const properties = {};
1769
+ for (const field of useCaseFields(useCase)) properties[field] = fieldBody(field, templateProps);
1770
+ return {
1771
+ ...schema,
1772
+ required: ["email"],
1773
+ properties
1774
+ };
1775
+ }
1776
+ /**
1777
+ * Derive the flow's register-step fields from the use case rather than
1778
+ * copying a hard-coded list into every bundle (#448): the register step
1779
+ * collects exactly what the schema defines. Other steps are untouched.
1780
+ */
1781
+ function applyUseCaseToFlow(flow, useCase) {
1782
+ const fields = [...useCaseFields(useCase)];
1783
+ const steps = flow.steps.map((step) => step.name === "register" ? {
1784
+ ...step,
1785
+ fields
1786
+ } : step);
1787
+ return {
1788
+ ...flow,
1789
+ steps
1790
+ };
1791
+ }
1792
+ function defaultHumanUserSchemaUrl(builtinSchemaBase = DEFAULT_BUILTIN_SCHEMA_BASE) {
1793
+ return `${trimTrailingSlash(builtinSchemaBase)}/default-human-user.json`;
1794
+ }
1795
+ function getDefaultHumanUserSchema(options = {}) {
1796
+ const builtinSchemaBase = trimTrailingSlash(options.builtinSchemaBase ?? "https://nextgen.com/api/schemas");
1797
+ return applyUseCaseToSchema(renderTemplate(presetTemplates(options.preset ?? "password-first").schema, {
1798
+ SERVER_URL: builtinSchemaBase,
1799
+ USER_SCHEMA_URL: options.userSchemaUrl ?? defaultHumanUserSchemaUrl(builtinSchemaBase)
1800
+ }), options.useCase ?? "minimal");
1801
+ }
1802
+ function getDefaultLoginFlow(options = {}) {
1803
+ const builtinSchemaBase = trimTrailingSlash(options.builtinSchemaBase ?? "https://nextgen.com/api/schemas");
1804
+ return applyUseCaseToFlow(renderTemplate(presetTemplates(options.preset ?? "password-first").flow, {
1805
+ SERVER_URL: builtinSchemaBase,
1806
+ USER_SCHEMA_URL: options.userSchemaUrl ?? defaultHumanUserSchemaUrl(builtinSchemaBase)
1807
+ }), options.useCase ?? "minimal");
1808
+ }
1809
+ function renderTemplate(value, replacements) {
1810
+ if (Array.isArray(value)) return value.map((item) => renderTemplate(item, replacements));
1811
+ if (value !== null && typeof value === "object") return Object.fromEntries(Object.entries(value).map(([key, item]) => [key, renderTemplate(item, replacements)]));
1812
+ if (typeof value === "string") return value.replaceAll(/\$\{([A-Z_]+)\}/g, (match, name) => {
1813
+ return replacements[name] ?? match;
1814
+ });
1815
+ return value;
1816
+ }
1817
+ function trimTrailingSlash(value) {
1818
+ let trimmed = value;
1819
+ while (trimmed.endsWith("/")) trimmed = trimmed.slice(0, -1);
1820
+ return trimmed;
1821
+ }
1822
+ //#endregion
1823
+ //#region src/bootstrap.ts
1824
+ const DEFAULT_PROJECT_NAME = "zitadel-testing";
1825
+ /**
1826
+ * Server-side half of `zitadel setup`, without any file scaffolding:
1827
+ * `POST /projects` is unauthenticated and mints the projectSecret used as the
1828
+ * bearer for everything else; the schema is uploaded without `$id` so the
1829
+ * server assigns an opaque id, which the flow must then reference.
1830
+ */
1831
+ async function bootstrapProject(options) {
1832
+ const { baseUrl } = options;
1833
+ const project = await createZitadelClient({ baseUrl }).createProject({
1834
+ name: options.projectName ?? DEFAULT_PROJECT_NAME,
1835
+ previewOrigins: options.appOrigins ?? [],
1836
+ seedDefaults: false
1837
+ });
1838
+ const projectId = requireString(project.id, "project id");
1839
+ const projectSecret = requireString(project.projectSecret, "project secret");
1840
+ const previewSecret = typeof project.previewSecret === "string" ? project.previewSecret : void 0;
1841
+ const client = createZitadelClient({
1842
+ baseUrl,
1843
+ token: projectSecret
1844
+ });
1845
+ const { $id: _templateId, ...schemaBody } = getDefaultHumanUserSchema({
1846
+ preset: options.preset,
1847
+ useCase: options.useCase
1848
+ });
1849
+ const schemaId = requireString((await client.createSchema(schemaBody, { project_id: projectId })).id, "schema id");
1850
+ const flowBody = getDefaultLoginFlow({
1851
+ userSchemaUrl: schemaId,
1852
+ preset: options.preset,
1853
+ useCase: options.useCase
1854
+ });
1855
+ return {
1856
+ projectId,
1857
+ projectSecret,
1858
+ previewSecret,
1859
+ schemaId,
1860
+ flowId: requireString((await client.createFlowDefinition({
1861
+ project_id: projectId,
1862
+ schema_uri: DEFAULT_FLOW_SCHEMA_URI,
1863
+ flow_definition: flowBody
1864
+ })).id, "flow definition id")
1865
+ };
1866
+ }
1867
+ function requireString(value, label) {
1868
+ if (typeof value === "string" && value.length > 0) return value;
1869
+ throw new Error(`Missing ${label} in server response.`);
1870
+ }
1871
+ //#endregion
1872
+ //#region src/cli.ts
1873
+ const DEFAULT_TIMEOUT_MS = 12e4;
1874
+ function resolveCliBin() {
1875
+ const require = (0, node_module.createRequire)(require("url").pathToFileURL(__filename).href);
1876
+ const pkgPath = require.resolve("@zitadel/cli/package.json");
1877
+ const rel = require(pkgPath).bin?.zitadel;
1878
+ if (!rel) throw new Error("@zitadel/cli does not declare a `zitadel` bin entry");
1879
+ return (0, node_path.join)((0, node_path.dirname)(pkgPath), rel);
1880
+ }
1881
+ function runCli(options) {
1882
+ const bin = options.bin ?? resolveCliBin();
1883
+ const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
1884
+ return new Promise((resolve, reject) => {
1885
+ const child = (0, node_child_process.spawn)(process.execPath, [bin, ...options.args], {
1886
+ env: {
1887
+ ...process.env,
1888
+ ...options.env
1889
+ },
1890
+ stdio: [
1891
+ "ignore",
1892
+ "pipe",
1893
+ "pipe"
1894
+ ]
1895
+ });
1896
+ let stdout = "";
1897
+ let stderr = "";
1898
+ child.stdout.setEncoding("utf8");
1899
+ child.stdout.on("data", (chunk) => {
1900
+ stdout += chunk;
1901
+ });
1902
+ child.stderr.setEncoding("utf8");
1903
+ child.stderr.on("data", (chunk) => {
1904
+ stderr += chunk;
1905
+ });
1906
+ const timer = setTimeout(() => {
1907
+ child.kill("SIGKILL");
1908
+ reject(/* @__PURE__ */ new Error(`zitadel ${options.args[0] ?? ""} timed out after ${timeoutMs}ms\n${tail(stderr)}`));
1909
+ }, timeoutMs);
1910
+ timer.unref();
1911
+ child.on("error", (error) => {
1912
+ clearTimeout(timer);
1913
+ reject(error);
1914
+ });
1915
+ child.on("close", (code) => {
1916
+ clearTimeout(timer);
1917
+ resolve({
1918
+ exitCode: code ?? -1,
1919
+ stdout,
1920
+ stderr
1921
+ });
1922
+ });
1923
+ });
1924
+ }
1925
+ function tail(text, lines = 20) {
1926
+ return text.split("\n").slice(-lines).join("\n").trim();
1927
+ }
1928
+ //#endregion
1929
+ //#region src/envelope.ts
1930
+ /**
1931
+ * Render an error envelope's remediation fields for humans — the CLI's
1932
+ * `hint`/`next_commands` are the actionable part of a failure (e.g. "Reinstall
1933
+ * @zitadel/cli so npm can install @zitadel/server"), so surface them instead
1934
+ * of a raw stdout dump. Returns undefined when the envelope has no message.
1935
+ */
1936
+ function describeEnvelopeError(envelope) {
1937
+ if (typeof envelope.message !== "string" || envelope.message.length === 0) return;
1938
+ const lines = [envelope.code ? `${envelope.code}: ${envelope.message}` : envelope.message];
1939
+ if (envelope.hint) lines.push(`hint: ${envelope.hint}`);
1940
+ if (envelope.next_commands && envelope.next_commands.length > 0) lines.push(`next: ${envelope.next_commands.join(" | ")}`);
1941
+ return lines.join("\n");
1942
+ }
1943
+ function parseCliEnvelope(stdout, context) {
1944
+ const start = stdout.indexOf("{");
1945
+ const end = stdout.lastIndexOf("}");
1946
+ if (start === -1 || end <= start) throw new Error(`${context}: expected a JSON envelope on stdout, got:\n${stdout.trim() || "(empty)"}`);
1947
+ let parsed;
1948
+ try {
1949
+ parsed = JSON.parse(stdout.slice(start, end + 1));
1950
+ } catch (error) {
1951
+ throw new Error(`${context}: failed to parse JSON envelope: ${error.message}\n${stdout.trim()}`, { cause: error });
1952
+ }
1953
+ if (typeof parsed !== "object" || parsed === null || typeof parsed.status !== "string") throw new Error(`${context}: stdout JSON is not a CLI envelope:\n${stdout.trim()}`);
1954
+ return parsed;
1955
+ }
1956
+ //#endregion
1957
+ //#region src/ports.ts
1958
+ /**
1959
+ * Ask the OS for a free TCP port. The port is released before returning, so a
1960
+ * racing process could grab it; the CLI's own preflight surfaces that as
1961
+ * E_PORT_IN_USE, which is loud rather than corrupting.
1962
+ */
1963
+ function getFreePort() {
1964
+ return new Promise((resolve, reject) => {
1965
+ const server = (0, node_net.createServer)();
1966
+ server.unref();
1967
+ server.on("error", reject);
1968
+ server.listen(0, "127.0.0.1", () => {
1969
+ const address = server.address();
1970
+ if (address === null || typeof address === "string") {
1971
+ server.close();
1972
+ reject(/* @__PURE__ */ new Error("could not determine a free port"));
1973
+ return;
1974
+ }
1975
+ const { port } = address;
1976
+ server.close((err) => {
1977
+ if (err) {
1978
+ reject(err);
1979
+ return;
1980
+ }
1981
+ resolve(port);
1982
+ });
1983
+ });
1984
+ });
1985
+ }
1986
+ //#endregion
1987
+ //#region src/lifecycle.ts
1988
+ /**
1989
+ * Boot an ephemeral local server by shelling out to `zitadel start` and parse
1990
+ * its JSON envelope. The CLI owns the subtle parts (port preflight, health
1991
+ * wait, process-group stop, embedded-Postgres reaping), so this module stays a
1992
+ * thin adapter; swapping it for direct library calls later must not change the
1993
+ * shape returned here.
1994
+ */
1995
+ async function bootLocalServer(options = {}) {
1996
+ const ownsDir = options.dir === void 0;
1997
+ const dir = options.dir ?? await (0, node_fs_promises.mkdtemp)((0, node_path.join)((0, node_os.tmpdir)(), "zitadel-testing-"));
1998
+ const port = options.port ?? await getFreePort();
1999
+ const env = {};
2000
+ if (options.serverBinary) env.ZITADEL_SERVER_BINARY = options.serverBinary;
2001
+ const result = await runCli({
2002
+ args: [
2003
+ "start",
2004
+ "--port",
2005
+ String(port),
2006
+ "--non-interactive",
2007
+ "--json",
2008
+ "-c",
2009
+ dir
2010
+ ],
2011
+ bin: options.cliBin,
2012
+ env,
2013
+ timeoutMs: options.timeoutMs
2014
+ });
2015
+ if (result.exitCode !== 0) throw new Error(`zitadel start exited with code ${result.exitCode}.\n${failureDetail(result)}\nstate dir kept for inspection: ${dir}`);
2016
+ const stopViaCli = async () => {
2017
+ const stopResult = await runCli({
2018
+ args: [
2019
+ "stop",
2020
+ "--non-interactive",
2021
+ "--json",
2022
+ "-c",
2023
+ dir
2024
+ ],
2025
+ bin: options.cliBin,
2026
+ env,
2027
+ timeoutMs: options.timeoutMs
2028
+ });
2029
+ if (stopResult.exitCode !== 0) throw new Error(`zitadel stop exited with code ${stopResult.exitCode}.\n${failureDetail(stopResult)}\nstate dir kept for inspection: ${dir}`);
2030
+ };
2031
+ let envelope;
2032
+ try {
2033
+ envelope = parseCliEnvelope(result.stdout, "zitadel start");
2034
+ if (envelope.status !== "ok") throw new Error(`zitadel start reported status "${envelope.status}":\n${describeEnvelopeError(envelope) ?? tail(result.stdout)}`);
2035
+ } catch (error) {
2036
+ const startError = new Error(`zitadel start produced unusable output.\nreason: ${error instanceof Error ? error.message : String(error)}\nstdout: ${tail(result.stdout) || "(empty)"}\nstderr: ${tail(result.stderr) || "(empty)"}\nstate dir kept for inspection: ${dir}`, { cause: error });
2037
+ try {
2038
+ await stopViaCli();
2039
+ } catch (stopError) {
2040
+ throw new AggregateError([startError, stopError], `${startError.message}\nStopping the possibly-running instance also failed: ${stopError instanceof Error ? stopError.message : String(stopError)}`);
2041
+ }
2042
+ throw startError;
2043
+ }
2044
+ const { runtime, urls } = envelope.data;
2045
+ const runStop = async () => {
2046
+ await stopViaCli();
2047
+ if (ownsDir && !options.keep) await (0, node_fs_promises.rm)(dir, {
2048
+ recursive: true,
2049
+ force: true
2050
+ });
2051
+ };
2052
+ let stopPromise;
2053
+ const stop = () => {
2054
+ stopPromise ??= runStop().catch((error) => {
2055
+ stopPromise = void 0;
2056
+ throw error;
2057
+ });
2058
+ return stopPromise;
2059
+ };
2060
+ return {
2061
+ baseUrl: urls.api,
2062
+ runtime: {
2063
+ port: runtime.port,
2064
+ pid: runtime.pid,
2065
+ dir,
2066
+ logPath: runtime.log_path
2067
+ },
2068
+ stop
2069
+ };
2070
+ }
2071
+ /**
2072
+ * A failed CLI run usually still prints an error envelope; its
2073
+ * message/hint/next_commands beat raw output tails (e.g. a fresh install
2074
+ * missing @zitadel/server gets "Reinstall @zitadel/cli" instead of a stack).
2075
+ */
2076
+ function failureDetail(result) {
2077
+ try {
2078
+ const described = describeEnvelopeError(parseCliEnvelope(result.stdout, "zitadel"));
2079
+ if (described) return described;
2080
+ } catch {}
2081
+ return `stdout: ${tail(result.stdout) || "(empty)"}\nstderr: ${tail(result.stderr) || "(empty)"}`;
2082
+ }
2083
+ //#endregion
2084
+ //#region src/seed.ts
2085
+ /**
2086
+ * A unique unused email + password. Nothing is created on the instance —
2087
+ * this is the input for registration-flow specs, which must prove the flow
2088
+ * creates the user.
2089
+ */
2090
+ function identity() {
2091
+ return {
2092
+ email: `e2e-${(0, node_crypto.randomUUID)().slice(0, 8)}@example.com`,
2093
+ password: `Pw!${(0, node_crypto.randomUUID)()}`
2094
+ };
2095
+ }
2096
+ /**
2097
+ * Create a user that can immediately complete the password login flow:
2098
+ * `POST /users` (the body must carry `$schema: <schema id>`) followed by
2099
+ * `PUT /users/{id}/password` with `isChangeRequired: false`.
2100
+ *
2101
+ * Defaults mint a unique email per call (email is x-unique per project), which
2102
+ * is what makes per-test seeding parallel-safe on a shared instance.
2103
+ */
2104
+ async function seedUser(client, context, input = {}) {
2105
+ const fresh = identity();
2106
+ const email = input.email ?? fresh.email;
2107
+ const password = input.password ?? fresh.password;
2108
+ const id = requireString((await client.createUser({
2109
+ ...input.attributes,
2110
+ $schema: context.schemaId,
2111
+ email
2112
+ }, { project_id: context.projectId })).id, "user id");
2113
+ await client.setUserPassword(id, {
2114
+ password,
2115
+ isChangeRequired: false
2116
+ }, { project_id: context.projectId });
2117
+ return {
2118
+ id,
2119
+ email,
2120
+ password
2121
+ };
2122
+ }
2123
+ /**
2124
+ * Seed `count` users sequentially. The template makes fixture data
2125
+ * deterministic per index (stable emails/names keep screenshot diffs about
2126
+ * code, not reshuffled data — the `console:dev-real` pattern); untemplated
2127
+ * fields fall back to the unique defaults. Name-like attributes need a
2128
+ * schema that declares them (`useCase: "consumer"` or wider).
2129
+ */
2130
+ async function seedUsers(client, context, count, template = {}) {
2131
+ const users = [];
2132
+ for (let index = 0; index < count; index += 1) users.push(await seedUser(client, context, {
2133
+ email: template.email?.(index),
2134
+ password: template.password?.(index),
2135
+ attributes: template.attributes?.(index)
2136
+ }));
2137
+ return users;
2138
+ }
2139
+ //#endregion
2140
+ //#region src/session.ts
2141
+ /** Mirrors the server's session cookie (internal/api/session.go). */
2142
+ const SESSION_COOKIE_NAME = "__nextgen_session";
2143
+ const MAX_FLOW_STEPS = 6;
2144
+ /**
2145
+ * Drive the real login flow headlessly for a seeded password user and
2146
+ * exchange the terminal handoff for a session: exactly what `<zitadel-login>`
2147
+ * does, minus the rendering. Supports flows whose steps only ask for the
2148
+ * user's email and password (the shipped `password-first` presets); any step
2149
+ * demanding more — a challenge, an unknown field — fails loudly by design.
2150
+ *
2151
+ * Flow calls use raw fetch instead of the typed client because the flow is
2152
+ * stateless through the sealed `_zflow` cookie (internal/api/flow.go): every
2153
+ * response re-seals the flow state into Set-Cookie, and submits are rejected
2154
+ * without it. Browsers round-trip it implicitly; here a one-cookie jar does.
2155
+ */
2156
+ async function mintSession(client, handle, context, user, options = {}) {
2157
+ const values = {
2158
+ email: user.email,
2159
+ password: user.password
2160
+ };
2161
+ const jar = new FlowCookieJar();
2162
+ const origin = options.origin;
2163
+ let response = await flowFetch(handle, jar, origin, "/flow", {
2164
+ project_id: context.projectId,
2165
+ purpose: "login",
2166
+ ...options.flowDefinitionName ? { flow_definition_name: options.flowDefinitionName } : {}
2167
+ });
2168
+ for (let hop = 0; hop < MAX_FLOW_STEPS; hop += 1) {
2169
+ if (response.handoff_token) {
2170
+ const exchanged = await client.exchangeHandoff({ handoff_token: response.handoff_token }, { project_id: context.projectId });
2171
+ return {
2172
+ user,
2173
+ sessionToken: exchanged.session_token,
2174
+ expiresAt: exchanged.session.expires_at,
2175
+ cookie: {
2176
+ name: SESSION_COOKIE_NAME,
2177
+ value: exchanged.session_token,
2178
+ httpOnly: true,
2179
+ secure: true,
2180
+ sameSite: "Lax",
2181
+ path: "/"
2182
+ }
2183
+ };
2184
+ }
2185
+ response = await flowFetch(handle, jar, origin, `/flow/${encodeURIComponent(response.id)}/submit`, {
2186
+ session_token: response.session_token,
2187
+ action: "submit",
2188
+ fields: collectFields(response, values)
2189
+ });
2190
+ }
2191
+ throw new Error(`seed.session: flow did not complete within ${MAX_FLOW_STEPS} steps (last step: ${describeStep(response)}).`);
2192
+ }
2193
+ /** One-cookie jar for the sealed `_zflow` flow-state cookie. */
2194
+ var FlowCookieJar = class {
2195
+ cookie;
2196
+ absorb(response) {
2197
+ for (const raw of response.headers.getSetCookie()) {
2198
+ const [pair] = raw.split(";", 1);
2199
+ if (pair?.startsWith("_zflow=")) this.cookie = pair;
2200
+ }
2201
+ }
2202
+ header() {
2203
+ return this.cookie ? { cookie: this.cookie } : {};
2204
+ }
2205
+ };
2206
+ async function flowFetch(handle, jar, origin, path, body) {
2207
+ const response = await fetch(`${handle.baseUrl}${path}`, {
2208
+ method: "POST",
2209
+ headers: {
2210
+ "content-type": "application/json",
2211
+ authorization: `Bearer ${handle.projectSecret}`,
2212
+ ...origin ? { origin } : {},
2213
+ ...jar.header()
2214
+ },
2215
+ body: JSON.stringify(body)
2216
+ });
2217
+ jar.absorb(response);
2218
+ const parsed = await response.json().catch(() => void 0);
2219
+ if (!response.ok || !parsed) {
2220
+ const detail = parsed && typeof parsed === "object" ? ` — ${JSON.stringify(parsed)}` : "";
2221
+ const hint = !origin && /origin/i.test(detail) ? "\nNo Origin header was sent: pass `origin` to seedSession() (the Playwright fixtures pass the suite's baseURL) or `appOrigins` to startLocalZitadel()." : "";
2222
+ throw new Error(`seed.session: POST ${path} returned ${response.status}${detail}${hint}`);
2223
+ }
2224
+ return parsed;
2225
+ }
2226
+ /**
2227
+ * Fill exactly the fields the current step declares — the orchestrator's
2228
+ * convention — from the known email/password values. An unknown required
2229
+ * field means this flow needs more than a password login can provide.
2230
+ */
2231
+ function collectFields(response, values) {
2232
+ const fields = {};
2233
+ for (const field of response.step.fields ?? []) {
2234
+ const value = values[fieldKey(field)];
2235
+ if (value === void 0) throw new Error(`seed.session supports password flows only; step ${describeStep(response)} declares field "${field.name}", which the kit cannot fill. Log in through the UI for flows with additional factors.`);
2236
+ fields[field.name] = value;
2237
+ }
2238
+ return fields;
2239
+ }
2240
+ /**
2241
+ * Steps name credential fields with schema pointers (e.g.
2242
+ * `x-auth-methods#password`); match on the trailing segment so the value map
2243
+ * stays the plain `{ email, password }` a caller thinks in.
2244
+ */
2245
+ function fieldKey(field) {
2246
+ const name = field.name;
2247
+ return (name.split(/[#/.]/).at(-1) ?? name).toLowerCase();
2248
+ }
2249
+ function describeStep(response) {
2250
+ const name = response.step.name ?? "(unnamed)";
2251
+ const declared = (response.step.fields ?? []).map((field) => field.name).join(", ");
2252
+ return `"${name}"${declared ? ` [fields: ${declared}]` : ""}`;
2253
+ }
2254
+ //#endregion
2255
+ //#region src/index.ts
2256
+ /**
2257
+ * Attach to an already-bootstrapped instance/project. Lifecycle-free on
2258
+ * purpose: this is the entry point for Playwright workers (via the handshake
2259
+ * file) and, later, for seeding remote instances.
2260
+ */
2261
+ function connectZitadel(handle) {
2262
+ const api = createZitadelClient({
2263
+ baseUrl: handle.baseUrl,
2264
+ token: handle.projectSecret
2265
+ });
2266
+ const context = {
2267
+ projectId: handle.projectId,
2268
+ schemaId: handle.schemaId
2269
+ };
2270
+ return {
2271
+ handle,
2272
+ api,
2273
+ appEnv: require_handshake.applyAppEnvTemplate(require_handshake.nextAppEnv, handle),
2274
+ seedUser: (input) => seedUser(api, context, input),
2275
+ seedUsers: (count, template) => seedUsers(api, context, count, template),
2276
+ identity,
2277
+ seedSession: async (input = {}) => {
2278
+ const { user: existing, flowDefinitionName, origin, ...userInput } = input;
2279
+ return mintSession(api, handle, context, existing ?? await seedUser(api, context, userInput), {
2280
+ flowDefinitionName,
2281
+ origin: origin ?? handle.appOrigin
2282
+ });
2283
+ }
2284
+ };
2285
+ }
2286
+ /**
2287
+ * Boot an ephemeral local instance (binary runtime + embedded Postgres, no
2288
+ * Docker) and bootstrap a project + default schema + login flow on it. The
2289
+ * result can seed loginable password users immediately.
2290
+ */
2291
+ async function startLocalZitadel(options = {}) {
2292
+ const server = await bootLocalServer(options);
2293
+ let bootstrapped;
2294
+ try {
2295
+ bootstrapped = await bootstrapProject({
2296
+ baseUrl: server.baseUrl,
2297
+ projectName: options.projectName,
2298
+ appOrigins: options.appOrigins,
2299
+ preset: options.preset,
2300
+ useCase: options.useCase
2301
+ });
2302
+ } catch (error) {
2303
+ try {
2304
+ await server.stop();
2305
+ } catch (stopError) {
2306
+ throw new AggregateError([error, stopError], "bootstrap failed, and stopping the booted instance also failed");
2307
+ }
2308
+ throw error;
2309
+ }
2310
+ return {
2311
+ ...connectZitadel({
2312
+ baseUrl: server.baseUrl,
2313
+ projectId: bootstrapped.projectId,
2314
+ projectSecret: bootstrapped.projectSecret,
2315
+ schemaId: bootstrapped.schemaId,
2316
+ previewSecret: bootstrapped.previewSecret,
2317
+ appOrigin: options.appOrigins?.[0]
2318
+ }),
2319
+ runtime: server.runtime,
2320
+ stop: server.stop,
2321
+ [Symbol.asyncDispose]: server.stop
2322
+ };
2323
+ }
2324
+ //#endregion
2325
+ Object.defineProperty(exports, "SESSION_COOKIE_NAME", {
2326
+ enumerable: true,
2327
+ get: function() {
2328
+ return SESSION_COOKIE_NAME;
2329
+ }
2330
+ });
2331
+ Object.defineProperty(exports, "bootLocalServer", {
2332
+ enumerable: true,
2333
+ get: function() {
2334
+ return bootLocalServer;
2335
+ }
2336
+ });
2337
+ Object.defineProperty(exports, "bootstrapProject", {
2338
+ enumerable: true,
2339
+ get: function() {
2340
+ return bootstrapProject;
2341
+ }
2342
+ });
2343
+ Object.defineProperty(exports, "connectZitadel", {
2344
+ enumerable: true,
2345
+ get: function() {
2346
+ return connectZitadel;
2347
+ }
2348
+ });
2349
+ Object.defineProperty(exports, "startLocalZitadel", {
2350
+ enumerable: true,
2351
+ get: function() {
2352
+ return startLocalZitadel;
2353
+ }
2354
+ });
2355
+
2356
+ //# sourceMappingURL=src-BIL0PdSd.cjs.map