@doist/outline-cli 1.5.2 → 1.6.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 (67) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/commands/auth.js +32 -138
  3. package/dist/commands/auth.js.map +1 -1
  4. package/dist/commands/changelog.d.ts +1 -6
  5. package/dist/commands/changelog.js +8 -88
  6. package/dist/commands/changelog.js.map +1 -1
  7. package/dist/commands/document.js +3 -3
  8. package/dist/commands/document.js.map +1 -1
  9. package/dist/commands/search.js +16 -11
  10. package/dist/commands/search.js.map +1 -1
  11. package/dist/commands/update/index.d.ts +1 -1
  12. package/dist/commands/update/index.js +11 -14
  13. package/dist/commands/update/index.js.map +1 -1
  14. package/dist/index.js +12 -2
  15. package/dist/index.js.map +1 -1
  16. package/dist/lib/api.d.ts +5 -1
  17. package/dist/lib/api.js +9 -7
  18. package/dist/lib/api.js.map +1 -1
  19. package/dist/lib/auth-pages.d.ts +2 -0
  20. package/dist/lib/auth-pages.js +101 -0
  21. package/dist/lib/auth-pages.js.map +1 -0
  22. package/dist/lib/auth-provider.d.ts +10 -0
  23. package/dist/lib/auth-provider.js +198 -0
  24. package/dist/lib/auth-provider.js.map +1 -0
  25. package/dist/lib/auth.d.ts +15 -6
  26. package/dist/lib/auth.js +28 -42
  27. package/dist/lib/auth.js.map +1 -1
  28. package/dist/lib/config.d.ts +18 -0
  29. package/dist/lib/config.js +20 -0
  30. package/dist/lib/config.js.map +1 -0
  31. package/dist/lib/errors.d.ts +8 -0
  32. package/dist/lib/errors.js +9 -0
  33. package/dist/lib/errors.js.map +1 -0
  34. package/dist/lib/global-args.d.ts +5 -0
  35. package/dist/lib/global-args.js +17 -0
  36. package/dist/lib/global-args.js.map +1 -0
  37. package/dist/lib/markdown.d.ts +2 -1
  38. package/dist/lib/markdown.js +10 -5
  39. package/dist/lib/markdown.js.map +1 -1
  40. package/dist/lib/output.d.ts +9 -5
  41. package/dist/lib/output.js +29 -11
  42. package/dist/lib/output.js.map +1 -1
  43. package/dist/lib/skills/content.d.ts +1 -1
  44. package/dist/lib/skills/content.js +10 -3
  45. package/dist/lib/skills/content.js.map +1 -1
  46. package/dist/lib/spinner.d.ts +2 -13
  47. package/dist/lib/spinner.js +4 -55
  48. package/dist/lib/spinner.js.map +1 -1
  49. package/package.json +6 -6
  50. package/dist/commands/update/action.d.ts +0 -4
  51. package/dist/commands/update/action.js +0 -157
  52. package/dist/commands/update/action.js.map +0 -1
  53. package/dist/commands/update/switch.d.ts +0 -4
  54. package/dist/commands/update/switch.js +0 -29
  55. package/dist/commands/update/switch.js.map +0 -1
  56. package/dist/lib/oauth-server.d.ts +0 -14
  57. package/dist/lib/oauth-server.js +0 -203
  58. package/dist/lib/oauth-server.js.map +0 -1
  59. package/dist/lib/oauth.d.ts +0 -17
  60. package/dist/lib/oauth.js +0 -42
  61. package/dist/lib/oauth.js.map +0 -1
  62. package/dist/lib/pkce.d.ts +0 -3
  63. package/dist/lib/pkce.js +0 -16
  64. package/dist/lib/pkce.js.map +0 -1
  65. package/dist/lib/update-config.d.ts +0 -3
  66. package/dist/lib/update-config.js +0 -35
  67. package/dist/lib/update-config.js.map +0 -1
package/dist/lib/api.js CHANGED
@@ -25,16 +25,18 @@ const API_SPINNER_CONFIG = {
25
25
  /**
26
26
  * Core API request function without spinner wrapping.
27
27
  */
28
- async function rawApiRequest(path, body = {}) {
29
- const baseUrl = getBaseUrl();
30
- const token = getApiToken();
28
+ async function rawApiRequest(path, body = {}, overrides = {}) {
29
+ const [resolvedBaseUrl, resolvedToken] = await Promise.all([
30
+ overrides.baseUrl ? Promise.resolve(overrides.baseUrl.replace(/\/$/, '')) : getBaseUrl(),
31
+ overrides.token ? Promise.resolve(overrides.token) : getApiToken(),
32
+ ]);
31
33
  const res = await fetchWithRetry({
32
- url: `${baseUrl}/api/${path}`,
34
+ url: `${resolvedBaseUrl}/api/${path}`,
33
35
  options: {
34
36
  method: 'POST',
35
37
  headers: {
36
38
  'Content-Type': 'application/json',
37
- Authorization: `Bearer ${token}`,
39
+ Authorization: `Bearer ${resolvedToken}`,
38
40
  },
39
41
  body: JSON.stringify(body),
40
42
  },
@@ -56,11 +58,11 @@ async function rawApiRequest(path, body = {}) {
56
58
  * Public API request function that wraps rawApiRequest with automatic spinners.
57
59
  * Spinner messages are configured per API path in API_SPINNER_CONFIG.
58
60
  */
59
- export async function apiRequest(path, body = {}) {
61
+ export async function apiRequest(path, body = {}, overrides = {}) {
60
62
  const spinnerConfig = API_SPINNER_CONFIG[path] ?? {
61
63
  text: 'Loading...',
62
64
  color: 'blue',
63
65
  };
64
- return withSpinner(spinnerConfig, () => rawApiRequest(path, body));
66
+ return withSpinner(spinnerConfig, () => rawApiRequest(path, body, overrides));
65
67
  }
66
68
  //# sourceMappingURL=api.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/lib/api.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/lib/api.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function renderSuccess(): string;
2
+ export declare function renderError(message: string): string;
@@ -0,0 +1,101 @@
1
+ function escapeHtml(text) {
2
+ return text
3
+ .replaceAll('&', '&')
4
+ .replaceAll('<', '&lt;')
5
+ .replaceAll('>', '&gt;')
6
+ .replaceAll('"', '&quot;')
7
+ .replaceAll("'", '&#39;');
8
+ }
9
+ function renderPage(title, subtitle, body) {
10
+ return `<!doctype html>
11
+ <html lang="en">
12
+ <head>
13
+ <meta charset="utf-8">
14
+ <meta name="viewport" content="width=device-width, initial-scale=1">
15
+ <title>${escapeHtml(title)} - Outline CLI</title>
16
+ <style>
17
+ :root {
18
+ --bg: #f5f7fb;
19
+ --surface: #ffffff;
20
+ --border: #e6e9f0;
21
+ --text: #1e2430;
22
+ --muted: #586178;
23
+ --ok: #15803d;
24
+ --ok-soft: #dcfce7;
25
+ --err: #b91c1c;
26
+ --err-soft: #fee2e2;
27
+ --radius: 14px;
28
+ }
29
+ * { box-sizing: border-box; }
30
+ body {
31
+ margin: 0;
32
+ min-height: 100vh;
33
+ display: grid;
34
+ place-items: center;
35
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
36
+ background: radial-gradient(1200px 500px at 50% -10%, #dbeafe 0%, var(--bg) 60%);
37
+ color: var(--text);
38
+ line-height: 1.5;
39
+ padding: 20px;
40
+ }
41
+ .card {
42
+ width: min(560px, 100%);
43
+ background: var(--surface);
44
+ border: 1px solid var(--border);
45
+ border-radius: var(--radius);
46
+ padding: 24px;
47
+ box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
48
+ }
49
+ h1 {
50
+ margin: 0 0 8px;
51
+ font-size: 24px;
52
+ letter-spacing: -0.01em;
53
+ }
54
+ .subtitle {
55
+ margin: 0 0 16px;
56
+ color: var(--muted);
57
+ font-size: 15px;
58
+ }
59
+ .message {
60
+ border-radius: 12px;
61
+ padding: 14px 16px;
62
+ font-size: 14px;
63
+ }
64
+ .success {
65
+ background: var(--ok-soft);
66
+ color: #14532d;
67
+ }
68
+ .error {
69
+ background: var(--err-soft);
70
+ color: #7f1d1d;
71
+ }
72
+ .hint {
73
+ margin-top: 14px;
74
+ color: var(--muted);
75
+ font-size: 13px;
76
+ }
77
+ code {
78
+ font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
79
+ background: #eef2ff;
80
+ border-radius: 6px;
81
+ padding: 2px 6px;
82
+ }
83
+ </style>
84
+ </head>
85
+ <body>
86
+ <main class="card">
87
+ <h1>${escapeHtml(title)}</h1>
88
+ <p class="subtitle">${escapeHtml(subtitle)}</p>
89
+ ${body}
90
+ <p class="hint">Return to your terminal and continue with <code>ol</code> commands.</p>
91
+ </main>
92
+ </body>
93
+ </html>`;
94
+ }
95
+ export function renderSuccess() {
96
+ return renderPage('Login complete', 'Outline CLI is now authenticated.', '<div class="message success">You can close this tab now.</div>');
97
+ }
98
+ export function renderError(message) {
99
+ return renderPage('Authentication failed', 'Outline CLI could not finish OAuth login.', `<div class="message error">${escapeHtml(message)}</div>`);
100
+ }
101
+ //# sourceMappingURL=auth-pages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-pages.js","sourceRoot":"","sources":["../../src/lib/auth-pages.ts"],"names":[],"mappings":"AAAA,SAAS,UAAU,CAAC,IAAY;IAC5B,OAAO,IAAI;SACN,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC;SACxB,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC;SACvB,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC;SACvB,UAAU,CAAC,GAAG,EAAE,QAAQ,CAAC;SACzB,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;AACjC,CAAC;AAED,SAAS,UAAU,CAAC,KAAa,EAAE,QAAgB,EAAE,IAAY;IAC7D,OAAO;;;;;WAKA,UAAU,CAAC,KAAK,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;UAwElB,UAAU,CAAC,KAAK,CAAC;0BACD,UAAU,CAAC,QAAQ,CAAC;MACxC,IAAI;;;;QAIF,CAAA;AACR,CAAC;AAED,MAAM,UAAU,aAAa;IACzB,OAAO,UAAU,CACb,gBAAgB,EAChB,mCAAmC,EACnC,gEAAgE,CACnE,CAAA;AACL,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,OAAe;IACvC,OAAO,UAAU,CACb,uBAAuB,EACvB,2CAA2C,EAC3C,8BAA8B,UAAU,CAAC,OAAO,CAAC,QAAQ,CAC5D,CAAA;AACL,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { type AuthAccount, type AuthProvider, type TokenStore } from '@doist/cli-core/auth';
2
+ export type OutlineAccount = AuthAccount & {
3
+ id: string;
4
+ label: string;
5
+ baseUrl: string;
6
+ oauthClientId: string;
7
+ teamName?: string;
8
+ };
9
+ export declare function createOutlineAuthProvider(): AuthProvider<OutlineAccount>;
10
+ export declare function createOutlineTokenStore(): TokenStore<OutlineAccount>;
@@ -0,0 +1,198 @@
1
+ import { createInterface } from 'node:readline/promises';
2
+ import { deriveChallenge, generateVerifier, } from '@doist/cli-core/auth';
3
+ import { fetchWithRetry } from '../transport/fetch-with-retry.js';
4
+ import { apiRequest } from './api.js';
5
+ import { clearConfig, getBaseUrl, getOAuthClientId } from './auth.js';
6
+ import { getConfig, updateConfig } from './config.js';
7
+ import { CliError } from './errors.js';
8
+ const DEFAULT_BASE_URL = 'https://app.getoutline.com';
9
+ function asHandshake(value) {
10
+ return value;
11
+ }
12
+ function stringFlag(flags, key) {
13
+ const value = flags[key];
14
+ return typeof value === 'string' && value.trim() ? value.trim() : undefined;
15
+ }
16
+ async function prompt(question) {
17
+ // Output to stderr so `--json` / `--ndjson` envelopes on stdout stay clean.
18
+ const rl = createInterface({ input: process.stdin, output: process.stderr });
19
+ try {
20
+ return (await rl.question(question)).trim();
21
+ }
22
+ finally {
23
+ rl.close();
24
+ }
25
+ }
26
+ async function resolveBaseUrl(flags) {
27
+ const fromFlag = stringFlag(flags, 'baseUrl');
28
+ if (fromFlag)
29
+ return fromFlag.replace(/\/$/, '');
30
+ const fromEnv = process.env.OUTLINE_URL?.trim();
31
+ if (fromEnv)
32
+ return fromEnv.replace(/\/$/, '');
33
+ const configured = await getBaseUrl();
34
+ const answered = await prompt(`Base URL (default: ${configured}): `);
35
+ return (answered || configured).replace(/\/$/, '');
36
+ }
37
+ async function resolveClientId(flags) {
38
+ const fromFlag = stringFlag(flags, 'clientId');
39
+ if (fromFlag)
40
+ return fromFlag;
41
+ const existing = await getOAuthClientId();
42
+ if (existing)
43
+ return existing;
44
+ const answered = await prompt('OAuth Client ID: ');
45
+ if (!answered) {
46
+ throw new Error('OAuth client ID is required. Create a public OAuth app in Outline settings, then pass --client-id <id> or set OUTLINE_OAUTH_CLIENT_ID.');
47
+ }
48
+ return answered;
49
+ }
50
+ export function createOutlineAuthProvider() {
51
+ return {
52
+ async authorize({ redirectUri, state, flags }) {
53
+ const baseUrl = await resolveBaseUrl(flags);
54
+ const clientId = await resolveClientId(flags);
55
+ const codeVerifier = generateVerifier();
56
+ const codeChallenge = deriveChallenge(codeVerifier);
57
+ const url = new URL(`${baseUrl}/oauth/authorize`);
58
+ url.searchParams.set('client_id', clientId);
59
+ url.searchParams.set('response_type', 'code');
60
+ url.searchParams.set('code_challenge', codeChallenge);
61
+ url.searchParams.set('code_challenge_method', 'S256');
62
+ url.searchParams.set('redirect_uri', redirectUri);
63
+ url.searchParams.set('state', state);
64
+ const handshake = { baseUrl, clientId, codeVerifier };
65
+ return { authorizeUrl: url.toString(), handshake };
66
+ },
67
+ async exchangeCode({ code, redirectUri, handshake }) {
68
+ const hs = asHandshake(handshake);
69
+ if (!hs.codeVerifier) {
70
+ throw new Error('Missing PKCE code verifier from authorize step.');
71
+ }
72
+ const params = new URLSearchParams({
73
+ grant_type: 'authorization_code',
74
+ client_id: hs.clientId,
75
+ redirect_uri: redirectUri,
76
+ code_verifier: hs.codeVerifier,
77
+ code,
78
+ });
79
+ const res = await fetchWithRetry({
80
+ url: `${hs.baseUrl}/oauth/token`,
81
+ options: {
82
+ method: 'POST',
83
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
84
+ body: params.toString(),
85
+ },
86
+ });
87
+ const json = (await res.json().catch(() => ({})));
88
+ if (!res.ok) {
89
+ const message = json.error_description || json.message || json.error || res.statusText;
90
+ throw new Error(`OAuth token exchange failed: ${message}`);
91
+ }
92
+ if (!json.access_token) {
93
+ throw new Error('OAuth token exchange did not return an access token.');
94
+ }
95
+ return { accessToken: json.access_token };
96
+ },
97
+ async validateToken({ token, handshake }) {
98
+ const hs = asHandshake(handshake);
99
+ const { data } = await apiRequest('auth.info', {}, {
100
+ token,
101
+ baseUrl: hs.baseUrl,
102
+ });
103
+ return {
104
+ id: data.user.id,
105
+ label: data.user.name,
106
+ baseUrl: hs.baseUrl,
107
+ oauthClientId: hs.clientId,
108
+ teamName: data.team.name,
109
+ };
110
+ },
111
+ };
112
+ }
113
+ export function createOutlineTokenStore() {
114
+ /**
115
+ * Derive a snapshot from an already-loaded config. Pure, so ref-aware
116
+ * callers can validate without a second config read.
117
+ */
118
+ function deriveSnapshot(config) {
119
+ if (!config.api_token)
120
+ return null;
121
+ const id = config.auth_user_id;
122
+ const label = config.auth_user_name;
123
+ if (!id || !label) {
124
+ // Stored token predates this adapter (env var, pre-upgrade
125
+ // config). No persisted identity to round-trip.
126
+ return null;
127
+ }
128
+ return {
129
+ token: config.api_token,
130
+ account: {
131
+ id,
132
+ label,
133
+ baseUrl: config.base_url ?? DEFAULT_BASE_URL,
134
+ oauthClientId: config.oauth_client_id ?? '',
135
+ teamName: config.auth_team_name,
136
+ },
137
+ };
138
+ }
139
+ /**
140
+ * Match the stored account against `--user <ref>`. Outline accounts use
141
+ * UUID ids and a display name — id matches are case-sensitive (UUIDs
142
+ * are canonical), label matches are case-insensitive so users can pass
143
+ * the name they see in `auth status` regardless of casing.
144
+ */
145
+ function matchesRef(account, ref) {
146
+ if (account.id === ref)
147
+ return true;
148
+ return account.label.toLowerCase() === ref.toLowerCase();
149
+ }
150
+ function refMismatch(ref) {
151
+ return new CliError('ACCOUNT_NOT_FOUND', `No stored account matches "${ref}".`);
152
+ }
153
+ return {
154
+ async active(ref) {
155
+ const snapshot = deriveSnapshot(await getConfig());
156
+ if (ref === undefined)
157
+ return snapshot;
158
+ if (!snapshot || !matchesRef(snapshot.account, ref))
159
+ throw refMismatch(ref);
160
+ return snapshot;
161
+ },
162
+ async set(account, token) {
163
+ await updateConfig({
164
+ api_token: token,
165
+ base_url: account.baseUrl,
166
+ oauth_client_id: account.oauthClientId,
167
+ auth_user_id: account.id,
168
+ auth_user_name: account.label,
169
+ auth_team_name: account.teamName,
170
+ });
171
+ },
172
+ async clear(ref) {
173
+ // With `ref`, validate before touching storage so a mismatch is
174
+ // an `ACCOUNT_NOT_FOUND` error rather than a silent success —
175
+ // `attachLogoutCommand` treats any non-throwing `clear()` as
176
+ // success. Load the config once and hand it to `clearConfig`
177
+ // so ref-based logout stays at one read + one write.
178
+ const config = await getConfig();
179
+ if (ref !== undefined) {
180
+ const snapshot = deriveSnapshot(config);
181
+ if (!snapshot || !matchesRef(snapshot.account, ref))
182
+ throw refMismatch(ref);
183
+ }
184
+ await clearConfig(config);
185
+ },
186
+ async list() {
187
+ const snapshot = deriveSnapshot(await getConfig());
188
+ return snapshot ? [{ account: snapshot.account, isDefault: true }] : [];
189
+ },
190
+ async setDefault(ref) {
191
+ const snapshot = deriveSnapshot(await getConfig());
192
+ if (!snapshot || !matchesRef(snapshot.account, ref))
193
+ throw refMismatch(ref);
194
+ // Single-user store — already the default once `ref` matches.
195
+ },
196
+ };
197
+ }
198
+ //# sourceMappingURL=auth-provider.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth-provider.js","sourceRoot":"","sources":["../../src/lib/auth-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAA;AACxD,OAAO,EAIH,eAAe,EACf,gBAAgB,GAEnB,MAAM,sBAAsB,CAAA;AAC7B,OAAO,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAA;AACjE,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;AACrC,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAA;AACrE,OAAO,EAAe,SAAS,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAEtC,MAAM,gBAAgB,GAAG,4BAA4B,CAAA;AAqBrD,SAAS,WAAW,CAAC,KAA8B;IAC/C,OAAO,KAAyB,CAAA;AACpC,CAAC;AAED,SAAS,UAAU,CAAC,KAA8B,EAAE,GAAW;IAC3D,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAA;IACxB,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAA;AAC/E,CAAC;AAED,KAAK,UAAU,MAAM,CAAC,QAAgB;IAClC,4EAA4E;IAC5E,MAAM,EAAE,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAA;IAC5E,IAAI,CAAC;QACD,OAAO,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,EAAE,CAAA;IAC/C,CAAC;YAAS,CAAC;QACP,EAAE,CAAC,KAAK,EAAE,CAAA;IACd,CAAC;AACL,CAAC;AAED,KAAK,UAAU,cAAc,CAAC,KAA8B;IACxD,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,EAAE,SAAS,CAAC,CAAA;IAC7C,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;IAChD,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,EAAE,CAAA;IAC/C,IAAI,OAAO;QAAE,OAAO,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;IAC9C,MAAM,UAAU,GAAG,MAAM,UAAU,EAAE,CAAA;IACrC,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,sBAAsB,UAAU,KAAK,CAAC,CAAA;IACpE,OAAO,CAAC,QAAQ,IAAI,UAAU,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;AACtD,CAAC;AAED,KAAK,UAAU,eAAe,CAAC,KAA8B;IACzD,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,EAAE,UAAU,CAAC,CAAA;IAC9C,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAA;IAC7B,MAAM,QAAQ,GAAG,MAAM,gBAAgB,EAAE,CAAA;IACzC,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAA;IAC7B,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,mBAAmB,CAAC,CAAA;IAClD,IAAI,CAAC,QAAQ,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACX,wIAAwI,CAC3I,CAAA;IACL,CAAC;IACD,OAAO,QAAQ,CAAA;AACnB,CAAC;AAED,MAAM,UAAU,yBAAyB;IACrC,OAAO;QACH,KAAK,CAAC,SAAS,CAAC,EAAE,WAAW,EAAE,KAAK,EAAE,KAAK,EAAE;YACzC,MAAM,OAAO,GAAG,MAAM,cAAc,CAAC,KAAK,CAAC,CAAA;YAC3C,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC,KAAK,CAAC,CAAA;YAC7C,MAAM,YAAY,GAAG,gBAAgB,EAAE,CAAA;YACvC,MAAM,aAAa,GAAG,eAAe,CAAC,YAAY,CAAC,CAAA;YAEnD,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,OAAO,kBAAkB,CAAC,CAAA;YACjD,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAA;YAC3C,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,eAAe,EAAE,MAAM,CAAC,CAAA;YAC7C,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,gBAAgB,EAAE,aAAa,CAAC,CAAA;YACrD,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,uBAAuB,EAAE,MAAM,CAAC,CAAA;YACrD,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,cAAc,EAAE,WAAW,CAAC,CAAA;YACjD,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;YAEpC,MAAM,SAAS,GAAqB,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAA;YACvE,OAAO,EAAE,YAAY,EAAE,GAAG,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,CAAA;QACtD,CAAC;QAED,KAAK,CAAC,YAAY,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE;YAC/C,MAAM,EAAE,GAAG,WAAW,CAAC,SAAS,CAAC,CAAA;YACjC,IAAI,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC;gBACnB,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAA;YACtE,CAAC;YAED,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC;gBAC/B,UAAU,EAAE,oBAAoB;gBAChC,SAAS,EAAE,EAAE,CAAC,QAAQ;gBACtB,YAAY,EAAE,WAAW;gBACzB,aAAa,EAAE,EAAE,CAAC,YAAY;gBAC9B,IAAI;aACP,CAAC,CAAA;YAEF,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC;gBAC7B,GAAG,EAAE,GAAG,EAAE,CAAC,OAAO,cAAc;gBAChC,OAAO,EAAE;oBACL,MAAM,EAAE,MAAM;oBACd,OAAO,EAAE,EAAE,cAAc,EAAE,mCAAmC,EAAE;oBAChE,IAAI,EAAE,MAAM,CAAC,QAAQ,EAAE;iBAC1B;aACJ,CAAC,CAAA;YAEF,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAK/C,CAAA;YAED,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACV,MAAM,OAAO,GACT,IAAI,CAAC,iBAAiB,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,KAAK,IAAI,GAAG,CAAC,UAAU,CAAA;gBAC1E,MAAM,IAAI,KAAK,CAAC,gCAAgC,OAAO,EAAE,CAAC,CAAA;YAC9D,CAAC;YAED,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;gBACrB,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAA;YAC3E,CAAC;YAED,OAAO,EAAE,WAAW,EAAE,IAAI,CAAC,YAAY,EAAE,CAAA;QAC7C,CAAC;QAED,KAAK,CAAC,aAAa,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE;YACpC,MAAM,EAAE,GAAG,WAAW,CAAC,SAAS,CAAC,CAAA;YACjC,MAAM,EAAE,IAAI,EAAE,GAAG,MAAM,UAAU,CAC7B,WAAW,EACX,EAAE,EACF;gBACI,KAAK;gBACL,OAAO,EAAE,EAAE,CAAC,OAAO;aACtB,CACJ,CAAA;YACD,OAAO;gBACH,EAAE,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE;gBAChB,KAAK,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI;gBACrB,OAAO,EAAE,EAAE,CAAC,OAAO;gBACnB,aAAa,EAAE,EAAE,CAAC,QAAQ;gBAC1B,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI;aAC3B,CAAA;QACL,CAAC;KACJ,CAAA;AACL,CAAC;AAED,MAAM,UAAU,uBAAuB;IACnC;;;OAGG;IACH,SAAS,cAAc,CACnB,MAAuB;QAEvB,IAAI,CAAC,MAAM,CAAC,SAAS;YAAE,OAAO,IAAI,CAAA;QAClC,MAAM,EAAE,GAAG,MAAM,CAAC,YAAY,CAAA;QAC9B,MAAM,KAAK,GAAG,MAAM,CAAC,cAAc,CAAA;QACnC,IAAI,CAAC,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC;YAChB,2DAA2D;YAC3D,gDAAgD;YAChD,OAAO,IAAI,CAAA;QACf,CAAC;QACD,OAAO;YACH,KAAK,EAAE,MAAM,CAAC,SAAS;YACvB,OAAO,EAAE;gBACL,EAAE;gBACF,KAAK;gBACL,OAAO,EAAE,MAAM,CAAC,QAAQ,IAAI,gBAAgB;gBAC5C,aAAa,EAAE,MAAM,CAAC,eAAe,IAAI,EAAE;gBAC3C,QAAQ,EAAE,MAAM,CAAC,cAAc;aAClC;SACJ,CAAA;IACL,CAAC;IAED;;;;;OAKG;IACH,SAAS,UAAU,CAAC,OAAuB,EAAE,GAAe;QACxD,IAAI,OAAO,CAAC,EAAE,KAAK,GAAG;YAAE,OAAO,IAAI,CAAA;QACnC,OAAO,OAAO,CAAC,KAAK,CAAC,WAAW,EAAE,KAAK,GAAG,CAAC,WAAW,EAAE,CAAA;IAC5D,CAAC;IAED,SAAS,WAAW,CAAC,GAAe;QAChC,OAAO,IAAI,QAAQ,CAAC,mBAAmB,EAAE,8BAA8B,GAAG,IAAI,CAAC,CAAA;IACnF,CAAC;IAED,OAAO;QACH,KAAK,CAAC,MAAM,CAAC,GAAgB;YACzB,MAAM,QAAQ,GAAG,cAAc,CAAC,MAAM,SAAS,EAAE,CAAC,CAAA;YAClD,IAAI,GAAG,KAAK,SAAS;gBAAE,OAAO,QAAQ,CAAA;YACtC,IAAI,CAAC,QAAQ,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC;gBAAE,MAAM,WAAW,CAAC,GAAG,CAAC,CAAA;YAC3E,OAAO,QAAQ,CAAA;QACnB,CAAC;QACD,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK;YACpB,MAAM,YAAY,CAAC;gBACf,SAAS,EAAE,KAAK;gBAChB,QAAQ,EAAE,OAAO,CAAC,OAAO;gBACzB,eAAe,EAAE,OAAO,CAAC,aAAa;gBACtC,YAAY,EAAE,OAAO,CAAC,EAAE;gBACxB,cAAc,EAAE,OAAO,CAAC,KAAK;gBAC7B,cAAc,EAAE,OAAO,CAAC,QAAQ;aACnC,CAAC,CAAA;QACN,CAAC;QACD,KAAK,CAAC,KAAK,CAAC,GAAgB;YACxB,gEAAgE;YAChE,8DAA8D;YAC9D,6DAA6D;YAC7D,6DAA6D;YAC7D,qDAAqD;YACrD,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAA;YAChC,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;gBACpB,MAAM,QAAQ,GAAG,cAAc,CAAC,MAAM,CAAC,CAAA;gBACvC,IAAI,CAAC,QAAQ,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC;oBAAE,MAAM,WAAW,CAAC,GAAG,CAAC,CAAA;YAC/E,CAAC;YACD,MAAM,WAAW,CAAC,MAAM,CAAC,CAAA;QAC7B,CAAC;QACD,KAAK,CAAC,IAAI;YACN,MAAM,QAAQ,GAAG,cAAc,CAAC,MAAM,SAAS,EAAE,CAAC,CAAA;YAClD,OAAO,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;QAC3E,CAAC;QACD,KAAK,CAAC,UAAU,CAAC,GAAe;YAC5B,MAAM,QAAQ,GAAG,cAAc,CAAC,MAAM,SAAS,EAAE,CAAC,CAAA;YAClD,IAAI,CAAC,QAAQ,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC;gBAAE,MAAM,WAAW,CAAC,GAAG,CAAC,CAAA;YAC3E,8DAA8D;QAClE,CAAC;KACJ,CAAA;AACL,CAAC"}
@@ -1,6 +1,15 @@
1
- export declare function getApiToken(): string;
2
- export declare function getBaseUrl(): string;
3
- export declare function getOAuthClientId(): string | undefined;
4
- export declare function getTokenSource(): 'env' | 'config' | null;
5
- export declare function saveConfig(token: string, baseUrl?: string, oauthClientId?: string): void;
6
- export declare function clearConfig(): void;
1
+ import { type Config } from './config.js';
2
+ export declare function getApiToken(): Promise<string>;
3
+ export declare function getBaseUrl(): Promise<string>;
4
+ export declare function getOAuthClientId(): Promise<string | undefined>;
5
+ export declare function getTokenSource(): Promise<'env' | 'config' | null>;
6
+ /**
7
+ * Clear the auth-related keys without deleting the file. The config is now
8
+ * shared with non-auth settings (notably `update_channel`); a blanket unlink
9
+ * would silently reset the user's update-channel preference too.
10
+ *
11
+ * Pass `existing` to skip the read when the caller has already loaded the
12
+ * config (e.g. ref-validated logout) — keeps that flow at one read + one
13
+ * write instead of two reads.
14
+ */
15
+ export declare function clearConfig(existing?: Partial<Config>): Promise<void>;
package/dist/lib/auth.js CHANGED
@@ -1,70 +1,56 @@
1
- import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'node:fs';
2
- import { homedir } from 'node:os';
3
- import { join } from 'node:path';
4
- const CONFIG_DIR = join(homedir(), '.config', 'outline-cli');
5
- const CONFIG_PATH = join(CONFIG_DIR, 'config.json');
1
+ import { getConfig, setConfig } from './config.js';
6
2
  const DEFAULT_BASE_URL = 'https://app.getoutline.com';
7
- function readConfig() {
8
- if (!existsSync(CONFIG_PATH))
9
- return {};
10
- try {
11
- return JSON.parse(readFileSync(CONFIG_PATH, 'utf-8'));
12
- }
13
- catch {
14
- return {};
15
- }
16
- }
17
- export function getApiToken() {
3
+ export async function getApiToken() {
18
4
  const envToken = process.env.OUTLINE_API_TOKEN;
19
5
  if (envToken)
20
6
  return envToken;
21
- const config = readConfig();
7
+ const config = await getConfig();
22
8
  if (config.api_token)
23
9
  return config.api_token;
24
10
  throw new Error('No API token found. Set OUTLINE_API_TOKEN env var or run: ol auth login');
25
11
  }
26
- export function getBaseUrl() {
12
+ export async function getBaseUrl() {
27
13
  const envUrl = process.env.OUTLINE_URL;
28
14
  if (envUrl)
29
15
  return envUrl.replace(/\/$/, '');
30
- const config = readConfig();
16
+ const config = await getConfig();
31
17
  if (config.base_url)
32
18
  return config.base_url.replace(/\/$/, '');
33
19
  return DEFAULT_BASE_URL;
34
20
  }
35
- export function getOAuthClientId() {
21
+ export async function getOAuthClientId() {
36
22
  const envClientId = process.env.OUTLINE_OAUTH_CLIENT_ID;
37
23
  if (envClientId)
38
24
  return envClientId;
39
- const config = readConfig();
25
+ const config = await getConfig();
40
26
  return config.oauth_client_id;
41
27
  }
42
- export function getTokenSource() {
28
+ export async function getTokenSource() {
43
29
  if (process.env.OUTLINE_API_TOKEN)
44
30
  return 'env';
45
- const config = readConfig();
31
+ const config = await getConfig();
46
32
  if (config.api_token)
47
33
  return 'config';
48
34
  return null;
49
35
  }
50
- export function saveConfig(token, baseUrl, oauthClientId) {
51
- mkdirSync(CONFIG_DIR, { recursive: true });
52
- const existing = readConfig();
53
- const config = {
54
- ...existing,
55
- api_token: token,
56
- };
57
- if (baseUrl) {
58
- config.base_url = baseUrl.replace(/\/$/, '');
59
- }
60
- if (oauthClientId) {
61
- config.oauth_client_id = oauthClientId;
62
- }
63
- writeFileSync(CONFIG_PATH, `${JSON.stringify(config, null, 2)}\n`);
64
- }
65
- export function clearConfig() {
66
- if (existsSync(CONFIG_PATH)) {
67
- rmSync(CONFIG_PATH);
68
- }
36
+ /**
37
+ * Clear the auth-related keys without deleting the file. The config is now
38
+ * shared with non-auth settings (notably `update_channel`); a blanket unlink
39
+ * would silently reset the user's update-channel preference too.
40
+ *
41
+ * Pass `existing` to skip the read when the caller has already loaded the
42
+ * config (e.g. ref-validated logout) — keeps that flow at one read + one
43
+ * write instead of two reads.
44
+ */
45
+ export async function clearConfig(existing) {
46
+ const config = existing ?? (await getConfig());
47
+ const { api_token, base_url, oauth_client_id, auth_user_id, auth_user_name, auth_team_name, ...rest } = config;
48
+ void api_token;
49
+ void base_url;
50
+ void oauth_client_id;
51
+ void auth_user_id;
52
+ void auth_user_name;
53
+ void auth_team_name;
54
+ await setConfig(rest);
69
55
  }
70
56
  //# sourceMappingURL=auth.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AACpF,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAA;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAQhC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,aAAa,CAAC,CAAA;AAC5D,MAAM,WAAW,GAAG,IAAI,CAAC,UAAU,EAAE,aAAa,CAAC,CAAA;AACnD,MAAM,gBAAgB,GAAG,4BAA4B,CAAA;AAErD,SAAS,UAAU;IACf,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC;QAAE,OAAO,EAAE,CAAA;IACvC,IAAI,CAAC;QACD,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC,CAAA;IACzD,CAAC;IAAC,MAAM,CAAC;QACL,OAAO,EAAE,CAAA;IACb,CAAC;AACL,CAAC;AAED,MAAM,UAAU,WAAW;IACvB,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAA;IAC9C,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAA;IAE7B,MAAM,MAAM,GAAG,UAAU,EAAE,CAAA;IAC3B,IAAI,MAAM,CAAC,SAAS;QAAE,OAAO,MAAM,CAAC,SAAS,CAAA;IAE7C,MAAM,IAAI,KAAK,CAAC,yEAAyE,CAAC,CAAA;AAC9F,CAAC;AAED,MAAM,UAAU,UAAU;IACtB,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,CAAA;IACtC,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;IAE5C,MAAM,MAAM,GAAG,UAAU,EAAE,CAAA;IAC3B,IAAI,MAAM,CAAC,QAAQ;QAAE,OAAO,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;IAE9D,OAAO,gBAAgB,CAAA;AAC3B,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC5B,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAA;IACvD,IAAI,WAAW;QAAE,OAAO,WAAW,CAAA;IAEnC,MAAM,MAAM,GAAG,UAAU,EAAE,CAAA;IAC3B,OAAO,MAAM,CAAC,eAAe,CAAA;AACjC,CAAC;AAED,MAAM,UAAU,cAAc;IAC1B,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB;QAAE,OAAO,KAAK,CAAA;IAC/C,MAAM,MAAM,GAAG,UAAU,EAAE,CAAA;IAC3B,IAAI,MAAM,CAAC,SAAS;QAAE,OAAO,QAAQ,CAAA;IACrC,OAAO,IAAI,CAAA;AACf,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAa,EAAE,OAAgB,EAAE,aAAsB;IAC9E,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IAC1C,MAAM,QAAQ,GAAG,UAAU,EAAE,CAAA;IAC7B,MAAM,MAAM,GAAW;QACnB,GAAG,QAAQ;QACX,SAAS,EAAE,KAAK;KACnB,CAAA;IACD,IAAI,OAAO,EAAE,CAAC;QACV,MAAM,CAAC,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;IAChD,CAAC;IACD,IAAI,aAAa,EAAE,CAAC;QAChB,MAAM,CAAC,eAAe,GAAG,aAAa,CAAA;IAC1C,CAAC;IACD,aAAa,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAA;AACtE,CAAC;AAED,MAAM,UAAU,WAAW;IACvB,IAAI,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC1B,MAAM,CAAC,WAAW,CAAC,CAAA;IACvB,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,SAAS,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAE/D,MAAM,gBAAgB,GAAG,4BAA4B,CAAA;AAErD,MAAM,CAAC,KAAK,UAAU,WAAW;IAC7B,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAA;IAC9C,IAAI,QAAQ;QAAE,OAAO,QAAQ,CAAA;IAE7B,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAA;IAChC,IAAI,MAAM,CAAC,SAAS;QAAE,OAAO,MAAM,CAAC,SAAS,CAAA;IAE7C,MAAM,IAAI,KAAK,CAAC,yEAAyE,CAAC,CAAA;AAC9F,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU;IAC5B,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,WAAW,CAAA;IACtC,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;IAE5C,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAA;IAChC,IAAI,MAAM,CAAC,QAAQ;QAAE,OAAO,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;IAE9D,OAAO,gBAAgB,CAAA;AAC3B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB;IAClC,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAA;IACvD,IAAI,WAAW;QAAE,OAAO,WAAW,CAAA;IAEnC,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAA;IAChC,OAAO,MAAM,CAAC,eAAe,CAAA;AACjC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,cAAc;IAChC,IAAI,OAAO,CAAC,GAAG,CAAC,iBAAiB;QAAE,OAAO,KAAK,CAAA;IAC/C,MAAM,MAAM,GAAG,MAAM,SAAS,EAAE,CAAA;IAChC,IAAI,MAAM,CAAC,SAAS;QAAE,OAAO,QAAQ,CAAA;IACrC,OAAO,IAAI,CAAA;AACf,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,QAA0B;IACxD,MAAM,MAAM,GAAG,QAAQ,IAAI,CAAC,MAAM,SAAS,EAAE,CAAC,CAAA;IAC9C,MAAM,EACF,SAAS,EACT,QAAQ,EACR,eAAe,EACf,YAAY,EACZ,cAAc,EACd,cAAc,EACd,GAAG,IAAI,EACV,GAAG,MAAM,CAAA;IACV,KAAK,SAAS,CAAA;IACd,KAAK,QAAQ,CAAA;IACb,KAAK,eAAe,CAAA;IACpB,KAAK,YAAY,CAAA;IACjB,KAAK,cAAc,CAAA;IACnB,KAAK,cAAc,CAAA;IACnB,MAAM,SAAS,CAAC,IAAc,CAAC,CAAA;AACnC,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { type CoreConfig } from '@doist/cli-core';
2
+ export type Config = CoreConfig & {
3
+ api_token?: string;
4
+ base_url?: string;
5
+ oauth_client_id?: string;
6
+ auth_user_id?: string;
7
+ auth_user_name?: string;
8
+ auth_team_name?: string;
9
+ };
10
+ /**
11
+ * Resolve the canonical config path on every call. Caching at module load
12
+ * would pin the path to the unmocked `node:os.homedir` before vitest's
13
+ * `vi.mock('node:os', …)` hoist takes effect in a fresh test file.
14
+ */
15
+ export declare function getConfigPath(): string;
16
+ export declare function getConfig(): Promise<Partial<Config>>;
17
+ export declare function setConfig(config: Config): Promise<void>;
18
+ export declare function updateConfig(updates: Partial<Config>): Promise<void>;
@@ -0,0 +1,20 @@
1
+ import { getConfigPath as coreGetConfigPath, readConfig as coreReadConfig, updateConfig as coreUpdateConfig, writeConfig as coreWriteConfig, } from '@doist/cli-core';
2
+ const APP_NAME = 'outline-cli';
3
+ /**
4
+ * Resolve the canonical config path on every call. Caching at module load
5
+ * would pin the path to the unmocked `node:os.homedir` before vitest's
6
+ * `vi.mock('node:os', …)` hoist takes effect in a fresh test file.
7
+ */
8
+ export function getConfigPath() {
9
+ return coreGetConfigPath(APP_NAME);
10
+ }
11
+ export async function getConfig() {
12
+ return coreReadConfig(getConfigPath());
13
+ }
14
+ export async function setConfig(config) {
15
+ return coreWriteConfig(getConfigPath(), config);
16
+ }
17
+ export async function updateConfig(updates) {
18
+ return coreUpdateConfig(getConfigPath(), updates);
19
+ }
20
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAEH,aAAa,IAAI,iBAAiB,EAClC,UAAU,IAAI,cAAc,EAC5B,YAAY,IAAI,gBAAgB,EAChC,WAAW,IAAI,eAAe,GACjC,MAAM,iBAAiB,CAAA;AAExB,MAAM,QAAQ,GAAG,aAAa,CAAA;AAW9B;;;;GAIG;AACH,MAAM,UAAU,aAAa;IACzB,OAAO,iBAAiB,CAAC,QAAQ,CAAC,CAAA;AACtC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS;IAC3B,OAAO,cAAc,CAAS,aAAa,EAAE,CAAC,CAAA;AAClD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,MAAc;IAC1C,OAAO,eAAe,CAAC,aAAa,EAAE,EAAE,MAAM,CAAC,CAAA;AACnD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,OAAwB;IACvD,OAAO,gBAAgB,CAAS,aAAa,EAAE,EAAE,OAAO,CAAC,CAAA;AAC7D,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { CliError as CoreCliError, type CliErrorCode, type ErrorType } from '@doist/cli-core';
2
+ export { CoreCliError as BaseCliError };
3
+ export type { ErrorType } from '@doist/cli-core';
4
+ export type ErrorCode = 'ACCOUNT_NOT_FOUND' | 'AUTH_VERIFICATION_FAILED' | 'CONFIRMATION_REQUIRED' | 'CONFLICTING_OPTIONS' | 'INVALID_PARENT' | 'MISSING_OPTION' | 'OAUTH_CALLBACK_PORT_INVALID' | 'OAUTH_CALLBACK_SERVER_FAILED' | 'OAUTH_CLIENT_ID_REQUIRED' | 'OAUTH_LOGIN_FAILED' | 'UNKNOWN_AGENT';
5
+ export declare class CliError extends CoreCliError<ErrorCode> {
6
+ constructor(code: ErrorCode | CliErrorCode, message: string, hints?: string[], type?: ErrorType);
7
+ }
8
+ export { getErrorMessage } from '@doist/cli-core';
@@ -0,0 +1,9 @@
1
+ import { CliError as CoreCliError } from '@doist/cli-core';
2
+ export { CoreCliError as BaseCliError };
3
+ export class CliError extends CoreCliError {
4
+ constructor(code, message, hints, type = 'error') {
5
+ super(code, message, { hints, type });
6
+ }
7
+ }
8
+ export { getErrorMessage } from '@doist/cli-core';
9
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/lib/errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,IAAI,YAAY,EAAqC,MAAM,iBAAiB,CAAA;AAE7F,OAAO,EAAE,YAAY,IAAI,YAAY,EAAE,CAAA;AAgBvC,MAAM,OAAO,QAAS,SAAQ,YAAuB;IACjD,YACI,IAA8B,EAC9B,OAAe,EACf,KAAgB,EAChB,OAAkB,OAAO;QAEzB,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAA;IACzC,CAAC;CACJ;AAED,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA"}
@@ -0,0 +1,5 @@
1
+ export declare const getGlobalArgs: () => import("@doist/cli-core").GlobalArgs;
2
+ export declare const resetGlobalArgs: () => void;
3
+ export declare const isAccessible: () => boolean;
4
+ export declare const shouldDisableSpinner: () => boolean;
5
+ export declare function isJsonMode(): boolean;
@@ -0,0 +1,17 @@
1
+ import { createAccessibleGate, createGlobalArgsStore, createSpinnerGate } from '@doist/cli-core';
2
+ const store = createGlobalArgsStore();
3
+ export const getGlobalArgs = store.get;
4
+ export const resetGlobalArgs = store.reset;
5
+ export const isAccessible = createAccessibleGate({
6
+ envVar: 'OL_ACCESSIBLE',
7
+ getArgs: store.get,
8
+ });
9
+ export const shouldDisableSpinner = createSpinnerGate({
10
+ envVar: 'OL_SPINNER',
11
+ getArgs: store.get,
12
+ });
13
+ export function isJsonMode() {
14
+ const args = store.get();
15
+ return args.json || args.ndjson;
16
+ }
17
+ //# sourceMappingURL=global-args.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"global-args.js","sourceRoot":"","sources":["../../src/lib/global-args.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAEhG,MAAM,KAAK,GAAG,qBAAqB,EAAE,CAAA;AAErC,MAAM,CAAC,MAAM,aAAa,GAAG,KAAK,CAAC,GAAG,CAAA;AACtC,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,CAAC,KAAK,CAAA;AAE1C,MAAM,CAAC,MAAM,YAAY,GAAG,oBAAoB,CAAC;IAC7C,MAAM,EAAE,eAAe;IACvB,OAAO,EAAE,KAAK,CAAC,GAAG;CACrB,CAAC,CAAA;AAEF,MAAM,CAAC,MAAM,oBAAoB,GAAG,iBAAiB,CAAC;IAClD,MAAM,EAAE,YAAY;IACpB,OAAO,EAAE,KAAK,CAAC,GAAG;CACrB,CAAC,CAAA;AAEF,MAAM,UAAU,UAAU;IACtB,MAAM,IAAI,GAAG,KAAK,CAAC,GAAG,EAAE,CAAA;IACxB,OAAO,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,CAAA;AACnC,CAAC"}
@@ -1 +1,2 @@
1
- export declare function renderMarkdown(text: string): string;
1
+ export declare function preloadMarkdown(): Promise<void>;
2
+ export declare function renderMarkdown(text: string): Promise<string>;
@@ -1,7 +1,12 @@
1
- import { marked } from 'marked';
2
- import { markedTerminal } from 'marked-terminal';
3
- marked.use(markedTerminal());
4
- export function renderMarkdown(text) {
5
- return marked.parse(text);
1
+ import { preloadMarkdown as corePreloadMarkdown, renderMarkdown as coreRenderMarkdown, } from '@doist/cli-core/markdown';
2
+ let preloadPromise = null;
3
+ export async function preloadMarkdown() {
4
+ if (!preloadPromise)
5
+ preloadPromise = corePreloadMarkdown();
6
+ return preloadPromise;
7
+ }
8
+ export async function renderMarkdown(text) {
9
+ await preloadMarkdown();
10
+ return coreRenderMarkdown(text);
6
11
  }
7
12
  //# sourceMappingURL=markdown.js.map