@capgo/cli 2.5.10-alpha.0 → 2.5.11

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.
@@ -0,0 +1,122 @@
1
+ import { SupabaseClient } from '@supabase/supabase-js'
2
+ import { program } from 'commander'
3
+ import { Database } from 'types/supabase.types'
4
+ import { setChannelInternal } from './set';
5
+ import { checkAppExistsAndHasPermission } from "../api/app";
6
+ import {
7
+ getConfig, createSupabaseClient,
8
+ findSavedKey, checkPlanValid,
9
+ verifyUser,
10
+ useLogSnag,
11
+ } from './utils';
12
+
13
+ interface Options {
14
+ apikey: string;
15
+ bundle: string;
16
+ state?: string;
17
+ downgrade?: boolean;
18
+ latest?: boolean;
19
+ upgrade?: boolean;
20
+ ios?: boolean;
21
+ android?: boolean;
22
+ selfAssign?: boolean;
23
+ channel?: string;
24
+ }
25
+
26
+ const findUnknownVersion = (supabase: SupabaseClient<Database>, appId: string) => supabase
27
+ .from('app_versions')
28
+ .select('id')
29
+ .eq('app_id', appId)
30
+ .eq('name', 'unknown')
31
+ .single()
32
+
33
+
34
+ const createChannel = (supabase: SupabaseClient<Database>, update: Database['public']['Tables']['channels']['Insert']) => supabase
35
+ .from('channels')
36
+ .insert(update)
37
+ .select()
38
+ .single()
39
+
40
+ const deleteChannel = (supabase: SupabaseClient<Database>, name: string, appId: string, userId: string) => supabase
41
+ .from('channels')
42
+ .delete()
43
+ .eq('name', name)
44
+ .eq('app_id', appId)
45
+ .eq('user_id', userId)
46
+ .single()
47
+
48
+ export const manageChannel = async (mode: string, channelId: string, appid: string, options: Options) => {
49
+ const apikey = options.apikey || findSavedKey()
50
+ const config = await getConfig();
51
+ appid = appid || config?.app?.appId
52
+ const snag = useLogSnag()
53
+
54
+ if (!apikey) {
55
+ program.error("Missing API key, you need to provide a API key to upload your bundle");
56
+ }
57
+ if (!appid || !channelId) {
58
+ program.error("Missing argument, you need to provide a appid and a channel name, or be in a capacitor project");
59
+ }
60
+ const supabase = createSupabaseClient(apikey)
61
+
62
+ const userId = await verifyUser(supabase, apikey, ['write', 'all']);
63
+ await checkPlanValid(supabase, userId, false)
64
+ // Check we have app access to this appId
65
+ await checkAppExistsAndHasPermission(supabase, appid, apikey);
66
+
67
+ if (mode === 'create') {
68
+ console.log(`Create channel ${appid}#${channelId} to Capgo cloud`);
69
+ try {
70
+ const { data } = await findUnknownVersion(supabase, appid)
71
+ if (!data) {
72
+ program.error(`Cannot find default version for channel creation, please contact Capgo support 🤨`);
73
+ }
74
+ await createChannel(supabase, { name: channelId, app_id: appid, version: data.id, created_by: userId });
75
+ console.log(`Channel created ✅`);
76
+ await snag.publish({
77
+ channel: 'app',
78
+ event: 'Create channel',
79
+ icon: '✅',
80
+ tags: {
81
+ 'user-id': userId,
82
+ 'app-id': appid,
83
+ 'channel': channelId,
84
+ },
85
+ notify: false,
86
+ }).catch()
87
+ } catch (error) {
88
+ console.log(`Cannot create Channel 🙀`, error);
89
+ }
90
+ } else if (mode === 'delete') {
91
+ console.log(`Delete channel ${appid}#${channelId} to Capgo cloud`);
92
+ try {
93
+ await deleteChannel(supabase, channelId, appid, userId);
94
+ console.log(`Channel Delete ✅`);
95
+ await snag.publish({
96
+ channel: 'app',
97
+ event: 'Delete channel',
98
+ icon: '✅',
99
+ tags: {
100
+ 'user-id': userId,
101
+ 'app-id': appid,
102
+ 'channel': channelId,
103
+ },
104
+ notify: false,
105
+ }).catch()
106
+ } catch (error) {
107
+ console.log(`Cannot delete Channel 🙀`, error);
108
+ }
109
+ } else if (mode === 'set') {
110
+ console.log(`Set channel ${appid}#${channelId} to Capgo cloud`);
111
+ try {
112
+ options.channel = channelId
113
+ await setChannelInternal(appid, apikey, config?.app?.package?.version, snag, options);
114
+ console.log(`Channel Set ✅`);
115
+ } catch (error) {
116
+ console.log(`Cannot set Channel 🙀`, error);
117
+ }
118
+ } else {
119
+ program.error('You should provide a valid option (create or delete)');
120
+ }
121
+ process.exit()
122
+ }
@@ -3,13 +3,13 @@ import semver from 'semver/preload';
3
3
  import promptSync from 'prompt-sync';
4
4
  import { SupabaseClient } from '@supabase/supabase-js';
5
5
  import { Database } from 'types/supabase.types';
6
- import { OptionsBase } from '../api/utils';
7
- import { createSupabaseClient, findSavedKey, getConfig, getHumanDate, verifyUser } from '../utils';
6
+ import { createSupabaseClient, findSavedKey, getConfig, getHumanDate, verifyUser } from './utils';
8
7
  import { deleteSpecificVersion, displayBundles, getActiveAppVersions } from '../api/versions';
9
8
  import { checkAppExistsAndHasPermission } from '../api/app';
10
9
  // import { definitions } from '../types/types_supabase';
11
10
 
12
- interface Options extends OptionsBase {
11
+ interface Options {
12
+ apikey: string;
13
13
  version: string;
14
14
  bundle: string;
15
15
  keep: number;
@@ -23,7 +23,7 @@ const removeVersions = async (toRemove: Database['public']['Tables']['app_versio
23
23
 
24
24
  // call deleteSpecificVersion one by one from toRemove sync
25
25
  for await (const row of toRemove) {
26
- console.log(`Removing ${row.name} created on ${(getHumanDate(row.created_at))}`);
26
+ console.log(`Removing ${row.name} created on ${(getHumanDate(row))}`);
27
27
  await deleteSpecificVersion(supabase, appid, userId, row.name);
28
28
  }
29
29
  }
@@ -112,6 +112,5 @@ export const cleanupApp = async (appid: string, options: Options) => {
112
112
  // Yes, lets clean it up
113
113
  console.log("You have confirmed removal, removing versions now");
114
114
  await removeVersions(toRemove, supabase, appid, userId);
115
- console.log(`Done ✅`);
116
115
  process.exit()
117
116
  }
@@ -1,7 +1,7 @@
1
1
  import { program } from 'commander'
2
2
  import { existsSync, readFileSync, writeFileSync } from 'fs'
3
3
  import { decryptSource } from '../api/crypto';
4
- import { baseKey, getConfig } from '../utils';
4
+ import { baseKey, getConfig } from './utils';
5
5
 
6
6
  interface Options {
7
7
  key?: string
@@ -39,6 +39,5 @@ export const decryptZip = async (zipPath: string, ivsessionKey: string, options:
39
39
  const decodedZip = decryptSource(zipFile, ivsessionKey, privateKey)
40
40
  // write decodedZip in a file
41
41
  writeFileSync(`${zipPath}_decrypted.zip`, decodedZip)
42
- console.log(`Done ✅`);
43
42
  process.exit()
44
43
  }
@@ -0,0 +1,99 @@
1
+ import { program } from 'commander';
2
+ import { createSupabaseClient, findSavedKey, formatError, getConfig, useLogSnag, verifyUser } from './utils';
3
+ // import { definitions } from '../types/types_supabase';
4
+ import { deleteSpecificVersion } from '../api/versions';
5
+
6
+ interface Options {
7
+ apikey: string;
8
+ bundle: string;
9
+ }
10
+
11
+ export const deleteApp = async (appid: string, options: Options) => {
12
+ const { bundle } = options;
13
+ const apikey = options.apikey || findSavedKey()
14
+ const config = await getConfig();
15
+ const snag = useLogSnag()
16
+
17
+ appid = appid || config?.app?.appId
18
+ if (!apikey) {
19
+ program.error('Missing API key, you need to provide an API key to delete your app');
20
+ }
21
+ if (!appid) {
22
+ program.error('Missing argument, you need to provide a appid, or be in a capacitor project');
23
+ }
24
+
25
+ const supabase = createSupabaseClient(apikey)
26
+
27
+ const userId = await verifyUser(supabase, apikey);
28
+
29
+ const { data: app, error: dbError0 } = await supabase
30
+ .rpc('exist_app', { appid, apikey })
31
+ .single()
32
+ if (!app || dbError0) {
33
+ program.error('No permission to delete')
34
+ }
35
+
36
+ if (bundle) {
37
+ console.log(`Delete ${appid}@${bundle} from Capgo`);
38
+
39
+ await deleteSpecificVersion(supabase, appid, userId, bundle);
40
+ console.log(`${appid}@${bundle} deleted from server`)
41
+ return
42
+ }
43
+
44
+ console.log(`Delete ${appid} from Capgo`);
45
+ const { data, error: vError } = await supabase
46
+ .from('app_versions')
47
+ .select()
48
+ .eq('app_id', appid)
49
+ .eq('user_id', userId)
50
+
51
+ if (vError) {
52
+ program.error(`App ${appid} not found in database ${formatError(vError)} `)
53
+ }
54
+
55
+ if (data && data.length) {
56
+ const filesToRemove = data
57
+ .filter((x => x.bucket_id && !x.external_url))
58
+ .map(x => `${userId}/${appid}/versions/${x.bucket_id} `)
59
+ const { error: delError } = await supabase
60
+ .storage
61
+ .from('apps')
62
+ .remove(filesToRemove)
63
+ if (delError) {
64
+ program.error(`Cannot delete stored version for app ${appid} from storage ${formatError(delError)} `)
65
+ }
66
+ }
67
+
68
+ const { error: delAppVersionError } = await supabase
69
+ .from('app_versions')
70
+ .delete()
71
+ .eq('app_id', appid)
72
+ .eq('user_id', userId)
73
+
74
+ if (delAppVersionError) {
75
+ program.error(`Cannot delete version for app ${appid} from database ${formatError(delAppVersionError)} `)
76
+ }
77
+
78
+ const { error: dbAppError } = await supabase
79
+ .from('apps')
80
+ .delete()
81
+ .eq('app_id', appid)
82
+ .eq('user_id', userId)
83
+
84
+ if (dbAppError) {
85
+ program.error(`Cannot delete from database ${formatError(dbAppError)} `)
86
+ }
87
+ await snag.publish({
88
+ channel: 'app',
89
+ event: 'App Deleted',
90
+ icon: '😱',
91
+ tags: {
92
+ 'user-id': userId,
93
+ 'app-id': appid,
94
+ },
95
+ notify: false,
96
+ }).catch()
97
+ console.log(`${appid} deleted from server`)
98
+ process.exit()
99
+ }
@@ -1,7 +1,7 @@
1
1
  import { program } from 'commander'
2
2
  import { existsSync, readFileSync, writeFileSync } from 'fs'
3
3
  import { encryptSource } from '../api/crypto';
4
- import { baseKeyPub } from '../utils';
4
+ import { baseKeyPub } from './utils';
5
5
 
6
6
  interface Options {
7
7
  key?: string
@@ -33,6 +33,5 @@ export const encryptZip = async (zipPath: string, options: Options) => {
33
33
  console.log('ivSessionKey', encodedZip.ivSessionKey)
34
34
  // write decodedZip in a file
35
35
  writeFileSync(`${zipPath}_encrypted.zip`, encodedZip.encryptedData)
36
- console.log(`Done ✅`);
37
36
  process.exit()
38
37
  }
@@ -1,76 +1,41 @@
1
1
  import { program } from 'commander';
2
- import { decryptZip } from './bundle/decrypt';
3
- import { encryptZip } from './bundle/encrypt';
4
- import { addApp } from './app/add';
2
+ import { decryptZip } from './decrypt';
3
+ import { encryptZip } from './encrypt';
4
+ import { addApp } from './add';
5
5
  import { manageKey } from './key';
6
- import { deleteVersion } from './bundle/delete';
7
- import { setChannel } from './channel/set';
8
- import { uploadVersion } from './bundle/upload';
9
- import pack from '../package.json'
6
+ import { manageChannel } from './channel';
7
+ import { deleteApp } from './delete';
8
+ import { setChannel } from './set';
9
+ import { uploadVersion } from './upload';
10
+ import pack from '../../package.json'
10
11
  import { login } from './login';
11
- import { listApp } from './app/list';
12
- import { cleanupApp } from './bundle/cleanup';
13
- import { addChannel } from './channel/add';
14
- import { deleteChannel } from './channel/delete';
15
- import { listChannels } from './channel/list';
16
- import { setApp } from './app/set';
17
- import { deleteApp } from './app/delete';
12
+ import { listApp } from './list';
13
+ import { cleanupApp } from './cleanup';
18
14
 
19
15
  program
20
16
  .description('Manage packages and bundle versions in capgo Cloud')
21
17
  .version(pack.version);
22
18
 
23
19
  program
24
- .command('login [apikey]')
25
- .alias('l')
26
- .description('Save apikey to your machine or folder')
27
- .action(login)
28
- .option('--local', 'Only save in local folder');
29
-
30
- const app = program
31
- .command('app')
32
- .description('Manage app');
33
-
34
- app
35
20
  .command('add [appid]')
36
21
  .alias('a')
37
- .description('Add a new app in capgo Cloud')
22
+ .description('Add a new app to capgo Cloud')
38
23
  .action(addApp)
39
24
  .option('-n, --name <name>', 'app name')
40
25
  .option('-i, --icon <icon>', 'app icon path')
41
26
  .option('-a, --apikey <apikey>', 'apikey to link to your account');
42
27
 
43
- app
44
- .command('delete [appid]')
45
- .alias('d')
46
- .description('Delete an app in capgo Cloud')
47
- .action(deleteApp)
48
- .option('-a, --apikey <apikey>', 'apikey to link to your account');
49
-
50
- app
51
- .command('list [appid]')
28
+ program
29
+ .command('login [apikey]')
52
30
  .alias('l')
53
- .description('list apps in capgo Cloud')
54
- .action(listApp)
55
- .option('-a, --apikey <apikey>', 'apikey to link to your account');
56
-
57
- app
58
- .command('set [appid]')
59
- .alias('s')
60
- .description('Set an app in capgo Cloud')
61
- .action(setApp)
62
- .option('-n, --name <name>', 'app name')
63
- .option('-i, --icon <icon>', 'app icon path')
64
- .option('-a, --apikey <apikey>', 'apikey to link to your account');
65
-
66
- const bundle = program
67
- .command('bundle')
68
- .description('Manage bundle');
31
+ .description('Save apikey to your machine or folder')
32
+ .action(login)
33
+ .option('--local', 'Only save in local folder');
69
34
 
70
- bundle
35
+ program
71
36
  .command('upload [appid]')
72
37
  .alias('u')
73
- .description('Upload a new bundle in capgo Cloud')
38
+ .description('Upload a new bundle to capgo Cloud')
74
39
  .action(uploadVersion)
75
40
  .option('-a, --apikey <apikey>', 'apikey to link to your account')
76
41
  .option('-p, --path <path>', 'path of the folder to upload')
@@ -82,72 +47,56 @@ bundle
82
47
  .option('--display-iv-session', 'Show in the console the iv and session key used to encrypt the update')
83
48
  .option('-b, --bundle <bundle>', 'bundle version number of the file to upload');
84
49
 
85
- bundle
50
+ program
51
+ .command('set [appid]')
52
+ .alias('s')
53
+ .description('Modify a channel configuration')
54
+ .action(setChannel)
55
+ .requiredOption('-c, --channel <channel>', 'channel to link to')
56
+ .option('-a, --apikey <apikey>', 'apikey to link to your account')
57
+ .option('-b, --bundle <bundle>', 'bundle version number of the file to set')
58
+ .option('-s, --state <state>', 'set the state of the channel, default or normal')
59
+ .option('--downgrade', 'Allow to downgrade to version under native one')
60
+ .option('--latest', 'get the latest version key in the package.json to set it to the channel')
61
+ .option('--no-downgrade', 'Disable downgrade to version under native one')
62
+ .option('--upgrade', 'Allow to upgrade to version above native one')
63
+ .option('--no-upgrade', 'Disable upgrade to version above native one')
64
+ .option('--ios', 'Allow sending update to ios devices')
65
+ .option('--no-ios', 'Disable sending update to ios devices')
66
+ .option('--android', 'Allow sending update to android devices')
67
+ .option('--no-android', 'Disable sending update to android devices')
68
+ .option('--self-assign', 'Allow to device to self assign to this channel')
69
+ .option('--no-self-assign', 'Disable devices to self assign to this channel');
70
+
71
+ program
86
72
  .command('delete [appid]')
87
73
  .alias('d')
88
- .description('Delete a bundle in capgo Cloud')
89
- .action(deleteVersion)
74
+ .description('Delete an app from capgo Cloud')
75
+ .action(deleteApp)
90
76
  .option('-a, --apikey <apikey>', 'apikey to link to your account')
77
+ .option('-b, --bundle <bundle>', 'bundle version number of the app to delete');
91
78
 
92
- bundle
79
+ program
93
80
  .command('list [appid]')
94
- .alias('l')
95
- .description('List bundle in capgo Cloud')
81
+ .alias('ls')
82
+ .description('List versions in capgo Cloud')
96
83
  .action(listApp)
97
84
  .option('-a, --apikey <apikey>', 'apikey to link to your account');
98
85
 
99
- bundle
86
+ program
100
87
  .command('cleanup [appid]')
101
88
  .alias('c')
89
+ .description('Cleanup versions in capgo Cloud')
102
90
  .action(cleanupApp)
103
- .description('Cleanup bundle in capgo Cloud')
104
91
  .option('-b, --bundle <bundle>', 'bundle version number of the app to delete')
105
92
  .option('-a, --apikey <apikey>', 'apikey to link to your account')
106
93
  .option('-k, --keep <keep>', 'number of version to keep')
107
94
  .option('-f, --force', 'force removal');
108
95
 
109
- bundle
110
- .command('decrypt [zipPath] [sessionKey]')
111
- .alias('l')
112
- .description('Decrypt a signed zip bundle')
113
- .action(decryptZip)
114
- .option('--key <key>', 'custom path for private signing key')
115
- .option('--keyData <keyData>', 'base64 private signing key');
116
-
117
- bundle
118
- .command('encrypt [zipPath]')
119
- .description('Encrypt a zip bundle')
120
- .action(encryptZip)
121
- .option('--key <key>', 'custom path for private signing key')
122
- .option('--keyData <keyData>', 'base64 private signing key');
123
-
124
- const channel = program
125
- .command('channel')
126
- .description('Manage channel');
127
-
128
- channel
129
- .command('add [channelid] [appid]')
130
- .alias('a')
131
- .description('Create channel')
132
- .action(addChannel)
133
-
134
- channel
135
- .command('delete [channelid] [appid]')
136
- .alias('d')
137
- .description('Delete channel')
138
- .action(deleteChannel)
139
-
140
- channel
141
- .command('list [appid]')
142
- .alias('l')
143
- .description('List channel')
144
- .action(listChannels)
145
-
146
- channel
147
- .command('set [channelid] [appid]')
148
- .alias('s')
149
- .description('Set channel')
150
- .action(setChannel)
96
+ program
97
+ .command('channel [mode] [channelid] [appid]')
98
+ .description('Create, set or delete channel')
99
+ .action(manageChannel)
151
100
  .option('-a, --apikey <apikey>', 'apikey to link to your account')
152
101
  .option('-b, --bundle <bundle>', 'bundle version number of the file to set')
153
102
  .option('-s, --state <state>', 'set the state of the channel, default or normal')
@@ -169,4 +118,19 @@ program
169
118
  .action(manageKey)
170
119
  .option('-f, --force', 'force generate a new one');
171
120
 
121
+
122
+ program
123
+ .command('decrypt [zipPath] [sessionKey]')
124
+ .description('Decrypt a signed zip update')
125
+ .action(decryptZip)
126
+ .option('--key <key>', 'custom path for private signing key')
127
+ .option('--keyData <keyData>', 'base64 private signing key');
128
+
129
+ program
130
+ .command('encrypt [zipPath]')
131
+ .description('Encrypt a zip update')
132
+ .action(encryptZip)
133
+ .option('--key <key>', 'custom path for private signing key')
134
+ .option('--keyData <keyData>', 'base64 private signing key');
135
+
172
136
  program.parseAsync();
@@ -1,7 +1,7 @@
1
1
  import { program } from 'commander'
2
2
  import { existsSync, readFileSync, writeFileSync } from 'fs'
3
3
  import { writeConfig } from '@capacitor/cli/dist/config';
4
- import { createRSA } from './api/crypto';
4
+ import { createRSA } from '../api/crypto';
5
5
  import { baseKey, baseKeyPub, getConfig } from './utils';
6
6
 
7
7
  interface Options {
@@ -1,19 +1,22 @@
1
1
  import { program } from 'commander';
2
+ import { createSupabaseClient, findSavedKey, getConfig, verifyUser } from './utils';
2
3
  import { checkAppExistsAndHasPermission } from '../api/app';
3
- import { OptionsBase } from '../api/utils';
4
- import { getActiveAppVersions, displayBundles } from '../api/versions';
5
- import { createSupabaseClient, findSavedKey, getConfig, verifyUser } from '../utils';
4
+ import { displayBundles, getActiveAppVersions } from '../api/versions';
6
5
 
7
- export const listApp = async (appId: string, options: OptionsBase) => {
6
+ interface Options {
7
+ apikey: string;
8
+ version: string;
9
+ }
10
+
11
+ export const listApp = async (appid: string, options: Options) => {
8
12
  const apikey = options.apikey || findSavedKey()
9
13
  const config = await getConfig();
10
14
 
11
- console.log('COMMAND DEPRECATED, use "app list" instead')
12
- appId = appId || config?.app?.appId
15
+ appid = appid || config?.app?.appId
13
16
  if (!apikey) {
14
17
  program.error('Missing API key, you need to provide an API key to delete your app');
15
18
  }
16
- if (!appId) {
19
+ if (!appid) {
17
20
  program.error('Missing argument, you need to provide a appid, or be in a capacitor project');
18
21
  }
19
22
  console.log(`Querying available versions in Capgo`);
@@ -22,17 +25,14 @@ export const listApp = async (appId: string, options: OptionsBase) => {
22
25
 
23
26
  const userId = await verifyUser(supabase, apikey);
24
27
 
25
- console.log(`Querying available versions in Capgo`);
26
-
27
28
  // Check we have app access to this appId
28
- await checkAppExistsAndHasPermission(supabase, appId, options.apikey);
29
+ await checkAppExistsAndHasPermission(supabase, appid, apikey);
29
30
 
30
31
  // Get all active app versions we might possibly be able to cleanup
31
- const allVersions = await getActiveAppVersions(supabase, appId, userId);
32
+ const allVersions = await getActiveAppVersions(supabase, appid, userId);
32
33
 
33
34
  console.log(`Active versions in Capgo: ${allVersions?.length}`);
34
35
 
35
36
  displayBundles(allVersions);
36
- console.log(`Done ✅`);
37
37
  process.exit()
38
38
  }
File without changes