@capgo/cli 2.2.10 → 2.3.5
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 +42 -0
- package/README.md +6 -2
- package/dist/index.js +1 -1
- package/package.json +6 -4
- package/src/api/app.ts +2 -1
- package/src/api/channels.ts +11 -6
- package/src/api/devices_override.ts +11 -7
- package/src/api/versions.ts +25 -5
- package/src/bin/add.ts +7 -7
- package/src/bin/cleanup.ts +34 -31
- package/src/bin/delete.ts +6 -5
- package/src/bin/index.ts +1 -1
- package/src/bin/list.ts +5 -8
- package/src/bin/set.ts +4 -3
- package/src/bin/upload.ts +12 -5
- package/src/bin/utils.ts +40 -21
- package/src/types/supabase.types.ts +1031 -0
- package/test/test_headers_rls.ts +4 -2
- package/src/types/types_supabase.ts +0 -4607
package/src/bin/delete.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { program } from 'commander';
|
|
2
2
|
import { createSupabaseClient, findSavedKey, formatError, getConfig, useLogSnag, verifyUser } from './utils';
|
|
3
|
-
import { definitions } from '../types/types_supabase';
|
|
3
|
+
// import { definitions } from '../types/types_supabase';
|
|
4
4
|
import { deleteSpecificVersion } from '../api/versions';
|
|
5
5
|
|
|
6
6
|
interface Options {
|
|
@@ -27,7 +27,8 @@ export const deleteApp = async (appid: string, options: Options) => {
|
|
|
27
27
|
const userId = await verifyUser(supabase, apikey);
|
|
28
28
|
|
|
29
29
|
const { data: app, error: dbError0 } = await supabase
|
|
30
|
-
.rpc
|
|
30
|
+
.rpc('exist_app', { appid, apikey })
|
|
31
|
+
.single()
|
|
31
32
|
if (!app || dbError0) {
|
|
32
33
|
program.error('No permission to delete')
|
|
33
34
|
}
|
|
@@ -42,7 +43,7 @@ export const deleteApp = async (appid: string, options: Options) => {
|
|
|
42
43
|
|
|
43
44
|
console.log(`Delete ${appid} from Capgo`);
|
|
44
45
|
const { data, error: vError } = await supabase
|
|
45
|
-
.from
|
|
46
|
+
.from('app_versions')
|
|
46
47
|
.select()
|
|
47
48
|
.eq('app_id', appid)
|
|
48
49
|
.eq('user_id', userId)
|
|
@@ -63,7 +64,7 @@ export const deleteApp = async (appid: string, options: Options) => {
|
|
|
63
64
|
}
|
|
64
65
|
|
|
65
66
|
const { error: delAppVersionError } = await supabase
|
|
66
|
-
.from
|
|
67
|
+
.from('app_versions')
|
|
67
68
|
.delete()
|
|
68
69
|
.eq('app_id', appid)
|
|
69
70
|
.eq('user_id', userId)
|
|
@@ -73,7 +74,7 @@ export const deleteApp = async (appid: string, options: Options) => {
|
|
|
73
74
|
}
|
|
74
75
|
|
|
75
76
|
const { error: dbAppError } = await supabase
|
|
76
|
-
.from
|
|
77
|
+
.from('apps')
|
|
77
78
|
.delete()
|
|
78
79
|
.eq('app_id', appid)
|
|
79
80
|
.eq('user_id', userId)
|
package/src/bin/index.ts
CHANGED
|
@@ -86,7 +86,7 @@ program
|
|
|
86
86
|
.alias('c')
|
|
87
87
|
.description('Cleanup versions in capgo Cloud')
|
|
88
88
|
.action(cleanupApp)
|
|
89
|
-
.
|
|
89
|
+
.option('-b, --bundle <bundle>', 'bundle version number of the app to delete')
|
|
90
90
|
.option('-a, --apikey <apikey>', 'apikey to link to your account')
|
|
91
91
|
.option('-k, --keep <keep>', 'number of version to keep')
|
|
92
92
|
.option('-f, --force', 'force removal');
|
package/src/bin/list.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { program } from 'commander';
|
|
2
|
-
import { createSupabaseClient, findSavedKey, getConfig,
|
|
2
|
+
import { createSupabaseClient, findSavedKey, getConfig, verifyUser } from './utils';
|
|
3
3
|
import { checkAppExistsAndHasPermission } from '../api/app';
|
|
4
|
-
import { getActiveAppVersions } from '../api/versions';
|
|
4
|
+
import { displayBundles, getActiveAppVersions } from '../api/versions';
|
|
5
5
|
|
|
6
6
|
interface Options {
|
|
7
7
|
apikey: string;
|
|
@@ -29,13 +29,10 @@ export const listApp = async (appid: string, options: Options) => {
|
|
|
29
29
|
await checkAppExistsAndHasPermission(supabase, appid, apikey);
|
|
30
30
|
|
|
31
31
|
// Get all active app versions we might possibly be able to cleanup
|
|
32
|
-
const
|
|
32
|
+
const allVersions = await getActiveAppVersions(supabase, appid, userId);
|
|
33
33
|
|
|
34
|
-
console.log(`Active versions in Capgo: ${
|
|
34
|
+
console.log(`Active versions in Capgo: ${allVersions?.length}`);
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
// convert created_at to human time
|
|
38
|
-
console.log(`${row.name} created on ${(getHumanDate(row))}`);
|
|
39
|
-
});
|
|
36
|
+
displayBundles(allVersions);
|
|
40
37
|
|
|
41
38
|
}
|
package/src/bin/set.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { program } from 'commander';
|
|
2
|
+
import { Database } from 'types/supabase.types';
|
|
2
3
|
import {
|
|
3
4
|
getConfig, createSupabaseClient, updateOrCreateChannel,
|
|
4
5
|
formatError, findSavedKey, checkPlanValid, useLogSnag, verifyUser
|
|
5
6
|
} from './utils';
|
|
6
|
-
import { definitions } from '../types/types_supabase';
|
|
7
|
+
// import { definitions } from '../types/types_supabase';
|
|
7
8
|
|
|
8
9
|
interface Options {
|
|
9
10
|
apikey: string;
|
|
@@ -48,7 +49,7 @@ export const setChannel = async (appid: string, options: Options) => {
|
|
|
48
49
|
const supabase = createSupabaseClient(apikey)
|
|
49
50
|
const userId = await verifyUser(supabase, apikey, ['write', 'all']);
|
|
50
51
|
await checkPlanValid(supabase, userId)
|
|
51
|
-
const channelPayload: Partial<
|
|
52
|
+
const channelPayload: Partial<Database['public']['Tables']['channels']['Row']> = {
|
|
52
53
|
created_by: userId,
|
|
53
54
|
app_id: appid,
|
|
54
55
|
name: channel,
|
|
@@ -56,7 +57,7 @@ export const setChannel = async (appid: string, options: Options) => {
|
|
|
56
57
|
const bundleVersion = latest ? config?.app?.package?.version : bundle
|
|
57
58
|
if (bundleVersion) {
|
|
58
59
|
const { data, error: vError } = await supabase
|
|
59
|
-
.from
|
|
60
|
+
.from('app_versions')
|
|
60
61
|
.select()
|
|
61
62
|
.eq('app_id', appid)
|
|
62
63
|
.eq('name', bundleVersion)
|
package/src/bin/upload.ts
CHANGED
|
@@ -7,7 +7,9 @@ import { checksum as getChecksum } from '@tomasklaen/checksum';
|
|
|
7
7
|
import { encryptSource } from '../api/crypto';
|
|
8
8
|
import {
|
|
9
9
|
host, hostWeb, getConfig, createSupabaseClient,
|
|
10
|
-
updateOrCreateChannel, updateOrCreateVersion,
|
|
10
|
+
updateOrCreateChannel, updateOrCreateVersion,
|
|
11
|
+
formatError, findSavedKey, checkPlanValid,
|
|
12
|
+
useLogSnag, verifyUser, regexSemver, baseKeyPub, convertAppName
|
|
11
13
|
} from './utils';
|
|
12
14
|
|
|
13
15
|
interface Options {
|
|
@@ -63,6 +65,7 @@ export const uploadVersion = async (appid: string, options: Options) => {
|
|
|
63
65
|
// checking if user has access rights before uploading
|
|
64
66
|
const { data: versionExist, error: versionExistError } = await supabase
|
|
65
67
|
.rpc('exist_app_versions', { apikey, name_version: bundle, appid })
|
|
68
|
+
.single()
|
|
66
69
|
|
|
67
70
|
if (versionExist || versionExistError) {
|
|
68
71
|
multibar.stop()
|
|
@@ -70,7 +73,7 @@ export const uploadVersion = async (appid: string, options: Options) => {
|
|
|
70
73
|
}
|
|
71
74
|
b1.increment();
|
|
72
75
|
const { data: isTrial, error: isTrialsError } = await supabase
|
|
73
|
-
.rpc
|
|
76
|
+
.rpc('is_trial', { userid: userId })
|
|
74
77
|
.single()
|
|
75
78
|
if (isTrial && isTrial > 0 || isTrialsError) {
|
|
76
79
|
multibar.log(`WARNING !!\nTrial expires in ${isTrial} days, upgrade here: ${hostWeb}/dashboard/settings/plans\n`);
|
|
@@ -78,7 +81,9 @@ export const uploadVersion = async (appid: string, options: Options) => {
|
|
|
78
81
|
b1.increment();
|
|
79
82
|
|
|
80
83
|
const { data: app, error: appError } = await supabase
|
|
81
|
-
.rpc
|
|
84
|
+
.rpc('exist_app', { appid, apikey })
|
|
85
|
+
.single()
|
|
86
|
+
|
|
82
87
|
if (!app || appError) {
|
|
83
88
|
multibar.stop()
|
|
84
89
|
program.error(`Cannot find app ${appid} in your account \n${formatError(appError)}`)
|
|
@@ -86,7 +91,9 @@ export const uploadVersion = async (appid: string, options: Options) => {
|
|
|
86
91
|
b1.increment();
|
|
87
92
|
// check if app already exist
|
|
88
93
|
const { data: appVersion, error: appVersionError } = await supabase
|
|
89
|
-
.rpc
|
|
94
|
+
.rpc('exist_app_versions', { appid, apikey, name_version: bundle })
|
|
95
|
+
.single()
|
|
96
|
+
|
|
90
97
|
if (appVersion || appVersionError) {
|
|
91
98
|
program.error(`Version already exists ${formatError(appVersionError)}`)
|
|
92
99
|
}
|
|
@@ -171,7 +178,7 @@ export const uploadVersion = async (appid: string, options: Options) => {
|
|
|
171
178
|
multibar.log('Cannot set bundle with upload key, use key with more rights for that\n');
|
|
172
179
|
}
|
|
173
180
|
multibar.stop()
|
|
174
|
-
const appidWeb = appid
|
|
181
|
+
const appidWeb = convertAppName(appid)
|
|
175
182
|
console.log("App uploaded to server")
|
|
176
183
|
console.log(`Try it in mobile app: ${host}/app_mobile`)
|
|
177
184
|
console.log(`Or set the channel ${channel} as public here: ${hostWeb}/app/package/${appidWeb}`)
|
package/src/bin/utils.ts
CHANGED
|
@@ -5,7 +5,7 @@ import prettyjson from 'prettyjson';
|
|
|
5
5
|
import { existsSync, readFileSync } from 'fs';
|
|
6
6
|
import { homedir } from 'os';
|
|
7
7
|
import { LogSnag } from 'logsnag';
|
|
8
|
-
import {
|
|
8
|
+
import { Database } from 'types/supabase.types';
|
|
9
9
|
|
|
10
10
|
export const baseKey = '.capgo_key';
|
|
11
11
|
export const baseKeyPub = `${baseKey}.pub`;
|
|
@@ -23,9 +23,11 @@ export const supaAnon = process.env.SUPA_DB === 'production'
|
|
|
23
23
|
: 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImF1Y3N5YnZuaGF2b2dkbXp3dGN3Iiwicm9sZSI6ImFub24iLCJpYXQiOjE2NTQ1Mzk1MDYsImV4cCI6MTk3MDExNTUwNn0.HyuZmo_EjF5fgZQU3g37bdNardK1CLHgxXmYqtr59bo'
|
|
24
24
|
/* eslint-enable */
|
|
25
25
|
|
|
26
|
-
export const createSupabaseClient = (apikey: string) => createClient(hostSupa, supaAnon, {
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
export const createSupabaseClient = (apikey: string) => createClient<Database>(hostSupa, supaAnon, {
|
|
27
|
+
global: {
|
|
28
|
+
headers: {
|
|
29
|
+
capgkey: apikey,
|
|
30
|
+
}
|
|
29
31
|
}
|
|
30
32
|
})
|
|
31
33
|
// eslint-disable-next-line max-len
|
|
@@ -34,6 +36,7 @@ export const regexSemver = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[
|
|
|
34
36
|
export const checkKey = async (supabase: SupabaseClient, apikey: string, keymode: string[]) => {
|
|
35
37
|
const { data: apiAccess, error: apiAccessError } = await supabase
|
|
36
38
|
.rpc('is_allowed_capgkey', { apikey, keymode })
|
|
39
|
+
.single()
|
|
37
40
|
|
|
38
41
|
if (!apiAccess || apiAccessError) {
|
|
39
42
|
program.error(`Invalid API key or insufficient permissions ${formatError(apiAccessError)}`);
|
|
@@ -42,7 +45,7 @@ export const checkKey = async (supabase: SupabaseClient, apikey: string, keymode
|
|
|
42
45
|
|
|
43
46
|
export const isGoodPlan = async (supabase: SupabaseClient, userId: string): Promise<boolean> => {
|
|
44
47
|
const { data, error } = await supabase
|
|
45
|
-
.rpc
|
|
48
|
+
.rpc('is_good_plan_v2', { userid: userId })
|
|
46
49
|
.single()
|
|
47
50
|
if (error) {
|
|
48
51
|
throw error
|
|
@@ -52,7 +55,7 @@ export const isGoodPlan = async (supabase: SupabaseClient, userId: string): Prom
|
|
|
52
55
|
|
|
53
56
|
export const isPaying = async (supabase: SupabaseClient, userId: string): Promise<boolean> => {
|
|
54
57
|
const { data, error } = await supabase
|
|
55
|
-
.rpc
|
|
58
|
+
.rpc('is_paying', { userid: userId })
|
|
56
59
|
.single()
|
|
57
60
|
if (error) {
|
|
58
61
|
throw error
|
|
@@ -62,7 +65,7 @@ export const isPaying = async (supabase: SupabaseClient, userId: string): Promis
|
|
|
62
65
|
|
|
63
66
|
export const isTrial = async (supabase: SupabaseClient, userId: string): Promise<number> => {
|
|
64
67
|
const { data, error } = await supabase
|
|
65
|
-
.rpc
|
|
68
|
+
.rpc('is_trial', { userid: userId })
|
|
66
69
|
.single()
|
|
67
70
|
if (error) {
|
|
68
71
|
throw error
|
|
@@ -72,7 +75,7 @@ export const isTrial = async (supabase: SupabaseClient, userId: string): Promise
|
|
|
72
75
|
|
|
73
76
|
export const isAllowedAction = async (supabase: SupabaseClient, userId: string): Promise<boolean> => {
|
|
74
77
|
const { data, error } = await supabase
|
|
75
|
-
.rpc
|
|
78
|
+
.rpc('is_allowed_action_user', { userid: userId })
|
|
76
79
|
.single()
|
|
77
80
|
if (error) {
|
|
78
81
|
throw error
|
|
@@ -96,11 +99,13 @@ export const findSavedKey = () => {
|
|
|
96
99
|
const userHomeDir = homedir();
|
|
97
100
|
let keyPath = `${userHomeDir}/.capgo`;
|
|
98
101
|
if (existsSync(keyPath)) {
|
|
102
|
+
console.log(`Use global apy key ${keyPath}`)
|
|
99
103
|
const key = readFileSync(keyPath, 'utf8');
|
|
100
104
|
return key.trim();
|
|
101
105
|
}
|
|
102
106
|
keyPath = `.capgo`;
|
|
103
107
|
if (existsSync(keyPath)) {
|
|
108
|
+
console.log(`Use local apy key ${keyPath}`)
|
|
104
109
|
const key = readFileSync(keyPath, 'utf8');
|
|
105
110
|
return key.trim();
|
|
106
111
|
}
|
|
@@ -131,47 +136,59 @@ export const getConfig = async () => {
|
|
|
131
136
|
return config;
|
|
132
137
|
}
|
|
133
138
|
|
|
134
|
-
export const updateOrCreateVersion = async (supabase: SupabaseClient,
|
|
139
|
+
export const updateOrCreateVersion = async (supabase: SupabaseClient,
|
|
140
|
+
update: Partial<Database['public']['Tables']['app_versions']['Row']>, apikey: string) => {
|
|
135
141
|
// console.log('updateOrCreateVersion', update, apikey)
|
|
136
142
|
const { data, error } = await supabase
|
|
137
|
-
.rpc
|
|
143
|
+
.rpc('exist_app_versions', { appid: update.app_id, name_version: update.name, apikey })
|
|
144
|
+
.single()
|
|
145
|
+
|
|
138
146
|
if (data && !error) {
|
|
139
147
|
update.deleted = false
|
|
140
148
|
return supabase
|
|
141
|
-
.from
|
|
149
|
+
.from('app_versions')
|
|
142
150
|
.update(update)
|
|
143
151
|
.eq('app_id', update.app_id)
|
|
144
152
|
.eq('name', update.name)
|
|
153
|
+
.single()
|
|
145
154
|
}
|
|
146
155
|
// console.log('create Version', data, error)
|
|
147
156
|
|
|
148
157
|
return supabase
|
|
149
|
-
.from
|
|
158
|
+
.from('app_versions')
|
|
150
159
|
.insert(update)
|
|
151
|
-
|
|
160
|
+
.select()
|
|
161
|
+
.single()
|
|
152
162
|
}
|
|
153
163
|
|
|
154
|
-
export const updateOrCreateChannel = async (supabase: SupabaseClient,
|
|
164
|
+
export const updateOrCreateChannel = async (supabase: SupabaseClient,
|
|
165
|
+
update: Partial<Database['public']['Tables']['channels']['Row']>, apikey: string) => {
|
|
155
166
|
// console.log('updateOrCreateChannel', update)
|
|
156
167
|
if (!update.app_id || !update.name || !update.created_by) {
|
|
157
168
|
console.error('missing app_id, name, or created_by')
|
|
158
169
|
return Promise.reject(new Error('missing app_id, name, or created_by'))
|
|
159
170
|
}
|
|
160
171
|
const { data, error } = await supabase
|
|
161
|
-
.rpc
|
|
172
|
+
.rpc('exist_channel', { appid: update.app_id, name_channel: update.name, apikey })
|
|
173
|
+
.single()
|
|
174
|
+
|
|
162
175
|
if (data && !error) {
|
|
163
176
|
return supabase
|
|
164
|
-
.from
|
|
165
|
-
.update(update
|
|
177
|
+
.from('channels')
|
|
178
|
+
.update(update)
|
|
166
179
|
.eq('app_id', update.app_id)
|
|
167
180
|
.eq('name', update.name)
|
|
168
181
|
.eq('created_by', update.created_by)
|
|
182
|
+
.single()
|
|
183
|
+
|
|
169
184
|
}
|
|
170
185
|
// console.log('create Channel', data, error)
|
|
171
186
|
|
|
172
187
|
return supabase
|
|
173
|
-
.from
|
|
174
|
-
.insert(update
|
|
188
|
+
.from('channels')
|
|
189
|
+
.insert(update)
|
|
190
|
+
.select()
|
|
191
|
+
.single()
|
|
175
192
|
}
|
|
176
193
|
|
|
177
194
|
export const useLogSnag = (): LogSnag => {
|
|
@@ -182,11 +199,13 @@ export const useLogSnag = (): LogSnag => {
|
|
|
182
199
|
return logsnag
|
|
183
200
|
}
|
|
184
201
|
|
|
202
|
+
export const convertAppName = (appName: string) => appName.replace(/\./g, '--')
|
|
185
203
|
export const verifyUser = async (supabase: SupabaseClient, apikey: string, keymod: string[] = ['all']) => {
|
|
186
204
|
await checkKey(supabase, apikey, keymod);
|
|
187
205
|
|
|
188
206
|
const { data: dataUser, error: userIdError } = await supabase
|
|
189
|
-
.rpc
|
|
207
|
+
.rpc('get_user_id', { apikey })
|
|
208
|
+
.single();
|
|
190
209
|
|
|
191
210
|
const userId = dataUser ? dataUser.toString() : '';
|
|
192
211
|
|
|
@@ -196,7 +215,7 @@ export const verifyUser = async (supabase: SupabaseClient, apikey: string, keymo
|
|
|
196
215
|
return userId;
|
|
197
216
|
}
|
|
198
217
|
|
|
199
|
-
export const getHumanDate = (row:
|
|
218
|
+
export const getHumanDate = (row: Database['public']['Tables']['app_versions']['Row']) => {
|
|
200
219
|
const date = new Date(row.created_at || '');
|
|
201
220
|
return date.toLocaleString();
|
|
202
221
|
}
|