@doow/cli 0.1.2 → 0.1.4
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/dist/cjs/auth/device-flow.js +18 -2
- package/dist/cjs/auth/device-flow.js.map +1 -1
- package/dist/cjs/auth/pkce.js +30 -11
- package/dist/cjs/auth/pkce.js.map +1 -1
- package/dist/cjs/config/env.js +1 -1
- package/dist/cjs/config/env.js.map +1 -1
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cli.cjs +104 -35
- package/dist/cli.cjs.map +1 -1
- package/dist/esm/auth/device-flow.js +18 -2
- package/dist/esm/auth/device-flow.js.map +1 -1
- package/dist/esm/auth/pkce.js +30 -11
- package/dist/esm/auth/pkce.js.map +1 -1
- package/dist/esm/config/env.js +1 -1
- package/dist/esm/config/env.js.map +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/types/index.d.ts +2 -2
- package/package.json +1 -1
|
@@ -10,7 +10,7 @@ var keyring = require('./keyring.js');
|
|
|
10
10
|
* environments where a browser cannot be opened on the same machine.
|
|
11
11
|
*
|
|
12
12
|
* Steps:
|
|
13
|
-
* 1. POST /v1/auth/device
|
|
13
|
+
* 1. POST /v1/auth/cli/device → get device_code + user_code
|
|
14
14
|
* 2. Display verification URI + user_code on stderr
|
|
15
15
|
* 3. Optionally open the browser (best-effort)
|
|
16
16
|
* 4. Poll POST /v1/auth/device/token until granted or expired
|
|
@@ -30,6 +30,15 @@ function sleep(ms) {
|
|
|
30
30
|
function expiresAtFromSecondsIn(secondsIn) {
|
|
31
31
|
return new Date(Date.now() + secondsIn * 1000).toISOString();
|
|
32
32
|
}
|
|
33
|
+
function isLegacyPendingPollResponse(status, body) {
|
|
34
|
+
const legacyBody = body;
|
|
35
|
+
return (status === 400 &&
|
|
36
|
+
body != null &&
|
|
37
|
+
typeof body === 'object' &&
|
|
38
|
+
legacyBody.name === 'HttpException' &&
|
|
39
|
+
legacyBody.message === 'Bad Request Exception' &&
|
|
40
|
+
legacyBody.response === 'Bad Request Exception');
|
|
41
|
+
}
|
|
33
42
|
// ---------------------------------------------------------------------------
|
|
34
43
|
// Core function
|
|
35
44
|
// ---------------------------------------------------------------------------
|
|
@@ -52,7 +61,7 @@ async function executeDeviceFlow(options = {}) {
|
|
|
52
61
|
// -------------------------------------------------------------------------
|
|
53
62
|
// Step 1: Request device authorization
|
|
54
63
|
// -------------------------------------------------------------------------
|
|
55
|
-
const authorizeRes = await fetch(`${apiUrl}/v1/auth/device
|
|
64
|
+
const authorizeRes = await fetch(`${apiUrl}/v1/auth/cli/device`, {
|
|
56
65
|
method: 'POST',
|
|
57
66
|
headers: { 'Content-Type': 'application/json' },
|
|
58
67
|
body: JSON.stringify({ client_id: 'doow-cli' }),
|
|
@@ -62,6 +71,7 @@ async function executeDeviceFlow(options = {}) {
|
|
|
62
71
|
throw new Error(`Device authorization request failed: HTTP ${authorizeRes.status}${body ? ` — ${body}` : ''}`);
|
|
63
72
|
}
|
|
64
73
|
const auth = (await authorizeRes.json());
|
|
74
|
+
const deviceCodeExpiresAt = Date.now() + auth.expires_in * 1000;
|
|
65
75
|
// -------------------------------------------------------------------------
|
|
66
76
|
// Step 2: Display instructions on stderr
|
|
67
77
|
// -------------------------------------------------------------------------
|
|
@@ -81,6 +91,9 @@ async function executeDeviceFlow(options = {}) {
|
|
|
81
91
|
let pollInterval = auth.interval; // seconds; RFC 8628 §3.5
|
|
82
92
|
while (true) {
|
|
83
93
|
await sleep(pollInterval * 1000);
|
|
94
|
+
if (Date.now() > deviceCodeExpiresAt) {
|
|
95
|
+
throw new Error('Device code expired. Run doow login --device again.');
|
|
96
|
+
}
|
|
84
97
|
const tokenRes = await fetch(`${apiUrl}/v1/auth/device/token`, {
|
|
85
98
|
method: 'POST',
|
|
86
99
|
headers: { 'Content-Type': 'application/json' },
|
|
@@ -125,6 +138,9 @@ async function executeDeviceFlow(options = {}) {
|
|
|
125
138
|
case 'access_denied':
|
|
126
139
|
throw new Error('Authorization denied by user.');
|
|
127
140
|
default:
|
|
141
|
+
if (isLegacyPendingPollResponse(tokenRes.status, errBody)) {
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
128
144
|
throw new Error(`Token polling failed: ${errBody.error}${errBody.error_description ? ` — ${errBody.error_description}` : ''}`);
|
|
129
145
|
}
|
|
130
146
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"device-flow.js","sources":["../../../../src/auth/device-flow.ts"],"sourcesContent":[null],"names":["getApiUrl","createCredentialStore","shouldShowUI"],"mappings":";;;;;AAAA;;;;;;;;;;;;AAYG;
|
|
1
|
+
{"version":3,"file":"device-flow.js","sources":["../../../../src/auth/device-flow.ts"],"sourcesContent":[null],"names":["getApiUrl","createCredentialStore","shouldShowUI"],"mappings":"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"}
|
package/dist/cjs/auth/pkce.js
CHANGED
|
@@ -157,13 +157,12 @@ function startCallbackServer(expectedState, timeoutMs) {
|
|
|
157
157
|
// ---------------------------------------------------------------------------
|
|
158
158
|
// Token exchange
|
|
159
159
|
// ---------------------------------------------------------------------------
|
|
160
|
-
async function exchangeCodeForTokens(apiUrl,
|
|
160
|
+
async function exchangeCodeForTokens(apiUrl, codeVerifier, state) {
|
|
161
161
|
const response = await fetch(`${apiUrl}/v1/auth/cli/token`, {
|
|
162
162
|
method: 'POST',
|
|
163
163
|
headers: { 'Content-Type': 'application/json' },
|
|
164
164
|
body: JSON.stringify({
|
|
165
165
|
grant_type: 'authorization_code',
|
|
166
|
-
code,
|
|
167
166
|
code_verifier: codeVerifier,
|
|
168
167
|
state,
|
|
169
168
|
}),
|
|
@@ -174,6 +173,31 @@ async function exchangeCodeForTokens(apiUrl, code, codeVerifier, state) {
|
|
|
174
173
|
}
|
|
175
174
|
return response.json();
|
|
176
175
|
}
|
|
176
|
+
async function requestAuthorizationUrl(apiUrl, codeChallenge, state, redirectUri) {
|
|
177
|
+
const response = await fetch(`${apiUrl}/v1/auth/cli/authorize`, {
|
|
178
|
+
method: 'POST',
|
|
179
|
+
headers: { 'Content-Type': 'application/json' },
|
|
180
|
+
body: JSON.stringify({
|
|
181
|
+
client_id: 'doow-cli',
|
|
182
|
+
code_challenge: codeChallenge,
|
|
183
|
+
code_challenge_method: 'S256',
|
|
184
|
+
redirect_uri: redirectUri,
|
|
185
|
+
state,
|
|
186
|
+
}),
|
|
187
|
+
});
|
|
188
|
+
if (!response.ok) {
|
|
189
|
+
const body = await response.text().catch(() => '(no body)');
|
|
190
|
+
throw new Error(`Authorize request failed: HTTP ${response.status} — ${body}`);
|
|
191
|
+
}
|
|
192
|
+
const payload = (await response.json());
|
|
193
|
+
if (payload.state !== state) {
|
|
194
|
+
throw new Error('Authorize response state mismatch — possible server bug. Try again.');
|
|
195
|
+
}
|
|
196
|
+
if (!payload.authorization_url) {
|
|
197
|
+
throw new Error('Authorize response did not include authorization_url.');
|
|
198
|
+
}
|
|
199
|
+
return payload.authorization_url;
|
|
200
|
+
}
|
|
177
201
|
// ---------------------------------------------------------------------------
|
|
178
202
|
// Main flow
|
|
179
203
|
// ---------------------------------------------------------------------------
|
|
@@ -197,14 +221,9 @@ async function executePkceFlow(options = {}) {
|
|
|
197
221
|
// Step 3: Start callback server
|
|
198
222
|
const { server, port, callbackPromise } = await startCallbackServer(state, timeout);
|
|
199
223
|
try {
|
|
200
|
-
// Step 4:
|
|
224
|
+
// Step 4: Request an authorization URL from the API
|
|
201
225
|
const redirectUri = `http://127.0.0.1:${port}/callback`;
|
|
202
|
-
const authorizeUrl =
|
|
203
|
-
`?response_type=code` +
|
|
204
|
-
`&code_challenge=${codeChallenge}` +
|
|
205
|
-
`&code_challenge_method=S256` +
|
|
206
|
-
`&state=${state}` +
|
|
207
|
-
`&redirect_uri=${encodeURIComponent(redirectUri)}`;
|
|
226
|
+
const authorizeUrl = await requestAuthorizationUrl(apiUrl, codeChallenge, state, redirectUri);
|
|
208
227
|
// Step 5: Open browser
|
|
209
228
|
try {
|
|
210
229
|
const { default: open } = await import('open');
|
|
@@ -215,9 +234,9 @@ async function executePkceFlow(options = {}) {
|
|
|
215
234
|
throw new Error(`Failed to open browser: ${msg}. Try doow login --device for headless environments.`);
|
|
216
235
|
}
|
|
217
236
|
// Step 6: Wait for callback
|
|
218
|
-
|
|
237
|
+
await callbackPromise;
|
|
219
238
|
// Step 7: Exchange code for tokens
|
|
220
|
-
const tokenResponse = await exchangeCodeForTokens(apiUrl,
|
|
239
|
+
const tokenResponse = await exchangeCodeForTokens(apiUrl, codeVerifier, state);
|
|
221
240
|
// Step 8: Store tokens
|
|
222
241
|
const expiresAt = new Date(Date.now() + tokenResponse.expires_in * 1000).toISOString();
|
|
223
242
|
const result = {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pkce.js","sources":["../../../../src/auth/pkce.ts"],"sourcesContent":[null],"names":["crypto","http","getActiveProfile","getApiUrl","createCredentialStore"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;;;;;;;;;AAcG;
|
|
1
|
+
{"version":3,"file":"pkce.js","sources":["../../../../src/auth/pkce.ts"],"sourcesContent":[null],"names":["crypto","http","getActiveProfile","getApiUrl","createCredentialStore"],"mappings":"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"}
|
package/dist/cjs/config/env.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"env.js","sources":["../../../../src/config/env.ts"],"sourcesContent":[null],"names":[],"mappings":";;AAEA;SACgB,KAAK,GAAA;AACnB,IAAA,OAAO,OAAO,CAAC,MAAM,CAAC,KAAK,KAAK,IAAI;AACtC;AAEA;SACgB,IAAI,GAAA;IAClB,OAAO,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;AAC5B;AAEA;;;;;AAKG;SACa,WAAW,GAAA;IACzB,OAAO,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;AACzC;AAEA;;;AAGG;SACa,YAAY,GAAA;IAC1B,OAAO,KAAK,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE;AAC7C;AAEA;;;AAGG;AACG,SAAU,SAAS,CAAC,OAAiB,EAAA;IACzC,IAAI,OAAO,EAAE,MAAM;QAAE,OAAO,OAAO,CAAC,MAAM;AAC1C,IAAA,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;AAAE,QAAA,OAAO,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;AACnE,IAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"env.js","sources":["../../../../src/config/env.ts"],"sourcesContent":[null],"names":[],"mappings":";;AAEA;SACgB,KAAK,GAAA;AACnB,IAAA,OAAO,OAAO,CAAC,MAAM,CAAC,KAAK,KAAK,IAAI;AACtC;AAEA;SACgB,IAAI,GAAA;IAClB,OAAO,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;AAC5B;AAEA;;;;;AAKG;SACa,WAAW,GAAA;IACzB,OAAO,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC;AACzC;AAEA;;;AAGG;SACa,YAAY,GAAA;IAC1B,OAAO,KAAK,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE;AAC7C;AAEA;;;AAGG;AACG,SAAU,SAAS,CAAC,OAAiB,EAAA;IACzC,IAAI,OAAO,EAAE,MAAM;QAAE,OAAO,OAAO,CAAC,MAAM;AAC1C,IAAA,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;AAAE,QAAA,OAAO,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;AACnE,IAAA,OAAO,yBAAyB;AAClC;;;;;;;;"}
|
package/dist/cjs/index.js
CHANGED
|
@@ -11,7 +11,7 @@ var detect = require('./auth/detect.js');
|
|
|
11
11
|
|
|
12
12
|
// @doow/cli library entry point
|
|
13
13
|
// Re-exports for programmatic usage
|
|
14
|
-
const VERSION =
|
|
14
|
+
const VERSION = "0.1.4" ;
|
|
15
15
|
|
|
16
16
|
exports.clearProfileCredentials = store.clearProfileCredentials;
|
|
17
17
|
exports.deleteProfile = store.deleteProfile;
|
package/dist/cjs/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../../src/index.ts"],"sourcesContent":[null],"names":[],"mappings":";;;;;;;;;;;AAAA;AACA;
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../../src/index.ts"],"sourcesContent":[null],"names":[],"mappings":";;;;;;;;;;;AAAA;AACA;AAIO,MAAM,OAAO,GACuB,OAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
package/dist/cli.cjs
CHANGED
|
@@ -231,7 +231,7 @@ function getApiUrl(profile) {
|
|
|
231
231
|
return profile.apiUrl;
|
|
232
232
|
if (process.env['DOOW_API_URL'])
|
|
233
233
|
return process.env['DOOW_API_URL'];
|
|
234
|
-
return 'https://api.doow.
|
|
234
|
+
return 'https://dev-api.doow.co';
|
|
235
235
|
}
|
|
236
236
|
|
|
237
237
|
// ---------------------------------------------------------------------------
|
|
@@ -626,13 +626,12 @@ function startCallbackServer(expectedState, timeoutMs) {
|
|
|
626
626
|
// ---------------------------------------------------------------------------
|
|
627
627
|
// Token exchange
|
|
628
628
|
// ---------------------------------------------------------------------------
|
|
629
|
-
async function exchangeCodeForTokens(apiUrl,
|
|
629
|
+
async function exchangeCodeForTokens(apiUrl, codeVerifier, state) {
|
|
630
630
|
const response = await fetch(`${apiUrl}/v1/auth/cli/token`, {
|
|
631
631
|
method: 'POST',
|
|
632
632
|
headers: { 'Content-Type': 'application/json' },
|
|
633
633
|
body: JSON.stringify({
|
|
634
634
|
grant_type: 'authorization_code',
|
|
635
|
-
code,
|
|
636
635
|
code_verifier: codeVerifier,
|
|
637
636
|
state,
|
|
638
637
|
}),
|
|
@@ -643,6 +642,31 @@ async function exchangeCodeForTokens(apiUrl, code, codeVerifier, state) {
|
|
|
643
642
|
}
|
|
644
643
|
return response.json();
|
|
645
644
|
}
|
|
645
|
+
async function requestAuthorizationUrl(apiUrl, codeChallenge, state, redirectUri) {
|
|
646
|
+
const response = await fetch(`${apiUrl}/v1/auth/cli/authorize`, {
|
|
647
|
+
method: 'POST',
|
|
648
|
+
headers: { 'Content-Type': 'application/json' },
|
|
649
|
+
body: JSON.stringify({
|
|
650
|
+
client_id: 'doow-cli',
|
|
651
|
+
code_challenge: codeChallenge,
|
|
652
|
+
code_challenge_method: 'S256',
|
|
653
|
+
redirect_uri: redirectUri,
|
|
654
|
+
state,
|
|
655
|
+
}),
|
|
656
|
+
});
|
|
657
|
+
if (!response.ok) {
|
|
658
|
+
const body = await response.text().catch(() => '(no body)');
|
|
659
|
+
throw new Error(`Authorize request failed: HTTP ${response.status} — ${body}`);
|
|
660
|
+
}
|
|
661
|
+
const payload = (await response.json());
|
|
662
|
+
if (payload.state !== state) {
|
|
663
|
+
throw new Error('Authorize response state mismatch — possible server bug. Try again.');
|
|
664
|
+
}
|
|
665
|
+
if (!payload.authorization_url) {
|
|
666
|
+
throw new Error('Authorize response did not include authorization_url.');
|
|
667
|
+
}
|
|
668
|
+
return payload.authorization_url;
|
|
669
|
+
}
|
|
646
670
|
// ---------------------------------------------------------------------------
|
|
647
671
|
// Main flow
|
|
648
672
|
// ---------------------------------------------------------------------------
|
|
@@ -666,14 +690,9 @@ async function executePkceFlow(options = {}) {
|
|
|
666
690
|
// Step 3: Start callback server
|
|
667
691
|
const { server, port, callbackPromise } = await startCallbackServer(state, timeout);
|
|
668
692
|
try {
|
|
669
|
-
// Step 4:
|
|
693
|
+
// Step 4: Request an authorization URL from the API
|
|
670
694
|
const redirectUri = `http://127.0.0.1:${port}/callback`;
|
|
671
|
-
const authorizeUrl =
|
|
672
|
-
`?response_type=code` +
|
|
673
|
-
`&code_challenge=${codeChallenge}` +
|
|
674
|
-
`&code_challenge_method=S256` +
|
|
675
|
-
`&state=${state}` +
|
|
676
|
-
`&redirect_uri=${encodeURIComponent(redirectUri)}`;
|
|
695
|
+
const authorizeUrl = await requestAuthorizationUrl(apiUrl, codeChallenge, state, redirectUri);
|
|
677
696
|
// Step 5: Open browser
|
|
678
697
|
try {
|
|
679
698
|
const { default: open } = await import('open');
|
|
@@ -684,9 +703,9 @@ async function executePkceFlow(options = {}) {
|
|
|
684
703
|
throw new Error(`Failed to open browser: ${msg}. Try doow login --device for headless environments.`);
|
|
685
704
|
}
|
|
686
705
|
// Step 6: Wait for callback
|
|
687
|
-
|
|
706
|
+
await callbackPromise;
|
|
688
707
|
// Step 7: Exchange code for tokens
|
|
689
|
-
const tokenResponse = await exchangeCodeForTokens(apiUrl,
|
|
708
|
+
const tokenResponse = await exchangeCodeForTokens(apiUrl, codeVerifier, state);
|
|
690
709
|
// Step 8: Store tokens
|
|
691
710
|
const expiresAt = new Date(Date.now() + tokenResponse.expires_in * 1000).toISOString();
|
|
692
711
|
const result = {
|
|
@@ -714,7 +733,7 @@ async function executePkceFlow(options = {}) {
|
|
|
714
733
|
* environments where a browser cannot be opened on the same machine.
|
|
715
734
|
*
|
|
716
735
|
* Steps:
|
|
717
|
-
* 1. POST /v1/auth/device
|
|
736
|
+
* 1. POST /v1/auth/cli/device → get device_code + user_code
|
|
718
737
|
* 2. Display verification URI + user_code on stderr
|
|
719
738
|
* 3. Optionally open the browser (best-effort)
|
|
720
739
|
* 4. Poll POST /v1/auth/device/token until granted or expired
|
|
@@ -734,6 +753,15 @@ function sleep$1(ms) {
|
|
|
734
753
|
function expiresAtFromSecondsIn(secondsIn) {
|
|
735
754
|
return new Date(Date.now() + secondsIn * 1000).toISOString();
|
|
736
755
|
}
|
|
756
|
+
function isLegacyPendingPollResponse(status, body) {
|
|
757
|
+
const legacyBody = body;
|
|
758
|
+
return (status === 400 &&
|
|
759
|
+
body != null &&
|
|
760
|
+
typeof body === 'object' &&
|
|
761
|
+
legacyBody.name === 'HttpException' &&
|
|
762
|
+
legacyBody.message === 'Bad Request Exception' &&
|
|
763
|
+
legacyBody.response === 'Bad Request Exception');
|
|
764
|
+
}
|
|
737
765
|
// ---------------------------------------------------------------------------
|
|
738
766
|
// Core function
|
|
739
767
|
// ---------------------------------------------------------------------------
|
|
@@ -756,7 +784,7 @@ async function executeDeviceFlow(options = {}) {
|
|
|
756
784
|
// -------------------------------------------------------------------------
|
|
757
785
|
// Step 1: Request device authorization
|
|
758
786
|
// -------------------------------------------------------------------------
|
|
759
|
-
const authorizeRes = await fetch(`${apiUrl}/v1/auth/device
|
|
787
|
+
const authorizeRes = await fetch(`${apiUrl}/v1/auth/cli/device`, {
|
|
760
788
|
method: 'POST',
|
|
761
789
|
headers: { 'Content-Type': 'application/json' },
|
|
762
790
|
body: JSON.stringify({ client_id: 'doow-cli' }),
|
|
@@ -766,6 +794,7 @@ async function executeDeviceFlow(options = {}) {
|
|
|
766
794
|
throw new Error(`Device authorization request failed: HTTP ${authorizeRes.status}${body ? ` — ${body}` : ''}`);
|
|
767
795
|
}
|
|
768
796
|
const auth = (await authorizeRes.json());
|
|
797
|
+
const deviceCodeExpiresAt = Date.now() + auth.expires_in * 1000;
|
|
769
798
|
// -------------------------------------------------------------------------
|
|
770
799
|
// Step 2: Display instructions on stderr
|
|
771
800
|
// -------------------------------------------------------------------------
|
|
@@ -785,6 +814,9 @@ async function executeDeviceFlow(options = {}) {
|
|
|
785
814
|
let pollInterval = auth.interval; // seconds; RFC 8628 §3.5
|
|
786
815
|
while (true) {
|
|
787
816
|
await sleep$1(pollInterval * 1000);
|
|
817
|
+
if (Date.now() > deviceCodeExpiresAt) {
|
|
818
|
+
throw new Error('Device code expired. Run doow login --device again.');
|
|
819
|
+
}
|
|
788
820
|
const tokenRes = await fetch(`${apiUrl}/v1/auth/device/token`, {
|
|
789
821
|
method: 'POST',
|
|
790
822
|
headers: { 'Content-Type': 'application/json' },
|
|
@@ -829,6 +861,9 @@ async function executeDeviceFlow(options = {}) {
|
|
|
829
861
|
case 'access_denied':
|
|
830
862
|
throw new Error('Authorization denied by user.');
|
|
831
863
|
default:
|
|
864
|
+
if (isLegacyPendingPollResponse(tokenRes.status, errBody)) {
|
|
865
|
+
continue;
|
|
866
|
+
}
|
|
832
867
|
throw new Error(`Token polling failed: ${errBody.error}${errBody.error_description ? ` — ${errBody.error_description}` : ''}`);
|
|
833
868
|
}
|
|
834
869
|
}
|
|
@@ -9137,29 +9172,45 @@ async function checkNetwork(apiUrl) {
|
|
|
9137
9172
|
}
|
|
9138
9173
|
}
|
|
9139
9174
|
async function checkApiVersion(apiUrl) {
|
|
9175
|
+
const healthPaths = ['/health', '/v1/health'];
|
|
9140
9176
|
try {
|
|
9141
9177
|
const controller = new AbortController();
|
|
9142
9178
|
const timeoutId = setTimeout(() => controller.abort(), 5000);
|
|
9143
|
-
|
|
9144
|
-
|
|
9145
|
-
|
|
9146
|
-
|
|
9147
|
-
|
|
9148
|
-
|
|
9149
|
-
|
|
9150
|
-
|
|
9151
|
-
|
|
9152
|
-
|
|
9153
|
-
|
|
9154
|
-
|
|
9155
|
-
|
|
9156
|
-
|
|
9157
|
-
|
|
9179
|
+
let lastPath = healthPaths[0];
|
|
9180
|
+
let lastStatus;
|
|
9181
|
+
for (const path of healthPaths) {
|
|
9182
|
+
lastPath = path;
|
|
9183
|
+
const res = await fetch(`${apiUrl}${path}`, { signal: controller.signal });
|
|
9184
|
+
if (res.ok) {
|
|
9185
|
+
clearTimeout(timeoutId);
|
|
9186
|
+
let version;
|
|
9187
|
+
try {
|
|
9188
|
+
const body = await res.json();
|
|
9189
|
+
if (typeof body['version'] === 'string')
|
|
9190
|
+
version = body['version'];
|
|
9191
|
+
else if (typeof body['server_version'] === 'string')
|
|
9192
|
+
version = body['server_version'];
|
|
9193
|
+
}
|
|
9194
|
+
catch {
|
|
9195
|
+
// non-JSON body is acceptable
|
|
9196
|
+
}
|
|
9197
|
+
return {
|
|
9198
|
+
name: 'api_version',
|
|
9199
|
+
status: 'pass',
|
|
9200
|
+
detail: version ? `server ${version}` : 'reachable (no version in response)',
|
|
9201
|
+
};
|
|
9202
|
+
}
|
|
9203
|
+
lastStatus = res.status;
|
|
9204
|
+
if (res.status !== 404 && res.status !== 410) {
|
|
9205
|
+
clearTimeout(timeoutId);
|
|
9206
|
+
return { name: 'api_version', status: 'warn', detail: `HTTP ${res.status} from ${path}` };
|
|
9207
|
+
}
|
|
9158
9208
|
}
|
|
9209
|
+
clearTimeout(timeoutId);
|
|
9159
9210
|
return {
|
|
9160
9211
|
name: 'api_version',
|
|
9161
|
-
status: '
|
|
9162
|
-
detail:
|
|
9212
|
+
status: 'warn',
|
|
9213
|
+
detail: `HTTP ${lastStatus ?? 404} from ${lastPath}`,
|
|
9163
9214
|
};
|
|
9164
9215
|
}
|
|
9165
9216
|
catch (err) {
|
|
@@ -33863,7 +33914,7 @@ async function startStdioServer(options) {
|
|
|
33863
33914
|
await server.connect(transport);
|
|
33864
33915
|
}
|
|
33865
33916
|
|
|
33866
|
-
const VERSION = "0.1.
|
|
33917
|
+
const VERSION = "0.1.4" ;
|
|
33867
33918
|
const ASCII_LOGO = `
|
|
33868
33919
|
_
|
|
33869
33920
|
__| | ___ ___ __ __
|
|
@@ -33880,6 +33931,10 @@ function printLogo() {
|
|
|
33880
33931
|
process.stdout.write(' Not logged in.\n\n');
|
|
33881
33932
|
process.stdout.write(' Run \x1b[36mdoow login\x1b[0m to get started.\n\n');
|
|
33882
33933
|
}
|
|
33934
|
+
function readString(data, key) {
|
|
33935
|
+
const value = data[key];
|
|
33936
|
+
return typeof value === 'string' ? value : undefined;
|
|
33937
|
+
}
|
|
33883
33938
|
// ---------------------------------------------------------------------------
|
|
33884
33939
|
// loginHandler — exported for testability
|
|
33885
33940
|
// ---------------------------------------------------------------------------
|
|
@@ -33989,14 +34044,28 @@ async function whoamiHandler(globalOpts, credentialStore) {
|
|
|
33989
34044
|
process.exit(1);
|
|
33990
34045
|
}
|
|
33991
34046
|
const data = (await res.json());
|
|
33992
|
-
const email = data
|
|
33993
|
-
const
|
|
34047
|
+
const email = readString(data, 'email') ?? '(unknown)';
|
|
34048
|
+
const organizationId = readString(data, 'organization_id');
|
|
34049
|
+
const org = readString(data, 'organization') ?? organizationId ?? '(unknown)';
|
|
34050
|
+
const role = readString(data, 'role');
|
|
34051
|
+
const capabilities = Array.isArray(data['capabilities'])
|
|
34052
|
+
? data['capabilities'].filter((value) => typeof value === 'string')
|
|
34053
|
+
: undefined;
|
|
33994
34054
|
if (isJson) {
|
|
33995
|
-
process.stdout.write(JSON.stringify({
|
|
34055
|
+
process.stdout.write(JSON.stringify({
|
|
34056
|
+
email,
|
|
34057
|
+
organization: org,
|
|
34058
|
+
organizationId,
|
|
34059
|
+
role,
|
|
34060
|
+
capabilities,
|
|
34061
|
+
profile: profileName,
|
|
34062
|
+
}) + '\n');
|
|
33996
34063
|
}
|
|
33997
34064
|
else {
|
|
33998
34065
|
process.stderr.write(`Logged in as ${email}\n`);
|
|
33999
34066
|
process.stderr.write(`Organization: ${org}\n`);
|
|
34067
|
+
if (role)
|
|
34068
|
+
process.stderr.write(`Role: ${role}\n`);
|
|
34000
34069
|
process.stderr.write(`Auth: ${resolved.source}\n`);
|
|
34001
34070
|
process.stderr.write(`Profile: ${profileName}\n`);
|
|
34002
34071
|
}
|