@capgo/cli 4.8.1 → 4.8.2

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/CHANGELOG.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
4
4
 
5
+ ### [4.8.2](https://github.com/Cap-go/CLI/compare/v4.8.1...v4.8.2) (2024-05-11)
6
+
5
7
  ### [4.8.1](https://github.com/Cap-go/CLI/compare/v4.8.0...v4.8.1) (2024-05-11)
6
8
 
7
9
  ## [4.8.0](https://github.com/Cap-go/CLI/compare/v4.7.0...v4.8.0) (2024-05-10)
package/dist/index.js CHANGED
@@ -92373,7 +92373,7 @@ var {
92373
92373
  // package.json
92374
92374
  var package_default = {
92375
92375
  name: "@capgo/cli",
92376
- version: "4.8.1",
92376
+ version: "4.8.2",
92377
92377
  description: "A CLI to upload to capgo servers",
92378
92378
  author: "github.com/riderx",
92379
92379
  license: "Apache 2.0",
@@ -94031,11 +94031,38 @@ async function updateOrCreateChannel(supabase, update) {
94031
94031
  }
94032
94032
  function useLogSnag() {
94033
94033
  const logsnag = new import_logsnag.LogSnag({
94034
- token: "c124f5e9d0ce5bdd14bbb48f815d5583",
94035
- project: "capgo"
94034
+ token: import_node_process8.default.env.CAPGO_LOGSNAG ?? "c124f5e9d0ce5bdd14bbb48f815d5583",
94035
+ project: import_node_process8.default.env.CAPGO_LOGSNAG_PROJECT ?? "capgo"
94036
94036
  });
94037
94037
  return logsnag;
94038
94038
  }
94039
+ async function getOrganization(supabase, roles) {
94040
+ const { error: orgError, data: allOrganizations } = await supabase.rpc("get_orgs_v5");
94041
+ if (orgError) {
94042
+ f2.error("Cannot get the list of organizations - exiting");
94043
+ f2.error(`Error ${JSON.stringify(orgError)}`);
94044
+ program.error("");
94045
+ }
94046
+ const adminOrgs = allOrganizations.filter((org) => !!roles.find((role) => role === org.role));
94047
+ if (adminOrgs.length === 0) {
94048
+ f2.error(`Could not get organization with roles: ${roles.join(" or ")} because the user does not have any org`);
94049
+ program.error("");
94050
+ }
94051
+ const organizationUidRaw = adminOrgs.length > 1 ? await ie({
94052
+ message: "Please pick the organization that you want to insert to",
94053
+ options: adminOrgs.map((org) => {
94054
+ return { value: org.gid, label: org.name };
94055
+ })
94056
+ }) : adminOrgs[0].gid;
94057
+ if (eD(organizationUidRaw)) {
94058
+ f2.error("Canceled organization selection, exiting");
94059
+ program.error("");
94060
+ }
94061
+ const organizationUid = organizationUidRaw;
94062
+ const organization = allOrganizations.find((org) => org.gid === organizationUid);
94063
+ f2.info(`Using the organization "${organization.name}" as the app owner`);
94064
+ return organization;
94065
+ }
94039
94066
  var convertAppName = (appName) => appName.replace(/\./g, "--");
94040
94067
  async function verifyUser(supabase, apikey, keymod = ["all"]) {
94041
94068
  await checkKey(supabase, apikey, keymod);
@@ -94401,18 +94428,18 @@ function wait2(ms) {
94401
94428
  setTimeout(resolve2, ms);
94402
94429
  });
94403
94430
  }
94404
- async function markSnag(channel2, userId, snag, event, icon = "\u2705") {
94431
+ async function markSnag(channel2, orgId, snag, event, icon = "\u2705") {
94405
94432
  await snag.track({
94406
94433
  channel: channel2,
94407
94434
  event,
94408
94435
  icon,
94409
- user_id: userId,
94436
+ user_id: orgId,
94410
94437
  notify: false
94411
94438
  }).catch();
94412
94439
  }
94413
- async function cancelCommand(channel2, command, userId, snag) {
94440
+ async function cancelCommand(channel2, command, orgId, snag) {
94414
94441
  if (eD(command)) {
94415
- await markSnag(channel2, userId, snag, "canceled", "\u{1F937}");
94442
+ await markSnag(channel2, orgId, snag, "canceled", "\u{1F937}");
94416
94443
  import_node_process10.default.exit();
94417
94444
  }
94418
94445
  }
@@ -94428,13 +94455,13 @@ async function getStats(supabase, query) {
94428
94455
  }
94429
94456
  return null;
94430
94457
  }
94431
- async function waitLog(channel2, supabase, appId, snag, userId, deviceId) {
94458
+ async function waitLog(channel2, supabase, appId, snag, orgId, deviceId) {
94432
94459
  let loop = true;
94433
94460
  let now = (/* @__PURE__ */ new Date()).toISOString();
94434
94461
  const appIdUrl = convertAppName(appId);
94435
94462
  const config = await getLocalConfig();
94436
94463
  const baseUrl = `${config.hostWeb}/app/p/${appIdUrl}`;
94437
- await markSnag(channel2, userId, snag, "Use waitlog");
94464
+ await markSnag(channel2, orgId, snag, "Use waitlog");
94438
94465
  const query = {
94439
94466
  appId,
94440
94467
  devicesId: deviceId ? [deviceId] : void 0,
@@ -94452,12 +94479,12 @@ async function waitLog(channel2, supabase, appId, snag, userId, deviceId) {
94452
94479
  f2.info(`Log from Device: ${data.device_id}`);
94453
94480
  if (data.action === "get") {
94454
94481
  f2.info("Update Sent your your device, wait until event download complete");
94455
- await markSnag(channel2, userId, snag, "done");
94482
+ await markSnag(channel2, orgId, snag, "done");
94456
94483
  } else if (data.action.startsWith("download_")) {
94457
94484
  const action = data.action.split("_")[1];
94458
94485
  if (action === "complete") {
94459
94486
  f2.info("Your bundle has been downloaded on your device, background the app now and open it again to see the update");
94460
- await markSnag(channel2, userId, snag, "downloaded");
94487
+ await markSnag(channel2, orgId, snag, "downloaded");
94461
94488
  } else if (action === "fail") {
94462
94489
  f2.error("Your bundle has failed to download on your device.");
94463
94490
  f2.error("Please check if you have network connection and try again");
@@ -94467,7 +94494,7 @@ async function waitLog(channel2, supabase, appId, snag, userId, deviceId) {
94467
94494
  } else if (data.action === "set") {
94468
94495
  f2.info("Your bundle has been set on your device \u2764\uFE0F");
94469
94496
  loop = false;
94470
- await markSnag(channel2, userId, snag, "set");
94497
+ await markSnag(channel2, orgId, snag, "set");
94471
94498
  return Promise.resolve(data);
94472
94499
  } else if (data.action === "NoChannelOrOverride") {
94473
94500
  f2.error(`No default channel or override (channel/device) found, please create it here ${baseUrl}`);
@@ -94535,12 +94562,13 @@ async function debugApp(appId, options) {
94535
94562
  const userId = await verifyUser(supabase, options.apikey);
94536
94563
  f2.info(`Getting active bundle in Capgo`);
94537
94564
  await checkAppExistsAndHasPermissionOrgErr(supabase, options.apikey, appId, 4 /* admin */);
94565
+ const orgId = await getOrganizationId(supabase, appId);
94538
94566
  const doRun = await se({ message: `Automatic check if update working in device ?` });
94539
94567
  await cancelCommand("debug", doRun, userId, snag);
94540
94568
  if (doRun) {
94541
94569
  f2.info(`Wait logs sent to Capgo from ${appId} device, Put the app in background and open it again.`);
94542
94570
  f2.info("Waiting...");
94543
- await waitLog("debug", supabase, appId, snag, userId, deviceId);
94571
+ await waitLog("debug", supabase, appId, snag, orgId, deviceId);
94544
94572
  $e(`Done \u2705`);
94545
94573
  } else {
94546
94574
  $e(`Canceled \u274C`);
@@ -95426,13 +95454,15 @@ var src_default = new Mime_default(standard_default, other_default)._freeze();
95426
95454
 
95427
95455
  // src/app/add.ts
95428
95456
  async function addApp(appId, options, throwErr = true) {
95457
+ await addAppInternal(appId, options, void 0, throwErr);
95458
+ }
95459
+ async function addAppInternal(appId, options, organization, throwErr = true) {
95429
95460
  if (throwErr)
95430
95461
  oe(`Adding`);
95431
95462
  await checkLatest();
95432
95463
  options.apikey = options.apikey || findSavedKey();
95433
95464
  const config = await getConfig();
95434
95465
  appId = appId || config?.app?.appId;
95435
- const snag = useLogSnag();
95436
95466
  if (!options.apikey) {
95437
95467
  f2.error(`Missing API key, you need to provide a API key to upload your bundle`);
95438
95468
  program.error("");
@@ -95446,7 +95476,7 @@ async function addApp(appId, options, throwErr = true) {
95446
95476
  program.error("");
95447
95477
  }
95448
95478
  const supabase = await createSupabaseClient(options.apikey);
95449
- let userId = await verifyUser(supabase, options.apikey, ["write", "all"]);
95479
+ const userId = await verifyUser(supabase, options.apikey, ["write", "all"]);
95450
95480
  const appExist = await checkAppExists(supabase, appId);
95451
95481
  if (throwErr && appExist) {
95452
95482
  f2.error(`App ${appId} already exist`);
@@ -95454,27 +95484,9 @@ async function addApp(appId, options, throwErr = true) {
95454
95484
  } else if (appExist) {
95455
95485
  return false;
95456
95486
  }
95457
- const { error: orgError, data: allOrganizations } = await supabase.rpc("get_orgs_v5");
95458
- if (orgError) {
95459
- f2.error("Cannot get the list of organizations - exiting");
95460
- f2.error(`Error ${JSON.stringify(orgError)}`);
95461
- program.error("");
95462
- }
95463
- const adminOrgs = allOrganizations.filter((org) => org.role === "admin" || org.role === "super_admin");
95464
- const organizationUidRaw = adminOrgs.length > 1 ? await ie({
95465
- message: "Please pick the organization that you want to insert to",
95466
- options: adminOrgs.map((org) => {
95467
- return { value: org.gid, label: org.name };
95468
- })
95469
- }) : adminOrgs[0].gid;
95470
- if (eD(organizationUidRaw)) {
95471
- f2.error("Canceled organization selection, exiting");
95472
- program.error("");
95473
- }
95474
- const organizationUid = organizationUidRaw;
95475
- const organization = allOrganizations.find((org) => org.gid === organizationUid);
95476
- userId = organization.created_by;
95477
- f2.info(`Using the organization "${organization.name}" as the app owner`);
95487
+ if (!organization)
95488
+ organization = await getOrganization(supabase, ["admin", "super_admin"]);
95489
+ const organizationUid = organization.gid;
95478
95490
  await checkPlanValid(supabase, organizationUid, options.apikey, void 0, false);
95479
95491
  let { name, icon } = options;
95480
95492
  appId = appId || config?.app?.appId;
@@ -95539,16 +95551,6 @@ async function addApp(appId, options, throwErr = true) {
95539
95551
  f2.error(`Could not add app ${formatError(dbVersionError)}`);
95540
95552
  program.error("");
95541
95553
  }
95542
- await snag.track({
95543
- channel: "app",
95544
- event: "App Added",
95545
- icon: "\u{1F389}",
95546
- user_id: userId,
95547
- tags: {
95548
- "app-id": appId
95549
- },
95550
- notify: false
95551
- }).catch();
95552
95554
  f2.success(`App ${appId} added to Capgo. ${throwErr ? "You can upload a bundle now" : ""}`);
95553
95555
  if (throwErr) {
95554
95556
  $e(`Done \u2705`);
@@ -95566,23 +95568,23 @@ var codeInject = "CapacitorUpdater.notifyAppReady()";
95566
95568
  var regexImport = /import.*from.*/g;
95567
95569
  var defaultChannel = "production";
95568
95570
  var execOption = { stdio: "pipe" };
95569
- async function cancelCommand2(command, userId, snag) {
95571
+ async function cancelCommand2(command, orgId, snag) {
95570
95572
  if (eD(command)) {
95571
- await markSnag("onboarding-v2", userId, snag, "canceled", "\u{1F937}");
95573
+ await markSnag("onboarding-v2", orgId, snag, "canceled", "\u{1F937}");
95572
95574
  import_node_process16.default.exit();
95573
95575
  }
95574
95576
  }
95575
- async function markStep(userId, snag, step) {
95576
- return markSnag("onboarding-v2", userId, snag, `onboarding-step-${step}`);
95577
+ async function markStep(orgId, snag, step) {
95578
+ return markSnag("onboarding-v2", orgId, snag, `onboarding-step-${step}`);
95577
95579
  }
95578
- async function step2(userId, snag, appId, options) {
95580
+ async function step2(organization, snag, appId, options) {
95579
95581
  const pm2 = getPMAndCommand();
95580
95582
  const doAdd = await se({ message: `Add ${appId} in Capgo?` });
95581
- await cancelCommand2(doAdd, userId, snag);
95583
+ await cancelCommand2(doAdd, organization.gid, snag);
95582
95584
  if (doAdd) {
95583
95585
  const s = de();
95584
95586
  s.start(`Running: ${pm2.runner} @capgo/cli@latest app add ${appId}`);
95585
- const addRes = await addApp(appId, options, false);
95587
+ const addRes = await addAppInternal(appId, options, organization, false);
95586
95588
  if (!addRes)
95587
95589
  s.stop(`App already add \u2705`);
95588
95590
  else
@@ -95590,12 +95592,12 @@ async function step2(userId, snag, appId, options) {
95590
95592
  } else {
95591
95593
  f2.info(`Run yourself "${pm2.runner} @capgo/cli@latest app add ${appId}"`);
95592
95594
  }
95593
- await markStep(userId, snag, 2);
95595
+ await markStep(organization.gid, snag, 2);
95594
95596
  }
95595
- async function step3(userId, snag, apikey, appId) {
95597
+ async function step3(orgId, snag, apikey, appId) {
95596
95598
  const pm2 = getPMAndCommand();
95597
95599
  const doChannel = await se({ message: `Create default channel ${defaultChannel} for ${appId} in Capgo?` });
95598
- await cancelCommand2(doChannel, userId, snag);
95600
+ await cancelCommand2(doChannel, orgId, snag);
95599
95601
  if (doChannel) {
95600
95602
  const s = de();
95601
95603
  s.start(`Running: ${pm2.runner} @capgo/cli@latest channel add ${defaultChannel} ${appId} --default`);
@@ -95610,14 +95612,14 @@ async function step3(userId, snag, apikey, appId) {
95610
95612
  } else {
95611
95613
  f2.info(`Run yourself "${pm2.runner} @capgo/cli@latest channel add ${defaultChannel} ${appId} --default"`);
95612
95614
  }
95613
- await markStep(userId, snag, 3);
95615
+ await markStep(orgId, snag, 3);
95614
95616
  }
95615
95617
  var urlMigrateV6 = "https://capacitorjs.com/docs/updating/6-0";
95616
95618
  var urlMigrateV5 = "https://capacitorjs.com/docs/updating/5-0";
95617
- async function step4(userId, snag, apikey, appId) {
95619
+ async function step4(orgId, snag, apikey, appId) {
95618
95620
  const pm2 = getPMAndCommand();
95619
95621
  const doInstall = await se({ message: `Automatic Install "@capgo/capacitor-updater" dependency in ${appId}?` });
95620
- await cancelCommand2(doInstall, userId, snag);
95622
+ await cancelCommand2(doInstall, orgId, snag);
95621
95623
  if (doInstall) {
95622
95624
  const s = de();
95623
95625
  s.start(`Checking if @capgo/capacitor-updater is installed`);
@@ -95654,11 +95656,11 @@ async function step4(userId, snag, apikey, appId) {
95654
95656
  } else {
95655
95657
  f2.info(`Run yourself "${pm2.installCommand} @capgo/capacitor-updater@latest"`);
95656
95658
  }
95657
- await markStep(userId, snag, 4);
95659
+ await markStep(orgId, snag, 4);
95658
95660
  }
95659
- async function step5(userId, snag, apikey, appId) {
95661
+ async function step5(orgId, snag, apikey, appId) {
95660
95662
  const doAddCode = await se({ message: `Automatic Add "${codeInject}" code and import in ${appId}?` });
95661
- await cancelCommand2(doAddCode, userId, snag);
95663
+ await cancelCommand2(doAddCode, orgId, snag);
95662
95664
  if (doAddCode) {
95663
95665
  const s = de();
95664
95666
  s.start(`Adding @capacitor-updater to your main file`);
@@ -95695,7 +95697,7 @@ ${codeInject};
95695
95697
  (0, import_node_fs11.writeFileSync)(mainFilePath, newMainFileContent);
95696
95698
  s.stop(`Code added to ${mainFilePath} \u2705`);
95697
95699
  }
95698
- await markStep(userId, snag, 5);
95700
+ await markStep(orgId, snag, 5);
95699
95701
  } else {
95700
95702
  f2.info(`Add to your main file the following code:
95701
95703
 
@@ -95705,10 +95707,10 @@ ${codeInject};
95705
95707
  `);
95706
95708
  }
95707
95709
  }
95708
- async function step6(userId, snag, apikey, appId) {
95710
+ async function step6(orgId, snag, apikey, appId) {
95709
95711
  const pm2 = getPMAndCommand();
95710
95712
  const doEncrypt = await se({ message: `Automatic configure end-to-end encryption in ${appId} updates?` });
95711
- await cancelCommand2(doEncrypt, userId, snag);
95713
+ await cancelCommand2(doEncrypt, orgId, snag);
95712
95714
  if (doEncrypt) {
95713
95715
  const s = de();
95714
95716
  s.start(`Running: ${pm2.runner} @capgo/cli@latest key create`);
@@ -95721,14 +95723,14 @@ async function step6(userId, snag, apikey, appId) {
95721
95723
  } else {
95722
95724
  s.stop(`key created \u{1F511}`);
95723
95725
  }
95724
- markSnag("onboarding-v2", userId, snag, "Use encryption");
95726
+ markSnag("onboarding-v2", orgId, snag, "Use encryption");
95725
95727
  }
95726
- await markStep(userId, snag, 6);
95728
+ await markStep(orgId, snag, 6);
95727
95729
  }
95728
- async function step7(userId, snag, apikey, appId) {
95730
+ async function step7(orgId, snag, apikey, appId) {
95729
95731
  const pm2 = getPMAndCommand();
95730
95732
  const doBuild = await se({ message: `Automatic build ${appId} with "${pm2.pm} run build" ?` });
95731
- await cancelCommand2(doBuild, userId, snag);
95733
+ await cancelCommand2(doBuild, orgId, snag);
95732
95734
  if (doBuild) {
95733
95735
  const s = de();
95734
95736
  const projectType = await findProjectType();
@@ -95746,12 +95748,12 @@ async function step7(userId, snag, apikey, appId) {
95746
95748
  } else {
95747
95749
  f2.info(`Build yourself with command: ${pm2.pm} run build && ${pm2.runner} cap sync`);
95748
95750
  }
95749
- await markStep(userId, snag, 7);
95751
+ await markStep(orgId, snag, 7);
95750
95752
  }
95751
- async function step8(userId, snag, apikey, appId) {
95753
+ async function step8(orgId, snag, apikey, appId) {
95752
95754
  const pm2 = getPMAndCommand();
95753
95755
  const doBundle = await se({ message: `Automatic upload ${appId} bundle to Capgo?` });
95754
- await cancelCommand2(doBundle, userId, snag);
95756
+ await cancelCommand2(doBundle, orgId, snag);
95755
95757
  if (doBundle) {
95756
95758
  const s = de();
95757
95759
  s.start(`Running: ${pm2.runner} @capgo/cli@latest bundle upload`);
@@ -95770,12 +95772,12 @@ async function step8(userId, snag, apikey, appId) {
95770
95772
  } else {
95771
95773
  f2.info(`Upload yourself with command: ${pm2.runner} @capgo/cli@latest bundle upload`);
95772
95774
  }
95773
- await markStep(userId, snag, 8);
95775
+ await markStep(orgId, snag, 8);
95774
95776
  }
95775
- async function step9(userId, snag) {
95777
+ async function step9(orgId, snag) {
95776
95778
  const pm2 = getPMAndCommand();
95777
95779
  const doRun = await se({ message: `Run in device now ?` });
95778
- await cancelCommand2(doRun, userId, snag);
95780
+ await cancelCommand2(doRun, orgId, snag);
95779
95781
  if (doRun) {
95780
95782
  const plaformType = await ie({
95781
95783
  message: "Pick a platform to run your app",
@@ -95796,20 +95798,7 @@ async function step9(userId, snag) {
95796
95798
  } else {
95797
95799
  f2.info(`Run yourself with command: ${pm2.runner} cap run <ios|android>`);
95798
95800
  }
95799
- await markStep(userId, snag, 9);
95800
- }
95801
- async function step10(userId, snag, supabase, appId) {
95802
- const doRun = await se({ message: `Automatic check if update working in device ?` });
95803
- await cancelCommand2(doRun, userId, snag);
95804
- if (doRun) {
95805
- f2.info(`Wait logs sent to Capgo from ${appId} device, Put the app in background and open it again.`);
95806
- f2.info("Waiting...");
95807
- await waitLog("onboarding-v2", supabase, appId, snag, userId);
95808
- } else {
95809
- const appIdUrl = convertAppName(appId);
95810
- f2.info(`Check logs in https://web.capgo.app/app/p/${appIdUrl}/logs to see if update works.`);
95811
- }
95812
- await markStep(userId, snag, 10);
95801
+ await markStep(orgId, snag, 9);
95813
95802
  }
95814
95803
  async function initApp(apikeyCommand, appId, options) {
95815
95804
  const pm2 = getPMAndCommand();
@@ -95826,18 +95815,19 @@ async function initApp(apikeyCommand, appId, options) {
95826
95815
  log.stop("Login Done \u2705");
95827
95816
  }
95828
95817
  const supabase = await createSupabaseClient(apikey);
95829
- const userId = await verifyUser(supabase, apikey, ["upload", "all", "read", "write"]);
95830
- await markStep(userId, snag, 1);
95831
- await step2(userId, snag, appId, options);
95832
- await step3(userId, snag, apikey, appId);
95833
- await step4(userId, snag, apikey, appId);
95834
- await step5(userId, snag, apikey, appId);
95835
- await step6(userId, snag, apikey, appId);
95836
- await step7(userId, snag, apikey, appId);
95837
- await step8(userId, snag, apikey, appId);
95838
- await step9(userId, snag);
95839
- await step10(userId, snag, supabase, appId);
95840
- await markStep(userId, snag, 0);
95818
+ await verifyUser(supabase, apikey, ["upload", "all", "read", "write"]);
95819
+ const organization = await getOrganization(supabase, ["admin", "super_admin"]);
95820
+ const orgId = organization.gid;
95821
+ await markStep(orgId, snag, 1);
95822
+ await step2(organization, snag, appId, options);
95823
+ await step3(orgId, snag, apikey, appId);
95824
+ await step4(orgId, snag, apikey, appId);
95825
+ await step5(orgId, snag, apikey, appId);
95826
+ await step6(orgId, snag, apikey, appId);
95827
+ await step7(orgId, snag, apikey, appId);
95828
+ await step8(orgId, snag, apikey, appId);
95829
+ await step9(orgId, snag);
95830
+ await markStep(orgId, snag, 0);
95841
95831
  f2.info(`Welcome onboard \u2708\uFE0F!`);
95842
95832
  f2.info(`Your Capgo update system is setup`);
95843
95833
  f2.info(`Next time use \`${pm2.runner} @capgo/cli@latest bundle upload\` to only upload your bundle`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/cli",
3
- "version": "4.8.1",
3
+ "version": "4.8.2",
4
4
  "description": "A CLI to upload to capgo servers",
5
5
  "author": "github.com/riderx",
6
6
  "license": "Apache 2.0",
package/src/app/add.ts CHANGED
@@ -7,17 +7,24 @@ import * as p from '@clack/prompts'
7
7
  import { checkLatest } from '../api/update'
8
8
  import type { Options } from '../api/app'
9
9
  import { checkAppExists, newIconPath } from '../api/app'
10
+ import type {
11
+ Organization,
12
+ } from '../utils'
10
13
  import {
11
14
  checkPlanValid,
12
15
  createSupabaseClient,
13
16
  findSavedKey,
14
17
  formatError,
15
18
  getConfig,
16
- useLogSnag,
19
+ getOrganization,
17
20
  verifyUser,
18
21
  } from '../utils'
19
22
 
20
23
  export async function addApp(appId: string, options: Options, throwErr = true) {
24
+ await addAppInternal(appId, options, undefined, throwErr)
25
+ }
26
+
27
+ export async function addAppInternal(appId: string, options: Options, organization?: Organization, throwErr = true) {
21
28
  if (throwErr)
22
29
  p.intro(`Adding`)
23
30
 
@@ -25,7 +32,6 @@ export async function addApp(appId: string, options: Options, throwErr = true) {
25
32
  options.apikey = options.apikey || findSavedKey()
26
33
  const config = await getConfig()
27
34
  appId = appId || config?.app?.appId
28
- const snag = useLogSnag()
29
35
 
30
36
  if (!options.apikey) {
31
37
  p.log.error(`Missing API key, you need to provide a API key to upload your bundle`)
@@ -43,7 +49,7 @@ export async function addApp(appId: string, options: Options, throwErr = true) {
43
49
 
44
50
  const supabase = await createSupabaseClient(options.apikey)
45
51
 
46
- let userId = await verifyUser(supabase, options.apikey, ['write', 'all'])
52
+ const userId = await verifyUser(supabase, options.apikey, ['write', 'all'])
47
53
 
48
54
  // Check we have app access to this appId
49
55
  const appExist = await checkAppExists(supabase, appId)
@@ -55,36 +61,10 @@ export async function addApp(appId: string, options: Options, throwErr = true) {
55
61
  return false
56
62
  }
57
63
 
58
- const { error: orgError, data: allOrganizations } = await supabase
59
- .rpc('get_orgs_v5')
60
-
61
- if (orgError) {
62
- p.log.error('Cannot get the list of organizations - exiting')
63
- p.log.error(`Error ${JSON.stringify(orgError)}`)
64
- program.error('')
65
- }
66
-
67
- const adminOrgs = allOrganizations.filter(org => org.role === 'admin' || org.role === 'super_admin')
68
-
69
- const organizationUidRaw = (adminOrgs.length > 1)
70
- ? await p.select({
71
- message: 'Please pick the organization that you want to insert to',
72
- options: adminOrgs.map((org) => {
73
- return { value: org.gid, label: org.name }
74
- }),
75
- })
76
- : adminOrgs[0].gid
77
-
78
- if (p.isCancel(organizationUidRaw)) {
79
- p.log.error('Canceled organization selection, exiting')
80
- program.error('')
81
- }
82
-
83
- const organizationUid = organizationUidRaw as string
84
- const organization = allOrganizations.find(org => org.gid === organizationUid)!
85
- userId = organization.created_by
64
+ if (!organization)
65
+ organization = await getOrganization(supabase, ['admin', 'super_admin'])
86
66
 
87
- p.log.info(`Using the organization "${organization.name}" as the app owner`)
67
+ const organizationUid = organization.gid
88
68
 
89
69
  await checkPlanValid(supabase, organizationUid, options.apikey, undefined, false)
90
70
 
@@ -168,16 +148,6 @@ export async function addApp(appId: string, options: Options, throwErr = true) {
168
148
  p.log.error(`Could not add app ${formatError(dbVersionError)}`)
169
149
  program.error('')
170
150
  }
171
- await snag.track({
172
- channel: 'app',
173
- event: 'App Added',
174
- icon: '🎉',
175
- user_id: userId,
176
- tags: {
177
- 'app-id': appId,
178
- },
179
- notify: false,
180
- }).catch()
181
151
  p.log.success(`App ${appId} added to Capgo. ${throwErr ? 'You can upload a bundle now' : ''}`)
182
152
  if (throwErr) {
183
153
  p.outro(`Done ✅`)
package/src/app/debug.ts CHANGED
@@ -6,7 +6,7 @@ import type LogSnag from 'logsnag'
6
6
  import type { Database } from '../types/supabase.types'
7
7
  import { checkAppExistsAndHasPermissionOrgErr } from '../api/app'
8
8
  import { checkLatest } from '../api/update'
9
- import { OrganizationPerm, convertAppName, createSupabaseClient, findSavedKey, formatError, getConfig, getLocalConfig, useLogSnag, verifyUser } from '../utils'
9
+ import { OrganizationPerm, convertAppName, createSupabaseClient, findSavedKey, formatError, getConfig, getLocalConfig, getOrganizationId, useLogSnag, verifyUser } from '../utils'
10
10
 
11
11
  function wait(ms: number) {
12
12
  return new Promise((resolve) => {
@@ -19,19 +19,19 @@ export interface OptionsBaseDebug {
19
19
  device?: string
20
20
  }
21
21
 
22
- export async function markSnag(channel: string, userId: string, snag: LogSnag, event: string, icon = '✅') {
22
+ export async function markSnag(channel: string, orgId: string, snag: LogSnag, event: string, icon = '✅') {
23
23
  await snag.track({
24
24
  channel,
25
25
  event,
26
26
  icon,
27
- user_id: userId,
27
+ user_id: orgId,
28
28
  notify: false,
29
29
  }).catch()
30
30
  }
31
31
 
32
- export async function cancelCommand(channel: string, command: boolean | symbol, userId: string, snag: LogSnag) {
32
+ export async function cancelCommand(channel: string, command: boolean | symbol, orgId: string, snag: LogSnag) {
33
33
  if (p.isCancel(command)) {
34
- await markSnag(channel, userId, snag, 'canceled', '🤷')
34
+ await markSnag(channel, orgId, snag, 'canceled', '🤷')
35
35
  process.exit()
36
36
  }
37
37
  }
@@ -65,13 +65,13 @@ export async function getStats(supabase: SupabaseClient<Database>, query: QueryS
65
65
  return null
66
66
  }
67
67
 
68
- export async function waitLog(channel: string, supabase: SupabaseClient<Database>, appId: string, snag: LogSnag, userId: string, deviceId?: string) {
68
+ export async function waitLog(channel: string, supabase: SupabaseClient<Database>, appId: string, snag: LogSnag, orgId: string, deviceId?: string) {
69
69
  let loop = true
70
70
  let now = new Date().toISOString()
71
71
  const appIdUrl = convertAppName(appId)
72
72
  const config = await getLocalConfig()
73
73
  const baseUrl = `${config.hostWeb}/app/p/${appIdUrl}`
74
- await markSnag(channel, userId, snag, 'Use waitlog')
74
+ await markSnag(channel, orgId, snag, 'Use waitlog')
75
75
  const query: QueryStats = {
76
76
  appId,
77
77
  devicesId: deviceId ? [deviceId] : undefined,
@@ -90,13 +90,13 @@ export async function waitLog(channel: string, supabase: SupabaseClient<Database
90
90
  p.log.info(`Log from Device: ${data.device_id}`)
91
91
  if (data.action === 'get') {
92
92
  p.log.info('Update Sent your your device, wait until event download complete')
93
- await markSnag(channel, userId, snag, 'done')
93
+ await markSnag(channel, orgId, snag, 'done')
94
94
  }
95
95
  else if (data.action.startsWith('download_')) {
96
96
  const action = data.action.split('_')[1]
97
97
  if (action === 'complete') {
98
98
  p.log.info('Your bundle has been downloaded on your device, background the app now and open it again to see the update')
99
- await markSnag(channel, userId, snag, 'downloaded')
99
+ await markSnag(channel, orgId, snag, 'downloaded')
100
100
  }
101
101
  else if (action === 'fail') {
102
102
  p.log.error('Your bundle has failed to download on your device.')
@@ -109,7 +109,7 @@ export async function waitLog(channel: string, supabase: SupabaseClient<Database
109
109
  else if (data.action === 'set') {
110
110
  p.log.info('Your bundle has been set on your device ❤️')
111
111
  loop = false
112
- await markSnag(channel, userId, snag, 'set')
112
+ await markSnag(channel, orgId, snag, 'set')
113
113
  return Promise.resolve(data)
114
114
  }
115
115
  else if (data.action === 'NoChannelOrOverride') {
@@ -202,12 +202,14 @@ export async function debugApp(appId: string, options: OptionsBaseDebug) {
202
202
  // Check we have app access to this appId
203
203
  await checkAppExistsAndHasPermissionOrgErr(supabase, options.apikey, appId, OrganizationPerm.admin)
204
204
 
205
+ const orgId = await getOrganizationId(supabase, appId)
206
+
205
207
  const doRun = await p.confirm({ message: `Automatic check if update working in device ?` })
206
208
  await cancelCommand('debug', doRun, userId, snag)
207
209
  if (doRun) {
208
210
  p.log.info(`Wait logs sent to Capgo from ${appId} device, Put the app in background and open it again.`)
209
211
  p.log.info('Waiting...')
210
- await waitLog('debug', supabase, appId, snag, userId, deviceId)
212
+ await waitLog('debug', supabase, appId, snag, orgId, deviceId)
211
213
  p.outro(`Done ✅`)
212
214
  }
213
215
  else {
package/src/init.ts CHANGED
@@ -12,10 +12,11 @@ import { createKey } from './key'
12
12
  import { addChannel } from './channel/add'
13
13
  import { uploadBundle } from './bundle/upload'
14
14
  import { doLoginExists, login } from './login'
15
- import { addApp } from './app/add'
15
+ import { addAppInternal } from './app/add'
16
16
  import { checkLatest } from './api/update'
17
17
  import type { Options } from './api/app'
18
- import { convertAppName, createSupabaseClient, findBuildCommandForProjectType, findMainFile, findMainFileForProjectType, findProjectType, findSavedKey, getConfig, getPMAndCommand, useLogSnag, verifyUser } from './utils'
18
+ import type { Organization } from './utils'
19
+ import { convertAppName, createSupabaseClient, findBuildCommandForProjectType, findMainFile, findMainFileForProjectType, findProjectType, findSavedKey, getConfig, getOrganization, getPMAndCommand, useLogSnag, verifyUser } from './utils'
19
20
 
20
21
  interface SuperOptions extends Options {
21
22
  local: boolean
@@ -27,25 +28,25 @@ const regexImport = /import.*from.*/g
27
28
  const defaultChannel = 'production'
28
29
  const execOption = { stdio: 'pipe' }
29
30
 
30
- async function cancelCommand(command: boolean | symbol, userId: string, snag: LogSnag) {
31
+ async function cancelCommand(command: boolean | symbol, orgId: string, snag: LogSnag) {
31
32
  if (p.isCancel(command)) {
32
- await markSnag('onboarding-v2', userId, snag, 'canceled', '🤷')
33
+ await markSnag('onboarding-v2', orgId, snag, 'canceled', '🤷')
33
34
  process.exit()
34
35
  }
35
36
  }
36
37
 
37
- async function markStep(userId: string, snag: LogSnag, step: number | string) {
38
- return markSnag('onboarding-v2', userId, snag, `onboarding-step-${step}`)
38
+ async function markStep(orgId: string, snag: LogSnag, step: number | string) {
39
+ return markSnag('onboarding-v2', orgId, snag, `onboarding-step-${step}`)
39
40
  }
40
41
 
41
- async function step2(userId: string, snag: LogSnag, appId: string, options: SuperOptions) {
42
+ async function step2(organization: Organization, snag: LogSnag, appId: string, options: SuperOptions) {
42
43
  const pm = getPMAndCommand()
43
44
  const doAdd = await p.confirm({ message: `Add ${appId} in Capgo?` })
44
- await cancelCommand(doAdd, userId, snag)
45
+ await cancelCommand(doAdd, organization.gid, snag)
45
46
  if (doAdd) {
46
47
  const s = p.spinner()
47
48
  s.start(`Running: ${pm.runner} @capgo/cli@latest app add ${appId}`)
48
- const addRes = await addApp(appId, options, false)
49
+ const addRes = await addAppInternal(appId, options, organization, false)
49
50
  if (!addRes)
50
51
  s.stop(`App already add ✅`)
51
52
  else
@@ -54,13 +55,13 @@ async function step2(userId: string, snag: LogSnag, appId: string, options: Supe
54
55
  else {
55
56
  p.log.info(`Run yourself "${pm.runner} @capgo/cli@latest app add ${appId}"`)
56
57
  }
57
- await markStep(userId, snag, 2)
58
+ await markStep(organization.gid, snag, 2)
58
59
  }
59
60
 
60
- async function step3(userId: string, snag: LogSnag, apikey: string, appId: string) {
61
+ async function step3(orgId: string, snag: LogSnag, apikey: string, appId: string) {
61
62
  const pm = getPMAndCommand()
62
63
  const doChannel = await p.confirm({ message: `Create default channel ${defaultChannel} for ${appId} in Capgo?` })
63
- await cancelCommand(doChannel, userId, snag)
64
+ await cancelCommand(doChannel, orgId, snag)
64
65
  if (doChannel) {
65
66
  const s = p.spinner()
66
67
  // create production channel public
@@ -77,15 +78,15 @@ async function step3(userId: string, snag: LogSnag, apikey: string, appId: strin
77
78
  else {
78
79
  p.log.info(`Run yourself "${pm.runner} @capgo/cli@latest channel add ${defaultChannel} ${appId} --default"`)
79
80
  }
80
- await markStep(userId, snag, 3)
81
+ await markStep(orgId, snag, 3)
81
82
  }
82
83
 
83
84
  const urlMigrateV6 = 'https://capacitorjs.com/docs/updating/6-0'
84
85
  const urlMigrateV5 = 'https://capacitorjs.com/docs/updating/5-0'
85
- async function step4(userId: string, snag: LogSnag, apikey: string, appId: string) {
86
+ async function step4(orgId: string, snag: LogSnag, apikey: string, appId: string) {
86
87
  const pm = getPMAndCommand()
87
88
  const doInstall = await p.confirm({ message: `Automatic Install "@capgo/capacitor-updater" dependency in ${appId}?` })
88
- await cancelCommand(doInstall, userId, snag)
89
+ await cancelCommand(doInstall, orgId, snag)
89
90
  if (doInstall) {
90
91
  const s = p.spinner()
91
92
  s.start(`Checking if @capgo/capacitor-updater is installed`)
@@ -129,12 +130,12 @@ async function step4(userId: string, snag: LogSnag, apikey: string, appId: strin
129
130
  else {
130
131
  p.log.info(`Run yourself "${pm.installCommand} @capgo/capacitor-updater@latest"`)
131
132
  }
132
- await markStep(userId, snag, 4)
133
+ await markStep(orgId, snag, 4)
133
134
  }
134
135
 
135
- async function step5(userId: string, snag: LogSnag, apikey: string, appId: string) {
136
+ async function step5(orgId: string, snag: LogSnag, apikey: string, appId: string) {
136
137
  const doAddCode = await p.confirm({ message: `Automatic Add "${codeInject}" code and import in ${appId}?` })
137
- await cancelCommand(doAddCode, userId, snag)
138
+ await cancelCommand(doAddCode, orgId, snag)
138
139
  if (doAddCode) {
139
140
  const s = p.spinner()
140
141
  s.start(`Adding @capacitor-updater to your main file`)
@@ -172,17 +173,17 @@ async function step5(userId: string, snag: LogSnag, apikey: string, appId: strin
172
173
  writeFileSync(mainFilePath, newMainFileContent)
173
174
  s.stop(`Code added to ${mainFilePath} ✅`)
174
175
  }
175
- await markStep(userId, snag, 5)
176
+ await markStep(orgId, snag, 5)
176
177
  }
177
178
  else {
178
179
  p.log.info(`Add to your main file the following code:\n\n${importInject};\n\n${codeInject};\n`)
179
180
  }
180
181
  }
181
182
 
182
- async function step6(userId: string, snag: LogSnag, apikey: string, appId: string) {
183
+ async function step6(orgId: string, snag: LogSnag, apikey: string, appId: string) {
183
184
  const pm = getPMAndCommand()
184
185
  const doEncrypt = await p.confirm({ message: `Automatic configure end-to-end encryption in ${appId} updates?` })
185
- await cancelCommand(doEncrypt, userId, snag)
186
+ await cancelCommand(doEncrypt, orgId, snag)
186
187
  if (doEncrypt) {
187
188
  const s = p.spinner()
188
189
  s.start(`Running: ${pm.runner} @capgo/cli@latest key create`)
@@ -196,15 +197,15 @@ async function step6(userId: string, snag: LogSnag, apikey: string, appId: strin
196
197
  else {
197
198
  s.stop(`key created 🔑`)
198
199
  }
199
- markSnag('onboarding-v2', userId, snag, 'Use encryption')
200
+ markSnag('onboarding-v2', orgId, snag, 'Use encryption')
200
201
  }
201
- await markStep(userId, snag, 6)
202
+ await markStep(orgId, snag, 6)
202
203
  }
203
204
 
204
- async function step7(userId: string, snag: LogSnag, apikey: string, appId: string) {
205
+ async function step7(orgId: string, snag: LogSnag, apikey: string, appId: string) {
205
206
  const pm = getPMAndCommand()
206
207
  const doBuild = await p.confirm({ message: `Automatic build ${appId} with "${pm.pm} run build" ?` })
207
- await cancelCommand(doBuild, userId, snag)
208
+ await cancelCommand(doBuild, orgId, snag)
208
209
  if (doBuild) {
209
210
  const s = p.spinner()
210
211
  const projectType = await findProjectType()
@@ -224,13 +225,13 @@ async function step7(userId: string, snag: LogSnag, apikey: string, appId: strin
224
225
  else {
225
226
  p.log.info(`Build yourself with command: ${pm.pm} run build && ${pm.runner} cap sync`)
226
227
  }
227
- await markStep(userId, snag, 7)
228
+ await markStep(orgId, snag, 7)
228
229
  }
229
230
 
230
- async function step8(userId: string, snag: LogSnag, apikey: string, appId: string) {
231
+ async function step8(orgId: string, snag: LogSnag, apikey: string, appId: string) {
231
232
  const pm = getPMAndCommand()
232
233
  const doBundle = await p.confirm({ message: `Automatic upload ${appId} bundle to Capgo?` })
233
- await cancelCommand(doBundle, userId, snag)
234
+ await cancelCommand(doBundle, orgId, snag)
234
235
  if (doBundle) {
235
236
  const s = p.spinner()
236
237
  s.start(`Running: ${pm.runner} @capgo/cli@latest bundle upload`)
@@ -251,13 +252,13 @@ async function step8(userId: string, snag: LogSnag, apikey: string, appId: strin
251
252
  else {
252
253
  p.log.info(`Upload yourself with command: ${pm.runner} @capgo/cli@latest bundle upload`)
253
254
  }
254
- await markStep(userId, snag, 8)
255
+ await markStep(orgId, snag, 8)
255
256
  }
256
257
 
257
- async function step9(userId: string, snag: LogSnag) {
258
+ async function step9(orgId: string, snag: LogSnag) {
258
259
  const pm = getPMAndCommand()
259
260
  const doRun = await p.confirm({ message: `Run in device now ?` })
260
- await cancelCommand(doRun, userId, snag)
261
+ await cancelCommand(doRun, orgId, snag)
261
262
  if (doRun) {
262
263
  const plaformType = await p.select({
263
264
  message: 'Pick a platform to run your app',
@@ -280,22 +281,22 @@ async function step9(userId: string, snag: LogSnag) {
280
281
  else {
281
282
  p.log.info(`Run yourself with command: ${pm.runner} cap run <ios|android>`)
282
283
  }
283
- await markStep(userId, snag, 9)
284
+ await markStep(orgId, snag, 9)
284
285
  }
285
286
 
286
- async function step10(userId: string, snag: LogSnag, supabase: SupabaseClient<Database>, appId: string) {
287
+ async function _step10(orgId: string, snag: LogSnag, supabase: SupabaseClient<Database>, appId: string) {
287
288
  const doRun = await p.confirm({ message: `Automatic check if update working in device ?` })
288
- await cancelCommand(doRun, userId, snag)
289
+ await cancelCommand(doRun, orgId, snag)
289
290
  if (doRun) {
290
291
  p.log.info(`Wait logs sent to Capgo from ${appId} device, Put the app in background and open it again.`)
291
292
  p.log.info('Waiting...')
292
- await waitLog('onboarding-v2', supabase, appId, snag, userId)
293
+ await waitLog('onboarding-v2', supabase, appId, snag, orgId)
293
294
  }
294
295
  else {
295
296
  const appIdUrl = convertAppName(appId)
296
297
  p.log.info(`Check logs in https://web.capgo.app/app/p/${appIdUrl}/logs to see if update works.`)
297
298
  }
298
- await markStep(userId, snag, 10)
299
+ await markStep(orgId, snag, 10)
299
300
  }
300
301
 
301
302
  export async function initApp(apikeyCommand: string, appId: string, options: SuperOptions) {
@@ -315,20 +316,24 @@ export async function initApp(apikeyCommand: string, appId: string, options: Sup
315
316
  }
316
317
 
317
318
  const supabase = await createSupabaseClient(apikey)
318
- const userId = await verifyUser(supabase, apikey, ['upload', 'all', 'read', 'write'])
319
- await markStep(userId, snag, 1)
319
+ await verifyUser(supabase, apikey, ['upload', 'all', 'read', 'write'])
320
320
 
321
- await step2(userId, snag, appId, options)
322
- await step3(userId, snag, apikey, appId)
323
- await step4(userId, snag, apikey, appId)
324
- await step5(userId, snag, apikey, appId)
325
- await step6(userId, snag, apikey, appId)
326
- await step7(userId, snag, apikey, appId)
327
- await step8(userId, snag, apikey, appId)
328
- await step9(userId, snag)
329
- await step10(userId, snag, supabase, appId)
321
+ const organization = await getOrganization(supabase, ['admin', 'super_admin'])
322
+ const orgId = organization.gid
330
323
 
331
- await markStep(userId, snag, 0)
324
+ await markStep(orgId, snag, 1)
325
+
326
+ await step2(organization, snag, appId, options)
327
+ await step3(orgId, snag, apikey, appId)
328
+ await step4(orgId, snag, apikey, appId)
329
+ await step5(orgId, snag, apikey, appId)
330
+ await step6(orgId, snag, apikey, appId)
331
+ await step7(orgId, snag, apikey, appId)
332
+ await step8(orgId, snag, apikey, appId)
333
+ await step9(orgId, snag)
334
+ // await step10(orgId, snag, supabase, appId)
335
+
336
+ await markStep(orgId, snag, 0)
332
337
  p.log.info(`Welcome onboard ✈️!`)
333
338
  p.log.info(`Your Capgo update system is setup`)
334
339
  p.log.info(`Next time use \`${pm.runner} @capgo/cli@latest bundle upload\` to only upload your bundle`)
package/src/utils.ts CHANGED
@@ -22,6 +22,10 @@ export const defaultHost = 'https://capgo.app'
22
22
  export const defaultApiHost = 'https://api.capgo.app'
23
23
  export const defaultHostWeb = 'https://web.capgo.app'
24
24
 
25
+ export type ArrayElement<ArrayType extends readonly unknown[]> =
26
+ ArrayType extends readonly (infer ElementType)[] ? ElementType : never
27
+ export type Organization = ArrayElement<Database['public']['Functions']['get_orgs_v5']['Returns']>
28
+
25
29
  export const regexSemver = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/
26
30
  export const formatError = (error: any) => error ? `\n${prettyjson.render(error)}` : ''
27
31
 
@@ -653,12 +657,50 @@ export async function updateOrCreateChannel(supabase: SupabaseClient<Database>,
653
657
 
654
658
  export function useLogSnag(): LogSnag {
655
659
  const logsnag = new LogSnag({
656
- token: 'c124f5e9d0ce5bdd14bbb48f815d5583',
657
- project: 'capgo',
660
+ token: process.env.CAPGO_LOGSNAG ?? 'c124f5e9d0ce5bdd14bbb48f815d5583',
661
+ project: process.env.CAPGO_LOGSNAG_PROJECT ?? 'capgo',
658
662
  })
659
663
  return logsnag
660
664
  }
661
665
 
666
+ export async function getOrganization(supabase: SupabaseClient<Database>, roles: string[]): Promise<Organization> {
667
+ const { error: orgError, data: allOrganizations } = await supabase
668
+ .rpc('get_orgs_v5')
669
+
670
+ if (orgError) {
671
+ p.log.error('Cannot get the list of organizations - exiting')
672
+ p.log.error(`Error ${JSON.stringify(orgError)}`)
673
+ program.error('')
674
+ }
675
+
676
+ const adminOrgs = allOrganizations.filter(org => !!roles.find(role => role === org.role))
677
+
678
+ if (adminOrgs.length === 0) {
679
+ p.log.error(`Could not get organization with roles: ${roles.join(' or ')} because the user does not have any org`)
680
+ program.error('')
681
+ }
682
+
683
+ const organizationUidRaw = (adminOrgs.length > 1)
684
+ ? await p.select({
685
+ message: 'Please pick the organization that you want to insert to',
686
+ options: adminOrgs.map((org) => {
687
+ return { value: org.gid, label: org.name }
688
+ }),
689
+ })
690
+ : adminOrgs[0].gid
691
+
692
+ if (p.isCancel(organizationUidRaw)) {
693
+ p.log.error('Canceled organization selection, exiting')
694
+ program.error('')
695
+ }
696
+
697
+ const organizationUid = organizationUidRaw as string
698
+ const organization = allOrganizations.find(org => org.gid === organizationUid)!
699
+
700
+ p.log.info(`Using the organization "${organization.name}" as the app owner`)
701
+ return organization
702
+ }
703
+
662
704
  export const convertAppName = (appName: string) => appName.replace(/\./g, '--')
663
705
 
664
706
  export async function verifyUser(supabase: SupabaseClient<Database>, apikey: string, keymod: Database['public']['Enums']['key_mode'][] = ['all']) {