@overscore/cli 0.11.2 → 0.11.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/index.js +71 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -74,7 +74,7 @@ async function loadEnv() {
|
|
|
74
74
|
process.exit(0);
|
|
75
75
|
}
|
|
76
76
|
async function apiRequest(method, urlPath, body, command) {
|
|
77
|
-
const { apiUrl, apiKey } = await loadEnv();
|
|
77
|
+
const { apiUrl, apiKey, projectSlug } = await loadEnv();
|
|
78
78
|
const baseUrl = apiUrl.replace(/\/api$/, "");
|
|
79
79
|
const url = `${baseUrl}${urlPath}`;
|
|
80
80
|
const headers = {
|
|
@@ -92,6 +92,23 @@ async function apiRequest(method, urlPath, body, command) {
|
|
|
92
92
|
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
93
93
|
});
|
|
94
94
|
const data = await res.json();
|
|
95
|
+
if (res.status === 401 && projectSlug) {
|
|
96
|
+
console.log("\n API key expired. Refreshing...\n");
|
|
97
|
+
const newKey = await refreshApiKey(projectSlug);
|
|
98
|
+
if (newKey) {
|
|
99
|
+
const retryRes = await fetch(url, {
|
|
100
|
+
method,
|
|
101
|
+
headers: { ...headers, Authorization: `Bearer ${newKey}` },
|
|
102
|
+
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
103
|
+
});
|
|
104
|
+
const retryData = await retryRes.json();
|
|
105
|
+
if (!retryRes.ok) {
|
|
106
|
+
console.error(`\n Error: ${retryData.error || `HTTP ${retryRes.status}`}\n`);
|
|
107
|
+
process.exit(1);
|
|
108
|
+
}
|
|
109
|
+
return retryData;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
95
112
|
if (!res.ok) {
|
|
96
113
|
console.error(`\n Error: ${data.error || `HTTP ${res.status}`}\n`);
|
|
97
114
|
process.exit(1);
|
|
@@ -116,6 +133,58 @@ function prompt(message) {
|
|
|
116
133
|
});
|
|
117
134
|
});
|
|
118
135
|
}
|
|
136
|
+
async function refreshApiKey(projectSlug) {
|
|
137
|
+
const configDir = path.join(process.env.HOME || "", ".overscore");
|
|
138
|
+
const configPath = path.join(configDir, "config");
|
|
139
|
+
let cfg = fs.existsSync(configPath)
|
|
140
|
+
? parseEnv(fs.readFileSync(configPath, "utf-8"))
|
|
141
|
+
: {};
|
|
142
|
+
let deviceToken = cfg.OVERSCORE_DEVICE_TOKEN;
|
|
143
|
+
if (!deviceToken) {
|
|
144
|
+
console.log("\n No session found. Launching browser login...\n");
|
|
145
|
+
await authLogin();
|
|
146
|
+
cfg = parseEnv(fs.readFileSync(configPath, "utf-8"));
|
|
147
|
+
deviceToken = cfg.OVERSCORE_DEVICE_TOKEN;
|
|
148
|
+
if (!deviceToken)
|
|
149
|
+
return null;
|
|
150
|
+
}
|
|
151
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
152
|
+
const keyRes = await fetch(`${HUB_URL}/api/projects/${projectSlug}/api-keys`, {
|
|
153
|
+
method: "POST",
|
|
154
|
+
headers: { Authorization: `Bearer ${deviceToken}`, "Content-Type": "application/json" },
|
|
155
|
+
body: JSON.stringify({ name: `cli-${Date.now()}` }),
|
|
156
|
+
});
|
|
157
|
+
if (keyRes.ok) {
|
|
158
|
+
const data = (await keyRes.json());
|
|
159
|
+
const newKey = data.raw_key;
|
|
160
|
+
if (!newKey)
|
|
161
|
+
return null;
|
|
162
|
+
// Update local .env if present
|
|
163
|
+
const envPath = path.resolve(process.cwd(), ".env");
|
|
164
|
+
if (fs.existsSync(envPath)) {
|
|
165
|
+
const envContent = fs.readFileSync(envPath, "utf-8");
|
|
166
|
+
fs.writeFileSync(envPath, envContent.replace(/^VITE_OVERSCORE_API_KEY=.*/m, `VITE_OVERSCORE_API_KEY=${newKey}`));
|
|
167
|
+
}
|
|
168
|
+
// Update global config
|
|
169
|
+
cfg.OVERSCORE_API_KEY = newKey;
|
|
170
|
+
fs.mkdirSync(configDir, { recursive: true });
|
|
171
|
+
fs.writeFileSync(configPath, Object.entries(cfg).map(([k, v]) => `${k}=${v}`).join("\n") + "\n", { mode: 0o600 });
|
|
172
|
+
console.log(" API key refreshed.\n");
|
|
173
|
+
return newKey;
|
|
174
|
+
}
|
|
175
|
+
if ((keyRes.status === 401 || keyRes.status === 403) && attempt === 0) {
|
|
176
|
+
console.log("\n Session expired. Launching browser login...\n");
|
|
177
|
+
await authLogin();
|
|
178
|
+
cfg = parseEnv(fs.readFileSync(configPath, "utf-8"));
|
|
179
|
+
deviceToken = cfg.OVERSCORE_DEVICE_TOKEN;
|
|
180
|
+
if (!deviceToken)
|
|
181
|
+
return null;
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
return null;
|
|
187
|
+
}
|
|
119
188
|
const SOURCE_EXCLUDE = new Set([
|
|
120
189
|
"node_modules",
|
|
121
190
|
"dist",
|
|
@@ -2001,7 +2070,7 @@ async function authLogin() {
|
|
|
2001
2070
|
resolveCallback({ token, project });
|
|
2002
2071
|
});
|
|
2003
2072
|
server.listen(chosenPort, "127.0.0.1");
|
|
2004
|
-
const loginUrl = `${HUB_URL}/login?next=${encodeURIComponent(`/api/cli/auth/finalize?port=${chosenPort}&state=${state}`)}&mode=signin`;
|
|
2073
|
+
const loginUrl = `${HUB_URL}/login?next=${encodeURIComponent(`/api/cli/auth/finalize?port=${chosenPort}&state=${state}`)}&mode=signin&switch=1`;
|
|
2005
2074
|
console.log(`\n Opening browser to authenticate...`);
|
|
2006
2075
|
console.log(`\n If your browser doesn't open automatically, visit:\n ${loginUrl}\n`);
|
|
2007
2076
|
try {
|