@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 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 `-s` or `--server` is not specified, you will be prompted interactively to enter the URL of your hosted or local EdgeOTA server.
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 + public key (safe to commit)
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 = `${serverUrl.replace(/\/$/, "")}/api/updates`;
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": "' + serverUrl + '/api/updates"\n' +
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: { Authorization: `Bearer ${token}` }
385
+ headers
362
386
  });
363
387
  if (!res.ok) {
364
388
  console.error(`❌ Failed to fetch releases (HTTP ${res.status})`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@renbostudios/edge-ota",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "preferGlobal": true,
5
5
  "description": "Zero-SDK, self-hostable OTA update CLI for Expo — push signed JS bundles to any EdgeOTA server",
6
6
  "license": "MIT",