vesper-wizard 2.0.4 → 2.0.5
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/package.json +1 -1
- package/wizard.js +49 -11
package/package.json
CHANGED
package/wizard.js
CHANGED
|
@@ -91,12 +91,34 @@ function httpJson(method, url, body) {
|
|
|
91
91
|
});
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
async function
|
|
94
|
+
async function probeDeviceAuth(baseUrl) {
|
|
95
95
|
try {
|
|
96
96
|
const res = await httpJson('POST', `${baseUrl}/api/auth/device/start`);
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
97
|
+
if (res.status === 201 && !!res.body && !!res.body.code) {
|
|
98
|
+
return { baseUrl, status: 'ready', response: res.body };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (res.status === 503 && res.body && res.body.requiresSetup) {
|
|
102
|
+
return {
|
|
103
|
+
baseUrl,
|
|
104
|
+
status: 'setup-required',
|
|
105
|
+
response: res.body,
|
|
106
|
+
message: res.body.error || 'Auth storage is not initialized.',
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
baseUrl,
|
|
112
|
+
status: 'unreachable',
|
|
113
|
+
response: res.body,
|
|
114
|
+
message: typeof res.body === 'string' ? res.body : JSON.stringify(res.body),
|
|
115
|
+
};
|
|
116
|
+
} catch (error) {
|
|
117
|
+
return {
|
|
118
|
+
baseUrl,
|
|
119
|
+
status: 'unreachable',
|
|
120
|
+
message: error && error.message ? error.message : 'Request failed',
|
|
121
|
+
};
|
|
100
122
|
}
|
|
101
123
|
}
|
|
102
124
|
|
|
@@ -105,13 +127,20 @@ async function resolveVesperApiBaseUrl() {
|
|
|
105
127
|
? [VESPER_API_URL]
|
|
106
128
|
: DEFAULT_VESPER_API_CANDIDATES;
|
|
107
129
|
|
|
130
|
+
let setupRequiredProbe = null;
|
|
131
|
+
|
|
108
132
|
for (const candidate of candidates) {
|
|
109
|
-
|
|
110
|
-
|
|
133
|
+
const probe = await probeDeviceAuth(candidate);
|
|
134
|
+
if (probe.status === 'ready') {
|
|
135
|
+
return probe;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (!setupRequiredProbe && probe.status === 'setup-required') {
|
|
139
|
+
setupRequiredProbe = probe;
|
|
111
140
|
}
|
|
112
141
|
}
|
|
113
142
|
|
|
114
|
-
return
|
|
143
|
+
return setupRequiredProbe;
|
|
115
144
|
}
|
|
116
145
|
|
|
117
146
|
function openBrowser(url) {
|
|
@@ -149,16 +178,25 @@ async function deviceAuthFlow() {
|
|
|
149
178
|
return null;
|
|
150
179
|
}
|
|
151
180
|
|
|
152
|
-
|
|
181
|
+
if (resolvedApiBaseUrl.status === 'setup-required') {
|
|
182
|
+
console.log(` ${yellow('!')} ${yellow('Reached Vesper auth endpoint, but local auth storage is not initialized.')}`);
|
|
183
|
+
console.log(` ${dim('Endpoint:')} ${dim(resolvedApiBaseUrl.baseUrl)}`);
|
|
184
|
+
console.log(` ${dim('Reason:')} ${dim(resolvedApiBaseUrl.message || 'Apply Supabase migrations first.')}`);
|
|
185
|
+
console.log(` ${dim('Run the SQL in supabase/migrations/001_device_auth.sql and 002_rate_limits.sql, then retry.')}`);
|
|
186
|
+
console.log(` ${dim('Falling back to local-only mode.\n')}`);
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
console.log(` ${dim('Auth endpoint:')} ${dim(resolvedApiBaseUrl.baseUrl)}\n`);
|
|
153
191
|
|
|
154
192
|
// Step 1: Call /api/auth/device/start
|
|
155
193
|
process.stdout.write(` ${dim('Requesting device code...')}`);
|
|
156
194
|
let startRes;
|
|
157
195
|
try {
|
|
158
|
-
startRes = await httpJson('POST', `${resolvedApiBaseUrl}/api/auth/device/start`);
|
|
196
|
+
startRes = await httpJson('POST', `${resolvedApiBaseUrl.baseUrl}/api/auth/device/start`);
|
|
159
197
|
} catch (err) {
|
|
160
198
|
console.log(` ${red('✗')}`);
|
|
161
|
-
console.log(` ${red('Could not reach Vesper API at')} ${dim(resolvedApiBaseUrl)}`);
|
|
199
|
+
console.log(` ${red('Could not reach Vesper API at')} ${dim(resolvedApiBaseUrl.baseUrl)}`);
|
|
162
200
|
console.log(` ${dim('Falling back to local-only mode.\n')}`);
|
|
163
201
|
return null;
|
|
164
202
|
}
|
|
@@ -198,7 +236,7 @@ async function deviceAuthFlow() {
|
|
|
198
236
|
process.stdout.write(`\r ${cyan(frame)} Polling... (${polls})`);
|
|
199
237
|
|
|
200
238
|
try {
|
|
201
|
-
const pollRes = await httpJson('GET', `${resolvedApiBaseUrl}/api/auth/device/poll?code=${code}`);
|
|
239
|
+
const pollRes = await httpJson('GET', `${resolvedApiBaseUrl.baseUrl}/api/auth/device/poll?code=${code}`);
|
|
202
240
|
|
|
203
241
|
if (pollRes.body.status === 'confirmed' && pollRes.body.apiKey) {
|
|
204
242
|
process.stdout.write(`\r ${green('✓')} Device authenticated! \n`);
|