@miosa/cli 1.1.18 → 1.1.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +0 -21
  2. package/dist/client.d.ts +1 -15
  3. package/dist/client.d.ts.map +1 -1
  4. package/dist/client.js +44 -118
  5. package/dist/client.js.map +1 -1
  6. package/dist/commands/databases.d.ts.map +1 -1
  7. package/dist/commands/databases.js +33 -10
  8. package/dist/commands/databases.js.map +1 -1
  9. package/dist/commands/devices.js +2 -5
  10. package/dist/commands/devices.js.map +1 -1
  11. package/dist/commands/doctor.d.ts.map +1 -1
  12. package/dist/commands/doctor.js +127 -58
  13. package/dist/commands/doctor.js.map +1 -1
  14. package/dist/commands/sandbox.d.ts.map +1 -1
  15. package/dist/commands/sandbox.js +91 -23
  16. package/dist/commands/sandbox.js.map +1 -1
  17. package/dist/commands/templates.d.ts.map +1 -1
  18. package/dist/commands/templates.js +252 -521
  19. package/dist/commands/templates.js.map +1 -1
  20. package/dist/commands/util.d.ts +0 -1
  21. package/dist/commands/util.d.ts.map +1 -1
  22. package/dist/commands/util.js +2 -15
  23. package/dist/commands/util.js.map +1 -1
  24. package/dist/commands/watch.d.ts.map +1 -1
  25. package/dist/commands/watch.js +1 -5
  26. package/dist/commands/watch.js.map +1 -1
  27. package/dist/config.d.ts +1 -1
  28. package/dist/config.d.ts.map +1 -1
  29. package/dist/config.js +4 -0
  30. package/dist/config.js.map +1 -1
  31. package/dist/errors.d.ts +2 -18
  32. package/dist/errors.d.ts.map +1 -1
  33. package/dist/errors.js +4 -37
  34. package/dist/errors.js.map +1 -1
  35. package/dist/net-diagnosis.d.ts +87 -0
  36. package/dist/net-diagnosis.d.ts.map +1 -0
  37. package/dist/net-diagnosis.js +408 -0
  38. package/dist/net-diagnosis.js.map +1 -0
  39. package/dist/types.d.ts +6 -8
  40. package/dist/types.d.ts.map +1 -1
  41. package/dist/types.js.map +1 -1
  42. package/package.json +1 -1
  43. package/dist/api-validation.d.ts +0 -53
  44. package/dist/api-validation.d.ts.map +0 -1
  45. package/dist/api-validation.js +0 -200
  46. package/dist/api-validation.js.map +0 -1
  47. package/dist/endpoint.d.ts +0 -37
  48. package/dist/endpoint.d.ts.map +0 -1
  49. package/dist/endpoint.js +0 -123
  50. package/dist/endpoint.js.map +0 -1
@@ -1,53 +0,0 @@
1
- /**
2
- * Field-level validation errors from the platform API.
3
- *
4
- * The API reports rejected fields in a top-level `errors` key, in one of two
5
- * shapes depending on which validator refused:
6
- *
7
- * Ecto changeset (`Ecto.Changeset.traverse_errors/2`) — a map of field to a
8
- * list of messages, possibly nested for embedded schemas:
9
- *
10
- * {"error":{"code":"VALIDATION_FAILED","message":"sandbox template is invalid"},
11
- * "errors":{"slug":["a template with this name already exists"]}}
12
- *
13
- * Hand-rolled spec validators (BuildSpec) — a list of objects:
14
- *
15
- * {"error":{"code":"INVALID_BUILDSPEC","message":"BuildSpec is invalid"},
16
- * "errors":[{"code":"REQUIRED","field":"from","message":"is required"}]}
17
- *
18
- * Neither shape was read before: the CLI only looked at `error.details`, so it
19
- * fell back to dumping the whole raw response body and the customer saw a JSON
20
- * blob naming an internal column (2026-08-26 live customer call).
21
- */
22
- export interface FieldIssue {
23
- /** Server-reported field path, e.g. "slug" or "steps.0.run". */
24
- readonly field: string;
25
- readonly message: string;
26
- readonly code?: string;
27
- }
28
- export declare function isUniquenessMessage(message: string): boolean;
29
- export declare function isServerAssignedField(field: string): boolean;
30
- export declare function fieldLabel(field: string): string;
31
- /**
32
- * Collect field-level issues from an error response body. Returns an empty
33
- * array when the body carries no per-field detail, so callers can fall back to
34
- * the top-level message.
35
- */
36
- export declare function parseFieldIssues(body: unknown): FieldIssue[];
37
- export interface RenderedIssues {
38
- /** One "field: message" line per issue, already labelled for the caller. */
39
- readonly lines: string[];
40
- /** Actionable next step, when the issues imply one. */
41
- readonly hint?: string;
42
- }
43
- /**
44
- * Turn field issues into the lines the CLI prints.
45
- *
46
- * `sentFields` are the top-level keys the CLI actually put in the request body.
47
- * They are what makes the misattribution guard possible: when the server blames
48
- * a field the request never set (the `[:tenant_id, :slug]` unique_constraint
49
- * case, where Ecto attaches a composite-index error to the FIRST field), the
50
- * CLI must not repeat that blame back to the user as if it were their input.
51
- */
52
- export declare function renderFieldIssues(issues: readonly FieldIssue[], sentFields?: readonly string[]): RenderedIssues;
53
- //# sourceMappingURL=api-validation.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"api-validation.d.ts","sourceRoot":"","sources":["../src/api-validation.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,MAAM,WAAW,UAAU;IACzB,gEAAgE;IAChE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAuCD,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAE5D;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAE5D;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMhD;AAOD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,UAAU,EAAE,CAY5D;AA0DD,MAAM,WAAW,cAAc;IAC7B,4EAA4E;IAC5E,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC;IACzB,uDAAuD;IACvD,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,SAAS,UAAU,EAAE,EAC7B,UAAU,GAAE,SAAS,MAAM,EAAO,GACjC,cAAc,CAgDhB"}
@@ -1,200 +0,0 @@
1
- /**
2
- * Field-level validation errors from the platform API.
3
- *
4
- * The API reports rejected fields in a top-level `errors` key, in one of two
5
- * shapes depending on which validator refused:
6
- *
7
- * Ecto changeset (`Ecto.Changeset.traverse_errors/2`) — a map of field to a
8
- * list of messages, possibly nested for embedded schemas:
9
- *
10
- * {"error":{"code":"VALIDATION_FAILED","message":"sandbox template is invalid"},
11
- * "errors":{"slug":["a template with this name already exists"]}}
12
- *
13
- * Hand-rolled spec validators (BuildSpec) — a list of objects:
14
- *
15
- * {"error":{"code":"INVALID_BUILDSPEC","message":"BuildSpec is invalid"},
16
- * "errors":[{"code":"REQUIRED","field":"from","message":"is required"}]}
17
- *
18
- * Neither shape was read before: the CLI only looked at `error.details`, so it
19
- * fell back to dumping the whole raw response body and the customer saw a JSON
20
- * blob naming an internal column (2026-08-26 live customer call).
21
- */
22
- /**
23
- * Fields the client never sets: the server assigns them from the credential or
24
- * from its own request context. A validation error attributed to one of these
25
- * is a server-side attribution artifact, not something the caller can correct
26
- * by changing its request.
27
- */
28
- const SERVER_ASSIGNED_FIELDS = new Set([
29
- "tenant_id",
30
- "organization_id",
31
- "owner_id",
32
- "user_id",
33
- "workspace_id",
34
- "account_id",
35
- "api_key_id",
36
- ]);
37
- /**
38
- * Internal column names mapped to the flag or field a caller actually controls.
39
- * Keeps the CLI from telling someone to fix a field their command has no way
40
- * to set.
41
- */
42
- const FIELD_LABELS = {
43
- slug: "name",
44
- build_spec: "dockerfile",
45
- normalized_build_spec: "dockerfile",
46
- dockerfile: "dockerfile",
47
- from: "dockerfile (FROM)",
48
- steps: "dockerfile (RUN/WORKDIR/ENV steps)",
49
- startCmd: "dockerfile (CMD/ENTRYPOINT)",
50
- previewPort: "dockerfile (EXPOSE)",
51
- artifactPaths: "dockerfile (artifact paths)",
52
- };
53
- /** Messages Ecto/Postgres produce for a unique-index violation. */
54
- const UNIQUENESS_MESSAGE = /has already been taken|already exists|must be unique/i;
55
- export function isUniquenessMessage(message) {
56
- return UNIQUENESS_MESSAGE.test(message);
57
- }
58
- export function isServerAssignedField(field) {
59
- return SERVER_ASSIGNED_FIELDS.has(rootField(field));
60
- }
61
- export function fieldLabel(field) {
62
- const root = rootField(field);
63
- const mapped = FIELD_LABELS[root];
64
- if (!mapped)
65
- return field;
66
- const rest = field.slice(root.length);
67
- return `${mapped}${rest}`;
68
- }
69
- function rootField(field) {
70
- const dot = field.indexOf(".");
71
- return dot === -1 ? field : field.slice(0, dot);
72
- }
73
- /**
74
- * Collect field-level issues from an error response body. Returns an empty
75
- * array when the body carries no per-field detail, so callers can fall back to
76
- * the top-level message.
77
- */
78
- export function parseFieldIssues(body) {
79
- if (!isRecord(body))
80
- return [];
81
- const candidates = [body["errors"]];
82
- if (isRecord(body["error"]))
83
- candidates.push(body["error"]["details"]);
84
- candidates.push(body["details"]);
85
- for (const candidate of candidates) {
86
- const issues = collect(candidate, "");
87
- if (issues.length > 0)
88
- return issues;
89
- }
90
- return [];
91
- }
92
- function collect(value, path) {
93
- if (value === null || value === undefined)
94
- return [];
95
- if (typeof value === "string") {
96
- return path === "" ? [] : [{ field: path, message: value }];
97
- }
98
- if (Array.isArray(value)) {
99
- // A list of message strings under a field path, or a list of
100
- // {field, message} objects at the top level.
101
- return value.flatMap((entry, index) => {
102
- if (typeof entry === "string") {
103
- return path === "" ? [] : [{ field: path, message: entry }];
104
- }
105
- if (isRecord(entry) && typeof entry["message"] === "string") {
106
- const field = asString(entry["field"]) ?? asString(entry["path"]) ?? path;
107
- if (!field)
108
- return [];
109
- return [
110
- {
111
- field,
112
- message: entry["message"],
113
- ...(asString(entry["code"])
114
- ? { code: asString(entry["code"]) }
115
- : {}),
116
- },
117
- ];
118
- }
119
- return collect(entry, path === "" ? String(index) : `${path}.${index}`);
120
- });
121
- }
122
- if (isRecord(value)) {
123
- // A single {field, message} object.
124
- if (typeof value["message"] === "string" && !("errors" in value)) {
125
- const field = asString(value["field"]) ?? asString(value["path"]) ?? path;
126
- if (field) {
127
- return [
128
- {
129
- field,
130
- message: value["message"],
131
- ...(asString(value["code"])
132
- ? { code: asString(value["code"]) }
133
- : {}),
134
- },
135
- ];
136
- }
137
- }
138
- return Object.entries(value).flatMap(([key, nested]) => collect(nested, path === "" ? key : `${path}.${key}`));
139
- }
140
- return [];
141
- }
142
- /**
143
- * Turn field issues into the lines the CLI prints.
144
- *
145
- * `sentFields` are the top-level keys the CLI actually put in the request body.
146
- * They are what makes the misattribution guard possible: when the server blames
147
- * a field the request never set (the `[:tenant_id, :slug]` unique_constraint
148
- * case, where Ecto attaches a composite-index error to the FIRST field), the
149
- * CLI must not repeat that blame back to the user as if it were their input.
150
- */
151
- export function renderFieldIssues(issues, sentFields = []) {
152
- if (issues.length === 0)
153
- return { lines: [] };
154
- const sent = new Set(sentFields);
155
- const lines = [];
156
- const hints = [];
157
- for (const issue of issues) {
158
- const root = rootField(issue.field);
159
- const misattributed = isServerAssignedField(issue.field) &&
160
- !sent.has(root) &&
161
- isUniquenessMessage(issue.message);
162
- if (misattributed) {
163
- // The request never carried this field, so the caller cannot act on it.
164
- // Report the collision as a collision and name the misattribution
165
- // instead of parroting an internal column back at the user.
166
- const collided = nameLikeField(sentFields);
167
- lines.push(collided
168
- ? `${collided}: already used by one of your existing resources`
169
- : "already exists: this resource is already registered");
170
- lines.push(`(the server reported this against "${issue.field}", ` +
171
- `which this command did not send - treat it as a duplicate, not a tenancy problem)`);
172
- hints.push(collided
173
- ? `Pick a different --${collided}, or remove the existing one first.`
174
- : "Pick a different name, or remove the existing resource first.");
175
- continue;
176
- }
177
- lines.push(`${fieldLabel(issue.field)}: ${issue.message}`);
178
- if (isUniquenessMessage(issue.message)) {
179
- const label = fieldLabel(issue.field);
180
- hints.push(`Pick a different --${label}, or remove the existing one first.`);
181
- }
182
- }
183
- const hint = hints[0];
184
- return hint === undefined ? { lines } : { lines, hint };
185
- }
186
- /** The most name-like field the request actually sent, for a duplicate hint. */
187
- function nameLikeField(sentFields) {
188
- for (const candidate of ["name", "slug", "title", "id"]) {
189
- if (sentFields.includes(candidate))
190
- return candidate === "slug" ? "name" : candidate;
191
- }
192
- return undefined;
193
- }
194
- function asString(value) {
195
- return typeof value === "string" && value !== "" ? value : undefined;
196
- }
197
- function isRecord(value) {
198
- return value !== null && typeof value === "object" && !Array.isArray(value);
199
- }
200
- //# sourceMappingURL=api-validation.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"api-validation.js","sourceRoot":"","sources":["../src/api-validation.ts"],"names":[],"mappings":"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"}
@@ -1,37 +0,0 @@
1
- /**
2
- * Endpoint resolution and transport-failure diagnosis.
3
- *
4
- * A CLI that cannot resolve its API host must say which host it tried, where
5
- * that host came from, and how to change it. The bare
6
- * `Network error: getaddrinfo ENOTFOUND <host>` it printed before named the
7
- * host but nothing else, leaving no way to tell a typo in `MIOSA_ENDPOINT`
8
- * apart from a typo in `~/.miosa/config.json` apart from real DNS trouble
9
- * (2026-08-26 live customer call).
10
- */
11
- import { NetworkError } from "./errors.js";
12
- export declare const DEFAULT_ENDPOINT = "https://api.miosa.ai";
13
- export type EndpointSource = "MIOSA_ENDPOINT" | "config-file" | "built-in-default";
14
- export interface EndpointOrigin {
15
- readonly source: EndpointSource;
16
- /** Human description of where the value lives, and how to change it. */
17
- readonly where: string;
18
- readonly fix: string;
19
- }
20
- /**
21
- * Work out where the endpoint currently in use came from. Mirrors the
22
- * precedence in `loadConfig`: MIOSA_ENDPOINT, then the config file, then the
23
- * built-in default.
24
- */
25
- export declare function endpointOrigin(endpoint: string): EndpointOrigin;
26
- /**
27
- * Reject an endpoint that is not a usable absolute http(s) URL before any
28
- * request is attempted. Undici's own failure for this is the opaque
29
- * `TypeError: Invalid URL`, which does not even echo the offending value.
30
- */
31
- export declare function assertUsableEndpoint(endpoint: string): void;
32
- /**
33
- * Build a NetworkError that names the host, the config value behind it, and
34
- * the command that changes it.
35
- */
36
- export declare function transportError(err: unknown, endpoint: string): NetworkError;
37
- //# sourceMappingURL=endpoint.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"endpoint.d.ts","sourceRoot":"","sources":["../src/endpoint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,EAAE,YAAY,EAAa,MAAM,aAAa,CAAC;AAEtD,eAAO,MAAM,gBAAgB,yBAAyB,CAAC;AAEvD,MAAM,MAAM,cAAc,GACxB,gBAAgB,GAAG,aAAa,GAAG,kBAAkB,CAAC;AAExD,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,wEAAwE;IACxE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,GAAG,cAAc,CAyB/D;AAaD;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAkB3D;AAyBD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,GAAG,YAAY,CAuC3E"}
package/dist/endpoint.js DELETED
@@ -1,123 +0,0 @@
1
- /**
2
- * Endpoint resolution and transport-failure diagnosis.
3
- *
4
- * A CLI that cannot resolve its API host must say which host it tried, where
5
- * that host came from, and how to change it. The bare
6
- * `Network error: getaddrinfo ENOTFOUND <host>` it printed before named the
7
- * host but nothing else, leaving no way to tell a typo in `MIOSA_ENDPOINT`
8
- * apart from a typo in `~/.miosa/config.json` apart from real DNS trouble
9
- * (2026-08-26 live customer call).
10
- */
11
- import { getConfigPath } from "./config.js";
12
- import { NetworkError, UserError } from "./errors.js";
13
- export const DEFAULT_ENDPOINT = "https://api.miosa.ai";
14
- /**
15
- * Work out where the endpoint currently in use came from. Mirrors the
16
- * precedence in `loadConfig`: MIOSA_ENDPOINT, then the config file, then the
17
- * built-in default.
18
- */
19
- export function endpointOrigin(endpoint) {
20
- const fromEnv = process.env["MIOSA_ENDPOINT"];
21
- const normalized = endpoint.replace(/\/$/, "");
22
- if (fromEnv && fromEnv.replace(/\/$/, "") === normalized) {
23
- return {
24
- source: "MIOSA_ENDPOINT",
25
- where: "the MIOSA_ENDPOINT environment variable",
26
- fix: `unset MIOSA_ENDPOINT (or: export MIOSA_ENDPOINT=${DEFAULT_ENDPOINT})`,
27
- };
28
- }
29
- if (normalized === DEFAULT_ENDPOINT) {
30
- return {
31
- source: "built-in-default",
32
- where: `the built-in default (${DEFAULT_ENDPOINT})`,
33
- fix: `miosa config set api_url ${DEFAULT_ENDPOINT}`,
34
- };
35
- }
36
- return {
37
- source: "config-file",
38
- where: `"endpoint" in ${configFileForDisplay()}`,
39
- fix: `miosa config set api_url ${DEFAULT_ENDPOINT}`,
40
- };
41
- }
42
- /**
43
- * Config file path for the message. Tolerates a stubbed config module (unit
44
- * tests replace it wholesale) by degrading to the documented location rather
45
- * than crashing the error path that is meant to explain a failure.
46
- */
47
- function configFileForDisplay() {
48
- return typeof getConfigPath === "function"
49
- ? getConfigPath()
50
- : "~/.miosa/config.json";
51
- }
52
- /**
53
- * Reject an endpoint that is not a usable absolute http(s) URL before any
54
- * request is attempted. Undici's own failure for this is the opaque
55
- * `TypeError: Invalid URL`, which does not even echo the offending value.
56
- */
57
- export function assertUsableEndpoint(endpoint) {
58
- const origin = endpointOrigin(endpoint);
59
- let parsed;
60
- try {
61
- parsed = new URL(endpoint);
62
- }
63
- catch {
64
- throw new UserError(`The MIOSA API endpoint is not a valid URL: ${JSON.stringify(endpoint)}`, `It is set in ${origin.where}. An endpoint must include the scheme, ` +
65
- `for example ${DEFAULT_ENDPOINT}. Fix it with: ${origin.fix}`);
66
- }
67
- if (parsed.protocol !== "https:" && parsed.protocol !== "http:") {
68
- throw new UserError(`The MIOSA API endpoint must be http or https, got ${JSON.stringify(endpoint)}`, `It is set in ${origin.where}. Fix it with: ${origin.fix}`);
69
- }
70
- }
71
- /** Walk `err.cause` for the first entry carrying an errno-style `code`. */
72
- function transportCause(err) {
73
- let current = err;
74
- for (let depth = 0; depth < 6 && current !== null && typeof current === "object"; depth += 1) {
75
- const candidate = current;
76
- if (typeof candidate.code === "string")
77
- return candidate;
78
- current = candidate.cause;
79
- }
80
- return undefined;
81
- }
82
- /**
83
- * Build a NetworkError that names the host, the config value behind it, and
84
- * the command that changes it.
85
- */
86
- export function transportError(err, endpoint) {
87
- const origin = endpointOrigin(endpoint);
88
- const raw = err instanceof Error ? err.message : String(err);
89
- const cause = transportCause(err);
90
- const code = typeof cause?.code === "string" ? cause.code : undefined;
91
- let host;
92
- try {
93
- host = new URL(endpoint).host;
94
- }
95
- catch {
96
- host = endpoint;
97
- }
98
- const detail = (() => {
99
- switch (code) {
100
- case "ENOTFOUND":
101
- case "EAI_AGAIN":
102
- return `DNS lookup failed for host "${host}" (${code}). That hostname does not resolve from this machine.`;
103
- case "ECONNREFUSED":
104
- return `The host "${host}" refused the connection (ECONNREFUSED). It resolved, but nothing is listening on that port.`;
105
- case "ETIMEDOUT":
106
- case "UND_ERR_CONNECT_TIMEOUT":
107
- return `Connecting to "${host}" timed out (${code}).`;
108
- case "CERT_HAS_EXPIRED":
109
- case "DEPTH_ZERO_SELF_SIGNED_CERT":
110
- case "UNABLE_TO_VERIFY_LEAF_SIGNATURE":
111
- return `TLS verification failed for "${host}" (${code}).`;
112
- default:
113
- return `Could not reach "${host}": ${raw}`;
114
- }
115
- })();
116
- const hint = code === "ENOTFOUND" || code === "EAI_AGAIN"
117
- ? `The endpoint ${endpoint} comes from ${origin.where}. ` +
118
- `Check it for a typo, then: ${origin.fix}`
119
- : `The endpoint ${endpoint} comes from ${origin.where}. ` +
120
- `Verify it with "miosa config get api_url", or change it: ${origin.fix}`;
121
- return new NetworkError(`Cannot reach the MIOSA API. ${detail}`, hint);
122
- }
123
- //# sourceMappingURL=endpoint.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"endpoint.js","sourceRoot":"","sources":["../src/endpoint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAEtD,MAAM,CAAC,MAAM,gBAAgB,GAAG,sBAAsB,CAAC;AAYvD;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,QAAgB;IAC7C,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAC;IAC9C,MAAM,UAAU,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAE/C,IAAI,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,UAAU,EAAE,CAAC;QACzD,OAAO;YACL,MAAM,EAAE,gBAAgB;YACxB,KAAK,EAAE,yCAAyC;YAChD,GAAG,EAAE,qDAAqD,gBAAgB,GAAG;SAC9E,CAAC;IACJ,CAAC;IAED,IAAI,UAAU,KAAK,gBAAgB,EAAE,CAAC;QACpC,OAAO;YACL,MAAM,EAAE,kBAAkB;YAC1B,KAAK,EAAE,yBAAyB,gBAAgB,GAAG;YACnD,GAAG,EAAE,4BAA4B,gBAAgB,EAAE;SACpD,CAAC;IACJ,CAAC;IAED,OAAO;QACL,MAAM,EAAE,aAAa;QACrB,KAAK,EAAE,iBAAiB,oBAAoB,EAAE,EAAE;QAChD,GAAG,EAAE,4BAA4B,gBAAgB,EAAE;KACpD,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,SAAS,oBAAoB;IAC3B,OAAO,OAAO,aAAa,KAAK,UAAU;QACxC,CAAC,CAAC,aAAa,EAAE;QACjB,CAAC,CAAC,sBAAsB,CAAC;AAC7B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,QAAgB;IACnD,MAAM,MAAM,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;IACxC,IAAI,MAAW,CAAC;IAChB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,SAAS,CACjB,8CAA8C,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,EACxE,gBAAgB,MAAM,CAAC,KAAK,yCAAyC;YACnE,eAAe,gBAAgB,kBAAkB,MAAM,CAAC,GAAG,EAAE,CAChE,CAAC;IACJ,CAAC;IACD,IAAI,MAAM,CAAC,QAAQ,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,KAAK,OAAO,EAAE,CAAC;QAChE,MAAM,IAAI,SAAS,CACjB,qDAAqD,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,EAC/E,gBAAgB,MAAM,CAAC,KAAK,kBAAkB,MAAM,CAAC,GAAG,EAAE,CAC3D,CAAC;IACJ,CAAC;AACH,CAAC;AAUD,2EAA2E;AAC3E,SAAS,cAAc,CAAC,GAAY;IAClC,IAAI,OAAO,GAAY,GAAG,CAAC;IAC3B,KACE,IAAI,KAAK,GAAG,CAAC,EACb,KAAK,GAAG,CAAC,IAAI,OAAO,KAAK,IAAI,IAAI,OAAO,OAAO,KAAK,QAAQ,EAC5D,KAAK,IAAI,CAAC,EACV,CAAC;QACD,MAAM,SAAS,GAAG,OAAoB,CAAC;QACvC,IAAI,OAAO,SAAS,CAAC,IAAI,KAAK,QAAQ;YAAE,OAAO,SAAS,CAAC;QACzD,OAAO,GAAG,SAAS,CAAC,KAAK,CAAC;IAC5B,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,GAAY,EAAE,QAAgB;IAC3D,MAAM,MAAM,GAAG,cAAc,CAAC,QAAQ,CAAC,CAAC;IACxC,MAAM,GAAG,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAC7D,MAAM,KAAK,GAAG,cAAc,CAAC,GAAG,CAAC,CAAC;IAClC,MAAM,IAAI,GAAG,OAAO,KAAK,EAAE,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;IACtE,IAAI,IAAY,CAAC;IACjB,IAAI,CAAC;QACH,IAAI,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,IAAI,GAAG,QAAQ,CAAC;IAClB,CAAC;IAED,MAAM,MAAM,GAAG,CAAC,GAAW,EAAE;QAC3B,QAAQ,IAAI,EAAE,CAAC;YACb,KAAK,WAAW,CAAC;YACjB,KAAK,WAAW;gBACd,OAAO,+BAA+B,IAAI,MAAM,IAAI,sDAAsD,CAAC;YAC7G,KAAK,cAAc;gBACjB,OAAO,aAAa,IAAI,8FAA8F,CAAC;YACzH,KAAK,WAAW,CAAC;YACjB,KAAK,yBAAyB;gBAC5B,OAAO,kBAAkB,IAAI,gBAAgB,IAAI,IAAI,CAAC;YACxD,KAAK,kBAAkB,CAAC;YACxB,KAAK,6BAA6B,CAAC;YACnC,KAAK,iCAAiC;gBACpC,OAAO,gCAAgC,IAAI,MAAM,IAAI,IAAI,CAAC;YAC5D;gBACE,OAAO,oBAAoB,IAAI,MAAM,GAAG,EAAE,CAAC;QAC/C,CAAC;IACH,CAAC,CAAC,EAAE,CAAC;IAEL,MAAM,IAAI,GACR,IAAI,KAAK,WAAW,IAAI,IAAI,KAAK,WAAW;QAC1C,CAAC,CAAC,gBAAgB,QAAQ,eAAe,MAAM,CAAC,KAAK,IAAI;YACvD,8BAA8B,MAAM,CAAC,GAAG,EAAE;QAC5C,CAAC,CAAC,gBAAgB,QAAQ,eAAe,MAAM,CAAC,KAAK,IAAI;YACvD,4DAA4D,MAAM,CAAC,GAAG,EAAE,CAAC;IAE/E,OAAO,IAAI,YAAY,CAAC,+BAA+B,MAAM,EAAE,EAAE,IAAI,CAAC,CAAC;AACzE,CAAC"}