@capgo/cli 4.12.12 → 4.12.14-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.
- package/.github/workflows/autofix.yml +25 -0
- package/CHANGELOG.md +9 -0
- package/bun.lockb +0 -0
- package/bunfig.toml +2 -0
- package/dist/index.js +40559 -50832
- package/package.json +22 -24
- package/src/api/app.ts +5 -5
- package/src/api/channels.ts +12 -12
- package/src/api/devices_override.ts +8 -8
- package/src/api/update.ts +2 -2
- package/src/api/versions.ts +10 -9
- package/src/app/add.ts +21 -22
- package/src/app/debug.ts +53 -54
- package/src/app/delete.ts +20 -20
- package/src/app/info.ts +34 -24
- package/src/app/list.ts +11 -11
- package/src/app/set.ts +16 -16
- package/src/bundle/check.ts +10 -10
- package/src/bundle/cleanup.ts +27 -27
- package/src/bundle/compatibility.ts +8 -8
- package/src/bundle/decrypt.ts +8 -8
- package/src/bundle/delete.ts +14 -15
- package/src/bundle/encrypt.ts +13 -13
- package/src/bundle/list.ts +11 -12
- package/src/bundle/unlink.ts +15 -13
- package/src/bundle/upload.ts +93 -86
- package/src/bundle/zip.ts +23 -21
- package/src/channel/add.ts +14 -14
- package/src/channel/currentBundle.ts +13 -13
- package/src/channel/delete.ts +13 -13
- package/src/channel/list.ts +11 -11
- package/src/channel/set.ts +28 -26
- package/src/config/index.ts +156 -0
- package/src/index.ts +6 -3
- package/src/init.ts +22 -22
- package/src/key.ts +45 -46
- package/src/login.ts +10 -10
- package/src/user/account.ts +3 -3
- package/src/utils.ts +119 -150
- package/tsconfig.json +1 -1
- package/vercel-ncc.js +18 -0
package/src/utils.ts
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs'
|
|
2
2
|
import { homedir, platform as osPlatform } from 'node:os'
|
|
3
|
-
import
|
|
4
|
-
import
|
|
3
|
+
import { join, resolve, sep } from 'node:path'
|
|
4
|
+
import { cwd, env, exit } from 'node:process'
|
|
5
5
|
import type { Buffer } from 'node:buffer'
|
|
6
|
-
import { loadConfig } from '@capacitor/cli/dist/config'
|
|
7
6
|
import { program } from 'commander'
|
|
8
7
|
import type { SupabaseClient } from '@supabase/supabase-js'
|
|
9
8
|
import { createClient } from '@supabase/supabase-js'
|
|
10
9
|
import prettyjson from 'prettyjson'
|
|
11
10
|
import { LogSnag } from 'logsnag'
|
|
12
|
-
import * as p from '@clack/prompts'
|
|
13
11
|
import ky from 'ky'
|
|
14
12
|
import { findRootSync } from '@manypkg/find-root'
|
|
15
13
|
import type { InstallCommand, PackageManagerRunner, PackageManagerType } from '@capgo/find-package-manager'
|
|
16
14
|
import { findInstallCommand, findPackageManagerRunner, findPackageManagerType } from '@capgo/find-package-manager'
|
|
17
15
|
import AdmZip from 'adm-zip'
|
|
18
16
|
import JSZip from 'jszip'
|
|
17
|
+
import { confirm as confirmC, isCancel, log, select, spinner } from '@clack/prompts'
|
|
18
|
+
import { loadConfig } from './config'
|
|
19
19
|
import type { Database } from './types/supabase.types'
|
|
20
20
|
|
|
21
21
|
export const baseKey = '.capgo_key'
|
|
@@ -41,30 +41,38 @@ export function wait(ms: number) {
|
|
|
41
41
|
})
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
+
export async function readPackageJson() {
|
|
45
|
+
const packageJson = readFileSync(join(cwd(), 'package.json'))
|
|
46
|
+
return JSON.parse(packageJson as any)
|
|
47
|
+
}
|
|
48
|
+
|
|
44
49
|
export async function getConfig() {
|
|
45
|
-
let config: Config
|
|
46
50
|
try {
|
|
47
|
-
|
|
51
|
+
const extConfig = await loadConfig()
|
|
52
|
+
if (!extConfig) {
|
|
53
|
+
log.error(`No capacitor config file found, run \`cap init\` first`)
|
|
54
|
+
program.error('')
|
|
55
|
+
}
|
|
56
|
+
return extConfig
|
|
48
57
|
}
|
|
49
58
|
catch (err) {
|
|
50
|
-
|
|
59
|
+
log.error(`No capacitor config file found, run \`cap init\` first ${formatError(err)}`)
|
|
51
60
|
program.error('')
|
|
52
61
|
}
|
|
53
|
-
return config
|
|
54
62
|
}
|
|
55
63
|
|
|
56
64
|
export async function getLocalConfig() {
|
|
57
65
|
try {
|
|
58
|
-
const
|
|
66
|
+
const extConfig = await getConfig()
|
|
59
67
|
const capConfig: Partial<CapgoConfig> = {
|
|
60
|
-
host: (config?.
|
|
61
|
-
hostWeb: (config?.
|
|
68
|
+
host: (extConfig?.config?.plugins?.CapacitorUpdater?.localHost || defaultHost) as string,
|
|
69
|
+
hostWeb: (extConfig?.config?.plugins?.CapacitorUpdater?.localWebHost || defaultHostWeb) as string,
|
|
62
70
|
}
|
|
63
71
|
|
|
64
|
-
if (config?.
|
|
65
|
-
|
|
66
|
-
capConfig.supaKey = config?.
|
|
67
|
-
capConfig.supaHost = config?.
|
|
72
|
+
if (extConfig?.config?.plugins?.CapacitorUpdater?.localSupa && extConfig?.config?.plugins?.CapacitorUpdater?.localSupaAnon) {
|
|
73
|
+
log.info('Using custom supabase instance from capacitor.config.json')
|
|
74
|
+
capConfig.supaKey = extConfig?.config?.plugins?.CapacitorUpdater?.localSupaAnon
|
|
75
|
+
capConfig.supaHost = extConfig?.config?.plugins?.CapacitorUpdater?.localSupa
|
|
68
76
|
}
|
|
69
77
|
return capConfig
|
|
70
78
|
}
|
|
@@ -93,7 +101,7 @@ export async function getRemoteConfig() {
|
|
|
93
101
|
.then(res => res.json<CapgoConfig>())
|
|
94
102
|
.then(data => ({ ...data, ...localConfig } as CapgoConfig))
|
|
95
103
|
.catch(() => {
|
|
96
|
-
|
|
104
|
+
log.info(`Local config ${formatError(localConfig)}`)
|
|
97
105
|
return localConfig
|
|
98
106
|
})
|
|
99
107
|
}
|
|
@@ -101,7 +109,7 @@ export async function getRemoteConfig() {
|
|
|
101
109
|
export async function createSupabaseClient(apikey: string) {
|
|
102
110
|
const config = await getRemoteConfig()
|
|
103
111
|
if (!config.supaHost || !config.supaKey) {
|
|
104
|
-
|
|
112
|
+
log.error('Cannot connect to server please try again later')
|
|
105
113
|
program.error('')
|
|
106
114
|
}
|
|
107
115
|
return createClient<Database>(config.supaHost, config.supaKey, {
|
|
@@ -122,7 +130,7 @@ export async function checkKey(supabase: SupabaseClient<Database>, apikey: strin
|
|
|
122
130
|
.single()
|
|
123
131
|
|
|
124
132
|
if (!apiAccess) {
|
|
125
|
-
|
|
133
|
+
log.error(`Invalid API key or insufficient permissions.`)
|
|
126
134
|
// create a string from keymode array with comma and space and "or" for the last one
|
|
127
135
|
const keymodeStr = keymode.map((k, i) => {
|
|
128
136
|
if (i === keymode.length - 1)
|
|
@@ -130,7 +138,7 @@ export async function checkKey(supabase: SupabaseClient<Database>, apikey: strin
|
|
|
130
138
|
|
|
131
139
|
return `${k}, `
|
|
132
140
|
}).join('')
|
|
133
|
-
|
|
141
|
+
log.error(`Your key should be: ${keymodeStr} mode.`)
|
|
134
142
|
program.error('')
|
|
135
143
|
}
|
|
136
144
|
}
|
|
@@ -188,9 +196,9 @@ export async function isAllowedAppOrg(supabase: SupabaseClient<Database>, apikey
|
|
|
188
196
|
.single()
|
|
189
197
|
|
|
190
198
|
if (error) {
|
|
191
|
-
|
|
199
|
+
log.error('Cannot get permissions for organization!')
|
|
192
200
|
console.error(error)
|
|
193
|
-
|
|
201
|
+
exit(1)
|
|
194
202
|
}
|
|
195
203
|
|
|
196
204
|
const ok = (data as string).includes('perm')
|
|
@@ -224,12 +232,12 @@ export async function isAllowedAppOrg(supabase: SupabaseClient<Database>, apikey
|
|
|
224
232
|
}
|
|
225
233
|
default: {
|
|
226
234
|
if ((data as string).includes('invite')) {
|
|
227
|
-
|
|
228
|
-
|
|
235
|
+
log.info('Please accept/deny the organization invitation before trying to access the app')
|
|
236
|
+
exit(1)
|
|
229
237
|
}
|
|
230
238
|
|
|
231
|
-
|
|
232
|
-
|
|
239
|
+
log.error(`Invalid output when fetching organization permission. Response: ${data}`)
|
|
240
|
+
exit(1)
|
|
233
241
|
}
|
|
234
242
|
}
|
|
235
243
|
|
|
@@ -256,8 +264,8 @@ export async function isAllowedAppOrg(supabase: SupabaseClient<Database>, apikey
|
|
|
256
264
|
break
|
|
257
265
|
}
|
|
258
266
|
default: {
|
|
259
|
-
|
|
260
|
-
|
|
267
|
+
log.error(`Invalid error when fetching organization permission. Response: ${data}`)
|
|
268
|
+
exit(1)
|
|
261
269
|
}
|
|
262
270
|
}
|
|
263
271
|
|
|
@@ -273,7 +281,7 @@ export async function checkPlanValid(supabase: SupabaseClient<Database>, orgId:
|
|
|
273
281
|
// isAllowedActionAppIdApiKey was updated in the orgs_v3 migration to work with the new system
|
|
274
282
|
const validPlan = await (appId ? isAllowedActionAppIdApiKey(supabase, appId, apikey) : isAllowedActionOrg(supabase, orgId))
|
|
275
283
|
if (!validPlan) {
|
|
276
|
-
|
|
284
|
+
log.error(`You need to upgrade your plan to continue to use capgo.\n Upgrade here: ${config.hostWeb}/dashboard/settings/plans\n`)
|
|
277
285
|
wait(100)
|
|
278
286
|
import('open')
|
|
279
287
|
.then((module) => {
|
|
@@ -287,7 +295,7 @@ export async function checkPlanValid(supabase: SupabaseClient<Database>, orgId:
|
|
|
287
295
|
isPayingOrg(supabase, orgId),
|
|
288
296
|
])
|
|
289
297
|
if (trialDays > 0 && warning && !ispaying)
|
|
290
|
-
|
|
298
|
+
log.warn(`WARNING !!\nTrial expires in ${trialDays} days, upgrade here: ${config.hostWeb}/dashboard/settings/plans\n`)
|
|
291
299
|
}
|
|
292
300
|
|
|
293
301
|
export function findSavedKey(quiet = false) {
|
|
@@ -297,17 +305,17 @@ export function findSavedKey(quiet = false) {
|
|
|
297
305
|
let keyPath = `${userHomeDir}/.capgo`
|
|
298
306
|
if (existsSync(keyPath)) {
|
|
299
307
|
if (!quiet)
|
|
300
|
-
|
|
308
|
+
log.info(`Use global apy key ${keyPath}`)
|
|
301
309
|
key = readFileSync(keyPath, 'utf8').trim()
|
|
302
310
|
}
|
|
303
311
|
keyPath = `.capgo`
|
|
304
312
|
if (!key && existsSync(keyPath)) {
|
|
305
313
|
if (!quiet)
|
|
306
|
-
|
|
314
|
+
log.info(`Use local apy key ${keyPath}`)
|
|
307
315
|
key = readFileSync(keyPath, 'utf8').trim()
|
|
308
316
|
}
|
|
309
317
|
if (!key) {
|
|
310
|
-
|
|
318
|
+
log.error(`Cannot find API key in local folder or global, please login first with ${getPMAndCommand().runner} @capacitor/cli login`)
|
|
311
319
|
program.error('')
|
|
312
320
|
}
|
|
313
321
|
return key
|
|
@@ -338,7 +346,7 @@ export async function findProjectType() {
|
|
|
338
346
|
// for sveltekit check if svelte.config.js exists or svelte is in package.json dependancies
|
|
339
347
|
// for vue check if vue.config.js exists or vue is in package.json dependancies
|
|
340
348
|
// for react check if package.json exists and react is in dependencies
|
|
341
|
-
const pwd =
|
|
349
|
+
const pwd = cwd()
|
|
342
350
|
let isTypeScript = false
|
|
343
351
|
|
|
344
352
|
// Check for TypeScript configuration file
|
|
@@ -350,39 +358,38 @@ export async function findProjectType() {
|
|
|
350
358
|
for await (const f of getFiles(pwd)) {
|
|
351
359
|
// find number of folder in path after pwd
|
|
352
360
|
if (f.includes('angular.json')) {
|
|
353
|
-
|
|
361
|
+
log.info('Found angular project')
|
|
354
362
|
return isTypeScript ? 'angular-ts' : 'angular-js'
|
|
355
363
|
}
|
|
356
364
|
if (f.includes('nuxt.config.js' || f.includes('nuxt.config.ts'))) {
|
|
357
|
-
|
|
365
|
+
log.info('Found nuxtjs project')
|
|
358
366
|
return isTypeScript ? 'nuxtjs-ts' : 'nuxtjs-js'
|
|
359
367
|
}
|
|
360
368
|
if (f.includes('next.config.js') || f.includes('next.config.mjs')) {
|
|
361
|
-
|
|
369
|
+
log.info('Found nextjs project')
|
|
362
370
|
return isTypeScript ? 'nextjs-ts' : 'nextjs-js'
|
|
363
371
|
}
|
|
364
372
|
if (f.includes('svelte.config.js')) {
|
|
365
|
-
|
|
373
|
+
log.info('Found sveltekit project')
|
|
366
374
|
return isTypeScript ? 'sveltekit-ts' : 'sveltekit-js'
|
|
367
375
|
}
|
|
368
|
-
if (f.includes('
|
|
369
|
-
|
|
376
|
+
if (f.includes('rolluconfig.js')) {
|
|
377
|
+
log.info('Found svelte project')
|
|
370
378
|
return isTypeScript ? 'svelte-ts' : 'svelte-js'
|
|
371
379
|
}
|
|
372
380
|
if (f.includes('vue.config.js')) {
|
|
373
|
-
|
|
381
|
+
log.info('Found vue project')
|
|
374
382
|
return isTypeScript ? 'vue-ts' : 'vue-js'
|
|
375
383
|
}
|
|
376
384
|
if (f.includes('package.json')) {
|
|
377
|
-
const
|
|
378
|
-
const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf8'))
|
|
385
|
+
const packageJson = await readPackageJson()
|
|
379
386
|
if (packageJson.dependencies) {
|
|
380
387
|
if (packageJson.dependencies.react) {
|
|
381
|
-
|
|
388
|
+
log.info('Found react project test')
|
|
382
389
|
return isTypeScript ? 'react-ts' : 'react-js'
|
|
383
390
|
}
|
|
384
391
|
if (packageJson.dependencies.vue) {
|
|
385
|
-
|
|
392
|
+
log.info('Found vue project')
|
|
386
393
|
return isTypeScript ? 'vue-ts' : 'vue-js'
|
|
387
394
|
}
|
|
388
395
|
}
|
|
@@ -414,34 +421,34 @@ export function findMainFileForProjectType(projectType: string, isTypeScript: bo
|
|
|
414
421
|
|
|
415
422
|
export async function findBuildCommandForProjectType(projectType: string) {
|
|
416
423
|
if (projectType === 'angular') {
|
|
417
|
-
|
|
424
|
+
log.info('Angular project detected')
|
|
418
425
|
return 'build'
|
|
419
426
|
}
|
|
420
427
|
|
|
421
428
|
if (projectType === 'nuxtjs') {
|
|
422
|
-
|
|
429
|
+
log.info('Nuxtjs project detected')
|
|
423
430
|
return 'generate'
|
|
424
431
|
}
|
|
425
432
|
|
|
426
433
|
if (projectType === 'nextjs') {
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
const doContinue = await
|
|
434
|
+
log.info('Nextjs project detected')
|
|
435
|
+
log.warn('Please make sure you have configured static export in your next.config.js: https://nextjs.org/docs/pages/building-your-application/deploying/static-exports')
|
|
436
|
+
log.warn('Please make sure you have the output: \'export\' and distDir: \'dist\' in your next.config.js')
|
|
437
|
+
const doContinue = await confirmC({ message: 'Do you want to continue?' })
|
|
431
438
|
if (!doContinue) {
|
|
432
|
-
|
|
439
|
+
log.error('Aborted')
|
|
433
440
|
program.error('')
|
|
434
441
|
}
|
|
435
442
|
return 'build'
|
|
436
443
|
}
|
|
437
444
|
|
|
438
445
|
if (projectType === 'sveltekit') {
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
const doContinue = await
|
|
446
|
+
log.info('Sveltekit project detected')
|
|
447
|
+
log.warn('Please make sure you have the adapter-static installed: https://kit.svelte.dev/docs/adapter-static')
|
|
448
|
+
log.warn('Please make sure you have the pages: \'dist\' and assets: \'dest\', in your svelte.config.js adaptater')
|
|
449
|
+
const doContinue = await confirmC({ message: 'Do you want to continue?' })
|
|
443
450
|
if (!doContinue) {
|
|
444
|
-
|
|
451
|
+
log.error('Aborted')
|
|
445
452
|
program.error('')
|
|
446
453
|
}
|
|
447
454
|
return 'build'
|
|
@@ -455,63 +462,20 @@ export async function findMainFile() {
|
|
|
455
462
|
const mainRegex = /(main|index)\.(ts|tsx|js|jsx)$/
|
|
456
463
|
// search for main.ts or main.js in local dir and subdirs
|
|
457
464
|
let mainFile = ''
|
|
458
|
-
const pwd =
|
|
465
|
+
const pwd = cwd()
|
|
459
466
|
const pwdL = pwd.split('/').length
|
|
460
467
|
for await (const f of getFiles(pwd)) {
|
|
461
468
|
// find number of folder in path after pwd
|
|
462
469
|
const folders = f.split('/').length - pwdL
|
|
463
470
|
if (folders <= 2 && mainRegex.test(f)) {
|
|
464
471
|
mainFile = f
|
|
465
|
-
|
|
472
|
+
log.info(`Found main file here ${f}`)
|
|
466
473
|
break
|
|
467
474
|
}
|
|
468
475
|
}
|
|
469
476
|
return mainFile
|
|
470
477
|
}
|
|
471
478
|
|
|
472
|
-
interface Config {
|
|
473
|
-
app: {
|
|
474
|
-
appId: string
|
|
475
|
-
appName: string
|
|
476
|
-
webDir: string
|
|
477
|
-
package: {
|
|
478
|
-
version: string
|
|
479
|
-
}
|
|
480
|
-
extConfigFilePath: string
|
|
481
|
-
extConfig: {
|
|
482
|
-
extConfig: object
|
|
483
|
-
plugins: {
|
|
484
|
-
extConfig: object
|
|
485
|
-
CapacitorUpdater: {
|
|
486
|
-
appReadyTimeout?: number
|
|
487
|
-
responseTimeout?: number
|
|
488
|
-
autoDeleteFailed?: boolean
|
|
489
|
-
autoDeletePrevious?: boolean
|
|
490
|
-
autoUpdate?: boolean
|
|
491
|
-
resetWhenUpdate?: boolean
|
|
492
|
-
updateUrl?: string
|
|
493
|
-
statsUrl?: string
|
|
494
|
-
privateKey?: string
|
|
495
|
-
version?: string
|
|
496
|
-
directUpdate?: boolean
|
|
497
|
-
periodCheckDelay?: number
|
|
498
|
-
localS3?: boolean
|
|
499
|
-
localHost?: string
|
|
500
|
-
localWebHost?: string
|
|
501
|
-
localSupa?: string
|
|
502
|
-
localSupaAnon?: string
|
|
503
|
-
allowModifyUrl?: boolean
|
|
504
|
-
defaultChannel?: string
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
server: {
|
|
508
|
-
cleartext: boolean
|
|
509
|
-
url: string
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
|
-
|
|
515
479
|
export async function updateOrCreateVersion(supabase: SupabaseClient<Database>, update: Database['public']['Tables']['app_versions']['Insert']) {
|
|
516
480
|
return supabase.from('app_versions')
|
|
517
481
|
.upsert(update, { onConflict: 'name,app_id' })
|
|
@@ -531,7 +495,7 @@ export async function uploadUrl(supabase: SupabaseClient<Database>, appId: strin
|
|
|
531
495
|
return res.data.url
|
|
532
496
|
}
|
|
533
497
|
catch (error) {
|
|
534
|
-
|
|
498
|
+
log.error(`Cannot get upload url ${formatError(error)}`)
|
|
535
499
|
}
|
|
536
500
|
return ''
|
|
537
501
|
}
|
|
@@ -548,7 +512,7 @@ async function prepareMultipart(supabase: SupabaseClient<Database>, appId: strin
|
|
|
548
512
|
return res.data as any
|
|
549
513
|
}
|
|
550
514
|
catch (error) {
|
|
551
|
-
|
|
515
|
+
log.error(`Cannot get upload url ${formatError(error)}`)
|
|
552
516
|
return null
|
|
553
517
|
}
|
|
554
518
|
}
|
|
@@ -569,7 +533,7 @@ export function zipFileUnix(filePath: string) {
|
|
|
569
533
|
}
|
|
570
534
|
|
|
571
535
|
export async function zipFileWindows(filePath: string): Promise<Buffer> {
|
|
572
|
-
|
|
536
|
+
log.info('Zipping file windows mode')
|
|
573
537
|
const zip = new JSZip()
|
|
574
538
|
|
|
575
539
|
// Helper function to recursively add files and folders to the ZIP archive
|
|
@@ -658,7 +622,7 @@ export async function uploadMultipart(supabase: SupabaseClient<Database>, appId:
|
|
|
658
622
|
return true
|
|
659
623
|
}
|
|
660
624
|
catch (e) {
|
|
661
|
-
|
|
625
|
+
log.error(`Could not upload via multipart ${formatError(e)}`)
|
|
662
626
|
return false
|
|
663
627
|
}
|
|
664
628
|
}
|
|
@@ -674,7 +638,7 @@ export async function deletedFailedVersion(supabase: SupabaseClient<Database>, a
|
|
|
674
638
|
return res.data.status
|
|
675
639
|
}
|
|
676
640
|
catch (error) {
|
|
677
|
-
|
|
641
|
+
log.error(`Cannot delete failed version ${formatError(error)}`)
|
|
678
642
|
return Promise.reject(new Error('Cannot delete failed version'))
|
|
679
643
|
}
|
|
680
644
|
}
|
|
@@ -710,7 +674,7 @@ async function uploadPart(
|
|
|
710
674
|
export async function updateOrCreateChannel(supabase: SupabaseClient<Database>, update: Database['public']['Tables']['channels']['Insert']) {
|
|
711
675
|
// console.log('updateOrCreateChannel', update)
|
|
712
676
|
if (!update.app_id || !update.name || !update.created_by) {
|
|
713
|
-
|
|
677
|
+
log.error('missing app_id, name, or created_by')
|
|
714
678
|
return Promise.reject(new Error('missing app_id, name, or created_by'))
|
|
715
679
|
}
|
|
716
680
|
const { data, error } = await supabase
|
|
@@ -723,19 +687,19 @@ export async function updateOrCreateChannel(supabase: SupabaseClient<Database>,
|
|
|
723
687
|
|
|
724
688
|
if (data && !error) {
|
|
725
689
|
if (data.enable_progressive_deploy) {
|
|
726
|
-
|
|
690
|
+
log.info('Progressive deploy is enabled')
|
|
727
691
|
|
|
728
692
|
if (data.secondaryVersionPercentage !== 1)
|
|
729
|
-
|
|
693
|
+
log.warn('Latest progressive deploy has not finished')
|
|
730
694
|
|
|
731
695
|
update.secondVersion = update.version
|
|
732
696
|
if (!data.secondVersion) {
|
|
733
|
-
|
|
697
|
+
log.error('missing secondVersion')
|
|
734
698
|
return Promise.reject(new Error('missing secondVersion'))
|
|
735
699
|
}
|
|
736
700
|
update.version = data.secondVersion
|
|
737
701
|
update.secondaryVersionPercentage = 0.1
|
|
738
|
-
|
|
702
|
+
log.info('Started new progressive upload!')
|
|
739
703
|
|
|
740
704
|
// update.version = undefined
|
|
741
705
|
}
|
|
@@ -758,8 +722,8 @@ export async function updateOrCreateChannel(supabase: SupabaseClient<Database>,
|
|
|
758
722
|
|
|
759
723
|
export function useLogSnag(): LogSnag {
|
|
760
724
|
const logsnag = new LogSnag({
|
|
761
|
-
token:
|
|
762
|
-
project:
|
|
725
|
+
token: env.CAPGO_LOGSNAG ?? 'c124f5e9d0ce5bdd14bbb48f815d5583',
|
|
726
|
+
project: env.CAPGO_LOGSNAG_PROJECT ?? 'capgo',
|
|
763
727
|
})
|
|
764
728
|
return logsnag
|
|
765
729
|
}
|
|
@@ -769,20 +733,20 @@ export async function getOrganization(supabase: SupabaseClient<Database>, roles:
|
|
|
769
733
|
.rpc('get_orgs_v5')
|
|
770
734
|
|
|
771
735
|
if (orgError) {
|
|
772
|
-
|
|
773
|
-
|
|
736
|
+
log.error('Cannot get the list of organizations - exiting')
|
|
737
|
+
log.error(`Error ${JSON.stringify(orgError)}`)
|
|
774
738
|
program.error('')
|
|
775
739
|
}
|
|
776
740
|
|
|
777
741
|
const adminOrgs = allOrganizations.filter(org => !!roles.find(role => role === org.role))
|
|
778
742
|
|
|
779
743
|
if (adminOrgs.length === 0) {
|
|
780
|
-
|
|
744
|
+
log.error(`Could not get organization with roles: ${roles.join(' or ')} because the user does not have any org`)
|
|
781
745
|
program.error('')
|
|
782
746
|
}
|
|
783
747
|
|
|
784
748
|
const organizationUidRaw = (adminOrgs.length > 1)
|
|
785
|
-
? await
|
|
749
|
+
? await select({
|
|
786
750
|
message: 'Please pick the organization that you want to insert to',
|
|
787
751
|
options: adminOrgs.map((org) => {
|
|
788
752
|
return { value: org.gid, label: org.name }
|
|
@@ -790,15 +754,15 @@ export async function getOrganization(supabase: SupabaseClient<Database>, roles:
|
|
|
790
754
|
})
|
|
791
755
|
: adminOrgs[0].gid
|
|
792
756
|
|
|
793
|
-
if (
|
|
794
|
-
|
|
757
|
+
if (isCancel(organizationUidRaw)) {
|
|
758
|
+
log.error('Canceled organization selection, exiting')
|
|
795
759
|
program.error('')
|
|
796
760
|
}
|
|
797
761
|
|
|
798
762
|
const organizationUid = organizationUidRaw as string
|
|
799
763
|
const organization = allOrganizations.find(org => org.gid === organizationUid)!
|
|
800
764
|
|
|
801
|
-
|
|
765
|
+
log.info(`Using the organization "${organization.name}" as the app owner`)
|
|
802
766
|
return organization
|
|
803
767
|
}
|
|
804
768
|
|
|
@@ -814,7 +778,7 @@ export async function verifyUser(supabase: SupabaseClient<Database>, apikey: str
|
|
|
814
778
|
const userId = (dataUser || '').toString()
|
|
815
779
|
|
|
816
780
|
if (!userId || userIdError) {
|
|
817
|
-
|
|
781
|
+
log.error(`Cannot auth user with apikey`)
|
|
818
782
|
program.error('')
|
|
819
783
|
}
|
|
820
784
|
return userId
|
|
@@ -827,7 +791,7 @@ export async function getOrganizationId(supabase: SupabaseClient<Database>, appI
|
|
|
827
791
|
.single()
|
|
828
792
|
|
|
829
793
|
if (!data || error) {
|
|
830
|
-
|
|
794
|
+
log.error(`Cannot get organization id for app id ${appId}`)
|
|
831
795
|
formatError(error)
|
|
832
796
|
program.error('')
|
|
833
797
|
}
|
|
@@ -843,7 +807,7 @@ export async function requireUpdateMetadata(supabase: SupabaseClient<Database>,
|
|
|
843
807
|
.limit(1)
|
|
844
808
|
|
|
845
809
|
if (error) {
|
|
846
|
-
|
|
810
|
+
log.error(`Cannot check if disableAutoUpdate is required ${formatError(error)}`)
|
|
847
811
|
program.error('')
|
|
848
812
|
}
|
|
849
813
|
|
|
@@ -867,7 +831,7 @@ let pmRunner: PackageManagerRunner = 'npx'
|
|
|
867
831
|
export function getPMAndCommand() {
|
|
868
832
|
if (pmFetched)
|
|
869
833
|
return { pm, command: pmCommand, installCommand: `${pm} ${pmCommand}`, runner: pmRunner }
|
|
870
|
-
const dir = findRootSync(
|
|
834
|
+
const dir = findRootSync(cwd())
|
|
871
835
|
pm = findPackageManagerType(dir.rootDir, 'npm')
|
|
872
836
|
pmCommand = findInstallCommand(pm)
|
|
873
837
|
pmFetched = true
|
|
@@ -891,42 +855,42 @@ function readDirRecursively(dir: string): string[] {
|
|
|
891
855
|
}
|
|
892
856
|
|
|
893
857
|
export async function getLocalDepenencies() {
|
|
894
|
-
const dir = findRootSync(
|
|
895
|
-
const packageJsonPath = join(
|
|
858
|
+
const dir = findRootSync(cwd())
|
|
859
|
+
const packageJsonPath = join(cwd(), 'package.json')
|
|
896
860
|
|
|
897
861
|
if (!existsSync(packageJsonPath)) {
|
|
898
|
-
|
|
862
|
+
log.error('Missing package.json, you need to be in a capacitor project')
|
|
899
863
|
program.error('')
|
|
900
864
|
}
|
|
901
865
|
|
|
902
866
|
let packageJson
|
|
903
867
|
try {
|
|
904
|
-
packageJson =
|
|
868
|
+
packageJson = await readPackageJson()
|
|
905
869
|
}
|
|
906
870
|
catch (err) {
|
|
907
|
-
|
|
871
|
+
log.error('Invalid package.json, JSON parsing failed')
|
|
908
872
|
console.error('json parse error: ', err)
|
|
909
873
|
program.error('')
|
|
910
874
|
}
|
|
911
875
|
|
|
912
876
|
const { dependencies } = packageJson
|
|
913
877
|
if (!dependencies) {
|
|
914
|
-
|
|
878
|
+
log.error('Missing dependencies section in package.json')
|
|
915
879
|
program.error('')
|
|
916
880
|
}
|
|
917
881
|
|
|
918
882
|
for (const [key, value] of Object.entries(dependencies)) {
|
|
919
883
|
if (typeof value !== 'string') {
|
|
920
|
-
|
|
884
|
+
log.error(`Invalid dependency ${key}: ${value}, expected string, got ${typeof value}`)
|
|
921
885
|
program.error('')
|
|
922
886
|
}
|
|
923
887
|
}
|
|
924
888
|
|
|
925
|
-
const nodeModulesPath = join(
|
|
889
|
+
const nodeModulesPath = join(cwd(), 'node_modules')
|
|
926
890
|
if (!existsSync(nodeModulesPath)) {
|
|
927
891
|
const pm = findPackageManagerType(dir.rootDir, 'npm')
|
|
928
892
|
const installCmd = findInstallCommand(pm)
|
|
929
|
-
|
|
893
|
+
log.error(`Missing node_modules folder, please run ${pm} ${installCmd}`)
|
|
930
894
|
program.error('')
|
|
931
895
|
}
|
|
932
896
|
|
|
@@ -941,7 +905,7 @@ export async function getLocalDepenencies() {
|
|
|
941
905
|
anyInvalid = true
|
|
942
906
|
const pm = findPackageManagerType(dir.rootDir, 'npm')
|
|
943
907
|
const installCmd = findInstallCommand(pm)
|
|
944
|
-
|
|
908
|
+
log.error(`Missing dependency ${key}, please run ${pm} ${installCmd}`)
|
|
945
909
|
return { name: key, version: value }
|
|
946
910
|
}
|
|
947
911
|
|
|
@@ -951,7 +915,7 @@ export async function getLocalDepenencies() {
|
|
|
951
915
|
hasNativeFiles = files.some(fileName => nativeFileRegex.test(fileName))
|
|
952
916
|
}
|
|
953
917
|
catch (error) {
|
|
954
|
-
|
|
918
|
+
log.error(`Error reading node_modules files for ${key} package`)
|
|
955
919
|
console.error(error)
|
|
956
920
|
program.error('')
|
|
957
921
|
}
|
|
@@ -969,25 +933,30 @@ export async function getLocalDepenencies() {
|
|
|
969
933
|
return dependenciesObject as { name: string, version: string, native: boolean }[]
|
|
970
934
|
}
|
|
971
935
|
|
|
936
|
+
interface ChannelChecksum {
|
|
937
|
+
version: {
|
|
938
|
+
checksum: string
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
|
|
972
942
|
export async function getRemoteChecksums(supabase: SupabaseClient<Database>, appId: string, channel: string) {
|
|
973
943
|
const { data, error } = await supabase
|
|
974
944
|
.from('channels')
|
|
975
|
-
.select(`version
|
|
976
|
-
checksum
|
|
977
|
-
)`)
|
|
945
|
+
.select(`version(checksum)`)
|
|
978
946
|
.eq('name', channel)
|
|
979
947
|
.eq('app_id', appId)
|
|
980
948
|
.single()
|
|
949
|
+
const channelData = data as any as ChannelChecksum
|
|
981
950
|
|
|
982
951
|
if (error
|
|
983
|
-
||
|
|
984
|
-
|| !
|
|
985
|
-
|| !
|
|
952
|
+
|| channelData === null
|
|
953
|
+
|| !channelData.version
|
|
954
|
+
|| !channelData.version.checksum
|
|
986
955
|
) {
|
|
987
956
|
return null
|
|
988
957
|
}
|
|
989
958
|
|
|
990
|
-
return
|
|
959
|
+
return channelData.version.checksum
|
|
991
960
|
}
|
|
992
961
|
|
|
993
962
|
export async function getRemoteDepenencies(supabase: SupabaseClient<Database>, appId: string, channel: string) {
|
|
@@ -1001,7 +970,7 @@ export async function getRemoteDepenencies(supabase: SupabaseClient<Database>, a
|
|
|
1001
970
|
.single()
|
|
1002
971
|
|
|
1003
972
|
if (error) {
|
|
1004
|
-
|
|
973
|
+
log.error(`Error fetching native packages: ${error.message}`)
|
|
1005
974
|
program.error('')
|
|
1006
975
|
}
|
|
1007
976
|
|
|
@@ -1011,30 +980,30 @@ export async function getRemoteDepenencies(supabase: SupabaseClient<Database>, a
|
|
|
1011
980
|
}
|
|
1012
981
|
catch (err) {
|
|
1013
982
|
// If we do not do this we will get an unreadable
|
|
1014
|
-
|
|
983
|
+
log.error(`Error parsing native packages`)
|
|
1015
984
|
program.error('')
|
|
1016
985
|
}
|
|
1017
986
|
|
|
1018
987
|
if (!castedRemoteNativePackages) {
|
|
1019
|
-
|
|
988
|
+
log.error(`Error parsing native packages, perhaps the metadata does not exist?`)
|
|
1020
989
|
program.error('')
|
|
1021
990
|
}
|
|
1022
991
|
|
|
1023
992
|
// Check types
|
|
1024
993
|
castedRemoteNativePackages.forEach((data: any) => {
|
|
1025
994
|
if (typeof data !== 'object') {
|
|
1026
|
-
|
|
995
|
+
log.error(`Invalid remote native package data: ${data}, expected object, got ${typeof data}`)
|
|
1027
996
|
program.error('')
|
|
1028
997
|
}
|
|
1029
998
|
|
|
1030
999
|
const { name, version } = data
|
|
1031
1000
|
if (!name || typeof name !== 'string') {
|
|
1032
|
-
|
|
1001
|
+
log.error(`Invalid remote native package name: ${name}, expected string, got ${typeof name}`)
|
|
1033
1002
|
program.error('')
|
|
1034
1003
|
}
|
|
1035
1004
|
|
|
1036
1005
|
if (!version || typeof version !== 'string') {
|
|
1037
|
-
|
|
1006
|
+
log.error(`Invalid remote native package version: ${version}, expected string, got ${typeof version}`)
|
|
1038
1007
|
program.error('')
|
|
1039
1008
|
}
|
|
1040
1009
|
})
|
|
@@ -1046,13 +1015,13 @@ export async function getRemoteDepenencies(supabase: SupabaseClient<Database>, a
|
|
|
1046
1015
|
}
|
|
1047
1016
|
|
|
1048
1017
|
export async function checkChecksum(supabase: SupabaseClient<Database>, appId: string, channel: string, currentChecksum: string) {
|
|
1049
|
-
const s =
|
|
1018
|
+
const s = spinner()
|
|
1050
1019
|
s.start(`Checking bundle checksum compatibility with channel ${channel}`)
|
|
1051
1020
|
const remoteChecksum = await getRemoteChecksums(supabase, appId, channel)
|
|
1052
1021
|
|
|
1053
1022
|
if (remoteChecksum && remoteChecksum === currentChecksum) {
|
|
1054
1023
|
// cannot upload the same bundle
|
|
1055
|
-
|
|
1024
|
+
log.error(`Cannot upload the same bundle content.\nCurrent bundle checksum matches remote bundle for channel ${channel}\nDid you builded your app before uploading ?`)
|
|
1056
1025
|
program.error('')
|
|
1057
1026
|
}
|
|
1058
1027
|
s.stop(`Checksum compatible with ${channel} channel`)
|