@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,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":"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"}
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
@@ -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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"}