@doist/outline-cli 1.0.0 → 1.0.2
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/CHANGELOG.md +21 -9
- package/README.md +2 -0
- package/dist/commands/auth.d.ts +1 -1
- package/dist/commands/auth.js +45 -48
- package/dist/commands/auth.js.map +1 -1
- package/dist/commands/collection.d.ts +1 -1
- package/dist/commands/collection.js +41 -55
- package/dist/commands/collection.js.map +1 -1
- package/dist/commands/document.d.ts +1 -1
- package/dist/commands/document.js +68 -86
- package/dist/commands/document.js.map +1 -1
- package/dist/commands/search.d.ts +1 -1
- package/dist/commands/search.js +15 -15
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/skill.d.ts +1 -1
- package/dist/commands/skill.js +26 -28
- package/dist/commands/skill.js.map +1 -1
- package/dist/index.js +11 -11
- package/dist/index.js.map +1 -1
- package/dist/lib/api.js +29 -25
- package/dist/lib/api.js.map +1 -1
- package/dist/lib/auth.d.ts +1 -1
- package/dist/lib/auth.js +13 -13
- package/dist/lib/auth.js.map +1 -1
- package/dist/lib/markdown.js +2 -2
- package/dist/lib/markdown.js.map +1 -1
- package/dist/lib/oauth-server.js +37 -37
- package/dist/lib/oauth-server.js.map +1 -1
- package/dist/lib/oauth.js +17 -13
- package/dist/lib/oauth.js.map +1 -1
- package/dist/lib/output.d.ts +1 -1
- package/dist/lib/output.js +3 -3
- package/dist/lib/output.js.map +1 -1
- package/dist/lib/pkce.js +3 -7
- package/dist/lib/pkce.js.map +1 -1
- package/dist/lib/refs.js +10 -12
- package/dist/lib/refs.js.map +1 -1
- package/dist/lib/skills/content.d.ts +1 -1
- package/dist/lib/skills/content.js +2 -2
- package/dist/lib/skills/content.js.map +1 -1
- package/dist/lib/skills/create-installer.d.ts +2 -1
- package/dist/lib/skills/create-installer.js +10 -10
- package/dist/lib/skills/create-installer.js.map +1 -1
- package/dist/lib/skills/index.d.ts +2 -2
- package/dist/lib/skills/index.js +20 -20
- package/dist/lib/skills/index.js.map +1 -1
- package/dist/lib/skills/update-installed.js +1 -1
- package/dist/lib/skills/update-installed.js.map +1 -1
- package/dist/lib/spinner.d.ts +1 -1
- package/dist/lib/spinner.js +5 -7
- package/dist/lib/spinner.js.map +1 -1
- package/dist/postinstall.js +14 -1
- package/dist/postinstall.js.map +1 -1
- package/dist/transport/fetch-with-retry.d.ts +15 -0
- package/dist/transport/fetch-with-retry.js +92 -0
- package/dist/transport/fetch-with-retry.js.map +1 -0
- package/dist/transport/http-dispatcher.d.ts +3 -0
- package/dist/transport/http-dispatcher.js +34 -0
- package/dist/transport/http-dispatcher.js.map +1 -0
- package/package.json +14 -4
- package/scripts/check-skill-sync.js +40 -0
- package/scripts/postinstall.js +5 -5
- package/scripts/sync-skill.js +30 -0
package/dist/lib/api.js
CHANGED
|
@@ -1,25 +1,26 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import { fetchWithRetry } from '../transport/fetch-with-retry.js';
|
|
2
|
+
import { getApiToken, getBaseUrl } from './auth.js';
|
|
3
|
+
import { withSpinner } from './spinner.js';
|
|
3
4
|
/**
|
|
4
5
|
* Spinner configuration mapping API paths to spinner options.
|
|
5
6
|
* Blue for read operations, green for creates, yellow for updates/deletes.
|
|
6
7
|
*/
|
|
7
8
|
const API_SPINNER_CONFIG = {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
9
|
+
'auth.info': { text: 'Checking authentication...', color: 'blue' },
|
|
10
|
+
'documents.search': { text: 'Searching documents...', color: 'blue' },
|
|
11
|
+
'documents.list': { text: 'Loading documents...', color: 'blue' },
|
|
12
|
+
'documents.info': { text: 'Loading document...', color: 'blue' },
|
|
13
|
+
'documents.create': { text: 'Creating document...', color: 'green' },
|
|
14
|
+
'documents.update': { text: 'Updating document...', color: 'yellow' },
|
|
15
|
+
'documents.delete': { text: 'Deleting document...', color: 'yellow' },
|
|
16
|
+
'documents.move': { text: 'Moving document...', color: 'yellow' },
|
|
17
|
+
'documents.archive': { text: 'Archiving document...', color: 'yellow' },
|
|
18
|
+
'documents.unarchive': { text: 'Unarchiving document...', color: 'yellow' },
|
|
19
|
+
'collections.list': { text: 'Loading collections...', color: 'blue' },
|
|
20
|
+
'collections.info': { text: 'Loading collection...', color: 'blue' },
|
|
21
|
+
'collections.create': { text: 'Creating collection...', color: 'green' },
|
|
22
|
+
'collections.update': { text: 'Updating collection...', color: 'yellow' },
|
|
23
|
+
'collections.delete': { text: 'Deleting collection...', color: 'yellow' },
|
|
23
24
|
};
|
|
24
25
|
/**
|
|
25
26
|
* Core API request function without spinner wrapping.
|
|
@@ -27,13 +28,16 @@ const API_SPINNER_CONFIG = {
|
|
|
27
28
|
async function rawApiRequest(path, body = {}) {
|
|
28
29
|
const baseUrl = getBaseUrl();
|
|
29
30
|
const token = getApiToken();
|
|
30
|
-
const res = await
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
const res = await fetchWithRetry({
|
|
32
|
+
url: `${baseUrl}/api/${path}`,
|
|
33
|
+
options: {
|
|
34
|
+
method: 'POST',
|
|
35
|
+
headers: {
|
|
36
|
+
'Content-Type': 'application/json',
|
|
37
|
+
Authorization: `Bearer ${token}`,
|
|
38
|
+
},
|
|
39
|
+
body: JSON.stringify(body),
|
|
35
40
|
},
|
|
36
|
-
body: JSON.stringify(body),
|
|
37
41
|
});
|
|
38
42
|
if (!res.ok) {
|
|
39
43
|
let message = `API error: ${res.status} ${res.statusText}`;
|
|
@@ -54,8 +58,8 @@ async function rawApiRequest(path, body = {}) {
|
|
|
54
58
|
*/
|
|
55
59
|
export async function apiRequest(path, body = {}) {
|
|
56
60
|
const spinnerConfig = API_SPINNER_CONFIG[path] ?? {
|
|
57
|
-
text:
|
|
58
|
-
color:
|
|
61
|
+
text: 'Loading...',
|
|
62
|
+
color: 'blue',
|
|
59
63
|
};
|
|
60
64
|
return withSpinner(spinnerConfig, () => rawApiRequest(path, body));
|
|
61
65
|
}
|
package/dist/lib/api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/lib/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/lib/api.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/auth.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export declare function getApiToken(): string;
|
|
2
2
|
export declare function getBaseUrl(): string;
|
|
3
3
|
export declare function getOAuthClientId(): string | undefined;
|
|
4
|
-
export declare function getTokenSource():
|
|
4
|
+
export declare function getTokenSource(): 'env' | 'config' | null;
|
|
5
5
|
export declare function saveConfig(token: string, baseUrl?: string, oauthClientId?: string): void;
|
|
6
6
|
export declare function clearConfig(): void;
|
package/dist/lib/auth.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync
|
|
2
|
-
import { homedir } from
|
|
3
|
-
import { join } from
|
|
4
|
-
const CONFIG_DIR = join(homedir(),
|
|
5
|
-
const CONFIG_PATH = join(CONFIG_DIR,
|
|
6
|
-
const DEFAULT_BASE_URL =
|
|
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');
|
|
6
|
+
const DEFAULT_BASE_URL = 'https://app.getoutline.com';
|
|
7
7
|
function readConfig() {
|
|
8
8
|
if (!existsSync(CONFIG_PATH))
|
|
9
9
|
return {};
|
|
10
10
|
try {
|
|
11
|
-
return JSON.parse(readFileSync(CONFIG_PATH,
|
|
11
|
+
return JSON.parse(readFileSync(CONFIG_PATH, 'utf-8'));
|
|
12
12
|
}
|
|
13
13
|
catch {
|
|
14
14
|
return {};
|
|
@@ -21,15 +21,15 @@ export function getApiToken() {
|
|
|
21
21
|
const config = readConfig();
|
|
22
22
|
if (config.api_token)
|
|
23
23
|
return config.api_token;
|
|
24
|
-
throw new Error(
|
|
24
|
+
throw new Error('No API token found. Set OUTLINE_API_TOKEN env var or run: ol auth login');
|
|
25
25
|
}
|
|
26
26
|
export function getBaseUrl() {
|
|
27
27
|
const envUrl = process.env.OUTLINE_URL;
|
|
28
28
|
if (envUrl)
|
|
29
|
-
return envUrl.replace(/\/$/,
|
|
29
|
+
return envUrl.replace(/\/$/, '');
|
|
30
30
|
const config = readConfig();
|
|
31
31
|
if (config.base_url)
|
|
32
|
-
return config.base_url.replace(/\/$/,
|
|
32
|
+
return config.base_url.replace(/\/$/, '');
|
|
33
33
|
return DEFAULT_BASE_URL;
|
|
34
34
|
}
|
|
35
35
|
export function getOAuthClientId() {
|
|
@@ -41,10 +41,10 @@ export function getOAuthClientId() {
|
|
|
41
41
|
}
|
|
42
42
|
export function getTokenSource() {
|
|
43
43
|
if (process.env.OUTLINE_API_TOKEN)
|
|
44
|
-
return
|
|
44
|
+
return 'env';
|
|
45
45
|
const config = readConfig();
|
|
46
46
|
if (config.api_token)
|
|
47
|
-
return
|
|
47
|
+
return 'config';
|
|
48
48
|
return null;
|
|
49
49
|
}
|
|
50
50
|
export function saveConfig(token, baseUrl, oauthClientId) {
|
|
@@ -55,7 +55,7 @@ export function saveConfig(token, baseUrl, oauthClientId) {
|
|
|
55
55
|
api_token: token,
|
|
56
56
|
};
|
|
57
57
|
if (baseUrl) {
|
|
58
|
-
config.base_url = baseUrl.replace(/\/$/,
|
|
58
|
+
config.base_url = baseUrl.replace(/\/$/, '');
|
|
59
59
|
}
|
|
60
60
|
if (oauthClientId) {
|
|
61
61
|
config.oauth_client_id = oauthClientId;
|
package/dist/lib/auth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/lib/auth.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/markdown.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { marked } from
|
|
2
|
-
import { markedTerminal } from
|
|
1
|
+
import { marked } from 'marked';
|
|
2
|
+
import { markedTerminal } from 'marked-terminal';
|
|
3
3
|
marked.use(markedTerminal());
|
|
4
4
|
export function renderMarkdown(text) {
|
|
5
5
|
return marked.parse(text);
|
package/dist/lib/markdown.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../src/lib/markdown.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,
|
|
1
|
+
{"version":3,"file":"markdown.js","sourceRoot":"","sources":["../../src/lib/markdown.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC/B,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAEhD,MAAM,CAAC,GAAG,CAAC,cAAc,EAAE,CAAC,CAAA;AAE5B,MAAM,UAAU,cAAc,CAAC,IAAY;IACvC,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,CAAW,CAAA;AACvC,CAAC"}
|
package/dist/lib/oauth-server.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import http from
|
|
1
|
+
import http from 'node:http';
|
|
2
2
|
export const DEFAULT_OAUTH_CALLBACK_PORT = 54969;
|
|
3
3
|
function escapeHtml(text) {
|
|
4
4
|
return text
|
|
5
|
-
.replaceAll(
|
|
6
|
-
.replaceAll(
|
|
7
|
-
.replaceAll(
|
|
8
|
-
.replaceAll('"',
|
|
9
|
-
.replaceAll("'",
|
|
5
|
+
.replaceAll('&', '&')
|
|
6
|
+
.replaceAll('<', '<')
|
|
7
|
+
.replaceAll('>', '>')
|
|
8
|
+
.replaceAll('"', '"')
|
|
9
|
+
.replaceAll("'", ''');
|
|
10
10
|
}
|
|
11
11
|
function renderPage(title, subtitle, body) {
|
|
12
12
|
return `<!doctype html>
|
|
@@ -95,14 +95,14 @@ function renderPage(title, subtitle, body) {
|
|
|
95
95
|
</html>`;
|
|
96
96
|
}
|
|
97
97
|
function renderSuccessPage() {
|
|
98
|
-
return renderPage(
|
|
98
|
+
return renderPage('Login complete', 'Outline CLI is now authenticated.', '<div class="message success">You can close this tab now.</div>');
|
|
99
99
|
}
|
|
100
100
|
function renderErrorPage(message) {
|
|
101
|
-
return renderPage(
|
|
101
|
+
return renderPage('Authentication failed', 'Outline CLI could not finish OAuth login.', `<div class="message error">${escapeHtml(message)}</div>`);
|
|
102
102
|
}
|
|
103
103
|
export async function startOAuthCallbackServer(options) {
|
|
104
|
-
const { state, timeoutMs = 3 * 60 * 1000, port = DEFAULT_OAUTH_CALLBACK_PORT
|
|
105
|
-
let origin =
|
|
104
|
+
const { state, timeoutMs = 3 * 60 * 1000, port = DEFAULT_OAUTH_CALLBACK_PORT } = options;
|
|
105
|
+
let origin = 'http://localhost';
|
|
106
106
|
let resolved = false;
|
|
107
107
|
let resolveCode;
|
|
108
108
|
let rejectCode;
|
|
@@ -112,53 +112,53 @@ export async function startOAuthCallbackServer(options) {
|
|
|
112
112
|
});
|
|
113
113
|
const server = http.createServer((req, res) => {
|
|
114
114
|
if (resolved) {
|
|
115
|
-
res.writeHead(409, {
|
|
116
|
-
res.end(renderErrorPage(
|
|
115
|
+
res.writeHead(409, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
116
|
+
res.end(renderErrorPage('Authorization was already received.'));
|
|
117
117
|
return;
|
|
118
118
|
}
|
|
119
|
-
if (req.method !==
|
|
120
|
-
res.writeHead(405, {
|
|
121
|
-
res.end(renderErrorPage(
|
|
119
|
+
if (req.method !== 'GET' || !req.url) {
|
|
120
|
+
res.writeHead(405, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
121
|
+
res.end(renderErrorPage('Invalid callback request method.'));
|
|
122
122
|
return;
|
|
123
123
|
}
|
|
124
124
|
const url = new URL(req.url, origin);
|
|
125
|
-
if (url.pathname !==
|
|
126
|
-
res.writeHead(404, {
|
|
127
|
-
res.end(renderErrorPage(
|
|
125
|
+
if (url.pathname !== '/callback') {
|
|
126
|
+
res.writeHead(404, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
127
|
+
res.end(renderErrorPage('Unknown callback path.'));
|
|
128
128
|
return;
|
|
129
129
|
}
|
|
130
130
|
// Check for OAuth error response first
|
|
131
|
-
const error = url.searchParams.get(
|
|
131
|
+
const error = url.searchParams.get('error');
|
|
132
132
|
if (error) {
|
|
133
|
-
const errorDescription = url.searchParams.get(
|
|
134
|
-
res.writeHead(400, {
|
|
133
|
+
const errorDescription = url.searchParams.get('error_description') || error;
|
|
134
|
+
res.writeHead(400, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
135
135
|
res.end(renderErrorPage(`Authorization failed: ${errorDescription}`));
|
|
136
136
|
rejectCode(new Error(`OAuth authorization denied: ${errorDescription}`));
|
|
137
137
|
resolved = true;
|
|
138
138
|
return;
|
|
139
139
|
}
|
|
140
|
-
const code = url.searchParams.get(
|
|
141
|
-
const returnedState = url.searchParams.get(
|
|
140
|
+
const code = url.searchParams.get('code');
|
|
141
|
+
const returnedState = url.searchParams.get('state');
|
|
142
142
|
if (!code || !returnedState) {
|
|
143
|
-
res.writeHead(400, {
|
|
144
|
-
res.end(renderErrorPage(
|
|
145
|
-
rejectCode(new Error(
|
|
143
|
+
res.writeHead(400, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
144
|
+
res.end(renderErrorPage('Missing OAuth code or state parameter.'));
|
|
145
|
+
rejectCode(new Error('Missing OAuth authorization code.'));
|
|
146
146
|
resolved = true;
|
|
147
147
|
return;
|
|
148
148
|
}
|
|
149
149
|
if (returnedState !== state) {
|
|
150
|
-
res.writeHead(400, {
|
|
151
|
-
res.end(renderErrorPage(
|
|
152
|
-
rejectCode(new Error(
|
|
150
|
+
res.writeHead(400, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
151
|
+
res.end(renderErrorPage('Invalid OAuth state parameter.'));
|
|
152
|
+
rejectCode(new Error('OAuth state mismatch.'));
|
|
153
153
|
resolved = true;
|
|
154
154
|
return;
|
|
155
155
|
}
|
|
156
|
-
res.writeHead(200, {
|
|
156
|
+
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
|
|
157
157
|
res.end(renderSuccessPage());
|
|
158
158
|
resolved = true;
|
|
159
159
|
resolveCode(code);
|
|
160
160
|
});
|
|
161
|
-
server.on(
|
|
161
|
+
server.on('error', (err) => {
|
|
162
162
|
if (resolved)
|
|
163
163
|
return;
|
|
164
164
|
resolved = true;
|
|
@@ -166,16 +166,16 @@ export async function startOAuthCallbackServer(options) {
|
|
|
166
166
|
});
|
|
167
167
|
await new Promise((resolve, reject) => {
|
|
168
168
|
const onListening = () => {
|
|
169
|
-
server.off(
|
|
169
|
+
server.off('error', onError);
|
|
170
170
|
resolve();
|
|
171
171
|
};
|
|
172
172
|
const onError = (err) => {
|
|
173
|
-
server.off(
|
|
173
|
+
server.off('listening', onListening);
|
|
174
174
|
reject(err);
|
|
175
175
|
};
|
|
176
|
-
server.once(
|
|
177
|
-
server.once(
|
|
178
|
-
server.listen(port,
|
|
176
|
+
server.once('listening', onListening);
|
|
177
|
+
server.once('error', onError);
|
|
178
|
+
server.listen(port, '127.0.0.1');
|
|
179
179
|
});
|
|
180
180
|
const { port: listeningPort } = server.address();
|
|
181
181
|
origin = `http://localhost:${listeningPort}`;
|
|
@@ -184,7 +184,7 @@ export async function startOAuthCallbackServer(options) {
|
|
|
184
184
|
if (resolved)
|
|
185
185
|
return;
|
|
186
186
|
resolved = true;
|
|
187
|
-
rejectCode(new Error(
|
|
187
|
+
rejectCode(new Error('Timed out waiting for OAuth callback.'));
|
|
188
188
|
server.close();
|
|
189
189
|
}, timeoutMs);
|
|
190
190
|
const close = () => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth-server.js","sourceRoot":"","sources":["../../src/lib/oauth-server.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"oauth-server.js","sourceRoot":"","sources":["../../src/lib/oauth-server.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/oauth.js
CHANGED
|
@@ -1,29 +1,33 @@
|
|
|
1
|
+
import { fetchWithRetry } from '../transport/fetch-with-retry.js';
|
|
1
2
|
export function buildAuthorizationUrl(options) {
|
|
2
3
|
const { baseUrl, clientId, redirectUri, codeChallenge, state } = options;
|
|
3
4
|
const url = new URL(`${baseUrl}/oauth/authorize`);
|
|
4
|
-
url.searchParams.set(
|
|
5
|
-
url.searchParams.set(
|
|
6
|
-
url.searchParams.set(
|
|
7
|
-
url.searchParams.set(
|
|
8
|
-
url.searchParams.set(
|
|
9
|
-
url.searchParams.set(
|
|
5
|
+
url.searchParams.set('client_id', clientId);
|
|
6
|
+
url.searchParams.set('response_type', 'code');
|
|
7
|
+
url.searchParams.set('code_challenge', codeChallenge);
|
|
8
|
+
url.searchParams.set('code_challenge_method', 'S256');
|
|
9
|
+
url.searchParams.set('redirect_uri', redirectUri);
|
|
10
|
+
url.searchParams.set('state', state);
|
|
10
11
|
return url.toString();
|
|
11
12
|
}
|
|
12
13
|
export async function exchangeCodeForToken(options) {
|
|
13
14
|
const { baseUrl, clientId, redirectUri, codeVerifier, code } = options;
|
|
14
15
|
const params = new URLSearchParams({
|
|
15
|
-
grant_type:
|
|
16
|
+
grant_type: 'authorization_code',
|
|
16
17
|
client_id: clientId,
|
|
17
18
|
redirect_uri: redirectUri,
|
|
18
19
|
code_verifier: codeVerifier,
|
|
19
20
|
code,
|
|
20
21
|
});
|
|
21
|
-
const res = await
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
22
|
+
const res = await fetchWithRetry({
|
|
23
|
+
url: `${baseUrl}/oauth/token`,
|
|
24
|
+
options: {
|
|
25
|
+
method: 'POST',
|
|
26
|
+
headers: {
|
|
27
|
+
'Content-Type': 'application/x-www-form-urlencoded',
|
|
28
|
+
},
|
|
29
|
+
body: params.toString(),
|
|
25
30
|
},
|
|
26
|
-
body: params.toString(),
|
|
27
31
|
});
|
|
28
32
|
const json = (await res.json());
|
|
29
33
|
if (!res.ok) {
|
|
@@ -31,7 +35,7 @@ export async function exchangeCodeForToken(options) {
|
|
|
31
35
|
throw new Error(`OAuth token exchange failed: ${message}`);
|
|
32
36
|
}
|
|
33
37
|
if (!json.access_token) {
|
|
34
|
-
throw new Error(
|
|
38
|
+
throw new Error('OAuth token exchange did not return an access token.');
|
|
35
39
|
}
|
|
36
40
|
return json.access_token;
|
|
37
41
|
}
|
package/dist/lib/oauth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"oauth.js","sourceRoot":"","sources":["../../src/lib/oauth.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"oauth.js","sourceRoot":"","sources":["../../src/lib/oauth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,kCAAkC,CAAA;AAyBjE,MAAM,UAAU,qBAAqB,CAAC,OAAgC;IAClE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,aAAa,EAAE,KAAK,EAAE,GAAG,OAAO,CAAA;IACxE,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,OAAO,kBAAkB,CAAC,CAAA;IACjD,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAA;IAC3C,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,eAAe,EAAE,MAAM,CAAC,CAAA;IAC7C,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,gBAAgB,EAAE,aAAa,CAAC,CAAA;IACrD,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,uBAAuB,EAAE,MAAM,CAAC,CAAA;IACrD,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,cAAc,EAAE,WAAW,CAAC,CAAA;IACjD,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAA;IACpC,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAA;AACzB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,OAA6B;IACpE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,IAAI,EAAE,GAAG,OAAO,CAAA;IACtE,MAAM,MAAM,GAAG,IAAI,eAAe,CAAC;QAC/B,UAAU,EAAE,oBAAoB;QAChC,SAAS,EAAE,QAAQ;QACnB,YAAY,EAAE,WAAW;QACzB,aAAa,EAAE,YAAY;QAC3B,IAAI;KACP,CAAC,CAAA;IAEF,MAAM,GAAG,GAAG,MAAM,cAAc,CAAC;QAC7B,GAAG,EAAE,GAAG,OAAO,cAAc;QAC7B,OAAO,EAAE;YACL,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACL,cAAc,EAAE,mCAAmC;aACtD;YACD,IAAI,EAAE,MAAM,CAAC,QAAQ,EAAE;SAC1B;KACJ,CAAC,CAAA;IAEF,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAkB,CAAA;IAChD,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;QACV,MAAM,OAAO,GAAG,IAAI,CAAC,iBAAiB,IAAI,IAAI,CAAC,OAAO,IAAI,IAAI,CAAC,KAAK,IAAI,GAAG,CAAC,UAAU,CAAA;QACtF,MAAM,IAAI,KAAK,CAAC,gCAAgC,OAAO,EAAE,CAAC,CAAA;IAC9D,CAAC;IAED,IAAI,CAAC,IAAI,CAAC,YAAY,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAA;IAC3E,CAAC;IAED,OAAO,IAAI,CAAC,YAAY,CAAA;AAC5B,CAAC"}
|
package/dist/lib/output.d.ts
CHANGED
package/dist/lib/output.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import chalk from
|
|
1
|
+
import chalk from 'chalk';
|
|
2
2
|
export function getOutputOptions(opts) {
|
|
3
3
|
return {
|
|
4
4
|
json: Boolean(opts.json),
|
|
@@ -50,11 +50,11 @@ function pick(obj, keys) {
|
|
|
50
50
|
export function formatError(code, message, hints) {
|
|
51
51
|
const lines = [`Error: ${code}`, message];
|
|
52
52
|
if (hints && hints.length > 0) {
|
|
53
|
-
lines.push(
|
|
53
|
+
lines.push('');
|
|
54
54
|
for (const hint of hints) {
|
|
55
55
|
lines.push(` - ${hint}`);
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
|
-
return chalk.red(lines.join(
|
|
58
|
+
return chalk.red(lines.join('\n'));
|
|
59
59
|
}
|
|
60
60
|
//# sourceMappingURL=output.js.map
|
package/dist/lib/output.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/lib/output.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,
|
|
1
|
+
{"version":3,"file":"output.js","sourceRoot":"","sources":["../../src/lib/output.ts"],"names":[],"mappings":"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"}
|
package/dist/lib/pkce.js
CHANGED
|
@@ -1,17 +1,13 @@
|
|
|
1
|
-
import { createHash, randomBytes } from
|
|
1
|
+
import { createHash, randomBytes } from 'node:crypto';
|
|
2
2
|
function base64UrlEncode(buffer) {
|
|
3
|
-
return buffer
|
|
4
|
-
.toString("base64")
|
|
5
|
-
.replace(/\+/g, "-")
|
|
6
|
-
.replace(/\//g, "_")
|
|
7
|
-
.replace(/=+$/, "");
|
|
3
|
+
return buffer.toString('base64').replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
|
8
4
|
}
|
|
9
5
|
export function generateCodeVerifier() {
|
|
10
6
|
// 64 bytes => 86 chars, within 43-128 requirement.
|
|
11
7
|
return base64UrlEncode(randomBytes(64));
|
|
12
8
|
}
|
|
13
9
|
export function generateCodeChallenge(codeVerifier) {
|
|
14
|
-
const hash = createHash(
|
|
10
|
+
const hash = createHash('sha256').update(codeVerifier).digest();
|
|
15
11
|
return base64UrlEncode(hash);
|
|
16
12
|
}
|
|
17
13
|
export function generateState() {
|
package/dist/lib/pkce.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pkce.js","sourceRoot":"","sources":["../../src/lib/pkce.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,
|
|
1
|
+
{"version":3,"file":"pkce.js","sourceRoot":"","sources":["../../src/lib/pkce.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAErD,SAAS,eAAe,CAAC,MAAc;IACnC,OAAO,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;AAC/F,CAAC;AAED,MAAM,UAAU,oBAAoB;IAChC,mDAAmD;IACnD,OAAO,eAAe,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAA;AAC3C,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,YAAoB;IACtD,MAAM,IAAI,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,MAAM,EAAE,CAAA;IAC/D,OAAO,eAAe,CAAC,IAAI,CAAC,CAAA;AAChC,CAAC;AAED,MAAM,UAAU,aAAa;IACzB,OAAO,eAAe,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC,CAAA;AAC3C,CAAC"}
|
package/dist/lib/refs.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { apiRequest } from
|
|
1
|
+
import { apiRequest } from './api.js';
|
|
2
2
|
/**
|
|
3
3
|
* Check if the input looks like a UUID
|
|
4
4
|
*/
|
|
@@ -30,7 +30,7 @@ function extractDocumentIdFromSlug(input) {
|
|
|
30
30
|
return input;
|
|
31
31
|
}
|
|
32
32
|
// If it looks like a URL, extract the slug suffix
|
|
33
|
-
const parts = input.replace(/\/$/,
|
|
33
|
+
const parts = input.replace(/\/$/, '').split('/');
|
|
34
34
|
const last = parts[parts.length - 1];
|
|
35
35
|
// Outline URL IDs are the part after the last hyphen in the slug
|
|
36
36
|
// Only extract if it's a slug with hyphen, not just a raw ID
|
|
@@ -44,15 +44,13 @@ function extractDocumentIdFromSlug(input) {
|
|
|
44
44
|
*/
|
|
45
45
|
function formatSuggestions(items, getName, getDisplayId, max = 5) {
|
|
46
46
|
const suggestions = items.slice(0, max);
|
|
47
|
-
return suggestions
|
|
48
|
-
.map((item) => ` - "${getName(item)}" (${getDisplayId(item)})`)
|
|
49
|
-
.join("\n");
|
|
47
|
+
return suggestions.map((item) => ` - "${getName(item)}" (${getDisplayId(item)})`).join('\n');
|
|
50
48
|
}
|
|
51
49
|
/**
|
|
52
50
|
* Generic fuzzy reference resolver
|
|
53
51
|
*/
|
|
54
52
|
async function resolveRef(options) {
|
|
55
|
-
const { ref, fetchById, fetchAllPaginated, getName, getDisplayId, entityType, extractSlugId
|
|
53
|
+
const { ref, fetchById, fetchAllPaginated, getName, getDisplayId, entityType, extractSlugId } = options;
|
|
56
54
|
// Try direct ID lookup first if it looks like an ID
|
|
57
55
|
// Only extract slug ID for documents, not collections
|
|
58
56
|
const extractedId = extractSlugId ? extractDocumentIdFromSlug(ref) : ref;
|
|
@@ -97,7 +95,7 @@ async function fetchAllDocuments() {
|
|
|
97
95
|
const limit = 100;
|
|
98
96
|
let offset = 0;
|
|
99
97
|
while (true) {
|
|
100
|
-
const { data } = await apiRequest(
|
|
98
|
+
const { data } = await apiRequest('documents.list', {
|
|
101
99
|
limit,
|
|
102
100
|
offset,
|
|
103
101
|
});
|
|
@@ -117,7 +115,7 @@ async function fetchAllCollections() {
|
|
|
117
115
|
const limit = 100;
|
|
118
116
|
let offset = 0;
|
|
119
117
|
while (true) {
|
|
120
|
-
const { data } = await apiRequest(
|
|
118
|
+
const { data } = await apiRequest('collections.list', {
|
|
121
119
|
limit,
|
|
122
120
|
offset,
|
|
123
121
|
});
|
|
@@ -136,13 +134,13 @@ export async function resolveDocumentRef(ref) {
|
|
|
136
134
|
return resolveRef({
|
|
137
135
|
ref,
|
|
138
136
|
fetchById: async (id) => {
|
|
139
|
-
const { data } = await apiRequest(
|
|
137
|
+
const { data } = await apiRequest('documents.info', { id });
|
|
140
138
|
return data;
|
|
141
139
|
},
|
|
142
140
|
fetchAllPaginated: fetchAllDocuments,
|
|
143
141
|
getName: (doc) => doc.title,
|
|
144
142
|
getDisplayId: (doc) => doc.urlId,
|
|
145
|
-
entityType:
|
|
143
|
+
entityType: 'Document',
|
|
146
144
|
extractSlugId: true,
|
|
147
145
|
});
|
|
148
146
|
}
|
|
@@ -160,13 +158,13 @@ export async function resolveCollectionRef(ref) {
|
|
|
160
158
|
return resolveRef({
|
|
161
159
|
ref,
|
|
162
160
|
fetchById: async (id) => {
|
|
163
|
-
const { data } = await apiRequest(
|
|
161
|
+
const { data } = await apiRequest('collections.info', { id });
|
|
164
162
|
return data;
|
|
165
163
|
},
|
|
166
164
|
fetchAllPaginated: fetchAllCollections,
|
|
167
165
|
getName: (col) => col.name,
|
|
168
166
|
getDisplayId: (col) => col.id,
|
|
169
|
-
entityType:
|
|
167
|
+
entityType: 'Collection',
|
|
170
168
|
extractSlugId: false,
|
|
171
169
|
});
|
|
172
170
|
}
|