@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/CHANGELOG.md +139 -5
- package/README.md +4 -0
- package/bun.lockb +0 -0
- package/dist/index.js +31453 -807
- package/package.json +2 -1
- package/src/api/channels.ts +2 -4
- package/src/api/versions.ts +14 -11
- package/src/app/add.ts +43 -6
- package/src/app/debug.ts +9 -3
- package/src/app/delete.ts +44 -6
- package/src/app/list.ts +4 -0
- package/src/app/set.ts +4 -4
- package/src/bundle/cleanup.ts +5 -6
- package/src/bundle/compatibility.ts +3 -3
- package/src/bundle/delete.ts +3 -3
- package/src/bundle/list.ts +3 -3
- package/src/bundle/unlink.ts +13 -7
- package/src/bundle/upload.ts +105 -23
- package/src/bundle/zip.ts +11 -9
- package/src/channel/add.ts +4 -4
- package/src/channel/currentBundle.ts +4 -5
- package/src/channel/delete.ts +3 -3
- package/src/channel/list.ts +3 -3
- package/src/channel/set.ts +7 -4
- package/src/index.ts +12 -7
- package/src/types/supabase.types.ts +589 -183
- package/src/utils.ts +36 -17
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@capgo/cli",
|
|
3
|
-
"version": "5.0.0-alpha.
|
|
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",
|
package/src/api/channels.ts
CHANGED
|
@@ -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,
|
|
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,
|
|
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 {
|
package/src/api/versions.ts
CHANGED
|
@@ -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,
|
|
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,
|
|
29
|
-
const versionData = await getVersionData(supabase, appid,
|
|
30
|
-
await checkVersionNotUsedInChannel(supabase, appid,
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
157
|
+
owner_org: organizationUid,
|
|
121
158
|
deleted: true,
|
|
122
159
|
name: 'unknown',
|
|
123
160
|
app_id: appId,
|
|
124
161
|
}, {
|
|
125
|
-
|
|
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 {
|
|
7
|
+
import { checkAppExistsAndHasPermissionOrgErr } from '../api/app'
|
|
8
8
|
import { checkLatest } from '../api/update'
|
|
9
|
-
import { convertAppName, createSupabaseClient, findSavedKey, formatError, getConfig, getLocalConfig, useLogSnag, verifyUser
|
|
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
|
|
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 {
|
|
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
|
|
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
|
-
|
|
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 {
|
|
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
|
|
29
|
+
await checkAppExistsAndHasPermissionOrgErr(supabase, options.apikey, appId, OrganizationPerm.admin)
|
|
30
30
|
|
|
31
31
|
const { name, icon, retention } = options
|
|
32
32
|
|
|
33
|
-
if (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
|
}
|
package/src/bundle/cleanup.ts
CHANGED
|
@@ -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 {
|
|
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
|
|
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 {
|
|
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
|
|
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)
|
package/src/bundle/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 {
|
|
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
|
|
31
|
+
await checkAppExistsAndHasPermissionOrgErr(supabase, options.apikey, appId, OrganizationPerm.write)
|
|
32
32
|
|
|
33
33
|
appId = appId || config?.app?.appId
|
|
34
34
|
if (!options.apikey) {
|
package/src/bundle/list.ts
CHANGED
|
@@ -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 {
|
|
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
|
|
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)
|
package/src/bundle/unlink.ts
CHANGED
|
@@ -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 {
|
|
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
|
|
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
|
|
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,
|
|
64
|
+
await checkPlanValid(supabase, orgId, options.apikey, appId)
|
|
59
65
|
|
|
60
|
-
const versionData = await getVersionData(supabase, appId,
|
|
61
|
-
await checkVersionNotUsedInChannel(supabase, appId,
|
|
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',
|