@omg-dev/cli 0.4.31 → 0.4.33

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.
Files changed (2) hide show
  1. package/dist/omg.mjs +248 -6
  2. package/package.json +1 -1
package/dist/omg.mjs CHANGED
@@ -2,8 +2,8 @@
2
2
  // @bun
3
3
 
4
4
  // src/index.ts
5
- import { readFileSync as readFileSync4, writeFileSync as writeFileSync4, mkdirSync as mkdirSync3 } from "fs";
6
- import { join as join5, resolve as resolve3, basename, dirname as dirname3 } from "path";
5
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync5, mkdirSync as mkdirSync3 } from "fs";
6
+ import { join as join6, resolve as resolve3, basename, dirname as dirname3 } from "path";
7
7
 
8
8
  // src/config.ts
9
9
  import { homedir } from "os";
@@ -446,6 +446,39 @@ function getStatus(token, slug) {
446
446
  function listApps(token) {
447
447
  return controlPlane("/api/cli/apps/list", token);
448
448
  }
449
+ function getVisibility(token, slug) {
450
+ return controlPlane(`/api/cli/apps/visibility?slug=${encodeURIComponent(slug)}`, token);
451
+ }
452
+ function setVisibility(token, slug, visibility) {
453
+ return controlPlane("/api/cli/apps/visibility", token, {
454
+ method: "POST",
455
+ body: JSON.stringify({ slug, visibility })
456
+ });
457
+ }
458
+ function envList(token, slug) {
459
+ return controlPlane(`/api/cli/env/list?slug=${encodeURIComponent(slug)}`, token);
460
+ }
461
+ function envPull(token, slug) {
462
+ return controlPlane(`/api/cli/env/pull?slug=${encodeURIComponent(slug)}`, token);
463
+ }
464
+ function envSet(token, slug, vars) {
465
+ return controlPlane("/api/cli/env/set", token, {
466
+ method: "POST",
467
+ body: JSON.stringify({ slug, vars })
468
+ });
469
+ }
470
+ function envRemove(token, slug, keys) {
471
+ return controlPlane("/api/cli/env/rm", token, {
472
+ method: "POST",
473
+ body: JSON.stringify({ slug, keys })
474
+ });
475
+ }
476
+ function envImport(token, slug, contents) {
477
+ return controlPlane("/api/cli/env/import", token, {
478
+ method: "POST",
479
+ body: JSON.stringify({ slug, contents })
480
+ });
481
+ }
449
482
  function getComputerConnectConfig(token) {
450
483
  return controlPlane("/api/cli/computer/connect", token);
451
484
  }
@@ -654,7 +687,7 @@ async function deploy(opts) {
654
687
  if (collected.files.length === 0)
655
688
  throw new Error(`No files to deploy in ${root}`);
656
689
  for (const s of collected.skippedSecrets) {
657
- onProgress(`skipping ${s} \u2014 set secrets in project settings, not the artifact`);
690
+ onProgress(`skipping ${s} \u2014 import it with \`omg env push --file ${s}\``);
658
691
  }
659
692
  for (const s of collected.skippedLarge)
660
693
  onProgress(`skipping ${s} \u2014 over the per-file limit`);
@@ -1306,6 +1339,190 @@ async function runDev(options) {
1306
1339
  }
1307
1340
  }
1308
1341
 
1342
+ // src/env.ts
1343
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync4, existsSync as existsSync2 } from "fs";
1344
+ import { join as join5 } from "path";
1345
+ async function defaultReadStdin() {
1346
+ const chunks = [];
1347
+ for await (const chunk of process.stdin)
1348
+ chunks.push(chunk);
1349
+ return Buffer.concat(chunks).toString("utf8");
1350
+ }
1351
+ function formatList(vars, out) {
1352
+ if (!vars.length) {
1353
+ out("No env vars set.");
1354
+ out("");
1355
+ out(" omg env set KEY=value set one");
1356
+ out(" omg env push --file .env import a local .env");
1357
+ return;
1358
+ }
1359
+ const width = Math.max(...vars.map((v) => v.key.length));
1360
+ for (const v of vars)
1361
+ out(` ${v.key.padEnd(width)} ${v.preview}`);
1362
+ }
1363
+ async function collectAssignments(args, readStdin) {
1364
+ const vars = {};
1365
+ for (let i = 0;i < args.length; i++) {
1366
+ const arg = args[i];
1367
+ const eq = arg.indexOf("=");
1368
+ if (eq > 0) {
1369
+ vars[arg.slice(0, eq)] = arg.slice(eq + 1);
1370
+ continue;
1371
+ }
1372
+ if (args[i + 1] === "-") {
1373
+ vars[arg] = (await readStdin()).replace(/\n$/, "");
1374
+ i++;
1375
+ continue;
1376
+ }
1377
+ throw new Error(`Expected KEY=value (or \`${arg} -\` to read the value from stdin), got "${arg}"`);
1378
+ }
1379
+ return vars;
1380
+ }
1381
+ function toDotenv(env) {
1382
+ return Object.keys(env).sort().map((k) => {
1383
+ const v = env[k] ?? "";
1384
+ const needsQuotes = /[\s"'#$`\\]/.test(v) || v === "";
1385
+ return `${k}=${needsQuotes ? JSON.stringify(v) : v}`;
1386
+ }).join(`
1387
+ `) + `
1388
+ `;
1389
+ }
1390
+ async function runEnv(opts) {
1391
+ const { args, slug, token, root, flag, out } = opts;
1392
+ const readStdin = opts.readStdin ?? defaultReadStdin;
1393
+ const sub = args[0] ?? "list";
1394
+ const rest = args.slice(1);
1395
+ switch (sub) {
1396
+ case "list":
1397
+ case "ls": {
1398
+ const { vars } = await envList(token, slug);
1399
+ formatList(vars, out);
1400
+ return 0;
1401
+ }
1402
+ case "set": {
1403
+ if (!rest.length) {
1404
+ out("Usage: omg env set KEY=value [KEY2=value2 ...]");
1405
+ out(" omg env set KEY - read the value from stdin");
1406
+ return 1;
1407
+ }
1408
+ const vars = await collectAssignments(rest, readStdin);
1409
+ const res = await envSet(token, slug, vars);
1410
+ for (const k of res.created)
1411
+ out(` + ${k}`);
1412
+ for (const k of res.updated)
1413
+ out(` ~ ${k} (updated)`);
1414
+ out("");
1415
+ out("Applies on next `omg deploy`.");
1416
+ return 0;
1417
+ }
1418
+ case "rm":
1419
+ case "remove":
1420
+ case "unset": {
1421
+ if (!rest.length) {
1422
+ out("Usage: omg env rm KEY [KEY2 ...]");
1423
+ return 1;
1424
+ }
1425
+ const res = await envRemove(token, slug, rest);
1426
+ for (const k of res.removed)
1427
+ out(` - ${k}`);
1428
+ for (const k of res.missing)
1429
+ out(` ? ${k} was not set`);
1430
+ if (res.removed.length) {
1431
+ out("");
1432
+ out("Applies on next `omg deploy`.");
1433
+ }
1434
+ return res.removed.length === 0 && res.missing.length ? 1 : 0;
1435
+ }
1436
+ case "pull": {
1437
+ const target = join5(root, flag("out") ?? ".env");
1438
+ if (existsSync2(target) && !args.includes("--force")) {
1439
+ out(`${target} already exists. Re-run with --force to overwrite.`);
1440
+ return 1;
1441
+ }
1442
+ const { env } = await envPull(token, slug);
1443
+ const keys = Object.keys(env);
1444
+ if (!keys.length) {
1445
+ out(`No env vars set for ${slug} \u2014 nothing to pull.`);
1446
+ return 0;
1447
+ }
1448
+ writeFileSync4(target, toDotenv(env), { mode: 384 });
1449
+ out(`Wrote ${keys.length} var${keys.length === 1 ? "" : "s"} to ${target}`);
1450
+ out("Add it to .gitignore \u2014 it holds real secrets.");
1451
+ return 0;
1452
+ }
1453
+ case "push":
1454
+ case "import": {
1455
+ const source = join5(root, flag("file") ?? ".env");
1456
+ if (!existsSync2(source)) {
1457
+ out(`No file at ${source}. Point at one with --file <path>.`);
1458
+ return 1;
1459
+ }
1460
+ const res = await envImport(token, slug, readFileSync4(source, "utf8"));
1461
+ for (const k of res.created)
1462
+ out(` + ${k}`);
1463
+ for (const k of res.updated)
1464
+ out(` ~ ${k} (updated)`);
1465
+ out("");
1466
+ out("Applies on next `omg deploy`.");
1467
+ return 0;
1468
+ }
1469
+ default:
1470
+ out(`Unknown: omg env ${sub}`);
1471
+ out("");
1472
+ out(" omg env list (masked)");
1473
+ out(" omg env set KEY=value set one or many");
1474
+ out(" omg env rm KEY remove");
1475
+ out(" omg env pull [--out .env] write real values locally");
1476
+ out(" omg env push [--file .env] import a local .env");
1477
+ return 1;
1478
+ }
1479
+ }
1480
+
1481
+ // src/visibility.ts
1482
+ var PUBLIC = "public";
1483
+ var OMG_USERS = "omg-users";
1484
+ function parseVisibility(arg) {
1485
+ const v = arg.trim().toLowerCase();
1486
+ if (v === PUBLIC || v === "anyone" || v === "open")
1487
+ return PUBLIC;
1488
+ if (v === OMG_USERS || v === "omg" || v === "users" || v === "private")
1489
+ return OMG_USERS;
1490
+ return null;
1491
+ }
1492
+ function describeVisibility(v) {
1493
+ return v === PUBLIC ? "public \u2014 anyone with the link" : "omg-users \u2014 any signed-in omg user";
1494
+ }
1495
+ async function runVisibility(opts) {
1496
+ const { args, slug, token, out } = opts;
1497
+ const target = args[0];
1498
+ if (!target) {
1499
+ const { visibility: visibility2, published } = await getVisibility(token, slug);
1500
+ out(`${slug}: ${describeVisibility(visibility2)}`);
1501
+ if (!published) {
1502
+ out("");
1503
+ out("Not published yet \u2014 run `omg deploy` first.");
1504
+ } else if (visibility2 === OMG_USERS) {
1505
+ out("");
1506
+ out("Non-browser clients (mobile apps, webhooks) will be redirected to sign in.");
1507
+ out("Run `omg visibility public` to serve anyone with the link.");
1508
+ }
1509
+ return 0;
1510
+ }
1511
+ const next = parseVisibility(target);
1512
+ if (!next) {
1513
+ out(`Unknown visibility "${target}".`);
1514
+ out("");
1515
+ out(" omg visibility public anyone with the link");
1516
+ out(" omg visibility omg-users any signed-in omg user (default)");
1517
+ return 1;
1518
+ }
1519
+ const { visibility } = await setVisibility(token, slug, next);
1520
+ out(`${slug}: ${describeVisibility(visibility)}`);
1521
+ out("");
1522
+ out("Live now \u2014 the gate is enforced at the edge, no redeploy needed.");
1523
+ return 0;
1524
+ }
1525
+
1309
1526
  // src/index.ts
1310
1527
  var argv = process.argv.slice(2);
1311
1528
  var cmd = argv[0] ?? "help";
@@ -1319,15 +1536,15 @@ var out = (msg = "") => process.stdout.write(msg + `
1319
1536
  var step = (msg) => out(` ${msg}`);
1320
1537
  function readLink(root) {
1321
1538
  try {
1322
- return JSON.parse(readFileSync4(join5(root, LINK_FILE), "utf8"));
1539
+ return JSON.parse(readFileSync5(join6(root, LINK_FILE), "utf8"));
1323
1540
  } catch {
1324
1541
  return null;
1325
1542
  }
1326
1543
  }
1327
1544
  function writeLink(root, link) {
1328
- const path = join5(root, LINK_FILE);
1545
+ const path = join6(root, LINK_FILE);
1329
1546
  mkdirSync3(dirname3(path), { recursive: true });
1330
- writeFileSync4(path, JSON.stringify(link, null, 2) + `
1547
+ writeFileSync5(path, JSON.stringify(link, null, 2) + `
1331
1548
  `);
1332
1549
  }
1333
1550
  var HELP = `omg \u2014 deploy a local project to omg.dev
@@ -1335,6 +1552,12 @@ var HELP = `omg \u2014 deploy a local project to omg.dev
1335
1552
  omg create <name> [--no-install]
1336
1553
  omg deploy [--name <name>] [--dir <path>] [--no-wait]
1337
1554
  omg status [--dir <path>]
1555
+ omg env list env vars (masked)
1556
+ omg env set KEY=value [KEY2=v2 ...] set (KEY - reads stdin)
1557
+ omg env rm KEY [KEY2 ...] remove
1558
+ omg env pull [--out .env] [--force] write real values locally
1559
+ omg env push [--file .env] import a local .env
1560
+ omg visibility [public|omg-users] the published app's access gate
1338
1561
  omg link <slug> [--dir <path>]
1339
1562
  omg login [--token <omg_sk_...>]
1340
1563
  omg logout
@@ -1435,6 +1658,25 @@ async function main() {
1435
1658
  out(`${link.slug}: ${status}`);
1436
1659
  return 0;
1437
1660
  }
1661
+ case "env": {
1662
+ const token = await requireToken();
1663
+ const link = readLink(root);
1664
+ if (!link?.slug) {
1665
+ out("Not linked to an app. Run `omg deploy` or `omg link <slug>` first.");
1666
+ return 1;
1667
+ }
1668
+ return runEnv({ args: argv.slice(1), slug: link.slug, token, root, flag, out });
1669
+ }
1670
+ case "visibility":
1671
+ case "access": {
1672
+ const token = await requireToken();
1673
+ const link = readLink(root);
1674
+ if (!link?.slug) {
1675
+ out("Not linked to an app. Run `omg deploy` or `omg link <slug>` first.");
1676
+ return 1;
1677
+ }
1678
+ return runVisibility({ args: argv.slice(1), slug: link.slug, token, out });
1679
+ }
1438
1680
  case "deploy": {
1439
1681
  const token = await requireToken();
1440
1682
  const link = readLink(root);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@omg-dev/cli",
3
- "version": "0.4.31",
3
+ "version": "0.4.33",
4
4
  "description": "Deploy and develop omg apps from your terminal.",
5
5
  "type": "module",
6
6
  "bin": {