@capgo/cli 4.13.2 → 4.13.4

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 (69) hide show
  1. package/dist/index.js +103 -103
  2. package/package.json +1 -1
  3. package/.github/FUNDING.yml +0 -1
  4. package/.github/workflows/autofix.yml +0 -25
  5. package/.github/workflows/build.yml +0 -46
  6. package/.github/workflows/bump_version.yml +0 -56
  7. package/.github/workflows/check_posix_paths.yml +0 -229
  8. package/.github/workflows/test.yml +0 -30
  9. package/.prettierignore +0 -6
  10. package/.vscode/launch.json +0 -23
  11. package/.vscode/settings.json +0 -46
  12. package/.vscode/tasks.json +0 -42
  13. package/CHANGELOG.md +0 -3392
  14. package/build.mjs +0 -21
  15. package/bun.lockb +0 -0
  16. package/bunfig.toml +0 -2
  17. package/capacitor.config.ts +0 -33
  18. package/crypto_explained.png +0 -0
  19. package/eslint.config.js +0 -10
  20. package/renovate.json +0 -23
  21. package/src/api/app.ts +0 -55
  22. package/src/api/channels.ts +0 -163
  23. package/src/api/crypto.ts +0 -116
  24. package/src/api/devices_override.ts +0 -41
  25. package/src/api/update.ts +0 -13
  26. package/src/api/versions.ts +0 -101
  27. package/src/app/add.ts +0 -157
  28. package/src/app/debug.ts +0 -258
  29. package/src/app/delete.ts +0 -110
  30. package/src/app/info.ts +0 -99
  31. package/src/app/list.ts +0 -67
  32. package/src/app/set.ts +0 -96
  33. package/src/bundle/check.ts +0 -42
  34. package/src/bundle/cleanup.ts +0 -123
  35. package/src/bundle/compatibility.ts +0 -70
  36. package/src/bundle/decrypt.ts +0 -54
  37. package/src/bundle/delete.ts +0 -52
  38. package/src/bundle/encrypt.ts +0 -60
  39. package/src/bundle/list.ts +0 -42
  40. package/src/bundle/unlink.ts +0 -88
  41. package/src/bundle/upload.ts +0 -552
  42. package/src/bundle/zip.ts +0 -145
  43. package/src/channel/add.ts +0 -80
  44. package/src/channel/currentBundle.ts +0 -72
  45. package/src/channel/delete.ts +0 -57
  46. package/src/channel/list.ts +0 -49
  47. package/src/channel/set.ts +0 -179
  48. package/src/config/index.ts +0 -156
  49. package/src/index.ts +0 -310
  50. package/src/init.ts +0 -495
  51. package/src/key.ts +0 -135
  52. package/src/login.ts +0 -70
  53. package/src/types/capacitor__cli.d.ts +0 -6
  54. package/src/types/supabase.types.ts +0 -2123
  55. package/src/user/account.ts +0 -11
  56. package/src/utils.ts +0 -1076
  57. package/test/VerifyZip.java +0 -83
  58. package/test/check-posix-paths.js +0 -21
  59. package/test/chunk_convert.ts +0 -28
  60. package/test/data.ts +0 -18769
  61. package/test/test_headers_rls.ts +0 -24
  62. package/test/test_semver.ts +0 -13
  63. package/test/test_upload/app.js +0 -3
  64. package/test/test_upload/assets/check-posix-paths.js +0 -21
  65. package/test/test_upload/index.html +0 -0
  66. package/test/test_zip_swift/Package.resolved +0 -24
  67. package/test/test_zip_swift/Package.swift +0 -29
  68. package/test/test_zip_swift/Sources/main.swift +0 -80
  69. package/tsconfig.json +0 -39
package/build.mjs DELETED
@@ -1,21 +0,0 @@
1
- import * as esbuild from "esbuild";
2
-
3
- esbuild.build({
4
- entryPoints: ["src/index.ts"],
5
- bundle: true,
6
- platform: "node",
7
- target: "node18",
8
- outfile: "dist/index.js", // Change this to output a single file
9
- sourcemap: process.env.NODE_ENV === "development",
10
- minify: true, // Minify the output
11
- treeShaking: true, // Enable tree shaking to remove unused code
12
- banner: {
13
- js: "#!/usr/bin/env node",
14
- },
15
- define: {
16
- "process.env.SUPA_DB": '"production"',
17
- },
18
- loader: {
19
- ".ts": "ts",
20
- },
21
- }).catch(() => process.exit(1));
package/bun.lockb DELETED
Binary file
package/bunfig.toml DELETED
@@ -1,2 +0,0 @@
1
- [install.scopes]
2
- "@jsr" = "https://npm.jsr.io"
@@ -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 { program } from 'commander'
3
- import { log } from '@clack/prompts'
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
- log.error('Invalid apikey, such apikey does not exists!')
22
- program.error('')
23
- break
24
- }
25
- case 'NO_APP': {
26
- 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
- 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
- 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,163 +0,0 @@
1
- import { exit } 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 { confirm as confirmC, intro, log, outro, spinner } 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
- log.error(`Cannot check Version ${appid}@${versionData.name}`)
17
- program.error('')
18
- }
19
- if (channelFound && channelFound.length > 0) {
20
- intro(`❌ Version ${appid}@${versionData.name} is used in ${channelFound.length} channel`)
21
- if (await confirmC({ message: 'unlink it?' })) {
22
- // loop on all channels and set version to unknown
23
- for (const channel of channelFound) {
24
- const s = 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
- exit(1)
35
- }
36
- s.stop(`✅ Channel ${channel.name} unlinked`)
37
- }
38
- }
39
- else {
40
- log.error(`Unlink it first`)
41
- program.error('')
42
- }
43
- 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, error }) => {
55
- if (error) {
56
- log.error(`Cannot call findUnknownVersion as it returned an error.\n${formatError(error)}`)
57
- program.error('')
58
- }
59
- return data
60
- })
61
- }
62
-
63
- export function createChannel(supabase: SupabaseClient<Database>, update: Database['public']['Tables']['channels']['Insert']) {
64
- return supabase
65
- .from('channels')
66
- .insert(update)
67
- .select()
68
- .single()
69
- }
70
-
71
- export function delChannel(supabase: SupabaseClient<Database>, name: string, appId: string, _userId: string) {
72
- return supabase
73
- .from('channels')
74
- .delete()
75
- .eq('name', name)
76
- .eq('app_id', appId)
77
- .single()
78
- }
79
- interface version {
80
- id: string
81
- name: string
82
- }
83
- interface Channel {
84
- id: number
85
- name: string
86
- public: boolean
87
- ios: boolean
88
- android: boolean
89
- disableAutoUpdate: string
90
- disableAutoUpdateUnderNative: boolean
91
- allow_device_self_set: boolean
92
- enable_progressive_deploy: boolean
93
- secondaryVersionPercentage: number
94
- secondVersion?: version
95
- enableAbTesting: boolean
96
- allow_emulator: boolean
97
- allow_dev: boolean
98
- version?: version
99
- }
100
- export function displayChannels(data: Channel[]) {
101
- const t = new Table({
102
- title: 'Channels',
103
- charLength: { '❌': 2, '✅': 2 },
104
- })
105
-
106
- // add rows with color
107
- data.reverse().forEach((row) => {
108
- t.addRow({
109
- 'Name': row.name,
110
- ...(row.version ? { Version: row.version.name } : undefined),
111
- 'Public': row.public ? '✅' : '❌',
112
- 'iOS': row.ios ? '✅' : '❌',
113
- 'Android': row.android ? '✅' : '❌',
114
- '⬆️ limit': row.disableAutoUpdate,
115
- '⬇️ under native': row.disableAutoUpdateUnderNative ? '❌' : '✅',
116
- 'Self assign': row.allow_device_self_set ? '✅' : '❌',
117
- 'Progressive': row.enable_progressive_deploy ? '✅' : '❌',
118
- ...(row.enable_progressive_deploy && row.secondVersion ? { 'Next version': row.secondVersion.name } : undefined),
119
- ...(row.enable_progressive_deploy && row.secondVersion ? { 'Next %': row.secondaryVersionPercentage } : undefined),
120
- 'AB Testing': row.enableAbTesting ? '✅' : '❌',
121
- ...(row.enableAbTesting && row.secondVersion ? { 'Version B': row.secondVersion } : undefined),
122
- ...(row.enableAbTesting && row.secondVersion ? { 'A/B %': row.secondaryVersionPercentage } : undefined),
123
- 'Emulator': row.allow_emulator ? '✅' : '❌',
124
- 'Dev 📱': row.allow_dev ? '✅' : '❌',
125
- })
126
- })
127
-
128
- log.success(t.render())
129
- }
130
-
131
- export async function getActiveChannels(supabase: SupabaseClient<Database>, appid: string) {
132
- const { data, error: vError } = await supabase
133
- .from('channels')
134
- .select(`
135
- id,
136
- name,
137
- public,
138
- allow_emulator,
139
- allow_dev,
140
- ios,
141
- android,
142
- allow_device_self_set,
143
- disableAutoUpdateUnderNative,
144
- disableAutoUpdate,
145
- enable_progressive_deploy,
146
- enableAbTesting,
147
- secondaryVersionPercentage,
148
- secondVersion (id, name),
149
- created_at,
150
- created_by,
151
- app_id,
152
- version (id, name)
153
- `)
154
- .eq('app_id', appid)
155
- // .eq('created_by', userId)
156
- .order('created_at', { ascending: false })
157
-
158
- if (vError) {
159
- log.error(`App ${appid} not found in database`)
160
- program.error('')
161
- }
162
- return data as any as Channel[]
163
- }
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 { exit } from 'node:process'
2
- import type { SupabaseClient } from '@supabase/supabase-js'
3
- import { program } from 'commander'
4
- import { confirm as confirmC, intro, log, spinner } 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
- log.error(`Cannot check Device override ${appid}@${versionData.name}`)
16
- program.error('')
17
- }
18
- if (deviceFound && deviceFound.length > 0) {
19
- intro(`❌ Version ${appid}@${versionData.name} is used in ${deviceFound.length} device override`)
20
- if (await confirmC({ message: 'unlink it?' })) {
21
- // loop on all devices and set version to unknown
22
- for (const device of deviceFound) {
23
- const s = 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
- exit(1)
32
- }
33
- s.stop(`✅ Device ${device.device_id} unlinked`)
34
- }
35
- }
36
- else {
37
- 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 { log } 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
- 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 { exit } 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 { log } from '@clack/prompts'
6
- import type { Database } from '../types/supabase.types'
7
-
8
- // import { definitions } from '../types/types_supabase';
9
- import { getHumanDate } from '../utils'
10
- import { checkVersionNotUsedInChannel } from './channels'
11
- import { checkVersionNotUsedInDeviceOverride } from './devices_override'
12
-
13
- export async function deleteAppVersion(supabase: SupabaseClient<Database>, appid: string, bundle: string) {
14
- const { error: delAppSpecVersionError } = await supabase
15
- .from('app_versions')
16
- .update({
17
- deleted: true,
18
- })
19
- .eq('app_id', appid)
20
- .eq('deleted', false)
21
- .eq('name', bundle)
22
- if (delAppSpecVersionError) {
23
- log.error(`App Version ${appid}@${bundle} not found in database`)
24
- program.error('')
25
- }
26
- }
27
-
28
- export async function deleteSpecificVersion(supabase: SupabaseClient<Database>, appid: string, bundle: string) {
29
- const versionData = await getVersionData(supabase, appid, bundle)
30
- await checkVersionNotUsedInChannel(supabase, appid, versionData)
31
- await checkVersionNotUsedInDeviceOverride(supabase, appid, versionData)
32
- // Delete only a specific version in storage
33
- await deleteAppVersion(supabase, appid, bundle)
34
- }
35
-
36
- export function displayBundles(data: (Database['public']['Tables']['app_versions']['Row'] & { keep?: string })[]) {
37
- if (!data.length) {
38
- log.error('No bundle found')
39
-
40
- exit(1)
41
- }
42
- const t = new Table({
43
- title: 'Bundles',
44
- charLength: { '❌': 2, '✅': 2 },
45
- })
46
-
47
- // add rows with color
48
- data.reverse().forEach((row) => {
49
- t.addRow({
50
- Version: row.name,
51
- Created: getHumanDate(row.created_at),
52
- ...(row.keep != null ? { Keep: row.keep } : {}),
53
- })
54
- })
55
-
56
- log.success(t.render())
57
- }
58
-
59
- export async function getActiveAppVersions(supabase: SupabaseClient<Database>, appid: string) {
60
- const { data, error: vError } = await supabase
61
- .from('app_versions')
62
- .select()
63
- .eq('app_id', appid)
64
- .eq('deleted', false)
65
- .order('created_at', { ascending: false })
66
-
67
- if (vError) {
68
- 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
- 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
- log.error(`App Version ${appid}@${bundle} doesn't exist`)
98
- program.error('')
99
- }
100
- return versionData
101
- }