@overlayed/cli 1.0.4 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +1 -1
  2. package/dist/cli.mjs +11 -11
  3. package/package.json +11 -15
package/README.md CHANGED
@@ -4,4 +4,4 @@ CLI for bundling overlayed applications
4
4
 
5
5
  ## Testing Locally
6
6
 
7
- Best way I've found to run locally is do `moon run cli:run -- <sub commands here>`, e.g. `moon run cli:run -- login`
7
+ Best way I've found to run locally is `pnpm vp test` for tests and `pnpm vp run -r build` from the repo root before trying CLI flows.
package/dist/cli.mjs CHANGED
@@ -1,17 +1,17 @@
1
1
  #!/usr/bin/env node
2
- import{Command as e}from"@commander-js/extra-typings";import t,{isXiorError as n}from"xior";import{scope as r,type as i}from"arktype";import a,{createWriteStream as o,existsSync as s,mkdirSync as c,readFileSync as ee,readdirSync as te,unlinkSync as ne,writeFileSync as re}from"fs";import{ensureDirSync as ie,ensureFileSync as l}from"fs-extra";import u,{join as ae}from"path";import*as d from"node:path";import f from"node:path";import p from"picocolors";import*as m from"node:fs";import oe,{createReadStream as h,existsSync as g,lstatSync as se,readFileSync as ce}from"node:fs";import{glob as _}from"glob";import le,{fileURLToPath as ue}from"node:url";import{createJiti as de}from"jiti";import fe from"update-notifier";import{readdir as pe}from"node:fs/promises";import me from"jszip";import{checkbox as he,confirm as ge,input as _e,password as ve}from"@inquirer/prompts";import{Listr as v}from"listr2";import{ListrInquirerPromptAdapter as y}from"@listr2/prompt-adapter-inquirer";import{exec as ye,execSync as be}from"child_process";import{promisify as xe}from"util";const b=`https://api.overlayed.gg`,x=t.create({baseURL:b,headers:{Accept:`application/json`,"Accept-Encoding":`gzip, deflate, br`}});let S;function C(e){S=e}x.interceptors.request.use(e=>{let t=S?.();return e.headers??={},t&&(e.headers[`X-Api-Key`]=t),e});function w(e){return e}function T(e){return e?t=>(e(t),t):w}function E(e,t){return x.post(`/v1/applications/${e}/bundles/jobs/upload`,t)}function D(e,t){return x.post(`/v1/applications/${e}/bundles/jobs/confirm`,{name:t})}function O(e,t){return x.get(`/v1/applications/${e}/bundles/jobs/${t}`)}const k=T();function A(e){return x.get(`/v1/public/applications/${e}`)}function j(){return x.get(`/v1/auth/me`)}async function M(e,t){if(e.method!==`PUT`)throw Error(`Unsupported presigned request method: ${e.method}`);let n=await fetch(e.url,{method:e.method,headers:{...e.headers,"Content-Length":t.byteLength.toString()},body:t});if(!n.ok){let e=await Se(n);throw Error(`Presigned upload failed (${n.status} ${n.statusText})${e?`: ${e}`:``}`)}}async function Se(e){try{let t=(await e.text()).trim();if(t.length===0)return;let n=2048;return t.length>n?`${t.slice(0,n)}…`:t}catch{return}}function Ce(e){throw e}function we(e){return Object.prototype.toString.call(e)===`[object Object]`}function N(e){return e?Array.isArray(e)?e:[e]:[]}function Te(e){return{all: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)})}}}var Ee=class{emitter;constructor(){this.emitter=Te()}on(e,t){N(e).forEach(e=>{this.emitter.on(e,t)})}off(e,t){N(e).forEach(e=>{this.emitter.off(e,t)})}emit(e,t){N(e).forEach(e=>{this.emitter.emit(e,t)})}removeAllListeners(){this.emitter.all.clear()}};function De(e,...t){return class extends e{static _instance;static getInstance(){return this._instance||=new e(...t),this._instance}static clearInstance(){this._instance=void 0}}}const Oe=De(class extends Ee{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()})}});var ke=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)throw this.reportInvalidConfigFile(t.issues),Error(`Invalid config data for ${this._path}: ${t.issues.map(e=>e.message).join(`; `)}`);this.data=this.onBeforeSave(e),this.save(e)}get(e={}){return this.data?this.data:this.load(e)}getKey(e,t={}){return this.get(t)[e]}save(e){let t=this.onBeforeSave(e);try{l(this.getFilePath()),a.writeFileSync(this.getFilePath(),JSON.stringify(t,void 0,2))}catch{return}return this.data=t}load(e={}){let{createIfMissing:t=!0}=e;if(!this.fileExists(this.getFilePath())||!this.canReadWriteFile(this.getFilePath())){t&&this.save(this._defaultValue);let e=this.onAfterLoad(this._defaultValue);return t&&(this.data=e),e}try{let e=a.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=i(`string.json.parse`).to(`object`)(e);if(t instanceof i.errors)return this._defaultValue;let n=this._schema[`~standard`].validate(t);if(n instanceof Promise)throw Error(`StructuredConfigFile does not support async validation`);return n.issues?this.migrate(t,this._defaultValue):this.migrate(n.value,this._defaultValue)}catch{return this._defaultValue}}canReadWriteFile(e){try{return a.accessSync(e,a.constants.R_OK|a.constants.W_OK),!0}catch{return!1}}fileExists(e){try{return a.accessSync(e,a.constants.F_OK),!0}catch{return!1}}migrate(e,t){let n={...e};for(let r in t)Object.prototype.hasOwnProperty.call(t,r)&&(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){Oe.getInstance().error(`Invalid config file`,`INVALID_CONFIG_FILE`,{issues:e.map(e=>e.message),filePath:this._path,data:this.data})}};const P=`**/overlayed.config.{js,ts,mts}`;async function F(){let e=je(),t=de(import.meta.url);return(await Promise.all(e.map(async e=>e.endsWith(`.ts`)?[await t.import(e,{default:!0}),e]:[(await import(le.pathToFileURL(e).toString())).default,e]))).filter(([e])=>Ae(e)).map(([e,t])=>[e,t])}function Ae(e){return we(e)&&`app`in e}function je(){return _.globSync(P,{absolute:!0,cwd:process.cwd()})}function Me(e,t){let n=t?.cwd??process.cwd(),r=d.join(n,`.overlayed`);m.existsSync(r)||m.mkdirSync(r,{recursive:!0});let i={application:{id:e.id,name:e.name,slug:e.slug,siteUrl:e.siteUrl},release:{id:null,channel:`local`,version:`0.0.0`}},a=d.join(r,`meta.json`);return m.writeFileSync(a,JSON.stringify(i,null,2)),i}const I=new ke({path:u.normalize(`${process.env.APPDATA||process.env.HOME||`.`}/.overlayed/config.json`),default:void 0,schema:r({Account:i({email:`string`,apiKey:`string`,"applicationId?":`string`,"baseUrl?":`string`})}).type({currentAccount:`Account | undefined`,accounts:`Account[]`}).or(`undefined`)}),L=`https://api.overlayed.gg`;function R(e,t){let n=t.applicationId===void 0||e.applicationId===void 0||e.applicationId===t.applicationId,r=(e.baseUrl??L)===t.baseUrl;return n&&r}function z(e){let{currentAccount:t,accounts:n,expected:r}=e;if(t&&R(t,r))return{account:t,source:`current`};let i=n.find(e=>R(e,r));if(i)return{account:i,source:`other`}}var Ne=class{pattern;options;constructor(e,t){this.pattern=e,this.options=t}},B=class{defaultIgnore=[`overlayed.config.ts`];patterns=[];constructor(e){this.config=e}addGlobPattern(e,t){let n=this.resolveOptions(t),r=N(e);this.patterns.push(new Ne(r,n))}async bundle(){let e=new me;for(let t of this.patterns){let n={...t.options},r;r=n.cwd?typeof n.cwd==`string`?n.cwd:ue(n.cwd):process.cwd(),f.isAbsolute(r)||(r=f.resolve(r)),n.absolute=!0,n.cwd=r;let i=await _(t.pattern,n),a=await this.getFilesPathsFromPaths(i);await Promise.all(a.map(async t=>{await this.zipFile(r,e,t)}))}return e}async validateFilePath(e){return Promise.resolve(!0)}async zipFile(e,t,n){let r=f.relative(e,n);if(r=r.replace(/^(\.\.\\|\.\.\/)+/,``),!g(n)){t.file(r,``,{compression:`DEFLATE`});return}if(!await this.validateFilePath(n))return;let i=h(n,`binary`);t.file(r,i,{compression:`DEFLATE`})}resolveOptions(e){return{...e,ignore:[...N(e?.ignore),...this.defaultIgnore]}}async getFilesPathsFromPaths(e){return Promise.all(e.map(async e=>await this.getFilePathsFromPathRecursive(e))).then(e=>e.flat())}async getFilePathsFromPathRecursive(e){if(!g(e)||!se(e).isDirectory())return[e];let t=await pe(e,{withFileTypes:!0});return(await Promise.all(t.map(async t=>{let n=f.join(e,t.name);return t.isDirectory()?await this.getFilePathsFromPathRecursive(n):[n]}))).flat()}},V=class extends Error{constructor(e){super(e),this.name=`CLIError`}},Pe=class extends B{defaultIgnore=[`overlayed.config.ts`,`**/installer/**`];mainFile;constructor(e){super(e),this.addGlobPattern(`package.json`),this.addGlobPattern(`node_modules/@overlayed/app`)}async bundle(){let e=await super.bundle();return await this.validateZip(e),e}async validateFilePath(e){return e.endsWith(`package.json`)&&!e.includes(`node_modules`)&&await this.validatePackageJson(e),!0}async validateZip(e){await Promise.all([this.validateNoInstallFolder(e),this.validateMainFile(e),this.validateNoReservedFiles(e)])}async validatePackageJson(e){if(!e)throw new H;let t=oe.readFileSync(e,`utf-8`),n=i(`string.json.parse`).to({main:`string`,devDependencies:{"@overlayed/electron":`string`}})(t);if(n instanceof i.errors)throw new Fe(n.summary);this.mainFile=n.main}async validateMainFile(e){if(!this.mainFile)throw new H;if(!e.file(u.normalize(this.mainFile)))throw new Ie(this.mainFile)}async validateNoInstallFolder(e){let t=e.folder(`install`);if(t&&t.length>0)throw new Le}async validateNoReservedFiles(e){for(let t of[`meta.json`,`app-update.yml`])if(e.file(t))throw new Re(t)}},H=class extends V{constructor(){super(`package.json not found in bundle`),this.name=`PackageJsonNotFoundError`}},Fe=class extends V{constructor(e){super(`package.json is invalid: ${e}`),this.name=`PackageJsonInvalidError`}},Ie=class extends V{constructor(e){super(`referenced package.json main file ${e} not found in bundle`),this.name=`MainFileNotFoundError`}},Le=class extends V{constructor(){super("folder `install` found in bundle is not allowed and is reserved for the installer"),this.name=`InstallFolderFoundError`}},Re=class extends V{constructor(e){super(`file \`${e}\` found in bundle is not allowed and is reserved for internal use`),this.name=`ReservedFileFoundError`}};const U=new class{write(e){process.stdout.write(e)}error(e){process.stderr.write(e)}},W={normal:ze,success:Be,error:Ve,warning:He,info:Ue};function ze(...e){return p.gray([...e,`
3
- `].join(` `))}function Be(...e){return[p.green(`✔`),...e,`
4
- `].join(` `)}function Ve(...e){return[p.red(`✘`),...e,`
5
- `].join(` `)}function He(...e){return[p.yellow(`⚠`),...e,`
6
- `].join(` `)}function Ue(...e){return[p.blue(`ℹ`),...e,`
7
- `].join(` `)}async function We(e){let t=I.get({createIfMissing:!1});if(!t)return;let n=z({currentAccount:t.currentAccount,accounts:t.accounts,expected:e});if(n){if(n.source===`current`)return n.account;if(process.stdin.isTTY&&await ge({message:`Current account ${t.currentAccount?.email??`(none)`} doesn't match application ${e.applicationId??`unscoped`}. Switch to ${n.account.email}?`,default:!0}))return I.set({...t,currentAccount:n.account}),n.account}}let G;function K(e){return G??=Ge(e),G}async function Ge(e){let{buildBaseUrl:t}=e,n=process.env.OVERLAYED_APPLICATION_ID;return n?{applicationId:n,baseUrl:t}:{applicationId:await Ke(),baseUrl:t}}async function Ke(){try{return(await F()).at(0)?.[0].applicationId}catch{return}}async function q(){let e=process.env.OVERLAYED_API_KEY,t=I.get();if(e&&t?.currentAccount&&U.write(W.warning(`Using OVERLAYED_API_KEY environment variable instead of stored credentials.`)),!e&&!await We(await K({buildBaseUrl:b})))throw new V(`Not authenticated. Run 'overlayed login' or set OVERLAYED_API_KEY.`);try{return(await j()).data.email}catch(t){if(!n(t))throw t;switch(t.response?.status){case 401:case 403:throw e?new V(`Authentication failed. Your OVERLAYED_API_KEY may be invalid or expired.`):new V(`Authentication failed. Your API key may be invalid or expired. Run 'overlayed login' to re-authenticate.`);default:throw Error(`API error occurred. Please try again later.`)}}}async function J(){let e=await F();if(e.length===0)throw new V(`No config file found matching `+P);return e.length>1&&U.write(p.yellow(`
8
- Multiple config files found matching ${P}, using the first one.
9
- `)),e.at(0)}var qe=class extends B{defaultIgnore=[`overlayed.config.ts`];constructor(e){super(e)}async bundle(){let e=await super.bundle();if(!Object.keys(e.files).some(e=>e.endsWith(`.html`)))throw new Je;return e}},Je=class extends Error{constructor(){super(`Site bundle must contain at least one HTML file`)}};async function Ye(e={}){await q();try{await Xe(e)}catch(e){if(e instanceof V&&process.exit(1),n(e)){let t=e.response?.status;throw new V(`Request to ${(e.config?.baseURL??``)+(e.config?.url??``)} failed with status ${t}. ${JSON.stringify(e.response?.data,null,2)}`)}throw e}}async function Xe(e){let t=await new v([{title:`Locating overlayed.config.ts`,task:async t=>t.config=await $e(e)},{task:async(t,n)=>{if(e.app||e.site){let n=[];if(e.app&&(t.config.app?n.push(`app`):U.write(W.warning(`${p.bold(`--app`)} flag provided but no app config found in overlayed.config.ts`))),e.site&&(t.config.site?n.push(`site`):U.write(W.warning(`${p.bold(`--site`)} flag provided but no site config found in overlayed.config.ts`))),n.length===0)throw Error(`No valid bundles selected. Ensure the selected bundle types have valid config in overlayed.config.ts`);t.targetBundles=n,U.write(p.green(`Selected bundles: `)+p.bold(n.join(`, `)))}else{let e=await n.prompt(y).run(...Qe(t.config));t.targetBundles=e,U.write(p.green(`Selected bundles: `)+p.bold(e.join(`, `)))}}},{task:async(t,n)=>{t.bundleNames={};for(let r of t.targetBundles){let i=r===`app`?e.app:e.site;if(typeof i==`string`)t.bundleNames[r]=i;else if(e.wait===!1)t.bundleNames[r]=void 0;else{let e=await n.prompt(y).run(_e,{message:`Enter a name for the ${r} bundle (leave empty for random name):`});t.bundleNames[r]=e.trim()||void 0}}},rendererOptions:{persistentOutput:!0}}]).run();function n(e,t){let n=new URL(`https://overlay.dev/deployments/jobs`);n.searchParams.set(`applicationId`,e);for(let e of t)n.searchParams.append(`jobId`,e);return n.toString()}let r=await new v([{title:`Uploading bundles`,task:e=>(e.jobIds??=[],new v(e.targetBundles.map((e,t)=>({title:`Uploading ${e} bundle`,task:async n=>{let r=n.bundleNames[e],i=await Ze(n.config,e,r);i&&(n.jobIds[t]=i.id)}})),{concurrent:!0,rendererOptions:{collapseSubtasks:!1}}))},{title:`Waiting for bundles to be processed.`,task:t=>{if(e.wait===!1){if(t.jobIds.length>0){let e=n(t.config.applicationId,t.jobIds);U.write(p.yellow(`Skipping wait. Check bundle status in the dashboard: `)+p.blue(e))}return}return new v(t.jobIds.map((e,r)=>({title:`Waiting for ${p.bold(t.targetBundles[r])} bundle to be processed. This may take a couple minutes - you can wait for the bundles to appear in the dashboard here: ${p.blue(n(t.config.applicationId,t.jobIds))}`,task:async(t,i)=>{let a=0,o=t.targetBundles[r],s=n(t.config.applicationId,t.jobIds),c;for(;;){if(a++>100){i.title=`${p.red(`Timeout`)} - ${p.bold(o)} bundle processing is taking longer than expected. Check the dashboard: ${p.blue(s)}`;return}c=await O(t.config.applicationId,e);let n=c.data.status;if(n===`completed`){i.title=`${p.green(`Completed`)} - ${p.bold(o)} bundle has been processed successfully.`;break}if(n===`failed`){i.title=`${p.red(`Failed`)} - ${p.bold(o)} bundle processing failed.`;break}n===`pending`?i.title=`${p.yellow(`Queued`)} - ${p.bold(o)} bundle is queued for processing. Dashboard: ${p.blue(s)}`:n===`running`&&(i.title=`${p.green(`Running`)} - ${p.bold(o)} bundle is being processed. Dashboard: ${p.blue(s)}`),await new Promise(e=>setTimeout(e,3e3))}if(c.data.status===`failed`){let e=`An unknown error occurred.`;c.data.runs.length>0&&(e=c.data.runs[c.data.runs.length-1].error_message??e),i.title=`${p.red(`Failed`)} - ${p.bold(o)} bundle processing failed: ${e}`}}})),{concurrent:!0,exitOnError:!1,rendererOptions:{collapseSubtasks:!1}})}}]).run(t);if(r.jobIds.length>0){let e=n(r.config.applicationId,r.jobIds);U.write(``),U.write(p.green(`Bundle dashboard: `)+p.blue(e))}}async function Ze(e,t,n){let r=(e.resolveCommitHash??it)(),i;if(t===`app`){let{appPackageVersion:a,electronPackageVersion:o}=nt(e.configPath,e.rawConfig);i={type:t,name:n,commit_hash:r,app_package_version:a,electron_package_version:o}}else i={type:t,name:n,commit_hash:r};let a=await E(e.applicationId,i),o=await e[t]?.bundle()??Ce(Error(`No bundle found for `+t));e.debug&&o.forEach(e=>{console.log(`Zipping: `,e)});let s=await o.generateAsync({type:`nodebuffer`});if(e.debug){let e=`.overlayed/tmp`;ie(e),re(`${e}/debug-${t}.zip`,s);return}return await M(a.data.upload_request,s),(await D(e.applicationId,a.data.asset_bundle_name)).data}function Qe(e){let t=e=>`(Disabled: No config found for "${e}" in overlayed.config.ts)`;return[he,{message:`Select your desired bundles to create and upload.`,shortcuts:{all:`a`,invert:`i`},choices:[{name:`App`,value:`app`,disabled:e.app?void 0:t(`app`)},{name:`Site`,value:`site`,disabled:e.site?void 0:t(`site`)}]}]}async function $e(e){let[t,n]=await J();return{...t,applicationId:k(t.applicationId),configPath:n,rawConfig:t,resolveCommitHash:t.resolveCommitHash,app:et(t,n,e),site:tt(t,n,e),debug:e.debug}}function et(e,t,n){let r=new Pe(e),i=Y(t,e.app.baseDir);return n.debug&&console.log(`[App] Bundling files from: `,i),r.addGlobPattern(e.app.include,{ignore:e.app.exclude,cwd:i}),r}function tt(e,t,n){if(!e.site)return;let r=new qe(e),i=Y(t,e.site.baseDir);return n.debug&&console.log(`[Site] Bundling files from: `,i),r.addGlobPattern(e.site.include,{ignore:e.site.exclude,cwd:i}),r}function Y(e,t){return t?u.resolve(u.dirname(e),t):u.dirname(e)}function nt(e,t){let n=Y(e,t.app.baseDir),r=t.app.resolvePackageVersion??((e,n)=>rt(n,e,t.app.nodeModulesDir));return{appPackageVersion:r(`@overlayed/app`,n),electronPackageVersion:r(`@overlayed/electron`,n)}}function rt(e,t,n){let r=u.resolve(e,n??`node_modules`,...t.split(`/`),`package.json`);try{let e=JSON.parse(ee(r,`utf-8`)).version;if(typeof e!=`string`)throw new V(`Could not determine installed ${t} version`);return e}catch(e){throw e instanceof V?e:new V(`Could not read installed ${t} package at ${r}`)}}function it(){try{return be(`git rev-parse HEAD`,{encoding:`utf-8`}).trim()}catch{return}}const at=new e(`bundle`).description(`Bundle the app and site for deployment.`).addHelpText(`after`,`
2
+ import{Command as e}from"@commander-js/extra-typings";import t,{isXiorError as n}from"xior";import{scope as r,type as i}from"arktype";import a,{readFileSync as o,writeFileSync as s}from"fs";import{ensureDirSync as c,ensureFileSync as l}from"fs-extra";import u from"path";import*as d from"node:path";import f from"node:path";import p from"picocolors";import*as m from"node:fs";import h,{createReadStream as ee,existsSync as g,lstatSync as _,readFileSync as te}from"node:fs";import{glob as v}from"glob";import ne,{fileURLToPath as re}from"node:url";import{createJiti as ie}from"jiti";import ae from"update-notifier";import{readdir as oe}from"node:fs/promises";import se from"jszip";import{checkbox as ce,confirm as le,input as ue,password as de}from"@inquirer/prompts";import{Listr as y}from"listr2";import{ListrInquirerPromptAdapter as b}from"@listr2/prompt-adapter-inquirer";import{exec as fe,execSync as pe}from"child_process";import{promisify as me}from"util";const x=import.meta.env.VITE_API_BASE_URL,S=t.create({baseURL:x,headers:{Accept:`application/json`,"Accept-Encoding":`gzip, deflate, br`}});let C;function w(e){C=e}S.interceptors.request.use(e=>{let t=C?.();return e.headers??={},t&&(e.headers[`X-Api-Key`]=t),e});function he(e){return e}function ge(e){return e?t=>(e(t),t):he}function _e(e,t){return S.post(`/v1/applications/${e}/bundles/jobs/upload`,t)}function ve(e,t){return S.post(`/v1/applications/${e}/bundles/jobs/confirm`,{name:t})}function ye(e,t){return S.get(`/v1/applications/${e}/bundles/jobs/${t}`)}const T=ge();function E(e){return S.get(`/v1/public/applications/${e}`)}function D(){return S.get(`/v1/auth/me`)}async function O(e,t){if(e.method!==`PUT`)throw Error(`Unsupported presigned request method: ${e.method}`);let n=await fetch(e.url,{method:e.method,headers:{...e.headers,"Content-Length":t.byteLength.toString()},body:t});if(!n.ok){let e=await k(n);throw Error(`Presigned upload failed (${n.status} ${n.statusText})${e?`: ${e}`:``}`)}}async function k(e){try{let t=(await e.text()).trim();if(t.length===0)return;let n=2048;return t.length>n?`${t.slice(0,n)}…`:t}catch{return}}function A(e){throw e}function j(e){return Object.prototype.toString.call(e)===`[object Object]`}function M(e){return e?Array.isArray(e)?e:[e]:[]}function N(e){return{all: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)})}}}var P=class{emitter;constructor(){this.emitter=N()}on(e,t){M(e).forEach(e=>{this.emitter.on(e,t)})}off(e,t){M(e).forEach(e=>{this.emitter.off(e,t)})}emit(e,t){M(e).forEach(e=>{this.emitter.emit(e,t)})}removeAllListeners(){this.emitter.all.clear()}};function be(e,...t){return class extends e{static _instance;static getInstance(){return this._instance||=new e(...t),this._instance}static clearInstance(){this._instance=void 0}}}const xe=be(class extends P{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()})}});var Se=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)throw this.reportInvalidConfigFile(t.issues),Error(`Invalid config data for ${this._path}: ${t.issues.map(e=>e.message).join(`; `)}`);this.data=this.onBeforeSave(e),this.save(e)}get(e={}){return this.data?this.data:this.load(e)}getKey(e,t={}){return this.get(t)[e]}save(e){let t=this.onBeforeSave(e);try{l(this.getFilePath()),a.writeFileSync(this.getFilePath(),JSON.stringify(t,void 0,2))}catch{return}return this.data=t}load(e={}){let{createIfMissing:t=!0}=e;if(!this.fileExists(this.getFilePath())||!this.canReadWriteFile(this.getFilePath())){t&&this.save(this._defaultValue);let e=this.onAfterLoad(this._defaultValue);return t&&(this.data=e),e}try{let e=a.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=i(`string.json.parse`).to(`object`)(e);if(t instanceof i.errors)return this._defaultValue;let n=this._schema[`~standard`].validate(t);if(n instanceof Promise)throw Error(`StructuredConfigFile does not support async validation`);return n.issues?this.migrate(t,this._defaultValue):this.migrate(n.value,this._defaultValue)}catch{return this._defaultValue}}canReadWriteFile(e){try{return a.accessSync(e,a.constants.R_OK|a.constants.W_OK),!0}catch{return!1}}fileExists(e){try{return a.accessSync(e,a.constants.F_OK),!0}catch{return!1}}migrate(e,t){let n={...e};for(let r in t)Object.prototype.hasOwnProperty.call(t,r)&&(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){xe.getInstance().error(`Invalid config file`,`INVALID_CONFIG_FILE`,{issues:e.map(e=>e.message),filePath:this._path,data:this.data})}};const F=`**/overlayed.config.{js,ts,mts}`;async function I(){let e=we(),t=ie(import.meta.url);return(await Promise.all(e.map(async e=>e.endsWith(`.ts`)?[await t.import(e,{default:!0}),e]:[(await import(ne.pathToFileURL(e).toString())).default,e]))).filter(([e])=>Ce(e)).map(([e,t])=>[e,t])}function Ce(e){return j(e)&&`app`in e}function we(){return v.globSync(F,{absolute:!0,cwd:process.cwd()})}function Te(e,t){let n=t?.cwd??process.cwd(),r=d.join(n,`.overlayed`);m.existsSync(r)||m.mkdirSync(r,{recursive:!0});let i={application:{id:e.id,name:e.name,slug:e.slug,siteUrl:e.siteUrl},release:{id:null,channel:`local`,version:`0.0.0`}},a=d.join(r,`meta.json`);return m.writeFileSync(a,JSON.stringify(i,null,2)),i}const L=new Se({path:u.normalize(`${process.env.APPDATA||process.env.HOME||`.`}/.overlayed/config.json`),default:void 0,schema:r({Account:i({email:`string`,apiKey:`string`,"applicationId?":`string`,"baseUrl?":`string`})}).type({currentAccount:`Account | undefined`,accounts:`Account[]`}).or(`undefined`)});function R(e,t){let n=t.applicationId===void 0||e.applicationId===void 0||e.applicationId===t.applicationId,r=(e.baseUrl??`https://api.overlayed.gg`)===t.baseUrl;return n&&r}function z(e){let{currentAccount:t,accounts:n,expected:r}=e;if(t&&R(t,r))return{account:t,source:`current`};let i=n.find(e=>R(e,r));if(i)return{account:i,source:`other`}}var Ee=class{pattern;options;constructor(e,t){this.pattern=e,this.options=t}},B=class{defaultIgnore=[`overlayed.config.ts`];patterns=[];constructor(e){this.config=e}addGlobPattern(e,t){let n=this.resolveOptions(t),r=M(e);this.patterns.push(new Ee(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:re(n.cwd):process.cwd(),f.isAbsolute(r)||(r=f.resolve(r)),n.absolute=!0,n.cwd=r;let i=await v(t.pattern,n),a=await this.getFilesPathsFromPaths(i);await Promise.all(a.map(async t=>{await this.zipFile(r,e,t)}))}return e}async validateFilePath(e){return Promise.resolve(!0)}async zipFile(e,t,n){let r=f.relative(e,n);if(r=r.replace(/^(\.\.\\|\.\.\/)+/,``),!g(n)){t.file(r,``,{compression:`DEFLATE`});return}if(!await this.validateFilePath(n))return;let i=ee(n,`binary`);t.file(r,i,{compression:`DEFLATE`})}resolveOptions(e){return{...e,ignore:[...M(e?.ignore),...this.defaultIgnore]}}async getFilesPathsFromPaths(e){return Promise.all(e.map(async e=>await this.getFilePathsFromPathRecursive(e))).then(e=>e.flat())}async getFilePathsFromPathRecursive(e){if(!g(e)||!_(e).isDirectory())return[e];let t=await oe(e,{withFileTypes:!0});return(await Promise.all(t.map(async t=>{let n=f.join(e,t.name);return t.isDirectory()?await this.getFilePathsFromPathRecursive(n):[n]}))).flat()}},V=class extends Error{constructor(e){super(e),this.name=`CLIError`}},De=class extends B{defaultIgnore=[`overlayed.config.ts`,`**/installer/**`];mainFile;constructor(e){super(e),this.addGlobPattern(`package.json`),this.addGlobPattern(`node_modules/@overlayed/app`)}async bundle(){let e=await super.bundle();return await this.validateZip(e),e}async validateFilePath(e){return e.endsWith(`package.json`)&&!e.includes(`node_modules`)&&await this.validatePackageJson(e),!0}async validateZip(e){await Promise.all([this.validateNoInstallFolder(e),this.validateMainFile(e),this.validateNoReservedFiles(e)])}async validatePackageJson(e){if(!e)throw new H;let t=h.readFileSync(e,`utf-8`),n=i(`string.json.parse`).to({main:`string`,"dependencies?":{"electron?":`string`},devDependencies:{"@overlayed/electron":`string`,"electron?":`string`}}).narrow((e,t)=>{let n=e.dependencies?.electron??e.devDependencies.electron;if(!n)return t.reject({expected:`electron as a dependency or devDependency`,actual:`missing`});if(n.startsWith(`^`))return t.reject({expected:`an exact electron version (no ^ prefix)`,actual:n});let r=e.devDependencies[`@overlayed/electron`];return r.startsWith(n)?!0:t.reject({expected:`@overlayed/electron version to start with "${n}"`,actual:r})})(t);if(n instanceof i.errors)throw new Oe(n.summary);this.mainFile=n.main}async validateMainFile(e){if(!this.mainFile)throw new H;if(!e.file(u.normalize(this.mainFile)))throw new ke(this.mainFile)}async validateNoInstallFolder(e){let t=e.folder(`install`);if(t&&t.length>0)throw new Ae}async validateNoReservedFiles(e){for(let t of[`meta.json`,`app-update.yml`])if(e.file(t))throw new je(t)}},H=class extends V{constructor(){super(`package.json not found in bundle`),this.name=`PackageJsonNotFoundError`}},Oe=class extends V{constructor(e){super(`package.json is invalid: ${e}`),this.name=`PackageJsonInvalidError`}},ke=class extends V{constructor(e){super(`referenced package.json main file ${e} not found in bundle`),this.name=`MainFileNotFoundError`}},Ae=class extends V{constructor(){super("folder `install` found in bundle is not allowed and is reserved for the installer"),this.name=`InstallFolderFoundError`}},je=class extends V{constructor(e){super(`file \`${e}\` found in bundle is not allowed and is reserved for internal use`),this.name=`ReservedFileFoundError`}};const U=new class{write(e){process.stdout.write(e)}error(e){process.stderr.write(e)}},W={normal:G,success:Me,error:Ne,warning:Pe,info:Fe};function G(...e){return p.gray([...e,`
3
+ `].join(` `))}function Me(...e){return[p.green(`✔`),...e,`
4
+ `].join(` `)}function Ne(...e){return[p.red(`✘`),...e,`
5
+ `].join(` `)}function Pe(...e){return[p.yellow(`⚠`),...e,`
6
+ `].join(` `)}function Fe(...e){return[p.blue(`ℹ`),...e,`
7
+ `].join(` `)}async function Ie(e){let t=L.get({createIfMissing:!1});if(!t)return;let n=z({currentAccount:t.currentAccount,accounts:t.accounts,expected:e});if(n){if(n.source===`current`)return n.account;if(process.stdin.isTTY&&await le({message:`Current account ${t.currentAccount?.email??`(none)`} doesn't match application ${e.applicationId??`unscoped`}. Switch to ${n.account.email}?`,default:!0}))return L.set({...t,currentAccount:n.account}),n.account}}let K;function q(e){return K??=Le(e),K}async function Le(e){let{buildBaseUrl:t}=e,n=process.env.OVERLAYED_APPLICATION_ID;return n?{applicationId:n,baseUrl:t}:{applicationId:await Re(),baseUrl:t}}async function Re(){try{return(await I()).at(0)?.[0].applicationId}catch{return}}async function J(){let e=process.env.OVERLAYED_API_KEY,t=L.get();if(e&&t?.currentAccount&&U.write(W.warning(`Using OVERLAYED_API_KEY environment variable instead of stored credentials.`)),!e&&!await Ie(await q({buildBaseUrl:x})))throw new V(`Not authenticated. Run 'overlayed login' or set OVERLAYED_API_KEY.`);try{return(await D()).data.email}catch(t){if(!n(t))throw t;switch(t.response?.status){case 401:case 403:throw e?new V(`Authentication failed. Your OVERLAYED_API_KEY may be invalid or expired.`):new V(`Authentication failed. Your API key may be invalid or expired. Run 'overlayed login' to re-authenticate.`);default:throw Error(`API error occurred. Please try again later.`)}}}async function Y(){let e=await I();if(e.length===0)throw new V(`No config file found matching `+F);return e.length>1&&U.write(p.yellow(`
8
+ Multiple config files found matching ${F}, using the first one.
9
+ `)),e.at(0)}var ze=class extends B{defaultIgnore=[`overlayed.config.ts`];constructor(e){super(e)}async bundle(){let e=await super.bundle();if(!Object.keys(e.files).some(e=>e.endsWith(`.html`)))throw new Be;return e}},Be=class extends Error{constructor(){super(`Site bundle must contain at least one HTML file`)}};async function Ve(e={}){await J();try{await He(e)}catch(e){if(e instanceof V&&process.exit(1),n(e)){let t=e.response?.status;throw new V(`Request to ${(e.config?.baseURL??``)+(e.config?.url??``)} failed with status ${t}. ${JSON.stringify(e.response?.data,null,2)}`)}throw e}}async function He(e){let t=await new y([{title:`Locating overlayed.config.ts`,task:async t=>t.config=await Ge(e)},{task:async(t,n)=>{if(e.app||e.site){let n=[];if(e.app&&(t.config.app?n.push(`app`):U.write(W.warning(`${p.bold(`--app`)} flag provided but no app config found in overlayed.config.ts`))),e.site&&(t.config.site?n.push(`site`):U.write(W.warning(`${p.bold(`--site`)} flag provided but no site config found in overlayed.config.ts`))),n.length===0)throw Error(`No valid bundles selected. Ensure the selected bundle types have valid config in overlayed.config.ts`);t.targetBundles=n,U.write(p.green(`Selected bundles: `)+p.bold(n.join(`, `)))}else{let e=await n.prompt(b).run(...We(t.config));t.targetBundles=e,U.write(p.green(`Selected bundles: `)+p.bold(e.join(`, `)))}}},{task:async(t,n)=>{t.bundleNames={};for(let r of t.targetBundles){let i=r===`app`?e.app:e.site;if(typeof i==`string`)t.bundleNames[r]=i;else if(e.wait===!1)t.bundleNames[r]=void 0;else{let e=await n.prompt(b).run(ue,{message:`Enter a name for the ${r} bundle (leave empty for random name):`});t.bundleNames[r]=e.trim()||void 0}}},rendererOptions:{persistentOutput:!0}}]).run();function n(e,t){let n=new URL(`https://overlay.dev/deployments/jobs`);n.searchParams.set(`applicationId`,e);for(let e of t)n.searchParams.append(`jobId`,e);return n.toString()}let r=await new y([{title:`Uploading bundles`,task:e=>(e.jobIds??=[],new y(e.targetBundles.map((e,t)=>({title:`Uploading ${e} bundle`,task:async n=>{let r=n.bundleNames[e],i=await Ue(n.config,e,r);i&&(n.jobIds[t]=i.id)}})),{concurrent:!0,rendererOptions:{collapseSubtasks:!1}}))},{title:`Waiting for bundles to be processed.`,task:t=>{if(e.wait===!1){if(t.jobIds.length>0){let e=n(t.config.applicationId,t.jobIds);U.write(p.yellow(`Skipping wait. Check bundle status in the dashboard: `)+p.blue(e))}return}return new y(t.jobIds.map((e,r)=>({title:`Waiting for ${p.bold(t.targetBundles[r])} bundle to be processed. This may take a couple minutes - you can wait for the bundles to appear in the dashboard here: ${p.blue(n(t.config.applicationId,t.jobIds))}`,task:async(t,i)=>{let a=0,o=t.targetBundles[r],s=n(t.config.applicationId,t.jobIds),c;for(;;){if(a++>100){i.title=`${p.red(`Timeout`)} - ${p.bold(o)} bundle processing is taking longer than expected. Check the dashboard: ${p.blue(s)}`;return}c=await ye(t.config.applicationId,e);let n=c.data.status;if(n===`completed`){i.title=`${p.green(`Completed`)} - ${p.bold(o)} bundle has been processed successfully.`;break}if(n===`failed`){i.title=`${p.red(`Failed`)} - ${p.bold(o)} bundle processing failed.`;break}n===`pending`?i.title=`${p.yellow(`Queued`)} - ${p.bold(o)} bundle is queued for processing. Dashboard: ${p.blue(s)}`:n===`running`&&(i.title=`${p.green(`Running`)} - ${p.bold(o)} bundle is being processed. Dashboard: ${p.blue(s)}`),await new Promise(e=>setTimeout(e,3e3))}if(c.data.status===`failed`){let e=`An unknown error occurred.`;c.data.runs.length>0&&(e=c.data.runs[c.data.runs.length-1].error_message??e),i.title=`${p.red(`Failed`)} - ${p.bold(o)} bundle processing failed: ${e}`}}})),{concurrent:!0,exitOnError:!1,rendererOptions:{collapseSubtasks:!1}})}}]).run(t);if(r.jobIds.length>0){let e=n(r.config.applicationId,r.jobIds);U.write(``),U.write(p.green(`Bundle dashboard: `)+p.blue(e))}}async function Ue(e,t,n){let r=(e.resolveCommitHash??Xe)(),i;if(t===`app`){let{appPackageVersion:a,electronPackageVersion:o}=Je(e.configPath,e.rawConfig);i={type:t,name:n,commit_hash:r,app_package_version:a,electron_package_version:o}}else i={type:t,name:n,commit_hash:r};let a=await _e(e.applicationId,i),o=await e[t]?.bundle()??A(Error(`No bundle found for `+t));e.debug&&o.forEach(e=>{console.log(`Zipping: `,e)});let l=await o.generateAsync({type:`nodebuffer`});if(e.debug){let e=`.overlayed/tmp`;c(e),s(`${e}/debug-${t}.zip`,l);return}return await O(a.data.upload_request,l),(await ve(e.applicationId,a.data.asset_bundle_name)).data}function We(e){let t=e=>`(Disabled: No config found for "${e}" in overlayed.config.ts)`;return[ce,{message:`Select your desired bundles to create and upload.`,shortcuts:{all:`a`,invert:`i`},choices:[{name:`App`,value:`app`,disabled:e.app?void 0:t(`app`)},{name:`Site`,value:`site`,disabled:e.site?void 0:t(`site`)}]}]}async function Ge(e){let[t,n]=await Y();return{...t,applicationId:T(t.applicationId),configPath:n,rawConfig:t,resolveCommitHash:t.resolveCommitHash,app:Ke(t,n,e),site:qe(t,n,e),debug:e.debug}}function Ke(e,t,n){let r=new De(e),i=X(t,e.app.baseDir);return n.debug&&console.log(`[App] Bundling files from: `,i),r.addGlobPattern(e.app.include,{ignore:e.app.exclude,cwd:i}),r}function qe(e,t,n){if(!e.site)return;let r=new ze(e),i=X(t,e.site.baseDir);return n.debug&&console.log(`[Site] Bundling files from: `,i),r.addGlobPattern(e.site.include,{ignore:e.site.exclude,cwd:i}),r}function X(e,t){return t?u.resolve(u.dirname(e),t):u.dirname(e)}function Je(e,t){let n=X(e,t.app.baseDir),r=t.app.resolvePackageVersion??((e,n)=>Ye(n,e,t.app.nodeModulesDir));return{appPackageVersion:r(`@overlayed/app`,n),electronPackageVersion:r(`@overlayed/electron`,n)}}function Ye(e,t,n){let r=u.resolve(e,n??`node_modules`,...t.split(`/`),`package.json`);try{let e=JSON.parse(o(r,`utf-8`)).version;if(typeof e!=`string`)throw new V(`Could not determine installed ${t} version`);return e}catch(e){throw e instanceof V?e:new V(`Could not read installed ${t} package at ${r}`)}}function Xe(){try{return pe(`git rev-parse HEAD`,{encoding:`utf-8`}).trim()}catch{return}}const Ze=new e(`bundle`).description(`Bundle the app and site for deployment.`).addHelpText(`after`,`
10
10
  Documentation:
11
11
  http://docs.overlayed.gg/cli/bundle
12
- `).helpCommand(`overlayed bundle`).option(`--debug`,`Enable debug mode`,!1).option(`--app [name]`,`Bundle the app (optional: provide a custom name, random if omitted)`).option(`--site [name]`,`Bundle the site (optional: provide a custom name, random if omitted)`).option(`--no-wait`,`Skip waiting for bundle processing to complete`).action(Ye);async function ot(){await q();let[e]=await J(),t=Me({...(await A(k(e.applicationId))).data,siteUrl:``});U.write(W.success(`Initialized development environment for ${t.application.name}`))}const st=new e(`init`).description(`Initialize the local development environment.`).action(ot),X=`https://overlay.dev`.replace(/\/$/,``);function ct(e){return`${X}${e}`}const lt=xe(ye);async function ut(){let e=ct(`/user-settings/api-keys?cli=true`);if(await dt(e),!await ve({message:`To authenticate, you'll need an API Key. We've opened the page to create one in your browser.\n\n${W.info(e)}\n\nOnce you have it, enter it here:`,async validate(e){if(e=e.trim(),!e||e.length===0)return`API key is required`;C(()=>e);try{let t=await j(),n=t.data.email,r=t.data.api_key?.application_id,i={email:n,apiKey:e,baseUrl:b};r!==void 0&&(i.applicationId=r);let a=I.get(),o=(a?.accounts??[]).filter(t=>t.apiKey!==e);I.set({...a,currentAccount:i,accounts:[...o,i]})}catch(e){if(!n(e))return`Unknown error has occurred: ${e}`;switch(e.response?.status){case 401:case 403:return`Invalid API key, please try again.`;default:return`API error, please try again later.`}}return C(()=>I.get()?.currentAccount?.apiKey),!0}}))throw Error(`Login unknown error - this should never happen`);let t=I.get();if(!t?.currentAccount)throw Error(`Could not get config after login`);let r=t.currentAccount.email;U.write(W.success(`Authentication Complete - Logged in as ${r}`))}async function dt(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 lt(n)}catch{}}const ft=new e(`login`).description(`Authenticate with the Overlayed platform.`).helpCommand(`overlayed login`).action(ut);async function pt(){let e=await q(),t=I.get();if(!t){U.write(W.normal(`Not currently logged in.`));return}let n=t.accounts.filter(t=>t.email!==e);I.set({...t,currentAccount:void 0,accounts:n}),U.write(W.normal(`Logged out from ${e}`))}const mt=new e(`logout`).description(`Log out of the currently authenticated account.`).helpCommand(`overlayed logout`).action(pt);async function ht(){let e=await q(),t=I.get()?.currentAccount,n=t?.applicationId??`(unscoped)`,r=t?.baseUrl??L;return U.write(W.normal(`Logged in as ${e}`)),U.write(W.normal(`Application: ${n}`)),r!==L&&U.write(W.normal(`Base URL: ${r} (development)`)),e}const gt=new e(`whoami`).description(`Display information about the currently authenticated user.`).addHelpText(`after`,`
12
+ `).helpCommand(`overlayed bundle`).option(`--debug`,`Enable debug mode`,!1).option(`--app [name]`,`Bundle the app (optional: provide a custom name, random if omitted)`).option(`--site [name]`,`Bundle the site (optional: provide a custom name, random if omitted)`).option(`--no-wait`,`Skip waiting for bundle processing to complete`).action(Ve);async function Qe(){await J();let[e]=await Y(),t=Te({...(await E(T(e.applicationId))).data,siteUrl:``});U.write(W.success(`Initialized development environment for ${t.application.name}`))}const $e=new e(`init`).description(`Initialize the local development environment.`).action(Qe),et=(import.meta.env.VITE_DASHBOARD_URL??`https://overlay.dev`).replace(/\/$/,``);function tt(e){return`${et}${e}`}const nt=me(fe);async function rt(){let e=tt(`/user-settings/api-keys?cli=true`);if(await it(e),!await de({message:`To authenticate, you'll need an API Key. We've opened the page to create one in your browser.\n\n${W.info(e)}\n\nOnce you have it, enter it here:`,async validate(e){if(e=e.trim(),!e||e.length===0)return`API key is required`;w(()=>e);try{let t=await D(),n=t.data.email,r=t.data.api_key?.application_id,i={email:n,apiKey:e,baseUrl:x};r!==void 0&&(i.applicationId=r);let a=L.get(),o=(a?.accounts??[]).filter(t=>t.apiKey!==e);L.set({...a,currentAccount:i,accounts:[...o,i]})}catch(e){if(!n(e))return`Unknown error has occurred: ${String(e)}`;switch(e.response?.status){case 401:case 403:return`Invalid API key, please try again.`;default:return`API error, please try again later.`}}return w(()=>L.get()?.currentAccount?.apiKey),!0}}))throw Error(`Login unknown error - this should never happen`);let t=L.get();if(!t?.currentAccount)throw Error(`Could not get config after login`);let r=t.currentAccount.email;U.write(W.success(`Authentication Complete - Logged in as ${r}`))}async function it(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 nt(n)}catch{}}const at=new e(`login`).description(`Authenticate with the Overlayed platform.`).helpCommand(`overlayed login`).action(rt);async function ot(){let e=await J(),t=L.get();if(!t){U.write(W.normal(`Not currently logged in.`));return}let n=t.accounts.filter(t=>t.email!==e);L.set({...t,currentAccount:void 0,accounts:n}),U.write(W.normal(`Logged out from ${e}`))}const st=new e(`logout`).description(`Log out of the currently authenticated account.`).helpCommand(`overlayed logout`).action(ot);async function ct(){let e=await J(),t=L.get()?.currentAccount,n=t?.applicationId??`(unscoped)`,r=t?.baseUrl??`https://api.overlayed.gg`;return U.write(W.normal(`Logged in as ${e}`)),U.write(W.normal(`Application: ${n}`)),r!==`https://api.overlayed.gg`&&U.write(W.normal(`Base URL: ${r} (development)`)),e}const lt=new e(`whoami`).description(`Display information about the currently authenticated user.`).addHelpText(`after`,`
13
13
  Documentation:
14
14
  http://docs.overlayed.gg/cli/whoami
15
- `).helpCommand(`overlayed whoami`).action(()=>{ht()});let Z=null;function _t(){if(Z)return Z;try{let e=new URL(`../package.json`,import.meta.url),t=JSON.parse(ce(e,`utf8`));if(typeof t==`object`&&t&&`name`in t&&`version`in t&&typeof t.name==`string`&&typeof t.version==`string`)return Z={name:t.name,version:t.version},Z;throw Error(`Invalid package.json structure`)}catch{throw Error(`Failed to read package.json`)}}const Q=_t();fe({pkg:Q}).notify({defer:!0});const $=new e;$.name(`overlayed`).description(`Overlayed CLI`).version(Q.version,`-v, --version`).addHelpText(`before`,`
15
+ `).helpCommand(`overlayed whoami`).action(()=>{ct()});let Z=null;function ut(){if(Z)return Z;try{let e=new URL(`../package.json`,import.meta.url),t=JSON.parse(te(e,`utf8`));if(typeof t==`object`&&t&&`name`in t&&`version`in t&&typeof t.name==`string`&&typeof t.version==`string`)return Z={name:t.name,version:t.version},Z;throw Error(`Invalid package.json structure`)}catch{throw Error(`Failed to read package.json`)}}const Q=ut();ae({pkg:Q}).notify({defer:!0});const $=new e;$.name(`overlayed`).description(`Overlayed CLI`).version(Q.version,`-v, --version`).addHelpText(`before`,`
16
16
  ${p.bold(p.cyan(`Overlayed`))} is revolutionizing game overlays.
17
- `).action(()=>$.help()),$.addCommand(at).addCommand(st).addCommand(ft).addCommand(mt).addCommand(gt).configureOutput({writeErr:e=>process.stderr.write(e)});const vt=await K({buildBaseUrl:b});C(()=>{if(process.env.OVERLAYED_API_KEY)return process.env.OVERLAYED_API_KEY;let e=I.get({createIfMissing:!1});if(e)return z({currentAccount:e.currentAccount,accounts:e.accounts,expected:vt})?.account.apiKey});try{await $.parseAsync(process.argv)}catch(e){e instanceof V&&(process.stderr.write(W.error(e.message)),process.exit(1)),console.error(`Unexpected error:`),console.error(e),process.exit(1)}export{};
17
+ `).action(()=>$.help()),$.addCommand(Ze).addCommand($e).addCommand(at).addCommand(st).addCommand(lt).configureOutput({writeErr:e=>process.stderr.write(e)});const dt=await q({buildBaseUrl:x});w(()=>{if(process.env.OVERLAYED_API_KEY)return process.env.OVERLAYED_API_KEY;let e=L.get({createIfMissing:!1});if(e)return z({currentAccount:e.currentAccount,accounts:e.accounts,expected:dt})?.account.apiKey});try{await $.parseAsync(process.argv)}catch(e){e instanceof V&&(process.stderr.write(W.error(e.message)),process.exit(1)),console.error(`Unexpected error:`),console.error(e),process.exit(1)}export{};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@overlayed/cli",
3
- "version": "1.0.4",
3
+ "version": "1.1.0",
4
4
  "description": "Overlayed CLI",
5
5
  "keywords": [
6
6
  "typescript"
@@ -24,28 +24,24 @@
24
24
  },
25
25
  "dependencies": {
26
26
  "@commander-js/extra-typings": "^14.0.0",
27
- "@inquirer/prompts": "^7.10.1",
28
- "@listr2/prompt-adapter-inquirer": "^3.0.5",
29
- "arktype": "^2.1.29",
30
- "commander": "^14.0.2",
31
- "fs-extra": "^11.3.2",
32
- "glob": "^11.1.0",
27
+ "@inquirer/prompts": "^8.4.2",
28
+ "@listr2/prompt-adapter-inquirer": "^4.2.3",
29
+ "arktype": "^2.2.0",
30
+ "commander": "^14.0.3",
31
+ "fs-extra": "^11.3.4",
32
+ "glob": "^13.0.6",
33
33
  "jiti": "^2.6.1",
34
34
  "jszip": "^3.10.1",
35
- "listr2": "^9.0.5",
35
+ "listr2": "^10.2.1",
36
36
  "picocolors": "^1.1.1",
37
37
  "update-notifier": "^7.3.1",
38
- "xior": "^0.7.8"
38
+ "xior": "^0.8.3"
39
39
  },
40
40
  "devDependencies": {
41
- "@ark/attest": "^0.49.0",
41
+ "@ark/attest": "^0.56.0",
42
42
  "@types/fs-extra": "^11.0.4",
43
43
  "@types/update-notifier": "^6.0.8",
44
- "dotenv": "^17.2.3",
45
- "rolldown": "1.0.0-beta.55",
46
- "tsdown": "0.18.1",
47
- "typescript": "^5.9.3",
48
- "vitest": "^3.2.4",
44
+ "typescript": "^6.0.3",
49
45
  "@overlayed/api": "0.0.6",
50
46
  "@overlayed/shared-node": "0.0.4",
51
47
  "@overlayed/utils": "0.0.4",