@renbostudios/edge-ota 0.2.9 → 0.3.1
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 +94 -11
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* edge-ota keygen — Generate a new ECDSA key pair (prints to stdout)
|
|
14
14
|
*/
|
|
15
15
|
import { Command } from "commander";
|
|
16
|
-
import { spawn } from "child_process";
|
|
16
|
+
import { execSync, spawn } from "child_process";
|
|
17
17
|
import fs from "fs";
|
|
18
18
|
import os from "os";
|
|
19
19
|
import path from "path";
|
|
@@ -146,7 +146,7 @@ const spin = (() => {
|
|
|
146
146
|
};
|
|
147
147
|
})();
|
|
148
148
|
// ─── Package version ─────────────────────────────────────────────────────────
|
|
149
|
-
let packageVersion = "0.
|
|
149
|
+
let packageVersion = "0.3.0";
|
|
150
150
|
try {
|
|
151
151
|
const pkgPath = path.join(__dirname, "..", "package.json");
|
|
152
152
|
if (fs.existsSync(pkgPath)) {
|
|
@@ -154,6 +154,70 @@ try {
|
|
|
154
154
|
}
|
|
155
155
|
}
|
|
156
156
|
catch { /* fallback */ }
|
|
157
|
+
// ─── Auto Update Check ────────────────────────────────────────────────────────
|
|
158
|
+
const UPDATE_CHECK_FILE = path.join(GLOBAL_CONFIG_DIR, "update-check.json");
|
|
159
|
+
function isNewerVersion(current, latest) {
|
|
160
|
+
const cParts = current.split(".").map(Number);
|
|
161
|
+
const lParts = latest.split(".").map(Number);
|
|
162
|
+
for (let i = 0; i < 3; i++) {
|
|
163
|
+
const cNum = cParts[i] || 0;
|
|
164
|
+
const lNum = lParts[i] || 0;
|
|
165
|
+
if (lNum > cNum)
|
|
166
|
+
return true;
|
|
167
|
+
if (lNum < cNum)
|
|
168
|
+
return false;
|
|
169
|
+
}
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
async function checkAndAutoUpdate() {
|
|
173
|
+
if (process.env.EDGE_OTA_UPDATING === "true")
|
|
174
|
+
return;
|
|
175
|
+
try {
|
|
176
|
+
const now = Date.now();
|
|
177
|
+
if (fs.existsSync(UPDATE_CHECK_FILE)) {
|
|
178
|
+
try {
|
|
179
|
+
const cache = JSON.parse(fs.readFileSync(UPDATE_CHECK_FILE, "utf-8"));
|
|
180
|
+
// Only check npm once every 15 minutes to keep CLI commands extremely fast
|
|
181
|
+
if (now - (cache.lastChecked || 0) < 15 * 60 * 1000) {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
catch { /* ignore */ }
|
|
186
|
+
}
|
|
187
|
+
// Save timestamp immediately to prevent concurrent requests
|
|
188
|
+
fs.mkdirSync(GLOBAL_CONFIG_DIR, { recursive: true });
|
|
189
|
+
fs.writeFileSync(UPDATE_CHECK_FILE, JSON.stringify({ lastChecked: now }));
|
|
190
|
+
// Fetch latest version from registry with a short 1s timeout
|
|
191
|
+
const controller = new AbortController();
|
|
192
|
+
const timerId = setTimeout(() => controller.abort(), 1000);
|
|
193
|
+
const res = await fetch("https://registry.npmjs.org/@renbostudios/edge-ota/latest", {
|
|
194
|
+
signal: controller.signal
|
|
195
|
+
});
|
|
196
|
+
clearTimeout(timerId);
|
|
197
|
+
if (!res.ok)
|
|
198
|
+
return;
|
|
199
|
+
const data = (await res.json());
|
|
200
|
+
const latestVersion = data.version;
|
|
201
|
+
if (latestVersion && isNewerVersion(packageVersion, latestVersion)) {
|
|
202
|
+
console.log(`\n ${c.yellow}${c.reset} New version of ${c.bold}edge-ota${c.reset} available: ${c.green}${latestVersion}${c.reset} (current: ${c.dim}${packageVersion}${c.reset})`);
|
|
203
|
+
console.log(` ${c.blue}➜${c.reset} Auto-updating globally...`);
|
|
204
|
+
try {
|
|
205
|
+
execSync("npm install -g @renbostudios/edge-ota", {
|
|
206
|
+
stdio: "inherit",
|
|
207
|
+
env: { ...process.env, EDGE_OTA_UPDATING: "true" }
|
|
208
|
+
});
|
|
209
|
+
console.log(` ${c.green}✓${c.reset} Successfully auto-updated to ${c.bold}${latestVersion}${c.reset}!\n`);
|
|
210
|
+
}
|
|
211
|
+
catch (err) {
|
|
212
|
+
console.error(` ${c.red}✗${c.reset} Auto-update failed: ${err.message}`);
|
|
213
|
+
console.error(` Please update manually: ${c.cyan}npm install -g @renbostudios/edge-ota${c.reset}\n`);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
catch {
|
|
218
|
+
// Fail silently so CLI works offline
|
|
219
|
+
}
|
|
220
|
+
}
|
|
157
221
|
// ─── Banner ───────────────────────────────────────────────────────────────────
|
|
158
222
|
function printBanner() {
|
|
159
223
|
const sep = `${c.dim}${"─".repeat(52)}${c.reset}`;
|
|
@@ -163,6 +227,8 @@ function printBanner() {
|
|
|
163
227
|
console.log(` ${c.dim}renbostudios.com${c.reset}`);
|
|
164
228
|
console.log(`${sep}\n`);
|
|
165
229
|
}
|
|
230
|
+
// ─── app.json helpers ────────────────────────────────────────────────────────
|
|
231
|
+
const DEFAULT_SERVER = "https://api.ota.renbo.site";
|
|
166
232
|
function readAppJson(cwd) {
|
|
167
233
|
const appJsonPath = path.resolve(cwd, "app.json");
|
|
168
234
|
if (!fs.existsSync(appJsonPath)) {
|
|
@@ -193,7 +259,7 @@ function readAppJson(cwd) {
|
|
|
193
259
|
console.error(` Run ${c.cyan}edge-ota init${c.reset} to set this up.\n`);
|
|
194
260
|
process.exit(1);
|
|
195
261
|
}
|
|
196
|
-
// Parse serverUrl and projectId from the updates URL
|
|
262
|
+
// Parse serverUrl and projectId from the updates URL.
|
|
197
263
|
// Expected format: https://<host>/api/projects/<uuid>/updates
|
|
198
264
|
// or: https://<host>/api/updates
|
|
199
265
|
let serverUrl;
|
|
@@ -213,7 +279,14 @@ function readAppJson(cwd) {
|
|
|
213
279
|
console.error(` ${c.red}✗${c.reset} Could not parse ${c.dim}expo.updates.url${c.reset} in app.json`);
|
|
214
280
|
process.exit(1);
|
|
215
281
|
}
|
|
216
|
-
|
|
282
|
+
// ── Project-level server override ──
|
|
283
|
+
// expo.extra.edgeOtaServer lets users point a specific project at a
|
|
284
|
+
// different (self-hosted) EdgeOTA instance without re-logging in.
|
|
285
|
+
const projectServer = expo?.extra?.edgeOtaServer;
|
|
286
|
+
if (projectServer) {
|
|
287
|
+
serverUrl = projectServer.replace(/\/$/, "");
|
|
288
|
+
}
|
|
289
|
+
return { serverUrl, projectId, runtimeVersion, publicKey: expo?.extra?.edgeOtaPublicKey };
|
|
217
290
|
}
|
|
218
291
|
function updateAppJson(cwd, serverUrl, projectId, publicKey) {
|
|
219
292
|
const appJsonPath = path.resolve(cwd, "app.json");
|
|
@@ -225,6 +298,8 @@ function updateAppJson(cwd, serverUrl, projectId, publicKey) {
|
|
|
225
298
|
data.expo = {};
|
|
226
299
|
if (!data.expo.updates)
|
|
227
300
|
data.expo.updates = {};
|
|
301
|
+
if (!data.expo.extra)
|
|
302
|
+
data.expo.extra = {};
|
|
228
303
|
const cleanUrl = serverUrl.replace(/\/$/, "");
|
|
229
304
|
data.expo.updates.url = projectId
|
|
230
305
|
? `${cleanUrl}/api/projects/${projectId}/updates`
|
|
@@ -232,13 +307,15 @@ function updateAppJson(cwd, serverUrl, projectId, publicKey) {
|
|
|
232
307
|
data.expo.updates.checkAutomatically = data.expo.updates.checkAutomatically ?? "ON_LOAD";
|
|
233
308
|
data.expo.updates.fallbackToCacheTimeout = data.expo.updates.fallbackToCacheTimeout ?? 30000;
|
|
234
309
|
data.expo.updates.requestHeaders = data.expo.updates.requestHeaders ?? { "expo-channel-name": "production" };
|
|
310
|
+
// Store the server URL in expo.extra.edgeOtaServer so users can easily
|
|
311
|
+
// override which EdgeOTA instance this project points to without re-running
|
|
312
|
+
// `edge-ota login`. They can edit this value directly in app.json.
|
|
313
|
+
data.expo.extra.edgeOtaServer = cleanUrl;
|
|
235
314
|
if (publicKey) {
|
|
236
|
-
data.expo.updates.codeSigningCertificate = undefined; // clear legacy
|
|
237
|
-
data.expo.extra = data.expo.extra ?? {};
|
|
238
315
|
data.expo.extra.edgeOtaPublicKey = publicKey;
|
|
239
316
|
}
|
|
240
317
|
fs.writeFileSync(appJsonPath, JSON.stringify(data, null, 2) + "\n", "utf-8");
|
|
241
|
-
console.log(` ${c.dim}app.json${c.reset} updated ${c.dim}expo.updates.url${c.reset}`);
|
|
318
|
+
console.log(` ${c.dim}app.json${c.reset} updated ${c.dim}expo.updates.url${c.reset} + ${c.dim}expo.extra.edgeOtaServer${c.reset}`);
|
|
242
319
|
}
|
|
243
320
|
catch (e) {
|
|
244
321
|
console.error(` ${c.yellow}⚠${c.reset} Could not update app.json: ${e.message}`);
|
|
@@ -462,11 +539,16 @@ program.action(() => {
|
|
|
462
539
|
program
|
|
463
540
|
.command("login")
|
|
464
541
|
.description("Authenticate with your EdgeOTA account")
|
|
465
|
-
.option("-s, --server <url>",
|
|
542
|
+
.option("-s, --server <url>", `EdgeOTA server URL (default: ${DEFAULT_SERVER})`)
|
|
466
543
|
.action(async (options) => {
|
|
467
544
|
printBanner();
|
|
468
|
-
|
|
469
|
-
|
|
545
|
+
const usingCustomServer = options.server && options.server !== DEFAULT_SERVER;
|
|
546
|
+
console.log(` ${c.bold}Sign in to EdgeOTA${c.reset}`);
|
|
547
|
+
if (usingCustomServer) {
|
|
548
|
+
console.log(` ${c.dim}server: ${options.server}${c.reset}`);
|
|
549
|
+
}
|
|
550
|
+
console.log();
|
|
551
|
+
const serverUrl = (options.server || DEFAULT_SERVER).replace(/\/$/, "");
|
|
470
552
|
const email = await ask(` ${c.dim}email:${c.reset} `);
|
|
471
553
|
const password = await askSecret(` ${c.dim}password:${c.reset} `);
|
|
472
554
|
spin.start("authenticating");
|
|
@@ -527,7 +609,7 @@ program
|
|
|
527
609
|
process.exit(1);
|
|
528
610
|
}
|
|
529
611
|
const globalCfg = loadGlobalConfig();
|
|
530
|
-
const serverUrl = (options.server || globalCfg?.serverUrl ||
|
|
612
|
+
const serverUrl = (options.server || globalCfg?.serverUrl || DEFAULT_SERVER).replace(/\/$/, "");
|
|
531
613
|
const cwd = process.cwd();
|
|
532
614
|
// Fetch existing projects
|
|
533
615
|
spin.start("fetching existing projects from server");
|
|
@@ -851,4 +933,5 @@ program
|
|
|
851
933
|
console.log(sep);
|
|
852
934
|
console.log(keys.publicKey);
|
|
853
935
|
});
|
|
936
|
+
await checkAndAutoUpdate();
|
|
854
937
|
program.parse(process.argv);
|
package/package.json
CHANGED