@overlayed/cli 0.0.5 → 0.1.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/dist/cli.js +16 -4
- package/package.json +48 -41
- package/dist/cli.d.ts +0 -1
package/dist/cli.js
CHANGED
|
@@ -1,8 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{Builtins as e,Cli as t,Command as n,UsageError as r}from"clipanion";import i from"chalk";import a,{createReadStream as
|
|
2
|
+
import{Builtins as e,Cli as t,Command as n,UsageError as r}from"clipanion";import i from"chalk";import a,{createReadStream as ee}from"node:fs";import{scope as te,type as o}from"arktype";import s,{createWriteStream as ne,existsSync as c,mkdirSync as l,readdirSync as u,unlinkSync as d,writeFileSync as f}from"fs";import{ensureFileSync as re}from"fs-extra";import p,{join as m}from"path";import h from"node:path";import{glob as g}from"glob";import ie,{fileURLToPath as ae}from"node:url";import{createJiti as oe}from"jiti";import se from"jszip";import{password as ce}from"@inquirer/prompts";import _,{isXiorError as v}from"xior";import{exec as y}from"child_process";import{promisify as b}from"util";const x={deployment:`deployment`};function S(e){return{all:e=e||new Map,on:function(t,n){var r=e.get(t);r?r.push(n):e.set(t,[n])},off:function(t,n){var r=e.get(t);r&&(n?r.splice(r.indexOf(n)>>>0,1):e.set(t,[]))},emit:function(t,n){var r=e.get(t);r&&r.slice().map(function(e){e(n)}),(r=e.get(`*`))&&r.slice().map(function(e){e(t,n)})}}}function C(e){return Object.prototype.toString.call(e)===`[object Object]`}function w(e){return e?Array.isArray(e)?e:[e]:[]}var T=class{data=[];constructor(){}get size(){return this.data.length}add(e){this.data.push(e)}next(){return this.data.shift()}clear(){this.data.length=0}*flush(){for(;this.size>0;){let e=this.next();e&&(yield e)}}},E=class{emitter;constructor(){this.emitter=S()}on(e,t){this.emitter.on(e,t)}off(e,t){this.emitter.off(e,t)}emit(e,t){this.emitter.emit(e,t)}removeAllListeners(){this.emitter.all.clear()}};function D(e,...t){let n=class extends e{static _instance;static getInstance(){return this._instance||(this._instance=new e(...t)),this._instance}static clearInstance(){this._instance=void 0}};return n}var O=class extends E{destroy(){this.removeAllListeners()}fatal(e,t,n){this.emit(`fatal`,{code:t,message:e,data:n,timestamp:Date.now()})}error(e,t,n){this.emit(`error`,{code:t,message:e,data:n,timestamp:Date.now()})}warn(e,t,n){this.emit(`warning`,{code:t,message:e,data:n,timestamp:Date.now()})}};const k=D(O);var A=class{data;_schema;_defaultValue;_path;constructor(e){let{schema:t,default:n,path:r}=e;this._schema=t,this._defaultValue=n,this._path=r}set(e){let t=this._schema[`~standard`].validate(e);if(t instanceof Promise)throw Error(`StructuredConfigFile does not support async validation`);if(t.issues){this.reportInvalidConfigFile(t.issues);return}this.data=this.onBeforeSave(e),this.save(e)}get(){return this.data?this.data:this.load()}getKey(e){let t=this.get();return t[e]}save(e){let t=this.onBeforeSave(e);try{re(this.getFilePath()),s.writeFileSync(this.getFilePath(),JSON.stringify(t,void 0,2))}catch{return}return this.data=t}load(){if(!this.fileExists(this.getFilePath())||!this.canReadWriteFile(this.getFilePath())){this.save(this._defaultValue);let e=this.onAfterLoad(this._defaultValue);return this.data=e,e}try{let e=s.readFileSync(this.getFilePath(),`utf8`),t=this.onAfterLoad(this.parseStoredData(e));return this.data=t,t}catch{return this.data=this._defaultValue}}onBeforeSave(e){return e}onAfterLoad(e){return e}getFilePath(){return this._path}parseStoredData(e){try{let t=o(`string.json.parse`).to(`object`),n=t(e);if(n instanceof o.errors)return this._defaultValue;let r=this._schema[`~standard`].validate(n);if(r instanceof Promise)throw Error(`StructuredConfigFile does not support async validation`);return r.issues?this.migrate(n,this._defaultValue):this.migrate(r.value,this._defaultValue)}catch{return this._defaultValue}}canReadWriteFile(e){try{return s.accessSync(e,s.constants.R_OK|s.constants.W_OK),!0}catch{return!1}}fileExists(e){try{return s.accessSync(e,s.constants.F_OK),!0}catch{return!1}}migrate(e,t){let n={...e};for(let r in t){if(!Object.prototype.hasOwnProperty.call(t,r))continue;r in e?e[r]!==null&&t[r]!==null&&typeof e[r]==`object`&&typeof t[r]==`object`&&!Array.isArray(e[r])&&!Array.isArray(t[r])?n[r]=this.migrate(e[r],t[r]):Array.isArray(t[r])&&(n[r]=e[r]):n[r]=t[r]}return n}reportInvalidConfigFile(e){k.getInstance().error(`Invalid config file`,`INVALID_CONFIG_FILE`,{issues:e.map(e=>e.message),filePath:this._path,data:this.data})}},j=class e extends E{stream;logPath;baseFileName;currentDate;rotationCheckInterval;isRotating=!1;constructor(e,t){super(),this.logPath=e,this.baseFileName=t.replace(`.log`,``),this.currentDate=this.getDateString(new Date),this.ensureLogDirectory(),this.ensureLogFile(),this.stream=this.createStream(),this.rotationCheckInterval=this.startRotationCheck(),this.cleanupOldLogs()}static scope(t,n){return new e(t,n)}log(...e){this.write(`log`,...e)}error(...e){this.write(`error`,...e)}warn(...e){this.write(`warn`,...e)}info(...e){this.write(`info`,...e)}debug(...e){this.write(`debug`,...e)}async close(){clearInterval(this.rotationCheckInterval),await new Promise(e=>{this.stream.end(()=>e())})}getCurrentFileName(){return this.getFileName(this.currentDate)}getFileName(e){return`${this.baseFileName}-${e}.log`}ensureLogDirectory(){try{l(this.logPath,{recursive:!0})}catch(e){throw console.error(`Failed to create log directory ${this.logPath}:`,e),e}}ensureLogFile(){let e=m(this.logPath,this.getFileName(this.currentDate));if(!c(e))try{f(e,``,`utf8`)}catch(t){throw console.error(`Failed to create log file ${e}:`,t),t}}getDateString(e){return e.toISOString().split(`T`)[0]}createStream(){let e=m(this.logPath,this.getFileName(this.currentDate));return ne(e,{flags:`a`,encoding:`utf8`})}async rotateLogs(){if(this.isRotating)return;this.isRotating=!0;let e=this.getDateString(new Date);e!==this.currentDate&&await new Promise(t=>{this.stream.end(()=>{this.currentDate=e,this.stream=this.createStream(),this.cleanupOldLogs(),t()})}),this.isRotating=!1}startRotationCheck(){return setInterval(()=>this.rotateLogs(),6e4)}cleanupOldLogs(){let e=u(this.logPath),t=new Date;t.setDate(t.getDate()-3),e.filter(e=>e.startsWith(this.baseFileName)&&e.endsWith(`.log`)).filter(e=>{let n=e.replace(`${this.baseFileName}-`,``).replace(`.log`,``),r=new Date(n);return r<t}).forEach(e=>{try{d(m(this.logPath,e))}catch(t){console.error(`Failed to delete old log file ${e}:`,t)}})}write(e,...t){let n=new Date,r=n.toISOString().replace(`T`,` `).replace(/\.\d+Z$/,``)+`.${n.getMilliseconds().toString().padStart(3,`0`)}`,i=t.map(e=>typeof e==`object`?JSON.stringify(e,void 0,2):String(e)).join(` `),a=`[${r}] [${e}] ${i}\n`;this.stream.write(a,e=>{e?this.emit(`error`,e):this.emit(`write`,a)})}};const M=()=>h.join(process.env.APPDATA??``,`overlayed`),N=e=>h.join(M(),`apps`,e),P=e=>h.join(N(e),`logs`);var F=class{fileLogger;path;appId;messageQueue=new T;fileName;constructor(e){this.fileName=e}init(e){this.appId=e,this.path=P(e),this.fileLogger=new j(this.path,this.fileName),this.messageQueue.flush().forEach(e=>{this.fileLogger?.[e.type](...e.args)})}scope(e){if(!this.appId||!this.path)throw Error(`Logger not initialized`);let t=`[${e}]`;return{scope:e=>this.scope(e),error:(...e)=>this.error(t,...e),warn:(...e)=>this.warn(t,...e),info:(...e)=>this.info(t,...e),log:(...e)=>this.log(t,...e)}}error(...e){this.handle(`error`,...e)}warn(...e){this.handle(`warn`,...e)}info(...e){this.handle(`log`,...e)}debug(...e){this.handle(`debug`,...e)}log(...e){this.handle(`log`,...e)}handle(e,...t){console[e](...t),this.fileLogger?this.fileLogger[e](...t):this.messageQueue.add({type:e,args:t})}};D(F,`main.log`);const I=`**/overlayed.config.{js,ts,mts}`;async function L(){let e=z(),t=oe(import.meta.url),n=await Promise.all(e.map(async e=>{if(e.endsWith(`.ts`)){let n=await t.import(e,{default:!0});return n}else{let t=await import(ie.pathToFileURL(e).toString());return t.default}}));return n.filter(R)}function R(e){return C(e)&&`app`in e}function z(){let e=g.globSync(I,{absolute:!0,cwd:process.cwd()});return e}var B=class{pattern;options;constructor(e,t){this.pattern=e,this.options=t}},V=class{patterns=[];addGlobPattern(e,t){let n=this.resolveOptions(t),r=w(e);this.patterns.push(new B(r,n))}async bundle(){let e=new se;for(let t of this.patterns){let n={...t.options},r;r=n.cwd?typeof n.cwd==`string`?n.cwd:ae(n.cwd):process.cwd(),h.isAbsolute(r)||(r=h.resolve(r)),n.absolute=!0,n.cwd=r;let i=await g(t.pattern,n);await Promise.all(i.map(async t=>{let n=h.relative(r,t),i=ee(t,`binary`);e.file(n,i,{compression:`DEFLATE`})}))}return e}resolveOptions(e){return e}},H=class extends Error{constructor(){super(`package.json not found in bundle`),this.name=`PackageJsonNotFoundError`}},U=class extends V{installerFolderGlob=`**/installer/**`;constructor(){super(),this.addGlobPattern(`package.json`)}async bundle(){let e=await super.bundle(),t=e.file(`package.json`);if(!t)throw new H;return e}resolveOptions(e){if(!e)return{ignore:this.installerFolderGlob};let t=typeof e.ignore==`string`?[e.ignore]:e.ignore??[];return t.push(this.installerFolderGlob),e.ignore=t,e}},W=class extends n{static paths=[[`bundle`]];static usage=n.Usage({category:x.deployment,description:`Bundle the app and site for deployment.`,details:`
|
|
3
3
|
Bundle the app and site for deployment.
|
|
4
4
|
|
|
5
5
|
[Docs](http://docs.overlayed.gg/cli/bundle)
|
|
6
|
-
`,examples:[[`Basic usage`,`$0 bundle`]]});async execute(){let e=await this.resolveConfig(),t=a.createWriteStream(process.cwd()+`/app.zip`)
|
|
7
|
-
Multiple config files found matching ${
|
|
8
|
-
`));let t=e.at(0);return{app:this.getAppBundler(t.app),site:t.site?this.getSiteBundler(t.site):void 0}}getAppBundler(e){let t=new
|
|
6
|
+
`,examples:[[`Basic usage`,`$0 bundle`]]});async execute(){let e=await this.resolveConfig(),t=a.createWriteStream(process.cwd()+`/app.zip`);try{let n=await e.app.bundle();t.write(await n.generateAsync({type:`nodebuffer`}))}catch(e){throw e instanceof H?new r(`package.json not found`):e}if(e.site){let t=a.createWriteStream(process.cwd()+`/site.zip`),n=await e.site?.bundle();t.write(await n?.generateAsync({type:`nodebuffer`}))}this.context.stdout.write(i.green(`Bundle created successfully.`))}async resolveConfig(){let e=await L();if(e.length===0)throw new r(`No config file found matching `+I);e.length>1&&this.context.stdout.write(i.yellow(`
|
|
7
|
+
Multiple config files found matching ${I}, using the first one.
|
|
8
|
+
`));let t=e.at(0);return{app:this.getAppBundler(t.app),site:t.site?this.getSiteBundler(t.site):void 0}}getAppBundler(e){let t=new U;return t.addGlobPattern(e.include,{ignore:e.exclude}),t}getSiteBundler(e){let t=new V;return t.addGlobPattern(e.include,{ignore:e.exclude}),t}};const G=_.create({baseURL:`https://updater.stats.cc`,headers:{Accept:`application/json`,"Accept-Encoding":`gzip, deflate, br`}});let le;G.interceptors.request.use(e=>{let t=le?.();return t?(e.headers??={},e.headers.Authorization=t,e):e});const K=_.create({baseURL:`https://api.overlayed.gg`,headers:{Accept:`application/json`,"Accept-Encoding":`gzip, deflate, br`}});let ue,q;function J(e){q=e}K.interceptors.request.use(e=>{let t=ue?.(),n=q?.();return e.headers??={},t&&(e.headers.Authorization=t),n&&(e.headers[`X-Api-Key`]=n),e});function de(e){return e}function Y(e){return e?t=>(e(t),t):de}Y(),Y(),Y();function X(){return K.get(`/v1/auth/me`)}Y();const fe=`https://dashboard.overlayed.gg`;function pe(e){return`${fe}${e}`}const me=p.normalize(`${process.env.APPDATA||process.env.HOME||`.`}/.overlayed/config.json`),he=te({Account:o({email:`string`,apiKey:`string`})}),Z=he.type({currentAccount:`Account | undefined`,accounts:`Account[]`}).or(`undefined`),Q=new A({path:me,default:void 0,schema:Z}),ge=b(y);var _e=class extends n{static paths=[[`login`]];static usage=n.Usage({description:`Authenticate with the Overlayed platform.`,details:`
|
|
9
|
+
Authenticate with the Overlayed platform.
|
|
10
|
+
`,examples:[[`Basic usage`,`$0 login`]]});async execute(){let e=pe(`/settings/api-keys`);await this.openUrl(e);let t=await ce({message:`To authenticate, you'll need an API Key. We've opened the page to create one in your browser.\n\n${i.blue(e)}\n\nOnce you have it, enter it here:`,async validate(e){J(()=>e);try{let t=await X(),n=t.data.email,r={email:n,apiKey:e},i=Q.get();Q.set({...i,currentAccount:r,accounts:i?.accounts.concat(r)??[r]})}catch(e){if(!v(e))return`Unknown error has occurred: ${e}`;let t=e.response?.status;switch(t){case 401:case 403:return`Invalid API key, please try again.`;default:return`API error, please try again later.`}}return J(()=>Q.get()?.currentAccount?.apiKey),!0}});if(!t)throw Error(`Login unknown error - this should never happen`);let n=Q.get();if(!n?.currentAccount)throw Error(`Could not get config after login`);let r=n.currentAccount.email;this.context.stdout.write(`${i.greenBright(`✅ Authentication Complete`)} - Logged in as ${r}`)}async openUrl(e){let t=process.platform,n;switch(t){case`darwin`:n=`open "${e}"`;break;case`win32`:n=`start "" "${e}"`;break;default:n=`xdg-open "${e}"`;break}try{await ge(n)}catch{}}},ve=class extends n{static paths=[[`logout`]];static usage=n.Usage({description:`Log out of the currently authenticated account.`,details:`
|
|
11
|
+
Log out of the currently authenticated account.
|
|
12
|
+
`,examples:[[`Basic usage`,`$0 logout`]]});async execute(){let e=Q.get();if(!e?.currentAccount){this.context.stderr.write(i.red(`Not currently authenticated.
|
|
13
|
+
`));return}let{currentAccount:t}=e,n=t.email,r=e.accounts.filter(e=>e.email!==t.email);Q.set({...e,currentAccount:void 0,accounts:r}),this.context.stdout.write(`Logged out from ${i.bold(n)}\n`)}},ye=class extends n{static paths=[[`whoami`]];static usage=n.Usage({description:`Display information about the currently authenticated user.`,details:`
|
|
14
|
+
Display information about the currently authenticated user.
|
|
15
|
+
|
|
16
|
+
[Docs](http://docs.overlayed.gg/cli/whoami)
|
|
17
|
+
`,examples:[[`Basic usage`,`$0 whoami`]]});async execute(){let e=Q.get();if(!e?.currentAccount){this.context.stderr.write(i.red(`Not authenticated. Run 'overlayed login' to authenticate.
|
|
18
|
+
`));return}try{let e=await X(),t=e.data.email;this.context.stdout.write(`Logged in as ${i.bold(t)}\n`)}catch(e){if(!v(e)){this.context.stderr.write(i.red(`Unknown error occurred: ${e}\n`));return}let t=e.response?.status;switch(t){case 401:case 403:this.context.stderr.write(i.red(`Authentication failed. Your API key may be invalid or expired. Run 'overlayed login' to re-authenticate.
|
|
19
|
+
`));break;default:this.context.stderr.write(i.red(`API error occurred. Please try again later.
|
|
20
|
+
`));break}}}};const be=process.argv.slice(2),$=new t({binaryName:`overlayed`,binaryLabel:`Overlayed`});[W,_e,ve,ye,e.HelpCommand].forEach(e=>{$.register(e)}),J(()=>Q.get()?.currentAccount?.apiKey),$.runExit(be);
|
package/package.json
CHANGED
|
@@ -1,42 +1,49 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
2
|
+
"name": "@overlayed/cli",
|
|
3
|
+
"author": "overlayed.gg",
|
|
4
|
+
"homepage": "https://overlayed.gg",
|
|
5
|
+
"license": "SEE LICENSE IN LICENSE.md",
|
|
6
|
+
"repository": {
|
|
7
|
+
"url": "https://github.com/overlayed-gg/overlayed-typescript",
|
|
8
|
+
"type": "git"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [
|
|
11
|
+
"typescript"
|
|
12
|
+
],
|
|
13
|
+
"version": "0.1.1",
|
|
14
|
+
"description": "Overlayed CLI",
|
|
15
|
+
"type": "module",
|
|
16
|
+
"bin": {
|
|
17
|
+
"overlayed": "./dist/cli.js"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist/**/*"
|
|
21
|
+
],
|
|
22
|
+
"publishConfig": {
|
|
23
|
+
"access": "public"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@ark/attest": "^0.45.0",
|
|
27
|
+
"@types/fs-extra": "^11.0.4",
|
|
28
|
+
"tsdown": "^0.12.9",
|
|
29
|
+
"typescript": "^5.8.2",
|
|
30
|
+
"vitest": "^3.0.9",
|
|
31
|
+
"@overlayed/api": "0.0.3",
|
|
32
|
+
"@overlayed/utils": "0.0.3",
|
|
33
|
+
"@overlayed/utils-node": "0.0.3"
|
|
34
|
+
},
|
|
35
|
+
"dependencies": {
|
|
36
|
+
"@inquirer/prompts": "^7.7.1",
|
|
37
|
+
"arktype": "^2.1.20",
|
|
38
|
+
"chalk": "^5.4.1",
|
|
39
|
+
"clipanion": "4.0.0-rc.4",
|
|
40
|
+
"fs-extra": "^11.3.0",
|
|
41
|
+
"glob": "^11.0.3",
|
|
42
|
+
"jiti": "^2.3.5",
|
|
43
|
+
"jszip": "^3.10.1",
|
|
44
|
+
"xior": "^0.7.8"
|
|
45
|
+
},
|
|
46
|
+
"engines": {
|
|
47
|
+
"node": ">=20.10.0"
|
|
48
|
+
}
|
|
49
|
+
}
|
package/dist/cli.d.ts
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { };
|