@whatcha/cli 0.0.0-stage → 0.3.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.
Files changed (59) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +345 -2
  3. package/dist/auth/gotrue-client.js +64 -0
  4. package/dist/auth/gotrue-client.js.map +1 -0
  5. package/dist/auth/session.js +147 -0
  6. package/dist/auth/session.js.map +1 -0
  7. package/dist/auth/token-store.js +165 -0
  8. package/dist/auth/token-store.js.map +1 -0
  9. package/dist/cli.js +134 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/commands/diaries.js +52 -0
  12. package/dist/commands/diaries.js.map +1 -0
  13. package/dist/commands/login.js +292 -0
  14. package/dist/commands/login.js.map +1 -0
  15. package/dist/commands/profiles.js +287 -0
  16. package/dist/commands/profiles.js.map +1 -0
  17. package/dist/commands/publish.js +81 -0
  18. package/dist/commands/publish.js.map +1 -0
  19. package/dist/commands/read.js +77 -0
  20. package/dist/commands/read.js.map +1 -0
  21. package/dist/commands/shared-diary.js +255 -0
  22. package/dist/commands/shared-diary.js.map +1 -0
  23. package/dist/commands/whoami.js +50 -0
  24. package/dist/commands/whoami.js.map +1 -0
  25. package/dist/commands/wiki.js +386 -0
  26. package/dist/commands/wiki.js.map +1 -0
  27. package/dist/commands/write.js +106 -0
  28. package/dist/commands/write.js.map +1 -0
  29. package/dist/config.js +47 -0
  30. package/dist/config.js.map +1 -0
  31. package/dist/errors.js +46 -0
  32. package/dist/errors.js.map +1 -0
  33. package/dist/http-client.js +102 -0
  34. package/dist/http-client.js.map +1 -0
  35. package/dist/index.js +16 -0
  36. package/dist/index.js.map +1 -0
  37. package/dist/lib/append-entry.js +193 -0
  38. package/dist/lib/append-entry.js.map +1 -0
  39. package/dist/lib/diary-resolve.js +50 -0
  40. package/dist/lib/diary-resolve.js.map +1 -0
  41. package/dist/lib/entry-date.js +96 -0
  42. package/dist/lib/entry-date.js.map +1 -0
  43. package/dist/lib/entry-find.js +39 -0
  44. package/dist/lib/entry-find.js.map +1 -0
  45. package/dist/lib/image-upload.js +126 -0
  46. package/dist/lib/image-upload.js.map +1 -0
  47. package/dist/lib/jwt.js +25 -0
  48. package/dist/lib/jwt.js.map +1 -0
  49. package/dist/lib/output.js +29 -0
  50. package/dist/lib/output.js.map +1 -0
  51. package/dist/lib/personal-access-token.js +46 -0
  52. package/dist/lib/personal-access-token.js.map +1 -0
  53. package/dist/lib/profile-family.js +29 -0
  54. package/dist/lib/profile-family.js.map +1 -0
  55. package/dist/lib/publication.js +55 -0
  56. package/dist/lib/publication.js.map +1 -0
  57. package/dist/types.js +6 -0
  58. package/dist/types.js.map +1 -0
  59. package/package.json +46 -4
@@ -0,0 +1,292 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.parseLoginArgs = parseLoginArgs;
7
+ exports.runLogin = runLogin;
8
+ const node_util_1 = require("node:util");
9
+ const node_readline_1 = __importDefault(require("node:readline"));
10
+ const session_1 = require("../auth/session");
11
+ const config_1 = require("../config");
12
+ const errors_1 = require("../errors");
13
+ const token_store_1 = require("../auth/token-store");
14
+ const gotrue_client_1 = require("../auth/gotrue-client");
15
+ const jwt_1 = require("../lib/jwt");
16
+ const personal_access_token_1 = require("../lib/personal-access-token");
17
+ const output_1 = require("../lib/output");
18
+ function parseLoginArgs(argv) {
19
+ let values;
20
+ try {
21
+ ({ values } = (0, node_util_1.parseArgs)({
22
+ args: argv,
23
+ options: {
24
+ json: { type: "boolean", default: false },
25
+ email: { type: "string" },
26
+ password: { type: "string" },
27
+ token: { type: "string" },
28
+ key: { type: "string" },
29
+ "api-url": { type: "string" },
30
+ },
31
+ allowPositionals: false,
32
+ }));
33
+ }
34
+ catch (err) {
35
+ throw new errors_1.CliUsageError(err.message);
36
+ }
37
+ return {
38
+ json: values.json,
39
+ email: values.email,
40
+ password: values.password,
41
+ token: values.token,
42
+ key: values.key,
43
+ apiUrl: values["api-url"] ?? (0, config_1.apiBaseUrl)(),
44
+ };
45
+ }
46
+ /** Masked stdin prompt -- readline has no built-in for this, so each keystroke is intercepted and only a literal newline is let through to the terminal. */
47
+ function promptHidden(question) {
48
+ return new Promise((resolve) => {
49
+ const rl = node_readline_1.default.createInterface({ input: process.stdin, output: process.stdout });
50
+ const rlWithOutput = rl;
51
+ const originalWrite = rlWithOutput._writeToOutput?.bind(rl);
52
+ let hidden = false;
53
+ rlWithOutput._writeToOutput = (str) => {
54
+ if (!hidden)
55
+ originalWrite?.(str);
56
+ };
57
+ rl.question(question, (answer) => {
58
+ rl.close();
59
+ process.stdout.write("\n");
60
+ resolve(answer);
61
+ });
62
+ hidden = true;
63
+ });
64
+ }
65
+ function prompt(question) {
66
+ return new Promise((resolve) => {
67
+ const rl = node_readline_1.default.createInterface({ input: process.stdin, output: process.stdout });
68
+ rl.question(question, (answer) => {
69
+ rl.close();
70
+ resolve(answer);
71
+ });
72
+ });
73
+ }
74
+ /**
75
+ * Non-interactive credentials, for the exact audience this CLI is for: an
76
+ * AI agent (or a script) invoking `whatcha` as a subprocess has no TTY to
77
+ * answer an interactive prompt at. `--email`/`--password` and
78
+ * `WHATCHA_EMAIL`/`WHATCHA_PASSWORD` are the same idea twice -- flags for a
79
+ * one-off, env vars for something that runs `whatcha login` from a config
80
+ * it does not want to put a password directly into.
81
+ */
82
+ async function resolveCredentials(opts) {
83
+ const email = opts.email ?? process.env.WHATCHA_EMAIL ?? (await prompt("Email: "));
84
+ const password = opts.password ?? process.env.WHATCHA_PASSWORD ?? (await promptHidden("Password: "));
85
+ if (!email || !password)
86
+ throw new errors_1.CliUsageError("Both an email and a password are required.");
87
+ return { email, password };
88
+ }
89
+ async function runLogin(opts, deps = {}) {
90
+ const key = resolveKey(opts);
91
+ if (key)
92
+ return finishLogin(await loginWithKey(opts, deps, key), opts, deps);
93
+ const token = opts.token ?? process.env.WHATCHA_TOKEN;
94
+ if (token)
95
+ return finishLogin(await loginWithToken(opts, deps, token), opts, deps);
96
+ const { email, password } = deps.credentials ?? (await resolveCredentials(opts));
97
+ const supabase = (0, config_1.supabaseCredentials)();
98
+ try {
99
+ const session = supabase
100
+ ? await loginWithPasswordViaGoTrue(supabase, email, password)
101
+ : await loginWithPasswordViaApi(opts, deps, email, password);
102
+ return finishLogin(session, opts, deps);
103
+ }
104
+ catch (err) {
105
+ return reportRefusal(err, opts);
106
+ }
107
+ }
108
+ /**
109
+ * Which personal access key to log in with, if any (#1663).
110
+ *
111
+ * `--key` is the explicit form. `--token` and WHATCHA_TOKEN predate keys and
112
+ * mean a refresh token, but a key is unmistakable by its prefix -- the same
113
+ * prefix the server itself goes by -- so a key handed to either is used as a
114
+ * key rather than sent to /auth/refresh to fail there. WHATCHA_KEY is the
115
+ * environment form of `--key`. Flags win over the environment: a person who
116
+ * typed `--email`, `--password` or `--token` meant that, whatever a
117
+ * WHATCHA_KEY left in the shell says.
118
+ */
119
+ function resolveKey(opts) {
120
+ if (opts.key !== undefined && opts.token !== undefined) {
121
+ throw new errors_1.CliUsageError("Give --key or --token, not both.");
122
+ }
123
+ if (opts.key !== undefined)
124
+ return checkedKey(opts.key, "--key");
125
+ if (opts.token !== undefined)
126
+ return (0, personal_access_token_1.looksLikePersonalAccessToken)(opts.token) ? checkedKey(opts.token, "--token") : undefined;
127
+ if (opts.email !== undefined || opts.password !== undefined)
128
+ return undefined;
129
+ const envKey = process.env.WHATCHA_KEY?.trim();
130
+ if (envKey)
131
+ return checkedKey(envKey, "WHATCHA_KEY");
132
+ const envToken = process.env.WHATCHA_TOKEN?.trim();
133
+ if (envToken && (0, personal_access_token_1.looksLikePersonalAccessToken)(envToken))
134
+ return checkedKey(envToken, "WHATCHA_TOKEN");
135
+ return undefined;
136
+ }
137
+ function checkedKey(raw, from) {
138
+ const key = raw.trim();
139
+ if (!(0, personal_access_token_1.looksLikePersonalAccessToken)(key)) {
140
+ throw new errors_1.CliUsageError(`${from} takes a personal access key (it starts with "whatcha_pat_"; issue one in ${personal_access_token_1.WHERE_KEYS_ARE_ISSUED}). ` +
141
+ "For a refresh token, use --token / WHATCHA_TOKEN.");
142
+ }
143
+ if (!(0, personal_access_token_1.isWellFormedPersonalAccessToken)(key)) {
144
+ throw new errors_1.CliUsageError(`${from} starts like a personal access key but is not a complete one -- it may have been cut off when it was copied.`);
145
+ }
146
+ return key;
147
+ }
148
+ /**
149
+ * A personal access key (#1469 / PR #1550) is the Bearer credential itself:
150
+ * nothing to exchange, nothing to refresh, no captcha anywhere on the path.
151
+ * `GET /me` is both the check that the key works and where the id/email for
152
+ * the confirmation line come from. A revoked or expired key surfaces as
153
+ * KEY_REVOKED / KEY_EXPIRED (lib/personal-access-token.ts), straight from
154
+ * here, before anything is saved.
155
+ */
156
+ async function loginWithKey(opts, deps, key) {
157
+ const client = deps.client ? new session_1.KeyErrorClient(deps.client) : (0, session_1.personalAccessTokenClient)(opts.apiUrl, key);
158
+ const me = await client.get("/me");
159
+ return {
160
+ userId: me.id,
161
+ email: me.email ?? null,
162
+ accessToken: key,
163
+ refreshToken: "",
164
+ // Never consulted for a key (auth/session.ts checks authKind first).
165
+ expiresIn: 0,
166
+ authKind: "key",
167
+ };
168
+ }
169
+ /**
170
+ * The escape hatch issue #1428 asks for: skip the password grant (and
171
+ * whatever captcha it is gated behind) entirely by handing `whatcha` a
172
+ * refresh token minted some other way -- by an ops flow, a support-issued
173
+ * token, or a browser sign-in on a device that could actually solve the
174
+ * challenge. `POST /auth/refresh` is GoTrue's own rotation and is not
175
+ * captcha-gated (openapi.yaml's /auth/refresh), so this is the one login
176
+ * path that does not depend on Turnstile letting an automated caller
177
+ * through at all -- verified against openapi.yaml's documented contract,
178
+ * not against a live server (no test account for this task -- see the PR
179
+ * description).
180
+ *
181
+ * `/auth/refresh` returns no user info, so the id/email shown to the
182
+ * person come from decoding the access token's own JWT payload -- display
183
+ * only, not a trust decision (the server verifies the token on every real
184
+ * request regardless of what this reads out of it).
185
+ */
186
+ async function loginWithToken(opts, deps, refreshToken) {
187
+ const anon = deps.client ?? (0, session_1.anonymousClient)(opts.apiUrl);
188
+ let refreshed;
189
+ try {
190
+ refreshed = await anon.post("/auth/refresh", { refreshToken });
191
+ }
192
+ catch (err) {
193
+ throw new errors_1.CliUsageError("That token could not be used to start a session (it may be expired, already rotated, or not a " +
194
+ `refresh token at all). ${err instanceof errors_1.ApiError ? err.message : err.message}`);
195
+ }
196
+ const claims = (0, jwt_1.decodeJwtPayloadUnsafe)(refreshed.accessToken);
197
+ return {
198
+ userId: typeof claims?.sub === "string" ? claims.sub : "(unknown)",
199
+ email: typeof claims?.email === "string" ? claims.email : null,
200
+ accessToken: refreshed.accessToken,
201
+ refreshToken: refreshed.refreshToken,
202
+ expiresIn: refreshed.expiresIn,
203
+ };
204
+ }
205
+ /** Opt-in direct-GoTrue path -- see auth/gotrue-client.ts's header comment for why this needs WHATCHA_SUPABASE_URL/WHATCHA_SUPABASE_ANON_KEY set. */
206
+ async function loginWithPasswordViaGoTrue(supabase, email, password) {
207
+ const res = await (0, gotrue_client_1.signInWithPassword)(supabase.url, supabase.anonKey, email, password);
208
+ return {
209
+ userId: res.userId,
210
+ email: res.email,
211
+ accessToken: res.accessToken,
212
+ refreshToken: res.refreshToken,
213
+ expiresIn: res.expiresIn,
214
+ };
215
+ }
216
+ /**
217
+ * Default path: `POST /auth/login`, the API's own thin wrapper over the
218
+ * same GoTrue password grant (apps/api/src/modules/account/routes/auth.ts).
219
+ * It collapses *every* GoTrue failure into one generic 401
220
+ * INVALID_CREDENTIALS -- wrong password, unverified email, and a Turnstile
221
+ * captcha rejection all read identically from here, because the route only
222
+ * checks `status >= 400` and never looks at the GoTrue error body. See
223
+ * reportRefusal for what the CLI can and cannot tell the person because of
224
+ * that.
225
+ */
226
+ async function loginWithPasswordViaApi(opts, deps, email, password) {
227
+ const client = deps.client ?? (0, session_1.anonymousClient)(opts.apiUrl);
228
+ const res = await client.post("/auth/login", { email, password });
229
+ return {
230
+ userId: res.user.id,
231
+ email: res.user.email ?? email,
232
+ accessToken: res.accessToken,
233
+ refreshToken: res.refreshToken,
234
+ expiresIn: res.expiresIn,
235
+ };
236
+ }
237
+ function reportRefusal(err, opts) {
238
+ let message;
239
+ if (err instanceof gotrue_client_1.GoTrueError) {
240
+ // The direct-GoTrue path: its error body actually says whether this was
241
+ // a captcha rejection, unlike /auth/login's generic 401.
242
+ message = err.looksLikeCaptchaFailure()
243
+ ? "Sign-in needs a captcha challenge (Cloudflare Turnstile) that this terminal cannot solve " +
244
+ "(issue #1428). Use a personal access key instead: issue one in " +
245
+ `${personal_access_token_1.WHERE_KEYS_ARE_ISSUED}, then run \`whatcha login --key <key>\` or set WHATCHA_KEY, ` +
246
+ "instead of retrying a password sign-in here."
247
+ : `Sign-in was refused: ${err.message}`;
248
+ }
249
+ else if (err instanceof errors_1.ApiError && err.status === 401) {
250
+ message =
251
+ "Sign-in was refused. This could be a wrong email/password, or it could be that GoTrue is demanding " +
252
+ "a captcha challenge (Cloudflare Turnstile) this terminal cannot solve (issue #1428) -- /auth/login " +
253
+ "answers both the same generic way, so whatcha cannot tell them apart here. If the password is right, " +
254
+ "do not keep retrying it: use a personal access key instead. Issue one in " +
255
+ `${personal_access_token_1.WHERE_KEYS_ARE_ISSUED}, then run \`whatcha login --key <key>\` or set WHATCHA_KEY.`;
256
+ }
257
+ else {
258
+ throw err;
259
+ }
260
+ if (opts.json)
261
+ (0, output_1.printJson)({ ok: false, error: { code: "LOGIN_REFUSED", message } });
262
+ else
263
+ (0, output_1.printErrorLine)(message);
264
+ return { exitCode: 1 };
265
+ }
266
+ async function finishLogin(session, opts, deps) {
267
+ const { store } = await (0, session_1.saveSession)({
268
+ apiBaseUrl: opts.apiUrl,
269
+ userId: session.userId,
270
+ email: session.email,
271
+ accessToken: session.accessToken,
272
+ refreshToken: session.refreshToken,
273
+ expiresAt: Date.now() + session.expiresIn * 1000,
274
+ authKind: session.authKind ?? "session",
275
+ }, deps.stores ?? (0, token_store_1.candidateStores)());
276
+ // Never the tokens themselves -- see lib/output.ts's header comment.
277
+ if (opts.json) {
278
+ (0, output_1.printJson)({
279
+ ok: true,
280
+ userId: session.userId,
281
+ email: session.email,
282
+ credentialStore: store.name,
283
+ ...(session.authKind === "key" ? { authKind: "key" } : {}),
284
+ });
285
+ }
286
+ else {
287
+ const how = session.authKind === "key" ? " with a personal access key" : "";
288
+ (0, output_1.printLine)(`Logged in as ${session.email ?? session.userId}${how}. Session saved to ${store.name}.`);
289
+ }
290
+ return { exitCode: 0 };
291
+ }
292
+ //# sourceMappingURL=login.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,287 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseProfilesArgs = parseProfilesArgs;
4
+ exports.runProfiles = runProfiles;
5
+ exports.parseRemoveArgs = parseRemoveArgs;
6
+ exports.runRemove = runRemove;
7
+ exports.parseAddArgs = parseAddArgs;
8
+ exports.runAdd = runAdd;
9
+ exports.parseSwitchArgs = parseSwitchArgs;
10
+ exports.runSwitch = runSwitch;
11
+ const node_util_1 = require("node:util");
12
+ const session_1 = require("../auth/session");
13
+ const token_store_1 = require("../auth/token-store");
14
+ const errors_1 = require("../errors");
15
+ const config_1 = require("../config");
16
+ const image_upload_1 = require("../lib/image-upload");
17
+ const output_1 = require("../lib/output");
18
+ const profile_family_1 = require("../lib/profile-family");
19
+ function parseProfilesArgs(argv) {
20
+ let values;
21
+ try {
22
+ ({ values } = (0, node_util_1.parseArgs)({
23
+ args: argv,
24
+ options: { json: { type: "boolean", default: false } },
25
+ allowPositionals: false,
26
+ }));
27
+ }
28
+ catch (err) {
29
+ throw new errors_1.CliUsageError(err.message);
30
+ }
31
+ return { json: values.json };
32
+ }
33
+ const label = (p) => p.displayName && p.displayName.length > 0 ? p.displayName : (p.username ?? p.id);
34
+ async function runProfiles(opts, deps = {}) {
35
+ const resolved = deps.client ? null : await (0, session_1.authenticatedClient)();
36
+ const client = deps.client ?? resolved.client;
37
+ const session = deps.session ?? resolved.session;
38
+ const switcher = await client.get("/me/profiles");
39
+ if (opts.json) {
40
+ (0, output_1.printJson)({ ok: true, ...switcher, currentProfileId: session.userId });
41
+ return { exitCode: 0 };
42
+ }
43
+ for (const p of switcher.profiles) {
44
+ const here = p.id === session.userId ? "* " : " ";
45
+ const kind = p.parentProfileId === null ? " (account)" : "";
46
+ (0, output_1.printLine)(`${here}@${p.username ?? "?"} ${label(p)}${kind}`);
47
+ }
48
+ (0, output_1.printLine)(switcher.remaining > 0
49
+ ? `${switcher.remaining} more allowed on this plan.`
50
+ : "This plan allows no more sub-profiles.");
51
+ return { exitCode: 0 };
52
+ }
53
+ function parseRemoveArgs(argv) {
54
+ let values;
55
+ let positionals;
56
+ try {
57
+ ({ values, positionals } = (0, node_util_1.parseArgs)({
58
+ args: argv,
59
+ options: { json: { type: "boolean", default: false } },
60
+ allowPositionals: true,
61
+ }));
62
+ }
63
+ catch (err) {
64
+ throw new errors_1.CliUsageError(err.message);
65
+ }
66
+ if (!positionals[0]) {
67
+ throw new errors_1.CliUsageError("Which profile? Run `whatcha profiles` to see them.");
68
+ }
69
+ return { target: positionals[0], json: values.json };
70
+ }
71
+ /**
72
+ * Delete a sub-profile, and everything it wrote.
73
+ *
74
+ * Not the account and not the profile the CLI is currently signed in as --
75
+ * the API refuses both, and this asks it rather than deciding locally, so
76
+ * the two agree by construction.
77
+ */
78
+ async function runRemove(opts, deps = {}) {
79
+ const resolved = deps.client ? null : await (0, session_1.authenticatedClient)();
80
+ const client = deps.client ?? resolved.client;
81
+ const switcher = await client.get("/me/profiles");
82
+ const target = (0, profile_family_1.findProfile)(switcher.profiles, opts.target);
83
+ if (!target) {
84
+ throw new errors_1.CliUsageError(`No profile "${opts.target}". Run \`whatcha profiles\` to see them.`);
85
+ }
86
+ await client.delete(`/me/profiles/${target.id}`);
87
+ if (opts.json)
88
+ (0, output_1.printJson)({ ok: true, deleted: target.id });
89
+ else
90
+ (0, output_1.printLine)(`Deleted @${target.username ?? target.id}.`);
91
+ return { exitCode: 0 };
92
+ }
93
+ /** The API's rules for a sub-profile (sub-profiles-service.ts), checked before anything is sent. */
94
+ const HANDLE_RE = /^[A-Za-z0-9][A-Za-z0-9_-]{2,29}$/;
95
+ const MAX_DISPLAY_NAME = 80;
96
+ /** `POST /me/avatar` takes at most 5 MB -- less than an upload's 40. */
97
+ const MAX_AVATAR_BYTES = 5 * 1024 * 1024;
98
+ function parseAddArgs(argv) {
99
+ let values;
100
+ let positionals;
101
+ try {
102
+ ({ values, positionals } = (0, node_util_1.parseArgs)({
103
+ args: argv,
104
+ options: {
105
+ json: { type: "boolean", default: false },
106
+ name: { type: "string" },
107
+ avatar: { type: "string" },
108
+ },
109
+ allowPositionals: true,
110
+ }));
111
+ }
112
+ catch (err) {
113
+ throw new errors_1.CliUsageError(err.message);
114
+ }
115
+ if (!positionals[0]) {
116
+ throw new errors_1.CliUsageError("Which @handle? Run `whatcha profile-add <@handle> --name <display name>`.");
117
+ }
118
+ if (positionals.length > 1) {
119
+ throw new errors_1.CliUsageError(`One @handle per call; quote a --name with spaces (got "${positionals.join(" ")}").`);
120
+ }
121
+ const username = positionals[0].replace(/^@/, "");
122
+ if (!HANDLE_RE.test(username)) {
123
+ throw new errors_1.CliUsageError("A @handle is 3-30 letters, digits, _ or -, and starts with a letter or digit.");
124
+ }
125
+ const displayName = values.name?.trim();
126
+ if (!displayName)
127
+ throw new errors_1.CliUsageError("--name is required: the profile's display name.");
128
+ if (displayName.length > MAX_DISPLAY_NAME) {
129
+ throw new errors_1.CliUsageError(`--name is at most ${MAX_DISPLAY_NAME} characters.`);
130
+ }
131
+ return { username, displayName, avatar: values.avatar, json: values.json };
132
+ }
133
+ /**
134
+ * Create a sub-profile (#1699): `POST /me/profiles`, the call the app's
135
+ * "Add a profile" dialog makes. The plan's limit and a taken @handle are
136
+ * the API's call -- `whatcha profiles --json` shows `remaining`.
137
+ *
138
+ * `--avatar` is set the way the profile would set it itself: a session for
139
+ * the new profile, used once for `POST /me/avatar` and dropped (see
140
+ * lib/profile-family.ts). The CLI stays signed in as it was -- creating a
141
+ * profile is not switching to it. The file is checked before the profile
142
+ * is created, so a wrong file creates nothing; if the profile is created
143
+ * and only the avatar then fails, that is reported (exit status 2) rather
144
+ * than undone -- the profile is real and usable, just without a picture.
145
+ */
146
+ async function runAdd(opts, deps = {}) {
147
+ const avatar = opts.avatar !== undefined ? await (0, image_upload_1.readImageFile)(opts.avatar) : undefined;
148
+ if (avatar && avatar.bytes.length > MAX_AVATAR_BYTES) {
149
+ throw new errors_1.CliUsageError(`${avatar.path} is over 5 MB; an avatar is at most 5 MB.`);
150
+ }
151
+ const resolved = deps.client ? null : await (0, session_1.authenticatedClient)();
152
+ const client = deps.client ?? resolved.client;
153
+ const forToken = deps.clientForToken ?? (0, profile_family_1.bearerClients)(resolved?.session.apiBaseUrl || (0, config_1.apiBaseUrl)());
154
+ let profile = await client.post("/me/profiles", {
155
+ username: opts.username,
156
+ displayName: opts.displayName,
157
+ });
158
+ let avatarError = null;
159
+ if (avatar) {
160
+ try {
161
+ const asProfile = await (0, profile_family_1.clientAsProfile)(client, profile.id, forToken);
162
+ const set = await asProfile.post("/me/avatar", {
163
+ fileName: avatar.fileName,
164
+ contentType: avatar.contentType,
165
+ dataBase64: Buffer.from(avatar.bytes).toString("base64"),
166
+ });
167
+ profile = { ...profile, avatarUrl: set.avatarUrl };
168
+ }
169
+ catch (err) {
170
+ if (!(err instanceof errors_1.ApiError))
171
+ throw err;
172
+ avatarError = { code: err.code, message: err.message };
173
+ }
174
+ }
175
+ if (opts.json)
176
+ (0, output_1.printJson)({ ok: true, profile, avatarError });
177
+ else
178
+ (0, output_1.printLine)(`Created @${profile.username ?? opts.username} (${label(profile)}). Run \`whatcha switch @${profile.username ?? opts.username}\` to write as it.`);
179
+ if (avatarError) {
180
+ (0, output_1.printErrorLine)(`WARNING: the profile was created, but its avatar could not be set (${avatarError.code}: ${avatarError.message}). ` +
181
+ "Set it in the app, under the profile's settings.");
182
+ return { exitCode: 2 };
183
+ }
184
+ return { exitCode: 0 };
185
+ }
186
+ function parseSwitchArgs(argv) {
187
+ let values;
188
+ let positionals;
189
+ try {
190
+ ({ values, positionals } = (0, node_util_1.parseArgs)({
191
+ args: argv,
192
+ options: {
193
+ json: { type: "boolean", default: false },
194
+ account: { type: "boolean", default: false },
195
+ },
196
+ allowPositionals: true,
197
+ }));
198
+ }
199
+ catch (err) {
200
+ throw new errors_1.CliUsageError(err.message);
201
+ }
202
+ const toAccount = values.account;
203
+ const target = positionals[0] ?? null;
204
+ if (!toAccount && !target) {
205
+ throw new errors_1.CliUsageError("Which profile? Run `whatcha switch <@handle>` or `whatcha switch --account`.");
206
+ }
207
+ if (toAccount && target) {
208
+ throw new errors_1.CliUsageError("Give a profile or --account, not both.");
209
+ }
210
+ return { target, toAccount, json: values.json };
211
+ }
212
+ async function runSwitch(opts, deps = {}) {
213
+ const stores = deps.stores ?? (0, token_store_1.candidateStores)();
214
+ const resolved = deps.client ? null : await (0, session_1.authenticatedClient)(stores);
215
+ const client = deps.client ?? resolved.client;
216
+ const session = (deps.session ?? resolved.session);
217
+ if (opts.toAccount) {
218
+ const { accountRefreshToken: _dropped, accountKey, ...rest } = session;
219
+ if (accountKey) {
220
+ // Logged in with a personal access key (#1663): the way back is the
221
+ // key itself, which needs no refresh.
222
+ await (0, session_1.saveSession)({ ...rest, accessToken: accountKey, refreshToken: "", expiresAt: 0, authKind: "key" }, stores);
223
+ if (opts.json)
224
+ (0, output_1.printJson)({ ok: true, switchedTo: "account" });
225
+ else
226
+ (0, output_1.printLine)("Back on the account.");
227
+ return { exitCode: 0 };
228
+ }
229
+ const back = session.accountRefreshToken;
230
+ if (!back) {
231
+ throw new errors_1.CliUsageError("Already on the account.");
232
+ }
233
+ // An access token cannot be derived here, so the stored one is left
234
+ // expired on purpose: authenticatedClient() refreshes from the refresh
235
+ // token on the very next command, which is the same path a session that
236
+ // sat unused overnight takes.
237
+ await (0, session_1.saveSession)({ ...rest, refreshToken: back, expiresAt: 0, authKind: "session" }, stores);
238
+ if (opts.json)
239
+ (0, output_1.printJson)({ ok: true, switchedTo: "account" });
240
+ else
241
+ (0, output_1.printLine)("Back on the account.");
242
+ return { exitCode: 0 };
243
+ }
244
+ const switcher = await client.get("/me/profiles");
245
+ const target = (0, profile_family_1.findProfile)(switcher.profiles, opts.target);
246
+ if (!target) {
247
+ throw new errors_1.CliUsageError(`No profile "${opts.target}". Run \`whatcha profiles\` to see them.`);
248
+ }
249
+ if (target.parentProfileId === null) {
250
+ throw new errors_1.CliUsageError("To go back to the account, run `whatcha switch --account`.");
251
+ }
252
+ if (target.id === session.userId) {
253
+ if (opts.json)
254
+ (0, output_1.printJson)({ ok: true, switchedTo: target.id, alreadyThere: true });
255
+ else
256
+ (0, output_1.printLine)(`Already writing as @${target.username ?? target.id}.`);
257
+ return { exitCode: 0 };
258
+ }
259
+ const issued = await client.post(`/me/profiles/${target.id}/session`, {});
260
+ // The account's credential is carried over BEFORE the session is
261
+ // replaced: after this save it is the only copy, and losing it would
262
+ // strand the CLI inside a sub-profile. A key login (#1663) has no refresh
263
+ // token, so what is kept is the key; once switched, the session itself is
264
+ // an ordinary sub-profile session either way.
265
+ const fromKey = session.accountKey ?? (session.authKind === "key" ? session.accessToken : undefined);
266
+ const stash = fromKey ? undefined : (session.accountRefreshToken ?? session.refreshToken);
267
+ const { accountRefreshToken: _r, accountKey: _k, ...base } = session;
268
+ const next = {
269
+ ...base,
270
+ userId: issued.profileId,
271
+ // A sub-profile has no address of its own; the internal one the API
272
+ // holds for GoTrue is never handed out and must not be stored here.
273
+ email: null,
274
+ accessToken: issued.accessToken,
275
+ refreshToken: issued.refreshToken,
276
+ expiresAt: Date.now() + issued.expiresIn * 1000,
277
+ authKind: "session",
278
+ ...(fromKey ? { accountKey: fromKey } : { accountRefreshToken: stash }),
279
+ };
280
+ await (0, session_1.saveSession)(next, stores);
281
+ if (opts.json)
282
+ (0, output_1.printJson)({ ok: true, switchedTo: issued.profileId });
283
+ else
284
+ (0, output_1.printLine)(`Writing as @${target.username ?? target.id}.`);
285
+ return { exitCode: 0 };
286
+ }
287
+ //# sourceMappingURL=profiles.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profiles.js","sourceRoot":"","sources":["../../src/commands/profiles.ts"],"names":[],"mappings":";;AAkCA,8CAYC;AAKD,kCA0BC;AAQD,0CAgBC;AASD,8BAkBC;AAgBD,oCAgCC;AAeD,wBA4CC;AASD,0CAwBC;AAaD,8BA0EC;AAnWD,yCAAsC;AACtC,6CAAmE;AACnE,qDAA2F;AAC3F,sCAAoD;AACpD,sCAAuC;AAEvC,sDAAoD;AACpD,0CAAqE;AACrE,0DAQ+B;AAkB/B,SAAgB,iBAAiB,CAAC,IAAc;IAC9C,IAAI,MAAM,CAAC;IACX,IAAI,CAAC;QACH,CAAC,EAAE,MAAM,EAAE,GAAG,IAAA,qBAAS,EAAC;YACtB,IAAI,EAAE,IAAI;YACV,OAAO,EAAE,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;YACtD,gBAAgB,EAAE,KAAK;SACxB,CAAC,CAAC,CAAC;IACN,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,sBAAa,CAAE,GAAa,CAAC,OAAO,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,MAAM,CAAC,IAAe,EAAE,CAAC;AAC1C,CAAC;AAED,MAAM,KAAK,GAAG,CAAC,CAAoB,EAAE,EAAE,CACrC,CAAC,CAAC,WAAW,IAAI,CAAC,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC;AAE5E,KAAK,UAAU,WAAW,CAC/B,IAAqB,EACrB,OAA4D,EAAE;IAE9D,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,IAAA,6BAAmB,GAAE,CAAC;IAClE,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,QAAS,CAAC,MAAM,CAAC;IAC/C,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,QAAS,CAAC,OAAO,CAAC;IAElD,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,GAAG,CAAkB,cAAc,CAAC,CAAC;IAEnE,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,IAAA,kBAAS,EAAC,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,QAAQ,EAAE,gBAAgB,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;QACvE,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;IACzB,CAAC;IAED,KAAK,MAAM,CAAC,IAAI,QAAQ,CAAC,QAAQ,EAAE,CAAC;QAClC,MAAM,IAAI,GAAG,CAAC,CAAC,EAAE,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;QACnD,MAAM,IAAI,GAAG,CAAC,CAAC,eAAe,KAAK,IAAI,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7D,IAAA,kBAAS,EAAC,GAAG,IAAI,IAAI,CAAC,CAAC,QAAQ,IAAI,GAAG,KAAK,KAAK,CAAC,CAAC,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC;IAChE,CAAC;IACD,IAAA,kBAAS,EACP,QAAQ,CAAC,SAAS,GAAG,CAAC;QACpB,CAAC,CAAC,GAAG,QAAQ,CAAC,SAAS,6BAA6B;QACpD,CAAC,CAAC,wCAAwC,CAC7C,CAAC;IACF,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;AACzB,CAAC;AAQD,SAAgB,eAAe,CAAC,IAAc;IAC5C,IAAI,MAAM,CAAC;IACX,IAAI,WAAqB,CAAC;IAC1B,IAAI,CAAC;QACH,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,IAAA,qBAAS,EAAC;YACnC,IAAI,EAAE,IAAI;YACV,OAAO,EAAE,EAAE,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE;YACtD,gBAAgB,EAAE,IAAI;SACvB,CAAC,CAAC,CAAC;IACN,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,sBAAa,CAAE,GAAa,CAAC,OAAO,CAAC,CAAC;IAClD,CAAC;IACD,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC;QACpB,MAAM,IAAI,sBAAa,CAAC,oDAAoD,CAAC,CAAC;IAChF,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAe,EAAE,CAAC;AAClE,CAAC;AAED;;;;;;GAMG;AACI,KAAK,UAAU,SAAS,CAC7B,IAAmB,EACnB,OAA4D,EAAE;IAE9D,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,IAAA,6BAAmB,GAAE,CAAC;IAClE,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,QAAS,CAAC,MAAM,CAAC;IAE/C,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,GAAG,CAAkB,cAAc,CAAC,CAAC;IACnE,MAAM,MAAM,GAAG,IAAA,4BAAW,EAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IAC3D,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,sBAAa,CAAC,eAAe,IAAI,CAAC,MAAM,0CAA0C,CAAC,CAAC;IAChG,CAAC;IAED,MAAM,MAAM,CAAC,MAAM,CAAuB,gBAAgB,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;IAEvE,IAAI,IAAI,CAAC,IAAI;QAAE,IAAA,kBAAS,EAAC,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,CAAC,EAAE,EAAE,CAAC,CAAC;;QACtD,IAAA,kBAAS,EAAC,YAAY,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,EAAE,GAAG,CAAC,CAAC;IAC5D,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;AACzB,CAAC;AAED,oGAAoG;AACpG,MAAM,SAAS,GAAG,kCAAkC,CAAC;AACrD,MAAM,gBAAgB,GAAG,EAAE,CAAC;AAC5B,wEAAwE;AACxE,MAAM,gBAAgB,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;AAUzC,SAAgB,YAAY,CAAC,IAAc;IACzC,IAAI,MAAM,CAAC;IACX,IAAI,WAAqB,CAAC;IAC1B,IAAI,CAAC;QACH,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,IAAA,qBAAS,EAAC;YACnC,IAAI,EAAE,IAAI;YACV,OAAO,EAAE;gBACP,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE;gBACzC,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBACxB,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;aAC3B;YACD,gBAAgB,EAAE,IAAI;SACvB,CAAC,CAAC,CAAC;IACN,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,sBAAa,CAAE,GAAa,CAAC,OAAO,CAAC,CAAC;IAClD,CAAC;IACD,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC;QACpB,MAAM,IAAI,sBAAa,CAAC,2EAA2E,CAAC,CAAC;IACvG,CAAC;IACD,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3B,MAAM,IAAI,sBAAa,CAAC,0DAA0D,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IAChH,CAAC;IACD,MAAM,QAAQ,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAClD,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC9B,MAAM,IAAI,sBAAa,CAAC,+EAA+E,CAAC,CAAC;IAC3G,CAAC;IACD,MAAM,WAAW,GAAI,MAAM,CAAC,IAA2B,EAAE,IAAI,EAAE,CAAC;IAChE,IAAI,CAAC,WAAW;QAAE,MAAM,IAAI,sBAAa,CAAC,iDAAiD,CAAC,CAAC;IAC7F,IAAI,WAAW,CAAC,MAAM,GAAG,gBAAgB,EAAE,CAAC;QAC1C,MAAM,IAAI,sBAAa,CAAC,qBAAqB,gBAAgB,cAAc,CAAC,CAAC;IAC/E,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,MAA4B,EAAE,IAAI,EAAE,MAAM,CAAC,IAAe,EAAE,CAAC;AAC9G,CAAC;AAED;;;;;;;;;;;;GAYG;AACI,KAAK,UAAU,MAAM,CAC1B,IAAgB,EAChB,OAAoE,EAAE;IAEtE,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,IAAA,4BAAa,EAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACxF,IAAI,MAAM,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,gBAAgB,EAAE,CAAC;QACrD,MAAM,IAAI,sBAAa,CAAC,GAAG,MAAM,CAAC,IAAI,2CAA2C,CAAC,CAAC;IACrF,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,IAAA,6BAAmB,GAAE,CAAC;IAClE,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,QAAS,CAAC,MAAM,CAAC;IAC/C,MAAM,QAAQ,GAAG,IAAI,CAAC,cAAc,IAAI,IAAA,8BAAa,EAAC,QAAQ,EAAE,OAAO,CAAC,UAAU,IAAI,IAAA,mBAAU,GAAE,CAAC,CAAC;IAEpG,IAAI,OAAO,GAAG,MAAM,MAAM,CAAC,IAAI,CAAoB,cAAc,EAAE;QACjE,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,WAAW,EAAE,IAAI,CAAC,WAAW;KAC9B,CAAC,CAAC;IAEH,IAAI,WAAW,GAA6C,IAAI,CAAC;IACjE,IAAI,MAAM,EAAE,CAAC;QACX,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,MAAM,IAAA,gCAAe,EAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;YACtE,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,IAAI,CAAwB,YAAY,EAAE;gBACpE,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,WAAW,EAAE,MAAM,CAAC,WAAW;gBAC/B,UAAU,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC;aACzD,CAAC,CAAC;YACH,OAAO,GAAG,EAAE,GAAG,OAAO,EAAE,SAAS,EAAE,GAAG,CAAC,SAAS,EAAE,CAAC;QACrD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAI,CAAC,CAAC,GAAG,YAAY,iBAAQ,CAAC;gBAAE,MAAM,GAAG,CAAC;YAC1C,WAAW,GAAG,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC;QACzD,CAAC;IACH,CAAC;IAED,IAAI,IAAI,CAAC,IAAI;QAAE,IAAA,kBAAS,EAAC,EAAE,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC,CAAC;;QACxD,IAAA,kBAAS,EAAC,YAAY,OAAO,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,KAAK,KAAK,CAAC,OAAO,CAAC,4BAA4B,OAAO,CAAC,QAAQ,IAAI,IAAI,CAAC,QAAQ,oBAAoB,CAAC,CAAC;IAClK,IAAI,WAAW,EAAE,CAAC;QAChB,IAAA,uBAAc,EACZ,sEAAsE,WAAW,CAAC,IAAI,KAAK,WAAW,CAAC,OAAO,KAAK;YACjH,kDAAkD,CACrD,CAAC;QACF,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;IACzB,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;AACzB,CAAC;AASD,SAAgB,eAAe,CAAC,IAAc;IAC5C,IAAI,MAAM,CAAC;IACX,IAAI,WAAqB,CAAC;IAC1B,IAAI,CAAC;QACH,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,IAAA,qBAAS,EAAC;YACnC,IAAI,EAAE,IAAI;YACV,OAAO,EAAE;gBACP,IAAI,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE;gBACzC,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE;aAC7C;YACD,gBAAgB,EAAE,IAAI;SACvB,CAAC,CAAC,CAAC;IACN,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,sBAAa,CAAE,GAAa,CAAC,OAAO,CAAC,CAAC;IAClD,CAAC;IACD,MAAM,SAAS,GAAG,MAAM,CAAC,OAAkB,CAAC;IAC5C,MAAM,MAAM,GAAG,WAAW,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC;IACtC,IAAI,CAAC,SAAS,IAAI,CAAC,MAAM,EAAE,CAAC;QAC1B,MAAM,IAAI,sBAAa,CAAC,8EAA8E,CAAC,CAAC;IAC1G,CAAC;IACD,IAAI,SAAS,IAAI,MAAM,EAAE,CAAC;QACxB,MAAM,IAAI,sBAAa,CAAC,wCAAwC,CAAC,CAAC;IACpE,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,CAAC,IAAe,EAAE,CAAC;AAC7D,CAAC;AAaM,KAAK,UAAU,SAAS,CAC7B,IAAmB,EACnB,OAAmF,EAAE;IAErF,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,IAAA,6BAAe,GAAE,CAAC;IAChD,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,IAAA,6BAAmB,EAAC,MAAM,CAAC,CAAC;IACxE,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,IAAI,QAAS,CAAC,MAAM,CAAC;IAC/C,MAAM,OAAO,GAAG,CAAC,IAAI,CAAC,OAAO,IAAI,QAAS,CAAC,OAAO,CAAqB,CAAC;IAExE,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QACnB,MAAM,EAAE,mBAAmB,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;QACvE,IAAI,UAAU,EAAE,CAAC;YACf,oEAAoE;YACpE,sCAAsC;YACtC,MAAM,IAAA,qBAAW,EAAC,EAAE,GAAG,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,EAAE,EAAE,SAAS,EAAE,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,EAAE,MAAM,CAAC,CAAC;YACjH,IAAI,IAAI,CAAC,IAAI;gBAAE,IAAA,kBAAS,EAAC,EAAE,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,CAAC;;gBACzD,IAAA,kBAAS,EAAC,sBAAsB,CAAC,CAAC;YACvC,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;QACzB,CAAC;QACD,MAAM,IAAI,GAAG,OAAO,CAAC,mBAAmB,CAAC;QACzC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,sBAAa,CAAC,yBAAyB,CAAC,CAAC;QACrD,CAAC;QACD,oEAAoE;QACpE,uEAAuE;QACvE,wEAAwE;QACxE,8BAA8B;QAC9B,MAAM,IAAA,qBAAW,EAAC,EAAE,GAAG,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,MAAM,CAAC,CAAC;QAC9F,IAAI,IAAI,CAAC,IAAI;YAAE,IAAA,kBAAS,EAAC,EAAE,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,CAAC,CAAC;;YACzD,IAAA,kBAAS,EAAC,sBAAsB,CAAC,CAAC;QACvC,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;IACzB,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,GAAG,CAAkB,cAAc,CAAC,CAAC;IACnE,MAAM,MAAM,GAAG,IAAA,4BAAW,EAAC,QAAQ,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAO,CAAC,CAAC;IAC5D,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,sBAAa,CAAC,eAAe,IAAI,CAAC,MAAM,0CAA0C,CAAC,CAAC;IAChG,CAAC;IACD,IAAI,MAAM,CAAC,eAAe,KAAK,IAAI,EAAE,CAAC;QACpC,MAAM,IAAI,sBAAa,CAAC,4DAA4D,CAAC,CAAC;IACxF,CAAC;IACD,IAAI,MAAM,CAAC,EAAE,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC;QACjC,IAAI,IAAI,CAAC,IAAI;YAAE,IAAA,kBAAS,EAAC,EAAE,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC;;YAC7E,IAAA,kBAAS,EAAC,uBAAuB,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,EAAE,GAAG,CAAC,CAAC;QACvE,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;IACzB,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAiB,gBAAgB,MAAM,CAAC,EAAE,UAAU,EAAE,EAAE,CAAC,CAAC;IAE1F,iEAAiE;IACjE,qEAAqE;IACrE,0EAA0E;IAC1E,0EAA0E;IAC1E,8CAA8C;IAC9C,MAAM,OAAO,GAAG,OAAO,CAAC,UAAU,IAAI,CAAC,OAAO,CAAC,QAAQ,KAAK,KAAK,CAAC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;IACrG,MAAM,KAAK,GAAG,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,mBAAmB,IAAI,OAAO,CAAC,YAAY,CAAC,CAAC;IAC1F,MAAM,EAAE,mBAAmB,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,GAAG,IAAI,EAAE,GAAG,OAAO,CAAC;IACrE,MAAM,IAAI,GAAqB;QAC7B,GAAG,IAAI;QACP,MAAM,EAAE,MAAM,CAAC,SAAS;QACxB,oEAAoE;QACpE,oEAAoE;QACpE,KAAK,EAAE,IAAI;QACX,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,YAAY,EAAE,MAAM,CAAC,YAAY;QACjC,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,MAAM,CAAC,SAAS,GAAG,IAAI;QAC/C,QAAQ,EAAE,SAAS;QACnB,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,mBAAmB,EAAE,KAAK,EAAE,CAAC;KACxE,CAAC;IACF,MAAM,IAAA,qBAAW,EAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAEhC,IAAI,IAAI,CAAC,IAAI;QAAE,IAAA,kBAAS,EAAC,EAAE,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,CAAC,SAAS,EAAE,CAAC,CAAC;;QAChE,IAAA,kBAAS,EAAC,eAAe,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,EAAE,GAAG,CAAC,CAAC;IAC/D,OAAO,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;AACzB,CAAC"}