@capgo/cli 5.0.0-alpha.7 → 7.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. package/README.md +197 -41
  2. package/dist/index.js +335 -95820
  3. package/dist/package.json +83 -0
  4. package/package.json +48 -62
  5. package/.eslintignore +0 -4
  6. package/.github/FUNDING.yml +0 -1
  7. package/.github/workflows/build.yml +0 -46
  8. package/.github/workflows/bump_version.yml +0 -56
  9. package/.github/workflows/test.yml +0 -30
  10. package/.prettierignore +0 -6
  11. package/.vscode/launch.json +0 -23
  12. package/.vscode/settings.json +0 -5
  13. package/.vscode/tasks.json +0 -42
  14. package/CHANGELOG.md +0 -2861
  15. package/build.mjs +0 -23
  16. package/bun.lockb +0 -0
  17. package/capacitor.config.ts +0 -33
  18. package/crypto_explained.png +0 -0
  19. package/eslint.config.js +0 -3
  20. package/renovate.json +0 -23
  21. package/src/api/app.ts +0 -75
  22. package/src/api/channels.ts +0 -140
  23. package/src/api/crypto.ts +0 -121
  24. package/src/api/devices_override.ts +0 -41
  25. package/src/api/update.ts +0 -12
  26. package/src/api/versions.ts +0 -101
  27. package/src/app/add.ts +0 -191
  28. package/src/app/debug.ts +0 -220
  29. package/src/app/delete.ts +0 -106
  30. package/src/app/info.ts +0 -87
  31. package/src/app/list.ts +0 -67
  32. package/src/app/set.ts +0 -94
  33. package/src/bundle/check.ts +0 -42
  34. package/src/bundle/cleanup.ts +0 -127
  35. package/src/bundle/compatibility.ts +0 -70
  36. package/src/bundle/decrypt.ts +0 -65
  37. package/src/bundle/delete.ts +0 -53
  38. package/src/bundle/encrypt.ts +0 -69
  39. package/src/bundle/list.ts +0 -43
  40. package/src/bundle/unlink.ts +0 -86
  41. package/src/bundle/upload.ts +0 -516
  42. package/src/bundle/zip.ts +0 -139
  43. package/src/channel/add.ts +0 -73
  44. package/src/channel/currentBundle.ts +0 -72
  45. package/src/channel/delete.ts +0 -51
  46. package/src/channel/list.ts +0 -49
  47. package/src/channel/set.ts +0 -174
  48. package/src/index.ts +0 -290
  49. package/src/init.ts +0 -301
  50. package/src/key.ts +0 -158
  51. package/src/login.ts +0 -66
  52. package/src/types/capacitor__cli.d.ts +0 -6
  53. package/src/types/supabase.types.ts +0 -2471
  54. package/src/utils.ts +0 -738
  55. package/test/chunk_convert.ts +0 -28
  56. package/test/data.ts +0 -18769
  57. package/test/test_headers_rls.ts +0 -24
  58. package/test/test_semver.ts +0 -13
  59. package/tsconfig.json +0 -39
package/src/app/set.ts DELETED
@@ -1,94 +0,0 @@
1
- import { randomUUID } from 'node:crypto'
2
- import { existsSync, readFileSync } from 'node:fs'
3
- import process from 'node:process'
4
- import mime from 'mime'
5
- import { program } from 'commander'
6
- import * as p from '@clack/prompts'
7
- import type { Options } from '../api/app'
8
- import { checkAppExistsAndHasPermissionOrgErr, newIconPath } from '../api/app'
9
- import { OrganizationPerm, createSupabaseClient, findSavedKey, formatError, getConfig, verifyUser } from '../utils'
10
-
11
- export async function setApp(appId: string, options: Options) {
12
- p.intro(`Set app`)
13
- options.apikey = options.apikey || findSavedKey()
14
- const config = await getConfig()
15
- appId = appId || config?.app?.appId
16
-
17
- if (!options.apikey) {
18
- p.log.error(`Missing API key, you need to provide a API key to upload your bundle`)
19
- program.error(``)
20
- }
21
- if (!appId) {
22
- p.log.error('Missing argument, you need to provide a appId, or be in a capacitor project')
23
- program.error(``)
24
- }
25
- const supabase = await createSupabaseClient(options.apikey)
26
-
27
- const userId = await verifyUser(supabase, options.apikey, ['write', 'all'])
28
- // Check we have app access to this appId
29
- await checkAppExistsAndHasPermissionOrgErr(supabase, options.apikey, appId, OrganizationPerm.admin)
30
-
31
- const { name, icon, retention } = options
32
-
33
- if (retention && Number.isNaN(Number(retention))) {
34
- p.log.error(`retention value must be a number`)
35
- program.error(``)
36
- }
37
- else if (retention && retention < 0) {
38
- p.log.error(`retention value cannot be less than 0`)
39
- program.error(``)
40
- }
41
-
42
- let iconBuff
43
- let iconType
44
- const fileName = `icon_${randomUUID()}`
45
- let signedURL = 'https://xvwzpoazmxkqosrdewyv.supabase.co/storage/v1/object/public/images/capgo.png'
46
-
47
- if (icon && existsSync(icon)) {
48
- iconBuff = readFileSync(icon)
49
- const contentType = mime.getType(icon)
50
- iconType = contentType || 'image/png'
51
- p.log.warn(`Found app icon ${icon}`)
52
- }
53
- else if (existsSync(newIconPath)) {
54
- iconBuff = readFileSync(newIconPath)
55
- const contentType = mime.getType(newIconPath)
56
- iconType = contentType || 'image/png'
57
- p.log.warn(`Found app icon ${newIconPath}`)
58
- }
59
- else {
60
- p.log.warn(`Cannot find app icon in any of the following locations: ${icon}, ${newIconPath}`)
61
- }
62
- if (iconBuff && iconType) {
63
- const { error } = await supabase.storage
64
- .from(`images/${userId}/${appId}`)
65
- .upload(fileName, iconBuff, {
66
- contentType: iconType,
67
- })
68
- if (error) {
69
- p.log.error(`Could not set app ${formatError(error)}`)
70
- program.error(``)
71
- }
72
- const { data: signedURLData } = await supabase
73
- .storage
74
- .from(`images/${userId}/${appId}`)
75
- .getPublicUrl(fileName)
76
- signedURL = signedURLData?.publicUrl || signedURL
77
- }
78
- // retention is in seconds in the database but received as days here
79
- const { error: dbError } = await supabase
80
- .from('apps')
81
- .update({
82
- icon_url: signedURL,
83
- name,
84
- retention: !retention ? undefined : retention * 24 * 60 * 60,
85
- })
86
- .eq('app_id', appId)
87
- .eq('user_id', userId)
88
- if (dbError) {
89
- p.log.error(`Could not set app ${formatError(dbError)}`)
90
- program.error(``)
91
- }
92
- p.outro(`Done ✅`)
93
- process.exit()
94
- }
@@ -1,42 +0,0 @@
1
- import fs from 'node:fs'
2
- import path from 'node:path'
3
-
4
- function searchInFile(filePath: string, searchString: string) {
5
- const content = fs.readFileSync(filePath, 'utf8')
6
- return content.includes(searchString)
7
- }
8
-
9
- export function searchInDirectory(dirPath: string, searchString: string) {
10
- const files = fs.readdirSync(dirPath)
11
- for (const file of files) {
12
- const filePath = path.join(dirPath, file)
13
- const stats = fs.statSync(filePath)
14
-
15
- if (stats.isDirectory()) {
16
- if (searchInDirectory(filePath, searchString))
17
- return true
18
- }
19
- else if (stats.isFile() && path.extname(filePath) === '.js') {
20
- if (searchInFile(filePath, searchString))
21
- return true
22
- }
23
- }
24
-
25
- return false
26
- }
27
-
28
- export function checkIndexPosition(dirPath: string): boolean {
29
- // look for index.html in the root folder or if there only one folder in the root folder look for index.html in this folder
30
- const files = fs.readdirSync(dirPath)
31
- if (files.length === 1) {
32
- const filePath = path.join(dirPath, files[0])
33
- const stats = fs.statSync(filePath)
34
- if (stats.isDirectory())
35
- return checkIndexPosition(filePath)
36
- }
37
- const index = files.indexOf('index.html')
38
- if (index > -1)
39
- return true
40
-
41
- return false
42
- }
@@ -1,127 +0,0 @@
1
- import process from 'node:process'
2
- import { program } from 'commander'
3
- import semver from 'semver/preload'
4
- import * as p from '@clack/prompts'
5
- import promptSync from 'prompt-sync'
6
- import type { SupabaseClient } from '@supabase/supabase-js'
7
- import type { Database } from '../types/supabase.types'
8
- import type { OptionsBase } from '../utils'
9
- import { OrganizationPerm, createSupabaseClient, findSavedKey, getConfig, getHumanDate, verifyUser } from '../utils'
10
- import { deleteSpecificVersion, displayBundles, getActiveAppVersions, getChannelsVersion } from '../api/versions'
11
- import { checkAppExistsAndHasPermissionOrgErr } from '../api/app'
12
- import { checkLatest } from '../api/update'
13
-
14
- interface Options extends OptionsBase {
15
- version: string
16
- bundle: string
17
- keep: number
18
- force: boolean
19
- }
20
-
21
- const prompt = promptSync()
22
-
23
- async function removeVersions(toRemove: Database['public']['Tables']['app_versions']['Row'][], supabase: SupabaseClient<Database>, appid: string, userId: string) {
24
- // call deleteSpecificVersion one by one from toRemove sync
25
- for await (const row of toRemove) {
26
- p.log.warn(`Removing ${row.name} created on ${(getHumanDate(row.created_at))}`)
27
- await deleteSpecificVersion(supabase, appid, userId, row.name)
28
- }
29
- }
30
-
31
- function getRemovableVersionsInSemverRange(data: Database['public']['Tables']['app_versions']['Row'][], bundle: string, nextMajor: string) {
32
- const toRemove: Database['public']['Tables']['app_versions']['Row'][] = []
33
-
34
- data?.forEach((row) => {
35
- if (semver.gte(row.name, bundle) && semver.lt(row.name, `${nextMajor}`))
36
- toRemove.push(row)
37
- })
38
- return toRemove
39
- }
40
-
41
- export async function cleanupBundle(appid: string, options: Options) {
42
- p.intro(`Cleanup versions in Capgo`)
43
- await checkLatest()
44
- options.apikey = options.apikey || findSavedKey()
45
- const { bundle, keep = 4 } = options
46
- const force = options.force || false
47
-
48
- const config = await getConfig()
49
- appid = appid || config?.app?.appId
50
- if (!options.apikey) {
51
- p.log.error('Missing API key, you need to provide an API key to delete your app')
52
- program.error('')
53
- }
54
- if (!appid) {
55
- p.log.error('Missing argument, you need to provide a appid, or be in a capacitor project')
56
- program.error('')
57
- }
58
- const supabase = await createSupabaseClient(options.apikey)
59
-
60
- const userId = await verifyUser(supabase, options.apikey, ['write', 'all'])
61
-
62
- // Check we have app access to this appId
63
- await checkAppExistsAndHasPermissionOrgErr(supabase, options.apikey, appid, OrganizationPerm.write)
64
- p.log.info(`Querying all available versions in Capgo`)
65
-
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 getActiveAppVersions(supabase, appid, userId)
68
-
69
- const versionInUse = await getChannelsVersion(supabase, appid)
70
-
71
- p.log.info(`Total active versions in Capgo: ${allVersions?.length}`)
72
- if (allVersions?.length === 0) {
73
- p.log.error('No versions found, aborting cleanup')
74
- return
75
- }
76
- if (bundle) {
77
- const nextMajor = `${semver.inc(bundle, 'major')}`
78
- p.log.info(`Querying available versions in Capgo between ${bundle} and ${nextMajor}`)
79
-
80
- // Get all app versions that are in the given range
81
- allVersions = getRemovableVersionsInSemverRange(allVersions, bundle, nextMajor) as (Database['public']['Tables']['app_versions']['Row'] & { keep: string })[]
82
-
83
- p.log.info(`Active versions in Capgo between ${bundle} and ${nextMajor}: ${allVersions?.length}`)
84
- }
85
-
86
- // Slice to keep and remove
87
-
88
- const toRemove: (Database['public']['Tables']['app_versions']['Row'] & { keep?: string })[] = []
89
- // Slice to keep and remove
90
- let kept = 0
91
- allVersions.forEach((v) => {
92
- const isInUse = versionInUse.find(vi => vi === v.id)
93
- if (kept < keep || isInUse) {
94
- if (isInUse)
95
- v.keep = '✅ (Linked to channel)'
96
- else
97
- v.keep = '✅'
98
-
99
- kept += 1
100
- }
101
- else {
102
- v.keep = '❌'
103
- toRemove.push(v)
104
- }
105
- })
106
-
107
- if (toRemove.length === 0) {
108
- p.log.warn('Nothing to be removed, aborting removal...')
109
- return
110
- }
111
- displayBundles(allVersions)
112
-
113
- // Check user wants to clean that all up
114
- if (!force) {
115
- const result = prompt('Do you want to continue removing the versions specified? Type yes to confirm: ')
116
- if (result !== 'yes') {
117
- p.log.warn('Not confirmed, aborting removal...')
118
- return
119
- }
120
- }
121
-
122
- // Yes, lets clean it up
123
- p.log.success('You have confirmed removal, removing versions now')
124
- await removeVersions(toRemove, supabase, appid, userId)
125
- p.outro(`Done ✅`)
126
- process.exit()
127
- }
@@ -1,70 +0,0 @@
1
- import * as p from '@clack/prompts'
2
- import { program } from 'commander'
3
- import { Table } from 'console-table-printer'
4
- import type { OptionsBase } from '../utils'
5
- import { OrganizationPerm, checkCompatibility, createSupabaseClient, findSavedKey, getConfig, verifyUser } from '../utils'
6
- import { checkAppExistsAndHasPermissionOrgErr } from '../api/app'
7
-
8
- interface Options extends OptionsBase {
9
- channel?: string
10
- text?: boolean
11
- }
12
-
13
- export async function checkCompatibilityCommand(appId: string, options: Options) {
14
- p.intro(`Check compatibility`)
15
- options.apikey = options.apikey || findSavedKey()
16
- const config = await getConfig()
17
- appId = appId || config?.app?.appId
18
-
19
- const { channel } = options
20
-
21
- if (!channel) {
22
- p.log.error('Missing argument, you need to provide a channel')
23
- program.error('')
24
- }
25
-
26
- if (!options.apikey) {
27
- p.log.error('Missing API key, you need to provide a API key to upload your bundle')
28
- program.error('')
29
- }
30
- if (!appId) {
31
- p.log.error('Missing argument, you need to provide a appId, or be in a capacitor project')
32
- program.error('')
33
- }
34
-
35
- const supabase = await createSupabaseClient(options.apikey)
36
- await verifyUser(supabase, options.apikey, ['write', 'all', 'read', 'upload'])
37
-
38
- // Check we have app access to this appId
39
- await checkAppExistsAndHasPermissionOrgErr(supabase, options.apikey, appId, OrganizationPerm.read)
40
-
41
- // const hashedLocalDependencies = new Map(dependenciesObject
42
- // .filter((a) => !!a.native && a.native !== undefined)
43
- // .map((a) => [a.name, a]))
44
-
45
- // const nativePackages = Array.from(hashedLocalDependencies, ([name, value]) => ({ name, version: value.version }))
46
- // await supabase.from('app_versions').update({ native_packages: nativePackages }).eq('id', '9654')
47
-
48
- const { finalCompatibility } = await checkCompatibility(supabase, appId, channel)
49
-
50
- const t = new Table({
51
- title: 'Compatibility',
52
- charLength: { '❌': 2, '✅': 2 },
53
- })
54
-
55
- const yesSymbol = options.text ? 'Yes' : '✅'
56
- const noSymbol = options.text ? 'No' : '❌'
57
-
58
- finalCompatibility.forEach((data) => {
59
- const { name, localVersion, remoteVersion } = data
60
-
61
- t.addRow({
62
- 'Package': name,
63
- 'Local version': localVersion ?? 'None',
64
- 'Remote version': remoteVersion ?? 'None',
65
- 'Compatible': remoteVersion === localVersion ? yesSymbol : noSymbol,
66
- })
67
- })
68
-
69
- p.log.success(t.render())
70
- }
@@ -1,65 +0,0 @@
1
- import { existsSync, readFileSync, writeFileSync } from 'node:fs'
2
- import process from 'node:process'
3
- import { program } from 'commander'
4
- import * as p from '@clack/prompts'
5
- import { decryptSource } from '../api/crypto'
6
- import { baseKeyPub, checKOldEncryption, getConfig } from '../utils'
7
- import { checkLatest } from '../api/update'
8
-
9
- interface Options {
10
- key?: string
11
- keyData?: string
12
- }
13
-
14
- export async function decryptZip(zipPath: string, ivsessionKey: string, options: Options) {
15
- p.intro(`Decrypt zip file`)
16
- await checkLatest()
17
- // write in file .capgo the apikey in home directory
18
-
19
- if (!existsSync(zipPath)) {
20
- p.log.error(`Zip not found at the path ${zipPath}`)
21
- program.error('')
22
- }
23
-
24
- const config = await getConfig()
25
- const { extConfig } = config.app
26
- // console.log('config - ', config)
27
- // console.log('extConfig - ', extConfig)
28
-
29
- await checKOldEncryption()
30
- // console.log(`There ${hasPrivateKeyInConfig ? 'IS' : 'IS NOT'} a privateKey in the config`);
31
-
32
- if (!options.key && !existsSync(baseKeyPub) && !extConfig.plugins?.CapacitorUpdater?.publicKey) {
33
- p.log.error(`Public key not found at the path ${baseKeyPub} or in ${config.app.extConfigFilePath}`)
34
- program.error('')
35
- }
36
- const keyPath = options.key || baseKeyPub
37
- // check if private exist
38
-
39
- let publicKey = extConfig?.plugins?.CapacitorUpdater?.publicKey
40
-
41
- if (!existsSync(keyPath) && !publicKey) {
42
- p.log.error(`Cannot find a public key at ${keyPath} or as keyData option or in ${config.app.extConfigFilePath}`)
43
- program.error('')
44
- }
45
- else if (existsSync(keyPath)) {
46
- // open with fs publicKey path
47
- const keyFile = readFileSync(keyPath)
48
- publicKey = keyFile.toString()
49
- }
50
-
51
- // let's doublecheck and make sure the key we are using is the right type based on the decryption strategy
52
- if (publicKey && !publicKey.startsWith('-----BEGIN RSA PUBLIC KEY-----')) {
53
- p.log.error(`the public key provided is not a valid RSA Public key`)
54
- program.error('')
55
- }
56
-
57
- const zipFile = readFileSync(zipPath)
58
-
59
- const decodedZip = decryptSource(zipFile, ivsessionKey, options.keyData ?? publicKey ?? '')
60
- // write decodedZip in a file
61
- writeFileSync(`${zipPath}_decrypted.zip`, decodedZip)
62
- p.log.success(`Decrypted zip file at ${zipPath}_decrypted.zip`)
63
- p.outro(`Done ✅`)
64
- process.exit()
65
- }
@@ -1,53 +0,0 @@
1
- import process from 'node:process'
2
- import { program } from 'commander'
3
- import * as p from '@clack/prompts'
4
- import { checkAppExistsAndHasPermissionOrgErr } from '../api/app'
5
- import type { OptionsBase } from '../utils'
6
- import { OrganizationPerm, createSupabaseClient, findSavedKey, getConfig, verifyUser } from '../utils'
7
- import { deleteSpecificVersion } from '../api/versions'
8
-
9
- interface Options extends OptionsBase {
10
- bundle: string
11
- }
12
-
13
- export async function deleteBundle(bundleId: string, appId: string, options: Options) {
14
- p.intro(`Delete bundle`)
15
- options.apikey = options.apikey || findSavedKey()
16
- const config = await getConfig()
17
- appId = appId || config?.app?.appId
18
-
19
- if (!options.apikey) {
20
- p.log.error('Missing API key, you need to provide a API key to upload your bundle')
21
- program.error('')
22
- }
23
- if (!appId) {
24
- p.log.error('Missing argument, you need to provide a appId, or be in a capacitor project')
25
- program.error('')
26
- }
27
- const supabase = await createSupabaseClient(options.apikey)
28
-
29
- const userId = await verifyUser(supabase, options.apikey, ['write', 'all'])
30
- // Check we have app access to this appId
31
- await checkAppExistsAndHasPermissionOrgErr(supabase, options.apikey, appId, OrganizationPerm.write)
32
-
33
- appId = appId || config?.app?.appId
34
- if (!options.apikey) {
35
- p.log.error('Missing API key, you need to provide an API key to delete your app')
36
- program.error('')
37
- }
38
- if (!bundleId) {
39
- p.log.error('Missing argument, you need to provide a bundleId, or be in a capacitor project')
40
- program.error('')
41
- }
42
- if (!appId) {
43
- p.log.error('Missing argument, you need to provide a appId, or be in a capacitor project')
44
- program.error('')
45
- }
46
-
47
- p.log.info(`Deleting bundle ${appId}@${bundleId} from Capgo`)
48
-
49
- await deleteSpecificVersion(supabase, appId, userId, bundleId)
50
- p.log.success(`Bundle ${appId}@${bundleId} deleted in Capgo`)
51
- p.outro(`Done`)
52
- process.exit()
53
- }
@@ -1,69 +0,0 @@
1
- import { existsSync, readFileSync, writeFileSync } from 'node:fs'
2
- import process from 'node:process'
3
- import { program } from 'commander'
4
- import ciDetect from 'ci-info'
5
- import * as p from '@clack/prompts'
6
- import { checkLatest } from '../api/update'
7
- import { encryptSource } from '../api/crypto'
8
- import { baseKey, checKOldEncryption, getLocalConfig } from '../utils'
9
-
10
- interface Options {
11
- key?: string
12
- keyData?: string
13
- }
14
-
15
- export async function encryptZip(zipPath: string, options: Options) {
16
- p.intro(`Encryption`)
17
-
18
- await checkLatest()
19
- const localConfig = await getLocalConfig()
20
- // console.log('localConfig - ', localConfig)
21
- // console.log('config - ', config)
22
-
23
- await checKOldEncryption()
24
-
25
- if (!existsSync(zipPath)) {
26
- p.log.error(`Error: Zip not found at the path ${zipPath}`)
27
- program.error('')
28
- }
29
-
30
- const keyPath = options.key || baseKey
31
- // check if privateKey exist
32
-
33
- let privateKey = options.keyData || ''
34
-
35
- if (!existsSync(keyPath) && !privateKey) {
36
- p.log.warning(`Cannot find a private key at ${keyPath} or as a keyData option`)
37
- if (ciDetect.isCI) {
38
- p.log.error(`Error: Missing key`)
39
- program.error('')
40
- }
41
- const res = await p.confirm({ message: `Do you want to use our private key?` })
42
- if (!res) {
43
- p.log.error(`Error: Missing private key`)
44
- program.error('')
45
- }
46
-
47
- privateKey = localConfig.signKey || ''
48
- }
49
- else if (existsSync(keyPath)) {
50
- // open with fs key path
51
- const keyFile = readFileSync(keyPath)
52
- privateKey = keyFile.toString()
53
- }
54
-
55
- // let's doublecheck and make sure the key we are using is the right type based on the decryption strategy
56
- if (privateKey && !privateKey.startsWith('-----BEGIN RSA PRIVATE KEY-----')) {
57
- p.log.error(`the private key provided is not a valid RSA Private key`)
58
- program.error('')
59
- }
60
-
61
- const zipFile = readFileSync(zipPath)
62
- const encodedZip = encryptSource(zipFile, privateKey)
63
- p.log.success(`ivSessionKey: ${encodedZip.ivSessionKey}`)
64
- // write decodedZip in a file
65
- writeFileSync(`${zipPath}_encrypted.zip`, encodedZip.encryptedData)
66
- p.log.success(`Encrypted zip saved at ${zipPath}_encrypted.zip`)
67
- p.outro(`Done ✅`)
68
- process.exit()
69
- }
@@ -1,43 +0,0 @@
1
- import process from 'node:process'
2
- import { program } from 'commander'
3
- import * as p from '@clack/prompts'
4
- import { checkAppExistsAndHasPermissionOrgErr } from '../api/app'
5
- import { displayBundles, getActiveAppVersions } from '../api/versions'
6
- import type { OptionsBase } from '../utils'
7
- import { OrganizationPerm, createSupabaseClient, findSavedKey, getConfig, verifyUser } from '../utils'
8
- import { checkLatest } from '../api/update'
9
-
10
- export async function listBundle(appId: string, options: OptionsBase) {
11
- p.intro(`List bundles`)
12
- await checkLatest()
13
- options.apikey = options.apikey || findSavedKey()
14
- const config = await getConfig()
15
-
16
- appId = appId || config?.app?.appId
17
- if (!options.apikey) {
18
- p.log.error('Missing API key, you need to provide a API key to upload your bundle')
19
- program.error('')
20
- }
21
- if (!appId) {
22
- p.log.error('Missing argument, you need to provide a appid, or be in a capacitor project')
23
- program.error('')
24
- }
25
-
26
- const supabase = await createSupabaseClient(options.apikey)
27
-
28
- const userId = await verifyUser(supabase, options.apikey, ['write', 'all', 'read', 'upload'])
29
-
30
- p.log.info(`Querying available versions of: ${appId} in Capgo`)
31
-
32
- // Check we have app access to this appId
33
- await checkAppExistsAndHasPermissionOrgErr(supabase, options.apikey, appId, OrganizationPerm.read)
34
-
35
- // Get all active app versions we might possibly be able to cleanup
36
- const allVersions = await getActiveAppVersions(supabase, appId, userId)
37
-
38
- p.log.info(`Active versions in Capgo: ${allVersions?.length}`)
39
-
40
- displayBundles(allVersions)
41
- p.outro(`Done ✅`)
42
- process.exit()
43
- }
@@ -1,86 +0,0 @@
1
- import process from 'node:process'
2
- import { program } from 'commander'
3
- import * as p from '@clack/prompts'
4
- import { getVersionData } from '../api/versions'
5
- import { checkVersionNotUsedInDeviceOverride } from '../api/devices_override'
6
- import { checkVersionNotUsedInChannel } from '../api/channels'
7
- import { checkAppExistsAndHasPermissionOrgErr } from '../api/app'
8
- import type {
9
- OptionsBase,
10
- } from '../utils'
11
- import {
12
- OrganizationPerm,
13
- checkPlanValid,
14
- createSupabaseClient,
15
- findSavedKey,
16
- formatError,
17
- getConfig,
18
- getOrganizationId,
19
- useLogSnag,
20
- verifyUser,
21
- } from '../utils'
22
-
23
- interface Options extends OptionsBase {
24
- bundle?: string
25
- }
26
-
27
- export async function unlinkDevice(channel: string, appId: string, options: Options) {
28
- p.intro(`Unlink bundle ${options.apikey}`)
29
- options.apikey = options.apikey || findSavedKey()
30
- const config = await getConfig()
31
- appId = appId || config?.app?.appId
32
- const snag = useLogSnag()
33
- let { bundle } = options
34
-
35
- bundle = bundle || config?.app?.package?.version
36
-
37
- if (!options.apikey) {
38
- p.log.error('Missing API key, you need to provide a API key to upload your bundle')
39
- program.error('')
40
- }
41
- if (!appId) {
42
- p.log.error('Missing argument, you need to provide a appId, or be in a capacitor project')
43
- program.error('')
44
- }
45
- if (!bundle) {
46
- p.log.error('Missing argument, you need to provide a bundle, or be in a capacitor project')
47
- program.error('')
48
- }
49
- const supabase = await createSupabaseClient(options.apikey)
50
-
51
- const [userId, orgId] = await Promise.all([
52
- verifyUser(supabase, options.apikey, ['all', 'write']),
53
- getOrganizationId(supabase, appId),
54
- ])
55
-
56
- // Check we have app access to this appId
57
- await checkAppExistsAndHasPermissionOrgErr(supabase, options.apikey, appId, OrganizationPerm.write)
58
-
59
- if (!channel) {
60
- p.log.error('Missing argument, you need to provide a channel')
61
- program.error('')
62
- }
63
- try {
64
- await checkPlanValid(supabase, orgId, options.apikey, appId)
65
-
66
- const versionData = await getVersionData(supabase, appId, bundle)
67
- await checkVersionNotUsedInChannel(supabase, appId, versionData)
68
- await checkVersionNotUsedInDeviceOverride(supabase, appId, versionData)
69
- await snag.track({
70
- channel: 'bundle',
71
- event: 'Unlink bundle',
72
- icon: '✅',
73
- user_id: userId,
74
- tags: {
75
- 'app-id': appId,
76
- },
77
- notify: false,
78
- }).catch()
79
- }
80
- catch (err) {
81
- p.log.error(`Unknow error ${formatError(err)}`)
82
- program.error('')
83
- }
84
- p.outro('Done ✅')
85
- process.exit()
86
- }