@capgo/cli 5.0.0-alpha.7 → 7.0.1

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 (59) hide show
  1. package/README.md +197 -41
  2. package/dist/index.js +335 -95820
  3. package/dist/package.json +83 -0
  4. package/package.json +48 -62
  5. package/.eslintignore +0 -4
  6. package/.github/FUNDING.yml +0 -1
  7. package/.github/workflows/build.yml +0 -46
  8. package/.github/workflows/bump_version.yml +0 -56
  9. package/.github/workflows/test.yml +0 -30
  10. package/.prettierignore +0 -6
  11. package/.vscode/launch.json +0 -23
  12. package/.vscode/settings.json +0 -5
  13. package/.vscode/tasks.json +0 -42
  14. package/CHANGELOG.md +0 -2861
  15. package/build.mjs +0 -23
  16. package/bun.lockb +0 -0
  17. package/capacitor.config.ts +0 -33
  18. package/crypto_explained.png +0 -0
  19. package/eslint.config.js +0 -3
  20. package/renovate.json +0 -23
  21. package/src/api/app.ts +0 -75
  22. package/src/api/channels.ts +0 -140
  23. package/src/api/crypto.ts +0 -121
  24. package/src/api/devices_override.ts +0 -41
  25. package/src/api/update.ts +0 -12
  26. package/src/api/versions.ts +0 -101
  27. package/src/app/add.ts +0 -191
  28. package/src/app/debug.ts +0 -220
  29. package/src/app/delete.ts +0 -106
  30. package/src/app/info.ts +0 -87
  31. package/src/app/list.ts +0 -67
  32. package/src/app/set.ts +0 -94
  33. package/src/bundle/check.ts +0 -42
  34. package/src/bundle/cleanup.ts +0 -127
  35. package/src/bundle/compatibility.ts +0 -70
  36. package/src/bundle/decrypt.ts +0 -65
  37. package/src/bundle/delete.ts +0 -53
  38. package/src/bundle/encrypt.ts +0 -69
  39. package/src/bundle/list.ts +0 -43
  40. package/src/bundle/unlink.ts +0 -86
  41. package/src/bundle/upload.ts +0 -516
  42. package/src/bundle/zip.ts +0 -139
  43. package/src/channel/add.ts +0 -73
  44. package/src/channel/currentBundle.ts +0 -72
  45. package/src/channel/delete.ts +0 -51
  46. package/src/channel/list.ts +0 -49
  47. package/src/channel/set.ts +0 -174
  48. package/src/index.ts +0 -290
  49. package/src/init.ts +0 -301
  50. package/src/key.ts +0 -158
  51. package/src/login.ts +0 -66
  52. package/src/types/capacitor__cli.d.ts +0 -6
  53. package/src/types/supabase.types.ts +0 -2471
  54. package/src/utils.ts +0 -738
  55. package/test/chunk_convert.ts +0 -28
  56. package/test/data.ts +0 -18769
  57. package/test/test_headers_rls.ts +0 -24
  58. package/test/test_semver.ts +0 -13
  59. 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: 'node20',
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,3 +0,0 @@
1
- const antfu = require('@antfu/eslint-config').default
2
-
3
- module.exports = antfu()
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,75 +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, isAllowedApp, 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 checkAppExistsAndHasPermissionErr(supabase: SupabaseClient<Database>, apikey: string, appid: string, shouldExist = true) {
16
- const appExist = await checkAppExists(supabase, appid)
17
- const perm = await isAllowedApp(supabase, apikey, appid)
18
-
19
- if (appExist && !shouldExist) {
20
- p.log.error(`App ${appid} already exist`)
21
- program.error('')
22
- }
23
- if (!appExist && shouldExist) {
24
- p.log.error(`App ${appid} does not exist`)
25
- program.error('')
26
- }
27
- if (appExist && !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('')
33
- }
34
- }
35
-
36
- export async function checkAppExistsAndHasPermissionOrgErr(supabase: SupabaseClient<Database>, apikey: string, appid: string, requiredPermission: OrganizationPerm) {
37
- const permissions = await isAllowedAppOrg(supabase, apikey, appid)
38
- if (!permissions.okay) {
39
- switch (permissions.error) {
40
- case 'INVALID_APIKEY': {
41
- p.log.error('Invalid apikey, such apikey does not exists!')
42
- program.error('')
43
- break
44
- }
45
- case 'NO_APP': {
46
- p.log.error(`App ${appid} does not exist`)
47
- program.error('')
48
- break
49
- }
50
- case 'NO_ORG': {
51
- p.log.error('Could not find organization, please contact support to resolve this!')
52
- program.error('')
53
- break
54
- }
55
- }
56
- }
57
-
58
- const remotePermNumber = permissions.data as number
59
- const requiredPermNumber = requiredPermission as number
60
-
61
- if (requiredPermNumber > remotePermNumber) {
62
- p.log.error(`Insuficcent permissions for app ${appid}. Current permission: ${OrganizationPerm[permissions.data]}, required for this action: ${OrganizationPerm[requiredPermission]}.`)
63
- program.error('')
64
- }
65
-
66
- return permissions.data
67
- }
68
-
69
- export interface Options extends OptionsBase {
70
- name?: string
71
- icon?: string
72
- retention?: number
73
- }
74
-
75
- 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,121 +0,0 @@
1
- import {
2
- constants,
3
- createCipheriv,
4
- createDecipheriv,
5
- generateKeyPairSync,
6
- privateEncrypt,
7
- publicDecrypt,
8
- randomBytes,
9
- } from 'node:crypto'
10
- import { Buffer } from 'node:buffer'
11
-
12
- const algorithm = 'aes-128-cbc'
13
- const formatB64 = 'base64'
14
- const padding = constants.RSA_PKCS1_PADDING
15
-
16
- export function decryptSource(source: Buffer, ivSessionKey: string, key: string): Buffer {
17
- // console.log('decryptKeyType - ', decryptKeyType);
18
- // console.log(key);
19
- // console.log('\nivSessionKey', ivSessionKey)
20
- const [ivB64, sessionb64Encrypted] = ivSessionKey.split(':')
21
- // console.log('\nsessionb64Encrypted', sessionb64Encrypted)
22
- // console.log('\nivB64', ivB64)
23
- const sessionKey = publicDecrypt(
24
- {
25
- key,
26
- padding,
27
- },
28
- Buffer.from(sessionb64Encrypted, formatB64),
29
- )
30
-
31
- // ivB64 to uft-8
32
- const initVector = Buffer.from(ivB64, formatB64)
33
- // console.log('\nSessionB64', sessionB64)
34
-
35
- const decipher = createDecipheriv(algorithm, sessionKey, initVector)
36
- decipher.setAutoPadding(true)
37
- const decryptedData = Buffer.concat([decipher.update(source), decipher.final()])
38
-
39
- return decryptedData
40
- }
41
- export interface Encoded {
42
- ivSessionKey: string
43
- encryptedData: Buffer
44
- }
45
- export function encryptSource(source: Buffer, key: string): Encoded {
46
- // console.log('decryptKeyType - ', decryptKeyType);
47
- // console.log(key);
48
-
49
- // encrypt zip with key
50
- const initVector = randomBytes(16)
51
- const sessionKey = randomBytes(16)
52
- // encrypt session key with public key
53
- // console.log('\nencrypted.key', encrypted.key.toString(CryptoJS.enc.Base64))
54
- const cipher = createCipheriv(algorithm, sessionKey, initVector)
55
- cipher.setAutoPadding(true)
56
- // console.log('\nsessionKey', sessionKey.toString())
57
- // const sessionB64 = sessionKey.toString(formatB64)
58
- // console.log('\nsessionB64', sessionB64)
59
- const ivB64 = initVector.toString(formatB64)
60
- // console.log('\nivB64', ivB64)
61
-
62
- const sessionb64Encrypted = privateEncrypt(
63
- {
64
- key,
65
- padding,
66
- },
67
- sessionKey,
68
- ).toString(formatB64)
69
-
70
- // console.log('\nsessionb64Encrypted', sessionb64Encrypted)
71
- const ivSessionKey = `${ivB64}:${sessionb64Encrypted}`
72
- // console.log('\nivSessionKey', sessionKey)
73
- // encrypted to buffer
74
-
75
- const encryptedData = Buffer.concat([cipher.update(source), cipher.final()])
76
-
77
- return {
78
- encryptedData,
79
- ivSessionKey,
80
- }
81
- }
82
- export interface RSAKeys {
83
- publicKey: string
84
- privateKey: string
85
- }
86
- export function createRSA(): RSAKeys {
87
- const { publicKey, privateKey } = generateKeyPairSync('rsa', {
88
- // The standard secure default length for RSA keys is 2048 bits
89
- modulusLength: 2048,
90
- })
91
-
92
- // Generate RSA key pair
93
- return {
94
- publicKey: publicKey.export({
95
- type: 'pkcs1',
96
- format: 'pem',
97
- }) as string,
98
- privateKey: privateKey.export({
99
- type: 'pkcs1',
100
- format: 'pem',
101
- }) as string,
102
- }
103
- }
104
- // test AES
105
-
106
- // const source = 'Hello world'
107
- // console.log('\nsource', source)
108
- // const { publicKey, privateKey } = createRSA()
109
-
110
- // console.log('\nencryptSource ================================================================')
111
- // // convert source to base64
112
- // const sourceBuff = Buffer.from(source)
113
- // const res = encryptSource(sourceBuff, publicKey)
114
- // console.log('\nencryptedData', res.encryptedData.toString('base64'))
115
- // // console.log('\nres', res)
116
- // console.log('\ndecryptSource ================================================================')
117
- // const decodedSource = decryptSource(res.encryptedData, res.ivSessionKey, privateKey)
118
- // // convert decodedSource from base64 to utf-8
119
- // const decodedSourceString = decodedSource.toString('utf-8')
120
- // console.log('\ndecodedSourceString', decodedSourceString)
121
- // 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,12 +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
- 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
- }
@@ -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
- }