@capgo/cli 4.2.3 → 4.2.7

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,35 @@
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.2.7](https://github.com/Cap-go/CLI/compare/v4.2.6...v4.2.7) (2024-03-23)
6
+
7
+
8
+ ### Bug Fixes
9
+
10
+ * lint issue ([a836b3c](https://github.com/Cap-go/CLI/commit/a836b3cf59a6396f2200a3a5383d5dd10e19ad07))
11
+
12
+ ### [4.2.6](https://github.com/Cap-go/CLI/compare/v4.2.5...v4.2.6) (2024-03-23)
13
+
14
+
15
+ ### Bug Fixes
16
+
17
+ * lint ([92b0e46](https://github.com/Cap-go/CLI/commit/92b0e462b7cc3d2c77b585d6596aba746df16b71))
18
+ * upload ([394b2ce](https://github.com/Cap-go/CLI/commit/394b2ceb1947de2e86870f1f3d57e9efe646b40a))
19
+
20
+ ### [4.2.5](https://github.com/Cap-go/CLI/compare/v4.2.4...v4.2.5) (2024-03-22)
21
+
22
+
23
+ ### Bug Fixes
24
+
25
+ * zip json output ([4028f9b](https://github.com/Cap-go/CLI/commit/4028f9b79b3c53a7967a137784918f4ac614d011))
26
+
27
+ ### [4.2.4](https://github.com/Cap-go/CLI/compare/v4.2.3...v4.2.4) (2024-03-22)
28
+
29
+
30
+ ### Bug Fixes
31
+
32
+ * make no-key works ([11eed1a](https://github.com/Cap-go/CLI/commit/11eed1a515d44800ef369303dd14c5218b2164ca))
33
+
5
34
  ### [4.2.3](https://github.com/Cap-go/CLI/compare/v4.2.2...v4.2.3) (2024-03-12)
6
35
 
7
36
 
package/dist/index.js CHANGED
@@ -61137,7 +61137,7 @@ var {
61137
61137
  // package.json
61138
61138
  var package_default = {
61139
61139
  name: "@capgo/cli",
61140
- version: "4.2.3",
61140
+ version: "4.2.7",
61141
61141
  description: "A CLI to upload to capgo servers",
61142
61142
  main: "dist/index.js",
61143
61143
  bin: {
@@ -62309,6 +62309,7 @@ var baseKeyPub = `${baseKey}.pub`;
62309
62309
  var defaultHost = "https://capgo.app";
62310
62310
  var defaultApiHost = "https://api.capgo.app";
62311
62311
  var defaultHostWeb = "https://web.capgo.app";
62312
+ var EMPTY_UUID = "00000000-0000-0000-0000-000000000000";
62312
62313
  var 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-]+)*))?$/;
62313
62314
  var formatError = (error) => error ? `
62314
62315
  ${import_prettyjson.default.render(error)}` : "";
@@ -62411,17 +62412,13 @@ async function getAppOwner(supabase, appId) {
62411
62412
  }
62412
62413
  return data.user_id;
62413
62414
  }
62414
- async function isAllowedApp(supabase, apikey, appId) {
62415
- const { data } = await supabase.rpc("is_app_owner", { apikey, appid: appId }).single();
62416
- return !!data;
62417
- }
62418
62415
  var OrganizationPerm = /* @__PURE__ */ ((OrganizationPerm2) => {
62419
62416
  OrganizationPerm2[OrganizationPerm2["none"] = 0] = "none";
62420
62417
  OrganizationPerm2[OrganizationPerm2["read"] = 1] = "read";
62421
62418
  OrganizationPerm2[OrganizationPerm2["upload"] = 2] = "upload";
62422
62419
  OrganizationPerm2[OrganizationPerm2["write"] = 3] = "write";
62423
62420
  OrganizationPerm2[OrganizationPerm2["admin"] = 4] = "admin";
62424
- OrganizationPerm2[OrganizationPerm2["owner"] = 5] = "owner";
62421
+ OrganizationPerm2[OrganizationPerm2["super_admin"] = 5] = "super_admin";
62425
62422
  return OrganizationPerm2;
62426
62423
  })(OrganizationPerm || {});
62427
62424
  var hasOrganizationPerm = (perm, required) => perm >= required;
@@ -62457,7 +62454,7 @@ async function isAllowedAppOrg(supabase, apikey, appId) {
62457
62454
  break;
62458
62455
  }
62459
62456
  case "perm_owner": {
62460
- perm = 5 /* owner */;
62457
+ perm = 5 /* super_admin */;
62461
62458
  break;
62462
62459
  }
62463
62460
  default: {
@@ -62568,10 +62565,10 @@ async function findMainFile() {
62568
62565
  async function updateOrCreateVersion(supabase, update) {
62569
62566
  return supabase.from("app_versions").upsert(update, { onConflict: "name,app_id" }).eq("app_id", update.app_id).eq("name", update.name);
62570
62567
  }
62571
- async function uploadUrl(supabase, appId, bucketId) {
62568
+ async function uploadUrl(supabase, appId, name) {
62572
62569
  const data = {
62573
62570
  app_id: appId,
62574
- bucket_id: bucketId
62571
+ name
62575
62572
  };
62576
62573
  try {
62577
62574
  const pathUploadLink = "private/upload_link";
@@ -62878,14 +62875,6 @@ The app size is ${mbSize} Mb, this may take a while to download for users
62878
62875
  (0, import_node_fs6.writeFileSync)(name, zipped);
62879
62876
  if (!json)
62880
62877
  s2.stop(`Saved to ${name}`);
62881
- if (options.json) {
62882
- const output = {
62883
- bundle: bundle2,
62884
- filename: name,
62885
- checksum
62886
- };
62887
- f2.info(formatError(output));
62888
- }
62889
62878
  await snag.track({
62890
62879
  channel: "app",
62891
62880
  event: "App zip",
@@ -62897,6 +62886,14 @@ The app size is ${mbSize} Mb, this may take a while to download for users
62897
62886
  }).catch();
62898
62887
  if (!json)
62899
62888
  $e(`Done \u2705`);
62889
+ if (json) {
62890
+ const output = {
62891
+ bundle: bundle2,
62892
+ filename: name,
62893
+ checksum
62894
+ };
62895
+ console.log(JSON.stringify(output, null, 2));
62896
+ }
62900
62897
  import_node_process9.default.exit();
62901
62898
  }
62902
62899
 
@@ -62938,24 +62935,6 @@ async function checkAppExists(supabase, appid) {
62938
62935
  const { data: app2 } = await supabase.rpc("exist_app_v2", { appid }).single();
62939
62936
  return !!app2;
62940
62937
  }
62941
- async function checkAppExistsAndHasPermissionErr(supabase, apikey, appid, shouldExist = true) {
62942
- const appExist = await checkAppExists(supabase, appid);
62943
- const perm = await isAllowedApp(supabase, apikey, appid);
62944
- if (appExist && !shouldExist) {
62945
- f2.error(`App ${appid} already exist`);
62946
- program.error("");
62947
- }
62948
- if (!appExist && shouldExist) {
62949
- f2.error(`App ${appid} does not exist`);
62950
- program.error("");
62951
- }
62952
- if (appExist && !perm) {
62953
- f2.error(`App ${appid} exist and you don't have permission to access it`);
62954
- if (appid === "io.ionic.starter")
62955
- f2.info("Modify your appid in your capacitor.config.json file to something unique, this is a default appid for ionic starter app");
62956
- program.error("");
62957
- }
62958
- }
62959
62938
  async function checkAppExistsAndHasPermissionOrgErr(supabase, apikey, appid, requiredPermission) {
62960
62939
  const permissions = await isAllowedAppOrg(supabase, apikey, appid);
62961
62940
  if (!permissions.okay) {
@@ -62988,6 +62967,11 @@ async function checkAppExistsAndHasPermissionOrgErr(supabase, apikey, appid, req
62988
62967
  var newIconPath = "assets/icon.png";
62989
62968
 
62990
62969
  // src/app/debug.ts
62970
+ function wait2(ms) {
62971
+ return new Promise((resolve2) => {
62972
+ setTimeout(resolve2, ms);
62973
+ });
62974
+ }
62991
62975
  async function markSnag(channel2, userId, snag, event, icon = "\u2705") {
62992
62976
  await snag.track({
62993
62977
  channel: channel2,
@@ -63098,7 +63082,7 @@ async function waitLog(channel2, supabase, appId, snag, userId, deviceId) {
63098
63082
  now = (/* @__PURE__ */ new Date()).toISOString();
63099
63083
  query.after = now;
63100
63084
  }
63101
- await wait(1e3);
63085
+ await wait2(1e3);
63102
63086
  }
63103
63087
  return Promise.resolve();
63104
63088
  }
@@ -63121,7 +63105,7 @@ async function debugApp(appId, options) {
63121
63105
  const snag = useLogSnag();
63122
63106
  const userId = await verifyUser(supabase, options.apikey);
63123
63107
  f2.info(`Getting active bundle in Capgo`);
63124
- await checkAppExistsAndHasPermissionErr(supabase, options.apikey, appId);
63108
+ await checkAppExistsAndHasPermissionOrgErr(supabase, options.apikey, appId, 4 /* admin */);
63125
63109
  const doRun = await se({ message: `Automatic check if update working in device ?` });
63126
63110
  await cancelCommand("debug", doRun, userId, snag);
63127
63111
  if (doRun) {
@@ -63302,8 +63286,8 @@ var import_node_process12 = __toESM(require("node:process"));
63302
63286
  // src/api/channels.ts
63303
63287
  var import_node_process11 = __toESM(require("node:process"));
63304
63288
  var import_console_table_printer = __toESM(require_dist18());
63305
- async function checkVersionNotUsedInChannel(supabase, appid, userId, versionData) {
63306
- const { data: channelFound, error: errorChannel } = await supabase.from("channels").select().eq("app_id", appid).eq("created_by", userId).eq("version", versionData.id);
63289
+ async function checkVersionNotUsedInChannel(supabase, appid, versionData) {
63290
+ const { data: channelFound, error: errorChannel } = await supabase.from("channels").select().eq("app_id", appid).eq("version", versionData.id);
63307
63291
  if (errorChannel) {
63308
63292
  f2.error(`Cannot check Version ${appid}@${versionData.name}`);
63309
63293
  program.error("");
@@ -63336,8 +63320,8 @@ function findUnknownVersion(supabase, appId) {
63336
63320
  function createChannel(supabase, update) {
63337
63321
  return supabase.from("channels").insert(update).select().single();
63338
63322
  }
63339
- function delChannel(supabase, name, appId, userId) {
63340
- return supabase.from("channels").delete().eq("name", name).eq("app_id", appId).eq("created_by", userId).single();
63323
+ function delChannel(supabase, name, appId, _userId) {
63324
+ return supabase.from("channels").delete().eq("name", name).eq("app_id", appId).single();
63341
63325
  }
63342
63326
  function displayChannels(data) {
63343
63327
  const t = new import_console_table_printer.Table({
@@ -63411,7 +63395,7 @@ async function addChannel(channelId, appId, options, shouldExit = true) {
63411
63395
  }
63412
63396
  const supabase = await createSupabaseClient(options.apikey);
63413
63397
  const userId = await verifyUser(supabase, options.apikey, ["write", "all"]);
63414
- await checkAppExistsAndHasPermissionErr(supabase, options.apikey, appId);
63398
+ await checkAppExistsAndHasPermissionOrgErr(supabase, options.apikey, appId, 4 /* admin */);
63415
63399
  f2.info(`Creating channel ${appId}#${channelId} to Capgo`);
63416
63400
  try {
63417
63401
  const data = await findUnknownVersion(supabase, appId);
@@ -63423,7 +63407,7 @@ async function addChannel(channelId, appId, options, shouldExit = true) {
63423
63407
  name: channelId,
63424
63408
  app_id: appId,
63425
63409
  version: data.id,
63426
- created_by: userId
63410
+ owner_org: EMPTY_UUID
63427
63411
  });
63428
63412
  f2.success(`Channel created \u2705`);
63429
63413
  await snag.track({
@@ -63463,7 +63447,7 @@ async function uploadBundle(appid, options, shouldExit = true) {
63463
63447
  oe(`Uploading`);
63464
63448
  await checkLatest();
63465
63449
  let { bundle: bundle2, path: path3, channel: channel2 } = options;
63466
- const { external, key: key2 = false, displayIvSession, autoMinUpdateVersion, ignoreMetadataCheck } = options;
63450
+ const { external, key: key2, displayIvSession, autoMinUpdateVersion, ignoreMetadataCheck } = options;
63467
63451
  let { minUpdateVersion } = options;
63468
63452
  options.apikey = options.apikey || findSavedKey();
63469
63453
  const snag = useLogSnag();
@@ -63573,8 +63557,6 @@ Trial expires in ${isTrial2} days`);
63573
63557
  f2.error(`Version already exists ${formatError(appVersionError)}`);
63574
63558
  program.error("");
63575
63559
  }
63576
- const safeBundle = bundle2.replace(/[^a-zA-Z0-9-_.!*'()]/g, "__");
63577
- const fileName = `${safeBundle}.zip`;
63578
63560
  let sessionKey;
63579
63561
  let checksum = "";
63580
63562
  let zipped = null;
@@ -63586,7 +63568,9 @@ Trial expires in ${isTrial2} days`);
63586
63568
  s.start(`Calculating checksum`);
63587
63569
  checksum = await (0, import_checksum2.checksum)(zipped, "crc32");
63588
63570
  s.stop(`Checksum: ${checksum}`);
63589
- if (key2 || (0, import_node_fs8.existsSync)(baseKeyPub)) {
63571
+ if (key2 === false) {
63572
+ f2.info(`Encryption ignored`);
63573
+ } else if (key2 || (0, import_node_fs8.existsSync)(baseKeyPub)) {
63590
63574
  const publicKey = typeof key2 === "string" ? key2 : baseKeyPub;
63591
63575
  let keyData = options.keyData || "";
63592
63576
  if (!keyData && !(0, import_node_fs8.existsSync)(publicKey)) {
@@ -63663,8 +63647,7 @@ The app size is ${mbSize} Mb, this may take a while to download for users
63663
63647
  const nativePackages = hashedLocalDependencies.size > 0 || !options.ignoreMetadataCheck ? Array.from(hashedLocalDependencies, ([name, value]) => ({ name, version: value.version })) : void 0;
63664
63648
  const appOwner = await getAppOwner(supabase, appid);
63665
63649
  const versionData = {
63666
- bucket_id: external ? void 0 : fileName,
63667
- user_id: appOwner,
63650
+ // bucket_id: external ? undefined : fileName,
63668
63651
  name: bundle2,
63669
63652
  app_id: appid,
63670
63653
  session_key: sessionKey,
@@ -63672,6 +63655,8 @@ The app size is ${mbSize} Mb, this may take a while to download for users
63672
63655
  storage_provider: external ? "external" : "r2-direct",
63673
63656
  minUpdateVersion,
63674
63657
  native_packages: nativePackages,
63658
+ owner_org: EMPTY_UUID,
63659
+ user_id: userId,
63675
63660
  checksum
63676
63661
  };
63677
63662
  const { error: dbError } = await updateOrCreateVersion(supabase, versionData);
@@ -63682,7 +63667,7 @@ The app size is ${mbSize} Mb, this may take a while to download for users
63682
63667
  if (!external && zipped) {
63683
63668
  const spinner = de();
63684
63669
  spinner.start(`Uploading Bundle`);
63685
- const url = await uploadUrl(supabase, appid, fileName);
63670
+ const url = await uploadUrl(supabase, appid, bundle2);
63686
63671
  if (!url) {
63687
63672
  f2.error(`Cannot get upload url`);
63688
63673
  program.error("");
@@ -63710,7 +63695,8 @@ The app size is ${mbSize} Mb, this may take a while to download for users
63710
63695
  name: channel2,
63711
63696
  app_id: appid,
63712
63697
  created_by: appOwner,
63713
- version: versionId
63698
+ version: versionId,
63699
+ owner_org: EMPTY_UUID
63714
63700
  });
63715
63701
  if (dbError3) {
63716
63702
  f2.error(`Cannot set channel, the upload key is not allowed to do that, use the "all" for this. ${formatError(dbError3)}`);
@@ -63945,7 +63931,7 @@ async function addApp(appId, options, throwErr = true) {
63945
63931
  program.error("");
63946
63932
  }
63947
63933
  const supabase = await createSupabaseClient(options.apikey);
63948
- const userId = await verifyUser(supabase, options.apikey, ["write", "all"]);
63934
+ let userId = await verifyUser(supabase, options.apikey, ["write", "all"]);
63949
63935
  await checkPlanValid(supabase, userId, options.apikey, void 0, false);
63950
63936
  const appExist = await checkAppExists(supabase, appId);
63951
63937
  if (throwErr && appExist) {
@@ -63954,6 +63940,27 @@ async function addApp(appId, options, throwErr = true) {
63954
63940
  } else if (appExist) {
63955
63941
  return true;
63956
63942
  }
63943
+ const { error: orgError, data: allOrganizations } = await supabase.rpc("get_orgs_v4");
63944
+ if (orgError) {
63945
+ f2.error("Cannot get the list of organizations - exiting");
63946
+ f2.error(`Error ${JSON.stringify(orgError)}`);
63947
+ program.error("");
63948
+ }
63949
+ const adminOrgs = allOrganizations.filter((org) => org.role === "admin" || org.role === "super_admin");
63950
+ const organizationUidRaw = adminOrgs.length > 1 ? await ie({
63951
+ message: "Please pick the organization that you want to insert to",
63952
+ options: adminOrgs.map((org) => {
63953
+ return { value: org.gid, label: org.name };
63954
+ })
63955
+ }) : adminOrgs[0].gid;
63956
+ if (eD(organizationUidRaw)) {
63957
+ f2.error("Canceled organization selection, exiting");
63958
+ program.error("");
63959
+ }
63960
+ const organizationUid = organizationUidRaw;
63961
+ const organization = allOrganizations.find((org) => org.gid === organizationUid);
63962
+ userId = organization.created_by;
63963
+ f2.info(`Using the organization "${organization.name}" as the app owner`);
63957
63964
  let { name, icon } = options;
63958
63965
  appId = appId || config?.app?.appId;
63959
63966
  name = name || config?.app?.appName || "Unknown";
@@ -63994,7 +64001,7 @@ async function addApp(appId, options, throwErr = true) {
63994
64001
  }
63995
64002
  const { error: dbError } = await supabase.from("apps").insert({
63996
64003
  icon_url: signedURL,
63997
- user_id: userId,
64004
+ owner_org: organizationUid,
63998
64005
  name,
63999
64006
  app_id: appId
64000
64007
  });
@@ -64003,12 +64010,12 @@ async function addApp(appId, options, throwErr = true) {
64003
64010
  program.error("");
64004
64011
  }
64005
64012
  const { error: dbVersionError } = await supabase.from("app_versions").insert([{
64006
- user_id: userId,
64013
+ owner_org: organizationUid,
64007
64014
  deleted: true,
64008
64015
  name: "unknown",
64009
64016
  app_id: appId
64010
64017
  }, {
64011
- user_id: userId,
64018
+ owner_org: organizationUid,
64012
64019
  deleted: true,
64013
64020
  name: "builtin",
64014
64021
  app_id: appId
@@ -64323,20 +64330,20 @@ async function checkVersionNotUsedInDeviceOverride(supabase, appid, versionData)
64323
64330
  }
64324
64331
 
64325
64332
  // src/api/versions.ts
64326
- async function deleteAppVersion(supabase, appid, userId, bundle2) {
64333
+ async function deleteAppVersion(supabase, appid, bundle2) {
64327
64334
  const { error: delAppSpecVersionError } = await supabase.from("app_versions").update({
64328
64335
  deleted: true
64329
- }).eq("app_id", appid).eq("deleted", false).eq("user_id", userId).eq("name", bundle2);
64336
+ }).eq("app_id", appid).eq("deleted", false).eq("name", bundle2);
64330
64337
  if (delAppSpecVersionError) {
64331
64338
  f2.error(`App Version ${appid}@${bundle2} not found in database`);
64332
64339
  program.error("");
64333
64340
  }
64334
64341
  }
64335
- async function deleteSpecificVersion(supabase, appid, userId, bundle2) {
64336
- const versionData = await getVersionData(supabase, appid, userId, bundle2);
64337
- await checkVersionNotUsedInChannel(supabase, appid, userId, versionData);
64342
+ async function deleteSpecificVersion(supabase, appid, _userId, bundle2) {
64343
+ const versionData = await getVersionData(supabase, appid, bundle2);
64344
+ await checkVersionNotUsedInChannel(supabase, appid, versionData);
64338
64345
  await checkVersionNotUsedInDeviceOverride(supabase, appid, versionData);
64339
- await deleteAppVersion(supabase, appid, userId, bundle2);
64346
+ await deleteAppVersion(supabase, appid, bundle2);
64340
64347
  }
64341
64348
  function displayBundles(data) {
64342
64349
  const t = new import_console_table_printer2.Table({
@@ -64352,8 +64359,8 @@ function displayBundles(data) {
64352
64359
  });
64353
64360
  f2.success(t.render());
64354
64361
  }
64355
- async function getActiveAppVersions(supabase, appid, userId) {
64356
- const { data, error: vError } = await supabase.from("app_versions").select().eq("app_id", appid).eq("user_id", userId).eq("deleted", false).order("created_at", { ascending: false });
64362
+ async function getActiveAppVersions(supabase, appid, _userId) {
64363
+ const { data, error: vError } = await supabase.from("app_versions").select().eq("app_id", appid).eq("deleted", false).order("created_at", { ascending: false });
64357
64364
  if (vError) {
64358
64365
  f2.error(`App ${appid} not found in database`);
64359
64366
  program.error("");
@@ -64368,8 +64375,8 @@ async function getChannelsVersion(supabase, appid) {
64368
64375
  }
64369
64376
  return channels.map((c2) => c2.version);
64370
64377
  }
64371
- async function getVersionData(supabase, appid, userId, bundle2) {
64372
- const { data: versionData, error: versionIdError } = await supabase.from("app_versions").select().eq("app_id", appid).eq("user_id", userId).eq("name", bundle2).eq("deleted", false).single();
64378
+ async function getVersionData(supabase, appid, bundle2) {
64379
+ const { data: versionData, error: versionIdError } = await supabase.from("app_versions").select().eq("app_id", appid).eq("name", bundle2).eq("deleted", false).single();
64373
64380
  if (!versionData || versionIdError) {
64374
64381
  f2.error(`App Version ${appid}@${bundle2} doesn't exist`);
64375
64382
  program.error("");
@@ -64395,7 +64402,7 @@ async function listBundle(appId, options) {
64395
64402
  const supabase = await createSupabaseClient(options.apikey);
64396
64403
  const userId = await verifyUser(supabase, options.apikey, ["write", "all", "read", "upload"]);
64397
64404
  f2.info(`Querying available versions of: ${appId} in Capgo`);
64398
- await checkAppExistsAndHasPermissionErr(supabase, options.apikey, appId);
64405
+ await checkAppExistsAndHasPermissionOrgErr(supabase, options.apikey, appId, 1 /* read */);
64399
64406
  const allVersions = await getActiveAppVersions(supabase, appId, userId);
64400
64407
  f2.info(`Active versions in Capgo: ${allVersions?.length}`);
64401
64408
  displayBundles(allVersions);
@@ -64570,7 +64577,7 @@ async function deleteBundle(bundleId, appId, options) {
64570
64577
  }
64571
64578
  const supabase = await createSupabaseClient(options.apikey);
64572
64579
  const userId = await verifyUser(supabase, options.apikey, ["write", "all"]);
64573
- await checkAppExistsAndHasPermissionErr(supabase, options.apikey, appId);
64580
+ await checkAppExistsAndHasPermissionOrgErr(supabase, options.apikey, appId, 3 /* write */);
64574
64581
  appId = appId || config?.app?.appId;
64575
64582
  if (!options.apikey) {
64576
64583
  f2.error("Missing API key, you need to provide an API key to delete your app");
@@ -64610,7 +64617,7 @@ async function setChannel(channel2, appId, options) {
64610
64617
  }
64611
64618
  const supabase = await createSupabaseClient(options.apikey);
64612
64619
  const userId = await verifyUser(supabase, options.apikey, ["write", "all"]);
64613
- await checkAppExistsAndHasPermissionErr(supabase, options.apikey, appId);
64620
+ await checkAppExistsAndHasPermissionOrgErr(supabase, options.apikey, appId, 4 /* admin */);
64614
64621
  const { bundle: bundle2, latest, downgrade, upgrade, ios, android, selfAssign, state, disableAutoUpdate } = options;
64615
64622
  if (!channel2) {
64616
64623
  f2.error("Missing argument, you need to provide a channel");
@@ -64722,13 +64729,13 @@ async function currentBundle(channel2, appId, options) {
64722
64729
  program.error("");
64723
64730
  }
64724
64731
  const supabase = await createSupabaseClient(options.apikey);
64725
- const userId = await verifyUser(supabase, options.apikey, ["write", "all", "read"]);
64726
- await checkAppExistsAndHasPermissionErr(supabase, options.apikey, appId);
64732
+ const _userId = await verifyUser(supabase, options.apikey, ["write", "all", "read"]);
64733
+ await checkAppExistsAndHasPermissionOrgErr(supabase, options.apikey, appId, 1 /* read */);
64727
64734
  if (!channel2) {
64728
64735
  f2.error(`Please provide a channel to get the bundle from.`);
64729
64736
  program.error("");
64730
64737
  }
64731
- const { data: supabaseChannel, error } = await supabase.from("channels").select("version ( name )").eq("name", channel2).eq("app_id", appId).eq("created_by", userId).limit(1);
64738
+ const { data: supabaseChannel, error } = await supabase.from("channels").select("version ( name )").eq("name", channel2).eq("app_id", appId).limit(1);
64732
64739
  if (error || supabaseChannel.length === 0) {
64733
64740
  f2.error(`Error retrieving channel ${channel2} for app ${appId}. Perhaps the channel does not exists?`);
64734
64741
  program.error("");
@@ -64820,8 +64827,8 @@ async function cleanupBundle(appid, options) {
64820
64827
  program.error("");
64821
64828
  }
64822
64829
  const supabase = await createSupabaseClient(options.apikey);
64823
- const userId = await verifyUser(supabase, options.apikey);
64824
- await checkAppExistsAndHasPermissionErr(supabase, options.apikey, appid);
64830
+ const userId = await verifyUser(supabase, options.apikey, ["write", "all"]);
64831
+ await checkAppExistsAndHasPermissionOrgErr(supabase, options.apikey, appid, 3 /* write */);
64825
64832
  f2.info(`Querying all available versions in Capgo`);
64826
64833
  let allVersions = await getActiveAppVersions(supabase, appid, userId);
64827
64834
  const versionInUse = await getChannelsVersion(supabase, appid);
@@ -64887,7 +64894,7 @@ async function deleteChannel(channelId, appId, options) {
64887
64894
  }
64888
64895
  const supabase = await createSupabaseClient(options.apikey);
64889
64896
  const userId = await verifyUser(supabase, options.apikey, ["write", "all"]);
64890
- await checkAppExistsAndHasPermissionErr(supabase, options.apikey, appId);
64897
+ await checkAppExistsAndHasPermissionOrgErr(supabase, options.apikey, appId, 4 /* admin */);
64891
64898
  f2.info(`Deleting channel ${appId}#${channelId} from Capgo`);
64892
64899
  try {
64893
64900
  await delChannel(supabase, channelId, appId, userId);
@@ -64926,7 +64933,7 @@ async function listChannels(appId, options) {
64926
64933
  }
64927
64934
  const supabase = await createSupabaseClient(options.apikey);
64928
64935
  const userId = await verifyUser(supabase, options.apikey, ["write", "all", "read", "upload"]);
64929
- await checkAppExistsAndHasPermissionErr(supabase, options.apikey, appId);
64936
+ await checkAppExistsAndHasPermissionOrgErr(supabase, options.apikey, appId, 1 /* read */);
64930
64937
  f2.info(`Querying available channels in Capgo`);
64931
64938
  const allVersions = await getActiveChannels(supabase, appId);
64932
64939
  f2.info(`Active channels in Capgo: ${allVersions?.length}`);
@@ -64964,9 +64971,9 @@ async function setApp(appId, options) {
64964
64971
  }
64965
64972
  const supabase = await createSupabaseClient(options.apikey);
64966
64973
  const userId = await verifyUser(supabase, options.apikey, ["write", "all"]);
64967
- await checkAppExistsAndHasPermissionErr(supabase, options.apikey, appId);
64974
+ await checkAppExistsAndHasPermissionOrgErr(supabase, options.apikey, appId, 4 /* admin */);
64968
64975
  const { name, icon, retention } = options;
64969
- if (retention && !Number.isNaN(Number(retention))) {
64976
+ if (retention && Number.isNaN(Number(retention))) {
64970
64977
  f2.error(`retention value must be a number`);
64971
64978
  program.error(``);
64972
64979
  } else if (retention && retention < 0) {
@@ -65032,15 +65039,39 @@ async function deleteApp(appId, options) {
65032
65039
  }
65033
65040
  const supabase = await createSupabaseClient(options.apikey);
65034
65041
  const userId = await verifyUser(supabase, options.apikey, ["write", "all"]);
65035
- await checkAppExistsAndHasPermissionErr(supabase, options.apikey, appId);
65042
+ await checkAppExistsAndHasPermissionOrgErr(supabase, options.apikey, appId, 5 /* super_admin */);
65043
+ const { data: appOwnerRaw, error: appOwnerError } = await supabase.from("apps").select(`owner_org ( created_by )`).eq("app_id", appId).single();
65044
+ const appOwner = appOwnerRaw;
65045
+ if (!appOwnerError && (appOwner?.owner_org.created_by ?? "") !== userId) {
65046
+ f2.warn("Deleting the app is not recomended for users that are not the organization owner");
65047
+ f2.warn("You are invited as a super_admin but your are not the owner");
65048
+ f2.warn("It's strongly recomended that you do not continue!");
65049
+ const shouldContinue = await ie({
65050
+ message: "Do you want to continue?",
65051
+ options: [
65052
+ {
65053
+ label: "Yes",
65054
+ value: "yes"
65055
+ },
65056
+ {
65057
+ label: "No",
65058
+ value: "no"
65059
+ }
65060
+ ]
65061
+ });
65062
+ if (eD(shouldContinue) || shouldContinue === "no") {
65063
+ f2.error("Canceled deleting the app, exiting");
65064
+ program.error("");
65065
+ }
65066
+ } else if (appOwnerError) {
65067
+ f2.warn(`Cannot get the app owner ${formatError(appOwnerError)}`);
65068
+ }
65036
65069
  const { error } = await supabase.storage.from(`images/${userId}`).remove([appId]);
65037
65070
  if (error)
65038
65071
  f2.error("Could not delete app logo");
65039
65072
  const { error: delError } = await supabase.storage.from(`apps/${appId}/${userId}`).remove(["versions"]);
65040
- if (delError) {
65073
+ if (delError)
65041
65074
  f2.error("Could not delete app version");
65042
- program.error("");
65043
- }
65044
65075
  const { error: dbError } = await supabase.from("apps").delete().eq("app_id", appId).eq("user_id", userId);
65045
65076
  if (dbError) {
65046
65077
  f2.error("Could not delete app");
@@ -65083,7 +65114,7 @@ async function checkCompatibilityCommand(appId, options) {
65083
65114
  }
65084
65115
  const supabase = await createSupabaseClient(options.apikey);
65085
65116
  await verifyUser(supabase, options.apikey, ["write", "all", "read", "upload"]);
65086
- await checkAppExistsAndHasPermissionErr(supabase, options.apikey, appId);
65117
+ await checkAppExistsAndHasPermissionOrgErr(supabase, options.apikey, appId, 1 /* read */);
65087
65118
  const { finalCompatibility } = await checkCompatibility(supabase, appId, channel2);
65088
65119
  const t = new import_console_table_printer4.Table({
65089
65120
  title: "Compatibility",
@@ -65122,7 +65153,6 @@ bundle.command("upload [appId]").alias("u").description("Upload a new bundle in
65122
65153
  bundle.command("compatibility [appId]").action(checkCompatibilityCommand).option("-a, --apikey <apikey>", "apikey to link to your account").option("-c, --channel <channel>", "channel to check the compatibility with").option("--text", "output text instead of emojis");
65123
65154
  bundle.command("delete [bundleId] [appId]").alias("d").description("Delete a bundle in Capgo Cloud").action(deleteBundle).option("-a, --apikey <apikey>", "apikey to link to your account");
65124
65155
  bundle.command("list [appId]").alias("l").description("List bundle in Capgo Cloud").action(listBundle).option("-a, --apikey <apikey>", "apikey to link to your account");
65125
- bundle.command("unlink [appId]").description("Unlink a bundle in Capgo Cloud").action(listBundle).option("-a, --apikey <apikey>", "apikey to link to your account").option("-b, --bundle <bundle>", "bundle version number of the bundle to unlink");
65126
65156
  bundle.command("cleanup [appId]").alias("c").action(cleanupBundle).description("Cleanup bundle in Capgo Cloud").option("-b, --bundle <bundle>", "bundle version number of the app to delete").option("-a, --apikey <apikey>", "apikey to link to your account").option("-k, --keep <keep>", "number of version to keep").option("-f, --force", "force removal");
65127
65157
  bundle.command("decrypt [zipPath] [sessionKey]").description("Decrypt a signed zip bundle").action(decryptZip).option("--key <key>", "custom path for private signing key").option("--key-data <keyData>", "base64 private signing key");
65128
65158
  bundle.command("encrypt [zipPath]").description("Encrypt a zip bundle").action(encryptZip).option("--key <key>", "custom path for private signing key").option("--key-data <keyData>", "base64 private signing key");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/cli",
3
- "version": "4.2.3",
3
+ "version": "4.2.7",
4
4
  "description": "A CLI to upload to capgo servers",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -6,12 +6,11 @@ import * as p from '@clack/prompts'
6
6
  import type { Database } from '../types/supabase.types'
7
7
  import { formatError } from '../utils'
8
8
 
9
- export async function checkVersionNotUsedInChannel(supabase: SupabaseClient<Database>, appid: string, userId: string, versionData: Database['public']['Tables']['app_versions']['Row']) {
9
+ export async function checkVersionNotUsedInChannel(supabase: SupabaseClient<Database>, appid: string, versionData: Database['public']['Tables']['app_versions']['Row']) {
10
10
  const { data: channelFound, error: errorChannel } = await supabase
11
11
  .from('channels')
12
12
  .select()
13
13
  .eq('app_id', appid)
14
- .eq('created_by', userId)
15
14
  .eq('version', versionData.id)
16
15
  if (errorChannel) {
17
16
  p.log.error(`Cannot check Version ${appid}@${versionData.name}`)
@@ -63,13 +62,12 @@ export function createChannel(supabase: SupabaseClient<Database>, update: Databa
63
62
  .single()
64
63
  }
65
64
 
66
- export function delChannel(supabase: SupabaseClient<Database>, name: string, appId: string, userId: string) {
65
+ export function delChannel(supabase: SupabaseClient<Database>, name: string, appId: string, _userId: string) {
67
66
  return supabase
68
67
  .from('channels')
69
68
  .delete()
70
69
  .eq('name', name)
71
70
  .eq('app_id', appId)
72
- .eq('created_by', userId)
73
71
  .single()
74
72
  }
75
73
  interface version {
@@ -9,7 +9,7 @@ import { getHumanDate } from '../utils'
9
9
  import { checkVersionNotUsedInChannel } from './channels'
10
10
  import { checkVersionNotUsedInDeviceOverride } from './devices_override'
11
11
 
12
- export async function deleteAppVersion(supabase: SupabaseClient<Database>, appid: string, userId: string, bundle: string) {
12
+ export async function deleteAppVersion(supabase: SupabaseClient<Database>, appid: string, bundle: string) {
13
13
  const { error: delAppSpecVersionError } = await supabase
14
14
  .from('app_versions')
15
15
  .update({
@@ -17,7 +17,6 @@ export async function deleteAppVersion(supabase: SupabaseClient<Database>, appid
17
17
  })
18
18
  .eq('app_id', appid)
19
19
  .eq('deleted', false)
20
- .eq('user_id', userId)
21
20
  .eq('name', bundle)
22
21
  if (delAppSpecVersionError) {
23
22
  p.log.error(`App Version ${appid}@${bundle} not found in database`)
@@ -25,12 +24,12 @@ export async function deleteAppVersion(supabase: SupabaseClient<Database>, appid
25
24
  }
26
25
  }
27
26
 
28
- export async function deleteSpecificVersion(supabase: SupabaseClient<Database>, appid: string, userId: string, bundle: string) {
29
- const versionData = await getVersionData(supabase, appid, userId, bundle)
30
- await checkVersionNotUsedInChannel(supabase, appid, userId, versionData)
27
+ export async function deleteSpecificVersion(supabase: SupabaseClient<Database>, appid: string, _userId: string, bundle: string) {
28
+ const versionData = await getVersionData(supabase, appid, bundle)
29
+ await checkVersionNotUsedInChannel(supabase, appid, versionData)
31
30
  await checkVersionNotUsedInDeviceOverride(supabase, appid, versionData)
32
31
  // Delete only a specific version in storage
33
- await deleteAppVersion(supabase, appid, userId, bundle)
32
+ await deleteAppVersion(supabase, appid, bundle)
34
33
  }
35
34
 
36
35
  export function displayBundles(data: (Database['public']['Tables']['app_versions']['Row'] & { keep?: string })[]) {
@@ -51,12 +50,12 @@ export function displayBundles(data: (Database['public']['Tables']['app_versions
51
50
  p.log.success(t.render())
52
51
  }
53
52
 
54
- export async function getActiveAppVersions(supabase: SupabaseClient<Database>, appid: string, userId: string) {
53
+ export async function getActiveAppVersions(supabase: SupabaseClient<Database>, appid: string, _userId: string) {
55
54
  const { data, error: vError } = await supabase
56
55
  .from('app_versions')
57
56
  .select()
58
57
  .eq('app_id', appid)
59
- .eq('user_id', userId)
58
+ // .eq('user_id', userId)
60
59
  .eq('deleted', false)
61
60
  .order('created_at', { ascending: false })
62
61
 
@@ -68,7 +67,7 @@ export async function getActiveAppVersions(supabase: SupabaseClient<Database>, a
68
67
  }
69
68
 
70
69
  export async function getChannelsVersion(supabase: SupabaseClient<Database>, appid: string) {
71
- // get all channels versionID
70
+ // get all channels versionID
72
71
  const { data: channels, error: channelsError } = await supabase
73
72
  .from('channels')
74
73
  .select('version')
@@ -81,12 +80,11 @@ export async function getChannelsVersion(supabase: SupabaseClient<Database>, app
81
80
  return channels.map(c => c.version)
82
81
  }
83
82
 
84
- export async function getVersionData(supabase: SupabaseClient<Database>, appid: string, userId: string, bundle: string) {
83
+ export async function getVersionData(supabase: SupabaseClient<Database>, appid: string, bundle: string) {
85
84
  const { data: versionData, error: versionIdError } = await supabase
86
85
  .from('app_versions')
87
86
  .select()
88
87
  .eq('app_id', appid)
89
- .eq('user_id', userId)
90
88
  .eq('name', bundle)
91
89
  .eq('deleted', false)
92
90
  .single()