@capgo/cli 3.14.63 → 3.14.67
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/build.yml +11 -13
- package/.github/workflows/bump_version.yml +14 -21
- package/CHANGELOG.md +23 -0
- package/build.mjs +23 -0
- package/bun.lockb +0 -0
- package/dist/index.js +65153 -1
- package/package.json +27 -30
- package/src/api/app.ts +1 -1
- package/src/api/channels.ts +1 -1
- package/src/api/crypto.ts +1 -1
- package/src/api/devices_override.ts +1 -1
- package/src/api/versions.ts +1 -1
- package/src/app/add.ts +4 -4
- package/src/app/debug.ts +4 -2
- package/src/app/info.ts +2 -2
- package/src/app/list.ts +1 -1
- package/src/app/set.ts +3 -3
- package/src/bundle/check.ts +1 -1
- package/src/bundle/cleanup.ts +1 -1
- package/src/bundle/decrypt.ts +1 -1
- package/src/bundle/unlink.ts +3 -3
- package/src/bundle/upload.ts +34 -32
- package/src/bundle/zip.ts +2 -2
- package/src/channel/set.ts +2 -2
- package/src/index.ts +0 -4
- package/src/init.ts +2 -2
- package/src/key.ts +1 -1
- package/src/login.ts +2 -2
- package/src/utils.ts +37 -10
- package/tsconfig.json +20 -8
- package/webpack.config.js +0 -34
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@capgo/cli",
|
|
3
|
-
"version": "3.14.
|
|
3
|
+
"version": "3.14.67",
|
|
4
4
|
"description": "A CLI to upload to capgo servers",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
"url": "https://github.com/Cap-go/capgo-cli/issues"
|
|
15
15
|
},
|
|
16
16
|
"engines": {
|
|
17
|
-
"npm": ">=
|
|
18
|
-
"node": ">=
|
|
17
|
+
"npm": ">=8.0.0",
|
|
18
|
+
"node": ">=20.0.0"
|
|
19
19
|
},
|
|
20
20
|
"keywords": [
|
|
21
21
|
"appflow alternative",
|
|
@@ -29,11 +29,11 @@
|
|
|
29
29
|
"capgo-cli"
|
|
30
30
|
],
|
|
31
31
|
"scripts": {
|
|
32
|
-
"
|
|
32
|
+
"build": "node build.mjs",
|
|
33
|
+
"dev": "NODE_ENV=development node build.mjs",
|
|
33
34
|
"no-debug": "node dist/index.js",
|
|
34
35
|
"test": "npx --yes ts-node -T src/index.ts",
|
|
35
|
-
"build": "
|
|
36
|
-
"dev-build": "SUPA_DB=development npx webpack --config webpack.config.js",
|
|
36
|
+
"dev-build": "SUPA_DB=development node build.mjs",
|
|
37
37
|
"pack": "pkg",
|
|
38
38
|
"types": "npx --yes supabase gen types typescript --project-id=xvwzpoazmxkqosrdewyv > src/types/supabase.types.ts",
|
|
39
39
|
"test_rls": "ts-node ./test/test_headers_rls.ts",
|
|
@@ -42,56 +42,53 @@
|
|
|
42
42
|
"author": "github.com/riderx",
|
|
43
43
|
"license": "Apache 2.0",
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@capacitor/cli": "5.
|
|
46
|
-
"@capgo/find-package-manager": "^0.0.
|
|
45
|
+
"@capacitor/cli": "5.7.0",
|
|
46
|
+
"@capgo/find-package-manager": "^0.0.9",
|
|
47
47
|
"@clack/prompts": "^0.7.0",
|
|
48
|
-
"@supabase/supabase-js": "^2.
|
|
48
|
+
"@supabase/supabase-js": "^2.39.3",
|
|
49
49
|
"@tomasklaen/checksum": "^1.1.0",
|
|
50
50
|
"@trufflesuite/spinnies": "^0.1.1",
|
|
51
51
|
"adm-zip": "^0.5.10",
|
|
52
|
-
"axios": "^1.6.2",
|
|
53
52
|
"ci-info": "^4.0.0",
|
|
54
|
-
"commander": "
|
|
55
|
-
"console-table-printer": "^2.
|
|
53
|
+
"commander": "12.0.0",
|
|
54
|
+
"console-table-printer": "^2.12.0",
|
|
56
55
|
"get-latest-version": "^5.1.0",
|
|
56
|
+
"ky": "^1.2.0",
|
|
57
57
|
"logsnag": "1.0.0",
|
|
58
|
-
"mime": "^
|
|
58
|
+
"mime": "^4.0.1",
|
|
59
59
|
"node-dir": "^0.1.17",
|
|
60
|
-
"open": "^
|
|
60
|
+
"open": "^10.0.3",
|
|
61
61
|
"prettyjson": "^1.2.5",
|
|
62
62
|
"prompt-sync": "^4.2.0",
|
|
63
63
|
"qrcode": "^1.5.3",
|
|
64
|
-
"semver": "^7.
|
|
64
|
+
"semver": "^7.6.0"
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
67
67
|
"@types/adm-zip": "0.5.5",
|
|
68
68
|
"@types/mime": "^3.0.4",
|
|
69
|
-
"@types/node": "^20.
|
|
69
|
+
"@types/node": "^20.11.17",
|
|
70
70
|
"@types/node-dir": "^0.0.37",
|
|
71
71
|
"@types/npmcli__ci-detect": "^2.0.3",
|
|
72
72
|
"@types/prettyjson": "^0.0.33",
|
|
73
73
|
"@types/prompt-sync": "^4.2.3",
|
|
74
74
|
"@types/qrcode": "^1.5.5",
|
|
75
75
|
"@types/semver": "^7.5.6",
|
|
76
|
-
"@typescript-eslint/eslint-plugin": "6.
|
|
77
|
-
"@typescript-eslint/parser": "6.
|
|
78
|
-
"
|
|
76
|
+
"@typescript-eslint/eslint-plugin": "6.21.0",
|
|
77
|
+
"@typescript-eslint/parser": "6.21.0",
|
|
78
|
+
"esbuild": "^0.20.0",
|
|
79
|
+
"eslint": "8.56.0",
|
|
79
80
|
"eslint-config-airbnb-base": "^15.0.0",
|
|
80
|
-
"eslint-config-prettier": "^9.
|
|
81
|
+
"eslint-config-prettier": "^9.1.0",
|
|
81
82
|
"eslint-import-resolver-typescript": "3.6.1",
|
|
82
|
-
"eslint-plugin-import": "2.29.
|
|
83
|
-
"eslint-plugin-prettier": "^5.
|
|
83
|
+
"eslint-plugin-import": "2.29.1",
|
|
84
|
+
"eslint-plugin-prettier": "^5.1.3",
|
|
84
85
|
"git-format-staged": "3.0.0",
|
|
85
|
-
"husky": "^
|
|
86
|
-
"nodemon": "3.0.2",
|
|
86
|
+
"husky": "^9.0.10",
|
|
87
87
|
"pkg": "5.8.1",
|
|
88
|
-
"prettier": "3.
|
|
88
|
+
"prettier": "3.2.5",
|
|
89
89
|
"ts-loader": "^9.5.1",
|
|
90
|
-
"ts-node": "^10.9.
|
|
90
|
+
"ts-node": "^10.9.2",
|
|
91
91
|
"tsconfig-paths": "4.2.0",
|
|
92
|
-
"typescript": "5.3.3"
|
|
93
|
-
"webpack": "5.89.0",
|
|
94
|
-
"webpack-cli": "^5.1.4",
|
|
95
|
-
"webpack-node-externals": "^3.0.0"
|
|
92
|
+
"typescript": "5.3.3"
|
|
96
93
|
}
|
|
97
94
|
}
|
package/src/api/app.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SupabaseClient } from '@supabase/supabase-js';
|
|
2
2
|
import * as p from '@clack/prompts';
|
|
3
3
|
import { program } from 'commander';
|
|
4
|
-
import { Database } from 'types/supabase.types';
|
|
4
|
+
import { Database } from '../types/supabase.types';
|
|
5
5
|
import { isAllowedApp, isAllowedAppOrg, OptionsBase, OrganizationPerm } from '../utils';
|
|
6
6
|
|
|
7
7
|
export const checkAppExists = async (supabase: SupabaseClient<Database>, appid: string) => {
|
package/src/api/channels.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { SupabaseClient } from '@supabase/supabase-js';
|
|
|
2
2
|
import { program } from 'commander';
|
|
3
3
|
import { Table } from 'console-table-printer';
|
|
4
4
|
import * as p from '@clack/prompts';
|
|
5
|
-
import { Database } from 'types/supabase.types';
|
|
5
|
+
import { Database } from '../types/supabase.types';
|
|
6
6
|
import { formatError, getHumanDate } from '../utils';
|
|
7
7
|
|
|
8
8
|
export const checkVersionNotUsedInChannel = async (supabase: SupabaseClient<Database>,
|
package/src/api/crypto.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SupabaseClient } from '@supabase/supabase-js';
|
|
2
2
|
import { program } from 'commander';
|
|
3
3
|
import * as p from '@clack/prompts';
|
|
4
|
-
import { Database } from 'types/supabase.types';
|
|
4
|
+
import { Database } from '../types/supabase.types';
|
|
5
5
|
import { formatError } from '../utils';
|
|
6
6
|
|
|
7
7
|
export const checkVersionNotUsedInDeviceOverride = async (supabase: SupabaseClient<Database>,
|
package/src/api/versions.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { SupabaseClient } from '@supabase/supabase-js';
|
|
|
2
2
|
import { program } from 'commander';
|
|
3
3
|
import { Table } from 'console-table-printer';
|
|
4
4
|
import * as p from '@clack/prompts';
|
|
5
|
-
import { Database } from 'types/supabase.types';
|
|
5
|
+
import { Database } from '../types/supabase.types';
|
|
6
6
|
// import { definitions } from '../types/types_supabase';
|
|
7
7
|
import { getHumanDate } from '../utils';
|
|
8
8
|
import { checkVersionNotUsedInChannel } from './channels';
|
package/src/app/add.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { randomUUID } from 'crypto';
|
|
2
|
-
import
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import mime from 'mime';
|
|
3
3
|
import { program } from 'commander';
|
|
4
4
|
import * as p from '@clack/prompts';
|
|
5
5
|
import { existsSync, readFileSync } from 'node:fs';
|
|
@@ -56,13 +56,13 @@ export const addApp = async (appId: string, options: Options, throwErr = true) =
|
|
|
56
56
|
|
|
57
57
|
if (icon && existsSync(icon)) {
|
|
58
58
|
iconBuff = readFileSync(icon);
|
|
59
|
-
const contentType = getType(icon);
|
|
59
|
+
const contentType = mime.getType(icon);
|
|
60
60
|
iconType = contentType || 'image/png';
|
|
61
61
|
p.log.warn(`Found app icon ${icon}`);
|
|
62
62
|
}
|
|
63
63
|
else if (existsSync(newIconPath)) {
|
|
64
64
|
iconBuff = readFileSync(newIconPath);
|
|
65
|
-
const contentType = getType(newIconPath);
|
|
65
|
+
const contentType = mime.getType(newIconPath);
|
|
66
66
|
iconType = contentType || 'image/png';
|
|
67
67
|
p.log.warn(`Found app icon ${newIconPath}`);
|
|
68
68
|
} else {
|
package/src/app/debug.ts
CHANGED
|
@@ -2,7 +2,7 @@ import * as p from '@clack/prompts';
|
|
|
2
2
|
import { SupabaseClient } from '@supabase/supabase-js';
|
|
3
3
|
import { program } from 'commander';
|
|
4
4
|
import LogSnag from 'logsnag';
|
|
5
|
-
import { Database } from 'types/supabase.types';
|
|
5
|
+
import { Database } from '../types/supabase.types';
|
|
6
6
|
import { checkAppExistsAndHasPermissionErr } from '../api/app';
|
|
7
7
|
import { checkLatest } from '../api/update';
|
|
8
8
|
import { convertAppName, createSupabaseClient, findSavedKey, getLocalConfig, useLogSnag, verifyUser, getConfig } from '../utils';
|
|
@@ -50,7 +50,9 @@ interface QueryStats {
|
|
|
50
50
|
export async function getStats(supabase: SupabaseClient<Database>, query: QueryStats)
|
|
51
51
|
: Promise<Database['public']['Tables']['stats']['Row'] | null> {
|
|
52
52
|
try {
|
|
53
|
-
const
|
|
53
|
+
const pathStats = 'get_stats'
|
|
54
|
+
// const pathStats = 'private/stats' // TODO: switch to new endpoint when new backend released
|
|
55
|
+
const res = await supabase.functions.invoke(pathStats, { body: JSON.stringify(query) })
|
|
54
56
|
const listData = res.data.data as Database['public']['Tables']['stats']['Row'][]
|
|
55
57
|
if (listData?.length > 0) {
|
|
56
58
|
return listData[0]
|
package/src/app/info.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readFileSync } from "fs"
|
|
2
|
-
import { join } from "path"
|
|
3
|
-
import os from 'os';
|
|
2
|
+
import { join } from "node:path"
|
|
3
|
+
import os from 'node:os';
|
|
4
4
|
import getLatest from "get-latest-version"
|
|
5
5
|
import Spinnies from '@trufflesuite/spinnies';
|
|
6
6
|
import pack from '../../package.json'
|
package/src/app/list.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { program } from 'commander';
|
|
|
2
2
|
import { Table } from 'console-table-printer';
|
|
3
3
|
import { SupabaseClient } from '@supabase/supabase-js';
|
|
4
4
|
import * as p from '@clack/prompts';
|
|
5
|
-
import { Database } from 'types/supabase.types';
|
|
5
|
+
import { Database } from '../types/supabase.types';
|
|
6
6
|
import { OptionsBase, createSupabaseClient, findSavedKey, getHumanDate, verifyUser } from '../utils';
|
|
7
7
|
import { checkLatest } from '../api/update';
|
|
8
8
|
|
package/src/app/set.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { randomUUID } from "crypto";
|
|
2
|
-
import
|
|
2
|
+
import mime from 'mime';
|
|
3
3
|
import { program } from "commander";
|
|
4
4
|
import * as p from '@clack/prompts';
|
|
5
5
|
import { existsSync, readFileSync } from "node:fs";
|
|
@@ -44,13 +44,13 @@ export const setApp = async (appId: string, options: Options) => {
|
|
|
44
44
|
|
|
45
45
|
if (icon && existsSync(icon)) {
|
|
46
46
|
iconBuff = readFileSync(icon);
|
|
47
|
-
const contentType = getType(icon);
|
|
47
|
+
const contentType = mime.getType(icon);
|
|
48
48
|
iconType = contentType || 'image/png';
|
|
49
49
|
p.log.warn(`Found app icon ${icon}`);
|
|
50
50
|
}
|
|
51
51
|
else if (existsSync(newIconPath)) {
|
|
52
52
|
iconBuff = readFileSync(newIconPath);
|
|
53
|
-
const contentType = getType(newIconPath);
|
|
53
|
+
const contentType = mime.getType(newIconPath);
|
|
54
54
|
iconType = contentType || 'image/png';
|
|
55
55
|
p.log.warn(`Found app icon ${newIconPath}`);
|
|
56
56
|
} else {
|
package/src/bundle/check.ts
CHANGED
package/src/bundle/cleanup.ts
CHANGED
|
@@ -3,7 +3,7 @@ import semver from 'semver/preload';
|
|
|
3
3
|
import * as p from '@clack/prompts';
|
|
4
4
|
import promptSync from 'prompt-sync';
|
|
5
5
|
import { SupabaseClient } from '@supabase/supabase-js';
|
|
6
|
-
import { Database } from 'types/supabase.types';
|
|
6
|
+
import { Database } from '../types/supabase.types';
|
|
7
7
|
import { OptionsBase, createSupabaseClient, findSavedKey, getConfig, getHumanDate, verifyUser } from '../utils';
|
|
8
8
|
import { deleteSpecificVersion, displayBundles, getActiveAppVersions, getChannelsVersion } from '../api/versions';
|
|
9
9
|
import { checkAppExistsAndHasPermissionErr } from '../api/app';
|
package/src/bundle/decrypt.ts
CHANGED
package/src/bundle/unlink.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { program } from 'commander';
|
|
2
2
|
import * as p from '@clack/prompts';
|
|
3
|
-
import { getVersionData } from 'api/versions';
|
|
3
|
+
import { getVersionData } from '../api/versions';
|
|
4
4
|
import { checkVersionNotUsedInDeviceOverride } from '../api/devices_override';
|
|
5
5
|
import { checkVersionNotUsedInChannel } from '../api/channels';
|
|
6
6
|
import { checkAppExistsAndHasPermissionErr } from "../api/app";
|
|
7
7
|
import {
|
|
8
|
-
OptionsBase,
|
|
8
|
+
OptionsBase,
|
|
9
9
|
getConfig, createSupabaseClient,
|
|
10
10
|
formatError, findSavedKey, checkPlanValid, useLogSnag, verifyUser
|
|
11
11
|
} from '../utils';
|
|
@@ -47,7 +47,7 @@ export const unlinkDevice = async (channel: string, appId: string, options: Opti
|
|
|
47
47
|
program.error('');
|
|
48
48
|
}
|
|
49
49
|
try {
|
|
50
|
-
await checkPlanValid(supabase, userId)
|
|
50
|
+
await checkPlanValid(supabase, userId, appId, options.apikey)
|
|
51
51
|
|
|
52
52
|
const versionData = await getVersionData(supabase, appId, userId, bundle);
|
|
53
53
|
await checkVersionNotUsedInChannel(supabase, appId, userId, versionData);
|
package/src/bundle/upload.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { randomUUID } from 'crypto';
|
|
2
|
-
import { existsSync, readFileSync } from 'fs';
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
3
3
|
import AdmZip from 'adm-zip';
|
|
4
4
|
import { program } from 'commander';
|
|
5
5
|
import * as p from '@clack/prompts';
|
|
6
6
|
import { checksum as getChecksum } from '@tomasklaen/checksum';
|
|
7
7
|
import ciDetect from 'ci-info';
|
|
8
|
-
import
|
|
8
|
+
import ky from 'ky';
|
|
9
9
|
import { checkLatest } from '../api/update';
|
|
10
10
|
import { checkAppExistsAndHasPermissionOrgErr } from "../api/app";
|
|
11
11
|
import { encryptSource } from '../api/crypto';
|
|
@@ -19,7 +19,8 @@ import {
|
|
|
19
19
|
getLocalDepenencies,
|
|
20
20
|
verifyUser,
|
|
21
21
|
OrganizationPerm,
|
|
22
|
-
hasOrganizationPerm
|
|
22
|
+
hasOrganizationPerm,
|
|
23
|
+
getAppOwner
|
|
23
24
|
} from '../utils';
|
|
24
25
|
import { checkIndexPosition, searchInDirectory } from './check';
|
|
25
26
|
|
|
@@ -54,10 +55,10 @@ export const uploadBundle = async (appid: string, options: Options, shouldExit =
|
|
|
54
55
|
channel = channel || 'dev';
|
|
55
56
|
|
|
56
57
|
const config = await getConfig();
|
|
57
|
-
const localS3: boolean = (config.app.extConfig.plugins && config.app.extConfig.plugins.CapacitorUpdater
|
|
58
|
+
const localS3: boolean = (config.app.extConfig.plugins && config.app.extConfig.plugins.CapacitorUpdater
|
|
58
59
|
&& config.app.extConfig.plugins.CapacitorUpdater.localS3) === true;
|
|
59
60
|
|
|
60
|
-
const checkNotifyAppReady = options.codeCheck
|
|
61
|
+
const checkNotifyAppReady = options.codeCheck
|
|
61
62
|
appid = appid || config?.app?.appId
|
|
62
63
|
// create bundle name format : 1.0.0-beta.x where x is a uuid
|
|
63
64
|
const uuid = randomUUID().split('-')[0];
|
|
@@ -90,8 +91,8 @@ export const uploadBundle = async (appid: string, options: Options, shouldExit =
|
|
|
90
91
|
}
|
|
91
92
|
const foundIndex = checkIndexPosition(path);
|
|
92
93
|
if (!foundIndex) {
|
|
93
|
-
|
|
94
|
-
|
|
94
|
+
p.log.error(`index.html is missing in the root folder or in the only folder in the root folder`);
|
|
95
|
+
program.error('');
|
|
95
96
|
}
|
|
96
97
|
}
|
|
97
98
|
|
|
@@ -100,22 +101,22 @@ export const uploadBundle = async (appid: string, options: Options, shouldExit =
|
|
|
100
101
|
const localConfig = await getLocalConfig()
|
|
101
102
|
const supabase = await createSupabaseClient(options.apikey)
|
|
102
103
|
const userId = await verifyUser(supabase, options.apikey, ['write', 'all', 'upload']);
|
|
103
|
-
await checkPlanValid(supabase, userId, false)
|
|
104
104
|
// Check we have app access to this appId
|
|
105
105
|
// await checkAppExistsAndHasPermissionErr(supabase, options.apikey, appid);
|
|
106
106
|
|
|
107
107
|
const permissions = await checkAppExistsAndHasPermissionOrgErr(supabase, options.apikey, appid, OrganizationPerm.upload)
|
|
108
|
+
await checkPlanValid(supabase, userId, appid, options.apikey, false)
|
|
108
109
|
|
|
109
110
|
const updateMetadataRequired = await requireUpdateMetadata(supabase, channel)
|
|
110
111
|
|
|
111
112
|
// Check compatibility here
|
|
112
113
|
const { data: channelData, error: channelError } = await supabase
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
114
|
+
.from('channels')
|
|
115
|
+
.select('version ( minUpdateVersion, native_packages )')
|
|
116
|
+
.eq('name', channel)
|
|
117
|
+
.eq('app_id', appid)
|
|
118
|
+
.single()
|
|
119
|
+
|
|
119
120
|
// eslint-disable-next-line no-undef-init
|
|
120
121
|
let localDependencies: Awaited<ReturnType<typeof getLocalDepenencies>> | undefined = undefined;
|
|
121
122
|
let finalCompatibility: Awaited<ReturnType<typeof checkCompatibility>>['finalCompatibility'];
|
|
@@ -124,14 +125,14 @@ export const uploadBundle = async (appid: string, options: Options, shouldExit =
|
|
|
124
125
|
if (!channelError && channelData && channelData.version && (channelData.version as any).native_packages && !ignoreMetadataCheck) {
|
|
125
126
|
const spinner = p.spinner();
|
|
126
127
|
spinner.start(`Checking bundle compatibility with channel ${channel}`);
|
|
127
|
-
const {
|
|
128
|
+
const {
|
|
128
129
|
finalCompatibility: finalCompatibilityWithChannel,
|
|
129
|
-
localDependencies: localDependenciesWithChannel
|
|
130
|
+
localDependencies: localDependenciesWithChannel
|
|
130
131
|
} = await checkCompatibility(supabase, appid, channel)
|
|
131
132
|
|
|
132
133
|
finalCompatibility = finalCompatibilityWithChannel
|
|
133
134
|
localDependencies = localDependenciesWithChannel
|
|
134
|
-
|
|
135
|
+
|
|
135
136
|
if (finalCompatibility.find((x) => x.localVersion !== x.remoteVersion)) {
|
|
136
137
|
p.log.error(`Your bundle is not compatible with the channel ${channel}`);
|
|
137
138
|
p.log.warn(`You can check compatibility with "npx @capgo/cli bundle compatibility"`);
|
|
@@ -147,7 +148,7 @@ export const uploadBundle = async (appid: string, options: Options, shouldExit =
|
|
|
147
148
|
p.log.error('Invalid remote min update version, skipping auto setting compatibility');
|
|
148
149
|
program.error('');
|
|
149
150
|
}
|
|
150
|
-
|
|
151
|
+
|
|
151
152
|
minUpdateVersion = lastMinUpdateVersion
|
|
152
153
|
p.log.info(`Auto set min-update-version to ${minUpdateVersion}`);
|
|
153
154
|
} catch (error) {
|
|
@@ -285,15 +286,17 @@ It will be also visible in your dashboard\n`);
|
|
|
285
286
|
}
|
|
286
287
|
|
|
287
288
|
const hashedLocalDependencies = localDependencies ? new Map(localDependencies
|
|
288
|
-
|
|
289
|
-
|
|
289
|
+
.filter((a) => !!a.native && a.native !== undefined)
|
|
290
|
+
.map((a) => [a.name, a])) : new Map()
|
|
290
291
|
|
|
291
292
|
// eslint-disable-next-line max-len
|
|
292
293
|
const nativePackages = (hashedLocalDependencies.size > 0 || !options.ignoreMetadataCheck) ? Array.from(hashedLocalDependencies, ([name, value]) => ({ name, version: value.version })) : undefined
|
|
293
294
|
|
|
295
|
+
const appOwner = await getAppOwner(supabase, appid)
|
|
296
|
+
|
|
294
297
|
const versionData = {
|
|
295
298
|
bucket_id: external ? undefined : fileName,
|
|
296
|
-
user_id:
|
|
299
|
+
user_id: appOwner,
|
|
297
300
|
name: bundle,
|
|
298
301
|
app_id: appid,
|
|
299
302
|
session_key: sessionKey,
|
|
@@ -317,20 +320,18 @@ It will be also visible in your dashboard\n`);
|
|
|
317
320
|
p.log.error(`Cannot get upload url`);
|
|
318
321
|
program.error('');
|
|
319
322
|
}
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
method: "put",
|
|
323
|
-
url,
|
|
324
|
-
data: zipped,
|
|
323
|
+
await ky.put(url, {
|
|
324
|
+
body: zipped,
|
|
325
325
|
headers: (!localS3 ? {
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
326
|
+
"Content-Type": "application/octet-stream",
|
|
327
|
+
"Cache-Control": "public, max-age=456789, immutable",
|
|
328
|
+
"x-amz-meta-crc32": checksum,
|
|
329
329
|
} : undefined)
|
|
330
330
|
})
|
|
331
331
|
versionData.storage_provider = 'r2'
|
|
332
332
|
const { error: dbError2 } = await updateOrCreateVersion(supabase, versionData, options.apikey)
|
|
333
333
|
if (dbError2) {
|
|
334
|
+
console.log(dbError2)
|
|
334
335
|
p.log.error(`Cannot update bundle ${formatError(dbError)}`);
|
|
335
336
|
program.error('');
|
|
336
337
|
}
|
|
@@ -344,11 +345,12 @@ It will be also visible in your dashboard\n`);
|
|
|
344
345
|
const { error: dbError3, data } = await updateOrCreateChannel(supabase, {
|
|
345
346
|
name: channel,
|
|
346
347
|
app_id: appid,
|
|
347
|
-
created_by:
|
|
348
|
+
created_by: appOwner,
|
|
348
349
|
version: versionId,
|
|
349
350
|
})
|
|
350
351
|
if (dbError3) {
|
|
351
352
|
p.log.error(`Cannot set channel, the upload key is not allowed to do that, use the "all" for this.`);
|
|
353
|
+
console.log(dbError3)
|
|
352
354
|
program.error('');
|
|
353
355
|
}
|
|
354
356
|
const appidWeb = convertAppName(appid)
|
|
@@ -359,7 +361,7 @@ It will be also visible in your dashboard\n`);
|
|
|
359
361
|
p.log.info(`Link device to this bundle to try it: ${bundleUrl}`);
|
|
360
362
|
}
|
|
361
363
|
|
|
362
|
-
if(options.bundleUrl) {
|
|
364
|
+
if (options.bundleUrl) {
|
|
363
365
|
p.log.info(`Bundle url: ${bundleUrl}`);
|
|
364
366
|
}
|
|
365
367
|
} else if (!versionId) {
|
package/src/bundle/zip.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { randomUUID } from 'crypto';
|
|
2
|
-
import { writeFileSync } from 'fs';
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { writeFileSync } from 'node:fs';
|
|
3
3
|
import AdmZip from 'adm-zip';
|
|
4
4
|
import { program } from 'commander';
|
|
5
5
|
import * as p from '@clack/prompts';
|
package/src/channel/set.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { program } from 'commander';
|
|
2
2
|
import * as p from '@clack/prompts';
|
|
3
|
-
import { Database } from 'types/supabase.types';
|
|
3
|
+
import { Database } from '../types/supabase.types';
|
|
4
4
|
import { checkAppExistsAndHasPermissionErr } from "../api/app";
|
|
5
5
|
import {
|
|
6
6
|
OptionsBase,
|
|
@@ -66,7 +66,7 @@ export const setChannel = async (channel: string, appId: string, options: Option
|
|
|
66
66
|
program.error('');
|
|
67
67
|
}
|
|
68
68
|
try {
|
|
69
|
-
await checkPlanValid(supabase, userId)
|
|
69
|
+
await checkPlanValid(supabase, userId, appId, options.apikey)
|
|
70
70
|
const channelPayload: Database['public']['Tables']['channels']['Insert'] = {
|
|
71
71
|
created_by: userId,
|
|
72
72
|
app_id: appId,
|
package/src/index.ts
CHANGED
|
@@ -64,7 +64,6 @@ app
|
|
|
64
64
|
|
|
65
65
|
app
|
|
66
66
|
.command('delete [appId]')
|
|
67
|
-
.alias('d')
|
|
68
67
|
.description('Delete an app in Capgo Cloud')
|
|
69
68
|
.action(deleteApp)
|
|
70
69
|
.option('-a, --apikey <apikey>', 'apikey to link to your account');
|
|
@@ -78,7 +77,6 @@ app
|
|
|
78
77
|
|
|
79
78
|
app
|
|
80
79
|
.command('debug [appId]')
|
|
81
|
-
.alias('d')
|
|
82
80
|
.description('Listen for live updates event in Capgo Cloud to debug your app')
|
|
83
81
|
.option('-a, --apikey <apikey>', 'apikey to link to your account')
|
|
84
82
|
.option('-d, --device <device>', 'the specific device to debug')
|
|
@@ -151,7 +149,6 @@ bundle
|
|
|
151
149
|
|
|
152
150
|
bundle
|
|
153
151
|
.command('unlink [appId]')
|
|
154
|
-
.alias('u')
|
|
155
152
|
.description('Unlink a bundle in Capgo Cloud')
|
|
156
153
|
.action(listBundle)
|
|
157
154
|
.option('-a, --apikey <apikey>', 'apikey to link to your account')
|
|
@@ -169,7 +166,6 @@ bundle
|
|
|
169
166
|
|
|
170
167
|
bundle
|
|
171
168
|
.command('decrypt [zipPath] [sessionKey]')
|
|
172
|
-
.alias('l')
|
|
173
169
|
.description('Decrypt a signed zip bundle')
|
|
174
170
|
.action(decryptZip)
|
|
175
171
|
.option('--key <key>', 'custom path for private signing key')
|
package/src/init.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { writeFileSync, readFileSync } from 'fs';
|
|
1
|
+
import { writeFileSync, readFileSync } from 'node:fs';
|
|
2
2
|
import { execSync, ExecSyncOptions, spawnSync } from 'child_process';
|
|
3
3
|
import { findPackageManagerType } from '@capgo/find-package-manager'
|
|
4
4
|
import * as p from '@clack/prompts';
|
|
5
5
|
import { SupabaseClient } from '@supabase/supabase-js';
|
|
6
6
|
import LogSnag from 'logsnag';
|
|
7
7
|
import semver from 'semver'
|
|
8
|
-
import { Database } from 'types/supabase.types';
|
|
8
|
+
import { Database } from './types/supabase.types';
|
|
9
9
|
import { markSnag , waitLog } from './app/debug';
|
|
10
10
|
import { createKey } from './key';
|
|
11
11
|
import { addChannel } from './channel/add';
|
package/src/key.ts
CHANGED
package/src/login.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { existsSync, writeFileSync, appendFileSync } from 'fs'
|
|
2
|
-
import { homedir } from 'os'
|
|
1
|
+
import { existsSync, writeFileSync, appendFileSync } from 'node:fs'
|
|
2
|
+
import { homedir } from 'node:os'
|
|
3
3
|
import { program } from 'commander';
|
|
4
4
|
import * as p from '@clack/prompts';
|
|
5
5
|
import { createSupabaseClient, useLogSnag, verifyUser } from './utils';
|
package/src/utils.ts
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import { existsSync, readdirSync, readFileSync } from 'fs';
|
|
2
|
-
import { homedir } from 'os';
|
|
3
|
-
import { resolve } from 'path';
|
|
1
|
+
import { existsSync, readdirSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { resolve } from 'node:path';
|
|
4
4
|
import { loadConfig } from '@capacitor/cli/dist/config';
|
|
5
5
|
import { program } from 'commander';
|
|
6
6
|
import { createClient, SupabaseClient } from '@supabase/supabase-js';
|
|
7
7
|
import prettyjson from 'prettyjson';
|
|
8
8
|
import { LogSnag } from 'logsnag';
|
|
9
9
|
import * as p from '@clack/prompts';
|
|
10
|
-
import
|
|
11
|
-
import axios from 'axios';
|
|
10
|
+
import ky from 'ky';
|
|
12
11
|
import { promiseFiles } from 'node-dir'
|
|
12
|
+
import { Database } from './types/supabase.types';
|
|
13
13
|
|
|
14
14
|
export const baseKey = '.capgo_key';
|
|
15
15
|
export const baseKeyPub = `${baseKey}.pub`;
|
|
@@ -68,9 +68,9 @@ interface CapgoConfig {
|
|
|
68
68
|
export const getRemoteConfig = async () => {
|
|
69
69
|
// call host + /api/get_config and parse the result as json using axios
|
|
70
70
|
const localConfig = await getLocalConfig()
|
|
71
|
-
return
|
|
71
|
+
return ky
|
|
72
72
|
.get(`${defaultApiHost}/get_config`)
|
|
73
|
-
.then((res) => res.
|
|
73
|
+
.then((res) => res.json<CapgoConfig>())
|
|
74
74
|
.then(data => ({ ...data, ...localConfig } as CapgoConfig))
|
|
75
75
|
.catch(() => {
|
|
76
76
|
console.log('Local config', localConfig);
|
|
@@ -144,6 +144,31 @@ export const isAllowedAction = async (supabase: SupabaseClient<Database>, userId
|
|
|
144
144
|
return !!data
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
+
export const isAllowedActionAppIdApiKey = async (supabase: SupabaseClient<Database>, appId: string, apikey: string): Promise<boolean> => {
|
|
148
|
+
const { data } = await supabase
|
|
149
|
+
.rpc('is_allowed_action', { apikey, appid: appId })
|
|
150
|
+
.single()
|
|
151
|
+
|
|
152
|
+
return !!data
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export const getAppOwner = async (supabase: SupabaseClient<Database>, appId: string): Promise<string> => {
|
|
156
|
+
const { data, error } = await supabase
|
|
157
|
+
.from('apps')
|
|
158
|
+
.select('user_id')
|
|
159
|
+
.eq('app_id', appId)
|
|
160
|
+
.single()
|
|
161
|
+
|
|
162
|
+
if (error) {
|
|
163
|
+
p.log.error('Cannot get app owner, exiting')
|
|
164
|
+
p.log.error('Please report the following error to capgo\'s staff')
|
|
165
|
+
console.error(error)
|
|
166
|
+
process.exit(1)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return data.user_id
|
|
170
|
+
}
|
|
171
|
+
|
|
147
172
|
export const isAllowedApp = async (supabase: SupabaseClient<Database>, apikey: string, appId: string): Promise<boolean> => {
|
|
148
173
|
const { data } = await supabase
|
|
149
174
|
.rpc('is_app_owner', { apikey, appid: appId })
|
|
@@ -251,9 +276,9 @@ export const isAllowedAppOrg = async (
|
|
|
251
276
|
}
|
|
252
277
|
}
|
|
253
278
|
|
|
254
|
-
export const checkPlanValid = async (supabase: SupabaseClient<Database>, userId: string, warning = true) => {
|
|
279
|
+
export const checkPlanValid = async (supabase: SupabaseClient<Database>, userId: string, appId: string, apikey: string, warning = true) => {
|
|
255
280
|
const config = await getRemoteConfig()
|
|
256
|
-
const validPlan = await
|
|
281
|
+
const validPlan = await isAllowedActionAppIdApiKey(supabase, appId, apikey)
|
|
257
282
|
if (!validPlan) {
|
|
258
283
|
p.log.error(`You need to upgrade your plan to continue to use capgo.\n Upgrade here: ${config.hostWeb}/dashboard/settings/plans\n`);
|
|
259
284
|
setTimeout(() => {
|
|
@@ -379,7 +404,9 @@ export async function uploadUrl(supabase: SupabaseClient<Database>, appId: strin
|
|
|
379
404
|
bucket_id: bucketId,
|
|
380
405
|
}
|
|
381
406
|
try {
|
|
382
|
-
const
|
|
407
|
+
const pathUploadLink = 'private/upload_link'
|
|
408
|
+
// const pathUploadLink = 'private/upload_link' // TODO: switch to new endpoint when new backend released
|
|
409
|
+
const res = await supabase.functions.invoke(pathUploadLink, { body: JSON.stringify(data) })
|
|
383
410
|
return res.data.url
|
|
384
411
|
} catch (error) {
|
|
385
412
|
p.log.error(`Cannot get upload url ${JSON.stringify(error)}`);
|