@capgo/cli 0.8.5 → 0.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.cz.toml CHANGED
@@ -1,7 +1,7 @@
1
1
  [tool.commitizen]
2
2
  name = "cz_conventional_commits"
3
3
  tag_format = "$major.$minor.$patch$prerelease"
4
- version = "0.8.5"
4
+ version = "0.10.1"
5
5
  version_files = [
6
6
  "package.json:version",
7
7
  ".cz.toml"
package/.eslintignore CHANGED
@@ -1,3 +1,4 @@
1
1
  dist
2
2
  test
3
3
  webpack.config.js
4
+ src/bin/types_supabase.ts
package/.eslintrc CHANGED
@@ -23,7 +23,6 @@
23
23
  ],
24
24
  "import/extensions": 0,
25
25
  "indent": "off",
26
- "@typescript-eslint/indent": ["error", 2],
27
26
  "eofline": 0,
28
27
  "arrow-parens": 0,
29
28
  "ordered-imports": 0,
package/CHANGELOG.md CHANGED
@@ -1,3 +1,42 @@
1
+ ## 0.10.1 (2022-06-01)
2
+
3
+ ### Fix
4
+
5
+ - lint issue
6
+
7
+ ## 0.10.0 (2022-06-01)
8
+
9
+ ### Fix
10
+
11
+ - remove useless import
12
+ - types
13
+ - error message system
14
+ - remove old deps
15
+ - add back limit in upload
16
+ - right issue in cli
17
+ - upload issue
18
+ - upload
19
+ - add method
20
+ - replace all console.error by program exit
21
+ - lint + do set
22
+
23
+ ## 0.9.0 (2022-05-24)
24
+
25
+ ### Fix
26
+
27
+ - supa config
28
+ - typing issues
29
+
30
+ ### Feat
31
+
32
+ - convert to supabase edge functions
33
+
34
+ ## 0.8.6 (2022-05-11)
35
+
36
+ ### Fix
37
+
38
+ - typo
39
+
1
40
  ## 0.8.5 (2022-05-11)
2
41
 
3
42
  ### Fix
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
1
  #!/usr/bin/env node
2
- (()=>{"use strict";var e={548:function(e,o,t){var r=this&&this.__awaiter||function(e,o,t,r){return new(t||(t=Promise))((function(a,n){function i(e){try{s(r.next(e))}catch(e){n(e)}}function p(e){try{s(r.throw(e))}catch(e){n(e)}}function s(e){var o;e.done?a(e.value):(o=e.value,o instanceof t?o:new t((function(e){e(o)}))).then(i,p)}s((r=r.apply(e,o||[])).next())}))},a=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(o,"__esModule",{value:!0}),o.addApp=void 0;const n=t(778),i=a(t(167)),p=a(t(867)),s=t(304),l=t(147),d=t(470),c=t(11),u=t(233);o.addApp=(e,o)=>r(void 0,void 0,void 0,(function*(){var t,r;let{name:a,icon:f}=o;const{apikey:h}=o;let v,g;try{v=yield(0,n.loadConfig)()}catch(e){s.program.error("No capacitor config file found, run `cap init` first")}e=e||(null===(t=null==v?void 0:v.app)||void 0===t?void 0:t.appId),a=a||(null===(r=null==v?void 0:v.app)||void 0===r?void 0:r.appName)||"Unknown",f=f||"resources/icon.png",h||s.program.error("Missing API key, you need to provide a API key to add your app"),e&&a||s.program.error("Missing argument, you need to provide a appid and a name, or be in a capacitor project"),console.log(`Add ${e} to Capgo`);try{console.log("Adding...");const o={appid:e,name:a};if(f&&(0,d.existsSync)(f)){const e=(0,l.readFileSync)(f),t=(0,c.getType)(f);o.icon=e.toString("base64"),o.iconType=t}g=yield(0,i.default)({method:"POST",url:`${u.host}/api/add`,data:o,validateStatus:()=>!0,headers:{authorization:h}})}catch(e){s.program.error(`Network Error \n${p.default.render(e.response.data)}`)}g&&200===g.status||s.program.error(`Server Error \n${p.default.render(g.data)}`),console.log("App added to server, you can upload a version now")}))},453:function(e,o,t){var r=this&&this.__awaiter||function(e,o,t,r){return new(t||(t=Promise))((function(a,n){function i(e){try{s(r.next(e))}catch(e){n(e)}}function p(e){try{s(r.throw(e))}catch(e){n(e)}}function s(e){var o;e.done?a(e.value):(o=e.value,o instanceof t?o:new t((function(e){e(o)}))).then(i,p)}s((r=r.apply(e,o||[])).next())}))},a=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(o,"__esModule",{value:!0}),o.deleteApp=void 0;const n=t(778),i=a(t(167)),p=a(t(867)),s=t(304),l=t(233);o.deleteApp=(e,o)=>r(void 0,void 0,void 0,(function*(){var t;const{apikey:r,version:a}=o;let d,c;try{d=yield(0,n.loadConfig)()}catch(e){s.program.error("No capacitor config file found, run `cap init` first")}e=e||(null===(t=null==d?void 0:d.app)||void 0===t?void 0:t.appId),r||s.program.error("Missing API key, you need to provide an API key to delete your app"),e||s.program.error("Missing argument, you need to provide a appid, or be in a capacitor project"),console.log(`Delete ${e} to Capgo`);try{console.log("Deleting..."),c=yield(0,i.default)({method:"POST",url:`${l.host}/api/delete`,data:{appid:e,version:a},validateStatus:()=>!0,headers:{authorization:r}})}catch(e){s.program.error(`Network Error \n${p.default.render(e.response.data)}`)}c&&200===c.status||s.program.error(`Server Error \n${p.default.render(c.data)}`),console.log("App deleted to server")}))},473:function(e,o,t){var r=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(o,"__esModule",{value:!0});const a=t(304),n=t(548),i=t(453),p=t(666),s=t(310),l=r(t(598));a.program.version(l.default.version).command("add [appid]").alias("a").action(n.addApp).option("-n, --name <name>","app name").option("-i, --icon <icon>","app icon path").option("-a, --apikey <apikey>","apikey to link to your account"),a.program.command("upload [appid]").alias("u").action(s.uploadVersion).option("-a, --apikey <apikey>","apikey to link to your account").option("-p, --path <path>","path of the file to upload").option("-c, --channel <channel>","channel to link to").option("-e, --external <url>","link to external url intead of upload to capgo cloud").option("-f, --format <base64|hex|binary|utf8>","choose the upload format default base64").option("-v, --version <version>","version number of the file to upload"),a.program.command("set [appid]").alias("s").action(p.setChannel).option("-c, --channel <channel>","channel to link to").option("-v, --version <version>","version number of the file to upload").option("-s, --state <state>","set the state of the channel, public or private").option("-a, --apikey <apikey>","apikey to link to your account"),a.program.description("Manage package and version in capgo Cloud").command("delete [appid]").alias("a").action(i.deleteApp).option("-a, --apikey <apikey>","apikey to link to your account").option("-v, --version <version>","version number of the app to delete"),a.program.parse(process.argv)},666:function(e,o,t){var r=this&&this.__awaiter||function(e,o,t,r){return new(t||(t=Promise))((function(a,n){function i(e){try{s(r.next(e))}catch(e){n(e)}}function p(e){try{s(r.throw(e))}catch(e){n(e)}}function s(e){var o;e.done?a(e.value):(o=e.value,o instanceof t?o:new t((function(e){e(o)}))).then(i,p)}s((r=r.apply(e,o||[])).next())}))},a=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(o,"__esModule",{value:!0}),o.setChannel=void 0;const n=t(778),i=a(t(167)),p=a(t(867)),s=t(304),l=t(233);o.setChannel=(e,o)=>r(void 0,void 0,void 0,(function*(){var t;const{apikey:r,version:a,state:d,channel:c="dev"}=o;let u,f,h;try{u=yield(0,n.loadConfig)()}catch(e){s.program.error("No capacitor config file found, run `cap init` first")}e=e||(null===(t=null==u?void 0:u.app)||void 0===t?void 0:t.appId),"public"!==d&&"private"!==d||(h="public"===d),r||s.program.error("Missing API key, you need to provide a API key to add your app"),e||s.program.error("Missing argument, you need to provide a appid, or be in a capacitor project"),a||h||s.program.error("Missing argument, you need to provide a state or a version"),a?console.log(`Set ${c} to @${a} in ${e}`):console.log(`Set${c} to @${d} in ${e}`);try{f=yield(0,i.default)({method:"POST",url:`${l.host}/api/channel`,data:{version:a,public:h,appid:e,channel:c},validateStatus:()=>!0,headers:{authorization:r}})}catch(e){s.program.error(`Network Error \n${p.default.render(e.response.data)}`)}f&&200===f.status||s.program.error(`Server Error \n${p.default.render(f.data)}`),a?console.log("Done ✅"):console.log(`You can use now is channel in your app with the url: ${l.host}/api/latest?appid=${e}&channel=${c}`)}))},310:function(e,o,t){var r=this&&this.__awaiter||function(e,o,t,r){return new(t||(t=Promise))((function(a,n){function i(e){try{s(r.next(e))}catch(e){n(e)}}function p(e){try{s(r.throw(e))}catch(e){n(e)}}function s(e){var o;e.done?a(e.value):(o=e.value,o instanceof t?o:new t((function(e){e(o)}))).then(i,p)}s((r=r.apply(e,o||[])).next())}))},a=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(o,"__esModule",{value:!0}),o.uploadVersion=void 0;const n=t(778),i=a(t(844)),p=a(t(167)),s=a(t(867)),l=t(304),d=a(t(295)),c=a(t(188)),u=t(233);(0,c.default)(p.default,{retries:3,retryDelay:c.default.exponentialDelay});const f=1048576;var h;!function(e){e.uft8="utf8",e.base64="base64",e.hex="hex",e.binary="binary"}(h||(h={}));const v=h.binary,g=(e,o)=>e<o?e:Math.floor(e/o),y={base64:e=>Math.floor(4*e/3),hex:e=>Math.floor(2*e),binary:e=>e,utf8:e=>e},m=(e,o)=>r(void 0,void 0,void 0,(function*(){return yield(0,p.default)({method:"POST",url:u.hostUpload,data:e,validateStatus:()=>!0,headers:{"Content-Type":"application/json",apikey:o,authorization:`Bearer ${u.supaAnon}`}})}));o.uploadVersion=(e,o)=>r(void 0,void 0,void 0,(function*(){var t,r,a,c,b,k;let{version:x,path:w,channel:_}=o;const{apikey:$,external:M,format:A}=o;let I;_=_||"dev";let N=v;A in h&&(N=A);try{I=yield(0,n.loadConfig)()}catch(e){l.program.error("No capacitor config file found, run `cap init` first")}if(e=e||(null===(t=null==I?void 0:I.app)||void 0===t?void 0:t.appId),x=x||(null===(a=null===(r=null==I?void 0:I.app)||void 0===r?void 0:r.package)||void 0===a?void 0:a.version),w=w||(null===(c=null==I?void 0:I.app)||void 0===c?void 0:c.webDir),$||l.program.error("Missing API key, you need to provide a API key to add your app"),e&&x&&w||l.program.error("Missing argument, you need to provide a appid and a version and a path, or be in a capacitor project"),console.log(`Upload ${e}@${x} started from path "${w}" to Capgo cloud`),M)try{const o=yield(0,p.default)({method:"POST",url:u.hostUpload,data:{version:x,appid:e,channel:_,external:M},validateStatus:()=>!0,headers:{"Content-Type":"application/json",apikey:$,authorization:`Bearer ${u.supaAnon}`}});200!==o.status&&l.program.error(`Server Error \n${s.default.render((null==o?void 0:o.data)||"")}`)}catch(e){e.response?l.program.error(`Network Error \n${s.default.render((null===(b=e.response)||void 0===b?void 0:b.data)||"")}`):l.program.error(`Network Error \n${s.default.render(e||"")}`)}else{const o=new d.default.SingleBar({format:"Uploading: [{bar}] {percentage}% | ETA: {eta}s | {value}/{total} Mb"},d.default.Presets.shades_grey);try{const t=new i.default;t.addLocalFolder(w);const r=t.toBuffer().toString(N),a=r.length,n=Math.floor(a/y[N](f)),p=g(a,y[N](f))>1?(P=a,S=y[N](f),Math.floor(P/g(P,S))):a;n>30&&l.program.error(`The app is too big, the limit is 30 Mb, your is ${n} Mb`),n>25&&console.log(`WARNING !!\nThe app size is ${n} Mb, the limit is 30 Mb`);const d=[];for(let e=0;e<r.length;e+=p)d.push(r.slice(e,e+p));let c;o.start(d.length,0,{speed:"N/A"});for(let t=0;t<d.length;t+=1){const r=yield m({version:x,appid:e,fileName:c,channel:_,format:N,app:d[t],isMultipart:d.length>1,chunk:t+1,totalChunks:d.length},$);200!==r.status&&(o.stop(),l.program.error(`Server Error \n${s.default.render((null==r?void 0:r.data)||"")}`)),o.update(t+1),c=r.data.fileName}o.stop()}catch(e){o.stop(),e.response?l.program.error(`Network Error \n${s.default.render((null===(k=e.response)||void 0===k?void 0:k.data)||"")}`):l.program.error(`Network Error \n${s.default.render(e||"")}`)}}var P,S;console.log("App uploaded to server"),console.log(`Try it in mobile app: ${u.host}/app_mobile`),console.log(`Or set the channel ${_} as public here: ${u.hostWeb}/app/package/${e}`),console.log("To use with live update in your own app")}))},233:(e,o)=>{Object.defineProperty(o,"__esModule",{value:!0}),o.supaAnon=o.hostUpload=o.hostWeb=o.host=void 0,o.host="https://capgo.app",o.hostWeb="https://web.capgo.app",o.hostUpload="https://xvwzpoazmxkqosrdewyv.functions.supabase.co/upload",o.supaAnon="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJyb2xlIjoiYW5vbiIsImlhdCI6MTYzNzgwNTAwOSwiZXhwIjoxOTUzMzgxMDA5fQ.8tgID1d4jodPwuo_fz4KHN4o1XKB9fnqyt0_GaJSj-w"},778:e=>{e.exports=require("@capacitor/cli/dist/config")},844:e=>{e.exports=require("adm-zip")},167:e=>{e.exports=require("axios")},188:e=>{e.exports=require("axios-retry")},295:e=>{e.exports=require("cli-progress")},304:e=>{e.exports=require("commander")},470:e=>{e.exports=require("fs-extra")},11:e=>{e.exports=require("mime")},867:e=>{e.exports=require("prettyjson")},147:e=>{e.exports=require("fs")},598:e=>{e.exports=JSON.parse('{"name":"@capgo/cli","version":"0.8.5","description":"A CLI to upload to capgo servers","main":"dist/index.js","bin":{"capgo":"dist/index.js"},"repository":{"type":"git","url":"git+https://github.com/Cap-go/capgo-cli.git"},"bugs":{"url":"https://github.com/Cap-go/capgo-cli/issues"},"keywords":["appflow alternative","ionic","capacitor","auto update","live update","capgo","cli","upload","capgo-cli"],"scripts":{"dev":"set NODE_ENV=development&& npx webpack --config webpack.config.js","no-debug":"node dist/index.js","build":"set NODE_ENV=production&& npx webpack --config webpack.config.js","pack":"pkg","lint":"eslint . --ext .ts --fix"},"author":"github.com/riderx","license":"Apache 2.0","dependencies":{"@capacitor/cli":"3.5.1","adm-zip":"^0.5.9","axios":"0.27.2","axios-retry":"^3.2.5","cli-progress":"3.11.0","commander":"9.2.0","form-data":"^4.0.0","fs-extra":"10.1.0","mime":"^3.0.0","node-stream-zip":"^1.15.0","prettyjson":"^1.2.5","upath":"^2.0.1"},"devDependencies":{"@types/adm-zip":"0.5.0","@types/fs-extra":"^9.0.13","@types/node":"^17.0.31","@typescript-eslint/eslint-plugin":"5.22.0","@typescript-eslint/parser":"5.22.0","eslint":"8.14.0","eslint-config-airbnb-base":"^15.0.0","eslint-config-prettier":"^8.5.0","eslint-import-resolver-typescript":"2.7.1","eslint-plugin-import":"2.26.0","eslint-plugin-prettier":"^4.0.0","git-format-staged":"3.0.0","husky":"^7.0.4","nodemon":"2.0.16","pkg":"5.6.0","prettier":"2.6.2","ts-loader":"^9.3.0","ts-node":"^10.7.0","tsconfig-paths":"4.0.0","typescript":"4.6.4","webpack":"5.72.0","webpack-cli":"^4.9.2","webpack-node-externals":"^3.0.0"}}')}},o={};!function t(r){var a=o[r];if(void 0!==a)return a.exports;var n=o[r]={exports:{}};return e[r].call(n.exports,n,n.exports,t),n.exports}(473)})();
2
+ (()=>{"use strict";var e={548:function(e,o,r){var t=this&&this.__awaiter||function(e,o,r,t){return new(r||(r=Promise))((function(a,n){function i(e){try{s(t.next(e))}catch(e){n(e)}}function p(e){try{s(t.throw(e))}catch(e){n(e)}}function s(e){var o;e.done?a(e.value):(o=e.value,o instanceof r?o:new r((function(e){e(o)}))).then(i,p)}s((t=t.apply(e,o||[])).next())}))};Object.defineProperty(o,"__esModule",{value:!0}),o.addApp=void 0;const a=r(304),n=r(113),i=r(147),p=r(470),s=r(11),d=r(233),l="assets/icon.png";o.addApp=(e,o)=>t(void 0,void 0,void 0,(function*(){var r,t;let{name:c,icon:u}=o;const{apikey:m}=o,g=yield(0,d.getConfig)();e=e||(null===(r=null==g?void 0:g.app)||void 0===r?void 0:r.appId),c=c||(null===(t=null==g?void 0:g.app)||void 0===t?void 0:t.appName)||"Unknown",u=u||"resources/icon.png",m||a.program.error("Missing API key, you need to provide a API key to add your app"),e&&c||a.program.error("Missing argument, you need to provide a appid and a name, or be in a capacitor project"),console.log(`Add ${e} to Capgo`);const v=(0,d.createSupabaseClient)(m),{data:f,error:y}=yield v.rpc("is_allowed_capgkey",{apikey:m,keymode:["write","all"]});if(!f||y)return void console.log("Invalid API key or insufisant rights");let h,_;console.log("Adding..."),u&&(0,p.existsSync)(u)?(h=(0,i.readFileSync)(u),_=(0,s.getType)(u)||"image/png",console.warn(`Found app icon ${u}`)):(0,p.existsSync)(l)?(h=(0,i.readFileSync)(l),_=(0,s.getType)(l)||"image/png",console.warn(`Found app icon ${l}`)):console.warn(`Cannot find app icon in any of the following locations: ${u}, ${l}`);const{data:k,error:b}=yield v.rpc("get_user_id",{apikey:m}),$=k?k.toString():"";$&&!b||a.program.error(`Cannot verify user ${(0,d.formatError)(b)}`);const{data:w,error:C}=yield v.rpc("exist_app",{appid:e,apikey:m});(w||C)&&a.program.error(`App already exists ${(0,d.formatError)(C)}`);const x=`icon_${(0,n.randomUUID)()}`;let I="https://xvwzpoazmxkqosrdewyv.supabase.co/storage/v1/object/public/images/capgo.png";if(h&&_){const{error:o}=yield v.storage.from(`images/${$}/${e}`).upload(x,h,{contentType:_});o&&a.program.error(`Could not add app ${(0,d.formatError)(o)}`);const{data:r}=yield v.storage.from(`images/${$}/${e}`).getPublicUrl(x);I=(null==r?void 0:r.publicURL)||I}const{error:q}=yield v.from("apps").insert({icon_url:I,user_id:$,name:c,app_id:e},{returning:"minimal"});q&&a.program.error(`Could not add app ${(0,d.formatError)(q)}`),console.log("App added to server, you can upload a version now")}))},453:function(e,o,r){var t=this&&this.__awaiter||function(e,o,r,t){return new(r||(r=Promise))((function(a,n){function i(e){try{s(t.next(e))}catch(e){n(e)}}function p(e){try{s(t.throw(e))}catch(e){n(e)}}function s(e){var o;e.done?a(e.value):(o=e.value,o instanceof r?o:new r((function(e){e(o)}))).then(i,p)}s((t=t.apply(e,o||[])).next())}))};Object.defineProperty(o,"__esModule",{value:!0}),o.deleteApp=void 0;const a=r(304),n=r(233);o.deleteApp=(e,o)=>t(void 0,void 0,void 0,(function*(){var r;const{apikey:t,version:i}=o,p=yield(0,n.getConfig)();e=e||(null===(r=null==p?void 0:p.app)||void 0===r?void 0:r.appId),t||a.program.error("Missing API key, you need to provide an API key to delete your app"),e||a.program.error("Missing argument, you need to provide a appid, or be in a capacitor project"),console.log(`Delete ${e} to Capgo`);const s=(0,n.createSupabaseClient)(t),{data:d,error:l}=yield s.rpc("is_allowed_capgkey",{apikey:t,keymode:["write","all"],app_id:e});if(!d||l)return void console.log("Invalid API key or insufisant rights");const{data:c,error:u}=yield s.rpc("get_user_id",{apikey:t}),m=c?c.toString():"";m&&!u||a.program.error(`Cannot verify user ${(0,n.formatError)(u)}`);const{data:g,error:v}=yield s.rpc("exist_app",{appid:e,apikey:t});if(g&&!v||a.program.error("No permission to delete"),i){const{data:o,error:r}=yield s.from("app_versions").select().eq("app_id",e).eq("user_id",m).eq("name",i).eq("deleted",!1);o&&o.length&&!r||a.program.error(`Version ${e}@${i} don't exist ${(0,n.formatError)(r)}`);const{data:t,error:p}=yield s.from("channels").select().eq("app_id",e).eq("created_by",m).eq("version",o[0].id);(t&&t.length||p)&&a.program.error(`Version ${e}@${i} is used in a channel, unlink it first ${(0,n.formatError)(p)}`);const{data:d,error:l}=yield s.from("devices_override").select().eq("app_id",e).eq("version",o[0].id);(d&&d.length||l)&&a.program.error(`Version ${e} @${i} is used in a device override, unlink it first ${(0,n.formatError)(l)}`);const{error:c}=yield s.storage.from("apps").remove([`${m} /${e}/versions / ${o[0].bucket_id} `]);c&&a.program.error(`Something went wrong when trying to delete ${e} @${i} ${c} `);const{error:u}=yield s.from("app_versions").update({deleted:!0}).eq("app_id",e).eq("name",i).eq("user_id",m);return u&&a.program.error(`App ${e} @${i} not found in database ${u} `),void console.log("App version deleted from server")}const{data:f,error:y}=yield s.from("app_versions").select().eq("app_id",e).eq("user_id",m);if(y&&a.program.error(`App ${e} not found in database ${y} `),f&&f.length){const o=f.map((o=>`${m} /${e}/versions / ${o.bucket_id} `)),{error:r}=yield s.storage.from("apps").remove(o);r&&a.program.error(`Cannot delete stored version for app ${e} from storage ${r} `)}const{error:h}=yield s.from("app_versions").delete().eq("app_id",e).eq("user_id",m);h&&a.program.error(`Cannot delete version for app ${e} from database ${h} `);const{error:_}=yield s.from("apps").delete().eq("app_id",e).eq("user_id",m);_&&a.program.error(`Cannot delete from database ${_} `),console.log("App deleted from server")}))},473:function(e,o,r){var t=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(o,"__esModule",{value:!0});const a=r(304),n=r(548),i=r(453),p=r(666),s=r(310),d=t(r(598));a.program.version(d.default.version).command("add [appid]").alias("a").action(n.addApp).option("-n, --name <name>","app name").option("-i, --icon <icon>","app icon path").option("-a, --apikey <apikey>","apikey to link to your account"),a.program.command("upload [appid]").alias("u").action(s.uploadVersion).option("-a, --apikey <apikey>","apikey to link to your account").option("-p, --path <path>","path of the file to upload").option("-c, --channel <channel>","channel to link to").option("-e, --external <url>","link to external url intead of upload to capgo cloud").option("-f, --format <base64|hex|binary|utf8>","choose the upload format default base64").option("-v, --version <version>","version number of the file to upload"),a.program.command("set [appid]").alias("s").action(p.setChannel).option("-c, --channel <channel>","channel to link to").option("-v, --version <version>","version number of the file to upload").option("-s, --state <state>","set the state of the channel, public or private").option("-a, --apikey <apikey>","apikey to link to your account"),a.program.description("Manage package and version in capgo Cloud").command("delete [appid]").alias("a").action(i.deleteApp).option("-a, --apikey <apikey>","apikey to link to your account").option("-v, --version <version>","version number of the app to delete"),a.program.parse(process.argv)},666:function(e,o,r){var t=this&&this.__awaiter||function(e,o,r,t){return new(r||(r=Promise))((function(a,n){function i(e){try{s(t.next(e))}catch(e){n(e)}}function p(e){try{s(t.throw(e))}catch(e){n(e)}}function s(e){var o;e.done?a(e.value):(o=e.value,o instanceof r?o:new r((function(e){e(o)}))).then(i,p)}s((t=t.apply(e,o||[])).next())}))};Object.defineProperty(o,"__esModule",{value:!0}),o.setChannel=void 0;const a=r(304),n=r(233);o.setChannel=(e,o)=>t(void 0,void 0,void 0,(function*(){var r,t,i;let{version:p}=o;const{apikey:s,state:d,channel:l="dev"}=o,c=yield(0,n.getConfig)();let u;e=e||(null===(r=null==c?void 0:c.app)||void 0===r?void 0:r.appId),p=p||(null===(i=null===(t=null==c?void 0:c.app)||void 0===t?void 0:t.package)||void 0===i?void 0:i.version),"public"!==d&&"private"!==d||(u="public"===d),s||a.program.error("Missing API key, you need to provide a API key to add your app"),e||a.program.error("Missing argument, you need to provide a appid, or be in a capacitor project"),p||u||a.program.error("Missing argument, you need to provide a state or a version"),p?console.log(`Set ${l} to @${p} in ${e}`):console.log(`Set${l} to @${d} in ${e}`);try{const o=(0,n.createSupabaseClient)(s),{data:r,error:t}=yield o.rpc("is_allowed_capgkey",{apikey:s,keymode:["write","all"],app_id:e});r&&!t||a.program.error("Invalid API key or insufisant rights");const{data:i,error:d}=yield o.rpc("get_user_id",{apikey:s}),c=i?i.toString():"";c&&!d||a.program.error("Cannot verify user");const m={created_by:c,app_id:e,name:l};if(p){const{data:r,error:t}=yield o.from("app_versions").select().eq("app_id",e).eq("name",p).eq("user_id",c).eq("deleted",!1);!t&&r&&r.length||a.program.error(`Cannot find version ${p}`),m.version=r[0].id}void 0!==u&&(m.public=u);try{const{error:e}=yield(0,n.updateOrCreateChannel)(o,m,s);e&&a.program.error(`Cannot set channel ${(0,n.formatError)(e)}`)}catch(e){a.program.error(`Cannot set channel ${(0,n.formatError)(e)}`)}}catch(e){a.program.error(`Unknow error ${(0,n.formatError)(e)}`)}p?console.log("Done ✅"):console.log(`You can use now is channel in your app with the url: ${n.host}/api/latest?appid=${e}&channel=${l}`)}))},310:function(e,o,r){var t=this&&this.__awaiter||function(e,o,r,t){return new(r||(r=Promise))((function(a,n){function i(e){try{s(t.next(e))}catch(e){n(e)}}function p(e){try{s(t.throw(e))}catch(e){n(e)}}function s(e){var o;e.done?a(e.value):(o=e.value,o instanceof r?o:new r((function(e){e(o)}))).then(i,p)}s((t=t.apply(e,o||[])).next())}))},a=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(o,"__esModule",{value:!0}),o.uploadVersion=void 0;const n=a(r(844)),i=r(304),p=r(113),s=a(r(295)),d=r(233);o.uploadVersion=(e,o)=>t(void 0,void 0,void 0,(function*(){var r,t,a,l;let{version:c,path:u,channel:m}=o;const{apikey:g,external:v}=o;m=m||"dev";const f=yield(0,d.getConfig)();e=e||(null===(r=null==f?void 0:f.app)||void 0===r?void 0:r.appId),c=c||(null===(a=null===(t=null==f?void 0:f.app)||void 0===t?void 0:t.package)||void 0===a?void 0:a.version),u=u||(null===(l=null==f?void 0:f.app)||void 0===l?void 0:l.webDir),g||i.program.error("Missing API key, you need to provide a API key to add your app"),e&&c&&u||i.program.error("Missing argument, you need to provide a appid and a version and a path, or be in a capacitor project"),console.log(`Upload ${e}@${c} started from path "${u}" to Capgo cloud`);const y=(0,d.createSupabaseClient)(g),h=new s.default.MultiBar({clearOnComplete:!1,hideCursor:!0},s.default.Presets.shades_grey),_=h.create(7,0,{format:"Uploading: [{bar}] {percentage}% | ETA: {eta}s | {value}/{total} Part"},s.default.Presets.shades_grey);_.start(7,0,{speed:"N/A"});const{data:k,error:b}=yield y.rpc("is_allowed_capgkey",{apikey:g,keymode:["upload","write","all"],app_id:e});k&&!b||(h.stop(),i.program.error(`Invalid API key or insufisant rights ${(0,d.formatError)(b)}`)),_.increment();const{data:$,error:w}=yield y.rpc("get_user_id",{apikey:g}),C=$?$.toString():"";C&&!w||(h.stop(),i.program.error(`Cannot verify user ${(0,d.formatError)(w)}`)),_.increment();const{data:x,error:I}=yield y.rpc("exist_app",{appid:e,apikey:g});if(x&&!I||(h.stop(),i.program.error(`Cannot find app ${e} in your account \n${(0,d.formatError)(I)}`)),_.increment(),v)v&&!v.startsWith("https://")&&(h.stop(),i.program.error(`External link should should start with "https://" current is "${v}"`));else{const o=new n.default;o.addLocalFolder(u);const r=o.toBuffer(),t=Math.floor(r.byteLength/1024/1024),a=`apps/${C}/${e}/versions`,s=(0,p.randomUUID)();_.increment(),t>30&&(h.stop(),i.program.error(`The app is too big, the limit is 30 Mb, your is ${t} Mb`)),t>25&&h.log(`WARNING !!\nThe app size is ${t} Mb, the limit is 30 Mb\n`);const{error:l}=yield y.storage.from(a).upload(s,r,{contentType:"application/zip"});l&&(h.stop(),i.program.error(`Cannot upload ${(0,d.formatError)(l)}`))}_.increment();const q=(0,p.randomUUID)(),{data:A,error:M}=yield(0,d.updateOrCreateVersion)(y,{bucket_id:v?void 0:q,user_id:C,name:c,app_id:e,external_url:v},g);if(M&&(h.stop(),i.program.error(`Cannot add version ${(0,d.formatError)(M)}`)),_.increment(),A&&A.length){const{error:o}=yield(0,d.updateOrCreateChannel)(y,{name:m,app_id:e,created_by:C,version:A[0].id},g);o&&h.log("Cannot set version with upload key, use key with more rights for that\n")}else h.log("Cannot set version with upload key, use key with more rights for that\n");_.increment(),h.stop(),console.log("App uploaded to server"),console.log(`Try it in mobile app: ${d.host}/app_mobile`),console.log(`Or set the channel ${m} as public here: ${d.hostWeb}/app/package/${e}`),console.log("To use with live update in your own app")}))},233:function(e,o,r){var t=this&&this.__awaiter||function(e,o,r,t){return new(r||(r=Promise))((function(a,n){function i(e){try{s(t.next(e))}catch(e){n(e)}}function p(e){try{s(t.throw(e))}catch(e){n(e)}}function s(e){var o;e.done?a(e.value):(o=e.value,o instanceof r?o:new r((function(e){e(o)}))).then(i,p)}s((t=t.apply(e,o||[])).next())}))},a=this&&this.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(o,"__esModule",{value:!0}),o.updateOrCreateChannel=o.updateOrCreateVersion=o.getConfig=o.formatError=o.createSupabaseClient=o.supaAnon=o.hostSupa=o.hostWeb=o.host=void 0;const n=r(778),i=r(304),p=r(885),s=a(r(867));o.host="https://capgo.app",o.hostWeb="https://web.capgo.app",o.hostSupa="https://aucsybvnhavogdmzwtcw.supabase.co",o.supaAnon="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZSIsInJlZiI6ImF1Y3N5YnZuaGF2b2dkbXp3dGN3Iiwicm9sZSI6ImFub24iLCJpYXQiOjE2NTM1ODcxNjgsImV4cCI6MTk2OTE2MzE2OH0.8FKKJqiGgoVA3p9GH5wvnbWkWywIxVLqQyZFhupZ7C4",o.createSupabaseClient=e=>(0,p.createClient)(o.hostSupa,o.supaAnon,{headers:{capgkey:e}}),o.formatError=e=>e?`\n${s.default.render(e)}`:"",o.getConfig=()=>t(void 0,void 0,void 0,(function*(){let e;try{e=yield(0,n.loadConfig)()}catch(e){i.program.error("No capacitor config file found, run `cap init` first")}return e})),o.updateOrCreateVersion=(e,o,r)=>t(void 0,void 0,void 0,(function*(){const{data:t,error:a}=yield e.rpc("exist_app_versions",{appid:o.app_id,name_version:o.name,apikey:r});return t&&!a?(o.deleted=!1,e.from("app_versions").update(o,{returning:"minimal"}).eq("app_id",o.app_id).eq("name",o.name)):e.from("app_versions").insert(o,{returning:"minimal"})})),o.updateOrCreateChannel=(e,o,r)=>t(void 0,void 0,void 0,(function*(){if(!o.app_id||!o.name||!o.created_by)return console.error("missing app_id, name, or created_by"),Promise.reject(new Error("missing app_id, name, or created_by"));const{data:t,error:a}=yield e.rpc("exist_channel",{appid:o.app_id,name_channel:o.name,apikey:r});return t&&!a?e.from("channels").update(o,{returning:"minimal"}).eq("app_id",o.app_id).eq("name",o.name).eq("created_by",o.created_by):e.from("channels").insert(o,{returning:"minimal"})}))},778:e=>{e.exports=require("@capacitor/cli/dist/config")},885:e=>{e.exports=require("@supabase/supabase-js")},844:e=>{e.exports=require("adm-zip")},295:e=>{e.exports=require("cli-progress")},304:e=>{e.exports=require("commander")},470:e=>{e.exports=require("fs-extra")},11:e=>{e.exports=require("mime")},867:e=>{e.exports=require("prettyjson")},113:e=>{e.exports=require("crypto")},147:e=>{e.exports=require("fs")},598:e=>{e.exports=JSON.parse('{"name":"@capgo/cli","version":"0.10.1","description":"A CLI to upload to capgo servers","main":"dist/index.js","bin":{"capgo":"dist/index.js"},"repository":{"type":"git","url":"git+https://github.com/Cap-go/capgo-cli.git"},"bugs":{"url":"https://github.com/Cap-go/capgo-cli/issues"},"keywords":["appflow alternative","ionic","capacitor","auto update","live update","capgo","cli","upload","capgo-cli"],"scripts":{"dev":"set NODE_ENV=development&& npx webpack --config webpack.config.js","no-debug":"node dist/index.js","build":"set NODE_ENV=production&& npx webpack --config webpack.config.js","pack":"pkg","test_rls":"ts-node ./test/test_headers_rls.ts","lint":"eslint . --ext .ts --fix"},"author":"github.com/riderx","license":"Apache 2.0","dependencies":{"@capacitor/cli":"3.5.1","@supabase/supabase-js":"^1.35.3","adm-zip":"^0.5.9","cli-progress":"3.11.0","commander":"9.2.0","form-data":"^4.0.0","fs-extra":"10.1.0","mime":"^3.0.0","node-stream-zip":"^1.15.0","prettyjson":"^1.2.5","upath":"^2.0.1"},"devDependencies":{"@types/adm-zip":"0.5.0","@types/cli-progress":"^3.11.0","@types/fs-extra":"^9.0.13","@types/mime":"^2.0.3","@types/node":"^17.0.31","@types/prettyjson":"^0.0.30","@typescript-eslint/eslint-plugin":"5.22.0","@typescript-eslint/parser":"5.22.0","eslint":"8.14.0","eslint-config-airbnb-base":"^15.0.0","eslint-config-prettier":"^8.5.0","eslint-import-resolver-typescript":"2.7.1","eslint-plugin-import":"2.26.0","eslint-plugin-prettier":"^4.0.0","git-format-staged":"3.0.0","husky":"^7.0.4","nodemon":"2.0.16","pkg":"5.6.0","prettier":"2.6.2","ts-loader":"^9.3.0","ts-node":"^10.7.0","tsconfig-paths":"4.0.0","typescript":"4.6.4","webpack":"5.72.0","webpack-cli":"^4.9.2","webpack-node-externals":"^3.0.0"}}')}},o={};!function r(t){var a=o[t];if(void 0!==a)return a.exports;var n=o[t]={exports:{}};return e[t].call(n.exports,n,n.exports,r),n.exports}(473)})();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/cli",
3
- "version": "0.8.5",
3
+ "version": "0.10.1",
4
4
  "description": "A CLI to upload to capgo servers",
5
5
  "main": "dist/index.js",
6
6
  "bin": {
@@ -29,15 +29,15 @@
29
29
  "no-debug": "node dist/index.js",
30
30
  "build": "set NODE_ENV=production&& npx webpack --config webpack.config.js",
31
31
  "pack": "pkg",
32
+ "test_rls": "ts-node ./test/test_headers_rls.ts",
32
33
  "lint": "eslint . --ext .ts --fix"
33
34
  },
34
35
  "author": "github.com/riderx",
35
36
  "license": "Apache 2.0",
36
37
  "dependencies": {
37
38
  "@capacitor/cli": "3.5.1",
39
+ "@supabase/supabase-js": "^1.35.3",
38
40
  "adm-zip": "^0.5.9",
39
- "axios": "0.27.2",
40
- "axios-retry": "^3.2.5",
41
41
  "cli-progress": "3.11.0",
42
42
  "commander": "9.2.0",
43
43
  "form-data": "^4.0.0",
@@ -49,8 +49,11 @@
49
49
  },
50
50
  "devDependencies": {
51
51
  "@types/adm-zip": "0.5.0",
52
+ "@types/cli-progress": "^3.11.0",
52
53
  "@types/fs-extra": "^9.0.13",
54
+ "@types/mime": "^2.0.3",
53
55
  "@types/node": "^17.0.31",
56
+ "@types/prettyjson": "^0.0.30",
54
57
  "@typescript-eslint/eslint-plugin": "5.22.0",
55
58
  "@typescript-eslint/parser": "5.22.0",
56
59
  "eslint": "8.14.0",
package/src/bin/add.ts CHANGED
@@ -1,21 +1,21 @@
1
- import { loadConfig } from '@capacitor/cli/dist/config';
2
- import axios from 'axios';
3
- import prettyjson from 'prettyjson';
4
1
  import { program } from 'commander';
2
+ import { randomUUID } from 'crypto';
5
3
  import { readFileSync } from 'fs';
6
4
  import { existsSync } from 'fs-extra';
7
5
  import { getType } from 'mime';
8
- import { host } from './utils';
6
+ import { definitions } from './types_supabase'
7
+ import { getConfig, createSupabaseClient, formatError } from './utils';
9
8
 
10
- export const addApp = async (appid: string, options: any) => {
9
+ interface Options {
10
+ apikey: string;
11
+ name?: string;
12
+ icon?: string;
13
+ }
14
+ const newIconPath = "assets/icon.png"
15
+ export const addApp = async (appid: string, options: Options) => {
11
16
  let { name, icon } = options;
12
17
  const { apikey } = options;
13
- let config;
14
- try {
15
- config = await loadConfig();
16
- } catch (err) {
17
- program.error("No capacitor config file found, run `cap init` first");
18
- }
18
+ const config = await getConfig();
19
19
  appid = appid || config?.app?.appId
20
20
  name = name || config?.app?.appName || 'Unknown'
21
21
  icon = icon || "resources/icon.png" // default path for capacitor app
@@ -26,30 +26,84 @@ export const addApp = async (appid: string, options: any) => {
26
26
  program.error("Missing argument, you need to provide a appid and a name, or be in a capacitor project");
27
27
  }
28
28
  console.log(`Add ${appid} to Capgo`);
29
- let res;
30
- try {
31
- console.log('Adding...');
32
- const data: any = { appid, name }
33
- if (icon && existsSync(icon)) {
34
- const iconBuff = readFileSync(icon);
35
- const contentType = getType(icon);
36
- data.icon = iconBuff.toString('base64');
37
- data.iconType = contentType;
29
+
30
+ const supabase = createSupabaseClient(apikey)
31
+
32
+ // checking if user has access before uploading image
33
+ const { data: apiAccess, error: apiAccessError } = await supabase
34
+ .rpc('is_allowed_capgkey', { apikey, keymode: ['write', 'all'] })
35
+
36
+ if (!apiAccess || apiAccessError) {
37
+ console.log('Invalid API key or insufisant rights');
38
+ return
39
+ }
40
+
41
+ console.log('Adding...');
42
+ let iconBuff;
43
+ let iconType;
44
+
45
+ if (icon && existsSync(icon)) {
46
+ iconBuff = readFileSync(icon);
47
+ const contentType = getType(icon);
48
+ iconType = contentType || 'image/png';
49
+ console.warn(`Found app icon ${icon}`);
50
+ }
51
+ else if (existsSync(newIconPath)) {
52
+ iconBuff = readFileSync(newIconPath);
53
+ const contentType = getType(newIconPath);
54
+ iconType = contentType || 'image/png';
55
+ console.warn(`Found app icon ${newIconPath}`);
56
+ } else {
57
+ console.warn(`Cannot find app icon in any of the following locations: ${icon}, ${newIconPath}`);
58
+ }
59
+
60
+ const { data: dataUser, error: userIdError } = await supabase
61
+ .rpc<string>('get_user_id', { apikey })
62
+
63
+ const userId = dataUser ? dataUser.toString() : '';
64
+
65
+ if (!userId || userIdError) {
66
+ program.error(`Cannot verify user ${formatError(userIdError)}`);
67
+ }
68
+
69
+ // check if app already exist
70
+ const { data: app, error: dbError0 } = await supabase
71
+ .rpc<string>('exist_app', { appid, apikey })
72
+ if (app || dbError0) {
73
+ program.error(`App already exists ${formatError(dbError0)}`)
74
+ }
75
+
76
+ const fileName = `icon_${randomUUID()}`
77
+ let signedURL = 'https://xvwzpoazmxkqosrdewyv.supabase.co/storage/v1/object/public/images/capgo.png'
78
+
79
+ // upload image if available
80
+ if (iconBuff && iconType) {
81
+ const { error } = await supabase.storage
82
+ .from(`images/${userId}/${appid}`)
83
+ .upload(fileName, iconBuff, {
84
+ contentType: iconType,
85
+ })
86
+ if (error) {
87
+ program.error(`Could not add app ${formatError(error)}`);
38
88
  }
39
- res = await axios({
40
- method: 'POST',
41
- url: `${host}/api/add`,
42
- data,
43
- validateStatus: () => true,
44
- headers: {
45
- 'authorization': apikey
46
- }
47
- })
48
- } catch (err) {
49
- program.error(`Network Error \n${prettyjson.render(err.response.data)}`);
50
- }
51
- if (!res || res.status !== 200) {
52
- program.error(`Server Error \n${prettyjson.render(res.data)}`);
89
+ const { data: signedURLData } = await supabase
90
+ .storage
91
+ .from(`images/${userId}/${appid}`)
92
+ .getPublicUrl(fileName)
93
+ signedURL = signedURLData?.publicURL || signedURL
94
+ }
95
+
96
+ // add app to db
97
+ const { error: dbError } = await supabase
98
+ .from<definitions['apps']>('apps')
99
+ .insert({
100
+ icon_url: signedURL,
101
+ user_id: userId,
102
+ name,
103
+ app_id: appid,
104
+ }, { returning: "minimal" })
105
+ if (dbError) {
106
+ program.error(`Could not add app ${formatError(dbError)}`);
53
107
  }
54
108
  console.log("App added to server, you can upload a version now")
55
109
  }
package/src/bin/delete.ts CHANGED
@@ -1,17 +1,15 @@
1
- import { loadConfig } from '@capacitor/cli/dist/config';
2
- import axios from 'axios';
3
- import prettyjson from 'prettyjson';
4
1
  import { program } from 'commander';
5
- import { host } from './utils';
2
+ import { getConfig, createSupabaseClient, formatError } from './utils';
3
+ import { definitions } from './types_supabase'
6
4
 
7
- export const deleteApp = async (appid: string, options: any) => {
5
+ interface Options {
6
+ apikey: string;
7
+ version: string;
8
+ }
9
+
10
+ export const deleteApp = async (appid: string, options: Options) => {
8
11
  const { apikey, version } = options;
9
- let config;
10
- try {
11
- config = await loadConfig();
12
- } catch (err) {
13
- program.error("No capacitor config file found, run `cap init` first");
14
- }
12
+ const config = await getConfig();
15
13
  appid = appid || config?.app?.appId
16
14
  if (!apikey) {
17
15
  program.error('Missing API key, you need to provide an API key to delete your app');
@@ -20,23 +18,125 @@ export const deleteApp = async (appid: string, options: any) => {
20
18
  program.error('Missing argument, you need to provide a appid, or be in a capacitor project');
21
19
  }
22
20
  console.log(`Delete ${appid} to Capgo`);
23
- let res;
24
- try {
25
- console.log('Deleting...');
26
- res = await axios({
27
- method: 'POST',
28
- url: `${host}/api/delete`,
29
- data: { appid, version },
30
- validateStatus: () => true,
31
- headers: {
32
- 'authorization': apikey
33
- }
34
- })
35
- } catch (err) {
36
- program.error(`Network Error \n${prettyjson.render(err.response.data)}`);
37
- }
38
- if (!res || res.status !== 200) {
39
- program.error(`Server Error \n${prettyjson.render(res.data)}`);
40
- }
41
- console.log("App deleted to server")
21
+
22
+ const supabase = createSupabaseClient(apikey)
23
+
24
+ // checking if user has access rights before deleting
25
+ const { data: apiAccess, error: apiAccessError } = await supabase
26
+ .rpc('is_allowed_capgkey', { apikey, keymode: ['write', 'all'], app_id: appid })
27
+
28
+ if (!apiAccess || apiAccessError) {
29
+ console.log('Invalid API key or insufisant rights');
30
+ return
31
+ }
32
+
33
+ const { data: dataUser, error: userIdError } = await supabase
34
+ .rpc<string>('get_user_id', { apikey })
35
+
36
+ const userId = dataUser ? dataUser.toString() : '';
37
+
38
+ if (!userId || userIdError) {
39
+ program.error(`Cannot verify user ${formatError(userIdError)}`);
40
+ }
41
+
42
+ const { data: app, error: dbError0 } = await supabase
43
+ .rpc<string>('exist_app', { appid, apikey })
44
+ if (!app || dbError0) {
45
+ program.error('No permission to delete')
46
+ }
47
+
48
+ if (version) {
49
+ const { data: versions, error: versionIdError } = await supabase
50
+ .from<definitions['app_versions']>('app_versions')
51
+ .select()
52
+ .eq('app_id', appid)
53
+ .eq('user_id', userId)
54
+ .eq('name', version)
55
+ .eq('deleted', false)
56
+ if (!versions || !versions.length || versionIdError) {
57
+ program.error(`Version ${appid}@${version} don't exist ${formatError(versionIdError)}`)
58
+ }
59
+ const { data: channelFound, error: errorChannel } = await supabase
60
+ .from<definitions['channels']>('channels')
61
+ .select()
62
+ .eq('app_id', appid)
63
+ .eq('created_by', userId)
64
+ .eq('version', versions[0].id)
65
+ if ((channelFound && channelFound.length) || errorChannel) {
66
+ program.error(`Version ${appid}@${version} is used in a channel, unlink it first ${formatError(errorChannel)}`)
67
+ }
68
+ const { data: deviceFound, error: errorDevice } = await supabase
69
+ .from<definitions['devices_override']>('devices_override')
70
+ .select()
71
+ .eq('app_id', appid)
72
+ .eq('version', versions[0].id)
73
+ if ((deviceFound && deviceFound.length) || errorDevice) {
74
+ program.error(`Version ${appid} @${version} is used in a device override, unlink it first ${formatError(errorDevice)}`)
75
+ }
76
+ // Delete only a specific version in storage
77
+ const { error: delError } = await supabase
78
+ .storage
79
+ .from('apps')
80
+ .remove([`${userId} /${appid}/versions / ${versions[0].bucket_id} `])
81
+ if (delError) {
82
+ program.error(`Something went wrong when trying to delete ${appid} @${version} ${delError} `)
83
+ }
84
+
85
+ const { error: delAppSpecVersionError } = await supabase
86
+ .from<definitions['app_versions']>('app_versions')
87
+ .update({
88
+ deleted: true,
89
+ })
90
+ .eq('app_id', appid)
91
+ .eq('name', version)
92
+ .eq('user_id', userId)
93
+ if (delAppSpecVersionError) {
94
+ program.error(`App ${appid} @${version} not found in database ${delAppSpecVersionError} `)
95
+ }
96
+ console.log("App version deleted from server")
97
+ return
98
+ }
99
+
100
+ const { data, error: vError } = await supabase
101
+ .from<definitions['app_versions']>('app_versions')
102
+ .select()
103
+ .eq('app_id', appid)
104
+ .eq('user_id', userId)
105
+
106
+ if (vError) {
107
+ program.error(`App ${appid} not found in database ${vError} `)
108
+ }
109
+
110
+ if (data && data.length) {
111
+ const filesToRemove = data.map(x => `${userId} /${appid}/versions / ${x.bucket_id} `)
112
+ const { error: delError } = await supabase
113
+ .storage
114
+ .from('apps')
115
+ .remove(filesToRemove)
116
+ if (delError) {
117
+ program.error(`Cannot delete stored version for app ${appid} from storage ${delError} `)
118
+ }
119
+ }
120
+
121
+ const { error: delAppVersionError } = await supabase
122
+ .from<definitions['app_versions']>('app_versions')
123
+ .delete()
124
+ .eq('app_id', appid)
125
+ .eq('user_id', userId)
126
+
127
+ if (delAppVersionError) {
128
+ program.error(`Cannot delete version for app ${appid} from database ${delAppVersionError} `)
129
+ }
130
+
131
+ const { error: dbAppError } = await supabase
132
+ .from<definitions['apps']>('apps')
133
+ .delete()
134
+ .eq('app_id', appid)
135
+ .eq('user_id', userId)
136
+
137
+ if (dbAppError) {
138
+ program.error(`Cannot delete from database ${dbAppError} `)
139
+ }
140
+
141
+ console.log("App deleted from server")
42
142
  }
package/src/bin/set.ts CHANGED
@@ -1,19 +1,20 @@
1
- import { loadConfig } from '@capacitor/cli/dist/config';
2
- import axios from 'axios';
3
- import prettyjson from 'prettyjson';
4
1
  import { program } from 'commander';
5
- import { host } from './utils';
2
+ import { getConfig, createSupabaseClient, updateOrCreateChannel, host, formatError } from './utils';
3
+ import { definitions } from './types_supabase';
6
4
 
7
- export const setChannel = async (appid, options) => {
8
- const { apikey, version, state, channel = 'dev' } = options;
9
- let config;
10
- let res;
11
- try {
12
- config = await loadConfig();
13
- } catch (err) {
14
- program.error("No capacitor config file found, run `cap init` first");
15
- }
5
+ interface Options {
6
+ apikey: string;
7
+ version: string;
8
+ state: string;
9
+ channel?: string;
10
+ }
11
+
12
+ export const setChannel = async (appid: string, options: Options) => {
13
+ let { version } = options;
14
+ const { apikey, state, channel = 'dev' } = options;
15
+ const config = await getConfig();
16
16
  appid = appid || config?.app?.appId
17
+ version = version || config?.app?.package?.version
17
18
  let parsedState
18
19
  if (state === 'public' || state === 'private')
19
20
  parsedState = state === 'public'
@@ -32,25 +33,50 @@ export const setChannel = async (appid, options) => {
32
33
  console.log(`Set${channel} to @${state} in ${appid}`);
33
34
  }
34
35
  try {
35
- res = await axios({
36
- method: 'POST',
37
- url: `${host}/api/channel`,
38
- data: {
39
- version,
40
- public: parsedState,
41
- appid,
42
- channel,
43
- },
44
- validateStatus: () => true,
45
- headers: {
46
- 'authorization': apikey
47
- }
48
- })
36
+ const supabase = createSupabaseClient(apikey)
37
+ const { data: apiAccess, error: apiAccessError } = await supabase
38
+ .rpc('is_allowed_capgkey', { apikey, keymode: ['write', 'all'], app_id: appid })
39
+
40
+ if (!apiAccess || apiAccessError) {
41
+ program.error("Invalid API key or insufisant rights");
42
+ }
43
+ const { data: dataUser, error: userIdError } = await supabase
44
+ .rpc<string>('get_user_id', { apikey })
45
+
46
+ const userId = dataUser ? dataUser.toString() : '';
47
+
48
+ if (!userId || userIdError) {
49
+ program.error('Cannot verify user')
50
+ }
51
+ const channelPayload: Partial<definitions['channels']> = {
52
+ created_by: userId,
53
+ app_id: appid,
54
+ name: channel,
55
+ }
56
+ if (version) {
57
+ const { data, error: vError } = await supabase
58
+ .from<definitions['app_versions']>('app_versions')
59
+ .select()
60
+ .eq('app_id', appid)
61
+ .eq('name', version)
62
+ .eq('user_id', userId)
63
+ .eq('deleted', false)
64
+ if (vError || !data || !data.length)
65
+ program.error(`Cannot find version ${version}`);
66
+ channelPayload.version = data[0].id
67
+ }
68
+ if (parsedState !== undefined)
69
+ channelPayload.public = parsedState
70
+ try {
71
+ const { error: dbError } = await updateOrCreateChannel(supabase, channelPayload, apikey)
72
+ if (dbError)
73
+ program.error(`Cannot set channel ${formatError(dbError)}`);
74
+ }
75
+ catch (e) {
76
+ program.error(`Cannot set channel ${formatError(e)}`);
77
+ }
49
78
  } catch (err) {
50
- program.error(`Network Error \n${prettyjson.render(err.response.data)}`);
51
- }
52
- if (!res || res.status !== 200) {
53
- program.error(`Server Error \n${prettyjson.render(res.data)}`);
79
+ program.error(`Unknow error ${formatError(err)}`);
54
80
  }
55
81
  if (version) {
56
82
  console.log(`Done ✅`);
@@ -0,0 +1,6 @@
1
+ // CapacitorConfig
2
+
3
+ declare module '@capacitor/cli/dist/config' {
4
+ export function loadConfig(): CapacitorConfig;
5
+ };
6
+