@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,147 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.KeyErrorClient = void 0;
|
|
4
|
+
exports.saveSession = saveSession;
|
|
5
|
+
exports.loadSession = loadSession;
|
|
6
|
+
exports.clearSession = clearSession;
|
|
7
|
+
exports.authenticatedClient = authenticatedClient;
|
|
8
|
+
exports.personalAccessTokenClient = personalAccessTokenClient;
|
|
9
|
+
exports.anonymousClient = anonymousClient;
|
|
10
|
+
const http_client_1 = require("../http-client");
|
|
11
|
+
const config_1 = require("../config");
|
|
12
|
+
const errors_1 = require("../errors");
|
|
13
|
+
const personal_access_token_1 = require("../lib/personal-access-token");
|
|
14
|
+
const token_store_1 = require("./token-store");
|
|
15
|
+
/** Refresh this many seconds before actual expiry, so a call in flight does not race the token dying mid-request. */
|
|
16
|
+
const REFRESH_MARGIN_SECONDS = 60;
|
|
17
|
+
/**
|
|
18
|
+
* Tries each candidate store in order (OS keychain first where one exists
|
|
19
|
+
* for the platform, the 0600 file always last) and uses the first one that
|
|
20
|
+
* actually accepts the write. A keychain that exists but is locked, or a
|
|
21
|
+
* Secret Service that is not running, throws on `save` rather than on
|
|
22
|
+
* `isAvailable` -- both are caught here, not just the availability check.
|
|
23
|
+
*/
|
|
24
|
+
async function saveSession(session, stores = (0, token_store_1.candidateStores)()) {
|
|
25
|
+
const errors = [];
|
|
26
|
+
for (const store of stores) {
|
|
27
|
+
if (!(await store.isAvailable()))
|
|
28
|
+
continue;
|
|
29
|
+
try {
|
|
30
|
+
await store.save(session);
|
|
31
|
+
return { store };
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
errors.push(`${store.name}: ${err.message}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
throw new Error(`Could not save the session to any credential store. Tried:\n${errors.join("\n")}`);
|
|
38
|
+
}
|
|
39
|
+
/** First candidate store that actually has a session, or null if none do. */
|
|
40
|
+
async function loadSession(stores = (0, token_store_1.candidateStores)()) {
|
|
41
|
+
for (const store of stores) {
|
|
42
|
+
if (!(await store.isAvailable()))
|
|
43
|
+
continue;
|
|
44
|
+
const session = await store.load();
|
|
45
|
+
if (session)
|
|
46
|
+
return session;
|
|
47
|
+
}
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
/** Best-effort clear from every candidate, not just whichever one currently holds the session -- avoids a stale copy surviving a store switch. */
|
|
51
|
+
async function clearSession(stores = (0, token_store_1.candidateStores)()) {
|
|
52
|
+
for (const store of stores) {
|
|
53
|
+
if (await store.isAvailable())
|
|
54
|
+
await store.clear();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* A client wired to a saved session, refreshing the access token first if
|
|
59
|
+
* it is at or near expiry. Every command but `login` starts here.
|
|
60
|
+
*
|
|
61
|
+
* Throws CliUsageError (not ApiError) when there is no session or the
|
|
62
|
+
* refresh itself fails -- both are "run `whatcha login`" situations, not
|
|
63
|
+
* something a command should try to recover from.
|
|
64
|
+
*/
|
|
65
|
+
async function authenticatedClient(stores = (0, token_store_1.candidateStores)()) {
|
|
66
|
+
let session = await loadSession(stores);
|
|
67
|
+
if (!session) {
|
|
68
|
+
throw new errors_1.CliUsageError("Not logged in. Run `whatcha login` first.");
|
|
69
|
+
}
|
|
70
|
+
const baseUrl = session.apiBaseUrl || (0, config_1.apiBaseUrl)();
|
|
71
|
+
if (session.authKind === "key") {
|
|
72
|
+
// A personal access key is the Bearer itself: nothing to refresh, and
|
|
73
|
+
// its refusals are reworded as the key's (KEY_REVOKED / KEY_EXPIRED).
|
|
74
|
+
return { client: personalAccessTokenClient(baseUrl, session.accessToken), session };
|
|
75
|
+
}
|
|
76
|
+
const nowSeconds = Date.now() / 1000;
|
|
77
|
+
if (session.expiresAt / 1000 - nowSeconds < REFRESH_MARGIN_SECONDS) {
|
|
78
|
+
const anon = new http_client_1.FetchWhatchaClient(baseUrl, async () => undefined);
|
|
79
|
+
let refreshed;
|
|
80
|
+
try {
|
|
81
|
+
refreshed = await anon.post("/auth/refresh", { refreshToken: session.refreshToken });
|
|
82
|
+
}
|
|
83
|
+
catch {
|
|
84
|
+
throw new errors_1.CliUsageError("The saved session has expired and could not be refreshed. Run `whatcha login` again.");
|
|
85
|
+
}
|
|
86
|
+
session = {
|
|
87
|
+
...session,
|
|
88
|
+
accessToken: refreshed.accessToken,
|
|
89
|
+
refreshToken: refreshed.refreshToken,
|
|
90
|
+
expiresAt: Date.now() + refreshed.expiresIn * 1000,
|
|
91
|
+
};
|
|
92
|
+
// Best-effort: a save failure here must not fail the command that
|
|
93
|
+
// triggered the refresh -- worst case, the next command refreshes
|
|
94
|
+
// again. Whichever store answered `load()` above is where this goes
|
|
95
|
+
// back to.
|
|
96
|
+
await saveSession(session, stores).catch(() => undefined);
|
|
97
|
+
}
|
|
98
|
+
const client = new http_client_1.FetchWhatchaClient(baseUrl, async () => `Bearer ${session.accessToken}`);
|
|
99
|
+
return { client, session };
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* A client that sends a personal access key (#1663) as its Bearer and
|
|
103
|
+
* reports a 401 as the key's problem -- see lib/personal-access-token.ts.
|
|
104
|
+
*/
|
|
105
|
+
function personalAccessTokenClient(baseUrl, key) {
|
|
106
|
+
return new KeyErrorClient(new http_client_1.FetchWhatchaClient(baseUrl, async () => `Bearer ${key}`));
|
|
107
|
+
}
|
|
108
|
+
/** Wraps any client so a 401 reads as KEY_REVOKED/KEY_EXPIRED. Exported for tests. */
|
|
109
|
+
class KeyErrorClient {
|
|
110
|
+
inner;
|
|
111
|
+
constructor(inner) {
|
|
112
|
+
this.inner = inner;
|
|
113
|
+
}
|
|
114
|
+
wrap(p) {
|
|
115
|
+
return p.catch((err) => {
|
|
116
|
+
throw (0, personal_access_token_1.translateKeyError)(err);
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
get(path, query) {
|
|
120
|
+
return this.wrap(this.inner.get(path, query));
|
|
121
|
+
}
|
|
122
|
+
post(path, body) {
|
|
123
|
+
return this.wrap(this.inner.post(path, body));
|
|
124
|
+
}
|
|
125
|
+
put(path, body) {
|
|
126
|
+
return this.wrap(this.inner.put(path, body));
|
|
127
|
+
}
|
|
128
|
+
patch(path, body) {
|
|
129
|
+
return this.wrap(this.inner.patch(path, body));
|
|
130
|
+
}
|
|
131
|
+
delete(path) {
|
|
132
|
+
return this.wrap(this.inner.delete(path));
|
|
133
|
+
}
|
|
134
|
+
getPage(path, query) {
|
|
135
|
+
return this.wrap(this.inner.getPage(path, query));
|
|
136
|
+
}
|
|
137
|
+
/** Not wrapped: the signed URL carries no key, so its 401/403 is never the key's. */
|
|
138
|
+
putBytes(url, headers, bytes) {
|
|
139
|
+
return this.inner.putBytes(url, headers, bytes);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
exports.KeyErrorClient = KeyErrorClient;
|
|
143
|
+
/** An unauthenticated client for `/auth/login` itself, or for `--api-url` probing. */
|
|
144
|
+
function anonymousClient(baseUrl = (0, config_1.apiBaseUrl)()) {
|
|
145
|
+
return new http_client_1.FetchWhatchaClient(baseUrl, async () => undefined);
|
|
146
|
+
}
|
|
147
|
+
//# sourceMappingURL=session.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/auth/session.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,165 @@
|
|
|
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.FileTokenStore = void 0;
|
|
7
|
+
exports.candidateStores = candidateStores;
|
|
8
|
+
const node_child_process_1 = require("node:child_process");
|
|
9
|
+
const promises_1 = __importDefault(require("node:fs/promises"));
|
|
10
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
11
|
+
const config_1 = require("../config");
|
|
12
|
+
function execFileText(cmd, args, input) {
|
|
13
|
+
return new Promise((resolve, reject) => {
|
|
14
|
+
const child = (0, node_child_process_1.execFile)(cmd, args, { encoding: "utf8", maxBuffer: 1024 * 1024 }, (err, stdout) => {
|
|
15
|
+
if (err)
|
|
16
|
+
reject(err);
|
|
17
|
+
else
|
|
18
|
+
resolve(stdout);
|
|
19
|
+
});
|
|
20
|
+
if (input !== undefined)
|
|
21
|
+
child.stdin?.end(input);
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
async function commandExists(cmd) {
|
|
25
|
+
try {
|
|
26
|
+
await execFileText(process.platform === "win32" ? "where" : "which", [cmd]);
|
|
27
|
+
return true;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const SERVICE = "whatcha-cli";
|
|
34
|
+
const ACCOUNT = "whatcha";
|
|
35
|
+
/**
|
|
36
|
+
* macOS Keychain, via the `security` CLI (no native module -- `keytar` and
|
|
37
|
+
* friends need a node-gyp build per platform, which is a lot to ask of
|
|
38
|
+
* `npm ci` for one command most sessions never touch). The whole session
|
|
39
|
+
* (both tokens, the email, the expiry) is stored as one JSON blob under a
|
|
40
|
+
* single fixed account name; this is a one-account CLI, not a credential
|
|
41
|
+
* manager for several.
|
|
42
|
+
*/
|
|
43
|
+
class MacKeychainStore {
|
|
44
|
+
name = "macOS Keychain";
|
|
45
|
+
async isAvailable() {
|
|
46
|
+
return process.platform === "darwin" && (await commandExists("security"));
|
|
47
|
+
}
|
|
48
|
+
async save(session) {
|
|
49
|
+
// -U: update in place if an entry already exists, instead of erroring.
|
|
50
|
+
await execFileText("security", [
|
|
51
|
+
"add-generic-password",
|
|
52
|
+
"-a",
|
|
53
|
+
ACCOUNT,
|
|
54
|
+
"-s",
|
|
55
|
+
SERVICE,
|
|
56
|
+
"-w",
|
|
57
|
+
JSON.stringify(session),
|
|
58
|
+
"-U",
|
|
59
|
+
]);
|
|
60
|
+
}
|
|
61
|
+
async load() {
|
|
62
|
+
try {
|
|
63
|
+
const out = await execFileText("security", ["find-generic-password", "-a", ACCOUNT, "-s", SERVICE, "-w"]);
|
|
64
|
+
return JSON.parse(out.trim());
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
async clear() {
|
|
71
|
+
try {
|
|
72
|
+
await execFileText("security", ["delete-generic-password", "-a", ACCOUNT, "-s", SERVICE]);
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
// Nothing stored -- clearing an already-empty store is not an error.
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Linux, via `secret-tool` (libsecret) -- GNOME Keyring, KWallet's libsecret
|
|
81
|
+
* shim, etc. Only actually works when a secret service is running, which a
|
|
82
|
+
* plain SSH session or a container usually does not have; `isAvailable`
|
|
83
|
+
* only checks the binary exists, so a headless box falls through to the
|
|
84
|
+
* file store the first time `save` throws (see auth/session.ts).
|
|
85
|
+
*/
|
|
86
|
+
class LinuxSecretToolStore {
|
|
87
|
+
name = "the Secret Service (secret-tool)";
|
|
88
|
+
async isAvailable() {
|
|
89
|
+
return process.platform === "linux" && (await commandExists("secret-tool"));
|
|
90
|
+
}
|
|
91
|
+
async save(session) {
|
|
92
|
+
await execFileText("secret-tool", ["store", "--label=whatcha CLI session", "service", SERVICE, "account", ACCOUNT], JSON.stringify(session));
|
|
93
|
+
}
|
|
94
|
+
async load() {
|
|
95
|
+
try {
|
|
96
|
+
const out = await execFileText("secret-tool", ["lookup", "service", SERVICE, "account", ACCOUNT]);
|
|
97
|
+
const trimmed = out.trim();
|
|
98
|
+
return trimmed ? JSON.parse(trimmed) : null;
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
async clear() {
|
|
105
|
+
try {
|
|
106
|
+
await execFileText("secret-tool", ["clear", "service", SERVICE, "account", ACCOUNT]);
|
|
107
|
+
}
|
|
108
|
+
catch {
|
|
109
|
+
// Nothing stored.
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* The fallback the task asks for by name: a 0600 file under the config dir.
|
|
115
|
+
* Always available, so it is always last in the candidate list and never
|
|
116
|
+
* itself falls back to anything.
|
|
117
|
+
*/
|
|
118
|
+
class FileTokenStore {
|
|
119
|
+
name = `file (${(0, config_1.credentialsFilePath)()})`;
|
|
120
|
+
async isAvailable() {
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
async save(session) {
|
|
124
|
+
const file = (0, config_1.credentialsFilePath)();
|
|
125
|
+
await promises_1.default.mkdir(node_path_1.default.dirname(file), { recursive: true, mode: 0o700 });
|
|
126
|
+
await promises_1.default.writeFile(file, JSON.stringify(session, null, 2), { mode: 0o600 });
|
|
127
|
+
// Belt and suspenders: writeFile's mode only applies when it creates the
|
|
128
|
+
// file. An existing file (re-login) keeps whatever mode it already had,
|
|
129
|
+
// so set it explicitly every time.
|
|
130
|
+
await promises_1.default.chmod(file, 0o600);
|
|
131
|
+
}
|
|
132
|
+
async load() {
|
|
133
|
+
try {
|
|
134
|
+
const text = await promises_1.default.readFile((0, config_1.credentialsFilePath)(), "utf8");
|
|
135
|
+
return JSON.parse(text);
|
|
136
|
+
}
|
|
137
|
+
catch (err) {
|
|
138
|
+
if (err.code === "ENOENT")
|
|
139
|
+
return null;
|
|
140
|
+
throw err;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
async clear() {
|
|
144
|
+
await promises_1.default.rm((0, config_1.credentialsFilePath)(), { force: true });
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
exports.FileTokenStore = FileTokenStore;
|
|
148
|
+
/**
|
|
149
|
+
* Platform-appropriate OS store first, file store always last. `save`
|
|
150
|
+
* picks the first available candidate and actually uses it; if that
|
|
151
|
+
* candidate's `save` throws (keychain present but locked, no Secret
|
|
152
|
+
* Service running, etc.) the caller falls back to the next one -- see
|
|
153
|
+
* `saveSession` in auth/session.ts, which is what prints "saved to <store
|
|
154
|
+
* name>" and is what tests/token-store.test.ts exercises.
|
|
155
|
+
*/
|
|
156
|
+
function candidateStores() {
|
|
157
|
+
const stores = [];
|
|
158
|
+
if (process.platform === "darwin")
|
|
159
|
+
stores.push(new MacKeychainStore());
|
|
160
|
+
if (process.platform === "linux")
|
|
161
|
+
stores.push(new LinuxSecretToolStore());
|
|
162
|
+
stores.push(new FileTokenStore());
|
|
163
|
+
return stores;
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=token-store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"token-store.js","sourceRoot":"","sources":["../../src/auth/token-store.ts"],"names":[],"mappings":";;;;;;AA2MA,0CAMC;AAjND,2DAA8C;AAC9C,gEAAkC;AAClC,0DAA6B;AAC7B,sCAAgD;AA6ChD,SAAS,YAAY,CAAC,GAAW,EAAE,IAAc,EAAE,KAAc;IAC/D,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,KAAK,GAAG,IAAA,6BAAQ,EAAC,GAAG,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,GAAG,IAAI,EAAE,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE;YAC9F,IAAI,GAAG;gBAAE,MAAM,CAAC,GAAG,CAAC,CAAC;;gBAChB,OAAO,CAAC,MAAM,CAAC,CAAC;QACvB,CAAC,CAAC,CAAC;QACH,IAAI,KAAK,KAAK,SAAS;YAAE,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;IACnD,CAAC,CAAC,CAAC;AACL,CAAC;AAED,KAAK,UAAU,aAAa,CAAC,GAAW;IACtC,IAAI,CAAC;QACH,MAAM,YAAY,CAAC,OAAO,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;QAC5E,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,MAAM,OAAO,GAAG,aAAa,CAAC;AAC9B,MAAM,OAAO,GAAG,SAAS,CAAC;AAE1B;;;;;;;GAOG;AACH,MAAM,gBAAgB;IACX,IAAI,GAAG,gBAAgB,CAAC;IAEjC,KAAK,CAAC,WAAW;QACf,OAAO,OAAO,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,MAAM,aAAa,CAAC,UAAU,CAAC,CAAC,CAAC;IAC5E,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,OAAsB;QAC/B,uEAAuE;QACvE,MAAM,YAAY,CAAC,UAAU,EAAE;YAC7B,sBAAsB;YACtB,IAAI;YACJ,OAAO;YACP,IAAI;YACJ,OAAO;YACP,IAAI;YACJ,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;YACvB,IAAI;SACL,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,IAAI;QACR,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC,UAAU,EAAE,CAAC,uBAAuB,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,CAAC,CAAC;YAC1G,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,CAAkB,CAAC;QACjD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,CAAC;YACH,MAAM,YAAY,CAAC,UAAU,EAAE,CAAC,yBAAyB,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC;QAC5F,CAAC;QAAC,MAAM,CAAC;YACP,qEAAqE;QACvE,CAAC;IACH,CAAC;CACF;AAED;;;;;;GAMG;AACH,MAAM,oBAAoB;IACf,IAAI,GAAG,kCAAkC,CAAC;IAEnD,KAAK,CAAC,WAAW;QACf,OAAO,OAAO,CAAC,QAAQ,KAAK,OAAO,IAAI,CAAC,MAAM,aAAa,CAAC,aAAa,CAAC,CAAC,CAAC;IAC9E,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,OAAsB;QAC/B,MAAM,YAAY,CAChB,aAAa,EACb,CAAC,OAAO,EAAE,6BAA6B,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,EAChF,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CACxB,CAAC;IACJ,CAAC;IAED,KAAK,CAAC,IAAI;QACR,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,YAAY,CAAC,aAAa,EAAE,CAAC,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC;YAClG,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;YAC3B,OAAO,OAAO,CAAC,CAAC,CAAE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAmB,CAAC,CAAC,CAAC,IAAI,CAAC;QACjE,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,CAAC;YACH,MAAM,YAAY,CAAC,aAAa,EAAE,CAAC,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC,CAAC;QACvF,CAAC;QAAC,MAAM,CAAC;YACP,kBAAkB;QACpB,CAAC;IACH,CAAC;CACF;AAED;;;;GAIG;AACH,MAAa,cAAc;IAChB,IAAI,GAAG,SAAS,IAAA,4BAAmB,GAAE,GAAG,CAAC;IAElD,KAAK,CAAC,WAAW;QACf,OAAO,IAAI,CAAC;IACd,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,OAAsB;QAC/B,MAAM,IAAI,GAAG,IAAA,4BAAmB,GAAE,CAAC;QACnC,MAAM,kBAAE,CAAC,KAAK,CAAC,mBAAI,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QACrE,MAAM,kBAAE,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAC5E,yEAAyE;QACzE,wEAAwE;QACxE,mCAAmC;QACnC,MAAM,kBAAE,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAC9B,CAAC;IAED,KAAK,CAAC,IAAI;QACR,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,kBAAE,CAAC,QAAQ,CAAC,IAAA,4BAAmB,GAAE,EAAE,MAAM,CAAC,CAAC;YAC9D,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAkB,CAAC;QAC3C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ;gBAAE,OAAO,IAAI,CAAC;YAClE,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;IAED,KAAK,CAAC,KAAK;QACT,MAAM,kBAAE,CAAC,EAAE,CAAC,IAAA,4BAAmB,GAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACtD,CAAC;CACF;AA9BD,wCA8BC;AAED;;;;;;;GAOG;AACH,SAAgB,eAAe;IAC7B,MAAM,MAAM,GAAiB,EAAE,CAAC;IAChC,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ;QAAE,MAAM,CAAC,IAAI,CAAC,IAAI,gBAAgB,EAAE,CAAC,CAAC;IACvE,IAAI,OAAO,CAAC,QAAQ,KAAK,OAAO;QAAE,MAAM,CAAC,IAAI,CAAC,IAAI,oBAAoB,EAAE,CAAC,CAAC;IAC1E,MAAM,CAAC,IAAI,CAAC,IAAI,cAAc,EAAE,CAAC,CAAC;IAClC,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.run = run;
|
|
4
|
+
const errors_1 = require("./errors");
|
|
5
|
+
const login_1 = require("./commands/login");
|
|
6
|
+
const diaries_1 = require("./commands/diaries");
|
|
7
|
+
const write_1 = require("./commands/write");
|
|
8
|
+
const read_1 = require("./commands/read");
|
|
9
|
+
const profiles_1 = require("./commands/profiles");
|
|
10
|
+
const shared_diary_1 = require("./commands/shared-diary");
|
|
11
|
+
const publish_1 = require("./commands/publish");
|
|
12
|
+
const whoami_1 = require("./commands/whoami");
|
|
13
|
+
const wiki_1 = require("./commands/wiki");
|
|
14
|
+
const output_1 = require("./lib/output");
|
|
15
|
+
const USAGE = `whatcha -- command-line client for what-are-you-do-ing
|
|
16
|
+
|
|
17
|
+
Usage:
|
|
18
|
+
whatcha login [--email <email>] [--password <password>] [--json]
|
|
19
|
+
whatcha login --key <personal-access-key> [--json]
|
|
20
|
+
whatcha login --token <refresh-token> [--json]
|
|
21
|
+
whatcha whoami [--json]
|
|
22
|
+
whatcha diaries [--json]
|
|
23
|
+
whatcha diary-new <name> [--with <@handle>]... [--timezone <tz>] [--description "..."] [--json]
|
|
24
|
+
whatcha invite <diary> <@handle> [--json]
|
|
25
|
+
whatcha publish <diary> [--off] [--json]
|
|
26
|
+
whatcha write <diary> --text "..." [--title "..."] [--tag <tag>]... [--time HH:MM] [--date YYYY-MM-DD] [--json]
|
|
27
|
+
whatcha read <diary> [--date YYYY-MM-DD] [--json]
|
|
28
|
+
whatcha profiles [--json]
|
|
29
|
+
whatcha switch <@handle> [--json]
|
|
30
|
+
whatcha switch --account [--json]
|
|
31
|
+
whatcha profile-add <@handle> --name <display name> [--avatar <file>] [--json]
|
|
32
|
+
whatcha profile-rm <@handle> [--json]
|
|
33
|
+
whatcha wiki list [--search <text>] [--group <group-id>] [--limit N] [--cursor <c>] [--json]
|
|
34
|
+
whatcha wiki read <page> [--group <group-id>] [--json]
|
|
35
|
+
whatcha wiki write <page> --text "..." [--image <file>]... [--cover <file>] [--replace] [--message "..."] [--group <group-id>] [--json]
|
|
36
|
+
whatcha wiki cover <page> <file> | --clear [--group <group-id>] [--json]
|
|
37
|
+
|
|
38
|
+
Every command accepts --json for machine-readable output.
|
|
39
|
+
For scripts and servers, log in with a personal access key (issue one in
|
|
40
|
+
Profile -> Connected apps and keys): --key, or WHATCHA_KEY. A key is used
|
|
41
|
+
as-is, never refreshed, and stops working the moment it is revoked
|
|
42
|
+
(error code KEY_REVOKED). Credentials for login can also come from
|
|
43
|
+
WHATCHA_EMAIL / WHATCHA_PASSWORD, or WHATCHA_TOKEN for a refresh token
|
|
44
|
+
(which may also hold a key).
|
|
45
|
+
`;
|
|
46
|
+
/**
|
|
47
|
+
* The whole CLI as one testable function: argv in, exit code out, nothing
|
|
48
|
+
* printed that isn't part of the documented contract. index.ts is the only
|
|
49
|
+
* thing that calls this against real process.argv/exit -- everything in
|
|
50
|
+
* tests/cli.test.ts calls it directly with a fake argv instead.
|
|
51
|
+
*/
|
|
52
|
+
async function run(argv) {
|
|
53
|
+
const [command, ...rest] = argv;
|
|
54
|
+
if (!command || command === "--help" || command === "-h") {
|
|
55
|
+
process.stdout.write(USAGE);
|
|
56
|
+
return command ? 0 : 1;
|
|
57
|
+
}
|
|
58
|
+
if (command === "--version") {
|
|
59
|
+
// require() rather than an import so this stays the one place that
|
|
60
|
+
// touches package.json -- no build-time JSON import wiring needed.
|
|
61
|
+
process.stdout.write(`${require("../package.json").version}\n`);
|
|
62
|
+
return 0;
|
|
63
|
+
}
|
|
64
|
+
// Only used to decide how to *format* a parse-time error below, before a
|
|
65
|
+
// command has had a chance to parse --json itself -- not a substitute for
|
|
66
|
+
// each command's own parseArgs, which is what actually validates it.
|
|
67
|
+
const wantsJson = rest.includes("--json");
|
|
68
|
+
try {
|
|
69
|
+
switch (command) {
|
|
70
|
+
case "login":
|
|
71
|
+
return (await (0, login_1.runLogin)((0, login_1.parseLoginArgs)(rest))).exitCode;
|
|
72
|
+
case "diaries":
|
|
73
|
+
return (await (0, diaries_1.runDiaries)((0, diaries_1.parseDiariesArgs)(rest))).exitCode;
|
|
74
|
+
// A diary written together, and putting it on the web (#1700, #1701).
|
|
75
|
+
case "diary-new":
|
|
76
|
+
return (await (0, shared_diary_1.runDiaryNew)((0, shared_diary_1.parseDiaryNewArgs)(rest))).exitCode;
|
|
77
|
+
case "invite":
|
|
78
|
+
return (await (0, shared_diary_1.runInvite)((0, shared_diary_1.parseInviteArgs)(rest))).exitCode;
|
|
79
|
+
case "publish":
|
|
80
|
+
return (await (0, publish_1.runPublish)((0, publish_1.parsePublishArgs)(rest))).exitCode;
|
|
81
|
+
case "write":
|
|
82
|
+
return (await (0, write_1.runWrite)((0, write_1.parseWriteArgs)(rest))).exitCode;
|
|
83
|
+
case "read":
|
|
84
|
+
return (await (0, read_1.runRead)((0, read_1.parseReadArgs)(rest))).exitCode;
|
|
85
|
+
case "whoami":
|
|
86
|
+
return (await (0, whoami_1.runWhoami)((0, whoami_1.parseWhoamiArgs)(rest))).exitCode;
|
|
87
|
+
// Experience Wiki (#1664). Public Square's pages, or a group's with
|
|
88
|
+
// --group; images and covers from local files (#1667).
|
|
89
|
+
case "wiki":
|
|
90
|
+
return (await (0, wiki_1.runWiki)((0, wiki_1.parseWikiArgs)(rest))).exitCode;
|
|
91
|
+
// Sub-accounts (#1538). After a switch every command above acts as
|
|
92
|
+
// the profile switched into -- the saved session simply is it.
|
|
93
|
+
case "profiles":
|
|
94
|
+
return (await (0, profiles_1.runProfiles)((0, profiles_1.parseProfilesArgs)(rest))).exitCode;
|
|
95
|
+
case "switch":
|
|
96
|
+
return (await (0, profiles_1.runSwitch)((0, profiles_1.parseSwitchArgs)(rest))).exitCode;
|
|
97
|
+
case "profile-add":
|
|
98
|
+
return (await (0, profiles_1.runAdd)((0, profiles_1.parseAddArgs)(rest))).exitCode;
|
|
99
|
+
case "profile-rm":
|
|
100
|
+
return (await (0, profiles_1.runRemove)((0, profiles_1.parseRemoveArgs)(rest))).exitCode;
|
|
101
|
+
default:
|
|
102
|
+
throw new errors_1.CliUsageError(`Unknown command "${command}". Run \`whatcha --help\` for usage.`);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
catch (err) {
|
|
106
|
+
return reportError(err, wantsJson);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
function reportError(err, wantsJson) {
|
|
110
|
+
if (err instanceof errors_1.CliUsageError) {
|
|
111
|
+
if (wantsJson)
|
|
112
|
+
(0, output_1.printJson)({ ok: false, error: { code: "USAGE", message: err.message } });
|
|
113
|
+
else
|
|
114
|
+
(0, output_1.printErrorLine)(err.message);
|
|
115
|
+
return 1;
|
|
116
|
+
}
|
|
117
|
+
if (err instanceof errors_1.ApiError) {
|
|
118
|
+
if (wantsJson)
|
|
119
|
+
(0, output_1.printJson)({ ok: false, error: { code: err.code, message: err.message } });
|
|
120
|
+
else
|
|
121
|
+
(0, output_1.printErrorLine)(`${err.code}: ${err.message}`);
|
|
122
|
+
return 1;
|
|
123
|
+
}
|
|
124
|
+
// Anything else is a bug in this CLI, not a user or API problem --
|
|
125
|
+
// surfaced in full (never swallowed), but still never as a raw uncaught
|
|
126
|
+
// exception stack trace to stdout in --json mode.
|
|
127
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
128
|
+
if (wantsJson)
|
|
129
|
+
(0, output_1.printJson)({ ok: false, error: { code: "INTERNAL", message } });
|
|
130
|
+
else
|
|
131
|
+
(0, output_1.printErrorLine)(`whatcha: internal error: ${message}`);
|
|
132
|
+
return 1;
|
|
133
|
+
}
|
|
134
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.parseDiariesArgs = parseDiariesArgs;
|
|
4
|
+
exports.runDiaries = runDiaries;
|
|
5
|
+
const node_util_1 = require("node:util");
|
|
6
|
+
const session_1 = require("../auth/session");
|
|
7
|
+
const config_1 = require("../config");
|
|
8
|
+
const errors_1 = require("../errors");
|
|
9
|
+
const diary_resolve_1 = require("../lib/diary-resolve");
|
|
10
|
+
const output_1 = require("../lib/output");
|
|
11
|
+
const publication_1 = require("../lib/publication");
|
|
12
|
+
function parseDiariesArgs(argv) {
|
|
13
|
+
let values;
|
|
14
|
+
try {
|
|
15
|
+
({ values } = (0, node_util_1.parseArgs)({
|
|
16
|
+
args: argv,
|
|
17
|
+
options: { json: { type: "boolean", default: false } },
|
|
18
|
+
allowPositionals: false,
|
|
19
|
+
}));
|
|
20
|
+
}
|
|
21
|
+
catch (err) {
|
|
22
|
+
throw new errors_1.CliUsageError(err.message);
|
|
23
|
+
}
|
|
24
|
+
return { json: values.json };
|
|
25
|
+
}
|
|
26
|
+
async function runDiaries(opts, deps = {}) {
|
|
27
|
+
const resolved = deps.client ? null : await (0, session_1.authenticatedClient)();
|
|
28
|
+
const client = deps.client ?? resolved.client;
|
|
29
|
+
const base = deps.apiBaseUrl ?? (resolved?.session.apiBaseUrl || (0, config_1.apiBaseUrl)());
|
|
30
|
+
const listed = await (0, diary_resolve_1.listAllDiaries)(client);
|
|
31
|
+
// #1701: whether each diary is published, and where it is read.
|
|
32
|
+
const published = await (0, publication_1.publicDiaryIds)(client, listed);
|
|
33
|
+
const diaries = listed.map((d) => {
|
|
34
|
+
const isPublic = published.has(d.id);
|
|
35
|
+
return { ...d, isPublic, publicUrl: isPublic ? (0, publication_1.publicDiaryUrl)(base, d.id) : null };
|
|
36
|
+
});
|
|
37
|
+
if (opts.json) {
|
|
38
|
+
(0, output_1.printJson)({ ok: true, diaries });
|
|
39
|
+
return { exitCode: 0 };
|
|
40
|
+
}
|
|
41
|
+
if (diaries.length === 0) {
|
|
42
|
+
(0, output_1.printLine)("No diaries.");
|
|
43
|
+
return { exitCode: 0 };
|
|
44
|
+
}
|
|
45
|
+
for (const d of diaries) {
|
|
46
|
+
const entries = d.entryCount === 1 ? "1 entry" : `${d.entryCount} entries`;
|
|
47
|
+
const pub = d.publicUrl ? ` public: ${d.publicUrl}` : "";
|
|
48
|
+
(0, output_1.printLine)(`${d.id} ${d.name} [${d.groupName}] ${entries} tz=${d.timezone}${pub}`);
|
|
49
|
+
}
|
|
50
|
+
return { exitCode: 0 };
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=diaries.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diaries.js","sourceRoot":"","sources":["../../src/commands/diaries.ts"],"names":[],"mappings":"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"}
|