@capgo/cli 4.13.9 → 4.13.10-beta.0

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 (57) hide show
  1. package/dist/index.js +381 -114689
  2. package/package.json +33 -33
  3. package/.github/FUNDING.yml +0 -1
  4. package/.github/workflows/build.yml +0 -46
  5. package/.github/workflows/bump_version.yml +0 -56
  6. package/.github/workflows/test.yml +0 -30
  7. package/.prettierignore +0 -6
  8. package/.vscode/launch.json +0 -23
  9. package/.vscode/settings.json +0 -46
  10. package/.vscode/tasks.json +0 -42
  11. package/CHANGELOG.md +0 -2739
  12. package/build.mjs +0 -23
  13. package/bun.lockb +0 -0
  14. package/capacitor.config.ts +0 -33
  15. package/crypto_explained.png +0 -0
  16. package/eslint.config.js +0 -10
  17. package/renovate.json +0 -23
  18. package/src/api/app.ts +0 -55
  19. package/src/api/channels.ts +0 -140
  20. package/src/api/crypto.ts +0 -116
  21. package/src/api/devices_override.ts +0 -41
  22. package/src/api/update.ts +0 -13
  23. package/src/api/versions.ts +0 -101
  24. package/src/app/add.ts +0 -158
  25. package/src/app/debug.ts +0 -222
  26. package/src/app/delete.ts +0 -106
  27. package/src/app/info.ts +0 -90
  28. package/src/app/list.ts +0 -67
  29. package/src/app/set.ts +0 -94
  30. package/src/bundle/check.ts +0 -42
  31. package/src/bundle/cleanup.ts +0 -127
  32. package/src/bundle/compatibility.ts +0 -70
  33. package/src/bundle/decrypt.ts +0 -54
  34. package/src/bundle/delete.ts +0 -53
  35. package/src/bundle/encrypt.ts +0 -60
  36. package/src/bundle/list.ts +0 -43
  37. package/src/bundle/unlink.ts +0 -86
  38. package/src/bundle/upload.ts +0 -532
  39. package/src/bundle/zip.ts +0 -139
  40. package/src/channel/add.ts +0 -74
  41. package/src/channel/currentBundle.ts +0 -72
  42. package/src/channel/delete.ts +0 -52
  43. package/src/channel/list.ts +0 -49
  44. package/src/channel/set.ts +0 -178
  45. package/src/index.ts +0 -307
  46. package/src/init.ts +0 -342
  47. package/src/key.ts +0 -131
  48. package/src/login.ts +0 -70
  49. package/src/types/capacitor__cli.d.ts +0 -6
  50. package/src/types/supabase.types.ts +0 -2193
  51. package/src/user/account.ts +0 -11
  52. package/src/utils.ts +0 -956
  53. package/test/chunk_convert.ts +0 -28
  54. package/test/data.ts +0 -18769
  55. package/test/test_headers_rls.ts +0 -24
  56. package/test/test_semver.ts +0 -13
  57. package/tsconfig.json +0 -39
package/build.mjs DELETED
@@ -1,23 +0,0 @@
1
- import * as esbuild from "esbuild";
2
-
3
- // Replace 'your-external-dependencies-here' with actual externals from your project
4
- const external = [];
5
-
6
- esbuild.build({
7
- entryPoints: ["src/index.ts"],
8
- bundle: true,
9
- platform: "node",
10
- target: "node18",
11
- external,
12
- outdir: "dist",
13
- sourcemap: process.env.NODE_ENV === "development",
14
- banner: {
15
- js: "#!/usr/bin/env node",
16
- },
17
- define: {
18
- "process.env.SUPA_DB": '"production"',
19
- },
20
- loader: {
21
- ".ts": "ts",
22
- },
23
- }).catch(() => process.exit(1));
package/bun.lockb DELETED
Binary file
@@ -1,33 +0,0 @@
1
- /*
2
- * Copyright 2020 EPAM Systems
3
- *
4
- * Licensed under the Apache License, Version 2.0 (the "License");
5
- * you may not use this file except in compliance with the License.
6
- * You may obtain a copy of the License at
7
- *
8
- * http://www.apache.org/licenses/LICENSE-2.0
9
- *
10
- * Unless required by applicable law or agreed to in writing, software
11
- * distributed under the License is distributed on an "AS IS" BASIS,
12
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
- * See the License for the specific language governing permissions and
14
- * limitations under the License.
15
- */
16
- import type { CapacitorConfig } from '@capacitor/cli'
17
-
18
- const config: CapacitorConfig = {
19
- appId: 'ee.forgr.capacitor_go',
20
- appName: 'Capgo',
21
- webDir: 'dist',
22
- bundledWebRuntime: false,
23
- plugins: {
24
- PushNotifications: {
25
- presentationOptions: ['badge', 'sound', 'alert'],
26
- },
27
- SplashScreen: {
28
- launchAutoHide: false,
29
- },
30
- },
31
- }
32
-
33
- export default config
Binary file
package/eslint.config.js DELETED
@@ -1,10 +0,0 @@
1
- const antfu = require('@antfu/eslint-config').default
2
-
3
- module.exports = antfu({
4
- ignores: [
5
- 'dist',
6
- 'test',
7
- 'webpack.config.js',
8
- 'src/types/types_supabase.ts',
9
- ],
10
- })
package/renovate.json DELETED
@@ -1,23 +0,0 @@
1
- {
2
- "$schema": "https://docs.renovatebot.com/renovate-schema.json",
3
- "extends": [
4
- "config:base",
5
- "schedule:earlyMondays"
6
- ],
7
- "lockFileMaintenance": {
8
- "enabled": true,
9
- "automerge": true,
10
- "automergeType": "branch",
11
- "platformAutomerge": true
12
- },
13
- "packageRules": [
14
- {
15
- "matchUpdateTypes": [
16
- "minor",
17
- "patch"
18
- ],
19
- "matchCurrentVersion": "!/^0/",
20
- "automerge": true
21
- }
22
- ]
23
- }
package/src/api/app.ts DELETED
@@ -1,55 +0,0 @@
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, getPMAndCommand, isAllowedAppOrg } from '../utils'
7
-
8
- export async function checkAppExists(supabase: SupabaseClient<Database>, appid: string) {
9
- const { data: app } = await supabase
10
- .rpc('exist_app_v2', { appid })
11
- .single()
12
- return !!app
13
- }
14
-
15
- export async function checkAppExistsAndHasPermissionOrgErr(supabase: SupabaseClient<Database>, apikey: string, appid: string, requiredPermission: OrganizationPerm) {
16
- const pm = getPMAndCommand()
17
- const permissions = await isAllowedAppOrg(supabase, apikey, appid)
18
- if (!permissions.okay) {
19
- switch (permissions.error) {
20
- case 'INVALID_APIKEY': {
21
- p.log.error('Invalid apikey, such apikey does not exists!')
22
- program.error('')
23
- break
24
- }
25
- case 'NO_APP': {
26
- p.log.error(`App ${appid} does not exist, run first \`${pm.runner} @capgo/cli app add ${appid}\` to create it`)
27
- program.error('')
28
- break
29
- }
30
- case 'NO_ORG': {
31
- p.log.error('Could not find organization, please contact support to resolve this!')
32
- program.error('')
33
- break
34
- }
35
- }
36
- }
37
-
38
- const remotePermNumber = permissions.data as number
39
- const requiredPermNumber = requiredPermission as number
40
-
41
- if (requiredPermNumber > remotePermNumber) {
42
- p.log.error(`Insuficcent permissions for app ${appid}. Current permission: ${OrganizationPerm[permissions.data]}, required for this action: ${OrganizationPerm[requiredPermission]}.`)
43
- program.error('')
44
- }
45
-
46
- return permissions.data
47
- }
48
-
49
- export interface Options extends OptionsBase {
50
- name?: string
51
- icon?: string
52
- retention?: number
53
- }
54
-
55
- export const newIconPath = 'assets/icon.png'
@@ -1,140 +0,0 @@
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 } from '../utils'
8
-
9
- export async function checkVersionNotUsedInChannel(supabase: SupabaseClient<Database>, appid: string, versionData: Database['public']['Tables']['app_versions']['Row']) {
10
- const { data: channelFound, error: errorChannel } = await supabase
11
- .from('channels')
12
- .select()
13
- .eq('app_id', appid)
14
- .eq('version', versionData.id)
15
- if (errorChannel) {
16
- p.log.error(`Cannot check Version ${appid}@${versionData.name}`)
17
- program.error('')
18
- }
19
- if (channelFound && channelFound.length > 0) {
20
- p.intro(`❌ Version ${appid}@${versionData.name} is used in ${channelFound.length} channel`)
21
- if (await p.confirm({ message: 'unlink it?' })) {
22
- // loop on all channels and set version to unknown
23
- for (const channel of channelFound) {
24
- const s = p.spinner()
25
- s.start(`Unlinking channel ${channel.name}`)
26
- const { error: errorChannelUpdate } = await supabase
27
- .from('channels')
28
- .update({
29
- version: (await findUnknownVersion(supabase, appid))?.id,
30
- })
31
- .eq('id', channel.id)
32
- if (errorChannelUpdate) {
33
- s.stop(`Cannot update channel ${channel.name} ${formatError(errorChannelUpdate)}`)
34
- process.exit(1)
35
- }
36
- s.stop(`✅ Channel ${channel.name} unlinked`)
37
- }
38
- }
39
- else {
40
- p.log.error(`Unlink it first`)
41
- program.error('')
42
- }
43
- p.outro(`Version unlinked from ${channelFound.length} channel`)
44
- }
45
- }
46
-
47
- export function findUnknownVersion(supabase: SupabaseClient<Database>, appId: string) {
48
- return supabase
49
- .from('app_versions')
50
- .select('id')
51
- .eq('app_id', appId)
52
- .eq('name', 'unknown')
53
- .throwOnError()
54
- .single().then(({ data }) => data)
55
- }
56
-
57
- export function createChannel(supabase: SupabaseClient<Database>, update: Database['public']['Tables']['channels']['Insert']) {
58
- return supabase
59
- .from('channels')
60
- .insert(update)
61
- .select()
62
- .single()
63
- }
64
-
65
- export function delChannel(supabase: SupabaseClient<Database>, name: string, appId: string, _userId: string) {
66
- return supabase
67
- .from('channels')
68
- .delete()
69
- .eq('name', name)
70
- .eq('app_id', appId)
71
- .single()
72
- }
73
- interface version {
74
- id: string
75
- name: string
76
- }
77
- export function displayChannels(data: (Database['public']['Tables']['channels']['Row'] & { version?: version, secondVersion?: version })[]) {
78
- const t = new Table({
79
- title: 'Channels',
80
- charLength: { '❌': 2, '✅': 2 },
81
- })
82
-
83
- // add rows with color
84
- data.reverse().forEach((row) => {
85
- t.addRow({
86
- 'Name': row.name,
87
- ...(row.version ? { Version: row.version.name } : undefined),
88
- 'Public': row.public ? '✅' : '❌',
89
- 'iOS': row.ios ? '❌' : '✅',
90
- 'Android': row.android ? '❌' : '✅',
91
- '⬆️ limit': row.disableAutoUpdate,
92
- '⬇️ under native': row.disableAutoUpdateUnderNative ? '❌' : '✅',
93
- 'Self assign': row.allow_device_self_set ? '✅' : '❌',
94
- 'Progressive': row.enable_progressive_deploy ? '✅' : '❌',
95
- ...(row.enable_progressive_deploy && row.secondVersion ? { 'Next version': row.secondVersion.name } : undefined),
96
- ...(row.enable_progressive_deploy && row.secondVersion ? { 'Next %': row.secondaryVersionPercentage } : undefined),
97
- 'AB Testing': row.enableAbTesting ? '✅' : '❌',
98
- ...(row.enableAbTesting && row.secondVersion ? { 'Version B': row.secondVersion } : undefined),
99
- ...(row.enableAbTesting && row.secondVersion ? { 'A/B %': row.secondaryVersionPercentage } : undefined),
100
- 'Emulator': row.allow_emulator ? '✅' : '❌',
101
- 'Dev 📱': row.allow_dev ? '✅' : '❌',
102
- })
103
- })
104
-
105
- p.log.success(t.render())
106
- }
107
-
108
- export async function getActiveChannels(supabase: SupabaseClient<Database>, appid: string) {
109
- const { data, error: vError } = await supabase
110
- .from('channels')
111
- .select(`
112
- id,
113
- name,
114
- public,
115
- allow_emulator,
116
- allow_dev,
117
- ios,
118
- android,
119
- allow_device_self_set,
120
- disableAutoUpdateUnderNative,
121
- disableAutoUpdate,
122
- enable_progressive_deploy,
123
- enableAbTesting,
124
- secondaryVersionPercentage,
125
- secondVersion (id, name),
126
- created_at,
127
- created_by,
128
- app_id,
129
- version (id, name)
130
- `)
131
- .eq('app_id', appid)
132
- // .eq('created_by', userId)
133
- .order('created_at', { ascending: false })
134
-
135
- if (vError) {
136
- p.log.error(`App ${appid} not found in database`)
137
- program.error('')
138
- }
139
- return data
140
- }
package/src/api/crypto.ts DELETED
@@ -1,116 +0,0 @@
1
- import {
2
- constants,
3
- createCipheriv,
4
- createDecipheriv,
5
- generateKeyPairSync,
6
- privateDecrypt,
7
- publicEncrypt,
8
- randomBytes,
9
- } from 'node:crypto'
10
- import { Buffer } from 'node:buffer'
11
-
12
- const algorithm = 'aes-128-cbc'
13
- const oaepHash = 'sha256'
14
- const formatB64 = 'base64'
15
- const padding = constants.RSA_PKCS1_OAEP_PADDING
16
-
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)
33
-
34
- const decipher = createDecipheriv(algorithm, sessionKey, initVector)
35
- decipher.setAutoPadding(true)
36
- const decryptedData = Buffer.concat([decipher.update(source), decipher.final()])
37
-
38
- return decryptedData
39
- }
40
- export interface Encoded {
41
- ivSessionKey: string
42
- encryptedData: Buffer
43
- }
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
69
-
70
- const encryptedData = Buffer.concat([cipher.update(source), cipher.final()])
71
-
72
- return {
73
- encryptedData,
74
- ivSessionKey,
75
- }
76
- }
77
- export interface RSAKeys {
78
- publicKey: string
79
- privateKey: string
80
- }
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
- })
86
-
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
- }
98
- }
99
- // test AES
100
-
101
- // const source = 'Hello world'
102
- // console.log('\nsource', source)
103
- // const { publicKey, privateKey } = createRSA()
104
-
105
- // console.log('\nencryptSource ================================================================')
106
- // // convert source to base64
107
- // const sourceBuff = Buffer.from(source)
108
- // const res = encryptSource(sourceBuff, publicKey)
109
- // console.log('\nencryptedData', res.encryptedData.toString('base64'))
110
- // // console.log('\nres', res)
111
- // console.log('\ndecryptSource ================================================================')
112
- // const decodedSource = decryptSource(res.encryptedData, res.ivSessionKey, privateKey)
113
- // // convert decodedSource from base64 to utf-8
114
- // const decodedSourceString = decodedSource.toString('utf-8')
115
- // console.log('\ndecodedSourceString', decodedSourceString)
116
- // console.log('\n Is match', decodedSourceString === source)
@@ -1,41 +0,0 @@
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'
7
-
8
- export async function checkVersionNotUsedInDeviceOverride(supabase: SupabaseClient<Database>, appid: string, versionData: Database['public']['Tables']['app_versions']['Row']) {
9
- const { data: deviceFound, error: errorDevice } = await supabase
10
- .from('devices_override')
11
- .select()
12
- .eq('app_id', appid)
13
- .eq('version', versionData.id)
14
- if (errorDevice) {
15
- p.log.error(`Cannot check Device override ${appid}@${versionData.name}`)
16
- program.error('')
17
- }
18
- if (deviceFound && deviceFound.length > 0) {
19
- p.intro(`❌ Version ${appid}@${versionData.name} is used in ${deviceFound.length} device override`)
20
- if (await p.confirm({ message: 'unlink it?' })) {
21
- // loop on all devices and set version to unknown
22
- for (const device of deviceFound) {
23
- const s = p.spinner()
24
- s.start(`Unlinking device ${device.device_id}`)
25
- const { error: errorDeviceDel } = await supabase
26
- .from('devices_override')
27
- .delete()
28
- .eq('device_id', device.device_id)
29
- if (errorDeviceDel) {
30
- s.stop(`Cannot unlink device ${device.device_id} ${formatError(errorDeviceDel)}`)
31
- process.exit(1)
32
- }
33
- s.stop(`✅ Device ${device.device_id} unlinked`)
34
- }
35
- }
36
- else {
37
- p.log.error(`Unlink it first`)
38
- program.error('')
39
- }
40
- }
41
- }
package/src/api/update.ts DELETED
@@ -1,13 +0,0 @@
1
- import getLatest from 'get-latest-version'
2
- import * as p from '@clack/prompts'
3
- import pack from '../../package.json'
4
-
5
- export async function checkLatest() {
6
- const latest = await getLatest('@capgo/cli')
7
- const major = latest?.split('.')[0]
8
- if (latest !== pack.version) {
9
- p.log.warning(`🚨 You are using @capgo/cli@${pack.version} it's not the latest version.
10
- Please use @capgo/cli@${latest}" or @capgo/cli@${major} to keep up to date with the latest features and bug fixes.`,
11
- )
12
- }
13
- }
@@ -1,101 +0,0 @@
1
- import type { SupabaseClient } from '@supabase/supabase-js'
2
- import { program } from 'commander'
3
- import { Table } from 'console-table-printer'
4
- import * as p from '@clack/prompts'
5
- import type { Database } from '../types/supabase.types'
6
-
7
- // import { definitions } from '../types/types_supabase';
8
- import { getHumanDate } from '../utils'
9
- import { checkVersionNotUsedInChannel } from './channels'
10
- import { checkVersionNotUsedInDeviceOverride } from './devices_override'
11
-
12
- export async function deleteAppVersion(supabase: SupabaseClient<Database>, appid: string, bundle: string) {
13
- const { error: delAppSpecVersionError } = await supabase
14
- .from('app_versions')
15
- .update({
16
- deleted: true,
17
- })
18
- .eq('app_id', appid)
19
- .eq('deleted', false)
20
- .eq('name', bundle)
21
- if (delAppSpecVersionError) {
22
- p.log.error(`App Version ${appid}@${bundle} not found in database`)
23
- program.error('')
24
- }
25
- }
26
-
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)
30
- await checkVersionNotUsedInDeviceOverride(supabase, appid, versionData)
31
- // Delete only a specific version in storage
32
- await deleteAppVersion(supabase, appid, bundle)
33
- }
34
-
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
- }
41
- const t = new Table({
42
- title: 'Bundles',
43
- charLength: { '❌': 2, '✅': 2 },
44
- })
45
-
46
- // add rows with color
47
- data.reverse().forEach((row) => {
48
- t.addRow({
49
- Version: row.name,
50
- Created: getHumanDate(row.created_at),
51
- ...(row.keep != null ? { Keep: row.keep } : {}),
52
- })
53
- })
54
-
55
- p.log.success(t.render())
56
- }
57
-
58
- export async function getActiveAppVersions(supabase: SupabaseClient<Database>, appid: string, _userId: string) {
59
- const { data, error: vError } = await supabase
60
- .from('app_versions')
61
- .select()
62
- .eq('app_id', appid)
63
- // .eq('user_id', userId)
64
- .eq('deleted', false)
65
- .order('created_at', { ascending: false })
66
-
67
- if (vError) {
68
- p.log.error(`App ${appid} not found in database`)
69
- program.error('')
70
- }
71
- return data
72
- }
73
-
74
- export async function getChannelsVersion(supabase: SupabaseClient<Database>, appid: string) {
75
- // get all channels versionID
76
- const { data: channels, error: channelsError } = await supabase
77
- .from('channels')
78
- .select('version')
79
- .eq('app_id', appid)
80
-
81
- if (channelsError) {
82
- p.log.error(`App ${appid} not found in database`)
83
- program.error('')
84
- }
85
- return channels.map(c => c.version)
86
- }
87
-
88
- export async function getVersionData(supabase: SupabaseClient<Database>, appid: string, bundle: string) {
89
- const { data: versionData, error: versionIdError } = await supabase
90
- .from('app_versions')
91
- .select()
92
- .eq('app_id', appid)
93
- .eq('name', bundle)
94
- .eq('deleted', false)
95
- .single()
96
- if (!versionData || versionIdError) {
97
- p.log.error(`App Version ${appid}@${bundle} doesn't exist`)
98
- program.error('')
99
- }
100
- return versionData
101
- }