@renbostudios/edge-ota 0.2.0 → 0.2.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/README.md +6 -3
- package/dist/index.js +29 -5
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -32,16 +32,17 @@ edge-ota status
|
|
|
32
32
|
|
|
33
33
|
Generates an ECDSA P-256 key pair, writes `edge-ota.config.json` and `.edge-ota.private.key`, auto-adds the private key to `.gitignore`, and automatically updates your Expo `app.json` configuration file with the new updates URL.
|
|
34
34
|
|
|
35
|
-
If
|
|
35
|
+
If `--server` is not specified, you will be prompted interactively to enter the URL of your hosted or local EdgeOTA server and your optional Project ID.
|
|
36
36
|
|
|
37
37
|
| Option | Default | Description |
|
|
38
38
|
|--------|---------|-------------|
|
|
39
39
|
| `-s, --server <url>` | — | Your EdgeOTA server URL (prompts if omitted) |
|
|
40
|
+
| `--project <id>` | — | Your EdgeOTA Project ID (prompts if omitted, optional) |
|
|
40
41
|
|
|
41
42
|
**Output:**
|
|
42
|
-
- `edge-ota.config.json` — server URL
|
|
43
|
+
- `edge-ota.config.json` — server URL, public key, and optional project ID (safe to commit)
|
|
43
44
|
- `.edge-ota.private.key` — private signing key (**never commit this**)
|
|
44
|
-
- **Auto-configured:** `app.json` is modified to point `expo.updates.url` to your server's `/api/updates` endpoint.
|
|
45
|
+
- **Auto-configured:** `app.json` is modified to point `expo.updates.url` to your server's updates endpoint. If a Project ID is configured, it points to `/api/projects/:projectId/updates`; otherwise, it falls back to the global `/api/updates` endpoint.
|
|
45
46
|
|
|
46
47
|
---
|
|
47
48
|
|
|
@@ -54,6 +55,7 @@ Runs `expo export`, hashes every asset with SHA-256, signs the payload with your
|
|
|
54
55
|
| `-c, --channel <name>` | `production` | Deployment channel |
|
|
55
56
|
| `-r, --runtime <version>` | `1.0.0` | Native runtime version (must match `runtimeVersion` in app.json) |
|
|
56
57
|
| `-p, --platform <platform>` | `all` | `ios`, `android`, or `all` |
|
|
58
|
+
| `--project <id>` | — | Project ID (overrides value in `edge-ota.config.json`) |
|
|
57
59
|
| `--skip-export` | — | Skip `expo export` — use existing `./dist` |
|
|
58
60
|
| `--dry-run` | — | Sign the payload but don't upload |
|
|
59
61
|
|
|
@@ -75,6 +77,7 @@ Lists recent releases from the server as a table.
|
|
|
75
77
|
|--------|---------|-------------|
|
|
76
78
|
| `-t, --token <token>` | `$EDGE_OTA_TOKEN` | Auth token from the dashboard |
|
|
77
79
|
| `-n, --limit <n>` | `10` | Number of releases to show |
|
|
80
|
+
| `--project <id>` | — | Project ID to query (overrides config) |
|
|
78
81
|
|
|
79
82
|
```bash
|
|
80
83
|
export EDGE_OTA_TOKEN="your-dashboard-token"
|
package/dist/index.js
CHANGED
|
@@ -44,7 +44,7 @@ function askQuestion(query) {
|
|
|
44
44
|
});
|
|
45
45
|
});
|
|
46
46
|
}
|
|
47
|
-
function updateAppJson(cwd, serverUrl) {
|
|
47
|
+
function updateAppJson(cwd, serverUrl, projectId) {
|
|
48
48
|
const appJsonPath = path.resolve(cwd, "app.json");
|
|
49
49
|
if (!fs.existsSync(appJsonPath)) {
|
|
50
50
|
console.log("⚠️ app.json not found in this directory. Skipping auto-update.");
|
|
@@ -59,7 +59,9 @@ function updateAppJson(cwd, serverUrl) {
|
|
|
59
59
|
if (!data.expo.updates) {
|
|
60
60
|
data.expo.updates = {};
|
|
61
61
|
}
|
|
62
|
-
const updateUrl =
|
|
62
|
+
const updateUrl = projectId
|
|
63
|
+
? `${serverUrl.replace(/\/$/, "")}/api/projects/${projectId}/updates`
|
|
64
|
+
: `${serverUrl.replace(/\/$/, "")}/api/updates`;
|
|
63
65
|
data.expo.updates.url = updateUrl;
|
|
64
66
|
fs.writeFileSync(appJsonPath, JSON.stringify(data, null, 2), "utf-8");
|
|
65
67
|
console.log(`✅ Updated app.json: expo.updates.url set to "${updateUrl}"`);
|
|
@@ -176,8 +178,10 @@ program
|
|
|
176
178
|
.command("init")
|
|
177
179
|
.description("Generate an ECDSA P-256 key pair and write edge-ota.config.json")
|
|
178
180
|
.option("-s, --server <url>", "EdgeOTA server URL")
|
|
181
|
+
.option("--project <id>", "EdgeOTA Project ID (optional)")
|
|
179
182
|
.action(async (options) => {
|
|
180
183
|
let serverUrl = options.server;
|
|
184
|
+
let projectId = options.project;
|
|
181
185
|
if (!serverUrl) {
|
|
182
186
|
console.log("ℹ️ Server URL not provided via -s/--server.");
|
|
183
187
|
const answer = await askQuestion("Enter your EdgeOTA server URL [http://localhost:3000]: ");
|
|
@@ -193,6 +197,13 @@ program
|
|
|
193
197
|
serverUrl = answer;
|
|
194
198
|
}
|
|
195
199
|
}
|
|
200
|
+
if (!projectId && !options.server) {
|
|
201
|
+
console.log("\nℹ️ Project ID not provided via --project.");
|
|
202
|
+
const pAnswer = await askQuestion("Enter your EdgeOTA Project ID (optional, press Enter for single-tenant self-hosted): ");
|
|
203
|
+
if (pAnswer.trim()) {
|
|
204
|
+
projectId = pAnswer.trim();
|
|
205
|
+
}
|
|
206
|
+
}
|
|
196
207
|
// Normalise URL (remove trailing slashes)
|
|
197
208
|
serverUrl = serverUrl.replace(/\/$/, "");
|
|
198
209
|
console.log("⚙️ Generating ECDSA P-256 key pair...");
|
|
@@ -201,6 +212,9 @@ program
|
|
|
201
212
|
serverUrl: serverUrl,
|
|
202
213
|
publicKey: keys.publicKey
|
|
203
214
|
};
|
|
215
|
+
if (projectId) {
|
|
216
|
+
config.projectId = projectId;
|
|
217
|
+
}
|
|
204
218
|
const cwd = process.cwd();
|
|
205
219
|
fs.writeFileSync("edge-ota.config.json", JSON.stringify(config, null, 2));
|
|
206
220
|
fs.writeFileSync(".edge-ota.private.key", keys.privateKey, { mode: 0o600 });
|
|
@@ -218,7 +232,10 @@ program
|
|
|
218
232
|
fs.writeFileSync(gitignorePath, `${gitignoreEntry}\n`);
|
|
219
233
|
}
|
|
220
234
|
// Auto-update app.json updates.url
|
|
221
|
-
updateAppJson(cwd, serverUrl);
|
|
235
|
+
updateAppJson(cwd, serverUrl, projectId);
|
|
236
|
+
const targetUrlStr = projectId
|
|
237
|
+
? `${serverUrl}/api/projects/${projectId}/updates`
|
|
238
|
+
: `${serverUrl}/api/updates`;
|
|
222
239
|
console.log("\n✅ EdgeOTA initialised.");
|
|
223
240
|
console.log(" Config : edge-ota.config.json");
|
|
224
241
|
console.log(" Key : .edge-ota.private.key (keep this secret!)");
|
|
@@ -226,7 +243,7 @@ program
|
|
|
226
243
|
console.log(keys.publicKey);
|
|
227
244
|
console.log("\n💡 Your app.json updates configuration has been configured to:\n" +
|
|
228
245
|
' "updates": {\n' +
|
|
229
|
-
' "url": "' +
|
|
246
|
+
' "url": "' + targetUrlStr + '"\n' +
|
|
230
247
|
" }\n" +
|
|
231
248
|
"\n✨ Powered by EdgeOTA — A product of Renbo Studios" +
|
|
232
249
|
"\n🚀 Need scalable app development or custom Cloudflare setup?" +
|
|
@@ -241,6 +258,7 @@ program
|
|
|
241
258
|
.option("-c, --channel <channel>", "Deployment channel", "production")
|
|
242
259
|
.option("-r, --runtime <version>", "React Native runtime version (semver)", "1.0.0")
|
|
243
260
|
.option("-p, --platform <platform>", "Target platform: ios | android | all", "all")
|
|
261
|
+
.option("--project <id>", "Project ID (optional, overrides config)")
|
|
244
262
|
.option("--skip-export", "Skip expo export (use existing ./dist directory)")
|
|
245
263
|
.option("--dry-run", "Build and sign the payload but do NOT upload")
|
|
246
264
|
.action(async (options) => {
|
|
@@ -349,16 +367,22 @@ program
|
|
|
349
367
|
.description("List recent releases from the EdgeOTA server")
|
|
350
368
|
.option("-t, --token <token>", "Auth token (or set EDGE_OTA_TOKEN env var)")
|
|
351
369
|
.option("-n, --limit <n>", "Number of releases to show", "10")
|
|
370
|
+
.option("--project <id>", "Project ID (optional)")
|
|
352
371
|
.action(async (options) => {
|
|
353
372
|
const cwd = process.cwd();
|
|
354
373
|
const config = loadConfig(cwd);
|
|
355
374
|
const token = options.token || process.env.EDGE_OTA_TOKEN;
|
|
375
|
+
const projectId = options.project || config.projectId;
|
|
356
376
|
if (!token) {
|
|
357
377
|
console.error("❌ Auth token required. Use -t <token> or set EDGE_OTA_TOKEN.");
|
|
358
378
|
process.exit(1);
|
|
359
379
|
}
|
|
380
|
+
const headers = { Authorization: `Bearer ${token}` };
|
|
381
|
+
if (projectId) {
|
|
382
|
+
headers["x-project-id"] = projectId;
|
|
383
|
+
}
|
|
360
384
|
const res = await fetch(`${config.serverUrl}/api/releases`, {
|
|
361
|
-
headers
|
|
385
|
+
headers
|
|
362
386
|
});
|
|
363
387
|
if (!res.ok) {
|
|
364
388
|
console.error(`❌ Failed to fetch releases (HTTP ${res.status})`);
|
package/package.json
CHANGED