liftbay 0.4.0 → 0.4.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.
Files changed (2) hide show
  1. package/dist/index.js +78 -25
  2. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -25899,7 +25899,7 @@ import { chmodSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync }
25899
25899
  import { homedir } from "os";
25900
25900
  import { join } from "path";
25901
25901
 
25902
- // node_modules/openapi-fetch/dist/index.mjs
25902
+ // ../sdk/node_modules/openapi-fetch/dist/index.mjs
25903
25903
  var PATH_PARAM_RE = /\{[^{}]+\}/g;
25904
25904
  var supportsRequestInitExt = () => {
25905
25905
  return typeof process === "object" && Number.parseInt(process?.versions?.node?.substring(0, 2)) >= 18 && process.versions.undici;
@@ -26375,7 +26375,7 @@ function removeTrailingSlash(url) {
26375
26375
  return url;
26376
26376
  }
26377
26377
 
26378
- // node_modules/@liftbay/sdk/dist/index.js
26378
+ // ../sdk/dist/index.js
26379
26379
  var LiftbayApiError = class extends Error {
26380
26380
  constructor(status2, code, message, fields = {}) {
26381
26381
  super(message);
@@ -27222,6 +27222,7 @@ function cancelled(value) {
27222
27222
  }
27223
27223
  return value;
27224
27224
  }
27225
+ var slugifyProject = (s) => s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 48);
27225
27226
  var slugify = (s) => s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40);
27226
27227
  async function createFirstOrg(lb, given) {
27227
27228
  const me = await unwrap(lb.GET("/v1/auth/me"));
@@ -27254,21 +27255,37 @@ async function ensureLinked(app, opts) {
27254
27255
  }
27255
27256
  const projects = await unwrap(lb.GET("/v1/orgs/{org}/projects", { params: { path: { org } } }));
27256
27257
  let slug = opts.project;
27258
+ let projectName;
27257
27259
  if (!slug) {
27258
27260
  const match = projects.find((pr) => pr.slug === app.slug);
27259
27261
  if (opts.yes || !isInteractive()) slug = match?.slug ?? app.slug;
27260
27262
  else {
27263
+ const taken = projects.some((pr) => pr.slug === app.slug);
27261
27264
  const choice = cancelled(
27262
27265
  await select({
27263
27266
  message: "Liftbay project",
27264
27267
  options: [
27265
- { value: "__new__", label: `Create "${app.slug}"`, hint: "new project" },
27266
- ...projects.map((pr) => ({ value: pr.slug, label: pr.name, hint: pr.slug }))
27268
+ ...taken ? [] : [{ value: "__new__", label: `Create "${app.name}"`, hint: `new project \xB7 liftbay.dev/${org}/${app.slug}` }],
27269
+ { value: "__named__", label: "Create a project with another name" },
27270
+ ...projects.map((pr) => ({ value: pr.slug, label: pr.name, hint: `existing \xB7 ${pr.slug}` }))
27267
27271
  ],
27268
- initialValue: match?.slug ?? "__new__"
27272
+ initialValue: match?.slug ?? (taken ? "__named__" : "__new__")
27269
27273
  })
27270
27274
  );
27271
- slug = choice === "__new__" ? app.slug : choice;
27275
+ if (choice === "__named__") {
27276
+ projectName = cancelled(
27277
+ await text({
27278
+ message: "Project name",
27279
+ initialValue: app.name,
27280
+ validate: (v) => {
27281
+ const s = slugifyProject(v ?? "");
27282
+ if (s.length < 2) return "At least 2 letters or digits";
27283
+ if (projects.some((pr) => pr.slug === s)) return `${s} already exists: pick it from the list instead`;
27284
+ }
27285
+ })
27286
+ );
27287
+ slug = slugifyProject(projectName);
27288
+ } else slug = choice === "__new__" ? app.slug : choice;
27272
27289
  }
27273
27290
  }
27274
27291
  let project2 = projects.find((pr) => pr.slug === slug);
@@ -27276,7 +27293,7 @@ async function ensureLinked(app, opts) {
27276
27293
  project2 = await unwrap(
27277
27294
  lb.POST("/v1/orgs/{org}/projects", {
27278
27295
  params: { path: { org } },
27279
- body: { name: app.name, slug, framework: app.framework, bundleId: app.bundleId, androidPackage: app.androidPackage }
27296
+ body: { name: projectName ?? app.name, slug, framework: app.framework, bundleId: app.bundleId, androidPackage: app.androidPackage }
27280
27297
  })
27281
27298
  );
27282
27299
  log.success(`Created project ${import_picocolors4.default.bold(`${org}/${project2.slug}`)} with development, preview and production environments`);
@@ -27574,6 +27591,34 @@ async function waitFor(lb, config, message, done) {
27574
27591
  spin.error("Stopped waiting");
27575
27592
  return null;
27576
27593
  }
27594
+ async function waitForInstall(lb, config, attempt) {
27595
+ const spin = spinner();
27596
+ spin.start(`Waiting for the GitHub App to be installed ${import_picocolors6.default.dim("(Ctrl-C to stop)")}`);
27597
+ const until = Date.now() + WAIT_MINUTES * 6e4;
27598
+ let last = "waiting";
27599
+ while (Date.now() < until) {
27600
+ await sleep2(3e3);
27601
+ const a2 = attempt ? (await lb.GET("/v1/orgs/{org}/github/install/{attempt}", { params: { path: { org: config.org, attempt } } })).data : void 0;
27602
+ if (a2 && a2.status !== last) {
27603
+ last = a2.status;
27604
+ if (a2.status === "needs_sign_in") spin.message(`GitHub is done. Sign in to Liftbay in that browser to finish linking ${import_picocolors6.default.dim("(Ctrl-C to stop)")}`);
27605
+ else if (a2.status !== "waiting" && a2.status !== "connected") {
27606
+ spin.error("GitHub didn't connect");
27607
+ return { ok: false, message: a2.message };
27608
+ }
27609
+ }
27610
+ const s = await status(lb, config);
27611
+ if (s.connected) {
27612
+ spin.stop(`GitHub App installed for ${s.repo}`);
27613
+ return { ok: true, status: s };
27614
+ }
27615
+ if (a2?.status === "connected") {
27616
+ spin.message(`Installed on ${s.repo.split("/")[0]}, but without access to ${s.repo}: on GitHub, Configure the app and select the repository ${import_picocolors6.default.dim("(Ctrl-C to stop)")}`);
27617
+ }
27618
+ }
27619
+ spin.error("Stopped waiting");
27620
+ return { ok: false, message: "The GitHub App wasn't installed within 15 minutes." };
27621
+ }
27577
27622
  async function ensureGithub(opts) {
27578
27623
  const config = requireConfig();
27579
27624
  const lb = client();
@@ -27586,28 +27631,36 @@ async function ensureGithub(opts) {
27586
27631
  }
27587
27632
  const owner = s.repo.split("/")[0];
27588
27633
  if (!s.connected) {
27589
- const { url } = await unwrap(lb.POST("/v1/orgs/{org}/github/install", { params: { path: { org: config.org } } }));
27590
27634
  log.warn(`The Liftbay GitHub App isn't installed for ${import_picocolors6.default.bold(s.repo)} yet. Builds run through it.`);
27591
- if (!interactive) {
27592
- if (opts.soft) return { ...s, installUrl: url };
27593
- fail(`Install the Liftbay GitHub App on ${owner} (give it access to ${s.repo}): ${url}
27635
+ for (let round = 0; ; round++) {
27636
+ const { url, attempt } = await unwrap(lb.POST("/v1/orgs/{org}/github/install", { params: { path: { org: config.org } } }));
27637
+ if (!interactive) {
27638
+ if (opts.soft) return { ...s, installUrl: url };
27639
+ fail(`Install the Liftbay GitHub App on ${owner} (give it access to ${s.repo}): ${url}
27594
27640
  Then run this again. In the dashboard: ${dashboardUrl()}/${config.org}/github`);
27595
- }
27596
- log.step("Install the Liftbay GitHub App");
27597
- log.message(
27598
- import_picocolors6.default.dim(`Pick ${import_picocolors6.default.bold(owner)}, give it access to ${import_picocolors6.default.bold(s.repo.split("/")[1])} (or all repositories) and save.
27599
- Already installed on GitHub? Choose Configure, check the repository is selected and save.`)
27600
- );
27601
- console.log(`
27641
+ }
27642
+ log.step(round ? "Install the Liftbay GitHub App (new link)" : "Install the Liftbay GitHub App");
27643
+ log.message(
27644
+ import_picocolors6.default.dim(
27645
+ `Pick ${import_picocolors6.default.bold(owner)}, give it access to ${import_picocolors6.default.bold(s.repo.split("/")[1])} (or all repositories), and install.
27646
+ Already installed on ${owner}? Choose Configure, make sure the repository is selected, and save.
27647
+ Copying the link instead? Open it in a browser signed in to ${dashboardUrl().replace(/^https?:\/\//, "")}, or sign in when asked.`
27648
+ )
27649
+ );
27650
+ console.log(`
27602
27651
  ${import_picocolors6.default.cyan(url)}
27603
27652
  `);
27604
- if (!cancelled(await confirm({ message: "Open this in your browser now?", initialValue: true }))) {
27605
- fail(`Install it from the link above, or at ${dashboardUrl()}/${config.org}/github, then run this again.`);
27653
+ openBrowser2(url);
27654
+ const result = await waitForInstall(lb, config, attempt);
27655
+ if (result.ok) {
27656
+ s = result.status;
27657
+ break;
27658
+ }
27659
+ log.error(result.message);
27660
+ if (!cancelled(await confirm({ message: "Try again with a new link?", initialValue: true }))) {
27661
+ fail(`GitHub isn't connected. Finish at ${dashboardUrl()}/${config.org}/github, or run \`liftbay github connect\` again.`);
27662
+ }
27606
27663
  }
27607
- openBrowser2(url);
27608
- const done = await waitFor(lb, config, "Waiting for the GitHub App to be installed", (x) => x.connected);
27609
- if (!done) fail(`The GitHub App isn't installed yet. Finish at ${dashboardUrl()}/${config.org}/github, then run this again.`);
27610
- s = done;
27611
27664
  }
27612
27665
  if (opts.needWorkflow && s.workflow !== "present") {
27613
27666
  const branch = s.defaultBranch ?? "the default branch";
@@ -29129,7 +29182,7 @@ async function channels() {
29129
29182
  }
29130
29183
 
29131
29184
  // src/index.ts
29132
- var program2 = new Command("liftbay").description("Build, ship and update React Native apps").version("0.4.0").option("--json", "print the result as JSON on stdout (progress goes to stderr; never prompts). Also LIFTBAY_JSON=1").hook("preAction", () => {
29185
+ var program2 = new Command("liftbay").description("Build, ship and update React Native apps").version("0.4.1").option("--json", "print the result as JSON on stdout (progress goes to stderr; never prompts). Also LIFTBAY_JSON=1").hook("preAction", () => {
29133
29186
  if (program2.opts().json || process.env.LIFTBAY_JSON === "1") enableJson();
29134
29187
  });
29135
29188
  var wrap = (fn) => async (...args) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "liftbay",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Build, sign, submit and update React Native apps from your own CI.",
5
5
  "keywords": [
6
6
  "react-native",
@@ -49,7 +49,7 @@
49
49
  "devDependencies": {
50
50
  "@clack/core": "1.5.1",
51
51
  "@clack/prompts": "^1.8.1",
52
- "@liftbay/sdk": "^0.1.0",
52
+ "@liftbay/sdk": "^0.1.1",
53
53
  "@types/node": "^26.6.4",
54
54
  "@types/qrcode": "^1.5.6",
55
55
  "@types/node-forge": "^1.3.14",