@zitadel/config 0.1.0-alpha.14 → 0.1.0-alpha.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/defaults/README-flows.md +66 -9
- package/defaults/README-schemas.md +139 -30
- package/defaults/default-login.json +1 -0
- package/defaults/presets/passkey-first/human-user.json +46 -0
- package/defaults/presets/passkey-first/login.json +161 -0
- package/dist/{defaults-B2iIPSSl.mjs → defaults-BQej3KIY.mjs} +191 -4
- package/dist/defaults-BQej3KIY.mjs.map +1 -0
- package/dist/{defaults-DzfOT2_7.d.mts → defaults-CSjBjBkQ.d.mts} +14 -3
- package/dist/defaults-CSjBjBkQ.d.mts.map +1 -0
- package/dist/defaults.d.mts +2 -2
- package/dist/defaults.mjs +2 -2
- package/dist/index.d.mts +5 -2
- package/dist/index.mjs +5 -2
- package/dist/meta-schemas-8nlyVL7g.mjs +456 -0
- package/dist/meta-schemas-8nlyVL7g.mjs.map +1 -0
- package/dist/meta-schemas.d.mts +21 -0
- package/dist/meta-schemas.d.mts.map +1 -0
- package/dist/meta-schemas.mjs +2 -0
- package/dist/normalize.d.mts +45 -0
- package/dist/normalize.d.mts.map +1 -0
- package/dist/normalize.mjs +88 -0
- package/dist/normalize.mjs.map +1 -0
- package/dist/validate.d.mts +94 -0
- package/dist/validate.d.mts.map +1 -0
- package/dist/validate.mjs +371 -0
- package/dist/validate.mjs.map +1 -0
- package/meta-schemas/auth-method.json +20 -0
- package/meta-schemas/auth-methods.json +24 -0
- package/meta-schemas/flow-definition.json +344 -0
- package/meta-schemas/user-property.json +76 -0
- package/meta-schemas/user-schema.json +50 -0
- package/package.json +20 -2
- package/dist/defaults-B2iIPSSl.mjs.map +0 -1
- package/dist/defaults-DzfOT2_7.d.mts.map +0 -1
|
@@ -0,0 +1,456 @@
|
|
|
1
|
+
//#region meta-schemas/auth-method.json
|
|
2
|
+
var auth_method_default = {
|
|
3
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
4
|
+
title: "AuthMethod",
|
|
5
|
+
type: "object",
|
|
6
|
+
required: ["enabled", "position"],
|
|
7
|
+
properties: {
|
|
8
|
+
"enabled": {
|
|
9
|
+
"type": "boolean",
|
|
10
|
+
"description": "Whether the authentication method is enabled or not"
|
|
11
|
+
},
|
|
12
|
+
"position": {
|
|
13
|
+
"type": "integer",
|
|
14
|
+
"minimum": 0,
|
|
15
|
+
"description": "The position of the authentication method in the list of supported methods"
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
//#endregion
|
|
20
|
+
//#region meta-schemas/auth-methods.json
|
|
21
|
+
var auth_methods_default = {
|
|
22
|
+
type: "object",
|
|
23
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
24
|
+
description: "A list of authentication methods supported by the user definition.",
|
|
25
|
+
minProperties: 1,
|
|
26
|
+
additionalProperties: false,
|
|
27
|
+
properties: {
|
|
28
|
+
"password": { "$ref": "auth-method.json" },
|
|
29
|
+
"passkey": { "$ref": "auth-method.json" },
|
|
30
|
+
"magic_link": { "$ref": "auth-method.json" },
|
|
31
|
+
"sso": { "$ref": "auth-method.json" },
|
|
32
|
+
"otp": { "$ref": "auth-method.json" }
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
//#endregion
|
|
36
|
+
//#region meta-schemas/flow-definition.json
|
|
37
|
+
var flow_definition_default = {
|
|
38
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
39
|
+
title: "FlowDefinition",
|
|
40
|
+
description: "Admin-authored configuration for a flow. A flow definition is a directed graph of steps backed by a user schema. The flow engine selects a definition based on `purpose` and `audience`, then walks the graph by evaluating `transitions` against client submissions. This schema describes the configuration shape only. Runtime emission to the client (capability dictionaries, branding, localized text) is a separate concern and is not modelled here.",
|
|
41
|
+
type: "object",
|
|
42
|
+
required: [
|
|
43
|
+
"name",
|
|
44
|
+
"status",
|
|
45
|
+
"user_schema",
|
|
46
|
+
"purposes",
|
|
47
|
+
"steps"
|
|
48
|
+
],
|
|
49
|
+
additionalProperties: false,
|
|
50
|
+
properties: {
|
|
51
|
+
"$schema": {
|
|
52
|
+
"type": "string",
|
|
53
|
+
"description": "Editor affordance: path or URL of this meta-schema so editors validate and autocomplete the file (scaffolded flow files point at `.zitadel/meta/flow-definition.json`). Ignored by the platform."
|
|
54
|
+
},
|
|
55
|
+
"name": {
|
|
56
|
+
"type": "string",
|
|
57
|
+
"pattern": "^[a-z][a-z0-9-]*$",
|
|
58
|
+
"examples": ["standard-login", "combined-auth"],
|
|
59
|
+
"description": "Stable identifier for this flow, used as the target of cross-flow `switch` and `pivot` transitions. Renaming is not supported — the `name` is part of the public contract another definition may reference. Acts as the human display label as well; no separate slug."
|
|
60
|
+
},
|
|
61
|
+
"status": {
|
|
62
|
+
"type": "string",
|
|
63
|
+
"enum": ["active", "draft"],
|
|
64
|
+
"description": "Lifecycle state. - active: the engine can select this definition for new flows. - draft: never selected for new flows; existing flows referencing it must handle it gracefully."
|
|
65
|
+
},
|
|
66
|
+
"user_schema": {
|
|
67
|
+
"type": "string",
|
|
68
|
+
"examples": ["sch_01KWHF18816ZQESRCS7Z2STJ05"],
|
|
69
|
+
"description": "Server-assigned identifier of the user schema this flow operates on, as returned by `POST /schemas`. Opaque to the client — the shape is a server implementation detail. Step `fields` reference property names defined in that schema; the engine resolves field type, validation, and implicit transition outcomes from the schema's `x-*` annotations at runtime."
|
|
70
|
+
},
|
|
71
|
+
"purposes": {
|
|
72
|
+
"type": "object",
|
|
73
|
+
"minProperties": 1,
|
|
74
|
+
"propertyNames": { "$ref": "#/$defs/Purpose" },
|
|
75
|
+
"additionalProperties": {
|
|
76
|
+
"type": "string",
|
|
77
|
+
"description": "Name of an entry-point step within this definition."
|
|
78
|
+
},
|
|
79
|
+
"examples": [{ "login": "identify" }, {
|
|
80
|
+
"login": "identify",
|
|
81
|
+
"register": "identify"
|
|
82
|
+
}],
|
|
83
|
+
"description": "Maps each purpose this definition handles to the step that begins the flow for that purpose. Every value must match a `name` in `steps`; the check is enforced by the engine, not by this schema."
|
|
84
|
+
},
|
|
85
|
+
"audience": {
|
|
86
|
+
"$ref": "#/$defs/Audience",
|
|
87
|
+
"description": "Scopes which requests this definition applies to. Omitted or empty arrays mean project-wide. The engine ranks matches by specificity (app > team > project-wide)."
|
|
88
|
+
},
|
|
89
|
+
"steps": {
|
|
90
|
+
"type": "array",
|
|
91
|
+
"minItems": 1,
|
|
92
|
+
"items": { "$ref": "#/$defs/Step" },
|
|
93
|
+
"description": "Step graph. Order is for human readability; actual sequencing is determined entirely by `transitions`. Every step's `name` must be unique within this array."
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
$defs: {
|
|
97
|
+
"Purpose": {
|
|
98
|
+
"type": "string",
|
|
99
|
+
"enum": [
|
|
100
|
+
"login",
|
|
101
|
+
"register",
|
|
102
|
+
"recovery",
|
|
103
|
+
"profiling",
|
|
104
|
+
"reauth",
|
|
105
|
+
"link_account"
|
|
106
|
+
],
|
|
107
|
+
"description": "What the user is trying to accomplish. - login: authenticate an existing user. - register: create a new user. - recovery: recover access (e.g. password reset). - profiling: collect required profile fields after authentication. - reauth: re-verify factors on an active session for step-up. - link_account: attach an external identity to an existing user."
|
|
108
|
+
},
|
|
109
|
+
"Audience": {
|
|
110
|
+
"type": "object",
|
|
111
|
+
"additionalProperties": false,
|
|
112
|
+
"properties": {
|
|
113
|
+
"team_ids": {
|
|
114
|
+
"type": "array",
|
|
115
|
+
"uniqueItems": true,
|
|
116
|
+
"items": { "type": "string" },
|
|
117
|
+
"examples": [["team_acme"]],
|
|
118
|
+
"description": "Restrict to specific teams (organizations)."
|
|
119
|
+
},
|
|
120
|
+
"app_ids": {
|
|
121
|
+
"type": "array",
|
|
122
|
+
"uniqueItems": true,
|
|
123
|
+
"items": { "type": "string" },
|
|
124
|
+
"examples": [["app_dashboard"]],
|
|
125
|
+
"description": "Restrict to specific applications."
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
"Step": {
|
|
130
|
+
"type": "object",
|
|
131
|
+
"required": ["name"],
|
|
132
|
+
"additionalProperties": false,
|
|
133
|
+
"properties": {
|
|
134
|
+
"name": {
|
|
135
|
+
"type": "string",
|
|
136
|
+
"pattern": "^[a-z][a-z0-9-]*$",
|
|
137
|
+
"examples": [
|
|
138
|
+
"identify",
|
|
139
|
+
"authenticate",
|
|
140
|
+
"done"
|
|
141
|
+
],
|
|
142
|
+
"description": "Unique step identifier within this definition. Slug-shaped so it is safe to use as a transition `target` and as a value in `purposes`. Referenced by other steps in the same definition."
|
|
143
|
+
},
|
|
144
|
+
"fields": {
|
|
145
|
+
"type": "array",
|
|
146
|
+
"uniqueItems": true,
|
|
147
|
+
"items": { "type": "string" },
|
|
148
|
+
"examples": [["email"], ["email", "password"]],
|
|
149
|
+
"description": "Schema property names to collect from the user on this step. Each entry must resolve to a property in the definition's `user_schema`, or use the reserved token `x-auth-methods#<method>` (e.g. `x-auth-methods#password`) to collect a credential proof for a method enabled at the schema root. The engine reads the schema's `x-*` annotations to derive: - field type and validation (rendered into the runtime payload), - implicit transition outcomes - e.g. a property with a non-empty `x-unique` scope makes `user_not_found` a valid `transitions` key on this step."
|
|
150
|
+
},
|
|
151
|
+
"actions": {
|
|
152
|
+
"type": "array",
|
|
153
|
+
"items": { "$ref": "#/$defs/Action" },
|
|
154
|
+
"description": "Ordered list of actions the user can take on this step. The `name` is what the client echoes back on submit. Every action's name must have a matching key in `transitions`; the engine rejects submissions for actions without a defined transition."
|
|
155
|
+
},
|
|
156
|
+
"gates": {
|
|
157
|
+
"type": "object",
|
|
158
|
+
"additionalProperties": { "$ref": "#/$defs/Gate" },
|
|
159
|
+
"description": "Security challenges that must be satisfied before this step's submission is accepted. Keyed by gate name (free identifier; referenced as the key in the runtime `step.gates` dictionary). The engine may inject additional gates at runtime based on policy or risk evaluation."
|
|
160
|
+
},
|
|
161
|
+
"sso_providers": {
|
|
162
|
+
"type": "array",
|
|
163
|
+
"items": { "$ref": "#/$defs/SSOProvider" },
|
|
164
|
+
"description": "Identity providers available on this step. When non-empty, the step must define a `transitions.callback` entry — the engine handles the reserved `sso` action transparently (redirect to the IdP, code exchange, user resolution) and fires `callback` on this step when the IdP returns. The flow author never writes a `transitions.sso`."
|
|
165
|
+
},
|
|
166
|
+
"on_success": {
|
|
167
|
+
"type": "string",
|
|
168
|
+
"enum": ["create_user"],
|
|
169
|
+
"description": "Server-side mutation to run after the step's fields validate and before the transition fires. - create_user: materialize the user from collected schema fields. Used by register flows."
|
|
170
|
+
},
|
|
171
|
+
"complete": {
|
|
172
|
+
"type": "string",
|
|
173
|
+
"enum": ["redirect", "show"],
|
|
174
|
+
"description": "Marks this step as terminal. A terminal step has no `fields`, `actions`, `transitions`, `gates`, or `sso_providers`. - redirect: client navigates to a `redirect_uri` resolved from the originating protocol request (OIDC, SAML). - show: client renders the step as a success or info screen."
|
|
175
|
+
},
|
|
176
|
+
"transitions": {
|
|
177
|
+
"type": "object",
|
|
178
|
+
"additionalProperties": { "$ref": "#/$defs/Transition" },
|
|
179
|
+
"description": "Maps action names and engine-emitted outcomes to the next state. Keys are either: - an action name declared in this step's `actions`, or - a reserved outcome the engine produces: - `user_not_found` - emitted when a unique field (`x-unique`) does not match an existing user. - `user_already_exists` - emitted when registration matches an existing user. - `callback` - emitted when an external system returns control to the flow (SSO callback, device authorization poll, etc.). A transition's `action` field controls whether the target is interpreted as a step in this definition (default) or as the name of another definition to switch or pivot into."
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
"Action": {
|
|
184
|
+
"type": "object",
|
|
185
|
+
"additionalProperties": false,
|
|
186
|
+
"properties": {
|
|
187
|
+
"name": {
|
|
188
|
+
"type": "string",
|
|
189
|
+
"minLength": 1,
|
|
190
|
+
"examples": [
|
|
191
|
+
"submit",
|
|
192
|
+
"passkey",
|
|
193
|
+
"email_fallback"
|
|
194
|
+
],
|
|
195
|
+
"description": "Action identifier, echoed back by the client on submit and matched against `transitions`. The name `back` is reserved for engine-injected back navigation."
|
|
196
|
+
},
|
|
197
|
+
"kind": {
|
|
198
|
+
"type": "string",
|
|
199
|
+
"enum": [
|
|
200
|
+
"submit",
|
|
201
|
+
"passkey",
|
|
202
|
+
"passkey_register",
|
|
203
|
+
"navigate"
|
|
204
|
+
],
|
|
205
|
+
"description": "How the engine handles the action. - submit: collect the step's fields and run validate/dispatch/on_success. - passkey: issue a WebAuthn assertion challenge; the matching transition fires once the assertion verifies. - passkey_register: issue a WebAuthn registration challenge; the matching transition fires once the attestation verifies. - navigate: route through the transition without running the input pipeline. (`back` exists on the wire but is engine-injected; declaring it is rejected.)"
|
|
206
|
+
},
|
|
207
|
+
"primary": {
|
|
208
|
+
"type": "boolean",
|
|
209
|
+
"default": false,
|
|
210
|
+
"description": "Marks this as the default/primary action. The runtime template uses this hint to choose visual emphasis. At most one action per step should be primary; this is not enforced here."
|
|
211
|
+
},
|
|
212
|
+
"text_key": {
|
|
213
|
+
"type": "string",
|
|
214
|
+
"examples": ["actions.signin.submit"],
|
|
215
|
+
"description": "Optional localization key override for the action's label. When omitted, the engine derives a key from the step and action names. Display text is resolved client-side from a locale dictionary, never by the engine."
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
"description": "Configuration for a user-invokable action on a step.",
|
|
219
|
+
"required": ["name", "kind"]
|
|
220
|
+
},
|
|
221
|
+
"Gate": {
|
|
222
|
+
"type": "object",
|
|
223
|
+
"required": ["kind", "provider"],
|
|
224
|
+
"additionalProperties": false,
|
|
225
|
+
"properties": {
|
|
226
|
+
"kind": {
|
|
227
|
+
"type": "string",
|
|
228
|
+
"enum": ["captcha"],
|
|
229
|
+
"description": "The gate category. Only `captcha` is currently defined. Authenticator ceremonies (e.g. passkey) are modelled as credential auth_attempts via `x-credential` on a field, not as gates."
|
|
230
|
+
},
|
|
231
|
+
"provider": {
|
|
232
|
+
"type": "string",
|
|
233
|
+
"examples": [
|
|
234
|
+
"altcha",
|
|
235
|
+
"turnstile",
|
|
236
|
+
"hcaptcha"
|
|
237
|
+
],
|
|
238
|
+
"description": "Provider identifier within the gate kind — e.g. `altcha`, `turnstile`, `hcaptcha`. The engine looks up an implementation in its provider registry."
|
|
239
|
+
},
|
|
240
|
+
"config": {
|
|
241
|
+
"type": "object",
|
|
242
|
+
"additionalProperties": true,
|
|
243
|
+
"examples": [{ "site_key": "0x4AAAAAAAxxxxxxxxxxxxxx" }],
|
|
244
|
+
"description": "Provider-specific configuration consumed by the implementation when issuing the per-render challenge. Opaque to the engine."
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
"SSOProvider": {
|
|
249
|
+
"type": "object",
|
|
250
|
+
"required": [
|
|
251
|
+
"id",
|
|
252
|
+
"name",
|
|
253
|
+
"template"
|
|
254
|
+
],
|
|
255
|
+
"additionalProperties": false,
|
|
256
|
+
"properties": {
|
|
257
|
+
"id": {
|
|
258
|
+
"type": "string",
|
|
259
|
+
"examples": ["google", "corp_idp"],
|
|
260
|
+
"description": "Provider instance identifier. Echoed back by the client when the user picks a provider; routed to the corresponding configured IdP at the engine."
|
|
261
|
+
},
|
|
262
|
+
"name": {
|
|
263
|
+
"type": "string",
|
|
264
|
+
"examples": ["Google", "Acme SSO"],
|
|
265
|
+
"description": "Display name surfaced to the user. Localized client-side if a matching text key exists in the locale dictionary."
|
|
266
|
+
},
|
|
267
|
+
"template": {
|
|
268
|
+
"type": "string",
|
|
269
|
+
"examples": [
|
|
270
|
+
"google",
|
|
271
|
+
"entraid",
|
|
272
|
+
"github"
|
|
273
|
+
],
|
|
274
|
+
"description": "Hint for rendering (logo, brand colors) — e.g. `google`, `entraid`, `github`. Consumed by the runtime template, not by the engine."
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
},
|
|
278
|
+
"Transition": {
|
|
279
|
+
"type": "object",
|
|
280
|
+
"required": ["target"],
|
|
281
|
+
"additionalProperties": false,
|
|
282
|
+
"properties": {
|
|
283
|
+
"target": {
|
|
284
|
+
"type": "string",
|
|
285
|
+
"examples": [
|
|
286
|
+
"authenticate",
|
|
287
|
+
"register",
|
|
288
|
+
"recovery"
|
|
289
|
+
],
|
|
290
|
+
"description": "When `action` is omitted, the `name` of a step in the same definition. When `action` is `switch` or `pivot`, the `name` of another flow definition in the same project."
|
|
291
|
+
},
|
|
292
|
+
"action": {
|
|
293
|
+
"type": ["string", "null"],
|
|
294
|
+
"enum": [
|
|
295
|
+
"switch",
|
|
296
|
+
"pivot",
|
|
297
|
+
null
|
|
298
|
+
],
|
|
299
|
+
"description": "How to interpret `target`. - Omitted: transition to a step in the current definition. - `switch`: replace the current flow with the target flow. No return; the current flow is discarded. Typical use: navigating between peer flows like login ↔ register. - `pivot`: push the target flow onto the stack. The current flow is paused; when the target flow completes the engine auto-pops back. Typical use: login → recovery → back to login."
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
};
|
|
305
|
+
//#endregion
|
|
306
|
+
//#region meta-schemas/user-property.json
|
|
307
|
+
var user_property_default = {
|
|
308
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
309
|
+
title: "UserProperty",
|
|
310
|
+
type: "object",
|
|
311
|
+
allOf: [{ "$ref": "https://json-schema.org/draft/2020-12/schema" }],
|
|
312
|
+
additionalProperties: true,
|
|
313
|
+
properties: {
|
|
314
|
+
"$schema": {
|
|
315
|
+
"type": "string",
|
|
316
|
+
"const": "https://json-schema.org/draft/2020-12/schema",
|
|
317
|
+
"description": "The JSON Schema version used for this schema."
|
|
318
|
+
},
|
|
319
|
+
"x-verify": {
|
|
320
|
+
"oneOf": [{ "type": "string" }, { "type": "null" }],
|
|
321
|
+
"description": "The verification method for this property, if applicable"
|
|
322
|
+
},
|
|
323
|
+
"x-unique": {
|
|
324
|
+
"oneOf": [{
|
|
325
|
+
"type": "string",
|
|
326
|
+
"enum": [
|
|
327
|
+
"unspecified",
|
|
328
|
+
"project",
|
|
329
|
+
"team"
|
|
330
|
+
]
|
|
331
|
+
}, { "type": "null" }],
|
|
332
|
+
"description": "The level of uniqueness for this property, if applicable"
|
|
333
|
+
},
|
|
334
|
+
"x-claim": {
|
|
335
|
+
"oneOf": [{ "type": "string" }, { "type": "null" }],
|
|
336
|
+
"description": "The claim name for this property, if applicable"
|
|
337
|
+
},
|
|
338
|
+
"x-editable": {
|
|
339
|
+
"type": "boolean",
|
|
340
|
+
"default": true,
|
|
341
|
+
"description": "Whether this property is editable by the user or not"
|
|
342
|
+
},
|
|
343
|
+
"x-sensitive": {
|
|
344
|
+
"type": "boolean",
|
|
345
|
+
"default": false,
|
|
346
|
+
"description": "Whether this property contains sensitive information or not"
|
|
347
|
+
},
|
|
348
|
+
"x-mfa": {
|
|
349
|
+
"type": "boolean",
|
|
350
|
+
"default": false,
|
|
351
|
+
"description": "Whether this property is used for multi-factor authentication or not"
|
|
352
|
+
},
|
|
353
|
+
"properties": {
|
|
354
|
+
"type": "object",
|
|
355
|
+
"description": "A map of additional properties for the user definition, where the key is the property name and the value is the property schema",
|
|
356
|
+
"additionalProperties": true
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
};
|
|
360
|
+
//#endregion
|
|
361
|
+
//#region meta-schemas/user-schema.json
|
|
362
|
+
var user_schema_default = {
|
|
363
|
+
title: "UserSchema",
|
|
364
|
+
$schema: "https://json-schema.org/draft/2020-12/schema",
|
|
365
|
+
type: "object",
|
|
366
|
+
required: [
|
|
367
|
+
"metaSchema",
|
|
368
|
+
"kind",
|
|
369
|
+
"x-auth-methods"
|
|
370
|
+
],
|
|
371
|
+
allOf: [{ "$ref": "https://json-schema.org/draft/2020-12/schema" }],
|
|
372
|
+
additionalProperties: true,
|
|
373
|
+
properties: {
|
|
374
|
+
"$schema": {
|
|
375
|
+
"type": "string",
|
|
376
|
+
"const": "https://json-schema.org/draft/2020-12/schema",
|
|
377
|
+
"description": "The JSON Schema version used for this schema."
|
|
378
|
+
},
|
|
379
|
+
"objectType": {
|
|
380
|
+
"type": "string",
|
|
381
|
+
"maxLength": 256,
|
|
382
|
+
"description": "The type of user this schema describes. This is a customer chosen name.",
|
|
383
|
+
"example": "human-user"
|
|
384
|
+
},
|
|
385
|
+
"kind": {
|
|
386
|
+
"type": "string",
|
|
387
|
+
"const": "user-schema",
|
|
388
|
+
"description": "Discriminator value for a user schema create request."
|
|
389
|
+
},
|
|
390
|
+
"metaSchema": {
|
|
391
|
+
"type": "string",
|
|
392
|
+
"maxLength": 1024,
|
|
393
|
+
"format": "uri",
|
|
394
|
+
"description": "The user Schema version used for this schema."
|
|
395
|
+
},
|
|
396
|
+
"x-auth-methods": { "$ref": "auth-methods.json" },
|
|
397
|
+
"properties": {
|
|
398
|
+
"type": "object",
|
|
399
|
+
"description": "A map of additional properties for the user definition, where the key is the property name and the value is the property schema",
|
|
400
|
+
"additionalProperties": { "$ref": "user-property.json" }
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
};
|
|
404
|
+
//#endregion
|
|
405
|
+
//#region src/meta-schemas.ts
|
|
406
|
+
/**
|
|
407
|
+
* The dialect meta-schemas `zitadel setup` copies into a project's
|
|
408
|
+
* `.zitadel/meta/` so the flow/schema dialect is machine-readable offline:
|
|
409
|
+
* editors validate flow files against `flow-definition.json` via a relative
|
|
410
|
+
* `$schema` pointer, and agents read the dialect files before authoring
|
|
411
|
+
* edits — no docs crawl, no hosted schema required.
|
|
412
|
+
*
|
|
413
|
+
* The files under `meta-schemas/` are committed copies of
|
|
414
|
+
* `api/openapi/endpoints/schemas/*.json` (the source the server embeds);
|
|
415
|
+
* a drift-audit test keeps them byte-identical in the monorepo.
|
|
416
|
+
*/
|
|
417
|
+
/** Project-relative directory setup writes the meta-schemas to. */
|
|
418
|
+
const META_SCHEMA_DIR = ".zitadel/meta";
|
|
419
|
+
/**
|
|
420
|
+
* The `$schema` value scaffolded flow files carry, relative to
|
|
421
|
+
* `.zitadel/flows/` — resolves to `{@link META_SCHEMA_DIR}/flow-definition.json`.
|
|
422
|
+
*/
|
|
423
|
+
const FLOW_FILE_SCHEMA_REF = "../meta/flow-definition.json";
|
|
424
|
+
/**
|
|
425
|
+
* The dialect files to materialize, in write order. `auth-methods.json` and
|
|
426
|
+
* `auth-method.json` are pulled in by `user-schema.json`'s relative `$ref`s —
|
|
427
|
+
* without them the copied dialect cannot resolve offline.
|
|
428
|
+
*/
|
|
429
|
+
function metaSchemaFiles() {
|
|
430
|
+
return [
|
|
431
|
+
{
|
|
432
|
+
name: "flow-definition.json",
|
|
433
|
+
body: flow_definition_default
|
|
434
|
+
},
|
|
435
|
+
{
|
|
436
|
+
name: "user-schema.json",
|
|
437
|
+
body: user_schema_default
|
|
438
|
+
},
|
|
439
|
+
{
|
|
440
|
+
name: "user-property.json",
|
|
441
|
+
body: user_property_default
|
|
442
|
+
},
|
|
443
|
+
{
|
|
444
|
+
name: "auth-methods.json",
|
|
445
|
+
body: auth_methods_default
|
|
446
|
+
},
|
|
447
|
+
{
|
|
448
|
+
name: "auth-method.json",
|
|
449
|
+
body: auth_method_default
|
|
450
|
+
}
|
|
451
|
+
];
|
|
452
|
+
}
|
|
453
|
+
//#endregion
|
|
454
|
+
export { META_SCHEMA_DIR as n, metaSchemaFiles as r, FLOW_FILE_SCHEMA_REF as t };
|
|
455
|
+
|
|
456
|
+
//# sourceMappingURL=meta-schemas-8nlyVL7g.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"meta-schemas-8nlyVL7g.mjs","names":["flowDefinitionMetaSchema","userSchemaMetaSchema","userPropertyMetaSchema","authMethodsMetaSchema","authMethodMetaSchema"],"sources":["../meta-schemas/auth-method.json","../meta-schemas/auth-methods.json","../meta-schemas/flow-definition.json","../meta-schemas/user-property.json","../meta-schemas/user-schema.json","../src/meta-schemas.ts"],"sourcesContent":["","","","","","/**\n * The dialect meta-schemas `zitadel setup` copies into a project's\n * `.zitadel/meta/` so the flow/schema dialect is machine-readable offline:\n * editors validate flow files against `flow-definition.json` via a relative\n * `$schema` pointer, and agents read the dialect files before authoring\n * edits — no docs crawl, no hosted schema required.\n *\n * The files under `meta-schemas/` are committed copies of\n * `api/openapi/endpoints/schemas/*.json` (the source the server embeds);\n * a drift-audit test keeps them byte-identical in the monorepo.\n */\nimport authMethodMetaSchema from \"../meta-schemas/auth-method.json\" with {\n type: \"json\",\n};\nimport authMethodsMetaSchema from \"../meta-schemas/auth-methods.json\" with {\n type: \"json\",\n};\nimport flowDefinitionMetaSchema from \"../meta-schemas/flow-definition.json\" with {\n type: \"json\",\n};\nimport userPropertyMetaSchema from \"../meta-schemas/user-property.json\" with {\n type: \"json\",\n};\nimport userSchemaMetaSchema from \"../meta-schemas/user-schema.json\" with {\n type: \"json\",\n};\n\n/** Project-relative directory setup writes the meta-schemas to. */\nexport const META_SCHEMA_DIR = \".zitadel/meta\";\n\n/**\n * The `$schema` value scaffolded flow files carry, relative to\n * `.zitadel/flows/` — resolves to `{@link META_SCHEMA_DIR}/flow-definition.json`.\n */\nexport const FLOW_FILE_SCHEMA_REF = \"../meta/flow-definition.json\";\n\nexport type MetaSchemaFile = { name: string; body: object };\n\n/**\n * The dialect files to materialize, in write order. `auth-methods.json` and\n * `auth-method.json` are pulled in by `user-schema.json`'s relative `$ref`s —\n * without them the copied dialect cannot resolve offline.\n */\nexport function metaSchemaFiles(): ReadonlyArray<MetaSchemaFile> {\n return [\n { name: \"flow-definition.json\", body: flowDefinitionMetaSchema as object },\n { name: \"user-schema.json\", body: userSchemaMetaSchema as object },\n { name: \"user-property.json\", body: userPropertyMetaSchema as object },\n { name: \"auth-methods.json\", body: authMethodsMetaSchema as object },\n { name: \"auth-method.json\", body: authMethodMetaSchema as object },\n ];\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AK4BA,MAAa,kBAAkB;;;;;AAM/B,MAAa,uBAAuB;;;;;;AASpC,SAAgB,kBAAiD;AAC/D,QAAO;EACL;GAAE,MAAM;GAAwB,MAAMA;GAAoC;EAC1E;GAAE,MAAM;GAAoB,MAAMC;GAAgC;EAClE;GAAE,MAAM;GAAsB,MAAMC;GAAkC;EACtE;GAAE,MAAM;GAAqB,MAAMC;GAAiC;EACpE;GAAE,MAAM;GAAoB,MAAMC;GAAgC;EACnE"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
//#region src/meta-schemas.d.ts
|
|
2
|
+
/** Project-relative directory setup writes the meta-schemas to. */
|
|
3
|
+
declare const META_SCHEMA_DIR = ".zitadel/meta";
|
|
4
|
+
/**
|
|
5
|
+
* The `$schema` value scaffolded flow files carry, relative to
|
|
6
|
+
* `.zitadel/flows/` — resolves to `{@link META_SCHEMA_DIR}/flow-definition.json`.
|
|
7
|
+
*/
|
|
8
|
+
declare const FLOW_FILE_SCHEMA_REF = "../meta/flow-definition.json";
|
|
9
|
+
type MetaSchemaFile = {
|
|
10
|
+
name: string;
|
|
11
|
+
body: object;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* The dialect files to materialize, in write order. `auth-methods.json` and
|
|
15
|
+
* `auth-method.json` are pulled in by `user-schema.json`'s relative `$ref`s —
|
|
16
|
+
* without them the copied dialect cannot resolve offline.
|
|
17
|
+
*/
|
|
18
|
+
declare function metaSchemaFiles(): ReadonlyArray<MetaSchemaFile>;
|
|
19
|
+
//#endregion
|
|
20
|
+
export { FLOW_FILE_SCHEMA_REF, META_SCHEMA_DIR, MetaSchemaFile, metaSchemaFiles };
|
|
21
|
+
//# sourceMappingURL=meta-schemas.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"meta-schemas.d.mts","names":[],"sources":["../src/meta-schemas.ts"],"mappings":";;cA4Ba,eAAA;;;;;cAMA,oBAAA;AAAA,KAED,cAAA;EAAmB,IAAA;EAAc,IAAA;AAAA;AAA7C;;;;;AAAA,iBAOgB,eAAA,CAAA,GAAmB,aAAA,CAAc,cAAA"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
//#region src/normalize.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Canonical-form normalizers for the two repo-config resource kinds.
|
|
4
|
+
*
|
|
5
|
+
* The sync engine compares `.zitadel/**` files against server responses;
|
|
6
|
+
* the server echoes fields the author never wrote (an empty `audience`
|
|
7
|
+
* on flows) and the meta-schema declares defaults an author may or may
|
|
8
|
+
* not spell out (`x-editable` et al on schema properties). Normalizing
|
|
9
|
+
* both sides before hashing or diffing keeps a one-field edit rendering
|
|
10
|
+
* as a one-field diff.
|
|
11
|
+
*
|
|
12
|
+
* Normalized bodies are for COMPARISON. Never upload them, and never
|
|
13
|
+
* write a normalized schema body to a file: the server stores schema
|
|
14
|
+
* bytes verbatim without materializing meta-schema defaults, so a
|
|
15
|
+
* stripped `"x-editable": true` would vanish from the next published
|
|
16
|
+
* revision. (Flow write-back may reuse {@link normalizeFlowBody} —
|
|
17
|
+
* everything it strips is pure transport noise.)
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Property-level defaults declared by the user-property meta-schema
|
|
21
|
+
* (`api/openapi/endpoints/schemas/user-property.json`). A property that
|
|
22
|
+
* spells one of these out is semantically identical to one that omits it.
|
|
23
|
+
*/
|
|
24
|
+
declare const USER_PROPERTY_DEFAULTS: Readonly<Record<string, boolean>>;
|
|
25
|
+
/**
|
|
26
|
+
* Return a deep copy of a bare flow-definition body with server-echoed
|
|
27
|
+
* noise removed: an empty `audience` and any detail-envelope keys. A
|
|
28
|
+
* top-level `$schema` is stripped too — it is a local editor affordance
|
|
29
|
+
* (scaffolded flow files point it at `.zitadel/meta/flow-definition.json`),
|
|
30
|
+
* never part of the resource: the server skips it on decode and omits it
|
|
31
|
+
* from responses, so comparing with it would read every scaffolded file
|
|
32
|
+
* as permanently diverged.
|
|
33
|
+
*/
|
|
34
|
+
declare function normalizeFlowBody(body: object): object;
|
|
35
|
+
/**
|
|
36
|
+
* Return a deep copy of a user-schema body with meta-schema property
|
|
37
|
+
* defaults stripped: a property carrying `"x-editable": true` (or the
|
|
38
|
+
* other {@link USER_PROPERTY_DEFAULTS}) normalizes to one omitting it.
|
|
39
|
+
* Only exact default values are removed; `$id` and every other field
|
|
40
|
+
* pass through untouched.
|
|
41
|
+
*/
|
|
42
|
+
declare function normalizeSchemaBody(body: object): object;
|
|
43
|
+
//#endregion
|
|
44
|
+
export { USER_PROPERTY_DEFAULTS, normalizeFlowBody, normalizeSchemaBody };
|
|
45
|
+
//# sourceMappingURL=normalize.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"normalize.d.mts","names":[],"sources":["../src/normalize.ts"],"mappings":";;AAuBA;;;;;AA0CA;;;;;AAmBA;;;;;;;;;;;cA7Da,sBAAA,EAAwB,QAAA,CAAS,MAAA;;;;;;;;;;iBA0C9B,iBAAA,CAAkB,IAAA;;;;;;;;iBAmBlB,mBAAA,CAAoB,IAAA"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
//#region src/normalize.ts
|
|
2
|
+
/**
|
|
3
|
+
* Canonical-form normalizers for the two repo-config resource kinds.
|
|
4
|
+
*
|
|
5
|
+
* The sync engine compares `.zitadel/**` files against server responses;
|
|
6
|
+
* the server echoes fields the author never wrote (an empty `audience`
|
|
7
|
+
* on flows) and the meta-schema declares defaults an author may or may
|
|
8
|
+
* not spell out (`x-editable` et al on schema properties). Normalizing
|
|
9
|
+
* both sides before hashing or diffing keeps a one-field edit rendering
|
|
10
|
+
* as a one-field diff.
|
|
11
|
+
*
|
|
12
|
+
* Normalized bodies are for COMPARISON. Never upload them, and never
|
|
13
|
+
* write a normalized schema body to a file: the server stores schema
|
|
14
|
+
* bytes verbatim without materializing meta-schema defaults, so a
|
|
15
|
+
* stripped `"x-editable": true` would vanish from the next published
|
|
16
|
+
* revision. (Flow write-back may reuse {@link normalizeFlowBody} —
|
|
17
|
+
* everything it strips is pure transport noise.)
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Property-level defaults declared by the user-property meta-schema
|
|
21
|
+
* (`api/openapi/endpoints/schemas/user-property.json`). A property that
|
|
22
|
+
* spells one of these out is semantically identical to one that omits it.
|
|
23
|
+
*/
|
|
24
|
+
const USER_PROPERTY_DEFAULTS = {
|
|
25
|
+
"x-editable": true,
|
|
26
|
+
"x-sensitive": false,
|
|
27
|
+
"x-mfa": false
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Keys of the flow-definition detail envelope. `fetch` in the flow syncer
|
|
31
|
+
* already unwraps the envelope; stripping them here as well makes the
|
|
32
|
+
* normalizer safe on raw detail responses.
|
|
33
|
+
*/
|
|
34
|
+
const FLOW_ENVELOPE_KEYS = [
|
|
35
|
+
"id",
|
|
36
|
+
"project_id",
|
|
37
|
+
"schema_uri",
|
|
38
|
+
"created_at",
|
|
39
|
+
"updated_at"
|
|
40
|
+
];
|
|
41
|
+
function isPlainObject(value) {
|
|
42
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* An `audience` counts as empty when it scopes nothing: no keys, or only
|
|
46
|
+
* `team_ids`/`app_ids` that are null or empty arrays. Unknown keys keep
|
|
47
|
+
* the audience — better a noisy diff than a silently dropped scope.
|
|
48
|
+
*/
|
|
49
|
+
function isEmptyAudience(value) {
|
|
50
|
+
if (!isPlainObject(value)) return false;
|
|
51
|
+
return Object.entries(value).every(([key, entry]) => (key === "team_ids" || key === "app_ids") && (entry === null || entry === void 0 || Array.isArray(entry) && entry.length === 0));
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Return a deep copy of a bare flow-definition body with server-echoed
|
|
55
|
+
* noise removed: an empty `audience` and any detail-envelope keys. A
|
|
56
|
+
* top-level `$schema` is stripped too — it is a local editor affordance
|
|
57
|
+
* (scaffolded flow files point it at `.zitadel/meta/flow-definition.json`),
|
|
58
|
+
* never part of the resource: the server skips it on decode and omits it
|
|
59
|
+
* from responses, so comparing with it would read every scaffolded file
|
|
60
|
+
* as permanently diverged.
|
|
61
|
+
*/
|
|
62
|
+
function normalizeFlowBody(body) {
|
|
63
|
+
const result = structuredClone(body);
|
|
64
|
+
for (const key of FLOW_ENVELOPE_KEYS) delete result[key];
|
|
65
|
+
delete result.$schema;
|
|
66
|
+
if ("audience" in result && isEmptyAudience(result.audience)) delete result.audience;
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Return a deep copy of a user-schema body with meta-schema property
|
|
71
|
+
* defaults stripped: a property carrying `"x-editable": true` (or the
|
|
72
|
+
* other {@link USER_PROPERTY_DEFAULTS}) normalizes to one omitting it.
|
|
73
|
+
* Only exact default values are removed; `$id` and every other field
|
|
74
|
+
* pass through untouched.
|
|
75
|
+
*/
|
|
76
|
+
function normalizeSchemaBody(body) {
|
|
77
|
+
const result = structuredClone(body);
|
|
78
|
+
if (!isPlainObject(result.properties)) return result;
|
|
79
|
+
for (const property of Object.values(result.properties)) {
|
|
80
|
+
if (!isPlainObject(property)) continue;
|
|
81
|
+
for (const [key, defaultValue] of Object.entries(USER_PROPERTY_DEFAULTS)) if (property[key] === defaultValue) delete property[key];
|
|
82
|
+
}
|
|
83
|
+
return result;
|
|
84
|
+
}
|
|
85
|
+
//#endregion
|
|
86
|
+
export { USER_PROPERTY_DEFAULTS, normalizeFlowBody, normalizeSchemaBody };
|
|
87
|
+
|
|
88
|
+
//# sourceMappingURL=normalize.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"normalize.mjs","names":[],"sources":["../src/normalize.ts"],"sourcesContent":["/**\n * Canonical-form normalizers for the two repo-config resource kinds.\n *\n * The sync engine compares `.zitadel/**` files against server responses;\n * the server echoes fields the author never wrote (an empty `audience`\n * on flows) and the meta-schema declares defaults an author may or may\n * not spell out (`x-editable` et al on schema properties). Normalizing\n * both sides before hashing or diffing keeps a one-field edit rendering\n * as a one-field diff.\n *\n * Normalized bodies are for COMPARISON. Never upload them, and never\n * write a normalized schema body to a file: the server stores schema\n * bytes verbatim without materializing meta-schema defaults, so a\n * stripped `\"x-editable\": true` would vanish from the next published\n * revision. (Flow write-back may reuse {@link normalizeFlowBody} —\n * everything it strips is pure transport noise.)\n */\n\n/**\n * Property-level defaults declared by the user-property meta-schema\n * (`api/openapi/endpoints/schemas/user-property.json`). A property that\n * spells one of these out is semantically identical to one that omits it.\n */\nexport const USER_PROPERTY_DEFAULTS: Readonly<Record<string, boolean>> = {\n \"x-editable\": true,\n \"x-sensitive\": false,\n \"x-mfa\": false,\n};\n\n/**\n * Keys of the flow-definition detail envelope. `fetch` in the flow syncer\n * already unwraps the envelope; stripping them here as well makes the\n * normalizer safe on raw detail responses.\n */\nconst FLOW_ENVELOPE_KEYS = [\"id\", \"project_id\", \"schema_uri\", \"created_at\", \"updated_at\"];\n\nfunction isPlainObject(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\n/**\n * An `audience` counts as empty when it scopes nothing: no keys, or only\n * `team_ids`/`app_ids` that are null or empty arrays. Unknown keys keep\n * the audience — better a noisy diff than a silently dropped scope.\n */\nfunction isEmptyAudience(value: unknown): boolean {\n if (!isPlainObject(value)) {\n return false;\n }\n return Object.entries(value).every(\n ([key, entry]) =>\n (key === \"team_ids\" || key === \"app_ids\") &&\n (entry === null || entry === undefined || (Array.isArray(entry) && entry.length === 0)),\n );\n}\n\n/**\n * Return a deep copy of a bare flow-definition body with server-echoed\n * noise removed: an empty `audience` and any detail-envelope keys. A\n * top-level `$schema` is stripped too — it is a local editor affordance\n * (scaffolded flow files point it at `.zitadel/meta/flow-definition.json`),\n * never part of the resource: the server skips it on decode and omits it\n * from responses, so comparing with it would read every scaffolded file\n * as permanently diverged.\n */\nexport function normalizeFlowBody(body: object): object {\n const result = structuredClone(body) as Record<string, unknown>;\n for (const key of FLOW_ENVELOPE_KEYS) {\n delete result[key];\n }\n delete result.$schema;\n if (\"audience\" in result && isEmptyAudience(result.audience)) {\n delete result.audience;\n }\n return result;\n}\n\n/**\n * Return a deep copy of a user-schema body with meta-schema property\n * defaults stripped: a property carrying `\"x-editable\": true` (or the\n * other {@link USER_PROPERTY_DEFAULTS}) normalizes to one omitting it.\n * Only exact default values are removed; `$id` and every other field\n * pass through untouched.\n */\nexport function normalizeSchemaBody(body: object): object {\n const result = structuredClone(body) as Record<string, unknown>;\n if (!isPlainObject(result.properties)) {\n return result;\n }\n for (const property of Object.values(result.properties)) {\n if (!isPlainObject(property)) {\n continue;\n }\n for (const [key, defaultValue] of Object.entries(USER_PROPERTY_DEFAULTS)) {\n if (property[key] === defaultValue) {\n delete property[key];\n }\n }\n }\n return result;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAuBA,MAAa,yBAA4D;CACvE,cAAc;CACd,eAAe;CACf,SAAS;CACV;;;;;;AAOD,MAAM,qBAAqB;CAAC;CAAM;CAAc;CAAc;CAAc;CAAa;AAEzF,SAAS,cAAc,OAAkD;AACvE,QAAO,OAAO,UAAU,YAAY,UAAU,QAAQ,CAAC,MAAM,QAAQ,MAAM;;;;;;;AAQ7E,SAAS,gBAAgB,OAAyB;AAChD,KAAI,CAAC,cAAc,MAAM,CACvB,QAAO;AAET,QAAO,OAAO,QAAQ,MAAM,CAAC,OAC1B,CAAC,KAAK,YACJ,QAAQ,cAAc,QAAQ,eAC9B,UAAU,QAAQ,UAAU,KAAA,KAAc,MAAM,QAAQ,MAAM,IAAI,MAAM,WAAW,GACvF;;;;;;;;;;;AAYH,SAAgB,kBAAkB,MAAsB;CACtD,MAAM,SAAS,gBAAgB,KAAK;AACpC,MAAK,MAAM,OAAO,mBAChB,QAAO,OAAO;AAEhB,QAAO,OAAO;AACd,KAAI,cAAc,UAAU,gBAAgB,OAAO,SAAS,CAC1D,QAAO,OAAO;AAEhB,QAAO;;;;;;;;;AAUT,SAAgB,oBAAoB,MAAsB;CACxD,MAAM,SAAS,gBAAgB,KAAK;AACpC,KAAI,CAAC,cAAc,OAAO,WAAW,CACnC,QAAO;AAET,MAAK,MAAM,YAAY,OAAO,OAAO,OAAO,WAAW,EAAE;AACvD,MAAI,CAAC,cAAc,SAAS,CAC1B;AAEF,OAAK,MAAM,CAAC,KAAK,iBAAiB,OAAO,QAAQ,uBAAuB,CACtE,KAAI,SAAS,SAAS,aACpB,QAAO,SAAS;;AAItB,QAAO"}
|