@capgo/cli 5.0.0-alpha.3 → 5.0.0-alpha.7
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 +139 -5
- package/README.md +4 -0
- package/bun.lockb +0 -0
- package/dist/index.js +31453 -807
- package/package.json +2 -1
- package/src/api/channels.ts +2 -4
- package/src/api/versions.ts +14 -11
- package/src/app/add.ts +43 -6
- package/src/app/debug.ts +9 -3
- package/src/app/delete.ts +44 -6
- package/src/app/list.ts +4 -0
- package/src/app/set.ts +4 -4
- package/src/bundle/cleanup.ts +5 -6
- package/src/bundle/compatibility.ts +3 -3
- package/src/bundle/delete.ts +3 -3
- package/src/bundle/list.ts +3 -3
- package/src/bundle/unlink.ts +13 -7
- package/src/bundle/upload.ts +105 -23
- package/src/bundle/zip.ts +11 -9
- package/src/channel/add.ts +4 -4
- package/src/channel/currentBundle.ts +4 -5
- package/src/channel/delete.ts +3 -3
- package/src/channel/list.ts +3 -3
- package/src/channel/set.ts +7 -4
- package/src/index.ts +12 -7
- package/src/types/supabase.types.ts +589 -183
- package/src/utils.ts +36 -17
package/src/bundle/upload.ts
CHANGED
|
@@ -8,6 +8,10 @@ import * as p from '@clack/prompts'
|
|
|
8
8
|
import { checksum as getChecksum } from '@tomasklaen/checksum'
|
|
9
9
|
import ciDetect from 'ci-info'
|
|
10
10
|
import ky from 'ky'
|
|
11
|
+
import {
|
|
12
|
+
PutObjectCommand,
|
|
13
|
+
S3Client,
|
|
14
|
+
} from '@aws-sdk/client-s3'
|
|
11
15
|
import { checkLatest } from '../api/update'
|
|
12
16
|
import { checkAppExistsAndHasPermissionOrgErr } from '../api/app'
|
|
13
17
|
import { encryptSource } from '../api/crypto'
|
|
@@ -15,6 +19,7 @@ import type {
|
|
|
15
19
|
OptionsBase,
|
|
16
20
|
} from '../utils'
|
|
17
21
|
import {
|
|
22
|
+
EMPTY_UUID,
|
|
18
23
|
OrganizationPerm,
|
|
19
24
|
baseKey,
|
|
20
25
|
checKOldEncryption,
|
|
@@ -28,6 +33,7 @@ import {
|
|
|
28
33
|
getConfig,
|
|
29
34
|
getLocalConfig,
|
|
30
35
|
getLocalDepenencies,
|
|
36
|
+
getOrganizationId,
|
|
31
37
|
hasOrganizationPerm,
|
|
32
38
|
regexSemver,
|
|
33
39
|
requireUpdateMetadata,
|
|
@@ -50,6 +56,10 @@ interface Options extends OptionsBase {
|
|
|
50
56
|
key?: boolean | string
|
|
51
57
|
keyData?: string
|
|
52
58
|
ivSessionKey?: string
|
|
59
|
+
s3Region?: string
|
|
60
|
+
s3Apikey?: string
|
|
61
|
+
s3Apisecret?: string
|
|
62
|
+
s3BucketName?: string
|
|
53
63
|
bundleUrl?: boolean
|
|
54
64
|
codeCheck?: boolean
|
|
55
65
|
minUpdateVersion?: string
|
|
@@ -63,6 +73,21 @@ export async function uploadBundle(appid: string, options: Options, shouldExit =
|
|
|
63
73
|
let { bundle, path, channel } = options
|
|
64
74
|
const { external, key, displayIvSession, autoMinUpdateVersion, ignoreMetadataCheck } = options
|
|
65
75
|
let { minUpdateVersion } = options
|
|
76
|
+
const { s3Region, s3Apikey, s3Apisecret, s3BucketName } = options
|
|
77
|
+
let useS3 = false
|
|
78
|
+
let s3Client
|
|
79
|
+
if (s3Region && s3Apikey && s3Apisecret && s3BucketName) {
|
|
80
|
+
p.log.info('Uploading to S3')
|
|
81
|
+
useS3 = true
|
|
82
|
+
s3Client = new S3Client({
|
|
83
|
+
region: s3Region,
|
|
84
|
+
credentials: {
|
|
85
|
+
accessKeyId: s3Apikey,
|
|
86
|
+
secretAccessKey: s3Apisecret,
|
|
87
|
+
},
|
|
88
|
+
})
|
|
89
|
+
}
|
|
90
|
+
|
|
66
91
|
options.apikey = options.apikey || findSavedKey()
|
|
67
92
|
const snag = useLogSnag()
|
|
68
93
|
|
|
@@ -91,6 +116,13 @@ export async function uploadBundle(appid: string, options: Options, shouldExit =
|
|
|
91
116
|
p.log.error('Missing argument, you need to provide a appid and a bundle and a path, or be in a capacitor project')
|
|
92
117
|
program.error('')
|
|
93
118
|
}
|
|
119
|
+
// if one S3 variable is set, check that all are set
|
|
120
|
+
if (s3BucketName || s3Region || s3Apikey || s3Apisecret) {
|
|
121
|
+
if (!s3BucketName || !s3Region || !s3Apikey || !s3Apisecret) {
|
|
122
|
+
p.log.error('Missing argument, for S3 upload you need to provide a bucket name, region, API key, and API secret')
|
|
123
|
+
program.error('')
|
|
124
|
+
}
|
|
125
|
+
}
|
|
94
126
|
// check if path exist
|
|
95
127
|
if (!existsSync(path)) {
|
|
96
128
|
p.log.error(`Path ${path} does not exist, build your app first, or provide a valid path`)
|
|
@@ -119,9 +151,12 @@ export async function uploadBundle(appid: string, options: Options, shouldExit =
|
|
|
119
151
|
// await checkAppExistsAndHasPermissionErr(supabase, options.apikey, appid);
|
|
120
152
|
|
|
121
153
|
const permissions = await checkAppExistsAndHasPermissionOrgErr(supabase, options.apikey, appid, OrganizationPerm.upload)
|
|
122
|
-
await checkPlanValid(supabase, userId, options.apikey, appid, true)
|
|
123
154
|
|
|
124
|
-
|
|
155
|
+
// Now if it does exist we will fetch the org id
|
|
156
|
+
const orgId = await getOrganizationId(supabase, appid)
|
|
157
|
+
await checkPlanValid(supabase, orgId, options.apikey, appid, true)
|
|
158
|
+
|
|
159
|
+
const updateMetadataRequired = await requireUpdateMetadata(supabase, channel, appid)
|
|
125
160
|
|
|
126
161
|
// Check compatibility here
|
|
127
162
|
const { data: channelData, error: channelError } = await supabase
|
|
@@ -197,11 +232,12 @@ export async function uploadBundle(appid: string, options: Options, shouldExit =
|
|
|
197
232
|
}
|
|
198
233
|
|
|
199
234
|
const { data: isTrial, error: isTrialsError } = await supabase
|
|
200
|
-
.rpc('
|
|
235
|
+
.rpc('is_trial_org', { orgid: orgId })
|
|
201
236
|
.single()
|
|
202
237
|
if ((isTrial && isTrial > 0) || isTrialsError) {
|
|
238
|
+
// TODO: Come back to this to fix for orgs v3
|
|
203
239
|
p.log.warn(`WARNING !!\nTrial expires in ${isTrial} days`)
|
|
204
|
-
p.log.warn(`Upgrade here: ${localConfig.hostWeb}/dashboard/settings/plans`)
|
|
240
|
+
p.log.warn(`Upgrade here: ${localConfig.hostWeb}/dashboard/settings/plans?oid=${orgId}`)
|
|
205
241
|
}
|
|
206
242
|
|
|
207
243
|
// check if app already exist
|
|
@@ -213,14 +249,11 @@ export async function uploadBundle(appid: string, options: Options, shouldExit =
|
|
|
213
249
|
p.log.error(`Version already exists ${formatError(appVersionError)}`)
|
|
214
250
|
program.error('')
|
|
215
251
|
}
|
|
216
|
-
// make bundle safe for s3 name https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-keys.html
|
|
217
|
-
const safeBundle = bundle.replace(/[^a-zA-Z0-9-_.!*'()]/g, '__')
|
|
218
|
-
const fileName = `${safeBundle}.zip`
|
|
219
252
|
|
|
220
253
|
let sessionKey
|
|
221
254
|
let checksum = ''
|
|
222
255
|
let zipped: Buffer | null = null
|
|
223
|
-
if (!external) {
|
|
256
|
+
if (!external && useS3 === false) {
|
|
224
257
|
const zip = new AdmZip()
|
|
225
258
|
zip.addLocalFolder(path)
|
|
226
259
|
zipped = zip.toBuffer()
|
|
@@ -241,7 +274,7 @@ export async function uploadBundle(appid: string, options: Options, shouldExit =
|
|
|
241
274
|
if (ciDetect.isCI)
|
|
242
275
|
program.error('')
|
|
243
276
|
|
|
244
|
-
const res = await p.confirm({ message: 'Do you want to use our
|
|
277
|
+
const res = await p.confirm({ message: 'Do you want to use our private key ?' })
|
|
245
278
|
if (!res) {
|
|
246
279
|
p.log.error(`Error: Missing public key`)
|
|
247
280
|
program.error('')
|
|
@@ -264,6 +297,10 @@ export async function uploadBundle(appid: string, options: Options, shouldExit =
|
|
|
264
297
|
keyData = keyFile.toString()
|
|
265
298
|
}
|
|
266
299
|
// encrypt
|
|
300
|
+
if (keyData && !keyData.startsWith('-----BEGIN RSA PRIVATE KEY-----')) {
|
|
301
|
+
p.log.error(`the private key provided is not a valid RSA Private key`)
|
|
302
|
+
program.error('')
|
|
303
|
+
}
|
|
267
304
|
p.log.info(`Encrypting your bundle`)
|
|
268
305
|
const res = encryptSource(zipped, keyData)
|
|
269
306
|
sessionKey = res.ivSessionKey
|
|
@@ -295,6 +332,15 @@ It will be also visible in your dashboard\n`)
|
|
|
295
332
|
program.error('')
|
|
296
333
|
}
|
|
297
334
|
else {
|
|
335
|
+
if (useS3) {
|
|
336
|
+
const zip = new AdmZip()
|
|
337
|
+
zip.addLocalFolder(path)
|
|
338
|
+
zipped = zip.toBuffer()
|
|
339
|
+
const s = p.spinner()
|
|
340
|
+
s.start(`Calculating checksum`)
|
|
341
|
+
checksum = await getChecksum(zipped, 'crc32')
|
|
342
|
+
s.stop(`Checksum: ${checksum}`)
|
|
343
|
+
}
|
|
298
344
|
await snag.track({
|
|
299
345
|
channel: 'app',
|
|
300
346
|
event: 'App external',
|
|
@@ -319,8 +365,7 @@ It will be also visible in your dashboard\n`)
|
|
|
319
365
|
const appOwner = await getAppOwner(supabase, appid)
|
|
320
366
|
|
|
321
367
|
const versionData = {
|
|
322
|
-
bucket_id: external ? undefined : fileName,
|
|
323
|
-
user_id: appOwner,
|
|
368
|
+
// bucket_id: external ? undefined : fileName,
|
|
324
369
|
name: bundle,
|
|
325
370
|
app_id: appid,
|
|
326
371
|
session_key: sessionKey,
|
|
@@ -328,6 +373,8 @@ It will be also visible in your dashboard\n`)
|
|
|
328
373
|
storage_provider: external ? 'external' : 'r2-direct',
|
|
329
374
|
minUpdateVersion,
|
|
330
375
|
native_packages: nativePackages,
|
|
376
|
+
owner_org: EMPTY_UUID,
|
|
377
|
+
user_id: userId,
|
|
331
378
|
checksum,
|
|
332
379
|
}
|
|
333
380
|
const { error: dbError } = await updateOrCreateVersion(supabase, versionData)
|
|
@@ -339,22 +386,29 @@ It will be also visible in your dashboard\n`)
|
|
|
339
386
|
const spinner = p.spinner()
|
|
340
387
|
spinner.start(`Uploading Bundle`)
|
|
341
388
|
|
|
342
|
-
const url = await uploadUrl(supabase, appid,
|
|
389
|
+
const url = await uploadUrl(supabase, appid, bundle)
|
|
343
390
|
if (!url) {
|
|
344
391
|
p.log.error(`Cannot get upload url`)
|
|
345
392
|
program.error('')
|
|
346
393
|
}
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
394
|
+
try {
|
|
395
|
+
await ky.put(url, {
|
|
396
|
+
timeout: 60000,
|
|
397
|
+
retry: 5,
|
|
398
|
+
body: zipped,
|
|
399
|
+
headers: (!localS3
|
|
400
|
+
? {
|
|
401
|
+
'Content-Type': 'application/octet-stream',
|
|
402
|
+
'Cache-Control': 'public, max-age=456789, immutable',
|
|
403
|
+
'x-amz-meta-crc32': checksum,
|
|
404
|
+
}
|
|
405
|
+
: undefined),
|
|
406
|
+
})
|
|
407
|
+
}
|
|
408
|
+
catch (errorUpload) {
|
|
409
|
+
p.log.error(`Cannot upload bundle ${formatError(errorUpload)}`)
|
|
410
|
+
program.error('')
|
|
411
|
+
}
|
|
358
412
|
versionData.storage_provider = 'r2'
|
|
359
413
|
const { error: dbError2 } = await updateOrCreateVersion(supabase, versionData)
|
|
360
414
|
if (dbError2) {
|
|
@@ -363,6 +417,33 @@ It will be also visible in your dashboard\n`)
|
|
|
363
417
|
}
|
|
364
418
|
spinner.stop('Bundle Uploaded 💪')
|
|
365
419
|
}
|
|
420
|
+
else if (useS3 && zipped) {
|
|
421
|
+
const spinner = p.spinner()
|
|
422
|
+
spinner.start(`Uploading Bundle`)
|
|
423
|
+
|
|
424
|
+
const fileName = `${appid}-${bundle}`
|
|
425
|
+
const encodeFileName = encodeURIComponent(fileName)
|
|
426
|
+
const command: PutObjectCommand = new PutObjectCommand({
|
|
427
|
+
Bucket: s3BucketName,
|
|
428
|
+
Key: fileName,
|
|
429
|
+
Body: zipped,
|
|
430
|
+
})
|
|
431
|
+
|
|
432
|
+
const response = await s3Client.send(command)
|
|
433
|
+
if (response.$metadata.httpStatusCode !== 200) {
|
|
434
|
+
p.log.error(`Cannot upload to S3`)
|
|
435
|
+
program.error('')
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
versionData.storage_provider = 'external'
|
|
439
|
+
versionData.external_url = `https://${s3BucketName}.s3.amazonaws.com/${encodeFileName}`
|
|
440
|
+
const { error: dbError2 } = await updateOrCreateVersion(supabase, versionData)
|
|
441
|
+
if (dbError2) {
|
|
442
|
+
p.log.error(`Cannot update bundle ${formatError(dbError2)}`)
|
|
443
|
+
program.error('')
|
|
444
|
+
}
|
|
445
|
+
spinner.stop('Bundle Uploaded 💪')
|
|
446
|
+
}
|
|
366
447
|
const { data: versionId } = await supabase
|
|
367
448
|
.rpc('get_app_versions', { apikey: options.apikey, name_version: bundle, appid })
|
|
368
449
|
.single()
|
|
@@ -373,6 +454,7 @@ It will be also visible in your dashboard\n`)
|
|
|
373
454
|
app_id: appid,
|
|
374
455
|
created_by: appOwner,
|
|
375
456
|
version: versionId,
|
|
457
|
+
owner_org: EMPTY_UUID,
|
|
376
458
|
})
|
|
377
459
|
if (dbError3) {
|
|
378
460
|
p.log.error(`Cannot set channel, the upload key is not allowed to do that, use the "all" for this. ${formatError(dbError3)}`)
|
package/src/bundle/zip.ts
CHANGED
|
@@ -112,15 +112,6 @@ export async function zipBundle(appId: string, options: Options) {
|
|
|
112
112
|
if (!json)
|
|
113
113
|
s2.stop(`Saved to ${name}`)
|
|
114
114
|
|
|
115
|
-
if (options.json) {
|
|
116
|
-
const output = {
|
|
117
|
-
bundle,
|
|
118
|
-
filename: name,
|
|
119
|
-
checksum,
|
|
120
|
-
}
|
|
121
|
-
p.log.info(formatError(output))
|
|
122
|
-
}
|
|
123
|
-
|
|
124
115
|
await snag.track({
|
|
125
116
|
channel: 'app',
|
|
126
117
|
event: 'App zip',
|
|
@@ -133,5 +124,16 @@ export async function zipBundle(appId: string, options: Options) {
|
|
|
133
124
|
|
|
134
125
|
if (!json)
|
|
135
126
|
p.outro(`Done ✅`)
|
|
127
|
+
|
|
128
|
+
if (json) {
|
|
129
|
+
const output = {
|
|
130
|
+
bundle,
|
|
131
|
+
filename: name,
|
|
132
|
+
checksum,
|
|
133
|
+
}
|
|
134
|
+
// Keep the console log and stringify for user who parse the output
|
|
135
|
+
// eslint-disable-next-line no-console
|
|
136
|
+
console.log(JSON.stringify(output, null, 2))
|
|
137
|
+
}
|
|
136
138
|
process.exit()
|
|
137
139
|
}
|
package/src/channel/add.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import process from 'node:process'
|
|
2
2
|
import { program } from 'commander'
|
|
3
3
|
import * as p from '@clack/prompts'
|
|
4
|
-
import {
|
|
4
|
+
import { checkAppExistsAndHasPermissionOrgErr } from '../api/app'
|
|
5
5
|
import { createChannel, findUnknownVersion } from '../api/channels'
|
|
6
6
|
import type { OptionsBase } from '../utils'
|
|
7
|
-
import { createSupabaseClient, findSavedKey, getConfig, useLogSnag, verifyUser } from '../utils'
|
|
7
|
+
import { EMPTY_UUID, OrganizationPerm, createSupabaseClient, findSavedKey, getConfig, useLogSnag, verifyUser } from '../utils'
|
|
8
8
|
|
|
9
9
|
interface Options extends OptionsBase {
|
|
10
10
|
default?: boolean
|
|
@@ -29,7 +29,7 @@ export async function addChannel(channelId: string, appId: string, options: Opti
|
|
|
29
29
|
|
|
30
30
|
const userId = await verifyUser(supabase, options.apikey, ['write', 'all'])
|
|
31
31
|
// Check we have app access to this appId
|
|
32
|
-
await
|
|
32
|
+
await checkAppExistsAndHasPermissionOrgErr(supabase, options.apikey, appId, OrganizationPerm.admin)
|
|
33
33
|
|
|
34
34
|
p.log.info(`Creating channel ${appId}#${channelId} to Capgo`)
|
|
35
35
|
try {
|
|
@@ -42,7 +42,7 @@ export async function addChannel(channelId: string, appId: string, options: Opti
|
|
|
42
42
|
name: channelId,
|
|
43
43
|
app_id: appId,
|
|
44
44
|
version: data.id,
|
|
45
|
-
|
|
45
|
+
owner_org: EMPTY_UUID,
|
|
46
46
|
})
|
|
47
47
|
p.log.success(`Channel created ✅`)
|
|
48
48
|
await snag.track({
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import process from 'node:process'
|
|
2
2
|
import { program } from 'commander'
|
|
3
3
|
import * as p from '@clack/prompts'
|
|
4
|
-
import {
|
|
4
|
+
import { checkAppExistsAndHasPermissionOrgErr } from '../api/app'
|
|
5
5
|
import type { OptionsBase } from '../utils'
|
|
6
|
-
import { createSupabaseClient, findSavedKey, getConfig, verifyUser } from '../utils'
|
|
6
|
+
import { OrganizationPerm, createSupabaseClient, findSavedKey, getConfig, verifyUser } from '../utils'
|
|
7
7
|
|
|
8
8
|
interface Options extends OptionsBase {
|
|
9
9
|
channel?: string
|
|
@@ -36,9 +36,9 @@ export async function currentBundle(channel: string, appId: string, options: Opt
|
|
|
36
36
|
}
|
|
37
37
|
const supabase = await createSupabaseClient(options.apikey)
|
|
38
38
|
|
|
39
|
-
const
|
|
39
|
+
const _userId = await verifyUser(supabase, options.apikey, ['write', 'all', 'read'])
|
|
40
40
|
// Check we have app access to this appId
|
|
41
|
-
await
|
|
41
|
+
await checkAppExistsAndHasPermissionOrgErr(supabase, options.apikey, appId, OrganizationPerm.read)
|
|
42
42
|
|
|
43
43
|
if (!channel) {
|
|
44
44
|
p.log.error(`Please provide a channel to get the bundle from.`)
|
|
@@ -50,7 +50,6 @@ export async function currentBundle(channel: string, appId: string, options: Opt
|
|
|
50
50
|
.select('version ( name )')
|
|
51
51
|
.eq('name', channel)
|
|
52
52
|
.eq('app_id', appId)
|
|
53
|
-
.eq('created_by', userId)
|
|
54
53
|
.limit(1)
|
|
55
54
|
|
|
56
55
|
if (error || supabaseChannel.length === 0) {
|
package/src/channel/delete.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import process from 'node:process'
|
|
2
2
|
import { program } from 'commander'
|
|
3
3
|
import * as p from '@clack/prompts'
|
|
4
|
-
import {
|
|
4
|
+
import { checkAppExistsAndHasPermissionOrgErr } from '../api/app'
|
|
5
5
|
import { delChannel } from '../api/channels'
|
|
6
6
|
import type { OptionsBase } from '../utils'
|
|
7
|
-
import { createSupabaseClient, findSavedKey, getConfig, useLogSnag, verifyUser } from '../utils'
|
|
7
|
+
import { OrganizationPerm, createSupabaseClient, findSavedKey, getConfig, useLogSnag, verifyUser } from '../utils'
|
|
8
8
|
|
|
9
9
|
export async function deleteChannel(channelId: string, appId: string, options: OptionsBase) {
|
|
10
10
|
p.intro(`Delete channel`)
|
|
@@ -25,7 +25,7 @@ export async function deleteChannel(channelId: string, appId: string, options: O
|
|
|
25
25
|
|
|
26
26
|
const userId = await verifyUser(supabase, options.apikey, ['write', 'all'])
|
|
27
27
|
// Check we have app access to this appId
|
|
28
|
-
await
|
|
28
|
+
await checkAppExistsAndHasPermissionOrgErr(supabase, options.apikey, appId, OrganizationPerm.admin)
|
|
29
29
|
|
|
30
30
|
p.log.info(`Deleting channel ${appId}#${channelId} from Capgo`)
|
|
31
31
|
try {
|
package/src/channel/list.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import process from 'node:process'
|
|
2
2
|
import { program } from 'commander'
|
|
3
3
|
import * as p from '@clack/prompts'
|
|
4
|
-
import {
|
|
4
|
+
import { checkAppExistsAndHasPermissionOrgErr } from '../api/app'
|
|
5
5
|
import { displayChannels, getActiveChannels } from '../api/channels'
|
|
6
6
|
import type { OptionsBase } from '../utils'
|
|
7
|
-
import { createSupabaseClient, findSavedKey, getConfig, useLogSnag, verifyUser } from '../utils'
|
|
7
|
+
import { OrganizationPerm, createSupabaseClient, findSavedKey, getConfig, useLogSnag, verifyUser } from '../utils'
|
|
8
8
|
|
|
9
9
|
export async function listChannels(appId: string, options: OptionsBase) {
|
|
10
10
|
p.intro(`List channels`)
|
|
@@ -24,7 +24,7 @@ export async function listChannels(appId: string, options: OptionsBase) {
|
|
|
24
24
|
|
|
25
25
|
const userId = await verifyUser(supabase, options.apikey, ['write', 'all', 'read', 'upload'])
|
|
26
26
|
// Check we have app access to this appId
|
|
27
|
-
await
|
|
27
|
+
await checkAppExistsAndHasPermissionOrgErr(supabase, options.apikey, appId, OrganizationPerm.read)
|
|
28
28
|
|
|
29
29
|
p.log.info(`Querying available channels in Capgo`)
|
|
30
30
|
|
package/src/channel/set.ts
CHANGED
|
@@ -2,16 +2,18 @@ import process from 'node:process'
|
|
|
2
2
|
import { program } from 'commander'
|
|
3
3
|
import * as p from '@clack/prompts'
|
|
4
4
|
import type { Database } from '../types/supabase.types'
|
|
5
|
-
import {
|
|
5
|
+
import { checkAppExistsAndHasPermissionOrgErr } from '../api/app'
|
|
6
6
|
import type {
|
|
7
7
|
OptionsBase,
|
|
8
8
|
} from '../utils'
|
|
9
9
|
import {
|
|
10
|
+
OrganizationPerm,
|
|
10
11
|
checkPlanValid,
|
|
11
12
|
createSupabaseClient,
|
|
12
13
|
findSavedKey,
|
|
13
14
|
formatError,
|
|
14
15
|
getConfig,
|
|
16
|
+
getOrganizationId,
|
|
15
17
|
updateOrCreateChannel,
|
|
16
18
|
useLogSnag,
|
|
17
19
|
verifyUser,
|
|
@@ -30,7 +32,7 @@ interface Options extends OptionsBase {
|
|
|
30
32
|
channel?: string
|
|
31
33
|
}
|
|
32
34
|
|
|
33
|
-
const disableAutoUpdatesPossibleOptions = ['major', 'minor', 'metadata', 'none']
|
|
35
|
+
const disableAutoUpdatesPossibleOptions = ['major', 'minor', 'metadata', 'patch', 'none']
|
|
34
36
|
|
|
35
37
|
export async function setChannel(channel: string, appId: string, options: Options) {
|
|
36
38
|
p.intro(`Set channel`)
|
|
@@ -51,7 +53,8 @@ export async function setChannel(channel: string, appId: string, options: Option
|
|
|
51
53
|
|
|
52
54
|
const userId = await verifyUser(supabase, options.apikey, ['write', 'all'])
|
|
53
55
|
// Check we have app access to this appId
|
|
54
|
-
await
|
|
56
|
+
await checkAppExistsAndHasPermissionOrgErr(supabase, options.apikey, appId, OrganizationPerm.admin)
|
|
57
|
+
const orgId = await getOrganizationId(supabase, appId)
|
|
55
58
|
|
|
56
59
|
const { bundle, latest, downgrade, upgrade, ios, android, selfAssign, state, disableAutoUpdate } = options
|
|
57
60
|
if (!channel) {
|
|
@@ -75,7 +78,7 @@ export async function setChannel(channel: string, appId: string, options: Option
|
|
|
75
78
|
program.error('')
|
|
76
79
|
}
|
|
77
80
|
try {
|
|
78
|
-
await checkPlanValid(supabase,
|
|
81
|
+
await checkPlanValid(supabase, orgId, options.apikey, appId)
|
|
79
82
|
const channelPayload: Database['public']['Tables']['channels']['Insert'] = {
|
|
80
83
|
created_by: userId,
|
|
81
84
|
app_id: appId,
|
package/src/index.ts
CHANGED
|
@@ -113,6 +113,10 @@ bundle
|
|
|
113
113
|
.option('-c, --channel <channel>', 'channel to link to')
|
|
114
114
|
.option('-e, --external <url>', 'link to external url intead of upload to Capgo Cloud')
|
|
115
115
|
.option('--iv-session-key <key>', 'Set the iv and session key for bundle url external')
|
|
116
|
+
.option('--s3-region <region>', 'Region for your AWS S3 bucket')
|
|
117
|
+
.option('--s3-apikey <apikey>', 'apikey for your AWS S3 account')
|
|
118
|
+
.option('--s3-apisecret <apisecret>', 'api secret for your AWS S3 account')
|
|
119
|
+
.option('--s3-bucket-name <bucketName>', 'Name for your AWS S3 bucket')
|
|
116
120
|
.option('--key <key>', 'custom path for public signing key')
|
|
117
121
|
.option('--key-data <keyData>', 'base64 public signing key')
|
|
118
122
|
.option('--bundle-url', 'prints bundle url into stdout')
|
|
@@ -148,12 +152,13 @@ bundle
|
|
|
148
152
|
.action(listBundle)
|
|
149
153
|
.option('-a, --apikey <apikey>', 'apikey to link to your account')
|
|
150
154
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
155
|
+
// TODO: Fix this command!
|
|
156
|
+
// bundle
|
|
157
|
+
// .command('unlink [appId]')
|
|
158
|
+
// .description('Unlink a bundle in Capgo Cloud')
|
|
159
|
+
// .action(listBundle)
|
|
160
|
+
// .option('-a, --apikey <apikey>', 'apikey to link to your account')
|
|
161
|
+
// .option('-b, --bundle <bundle>', 'bundle version number of the bundle to unlink')
|
|
157
162
|
|
|
158
163
|
bundle
|
|
159
164
|
.command('cleanup [appId]')
|
|
@@ -242,7 +247,7 @@ channel
|
|
|
242
247
|
.option('--no-android', 'Disable sending update to android devices')
|
|
243
248
|
.option('--self-assign', 'Allow to device to self assign to this channel')
|
|
244
249
|
.option('--no-self-assign', 'Disable devices to self assign to this channel')
|
|
245
|
-
.option('--disable-auto-update <disableAutoUpdate>', 'Disable auto update strategy for this channel.The possible options are: major, minor, metadata, none')
|
|
250
|
+
.option('--disable-auto-update <disableAutoUpdate>', 'Disable auto update strategy for this channel.The possible options are: major, minor, metadata, patch, none')
|
|
246
251
|
|
|
247
252
|
const key = program
|
|
248
253
|
.command('key')
|