@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.
- package/dist/index.js +103 -103
- package/package.json +1 -1
- package/.github/FUNDING.yml +0 -1
- package/.github/workflows/autofix.yml +0 -25
- package/.github/workflows/build.yml +0 -46
- package/.github/workflows/bump_version.yml +0 -56
- package/.github/workflows/check_posix_paths.yml +0 -229
- package/.github/workflows/test.yml +0 -30
- package/.prettierignore +0 -6
- package/.vscode/launch.json +0 -23
- package/.vscode/settings.json +0 -46
- package/.vscode/tasks.json +0 -42
- package/CHANGELOG.md +0 -3392
- package/build.mjs +0 -21
- package/bun.lockb +0 -0
- package/bunfig.toml +0 -2
- package/capacitor.config.ts +0 -33
- package/crypto_explained.png +0 -0
- package/eslint.config.js +0 -10
- package/renovate.json +0 -23
- package/src/api/app.ts +0 -55
- package/src/api/channels.ts +0 -163
- package/src/api/crypto.ts +0 -116
- package/src/api/devices_override.ts +0 -41
- package/src/api/update.ts +0 -13
- package/src/api/versions.ts +0 -101
- package/src/app/add.ts +0 -157
- package/src/app/debug.ts +0 -258
- package/src/app/delete.ts +0 -110
- package/src/app/info.ts +0 -99
- package/src/app/list.ts +0 -67
- package/src/app/set.ts +0 -96
- package/src/bundle/check.ts +0 -42
- package/src/bundle/cleanup.ts +0 -123
- package/src/bundle/compatibility.ts +0 -70
- package/src/bundle/decrypt.ts +0 -54
- package/src/bundle/delete.ts +0 -52
- package/src/bundle/encrypt.ts +0 -60
- package/src/bundle/list.ts +0 -42
- package/src/bundle/unlink.ts +0 -88
- package/src/bundle/upload.ts +0 -552
- package/src/bundle/zip.ts +0 -145
- package/src/channel/add.ts +0 -80
- package/src/channel/currentBundle.ts +0 -72
- package/src/channel/delete.ts +0 -57
- package/src/channel/list.ts +0 -49
- package/src/channel/set.ts +0 -179
- package/src/config/index.ts +0 -156
- package/src/index.ts +0 -310
- package/src/init.ts +0 -495
- package/src/key.ts +0 -135
- package/src/login.ts +0 -70
- package/src/types/capacitor__cli.d.ts +0 -6
- package/src/types/supabase.types.ts +0 -2123
- package/src/user/account.ts +0 -11
- package/src/utils.ts +0 -1076
- package/test/VerifyZip.java +0 -83
- package/test/check-posix-paths.js +0 -21
- package/test/chunk_convert.ts +0 -28
- package/test/data.ts +0 -18769
- package/test/test_headers_rls.ts +0 -24
- package/test/test_semver.ts +0 -13
- package/test/test_upload/app.js +0 -3
- package/test/test_upload/assets/check-posix-paths.js +0 -21
- package/test/test_upload/index.html +0 -0
- package/test/test_zip_swift/Package.resolved +0 -24
- package/test/test_zip_swift/Package.swift +0 -29
- package/test/test_zip_swift/Sources/main.swift +0 -80
- package/tsconfig.json +0 -39
package/src/init.ts
DELETED
|
@@ -1,495 +0,0 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from 'node:fs'
|
|
2
|
-
import type { ExecSyncOptions } from 'node:child_process'
|
|
3
|
-
import { execSync, spawnSync } from 'node:child_process'
|
|
4
|
-
import { exit } from 'node:process'
|
|
5
|
-
import { join } from 'node:path'
|
|
6
|
-
import * as p from '@clack/prompts'
|
|
7
|
-
import type LogSnag from 'logsnag'
|
|
8
|
-
import semver from 'semver'
|
|
9
|
-
import tmp from 'tmp'
|
|
10
|
-
import { markSnag, waitLog } from './app/debug'
|
|
11
|
-
import { createKey } from './key'
|
|
12
|
-
import { addChannel } from './channel/add'
|
|
13
|
-
import { uploadBundle } from './bundle/upload'
|
|
14
|
-
import { doLoginExists, login } from './login'
|
|
15
|
-
import { addAppInternal } from './app/add'
|
|
16
|
-
import { checkLatest } from './api/update'
|
|
17
|
-
import type { Options } from './api/app'
|
|
18
|
-
import type { Organization } from './utils'
|
|
19
|
-
import { convertAppName, createSupabaseClient, findBuildCommandForProjectType, findMainFile, findMainFileForProjectType, findProjectType, findSavedKey, getConfig, getOrganization, getPMAndCommand, readPackageJson, useLogSnag, verifyUser } from './utils'
|
|
20
|
-
|
|
21
|
-
interface SuperOptions extends Options {
|
|
22
|
-
local: boolean
|
|
23
|
-
}
|
|
24
|
-
const importInject = 'import { CapacitorUpdater } from \'@capgo/capacitor-updater\''
|
|
25
|
-
const codeInject = 'CapacitorUpdater.notifyAppReady()'
|
|
26
|
-
// create regex to find line who start by 'import ' and end by ' from '
|
|
27
|
-
const regexImport = /import.*from.*/g
|
|
28
|
-
const defaultChannel = 'production'
|
|
29
|
-
const execOption = { stdio: 'pipe' }
|
|
30
|
-
|
|
31
|
-
let tmpObject: tmp.FileResult['name'] | undefined
|
|
32
|
-
|
|
33
|
-
function readTmpObj() {
|
|
34
|
-
if (!tmpObject) {
|
|
35
|
-
tmpObject = readdirSync(tmp.tmpdir)
|
|
36
|
-
.map((name) => { return { name, full: `${tmp.tmpdir}/${name}` } })
|
|
37
|
-
.find(obj => obj.name.startsWith('capgocli'))?.full
|
|
38
|
-
?? tmp.fileSync({ prefix: 'capgocli' }).name
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function markStepDone(step: number) {
|
|
43
|
-
try {
|
|
44
|
-
readTmpObj()
|
|
45
|
-
writeFileSync(tmpObject!, JSON.stringify({ step_done: step }))
|
|
46
|
-
}
|
|
47
|
-
catch (err) {
|
|
48
|
-
p.log.error(`Cannot mark step as done in the CLI, error:\n${err}`)
|
|
49
|
-
p.log.warn('Onboarding will continue but please report it to the capgo team!')
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
async function readStepsDone(orgId: string, snag: LogSnag): Promise<number | undefined> {
|
|
54
|
-
try {
|
|
55
|
-
readTmpObj()
|
|
56
|
-
const rawData = readFileSync(tmpObject!, 'utf-8')
|
|
57
|
-
if (!rawData || rawData.length === 0)
|
|
58
|
-
return undefined
|
|
59
|
-
|
|
60
|
-
const { step_done } = JSON.parse(rawData)
|
|
61
|
-
p.log.info(`You have already got to the step ${step_done}/10 in the previous session`)
|
|
62
|
-
const skipSteps = await p.confirm({ message: 'Would you like to continue from where you left off?' })
|
|
63
|
-
await cancelCommand(skipSteps, orgId, snag)
|
|
64
|
-
if (skipSteps)
|
|
65
|
-
return step_done
|
|
66
|
-
return undefined
|
|
67
|
-
}
|
|
68
|
-
catch (err) {
|
|
69
|
-
p.log.error(`Cannot read which steps have been compleated, error:\n${err}`)
|
|
70
|
-
p.log.warn('Onboarding will continue but please report it to the capgo team!')
|
|
71
|
-
return undefined
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function cleanupStepsDone() {
|
|
76
|
-
if (!tmpObject) {
|
|
77
|
-
return
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
try {
|
|
81
|
-
rmSync(tmpObject)
|
|
82
|
-
}
|
|
83
|
-
catch (err) {
|
|
84
|
-
p.log.error(`Cannot delete the tmp steps file.\nError: ${err}`)
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
async function cancelCommand(command: boolean | symbol, orgId: string, snag: LogSnag) {
|
|
89
|
-
if (p.isCancel(command)) {
|
|
90
|
-
await markSnag('onboarding-v2', orgId, snag, 'canceled', '🤷')
|
|
91
|
-
exit()
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
async function markStep(orgId: string, snag: LogSnag, step: number | string) {
|
|
96
|
-
return markSnag('onboarding-v2', orgId, snag, `onboarding-step-${step}`)
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
async function step2(organization: Organization, snag: LogSnag, appId: string, options: SuperOptions) {
|
|
100
|
-
const pm = getPMAndCommand()
|
|
101
|
-
const doAdd = await p.confirm({ message: `Add ${appId} in Capgo?` })
|
|
102
|
-
await cancelCommand(doAdd, organization.gid, snag)
|
|
103
|
-
if (doAdd) {
|
|
104
|
-
const s = p.spinner()
|
|
105
|
-
s.start(`Running: ${pm.runner} @capgo/cli@latest app add ${appId}`)
|
|
106
|
-
const addRes = await addAppInternal(appId, options, organization, false)
|
|
107
|
-
if (!addRes)
|
|
108
|
-
s.stop(`App already add ✅`)
|
|
109
|
-
else
|
|
110
|
-
s.stop(`App add Done ✅`)
|
|
111
|
-
}
|
|
112
|
-
else {
|
|
113
|
-
p.log.info(`If you change your mind, run it for yourself with: "${pm.runner} @capgo/cli@latest app add ${appId}"`)
|
|
114
|
-
}
|
|
115
|
-
await markStep(organization.gid, snag, 2)
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
async function step3(orgId: string, snag: LogSnag, apikey: string, appId: string) {
|
|
119
|
-
const pm = getPMAndCommand()
|
|
120
|
-
const doChannel = await p.confirm({ message: `Create default channel ${defaultChannel} for ${appId} in Capgo?` })
|
|
121
|
-
await cancelCommand(doChannel, orgId, snag)
|
|
122
|
-
if (doChannel) {
|
|
123
|
-
const s = p.spinner()
|
|
124
|
-
// create production channel public
|
|
125
|
-
s.start(`Running: ${pm.runner} @capgo/cli@latest channel add ${defaultChannel} ${appId} --default`)
|
|
126
|
-
const addChannelRes = await addChannel(defaultChannel, appId, {
|
|
127
|
-
default: true,
|
|
128
|
-
apikey,
|
|
129
|
-
}, false)
|
|
130
|
-
if (!addChannelRes)
|
|
131
|
-
s.stop(`Channel already added ✅`)
|
|
132
|
-
else
|
|
133
|
-
s.stop(`Channel add Done ✅`)
|
|
134
|
-
}
|
|
135
|
-
else {
|
|
136
|
-
p.log.info(`If you change your mind, run it for yourself with: "${pm.runner} @capgo/cli@latest channel add ${defaultChannel} ${appId} --default"`)
|
|
137
|
-
}
|
|
138
|
-
await markStep(orgId, snag, 3)
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
const urlMigrateV6 = 'https://capacitorjs.com/docs/updating/6-0'
|
|
142
|
-
const urlMigrateV5 = 'https://capacitorjs.com/docs/updating/5-0'
|
|
143
|
-
async function step4(orgId: string, snag: LogSnag, apikey: string, appId: string) {
|
|
144
|
-
const pm = getPMAndCommand()
|
|
145
|
-
const doInstall = await p.confirm({ message: `Automatic Install "@capgo/capacitor-updater" dependency in ${appId}?` })
|
|
146
|
-
await cancelCommand(doInstall, orgId, snag)
|
|
147
|
-
if (doInstall) {
|
|
148
|
-
const s = p.spinner()
|
|
149
|
-
s.start(`Checking if @capgo/capacitor-updater is installed`)
|
|
150
|
-
let versionToInstall = 'latest'
|
|
151
|
-
const pack = await readPackageJson()
|
|
152
|
-
let coreVersion = pack.dependencies['@capacitor/core'] || pack.devDependencies['@capacitor/core']
|
|
153
|
-
coreVersion = coreVersion?.replace('^', '').replace('~', '')
|
|
154
|
-
if (!coreVersion) {
|
|
155
|
-
s.stop('Error')
|
|
156
|
-
p.log.warn(`Cannot find @capacitor/core in package.json, please run \`capgo init\` in a capacitor project`)
|
|
157
|
-
p.outro(`Bye 👋`)
|
|
158
|
-
exit()
|
|
159
|
-
}
|
|
160
|
-
else if (semver.lt(coreVersion, '5.0.0')) {
|
|
161
|
-
s.stop('Error')
|
|
162
|
-
p.log.warn(`@capacitor/core version is ${coreVersion}, please update to Capacitor v5 first: ${urlMigrateV5}`)
|
|
163
|
-
p.outro(`Bye 👋`)
|
|
164
|
-
exit()
|
|
165
|
-
}
|
|
166
|
-
else if (semver.lt(coreVersion, '6.0.0')) {
|
|
167
|
-
s.stop(`@capacitor/core version is ${coreVersion}, please update to Capacitor v6: ${urlMigrateV6} to access the best features of Capgo`)
|
|
168
|
-
versionToInstall = '^5.0.0'
|
|
169
|
-
}
|
|
170
|
-
if (pm.pm === 'unknown') {
|
|
171
|
-
s.stop('Error')
|
|
172
|
-
p.log.warn(`Cannot reconize package manager, please run \`capgo init\` in a capacitor project with npm, pnpm, bun or yarn`)
|
|
173
|
-
p.outro(`Bye 👋`)
|
|
174
|
-
exit()
|
|
175
|
-
}
|
|
176
|
-
// // use pm to install capgo
|
|
177
|
-
// // run command pm install @capgo/capacitor-updater@latest
|
|
178
|
-
// check if capgo is already installed in package.json
|
|
179
|
-
if (pack.dependencies['@capgo/capacitor-updater']) {
|
|
180
|
-
s.stop(`Capgo already installed ✅`)
|
|
181
|
-
}
|
|
182
|
-
else {
|
|
183
|
-
await execSync(`${pm.installCommand} @capgo/capacitor-updater@${versionToInstall}`, execOption as ExecSyncOptions)
|
|
184
|
-
s.stop(`Install Done ✅`)
|
|
185
|
-
}
|
|
186
|
-
}
|
|
187
|
-
else {
|
|
188
|
-
p.log.info(`If you change your mind, run it for yourself with: "${pm.installCommand} @capgo/capacitor-updater@latest"`)
|
|
189
|
-
}
|
|
190
|
-
await markStep(orgId, snag, 4)
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
async function step5(orgId: string, snag: LogSnag, apikey: string, appId: string) {
|
|
194
|
-
const doAddCode = await p.confirm({ message: `Automatic Add "${codeInject}" code and import in ${appId}?` })
|
|
195
|
-
await cancelCommand(doAddCode, orgId, snag)
|
|
196
|
-
|
|
197
|
-
if (doAddCode) {
|
|
198
|
-
const s = p.spinner()
|
|
199
|
-
s.start(`Adding @capacitor-updater to your main file`)
|
|
200
|
-
|
|
201
|
-
const projectType = await findProjectType()
|
|
202
|
-
if (projectType === 'nuxtjs-js' || projectType === 'nuxtjs-ts') {
|
|
203
|
-
// Nuxt.js specific logic
|
|
204
|
-
const nuxtDir = join('plugins')
|
|
205
|
-
if (!existsSync(nuxtDir)) {
|
|
206
|
-
mkdirSync(nuxtDir, { recursive: true })
|
|
207
|
-
}
|
|
208
|
-
let nuxtFilePath
|
|
209
|
-
if (projectType === 'nuxtjs-ts') {
|
|
210
|
-
nuxtFilePath = join(nuxtDir, 'capacitorUpdater.client.ts')
|
|
211
|
-
}
|
|
212
|
-
else {
|
|
213
|
-
nuxtFilePath = join(nuxtDir, 'capacitorUpdater.client.js')
|
|
214
|
-
}
|
|
215
|
-
const nuxtFileContent = `
|
|
216
|
-
import { CapacitorUpdater } from '@capgo/capacitor-updater'
|
|
217
|
-
|
|
218
|
-
export default defineNuxtPlugin(() => {
|
|
219
|
-
CapacitorUpdater.notifyAppReady()
|
|
220
|
-
})
|
|
221
|
-
`
|
|
222
|
-
if (existsSync(nuxtFilePath)) {
|
|
223
|
-
const currentContent = readFileSync(nuxtFilePath, 'utf8')
|
|
224
|
-
if (currentContent.includes('CapacitorUpdater.notifyAppReady()')) {
|
|
225
|
-
s.stop('Code already added to capacitorUpdater.client.ts file inside plugins directory ✅')
|
|
226
|
-
p.log.info('Plugins directory and capacitorUpdater.client.ts file already exist with required code')
|
|
227
|
-
}
|
|
228
|
-
else {
|
|
229
|
-
writeFileSync(nuxtFilePath, nuxtFileContent, 'utf8')
|
|
230
|
-
s.stop('Code added to capacitorUpdater.client.ts file inside plugins directory ✅')
|
|
231
|
-
p.log.info('Updated capacitorUpdater.client.ts file with required code')
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
else {
|
|
235
|
-
writeFileSync(nuxtFilePath, nuxtFileContent, 'utf8')
|
|
236
|
-
s.stop('Code added to capacitorUpdater.client.ts file inside plugins directory ✅')
|
|
237
|
-
p.log.info('Created plugins directory and capacitorUpdater.client.ts file')
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
else {
|
|
241
|
-
// Handle other project types
|
|
242
|
-
let mainFilePath
|
|
243
|
-
if (projectType === 'unknown') {
|
|
244
|
-
mainFilePath = await findMainFile()
|
|
245
|
-
}
|
|
246
|
-
else {
|
|
247
|
-
const isTypeScript = projectType.endsWith('-ts')
|
|
248
|
-
mainFilePath = await findMainFileForProjectType(projectType, isTypeScript)
|
|
249
|
-
}
|
|
250
|
-
|
|
251
|
-
if (!mainFilePath) {
|
|
252
|
-
s.stop('Error')
|
|
253
|
-
if (projectType === 'nextjs-js' || projectType === 'nextjs-ts') {
|
|
254
|
-
p.log.warn(`You might not be using app router configuration or the latest version of Next.js`)
|
|
255
|
-
}
|
|
256
|
-
else {
|
|
257
|
-
p.log.warn(`Cannot find the latest version of ${projectType}, you might need to upgrade to the latest version of ${projectType}`)
|
|
258
|
-
}
|
|
259
|
-
p.outro(`Bye 👋`)
|
|
260
|
-
exit()
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
// Open main file and inject codeInject
|
|
264
|
-
const mainFile = readFileSync(mainFilePath, 'utf8')
|
|
265
|
-
const mainFileContent = mainFile.toString()
|
|
266
|
-
const matches = mainFileContent.match(regexImport)
|
|
267
|
-
const last = matches?.pop()
|
|
268
|
-
|
|
269
|
-
if (!last) {
|
|
270
|
-
s.stop('Error')
|
|
271
|
-
p.log.warn(`Cannot find import line in main file, use manual installation: https://capgo.app/docs/plugin/installation/`)
|
|
272
|
-
p.outro(`Bye 👋`)
|
|
273
|
-
exit()
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
if (mainFileContent.includes(codeInject)) {
|
|
277
|
-
s.stop(`Code already added to ${mainFilePath} ✅`)
|
|
278
|
-
}
|
|
279
|
-
else {
|
|
280
|
-
const newMainFileContent = mainFileContent.replace(last, `${last}\n${importInject};\n\n${codeInject};\n`)
|
|
281
|
-
writeFileSync(mainFilePath, newMainFileContent, 'utf8')
|
|
282
|
-
s.stop(`Code added to ${mainFilePath} ✅`)
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
await markStep(orgId, snag, 5)
|
|
287
|
-
}
|
|
288
|
-
else {
|
|
289
|
-
p.log.info(`Add to your main file the following code:\n\n${importInject};\n\n${codeInject};\n`)
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
async function step6(orgId: string, snag: LogSnag, apikey: string, appId: string) {
|
|
294
|
-
const pm = getPMAndCommand()
|
|
295
|
-
const doEncrypt = await p.confirm({ message: `Automatic configure end-to-end encryption in ${appId} updates?` })
|
|
296
|
-
await cancelCommand(doEncrypt, orgId, snag)
|
|
297
|
-
if (doEncrypt) {
|
|
298
|
-
const s = p.spinner()
|
|
299
|
-
s.start(`Running: ${pm.runner} @capgo/cli@latest key create`)
|
|
300
|
-
const keyRes = await createKey({ force: true }, false)
|
|
301
|
-
if (!keyRes) {
|
|
302
|
-
s.stop('Error')
|
|
303
|
-
p.log.warn(`Cannot create key ❌`)
|
|
304
|
-
p.outro(`Bye 👋`)
|
|
305
|
-
exit(1)
|
|
306
|
-
}
|
|
307
|
-
else {
|
|
308
|
-
s.stop(`key created 🔑`)
|
|
309
|
-
}
|
|
310
|
-
markSnag('onboarding-v2', orgId, snag, 'Use encryption')
|
|
311
|
-
}
|
|
312
|
-
await markStep(orgId, snag, 6)
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
async function step7(orgId: string, snag: LogSnag, apikey: string, appId: string) {
|
|
316
|
-
const pm = getPMAndCommand()
|
|
317
|
-
const doBuild = await p.confirm({ message: `Automatic build ${appId} with "${pm.pm} run build" ?` })
|
|
318
|
-
await cancelCommand(doBuild, orgId, snag)
|
|
319
|
-
if (doBuild) {
|
|
320
|
-
const s = p.spinner()
|
|
321
|
-
const projectType = await findProjectType()
|
|
322
|
-
const buildCommand = await findBuildCommandForProjectType(projectType)
|
|
323
|
-
s.start(`Running: ${pm.pm} run ${buildCommand} && ${pm.runner} cap sync`)
|
|
324
|
-
const pack = await readPackageJson()
|
|
325
|
-
// check in script build exist
|
|
326
|
-
if (!pack.scripts[buildCommand]) {
|
|
327
|
-
s.stop('Error')
|
|
328
|
-
p.log.warn(`Cannot find ${buildCommand} script in package.json, please add it and run \`capgo init\` again`)
|
|
329
|
-
p.outro(`Bye 👋`)
|
|
330
|
-
exit()
|
|
331
|
-
}
|
|
332
|
-
execSync(`${pm.pm} run ${buildCommand} && ${pm.runner} cap sync`, execOption as ExecSyncOptions)
|
|
333
|
-
s.stop(`Build & Sync Done ✅`)
|
|
334
|
-
}
|
|
335
|
-
else {
|
|
336
|
-
p.log.info(`Build yourself with command: ${pm.pm} run build && ${pm.runner} cap sync`)
|
|
337
|
-
}
|
|
338
|
-
await markStep(orgId, snag, 7)
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
async function step8(orgId: string, snag: LogSnag, apikey: string, appId: string) {
|
|
342
|
-
const pm = getPMAndCommand()
|
|
343
|
-
const doBundle = await p.confirm({ message: `Automatic upload ${appId} bundle to Capgo?` })
|
|
344
|
-
await cancelCommand(doBundle, orgId, snag)
|
|
345
|
-
if (doBundle) {
|
|
346
|
-
const s = p.spinner()
|
|
347
|
-
s.start(`Running: ${pm.runner} @capgo/cli@latest bundle upload`)
|
|
348
|
-
const uploadRes = await uploadBundle(appId, {
|
|
349
|
-
channel: defaultChannel,
|
|
350
|
-
apikey,
|
|
351
|
-
}, false)
|
|
352
|
-
if (!uploadRes) {
|
|
353
|
-
s.stop('Error')
|
|
354
|
-
p.log.warn(`Upload failed ❌`)
|
|
355
|
-
p.outro(`Bye 👋`)
|
|
356
|
-
exit()
|
|
357
|
-
}
|
|
358
|
-
else {
|
|
359
|
-
s.stop(`Upload Done ✅`)
|
|
360
|
-
}
|
|
361
|
-
}
|
|
362
|
-
else {
|
|
363
|
-
p.log.info(`Upload yourself with command: ${pm.runner} @capgo/cli@latest bundle upload`)
|
|
364
|
-
}
|
|
365
|
-
await markStep(orgId, snag, 8)
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
async function step9(orgId: string, snag: LogSnag) {
|
|
369
|
-
const pm = getPMAndCommand()
|
|
370
|
-
const doRun = await p.confirm({ message: `Run in device now ?` })
|
|
371
|
-
await cancelCommand(doRun, orgId, snag)
|
|
372
|
-
if (doRun) {
|
|
373
|
-
const plaformType = await p.select({
|
|
374
|
-
message: 'Pick a platform to run your app',
|
|
375
|
-
options: [
|
|
376
|
-
{ value: 'ios', label: 'IOS' },
|
|
377
|
-
{ value: 'android', label: 'Android' },
|
|
378
|
-
],
|
|
379
|
-
})
|
|
380
|
-
if (p.isCancel(plaformType)) {
|
|
381
|
-
p.outro(`Bye 👋`)
|
|
382
|
-
exit()
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
const platform = plaformType as 'ios' | 'android'
|
|
386
|
-
const s = p.spinner()
|
|
387
|
-
s.start(`Running: ${pm.runner} cap run ${platform}`)
|
|
388
|
-
await spawnSync(pm.runner, ['cap', 'run', platform], { stdio: 'inherit' })
|
|
389
|
-
s.stop(`Started Done ✅`)
|
|
390
|
-
}
|
|
391
|
-
else {
|
|
392
|
-
p.log.info(`If you change your mind, run it for yourself with: ${pm.runner} cap run <ios|android>`)
|
|
393
|
-
}
|
|
394
|
-
await markStep(orgId, snag, 9)
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
async function step10(orgId: string, snag: LogSnag, apikey: string, appId: string) {
|
|
398
|
-
const doRun = await p.confirm({ message: `Automatic check if update working in device ?` })
|
|
399
|
-
await cancelCommand(doRun, orgId, snag)
|
|
400
|
-
if (doRun) {
|
|
401
|
-
p.log.info(`Wait logs sent to Capgo from ${appId} device, Please open your app 💪`)
|
|
402
|
-
await waitLog('onboarding-v2', apikey, appId, snag, orgId)
|
|
403
|
-
}
|
|
404
|
-
else {
|
|
405
|
-
const appIdUrl = convertAppName(appId)
|
|
406
|
-
p.log.info(`Check logs in https://web.capgo.app/app/p/${appIdUrl}/logs to see if update works.`)
|
|
407
|
-
}
|
|
408
|
-
await markStep(orgId, snag, 10)
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
export async function initApp(apikeyCommand: string, appId: string, options: SuperOptions) {
|
|
412
|
-
const pm = getPMAndCommand()
|
|
413
|
-
p.intro(`Capgo onboarding 🛫`)
|
|
414
|
-
await checkLatest()
|
|
415
|
-
const snag = useLogSnag()
|
|
416
|
-
const extConfig = await getConfig()
|
|
417
|
-
appId = appId || extConfig?.config?.appId
|
|
418
|
-
const apikey = apikeyCommand || findSavedKey()
|
|
419
|
-
|
|
420
|
-
const log = p.spinner()
|
|
421
|
-
if (!doLoginExists() || apikeyCommand) {
|
|
422
|
-
log.start(`Running: ${pm.runner} @capgo/cli@latest login ***`)
|
|
423
|
-
await login(apikey, options, false)
|
|
424
|
-
log.stop('Login Done ✅')
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
const supabase = await createSupabaseClient(apikey)
|
|
428
|
-
await verifyUser(supabase, apikey, ['upload', 'all', 'read', 'write'])
|
|
429
|
-
|
|
430
|
-
const organization = await getOrganization(supabase, ['admin', 'super_admin'])
|
|
431
|
-
const orgId = organization.gid
|
|
432
|
-
|
|
433
|
-
const stepToSkip = await readStepsDone(orgId, snag) ?? 0
|
|
434
|
-
|
|
435
|
-
try {
|
|
436
|
-
if (stepToSkip < 1)
|
|
437
|
-
await markStep(orgId, snag, 1)
|
|
438
|
-
|
|
439
|
-
if (stepToSkip < 2) {
|
|
440
|
-
await step2(organization, snag, appId, options)
|
|
441
|
-
markStepDone(2)
|
|
442
|
-
}
|
|
443
|
-
|
|
444
|
-
if (stepToSkip < 3) {
|
|
445
|
-
await step3(orgId, snag, apikey, appId)
|
|
446
|
-
markStepDone(3)
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
if (stepToSkip < 4) {
|
|
450
|
-
await step4(orgId, snag, apikey, appId)
|
|
451
|
-
markStepDone(4)
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
if (stepToSkip < 5) {
|
|
455
|
-
await step5(orgId, snag, apikey, appId)
|
|
456
|
-
markStepDone(5)
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
if (stepToSkip < 6) {
|
|
460
|
-
await step6(orgId, snag, apikey, appId)
|
|
461
|
-
markStepDone(6)
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
if (stepToSkip < 7) {
|
|
465
|
-
await step7(orgId, snag, apikey, appId)
|
|
466
|
-
markStepDone(7)
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
if (stepToSkip < 8) {
|
|
470
|
-
await step8(orgId, snag, apikey, appId)
|
|
471
|
-
markStepDone(8)
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
if (stepToSkip < 9) {
|
|
475
|
-
await step9(orgId, snag)
|
|
476
|
-
markStepDone(9)
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
await step10(orgId, snag, apikey, appId)
|
|
480
|
-
await markStep(orgId, snag, 0)
|
|
481
|
-
cleanupStepsDone()
|
|
482
|
-
}
|
|
483
|
-
catch (e) {
|
|
484
|
-
console.error(e)
|
|
485
|
-
p.log.error(`Error during onboarding, please try again later`)
|
|
486
|
-
exit(1)
|
|
487
|
-
}
|
|
488
|
-
|
|
489
|
-
p.log.info(`Welcome onboard ✈️!`)
|
|
490
|
-
p.log.info(`Your Capgo update system is setup`)
|
|
491
|
-
p.log.info(`Next time use \`${pm.runner} @capgo/cli@latest bundle upload\` to only upload your bundle`)
|
|
492
|
-
p.log.info(`If you have any issue try to use the debug command \`${pm.runner} @capgo/cli@latest app debug\``)
|
|
493
|
-
p.outro(`Bye 👋`)
|
|
494
|
-
exit()
|
|
495
|
-
}
|
package/src/key.ts
DELETED
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
import { existsSync, readFileSync, writeFileSync } from 'node:fs'
|
|
2
|
-
import { program } from 'commander'
|
|
3
|
-
import { intro, log, outro } from '@clack/prompts'
|
|
4
|
-
import { writeConfig } from './config'
|
|
5
|
-
import { createRSA } from './api/crypto'
|
|
6
|
-
import { baseKey, baseKeyPub, getConfig } from './utils'
|
|
7
|
-
import { checkLatest } from './api/update'
|
|
8
|
-
|
|
9
|
-
interface saveOptions {
|
|
10
|
-
key?: string
|
|
11
|
-
keyData?: string
|
|
12
|
-
}
|
|
13
|
-
interface Options {
|
|
14
|
-
force?: boolean
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export async function saveKey(options: saveOptions, logg = true) {
|
|
18
|
-
if (logg)
|
|
19
|
-
intro(`Save keys 🔑`)
|
|
20
|
-
|
|
21
|
-
const extConfig = await getConfig()
|
|
22
|
-
|
|
23
|
-
const keyPath = options.key || baseKey
|
|
24
|
-
// check if publicKey exist
|
|
25
|
-
|
|
26
|
-
let privateKey = options.keyData || ''
|
|
27
|
-
|
|
28
|
-
if (!existsSync(keyPath) && !privateKey) {
|
|
29
|
-
if (logg) {
|
|
30
|
-
log.error(`Cannot find public key ${keyPath} or as keyData option or in ${extConfig.path}`)
|
|
31
|
-
program.error('')
|
|
32
|
-
}
|
|
33
|
-
else {
|
|
34
|
-
return false
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
else if (existsSync(keyPath)) {
|
|
38
|
-
// open with fs publicKey path
|
|
39
|
-
const keyFile = readFileSync(keyPath)
|
|
40
|
-
privateKey = keyFile.toString()
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
if (extConfig?.config) {
|
|
44
|
-
if (!extConfig.config.plugins) {
|
|
45
|
-
extConfig.config.plugins = {
|
|
46
|
-
extConfig: {},
|
|
47
|
-
CapacitorUpdater: {},
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
if (!extConfig.config.plugins.CapacitorUpdater)
|
|
51
|
-
extConfig.config.plugins.CapacitorUpdater = {}
|
|
52
|
-
|
|
53
|
-
extConfig.config.plugins.CapacitorUpdater.privateKey = privateKey
|
|
54
|
-
// console.log('extConfig', extConfig)
|
|
55
|
-
await writeConfig(extConfig)
|
|
56
|
-
}
|
|
57
|
-
if (log) {
|
|
58
|
-
log.success(`private key saved into ${extConfig.path} file in local directory`)
|
|
59
|
-
log.success(`your app will decode the zip archive with this key`)
|
|
60
|
-
}
|
|
61
|
-
return true
|
|
62
|
-
}
|
|
63
|
-
export async function saveKeyCommand(options: saveOptions) {
|
|
64
|
-
intro(`Save keys 🔑`)
|
|
65
|
-
await checkLatest()
|
|
66
|
-
await saveKey(options)
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
export async function createKey(options: Options, logg = true) {
|
|
70
|
-
// write in file .capgo the apikey in home directory
|
|
71
|
-
if (logg)
|
|
72
|
-
intro(`Create keys 🔑`)
|
|
73
|
-
|
|
74
|
-
const { publicKey, privateKey } = createRSA()
|
|
75
|
-
|
|
76
|
-
// check if baseName already exist
|
|
77
|
-
if (existsSync(baseKeyPub) && !options.force) {
|
|
78
|
-
log.error('Public Key already exists, use --force to overwrite')
|
|
79
|
-
if (logg) {
|
|
80
|
-
program.error('')
|
|
81
|
-
}
|
|
82
|
-
else {
|
|
83
|
-
return false
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
writeFileSync(baseKeyPub, publicKey)
|
|
87
|
-
if (existsSync(baseKey) && !options.force) {
|
|
88
|
-
log.error('Private Key already exists, use --force to overwrite')
|
|
89
|
-
if (logg) {
|
|
90
|
-
program.error('')
|
|
91
|
-
}
|
|
92
|
-
else {
|
|
93
|
-
return false
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
writeFileSync(baseKey, privateKey)
|
|
97
|
-
|
|
98
|
-
const extConfig = await getConfig()
|
|
99
|
-
if (extConfig?.config) {
|
|
100
|
-
if (!extConfig.config.plugins) {
|
|
101
|
-
extConfig.config.plugins = {
|
|
102
|
-
extConfig: {},
|
|
103
|
-
CapacitorUpdater: {},
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
if (!extConfig.config.plugins.CapacitorUpdater) {
|
|
108
|
-
extConfig.config.plugins.CapacitorUpdater = {}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
const flattenPrivateKey = privateKey.replace(/\\n/g, '\\n')
|
|
112
|
-
extConfig.config.plugins.CapacitorUpdater.privateKey = flattenPrivateKey
|
|
113
|
-
// console.log('extConfig', extConfig)
|
|
114
|
-
writeConfig(extConfig)
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
if (logg) {
|
|
118
|
-
log.success('Your RSA key has been generated')
|
|
119
|
-
log.success(`Public key saved in ${baseKeyPub}`)
|
|
120
|
-
log.success('This key will be use to encrypt your bundle before sending it to Capgo')
|
|
121
|
-
log.success('Keep it safe')
|
|
122
|
-
log.success('Than make it unreadable by Capgo and unmodifiable by anyone')
|
|
123
|
-
log.success(`Private key saved in ${extConfig.path}`)
|
|
124
|
-
log.success('Your app will be the only one having it')
|
|
125
|
-
log.success('Only your users can decrypt your update')
|
|
126
|
-
log.success('Only you can send them an update')
|
|
127
|
-
outro(`Done ✅`)
|
|
128
|
-
}
|
|
129
|
-
return true
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
export async function createKeyCommand(options: Options) {
|
|
133
|
-
await checkLatest()
|
|
134
|
-
await createKey(options)
|
|
135
|
-
}
|
package/src/login.ts
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
import { appendFileSync, existsSync, writeFileSync } from 'node:fs'
|
|
2
|
-
import { homedir } from 'node:os'
|
|
3
|
-
import { exit } from 'node:process'
|
|
4
|
-
import { program } from 'commander'
|
|
5
|
-
import { intro, log, outro } from '@clack/prompts'
|
|
6
|
-
import { createSupabaseClient, useLogSnag, verifyUser } from './utils'
|
|
7
|
-
import { checkLatest } from './api/update'
|
|
8
|
-
|
|
9
|
-
interface Options {
|
|
10
|
-
local: boolean
|
|
11
|
-
}
|
|
12
|
-
export async function doLoginExists() {
|
|
13
|
-
const userHomeDir = homedir()
|
|
14
|
-
return existsSync(`${userHomeDir}/.capgo`) || existsSync('.capgo')
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export async function login(apikey: string, options: Options, shouldExit = true) {
|
|
18
|
-
if (shouldExit)
|
|
19
|
-
intro(`Login to Capgo`)
|
|
20
|
-
|
|
21
|
-
if (!apikey) {
|
|
22
|
-
if (shouldExit) {
|
|
23
|
-
log.error('Missing API key, you need to provide a API key to upload your bundle')
|
|
24
|
-
program.error('')
|
|
25
|
-
}
|
|
26
|
-
return false
|
|
27
|
-
}
|
|
28
|
-
await checkLatest()
|
|
29
|
-
// write in file .capgo the apikey in home directory
|
|
30
|
-
try {
|
|
31
|
-
const { local } = options
|
|
32
|
-
const snag = useLogSnag()
|
|
33
|
-
|
|
34
|
-
if (local) {
|
|
35
|
-
if (!existsSync('.git')) {
|
|
36
|
-
log.error('To use local you should be in a git repository')
|
|
37
|
-
program.error('')
|
|
38
|
-
}
|
|
39
|
-
writeFileSync('.capgo', `${apikey}\n`)
|
|
40
|
-
appendFileSync('.gitignore', '.capgo\n')
|
|
41
|
-
}
|
|
42
|
-
else {
|
|
43
|
-
const userHomeDir = homedir()
|
|
44
|
-
writeFileSync(`${userHomeDir}/.capgo`, `${apikey}\n`)
|
|
45
|
-
}
|
|
46
|
-
const supabase = await createSupabaseClient(apikey)
|
|
47
|
-
const userId = await verifyUser(supabase, apikey, ['write', 'all', 'upload'])
|
|
48
|
-
await snag.track({
|
|
49
|
-
channel: 'user-login',
|
|
50
|
-
event: 'User CLI login',
|
|
51
|
-
icon: '✅',
|
|
52
|
-
user_id: userId,
|
|
53
|
-
notify: false,
|
|
54
|
-
}).catch()
|
|
55
|
-
log.success(`login saved into .capgo file in ${local ? 'local' : 'home'} directory`)
|
|
56
|
-
}
|
|
57
|
-
catch (e) {
|
|
58
|
-
log.error(`Error while saving login`)
|
|
59
|
-
exit(1)
|
|
60
|
-
}
|
|
61
|
-
if (shouldExit) {
|
|
62
|
-
outro('Done ✅')
|
|
63
|
-
exit()
|
|
64
|
-
}
|
|
65
|
-
return true
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export async function loginCommand(apikey: string, options: Options) {
|
|
69
|
-
login(apikey, options, true)
|
|
70
|
-
}
|