@capgo/cli 5.0.0-alpha.3 → 5.0.0-alpha.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/cli",
3
- "version": "5.0.0-alpha.3",
3
+ "version": "5.0.0-alpha.7",
4
4
  "description": "A CLI to upload to capgo servers",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -43,6 +43,7 @@
43
43
  "author": "github.com/riderx",
44
44
  "license": "Apache 2.0",
45
45
  "dependencies": {
46
+ "@aws-sdk/client-s3": "^3.540.0",
46
47
  "@capacitor/cli": "5.7.0",
47
48
  "@capgo/find-package-manager": "0.0.10",
48
49
  "@clack/prompts": "^0.7.0",
@@ -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,15 +24,20 @@ 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 })[]) {
36
+ if (!data.length) {
37
+ p.log.error('No bundle found')
38
+ // eslint-disable-next-line node/prefer-global/process
39
+ process.exit(1)
40
+ }
37
41
  const t = new Table({
38
42
  title: 'Bundles',
39
43
  charLength: { '❌': 2, '✅': 2 },
@@ -51,12 +55,12 @@ export function displayBundles(data: (Database['public']['Tables']['app_versions
51
55
  p.log.success(t.render())
52
56
  }
53
57
 
54
- export async function getActiveAppVersions(supabase: SupabaseClient<Database>, appid: string, userId: string) {
58
+ export async function getActiveAppVersions(supabase: SupabaseClient<Database>, appid: string, _userId: string) {
55
59
  const { data, error: vError } = await supabase
56
60
  .from('app_versions')
57
61
  .select()
58
62
  .eq('app_id', appid)
59
- .eq('user_id', userId)
63
+ // .eq('user_id', userId)
60
64
  .eq('deleted', false)
61
65
  .order('created_at', { ascending: false })
62
66
 
@@ -68,7 +72,7 @@ export async function getActiveAppVersions(supabase: SupabaseClient<Database>, a
68
72
  }
69
73
 
70
74
  export async function getChannelsVersion(supabase: SupabaseClient<Database>, appid: string) {
71
- // get all channels versionID
75
+ // get all channels versionID
72
76
  const { data: channels, error: channelsError } = await supabase
73
77
  .from('channels')
74
78
  .select('version')
@@ -81,12 +85,11 @@ export async function getChannelsVersion(supabase: SupabaseClient<Database>, app
81
85
  return channels.map(c => c.version)
82
86
  }
83
87
 
84
- export async function getVersionData(supabase: SupabaseClient<Database>, appid: string, userId: string, bundle: string) {
88
+ export async function getVersionData(supabase: SupabaseClient<Database>, appid: string, bundle: string) {
85
89
  const { data: versionData, error: versionIdError } = await supabase
86
90
  .from('app_versions')
87
91
  .select()
88
92
  .eq('app_id', appid)
89
- .eq('user_id', userId)
90
93
  .eq('name', bundle)
91
94
  .eq('deleted', false)
92
95
  .single()
package/src/app/add.ts CHANGED
@@ -35,11 +35,15 @@ export async function addApp(appId: string, options: Options, throwErr = true) {
35
35
  p.log.error('Missing argument, you need to provide a appId, or be in a capacitor project')
36
36
  program.error('')
37
37
  }
38
- const supabase = await createSupabaseClient(options.apikey)
39
38
 
40
- const userId = await verifyUser(supabase, options.apikey, ['write', 'all'])
39
+ if (appId.includes('--')) {
40
+ p.log.error('The app id includes illegal symbols. You cannot use "--" in the app id')
41
+ program.error('')
42
+ }
43
+
44
+ const supabase = await createSupabaseClient(options.apikey)
41
45
 
42
- await checkPlanValid(supabase, userId, options.apikey, undefined, false)
46
+ let userId = await verifyUser(supabase, options.apikey, ['write', 'all'])
43
47
 
44
48
  // Check we have app access to this appId
45
49
  const appExist = await checkAppExists(supabase, appId)
@@ -51,6 +55,39 @@ export async function addApp(appId: string, options: Options, throwErr = true) {
51
55
  return true
52
56
  }
53
57
 
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
86
+
87
+ p.log.info(`Using the organization "${organization.name}" as the app owner`)
88
+
89
+ await checkPlanValid(supabase, organizationUid, options.apikey, undefined, false)
90
+
54
91
  let { name, icon } = options
55
92
  appId = appId || config?.app?.appId
56
93
  name = name || config?.app?.appName || 'Unknown'
@@ -106,7 +143,7 @@ export async function addApp(appId: string, options: Options, throwErr = true) {
106
143
  .from('apps')
107
144
  .insert({
108
145
  icon_url: signedURL,
109
- user_id: userId,
146
+ owner_org: organizationUid,
110
147
  name,
111
148
  app_id: appId,
112
149
  })
@@ -117,12 +154,12 @@ export async function addApp(appId: string, options: Options, throwErr = true) {
117
154
  const { error: dbVersionError } = await supabase
118
155
  .from('app_versions')
119
156
  .insert([{
120
- user_id: userId,
157
+ owner_org: organizationUid,
121
158
  deleted: true,
122
159
  name: 'unknown',
123
160
  app_id: appId,
124
161
  }, {
125
- user_id: userId,
162
+ owner_org: organizationUid,
126
163
  deleted: true,
127
164
  name: 'builtin',
128
165
  app_id: appId,
package/src/app/debug.ts CHANGED
@@ -4,9 +4,15 @@ import type { SupabaseClient } from '@supabase/supabase-js'
4
4
  import { program } from 'commander'
5
5
  import type LogSnag from 'logsnag'
6
6
  import type { Database } from '../types/supabase.types'
7
- import { checkAppExistsAndHasPermissionErr } from '../api/app'
7
+ import { checkAppExistsAndHasPermissionOrgErr } from '../api/app'
8
8
  import { checkLatest } from '../api/update'
9
- import { convertAppName, createSupabaseClient, findSavedKey, formatError, getConfig, getLocalConfig, useLogSnag, verifyUser, wait } from '../utils'
9
+ import { OrganizationPerm, convertAppName, createSupabaseClient, findSavedKey, formatError, getConfig, getLocalConfig, useLogSnag, verifyUser } from '../utils'
10
+
11
+ function wait(ms: number) {
12
+ return new Promise((resolve) => {
13
+ setTimeout(resolve, ms)
14
+ })
15
+ }
10
16
 
11
17
  export interface OptionsBaseDebug {
12
18
  apikey: string
@@ -194,7 +200,7 @@ export async function debugApp(appId: string, options: OptionsBaseDebug) {
194
200
  p.log.info(`Getting active bundle in Capgo`)
195
201
 
196
202
  // Check we have app access to this appId
197
- await checkAppExistsAndHasPermissionErr(supabase, options.apikey, appId)
203
+ await checkAppExistsAndHasPermissionOrgErr(supabase, options.apikey, appId, OrganizationPerm.admin)
198
204
 
199
205
  const doRun = await p.confirm({ message: `Automatic check if update working in device ?` })
200
206
  await cancelCommand('debug', doRun, userId, snag)
package/src/app/delete.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  import process from 'node:process'
2
2
  import { program } from 'commander'
3
3
  import * as p from '@clack/prompts'
4
- import { checkAppExistsAndHasPermissionErr } from '../api/app'
4
+ import { checkAppExistsAndHasPermissionOrgErr } from '../api/app'
5
5
  import type { OptionsBase } from '../utils'
6
- import { createSupabaseClient, findSavedKey, getConfig, useLogSnag, verifyUser } from '../utils'
6
+ import { OrganizationPerm, createSupabaseClient, findSavedKey, formatError, getConfig, useLogSnag, verifyUser } from '../utils'
7
7
 
8
8
  export async function deleteApp(appId: string, options: OptionsBase) {
9
9
  p.intro(`Deleting`)
@@ -24,7 +24,45 @@ export async function deleteApp(appId: string, options: OptionsBase) {
24
24
 
25
25
  const userId = await verifyUser(supabase, options.apikey, ['write', 'all'])
26
26
  // Check we have app access to this appId
27
- await checkAppExistsAndHasPermissionErr(supabase, options.apikey, appId)
27
+ await checkAppExistsAndHasPermissionOrgErr(supabase, options.apikey, appId, OrganizationPerm.super_admin)
28
+
29
+ const { data: appOwnerRaw, error: appOwnerError } = await supabase.from('apps')
30
+ .select(`owner_org ( created_by )`)
31
+ .eq('app_id', appId)
32
+ .single()
33
+
34
+ const appOwner = appOwnerRaw as { owner_org: { created_by: string } } | null
35
+
36
+ if (!appOwnerError && (appOwner?.owner_org.created_by ?? '') !== userId) {
37
+ // We are dealing with a member user that is not the owner
38
+ // Deleting the app is not recomended at this stage
39
+
40
+ p.log.warn('Deleting the app is not recomended for users that are not the organization owner')
41
+ p.log.warn('You are invited as a super_admin but your are not the owner')
42
+ p.log.warn('It\'s strongly recomended that you do not continue!')
43
+
44
+ const shouldContinue = await p.select({
45
+ message: 'Do you want to continue?',
46
+ options: [
47
+ {
48
+ label: 'Yes',
49
+ value: 'yes',
50
+ },
51
+ {
52
+ label: 'No',
53
+ value: 'no',
54
+ },
55
+ ],
56
+ })
57
+
58
+ if (p.isCancel(shouldContinue) || shouldContinue === 'no') {
59
+ p.log.error('Canceled deleting the app, exiting')
60
+ program.error('')
61
+ }
62
+ }
63
+ else if (appOwnerError) {
64
+ p.log.warn(`Cannot get the app owner ${formatError(appOwnerError)}`)
65
+ }
28
66
 
29
67
  const { error } = await supabase
30
68
  .storage
@@ -37,10 +75,10 @@ export async function deleteApp(appId: string, options: OptionsBase) {
37
75
  .storage
38
76
  .from(`apps/${appId}/${userId}`)
39
77
  .remove(['versions'])
40
- if (delError) {
78
+ if (delError)
41
79
  p.log.error('Could not delete app version')
42
- program.error('')
43
- }
80
+ // We should not care too much, most is in r2 anyways :/
81
+ // program.error('')
44
82
 
45
83
  const { error: dbError } = await supabase
46
84
  .from('apps')
package/src/app/list.ts CHANGED
@@ -9,6 +9,10 @@ import { createSupabaseClient, findSavedKey, getHumanDate, verifyUser } from '..
9
9
  import { checkLatest } from '../api/update'
10
10
 
11
11
  function displayApp(data: Database['public']['Tables']['apps']['Row'][]) {
12
+ if (!data.length) {
13
+ p.log.error('No apps found')
14
+ process.exit(1)
15
+ }
12
16
  const t = new Table({
13
17
  title: 'Apps',
14
18
  charLength: { '❌': 2, '✅': 2 },
package/src/app/set.ts CHANGED
@@ -5,8 +5,8 @@ import mime from 'mime'
5
5
  import { program } from 'commander'
6
6
  import * as p from '@clack/prompts'
7
7
  import type { Options } from '../api/app'
8
- import { checkAppExistsAndHasPermissionErr, newIconPath } from '../api/app'
9
- import { createSupabaseClient, findSavedKey, formatError, getConfig, verifyUser } from '../utils'
8
+ import { checkAppExistsAndHasPermissionOrgErr, newIconPath } from '../api/app'
9
+ import { OrganizationPerm, createSupabaseClient, findSavedKey, formatError, getConfig, verifyUser } from '../utils'
10
10
 
11
11
  export async function setApp(appId: string, options: Options) {
12
12
  p.intro(`Set app`)
@@ -26,11 +26,11 @@ export async function setApp(appId: string, options: Options) {
26
26
 
27
27
  const userId = await verifyUser(supabase, options.apikey, ['write', 'all'])
28
28
  // Check we have app access to this appId
29
- await checkAppExistsAndHasPermissionErr(supabase, options.apikey, appId)
29
+ await checkAppExistsAndHasPermissionOrgErr(supabase, options.apikey, appId, OrganizationPerm.admin)
30
30
 
31
31
  const { name, icon, retention } = options
32
32
 
33
- if (retention && !Number.isNaN(Number(retention))) {
33
+ if (retention && Number.isNaN(Number(retention))) {
34
34
  p.log.error(`retention value must be a number`)
35
35
  program.error(``)
36
36
  }
@@ -6,9 +6,9 @@ import promptSync from 'prompt-sync'
6
6
  import type { SupabaseClient } from '@supabase/supabase-js'
7
7
  import type { Database } from '../types/supabase.types'
8
8
  import type { OptionsBase } from '../utils'
9
- import { createSupabaseClient, findSavedKey, getConfig, getHumanDate, verifyUser } from '../utils'
9
+ import { OrganizationPerm, createSupabaseClient, findSavedKey, getConfig, getHumanDate, verifyUser } from '../utils'
10
10
  import { deleteSpecificVersion, displayBundles, getActiveAppVersions, getChannelsVersion } from '../api/versions'
11
- import { checkAppExistsAndHasPermissionErr } from '../api/app'
11
+ import { checkAppExistsAndHasPermissionOrgErr } from '../api/app'
12
12
  import { checkLatest } from '../api/update'
13
13
 
14
14
  interface Options extends OptionsBase {
@@ -57,15 +57,14 @@ export async function cleanupBundle(appid: string, options: Options) {
57
57
  }
58
58
  const supabase = await createSupabaseClient(options.apikey)
59
59
 
60
- const userId = await verifyUser(supabase, options.apikey)
60
+ const userId = await verifyUser(supabase, options.apikey, ['write', 'all'])
61
61
 
62
62
  // Check we have app access to this appId
63
- await checkAppExistsAndHasPermissionErr(supabase, options.apikey, appid)
63
+ await checkAppExistsAndHasPermissionOrgErr(supabase, options.apikey, appid, OrganizationPerm.write)
64
64
  p.log.info(`Querying all available versions in Capgo`)
65
65
 
66
66
  // Get all active app versions we might possibly be able to cleanup
67
- let allVersions: (Database['public']['Tables']['app_versions']['Row'] & { keep?: string })[] = await
68
- getActiveAppVersions(supabase, appid, userId)
67
+ let allVersions: (Database['public']['Tables']['app_versions']['Row'] & { keep?: string })[] = await getActiveAppVersions(supabase, appid, userId)
69
68
 
70
69
  const versionInUse = await getChannelsVersion(supabase, appid)
71
70
 
@@ -2,8 +2,8 @@ import * as p from '@clack/prompts'
2
2
  import { program } from 'commander'
3
3
  import { Table } from 'console-table-printer'
4
4
  import type { OptionsBase } from '../utils'
5
- import { checkCompatibility, createSupabaseClient, findSavedKey, getConfig, verifyUser } from '../utils'
6
- import { checkAppExistsAndHasPermissionErr } from '../api/app'
5
+ import { OrganizationPerm, checkCompatibility, createSupabaseClient, findSavedKey, getConfig, verifyUser } from '../utils'
6
+ import { checkAppExistsAndHasPermissionOrgErr } from '../api/app'
7
7
 
8
8
  interface Options extends OptionsBase {
9
9
  channel?: string
@@ -36,7 +36,7 @@ export async function checkCompatibilityCommand(appId: string, options: Options)
36
36
  await verifyUser(supabase, options.apikey, ['write', 'all', 'read', 'upload'])
37
37
 
38
38
  // Check we have app access to this appId
39
- await checkAppExistsAndHasPermissionErr(supabase, options.apikey, appId)
39
+ await checkAppExistsAndHasPermissionOrgErr(supabase, options.apikey, appId, OrganizationPerm.read)
40
40
 
41
41
  // const hashedLocalDependencies = new Map(dependenciesObject
42
42
  // .filter((a) => !!a.native && a.native !== undefined)
@@ -1,9 +1,9 @@
1
1
  import process from 'node:process'
2
2
  import { program } from 'commander'
3
3
  import * as p from '@clack/prompts'
4
- import { checkAppExistsAndHasPermissionErr } from '../api/app'
4
+ import { checkAppExistsAndHasPermissionOrgErr } from '../api/app'
5
5
  import type { OptionsBase } from '../utils'
6
- import { createSupabaseClient, findSavedKey, getConfig, verifyUser } from '../utils'
6
+ import { OrganizationPerm, createSupabaseClient, findSavedKey, getConfig, verifyUser } from '../utils'
7
7
  import { deleteSpecificVersion } from '../api/versions'
8
8
 
9
9
  interface Options extends OptionsBase {
@@ -28,7 +28,7 @@ export async function deleteBundle(bundleId: string, appId: string, options: Opt
28
28
 
29
29
  const userId = await verifyUser(supabase, options.apikey, ['write', 'all'])
30
30
  // Check we have app access to this appId
31
- await checkAppExistsAndHasPermissionErr(supabase, options.apikey, appId)
31
+ await checkAppExistsAndHasPermissionOrgErr(supabase, options.apikey, appId, OrganizationPerm.write)
32
32
 
33
33
  appId = appId || config?.app?.appId
34
34
  if (!options.apikey) {
@@ -1,10 +1,10 @@
1
1
  import process from 'node:process'
2
2
  import { program } from 'commander'
3
3
  import * as p from '@clack/prompts'
4
- import { checkAppExistsAndHasPermissionErr } from '../api/app'
4
+ import { checkAppExistsAndHasPermissionOrgErr } from '../api/app'
5
5
  import { displayBundles, getActiveAppVersions } from '../api/versions'
6
6
  import type { OptionsBase } from '../utils'
7
- import { createSupabaseClient, findSavedKey, getConfig, verifyUser } from '../utils'
7
+ import { OrganizationPerm, createSupabaseClient, findSavedKey, getConfig, verifyUser } from '../utils'
8
8
  import { checkLatest } from '../api/update'
9
9
 
10
10
  export async function listBundle(appId: string, options: OptionsBase) {
@@ -30,7 +30,7 @@ export async function listBundle(appId: string, options: OptionsBase) {
30
30
  p.log.info(`Querying available versions of: ${appId} in Capgo`)
31
31
 
32
32
  // Check we have app access to this appId
33
- await checkAppExistsAndHasPermissionErr(supabase, options.apikey, appId)
33
+ await checkAppExistsAndHasPermissionOrgErr(supabase, options.apikey, appId, OrganizationPerm.read)
34
34
 
35
35
  // Get all active app versions we might possibly be able to cleanup
36
36
  const allVersions = await getActiveAppVersions(supabase, appId, userId)
@@ -4,16 +4,18 @@ import * as p from '@clack/prompts'
4
4
  import { getVersionData } from '../api/versions'
5
5
  import { checkVersionNotUsedInDeviceOverride } from '../api/devices_override'
6
6
  import { checkVersionNotUsedInChannel } from '../api/channels'
7
- import { checkAppExistsAndHasPermissionErr } from '../api/app'
7
+ import { checkAppExistsAndHasPermissionOrgErr } from '../api/app'
8
8
  import type {
9
9
  OptionsBase,
10
10
  } from '../utils'
11
11
  import {
12
+ OrganizationPerm,
12
13
  checkPlanValid,
13
14
  createSupabaseClient,
14
15
  findSavedKey,
15
16
  formatError,
16
17
  getConfig,
18
+ getOrganizationId,
17
19
  useLogSnag,
18
20
  verifyUser,
19
21
  } from '../utils'
@@ -23,7 +25,7 @@ interface Options extends OptionsBase {
23
25
  }
24
26
 
25
27
  export async function unlinkDevice(channel: string, appId: string, options: Options) {
26
- p.intro(`Unlink bundle`)
28
+ p.intro(`Unlink bundle ${options.apikey}`)
27
29
  options.apikey = options.apikey || findSavedKey()
28
30
  const config = await getConfig()
29
31
  appId = appId || config?.app?.appId
@@ -46,19 +48,23 @@ export async function unlinkDevice(channel: string, appId: string, options: Opti
46
48
  }
47
49
  const supabase = await createSupabaseClient(options.apikey)
48
50
 
49
- const userId = await verifyUser(supabase, options.apikey, ['write', 'all'])
51
+ const [userId, orgId] = await Promise.all([
52
+ verifyUser(supabase, options.apikey, ['all', 'write']),
53
+ getOrganizationId(supabase, appId),
54
+ ])
55
+
50
56
  // Check we have app access to this appId
51
- await checkAppExistsAndHasPermissionErr(supabase, options.apikey, appId)
57
+ await checkAppExistsAndHasPermissionOrgErr(supabase, options.apikey, appId, OrganizationPerm.write)
52
58
 
53
59
  if (!channel) {
54
60
  p.log.error('Missing argument, you need to provide a channel')
55
61
  program.error('')
56
62
  }
57
63
  try {
58
- await checkPlanValid(supabase, userId, options.apikey, appId)
64
+ await checkPlanValid(supabase, orgId, options.apikey, appId)
59
65
 
60
- const versionData = await getVersionData(supabase, appId, userId, bundle)
61
- await checkVersionNotUsedInChannel(supabase, appId, userId, versionData)
66
+ const versionData = await getVersionData(supabase, appId, bundle)
67
+ await checkVersionNotUsedInChannel(supabase, appId, versionData)
62
68
  await checkVersionNotUsedInDeviceOverride(supabase, appId, versionData)
63
69
  await snag.track({
64
70
  channel: 'bundle',