@capgo/cli 4.0.11 → 4.0.13
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 +10 -0
- package/bun.lockb +0 -0
- package/capacitor.config.ts +2 -2
- package/dist/index.js +652 -655
- package/eslint.config.js +3 -0
- package/package.json +3 -2
- package/src/api/app.ts +29 -36
- package/src/api/channels.ts +53 -49
- package/src/api/crypto.ts +83 -80
- package/src/api/devices_override.ts +12 -13
- package/src/api/update.ts +10 -10
- package/src/api/versions.ts +43 -42
- package/src/app/add.ts +61 -53
- package/src/app/debug.ts +153 -151
- package/src/app/delete.ts +61 -59
- package/src/app/info.ts +74 -77
- package/src/app/list.ts +33 -31
- package/src/app/set.ts +85 -82
- package/src/bundle/check.ts +30 -32
- package/src/bundle/cleanup.ts +71 -74
- package/src/bundle/compatibility.ts +52 -55
- package/src/bundle/decrypt.ts +21 -19
- package/src/bundle/delete.ts +27 -25
- package/src/bundle/encrypt.ts +23 -21
- package/src/bundle/list.ts +42 -40
- package/src/bundle/unlink.ts +69 -60
- package/src/bundle/upload.ts +170 -149
- package/src/bundle/zip.ts +122 -117
- package/src/channel/add.ts +62 -60
- package/src/channel/currentBundle.ts +56 -56
- package/src/channel/delete.ts +46 -43
- package/src/channel/list.ts +23 -21
- package/src/channel/set.ts +76 -68
- package/src/index.ts +55 -57
- package/src/init.ts +254 -252
- package/src/key.ts +56 -52
- package/src/login.ts +30 -28
- package/src/types/capacitor__cli.d.ts +2 -3
- package/src/types/supabase.types.ts +505 -505
- package/src/utils.ts +560 -571
- package/.eslintrc +0 -71
package/eslint.config.js
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@capgo/cli",
|
|
3
|
-
"version": "4.0.
|
|
3
|
+
"version": "4.0.13",
|
|
4
4
|
"description": "A CLI to upload to capgo servers",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"pack": "pkg",
|
|
39
39
|
"types": "npx --yes supabase gen types typescript --project-id=xvwzpoazmxkqosrdewyv > src/types/supabase.types.ts",
|
|
40
40
|
"test_rls": "ts-node ./test/test_headers_rls.ts",
|
|
41
|
-
"lint": "eslint
|
|
41
|
+
"lint": "eslint \"src/**/*.ts\" --fix"
|
|
42
42
|
},
|
|
43
43
|
"author": "github.com/riderx",
|
|
44
44
|
"license": "Apache 2.0",
|
|
@@ -65,6 +65,7 @@
|
|
|
65
65
|
"semver": "^7.6.0"
|
|
66
66
|
},
|
|
67
67
|
"devDependencies": {
|
|
68
|
+
"@antfu/eslint-config": "^2.6.4",
|
|
68
69
|
"@types/adm-zip": "0.5.5",
|
|
69
70
|
"@types/mime": "^3.0.4",
|
|
70
71
|
"@types/node": "^20.11.17",
|
package/src/api/app.ts
CHANGED
|
@@ -1,56 +1,50 @@
|
|
|
1
|
-
import { SupabaseClient } from '@supabase/supabase-js'
|
|
2
|
-
import * as p from '@clack/prompts'
|
|
3
|
-
import { program } from 'commander'
|
|
4
|
-
import { Database } from '../types/supabase.types'
|
|
5
|
-
import {
|
|
1
|
+
import type { SupabaseClient } from '@supabase/supabase-js'
|
|
2
|
+
import * as p from '@clack/prompts'
|
|
3
|
+
import { program } from 'commander'
|
|
4
|
+
import type { Database } from '../types/supabase.types'
|
|
5
|
+
import type { OptionsBase } from '../utils'
|
|
6
|
+
import { OrganizationPerm, isAllowedApp, isAllowedAppOrg } from '../utils'
|
|
6
7
|
|
|
7
|
-
export
|
|
8
|
+
export async function checkAppExists(supabase: SupabaseClient<Database>, appid: string) {
|
|
8
9
|
const { data: app } = await supabase
|
|
9
10
|
.rpc('exist_app_v2', { appid })
|
|
10
|
-
.single()
|
|
11
|
-
return !!app
|
|
11
|
+
.single()
|
|
12
|
+
return !!app
|
|
12
13
|
}
|
|
13
14
|
|
|
14
|
-
export
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
const perm = await isAllowedApp(supabase, apikey, appid);
|
|
15
|
+
export async function checkAppExistsAndHasPermissionErr(supabase: SupabaseClient<Database>, apikey: string, appid: string, shouldExist = true) {
|
|
16
|
+
const res = await checkAppExists(supabase, appid)
|
|
17
|
+
const perm = await isAllowedApp(supabase, apikey, appid)
|
|
18
18
|
|
|
19
19
|
if (res && !shouldExist) {
|
|
20
|
-
p.log.error(`App ${appid} already exist`)
|
|
21
|
-
program.error('')
|
|
20
|
+
p.log.error(`App ${appid} already exist`)
|
|
21
|
+
program.error('')
|
|
22
22
|
}
|
|
23
23
|
if (!res && shouldExist) {
|
|
24
|
-
p.log.error(`App ${appid} does not exist`)
|
|
25
|
-
program.error('')
|
|
24
|
+
p.log.error(`App ${appid} does not exist`)
|
|
25
|
+
program.error('')
|
|
26
26
|
}
|
|
27
27
|
if (res && !perm) {
|
|
28
|
-
p.log.error(`App ${appid} exist and you don't have permission to access it`)
|
|
29
|
-
if (appid === 'io.ionic.starter')
|
|
30
|
-
p.log.info('Modify your appid in your capacitor.config.json file to something unique, this is a default appid for ionic starter app')
|
|
31
|
-
|
|
32
|
-
program.error('')
|
|
28
|
+
p.log.error(`App ${appid} exist and you don't have permission to access it`)
|
|
29
|
+
if (appid === 'io.ionic.starter')
|
|
30
|
+
p.log.info('Modify your appid in your capacitor.config.json file to something unique, this is a default appid for ionic starter app')
|
|
31
|
+
|
|
32
|
+
program.error('')
|
|
33
33
|
}
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
export
|
|
37
|
-
supabase: SupabaseClient<Database>,
|
|
38
|
-
apikey: string,
|
|
39
|
-
appid: string,
|
|
40
|
-
requiredPermission: OrganizationPerm
|
|
41
|
-
) => {
|
|
36
|
+
export async function checkAppExistsAndHasPermissionOrgErr(supabase: SupabaseClient<Database>, apikey: string, appid: string, requiredPermission: OrganizationPerm) {
|
|
42
37
|
const permissions = await isAllowedAppOrg(supabase, apikey, appid)
|
|
43
38
|
if (!permissions.okay) {
|
|
44
|
-
// eslint-disable-next-line default-case
|
|
45
39
|
switch (permissions.error) {
|
|
46
40
|
case 'INVALID_APIKEY': {
|
|
47
41
|
p.log.error('Invalid apikey, such apikey does not exists!')
|
|
48
|
-
program.error('')
|
|
42
|
+
program.error('')
|
|
49
43
|
break
|
|
50
44
|
}
|
|
51
45
|
case 'NO_APP': {
|
|
52
|
-
p.log.error(`App ${appid} does not exist`)
|
|
53
|
-
program.error('')
|
|
46
|
+
p.log.error(`App ${appid} does not exist`)
|
|
47
|
+
program.error('')
|
|
54
48
|
break
|
|
55
49
|
}
|
|
56
50
|
case 'NO_ORG': {
|
|
@@ -65,7 +59,6 @@ export const checkAppExistsAndHasPermissionOrgErr = async (
|
|
|
65
59
|
const requiredPermNumber = requiredPermission as number
|
|
66
60
|
|
|
67
61
|
if (requiredPermNumber > remotePermNumber) {
|
|
68
|
-
// eslint-disable-next-line max-len
|
|
69
62
|
p.log.error(`Insuficcent permissions for app ${appid}. Current permission: ${OrganizationPerm[permissions.data]}, required for this action: ${OrganizationPerm[requiredPermission]}.`)
|
|
70
63
|
program.error('')
|
|
71
64
|
}
|
|
@@ -74,9 +67,9 @@ export const checkAppExistsAndHasPermissionOrgErr = async (
|
|
|
74
67
|
}
|
|
75
68
|
|
|
76
69
|
export interface Options extends OptionsBase {
|
|
77
|
-
name?: string
|
|
78
|
-
icon?: string
|
|
79
|
-
retention?: number
|
|
70
|
+
name?: string
|
|
71
|
+
icon?: string
|
|
72
|
+
retention?: number
|
|
80
73
|
}
|
|
81
74
|
|
|
82
|
-
export const newIconPath =
|
|
75
|
+
export const newIconPath = 'assets/icon.png'
|
package/src/api/channels.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
1
|
+
import process from 'node:process'
|
|
2
|
+
import type { SupabaseClient } from '@supabase/supabase-js'
|
|
3
|
+
import { program } from 'commander'
|
|
4
|
+
import { Table } from 'console-table-printer'
|
|
5
|
+
import * as p from '@clack/prompts'
|
|
6
|
+
import type { Database } from '../types/supabase.types'
|
|
7
|
+
import { formatError, getHumanDate } from '../utils'
|
|
7
8
|
|
|
8
|
-
export
|
|
9
|
-
appid: string, userId: string, versionData: Database['public']['Tables']['app_versions']['Row']) => {
|
|
9
|
+
export async function checkVersionNotUsedInChannel(supabase: SupabaseClient<Database>, appid: string, userId: string, versionData: Database['public']['Tables']['app_versions']['Row']) {
|
|
10
10
|
const { data: channelFound, error: errorChannel } = await supabase
|
|
11
11
|
.from('channels')
|
|
12
12
|
.select()
|
|
@@ -14,20 +14,20 @@ export const checkVersionNotUsedInChannel = async (supabase: SupabaseClient<Data
|
|
|
14
14
|
.eq('created_by', userId)
|
|
15
15
|
.eq('version', versionData.id)
|
|
16
16
|
if (errorChannel) {
|
|
17
|
-
p.log.error(`Cannot check Version ${appid}@${versionData.name}`)
|
|
18
|
-
program.error('')
|
|
17
|
+
p.log.error(`Cannot check Version ${appid}@${versionData.name}`)
|
|
18
|
+
program.error('')
|
|
19
19
|
}
|
|
20
20
|
if (channelFound && channelFound.length > 0) {
|
|
21
21
|
p.intro(`❌ Version ${appid}@${versionData.name} is used in ${channelFound.length} channel`)
|
|
22
22
|
if (await p.confirm({ message: 'unlink it?' })) {
|
|
23
23
|
// loop on all channels and set version to unknown
|
|
24
24
|
for (const channel of channelFound) {
|
|
25
|
-
const s = p.spinner()
|
|
25
|
+
const s = p.spinner()
|
|
26
26
|
s.start(`Unlinking channel ${channel.name}`)
|
|
27
27
|
const { error: errorChannelUpdate } = await supabase
|
|
28
28
|
.from('channels')
|
|
29
29
|
.update({
|
|
30
|
-
version: (await findUnknownVersion(supabase, appid))?.id
|
|
30
|
+
version: (await findUnknownVersion(supabase, appid))?.id,
|
|
31
31
|
})
|
|
32
32
|
.eq('id', channel.id)
|
|
33
33
|
if (errorChannelUpdate) {
|
|
@@ -38,66 +38,70 @@ export const checkVersionNotUsedInChannel = async (supabase: SupabaseClient<Data
|
|
|
38
38
|
}
|
|
39
39
|
}
|
|
40
40
|
else {
|
|
41
|
-
p.log.error(`Unlink it first`)
|
|
42
|
-
program.error('')
|
|
41
|
+
p.log.error(`Unlink it first`)
|
|
42
|
+
program.error('')
|
|
43
43
|
}
|
|
44
44
|
p.outro(`Version unlinked from ${channelFound.length} channel`)
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
|
|
48
|
-
export
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
export const createChannel = (supabase: SupabaseClient<Database>, update: Database['public']['Tables']['channels']['Insert']) => supabase
|
|
58
|
-
.from('channels')
|
|
59
|
-
.insert(update)
|
|
60
|
-
.select()
|
|
61
|
-
.single()
|
|
48
|
+
export function findUnknownVersion(supabase: SupabaseClient<Database>, appId: string) {
|
|
49
|
+
return supabase
|
|
50
|
+
.from('app_versions')
|
|
51
|
+
.select('id')
|
|
52
|
+
.eq('app_id', appId)
|
|
53
|
+
.eq('name', 'unknown')
|
|
54
|
+
.throwOnError()
|
|
55
|
+
.single().then(({ data }) => data)
|
|
56
|
+
}
|
|
62
57
|
|
|
63
|
-
export
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
58
|
+
export function createChannel(supabase: SupabaseClient<Database>, update: Database['public']['Tables']['channels']['Insert']) {
|
|
59
|
+
return supabase
|
|
60
|
+
.from('channels')
|
|
61
|
+
.insert(update)
|
|
62
|
+
.select()
|
|
63
|
+
.single()
|
|
64
|
+
}
|
|
70
65
|
|
|
66
|
+
export function delChannel(supabase: SupabaseClient<Database>, name: string, appId: string, userId: string) {
|
|
67
|
+
return supabase
|
|
68
|
+
.from('channels')
|
|
69
|
+
.delete()
|
|
70
|
+
.eq('name', name)
|
|
71
|
+
.eq('app_id', appId)
|
|
72
|
+
.eq('created_by', userId)
|
|
73
|
+
.single()
|
|
74
|
+
}
|
|
71
75
|
|
|
72
|
-
export
|
|
76
|
+
export function displayChannels(data: (Database['public']['Tables']['channels']['Row'] & { keep?: string })[]) {
|
|
73
77
|
const t = new Table({
|
|
74
|
-
title:
|
|
75
|
-
charLength: {
|
|
76
|
-
})
|
|
78
|
+
title: 'Channels',
|
|
79
|
+
charLength: { '❌': 2, '✅': 2 },
|
|
80
|
+
})
|
|
77
81
|
|
|
78
82
|
// add rows with color
|
|
79
|
-
data.reverse().forEach(row => {
|
|
83
|
+
data.reverse().forEach((row) => {
|
|
80
84
|
t.addRow({
|
|
81
85
|
Name: row.name,
|
|
82
86
|
Created: getHumanDate(row.created_at),
|
|
83
|
-
Public: row.public ? '✅' : '❌'
|
|
84
|
-
})
|
|
85
|
-
})
|
|
87
|
+
Public: row.public ? '✅' : '❌',
|
|
88
|
+
})
|
|
89
|
+
})
|
|
86
90
|
|
|
87
|
-
p.log.success(t.render())
|
|
91
|
+
p.log.success(t.render())
|
|
88
92
|
}
|
|
89
93
|
|
|
90
|
-
export
|
|
94
|
+
export async function getActiveChannels(supabase: SupabaseClient<Database>, appid: string) {
|
|
91
95
|
const { data, error: vError } = await supabase
|
|
92
96
|
.from('channels')
|
|
93
97
|
.select()
|
|
94
98
|
.eq('app_id', appid)
|
|
95
99
|
// .eq('created_by', userId)
|
|
96
|
-
.order('created_at', { ascending: false })
|
|
100
|
+
.order('created_at', { ascending: false })
|
|
97
101
|
|
|
98
102
|
if (vError) {
|
|
99
|
-
p.log.error(`App ${appid} not found in database`)
|
|
100
|
-
program.error('')
|
|
103
|
+
p.log.error(`App ${appid} not found in database`)
|
|
104
|
+
program.error('')
|
|
101
105
|
}
|
|
102
|
-
return data
|
|
106
|
+
return data
|
|
103
107
|
}
|
package/src/api/crypto.ts
CHANGED
|
@@ -1,97 +1,100 @@
|
|
|
1
|
-
|
|
2
1
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
2
|
+
constants,
|
|
3
|
+
createCipheriv,
|
|
4
|
+
createDecipheriv,
|
|
5
|
+
generateKeyPairSync,
|
|
6
|
+
privateDecrypt,
|
|
7
|
+
publicEncrypt,
|
|
8
|
+
randomBytes,
|
|
9
|
+
} from 'node:crypto'
|
|
10
|
+
import { Buffer } from 'node:buffer'
|
|
8
11
|
|
|
9
|
-
const algorithm =
|
|
10
|
-
const oaepHash = 'sha256'
|
|
11
|
-
const formatB64 = 'base64'
|
|
12
|
-
const padding = constants.RSA_PKCS1_OAEP_PADDING
|
|
12
|
+
const algorithm = 'aes-128-cbc'
|
|
13
|
+
const oaepHash = 'sha256'
|
|
14
|
+
const formatB64 = 'base64'
|
|
15
|
+
const padding = constants.RSA_PKCS1_OAEP_PADDING
|
|
13
16
|
|
|
14
|
-
export
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
17
|
+
export function decryptSource(source: Buffer, ivSessionKey: string, privateKey: string): Buffer {
|
|
18
|
+
// console.log('\nivSessionKey', ivSessionKey)
|
|
19
|
+
const [ivB64, sessionb64Encrypted] = ivSessionKey.split(':')
|
|
20
|
+
// console.log('\nsessionb64Encrypted', sessionb64Encrypted)
|
|
21
|
+
// console.log('\nivB64', ivB64)
|
|
22
|
+
const sessionKey = privateDecrypt(
|
|
23
|
+
{
|
|
24
|
+
key: privateKey,
|
|
25
|
+
padding,
|
|
26
|
+
oaepHash,
|
|
27
|
+
},
|
|
28
|
+
Buffer.from(sessionb64Encrypted, formatB64),
|
|
29
|
+
)
|
|
30
|
+
// ivB64 to uft-8
|
|
31
|
+
const initVector = Buffer.from(ivB64, formatB64)
|
|
32
|
+
// console.log('\nSessionB64', sessionB64)
|
|
30
33
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
+
const decipher = createDecipheriv(algorithm, sessionKey, initVector)
|
|
35
|
+
decipher.setAutoPadding(true)
|
|
36
|
+
const decryptedData = Buffer.concat([decipher.update(source), decipher.final()])
|
|
34
37
|
|
|
35
|
-
|
|
38
|
+
return decryptedData
|
|
36
39
|
}
|
|
37
40
|
export interface Encoded {
|
|
38
|
-
|
|
39
|
-
|
|
41
|
+
ivSessionKey: string
|
|
42
|
+
encryptedData: Buffer
|
|
40
43
|
}
|
|
41
|
-
export
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
44
|
+
export function encryptSource(source: Buffer, publicKey: string): Encoded {
|
|
45
|
+
// encrypt zip with key
|
|
46
|
+
const initVector = randomBytes(16)
|
|
47
|
+
const sessionKey = randomBytes(16)
|
|
48
|
+
// encrypt session key with public key
|
|
49
|
+
// console.log('\nencrypted.key', encrypted.key.toString(CryptoJS.enc.Base64))
|
|
50
|
+
const cipher = createCipheriv(algorithm, sessionKey, initVector)
|
|
51
|
+
cipher.setAutoPadding(true)
|
|
52
|
+
// console.log('\nsessionKey', sessionKey.toString())
|
|
53
|
+
// const sessionB64 = sessionKey.toString(formatB64)
|
|
54
|
+
// console.log('\nsessionB64', sessionB64)
|
|
55
|
+
const ivB64 = initVector.toString(formatB64)
|
|
56
|
+
// console.log('\nivB64', ivB64)
|
|
57
|
+
const sessionb64Encrypted = publicEncrypt(
|
|
58
|
+
{
|
|
59
|
+
key: publicKey,
|
|
60
|
+
padding,
|
|
61
|
+
oaepHash,
|
|
62
|
+
},
|
|
63
|
+
sessionKey,
|
|
64
|
+
).toString(formatB64)
|
|
65
|
+
// console.log('\nsessionb64Encrypted', sessionb64Encrypted)
|
|
66
|
+
const ivSessionKey = `${ivB64}:${sessionb64Encrypted}`
|
|
67
|
+
// console.log('\nivSessionKey', sessionKey)
|
|
68
|
+
// encrypted to buffer
|
|
66
69
|
|
|
67
|
-
|
|
70
|
+
const encryptedData = Buffer.concat([cipher.update(source), cipher.final()])
|
|
68
71
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
72
|
+
return {
|
|
73
|
+
encryptedData,
|
|
74
|
+
ivSessionKey,
|
|
75
|
+
}
|
|
73
76
|
}
|
|
74
77
|
export interface RSAKeys {
|
|
75
|
-
|
|
76
|
-
|
|
78
|
+
publicKey: string
|
|
79
|
+
privateKey: string
|
|
77
80
|
}
|
|
78
|
-
export
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
81
|
+
export function createRSA(): RSAKeys {
|
|
82
|
+
const { publicKey, privateKey } = generateKeyPairSync('rsa', {
|
|
83
|
+
// The standard secure default length for RSA keys is 2048 bits
|
|
84
|
+
modulusLength: 2048,
|
|
85
|
+
})
|
|
83
86
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
87
|
+
// Generate RSA key pair
|
|
88
|
+
return {
|
|
89
|
+
publicKey: publicKey.export({
|
|
90
|
+
type: 'pkcs1',
|
|
91
|
+
format: 'pem',
|
|
92
|
+
}) as string,
|
|
93
|
+
privateKey: privateKey.export({
|
|
94
|
+
type: 'pkcs1',
|
|
95
|
+
format: 'pem',
|
|
96
|
+
}) as string,
|
|
97
|
+
}
|
|
95
98
|
}
|
|
96
99
|
// test AES
|
|
97
100
|
|
|
@@ -1,27 +1,26 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
|
|
7
|
-
export const checkVersionNotUsedInDeviceOverride = async (supabase: SupabaseClient<Database>,
|
|
8
|
-
appid: string, versionData: Database['public']['Tables']['app_versions']['Row']) => {
|
|
1
|
+
import process from 'node:process'
|
|
2
|
+
import type { SupabaseClient } from '@supabase/supabase-js'
|
|
3
|
+
import { program } from 'commander'
|
|
4
|
+
import * as p from '@clack/prompts'
|
|
5
|
+
import type { Database } from '../types/supabase.types'
|
|
6
|
+
import { formatError } from '../utils'
|
|
9
7
|
|
|
8
|
+
export async function checkVersionNotUsedInDeviceOverride(supabase: SupabaseClient<Database>, appid: string, versionData: Database['public']['Tables']['app_versions']['Row']) {
|
|
10
9
|
const { data: deviceFound, error: errorDevice } = await supabase
|
|
11
10
|
.from('devices_override')
|
|
12
11
|
.select()
|
|
13
12
|
.eq('app_id', appid)
|
|
14
13
|
.eq('version', versionData.id)
|
|
15
14
|
if (errorDevice) {
|
|
16
|
-
p.log.error(`Cannot check Device override ${appid}@${versionData.name}`)
|
|
17
|
-
program.error('')
|
|
15
|
+
p.log.error(`Cannot check Device override ${appid}@${versionData.name}`)
|
|
16
|
+
program.error('')
|
|
18
17
|
}
|
|
19
18
|
if (deviceFound && deviceFound.length > 0) {
|
|
20
19
|
p.intro(`❌ Version ${appid}@${versionData.name} is used in ${deviceFound.length} device override`)
|
|
21
20
|
if (await p.confirm({ message: 'unlink it?' })) {
|
|
22
21
|
// loop on all devices and set version to unknown
|
|
23
22
|
for (const device of deviceFound) {
|
|
24
|
-
const s = p.spinner()
|
|
23
|
+
const s = p.spinner()
|
|
25
24
|
s.start(`Unlinking device ${device.device_id}`)
|
|
26
25
|
const { error: errorDeviceDel } = await supabase
|
|
27
26
|
.from('devices_override')
|
|
@@ -35,8 +34,8 @@ export const checkVersionNotUsedInDeviceOverride = async (supabase: SupabaseClie
|
|
|
35
34
|
}
|
|
36
35
|
}
|
|
37
36
|
else {
|
|
38
|
-
p.log.error(`Unlink it first`)
|
|
39
|
-
program.error('')
|
|
37
|
+
p.log.error(`Unlink it first`)
|
|
38
|
+
program.error('')
|
|
40
39
|
}
|
|
41
40
|
}
|
|
42
41
|
}
|
package/src/api/update.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import getLatest from
|
|
2
|
-
import * as p from '@clack/prompts'
|
|
1
|
+
import getLatest from 'get-latest-version'
|
|
2
|
+
import * as p from '@clack/prompts'
|
|
3
3
|
import pack from '../../package.json'
|
|
4
4
|
|
|
5
|
-
export
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
Please use @capgo/cli@${latest}" or @capgo/cli@latest to keep up to date with the latest features and bug fixes
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
}
|
|
5
|
+
export async function checkLatest() {
|
|
6
|
+
const latest = await getLatest('@capgo/cli')
|
|
7
|
+
if (latest !== pack.version) {
|
|
8
|
+
p.log.warning(`🚨 You are using @capgo/cli@${pack.version} it's not the latest version.
|
|
9
|
+
Please use @capgo/cli@${latest}" or @capgo/cli@latest to keep up to date with the latest features and bug fixes.`,
|
|
10
|
+
)
|
|
11
|
+
}
|
|
12
|
+
}
|