@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.
- package/LICENSE +202 -0
- package/README.md +345 -2
- package/dist/auth/gotrue-client.js +64 -0
- package/dist/auth/gotrue-client.js.map +1 -0
- package/dist/auth/session.js +147 -0
- package/dist/auth/session.js.map +1 -0
- package/dist/auth/token-store.js +165 -0
- package/dist/auth/token-store.js.map +1 -0
- package/dist/cli.js +134 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/diaries.js +52 -0
- package/dist/commands/diaries.js.map +1 -0
- package/dist/commands/login.js +292 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/profiles.js +287 -0
- package/dist/commands/profiles.js.map +1 -0
- package/dist/commands/publish.js +81 -0
- package/dist/commands/publish.js.map +1 -0
- package/dist/commands/read.js +77 -0
- package/dist/commands/read.js.map +1 -0
- package/dist/commands/shared-diary.js +255 -0
- package/dist/commands/shared-diary.js.map +1 -0
- package/dist/commands/whoami.js +50 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/commands/wiki.js +386 -0
- package/dist/commands/wiki.js.map +1 -0
- package/dist/commands/write.js +106 -0
- package/dist/commands/write.js.map +1 -0
- package/dist/config.js +47 -0
- package/dist/config.js.map +1 -0
- package/dist/errors.js +46 -0
- package/dist/errors.js.map +1 -0
- package/dist/http-client.js +102 -0
- package/dist/http-client.js.map +1 -0
- package/dist/index.js +16 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/append-entry.js +193 -0
- package/dist/lib/append-entry.js.map +1 -0
- package/dist/lib/diary-resolve.js +50 -0
- package/dist/lib/diary-resolve.js.map +1 -0
- package/dist/lib/entry-date.js +96 -0
- package/dist/lib/entry-date.js.map +1 -0
- package/dist/lib/entry-find.js +39 -0
- package/dist/lib/entry-find.js.map +1 -0
- package/dist/lib/image-upload.js +126 -0
- package/dist/lib/image-upload.js.map +1 -0
- package/dist/lib/jwt.js +25 -0
- package/dist/lib/jwt.js.map +1 -0
- package/dist/lib/output.js +29 -0
- package/dist/lib/output.js.map +1 -0
- package/dist/lib/personal-access-token.js +46 -0
- package/dist/lib/personal-access-token.js.map +1 -0
- package/dist/lib/profile-family.js +29 -0
- package/dist/lib/profile-family.js.map +1 -0
- package/dist/lib/publication.js +55 -0
- package/dist/lib/publication.js.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- 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":"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"}
|