@hantera/cli 20240801.2.0 → 20240922.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.
- package/dist/index.js +1 -1
- package/package.json +46 -39
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import yargs from"yargs";import{hideBin}from"yargs/helpers";import path from"path";import fs from"fs";import chalk from"chalk";import{createServer,build}from"vite";import vue from"@vitejs/plugin-vue";import mkcert from"vite-plugin-mkcert";import boxen from"boxen";import readline from"readline-sync";import fetch from"node-fetch";import{parseAllDocuments}from"yaml";import{AsciiTable3}from"ascii-table3";import os from"os";import*as url from"url";var __assign=function(){__assign=Object.assign||function __assign(t){for(var s,i=1,n=arguments.length;i<n;i++){s=arguments[i];for(var p in s)if(Object.prototype.hasOwnProperty.call(s,p))t[p]=s[p]}return t};return __assign.apply(this,arguments)};function __awaiter(thisArg,_arguments,P,generator){function adopt(value){return value instanceof P?value:new P((function(resolve){resolve(value)}))}return new(P||(P=Promise))((function(resolve,reject){function fulfilled(value){try{step(generator.next(value))}catch(e){reject(e)}}function rejected(value){try{step(generator["throw"](value))}catch(e){reject(e)}}function step(result){result.done?resolve(result.value):adopt(result.value).then(fulfilled,rejected)}step((generator=generator.apply(thisArg,_arguments||[])).next())}))}function __generator(thisArg,body){var _={label:0,sent:function(){if(t[0]&1)throw t[1];return t[1]},trys:[],ops:[]},f,y,t,g;return g={next:verb(0),throw:verb(1),return:verb(2)},typeof Symbol==="function"&&(g[Symbol.iterator]=function(){return this}),g;function verb(n){return function(v){return step([n,v])}}function step(op){if(f)throw new TypeError("Generator is already executing.");while(g&&(g=0,op[0]&&(_=0)),_)try{if(f=1,y&&(t=op[0]&2?y["return"]:op[0]?y["throw"]||((t=y["return"])&&t.call(y),0):y.next)&&!(t=t.call(y,op[1])).done)return t;if(y=0,t)op=[op[0]&2,t.value];switch(op[0]){case 0:case 1:t=op;break;case 4:_.label++;return{value:op[1],done:false};case 5:_.label++;y=op[1];op=[0];continue;case 7:op=_.ops.pop();_.trys.pop();continue;default:if(!(t=_.trys,t=t.length>0&&t[t.length-1])&&(op[0]===6||op[0]===2)){_=0;continue}if(op[0]===3&&(!t||op[1]>t[0]&&op[1]<t[3])){_.label=op[1];break}if(op[0]===6&&_.label<t[1]){_.label=t[1];t=op;break}if(t&&_.label<t[2]){_.label=t[2];_.ops.push(op);break}if(t[2])_.ops.pop();_.trys.pop();continue}op=body.call(thisArg,_)}catch(e){op=[6,e];y=0}finally{f=t=0}if(op[0]&5)throw op[1];return{value:op[0]?op[1]:void 0,done:true}}}function __spreadArray(to,from,pack){if(pack||arguments.length===2)for(var i=0,l=from.length,ar;i<l;i++){if(ar||!(i in from)){if(!ar)ar=Array.prototype.slice.call(from,0,i);ar[i]=from[i]}}return to.concat(ar||Array.prototype.slice.call(from))}typeof SuppressedError==="function"?SuppressedError:function(error,suppressed,message){var e=new Error(message);return e.name="SuppressedError",e.error=error,e.suppressed=suppressed,e};function packageToImportMapKey$1(p){return"__portal_"+p.replace("@","").replace("/","_").replace("-","_")}function portalResolve$1(packages){return{name:"vite-plugin-portal-resolve",enforce:"pre",config:function(config){var _a,_b,_c,_d;config.optimizeDeps=__assign(__assign({},(_a=config.optimizeDeps)!==null&&_a!==void 0?_a:{}),{exclude:__spreadArray(__spreadArray([],(_c=(_b=config.optimizeDeps)===null||_b===void 0?void 0:_b.exclude)!==null&&_c!==void 0?_c:[],true),packages,true)});if(!config.build){config.build={}}if(!config.build.rollupOptions){config.build.rollupOptions={}}config.build.rollupOptions.external=__spreadArray(__spreadArray([],(_d=config.build.rollupOptions.external)!==null&&_d!==void 0?_d:[],true),packages.map(packageToImportMapKey$1),true)},configResolved:function(resolvedConfig){var VALID_ID_PREFIX="/@id/";var reg=new RegExp("".concat(VALID_ID_PREFIX,"(").concat(packages.map((function(r){return packageToImportMapKey$1(r)})).join("|"),")"),"g");resolvedConfig.plugins.push({name:"vite-plugin-portal-resolve-replace-idprefix",transform:function(code){var result=reg.test(code)?code.replace(reg,(function(m,s1){return s1})):code;return result}})},resolveId:function(source,importer,options){return __awaiter(this,void 0,void 0,(function(){return __generator(this,(function(_a){if(packages.includes(source)){return[2,{id:packageToImportMapKey$1(source),external:true}]}return[2]}))}))}}}function packageToImportMapKey(p){return"__portal_"+p.replace("@","").replace("/","_").replace("-","_")}function portalResolve(packages){var reg=new RegExp("(import (?:.+?) from [\"'])(".concat(packages.map((function(r){return r.replace("/","\\/")})).join("|"),")([\"'];?)"),"g");return{name:"vite-plugin-portal-resolve",enforce:"pre",config:function(config){var _a,_b,_c,_d;config.optimizeDeps=__assign(__assign({},(_a=config.optimizeDeps)!==null&&_a!==void 0?_a:{}),{exclude:__spreadArray(__spreadArray([],(_c=(_b=config.optimizeDeps)===null||_b===void 0?void 0:_b.exclude)!==null&&_c!==void 0?_c:[],true),packages,true)});if(!config.build){config.build={}}if(!config.build.rollupOptions){config.build.rollupOptions={}}config.build.rollupOptions.external=__spreadArray(__spreadArray([],(_d=config.build.rollupOptions.external)!==null&&_d!==void 0?_d:[],true),packages.map(packageToImportMapKey),true)},configResolved:function(resolvedConfig){resolvedConfig.plugins.push({name:"vite-plugin-portal-resolve-replace-idprefix",transform:function(code){var result=reg.test(code)?code.replace(reg,(function(m,s1,s2,s3){return s1+packageToImportMapKey(s2)+s3})):code;return result}})}}}function developmentConfig(appDir){return{configFile:false,mode:"development",root:path.join(appDir,".hantera"),plugins:[vue(),portalResolve$1(["vue","@hantera/portal-app"]),mkcert()],logLevel:"error",server:{port:4734,https:true},build:{target:"esnext"}}}function buildConfig(appDir,entry){var result=developmentConfig(appDir);result.mode="production";delete result.server;result.logLevel="warn";result.build.lib={entry,name:"hantera-app",fileName:"index",formats:["es"]};result.plugins=[vue(),portalResolve(["vue","@hantera/portal-app"])];result.build.outDir=path.join(appDir,".hantera","dist");return result}var configFolder=path.join(process.env.APPDATA||(process.platform=="darwin"?process.env.HOME+"/Library/Preferences":process.env.HOME+"/.local/share"),"hantera-cli");if(!fs.existsSync(configFolder)){fs.mkdirSync(configFolder,484)}var configFile=path.join(configFolder,"hantera-cli.config.json");function loadConfig(){var configContent="{}";if(fs.existsSync(configFile)){configContent=fs.readFileSync(configFile,"utf8")}try{var result=JSON.parse(configContent);if(!result.environments){result.environments={}}return result}catch(_a){console.log(chalk.red("Unable to parse config file. Ignoring."));return{}}}var config=__assign(__assign({},loadConfig()),{save:function(){fs.writeFileSync(configFile,JSON.stringify(config))}});function app(appDir){if(!appDir||appDir==="."){appDir=process.cwd()}else if(!path.isAbsolute(appDir)){appDir=path.join(process.cwd(),appDir)}appDir=path.normalize(appDir);if(!fs.existsSync(path.join(appDir,"package.json"))){console.log(chalk.red("'package.json' not found in path '".concat(appDir,"'")));return}var packageJson=JSON.parse(fs.readFileSync(path.join(appDir,"package.json"),"utf8"));if(!packageJson.name){console.log(chalk.red("package.json missing 'name' property."))}var entryPath=path.normalize(path.join(appDir,packageJson.main||"index.ts"));return{packageJson,dev:function(){return __awaiter(this,void 0,void 0,(function(){var cacheDir,loader_ts,server;return __generator(this,(function(_a){switch(_a.label){case 0:cacheDir=path.join(appDir,".hantera");if(!fs.existsSync(cacheDir)){fs.mkdirSync(cacheDir,484)}fs.writeFile(path.join(cacheDir,"index.html"),'<!DOCTYPE html>\n <html lang="en">\n <head>\n </head>\n <body>\n <script type="module" src="loader.ts"><\/script>\n </body>\n </html>\n ',(function(err){if(err){console.error(err)}}));loader_ts="export const appId = ".concat(JSON.stringify(packageJson.name),";\n export { default as default } from '").concat(path.relative(cacheDir,entryPath).replace("\\","/").replace(".ts",""),"';");fs.writeFile(path.join(cacheDir,"loader.ts"),loader_ts,(function(err){if(err){console.error(err)}}));return[4,createServer(developmentConfig(appDir))];case 1:server=_a.sent();return[4,server.listen()];case 2:_a.sent();console.log(chalk.green("Local app development is running.."));console.log(boxen(chalk.black('To enable local development mode in Hantera portal:\n- Go to Developer settings (requires developer permission)\n- Click "Enable Local Development"'),{borderStyle:"none",backgroundColor:"blue",padding:1}));return[2]}}))}))},build:function(){return __awaiter(this,void 0,void 0,(function(){return __generator(this,(function(_a){switch(_a.label){case 0:fs.rmSync(path.join(appDir,".hantera","dist"),{recursive:true,force:true});return[4,build(buildConfig(appDir,entryPath))];case 1:_a.sent();return[2]}}))}))},upload:function(env,force){var _a,_b;if(force===void 0){force=false}return __awaiter(this,void 0,void 0,(function(){function upload(type){return __awaiter(this,void 0,void 0,(function(){var file,_a,_b,_c,_d,_e,_f;return __generator(this,(function(_g){switch(_g.label){case 0:file=type===AppAssetType.js?path.join(appDir,".hantera","dist","index.js"):path.join(appDir,".hantera","dist","style.css");if(!fs.existsSync(file)){return[2]}console.log("Uploading ".concat(type===AppAssetType.js?"scripts":"stylesheets","..."));return[4,fetch("".concat(serverUrl,"/apps/upload/").concat(versionId,"?type=").concat(type),{method:"POST",headers:{"Content-Type":"text/plain",Authorization:"Bearer ".concat(token)},body:fs.readFileSync(file,"utf-8")})];case 1:response=_g.sent();if(!!response.ok)return[3,3];_b=(_a=console).log;_d=(_c=chalk).red;_f=(_e="Upload failed: (".concat(response.status," ").concat(response.statusText,") ")).concat;return[4,response.text()];case 2:_b.apply(_a,[_d.apply(_c,[_f.apply(_e,[_g.sent()])])]);return[2];case 3:return[2]}}))}))}var token,answer,serverUrl,response,_c,_d,_e,_f,_g,_h,versionId,_j,_k,_l,_m,_o,_p;return __generator(this,(function(_q){switch(_q.label){case 0:token=(_a=config.environments[env])===null||_a===void 0?void 0:_a.token;if(!token){console.log(chalk.red("No login found for '".concat(env,"'")))}if(!force){answer=readline.question(chalk.yellow("Installing '".concat(packageJson.name,"' in '").concat(env,"', proceed? [Y/n]")));if(!(!answer||answer==="Y"||answer==="y")){console.log("Aborting");return[2]}}serverUrl=null;if(env==="localhost"){serverUrl="http://localhost:3100"}else{serverUrl="https://".concat(env,".portal.ams.hantera.cloud")}return[4,fetch("".concat(serverUrl,"/apps/install"),{method:"POST",headers:{"Content-Type":"application/json",Authorization:"Bearer ".concat(token)},body:JSON.stringify({id:packageJson.name,description:packageJson.description,version:packageJson.version,authorName:(_b=packageJson.author)===null||_b===void 0?void 0:_b.name})})];case 1:response=_q.sent();if(!!response.ok)return[3,3];_d=(_c=console).log;_f=(_e=chalk).red;_h=(_g="Unable to install: (".concat(response.status," ").concat(response.statusText,") ")).concat;return[4,response.text()];case 2:_d.apply(_c,[_f.apply(_e,[_h.apply(_g,[_q.sent()])])]);return[2];case 3:return[4,response.json()];case 4:versionId=_q.sent();return[4,upload(AppAssetType.js)];case 5:_q.sent();return[4,upload(AppAssetType.css)];case 6:_q.sent();return[4,fetch("".concat(serverUrl,"/apps/end/").concat(versionId),{method:"POST",headers:{"Content-Type":"application/json",Authorization:"Bearer ".concat(token)}})];case 7:response=_q.sent();if(!!response.ok)return[3,9];_k=(_j=console).log;_m=(_l=chalk).red;_p=(_o="Unable to install: (".concat(response.status," ").concat(response.statusText,") ")).concat;return[4,response.text()];case 8:_k.apply(_j,[_m.apply(_l,[_p.apply(_o,[_q.sent()])])]);return[2];case 9:console.log(chalk.green("App '".concat(packageJson.name,"' installed to '").concat(env,"' successfully!")));return[2]}}))}))}}}var AppAssetType;(function(AppAssetType){AppAssetType["js"]="js";AppAssetType["css"]="css"})(AppAssetType||(AppAssetType={}));function getPortalServerUrl(env){if(env==="localhost"){return"http://localhost:3100"}else{return"https://".concat(env,".portal.ams.hantera.cloud")}}function getServerUrl(env){if(env==="localhost"){return"http://localhost:3300"}else{return"https://".concat(env,".core.ams.hantera.cloud")}}function remote(){function getApps(env){var _a;return __awaiter(this,void 0,void 0,(function(){var token,serverUrl,response,_b,_c,_d,_e,_f,_g;return __generator(this,(function(_h){switch(_h.label){case 0:token=(_a=config.environments[env])===null||_a===void 0?void 0:_a.token;if(!token){console.log(chalk.red("No login found for '".concat(env,"'")));return[2]}serverUrl=getPortalServerUrl(env);return[4,fetch("".concat(serverUrl,"/apps/list"),{method:"GET",headers:{"Content-Type":"application/json",Authorization:"Bearer ".concat(token)}})];case 1:response=_h.sent();if(!!response.ok)return[3,3];_c=(_b=console).log;_e=(_d=chalk).red;_g=(_f="Unable to fetch installed apps: (".concat(response.status," ").concat(response.statusText,") ")).concat;return[4,response.text()];case 2:_c.apply(_b,[_e.apply(_d,[_g.apply(_f,[_h.sent()])])]);return[2];case 3:return[4,response.json()];case 4:return[2,_h.sent().map((function(r){return{id:r.id,currentVersion:r.currentVersion,authorName:r.authorName,description:r.description,disabledUtc:r.disabledUtc,versions:r.versions}}))]}}))}))}return{deactivateApp:function(env,appId){var _a;return __awaiter(this,void 0,void 0,(function(){var token,answer,serverUrl,response,_b,_c,_d,_e,_f,_g;return __generator(this,(function(_h){switch(_h.label){case 0:token=(_a=config.environments[env])===null||_a===void 0?void 0:_a.token;if(!token){console.log(chalk.red("No login found for '".concat(env,"'")))}answer=readline.question(chalk.yellow("Disabling '".concat(appId,"' in '").concat(env,"', proceed? [Y/n]")));if(!(!answer||answer==="Y"||answer==="y")){console.log("Aborting");return[2]}serverUrl=getPortalServerUrl(env);return[4,fetch("".concat(serverUrl,"/apps/disable"),{method:"POST",headers:{"Content-Type":"application/json",Authorization:"Bearer ".concat(token)},body:JSON.stringify({id:appId})})];case 1:response=_h.sent();if(!(response.status===404))return[3,2];console.log(chalk.red("App ".concat(appId,"' not found, try 'h_ list'")));return[3,5];case 2:if(!!response.ok)return[3,4];_c=(_b=console).log;_e=(_d=chalk).red;_g=(_f="Unable to disable: (".concat(response.status," ").concat(response.statusText,") ")).concat;return[4,response.text()];case 3:_c.apply(_b,[_e.apply(_d,[_g.apply(_f,[_h.sent()])])]);return[2];case 4:console.log(chalk.green("App '".concat(appId,"' disabled in '").concat(env,"' successfully!")));_h.label=5;case 5:return[2]}}))}))},activateApp:function(env,appId,version){var _a;return __awaiter(this,void 0,void 0,(function(){var token,answer,serverUrl,response,_b,_c,_d,_e,_f,_g;return __generator(this,(function(_h){switch(_h.label){case 0:token=(_a=config.environments[env])===null||_a===void 0?void 0:_a.token;if(!token){console.log(chalk.red("No login found for '".concat(env,"'")))}answer=readline.question(chalk.yellow("Activating '".concat(appId,"@").concat(version?version:"installed","' in '").concat(env,"', proceed? [Y/n]")));if(!(!answer||answer==="Y"||answer==="y")){console.log("Aborting");return[2]}serverUrl=getPortalServerUrl(env);return[4,fetch("".concat(serverUrl,"/apps/activate"),{method:"POST",headers:{"Content-Type":"application/json",Authorization:"Bearer ".concat(token)},body:JSON.stringify({id:appId,version})})];case 1:response=_h.sent();if(!(response.status===404))return[3,2];if(version){console.log(chalk.red("App '".concat(appId,"@").concat(version,"' not found, try 'h_ list'")))}else{console.log(chalk.red("App '".concat(appId,"' not found, try 'h_ list'")))}return[3,5];case 2:if(!!response.ok)return[3,4];_c=(_b=console).log;_e=(_d=chalk).red;_g=(_f="Unable to activate: (".concat(response.status," ").concat(response.statusText,") ")).concat;return[4,response.text()];case 3:_c.apply(_b,[_e.apply(_d,[_g.apply(_f,[_h.sent()])])]);return[2];case 4:console.log(chalk.green("App '".concat(appId,"' activated in '").concat(env,"' successfully!")));_h.label=5;case 5:return[2]}}))}))},getApps,listApps:function(env){return __awaiter(this,void 0,void 0,(function(){var apps,table,count,_i,apps_1,app;return __generator(this,(function(_a){switch(_a.label){case 0:return[4,getApps(env)];case 1:apps=_a.sent();table=new AsciiTable3("Apps in '".concat(env,"'"));table.setHeading("Id","Version","Author","Description","Disabled");table.setWidth(4,30).setWrapped(4);count=0;for(_i=0,apps_1=apps;_i<apps_1.length;_i++){app=apps_1[_i];count+=1;table.addRow(app.id,app.currentVersion,app.authorName,app.description,app.disabledUtc?new Date(app.disabledUtc).toDateString():"")}if(count>0){console.log(table.toString())}else{console.log("No apps installed")}return[2]}}))}))},appDetails:function(env,appId){return __awaiter(this,void 0,void 0,(function(){var apps,app,table,count,_i,_a,version;return __generator(this,(function(_b){switch(_b.label){case 0:return[4,getApps(env)];case 1:apps=_b.sent();if(!apps){console.log(chalk.red("Unable to fetch installed apps"));return[2]}app=apps.find((function(r){return r.id===appId}));if(!app){console.log(chalk.red("App '".concat(appId,"' not found in '").concat(env,"'")));return[2]}console.log(chalk.bold(app.id));console.log("By "+app.authorName);console.log();console.log(app.description);console.log();table=new AsciiTable3("Installed versions of '".concat(appId,"' in '").concat(env,"'"));table.setHeading("Version","Installed","Uploaded By");table.setWidth(4,30).setWrapped(4);count=0;for(_i=0,_a=app.versions;_i<_a.length;_i++){version=_a[_i];count+=1;table.addRow(version.isActive?chalk.blue(version.version):version.version,new Date(version.installedUtc).toDateString(),version.uploadedBy)}if(count>0){console.log(table.toString())}return[2]}}))}))},importSettings:function(env,clear,values){var _a;return __awaiter(this,void 0,void 0,(function(){var token,payload,serverUrl,response,_b,_c,_d,_e,_f,_g,result;return __generator(this,(function(_h){switch(_h.label){case 0:token=(_a=config.environments[env])===null||_a===void 0?void 0:_a.token;if(!token){console.log(chalk.red("No login found for '".concat(env,"'")))}payload={clear:!!clear,values};console.log("Applying settings..");serverUrl=getServerUrl(env);return[4,fetch("".concat(serverUrl,"/api/system/settings/apply"),{method:"POST",headers:{"Content-Type":"application/json",Authorization:"Bearer ".concat(token)},body:JSON.stringify(payload)})];case 1:response=_h.sent();if(!!response.ok)return[3,3];_c=(_b=console).log;_e=(_d=chalk).red;_g=(_f="Unable to apply settings: (".concat(response.status," ").concat(response.statusText,") ")).concat;return[4,response.text()];case 2:_c.apply(_b,[_e.apply(_d,[_g.apply(_f,[_h.sent()])])]);return[2];case 3:return[4,response.json()];case 4:result=_h.sent();result.forEach((function(r){if(r.oldValue){console.log("Setting '".concat(r.key,"' changed from ").concat(JSON.stringify(r.oldValue)," to ").concat(JSON.stringify(r.newValue)))}else{console.log("Setting '".concat(r.key,"' set to ").concat(JSON.stringify(r.newValue)))}}));console.log(chalk.green("Settings applied successfully!"));_h.label=5;case 5:return[2]}}))}))},saveComponent:function(env,componentId,source){var _a;return __awaiter(this,void 0,void 0,(function(){var token,payload,serverUrl,response,_b,_c,_d,_e,_f,_g;return __generator(this,(function(_h){switch(_h.label){case 0:token=(_a=config.environments[env])===null||_a===void 0?void 0:_a.token;if(!token){console.log(chalk.red("No login found for '".concat(env,"'")))}payload={componentId,data:source};console.log("Uploading component '".concat(componentId,"'.."));serverUrl=getServerUrl(env);return[4,fetch("".concat(serverUrl,"/api/system/saveComponent"),{method:"POST",headers:{"Content-Type":"application/json",Authorization:"Bearer ".concat(token)},body:JSON.stringify(payload)})];case 1:response=_h.sent();if(!!response.ok)return[3,3];_c=(_b=console).log;_e=(_d=chalk).red;_g=(_f="Unable to upload component: (".concat(response.status," ").concat(response.statusText,") ")).concat;return[4,response.text()];case 2:_c.apply(_b,[_e.apply(_d,[_g.apply(_f,[_h.sent()])])]);return[2,false];case 3:console.log(chalk.green("Script uploaded successfully!"));return[2,true]}}))}))},validateComponent:function(env,componentId,source){var _a;return __awaiter(this,void 0,void 0,(function(){var token,payload,serverUrl,response,_b,_c,_d,_e,_f,_g,result;return __generator(this,(function(_h){switch(_h.label){case 0:token=(_a=config.environments[env])===null||_a===void 0?void 0:_a.token;if(!token){console.log(chalk.red("No login found for '".concat(env,"'")))}payload={componentId,data:source};console.log("Validating component '".concat(componentId,"'.."));serverUrl=getServerUrl(env);return[4,fetch("".concat(serverUrl,"/api/system/validateComponent"),{method:"POST",headers:{"Content-Type":"application/json",Authorization:"Bearer ".concat(token)},body:JSON.stringify(payload)})];case 1:response=_h.sent();if(!!response.ok)return[3,3];_c=(_b=console).log;_e=(_d=chalk).red;_g=(_f="Unable to validate component: (".concat(response.status," ").concat(response.statusText,") ")).concat;return[4,response.text()];case 2:_c.apply(_b,[_e.apply(_d,[_g.apply(_f,[_h.sent()])])]);return[2,false];case 3:return[4,response.json()];case 4:result=_h.sent();result.errors.forEach((function(r){var pos=r.absolutePosition;if(r.isWarning){console.log(chalk.yellow(" Warning ".concat(pos.fromLine,":").concat(pos.fromColumn," - ").concat(pos.toLine,":").concat(pos.toColumn," ").concat(r.message)))}else{console.log(chalk.red(" Error ".concat(pos.fromLine,":").concat(pos.fromColumn," - ").concat(pos.toLine,":").concat(pos.toColumn," ").concat(r.message)))}}));if(!result.successful){console.log(chalk.red("Component '"+componentId+"' is not valid. See errors above script."));return[2,false]}return[2,true]}}))}))},updateSearchIndices:function(env,nodes,rebuild){var _a;return __awaiter(this,void 0,void 0,(function(){var token,payload,serverUrl,response,_b,_c,_d,_e,_f,_g;return __generator(this,(function(_h){switch(_h.label){case 0:token=(_a=config.environments[env])===null||_a===void 0?void 0:_a.token;if(!token){console.log(chalk.red("No login found for '".concat(env,"'")))}payload={nodes,rebuild};console.log("Scheduling index update..");serverUrl=getServerUrl(env);return[4,fetch("".concat(serverUrl,"/api/system/searchIndex/update"),{method:"POST",headers:{"Content-Type":"application/json",Authorization:"Bearer ".concat(token)},body:JSON.stringify(payload)})];case 1:response=_h.sent();if(!!response.ok)return[3,3];_c=(_b=console).log;_e=(_d=chalk).red;_g=(_f="Unable to schedule rebuild: (".concat(response.status," ").concat(response.statusText,") ")).concat;return[4,response.text()];case 2:_c.apply(_b,[_e.apply(_d,[_g.apply(_f,[_h.sent()])])]);return[2,false];case 3:console.log(chalk.green("Rebuild scheduled successfully!"));console.log("This operation may take a while to complete. Use 'h_ signals processes/hantera/graph' to check progress.");return[2,true]}}))}))},printSignals:function(env,path,clearConsole){var _a;if(clearConsole===void 0){clearConsole=false}return __awaiter(this,void 0,void 0,(function(){var token,serverUrl,response,_b,_c,_d,_e,_f,_g,result,err_1;return __generator(this,(function(_h){switch(_h.label){case 0:token=(_a=config.environments[env])===null||_a===void 0?void 0:_a.token;if(!token){console.log(chalk.red("No login found for '".concat(env,"'")))}serverUrl=getServerUrl(env);_h.label=1;case 1:_h.trys.push([1,7,,8]);return[4,fetch("".concat(serverUrl,"/api/system/signals/").concat(path!==null&&path!==void 0?path:""),{method:"GET",headers:{"Content-Type":"application/json",Authorization:"Bearer ".concat(token)}})];case 2:response=_h.sent();if(!!response.ok)return[3,4];_c=(_b=console).log;_e=(_d=chalk).red;_g=(_f="Unable to get signals: (".concat(response.status," ").concat(response.statusText,") ")).concat;return[4,response.text()];case 3:_c.apply(_b,[_e.apply(_d,[_g.apply(_f,[_h.sent()])])]);return[2,false];case 4:return[4,response.json()];case 5:result=_h.sent();if(clearConsole){console.clear()}result.forEach((function(signal){if(signal.status==="ok"){print(" OK ",chalk.green,signal.id,signal.message)}else if(signal.status==="warning"){print("WARN",chalk.yellow,signal.id,signal.message)}else if(signal.status==="error"){print("ERR ",chalk.red,signal.id,signal.message)}else if(signal.status==="pending"){print("PEND",chalk.gray,signal.id,signal.message)}else if(signal.status==="processing"){print("PROC",chalk.gray,signal.id,signal.message)}function print(status,color,signalId,message){console.log("["+color(status)+"] ".concat(signalId.join("/")).concat(message?": "+message:""))}}));console.log("Updated: "+(new Date).toLocaleTimeString());_h.label=6;case 6:return[3,8];case 7:err_1=_h.sent();if(clearConsole){console.clear()}console.log(chalk.red("Unable to get signals: ".concat(err_1)));console.log("Updated: "+(new Date).toLocaleTimeString());return[3,8];case 8:return[2]}}))}))}}}function manifest(manifestPath,envOverride){manifestPath=path.join(process.cwd(),manifestPath);if(!fs.existsSync(manifestPath)){console.log(chalk.red("'".concat(manifestPath,"' not found.")));return}var manifests=parseAllDocuments(fs.readFileSync(manifestPath,"utf8")).map((function(r){return r.toJS()}));if(!manifests){throw"'".concat(manifestPath,"' is empty or invalid.")}manifests.forEach((function(manifest){var _a;if(!envOverride&&!manifest.env){throw"No 'env' manifest property specified and no override passed to command"}(_a=manifest.apps)===null||_a===void 0?void 0:_a.add.forEach((function(r){if(!r.path){throw"App lacks 'path', only local apps are supported for now"}}))}));var remote$1=remote();return{apply:function(){return __awaiter(this,void 0,void 0,(function(){var _i,manifests_1,manifest_1,_a,manifests_2,manifest_2;return __generator(this,(function(_b){switch(_b.label){case 0:_i=0,manifests_1=manifests;_b.label=1;case 1:if(!(_i<manifests_1.length))return[3,4];manifest_1=manifests_1[_i];return[4,validateComponents(manifest_1)];case 2:if(!_b.sent()){return[2]}_b.label=3;case 3:_i++;return[3,1];case 4:_a=0,manifests_2=manifests;_b.label=5;case 5:if(!(_a<manifests_2.length))return[3,10];manifest_2=manifests_2[_a];return[4,applyApps(manifest_2)];case 6:_b.sent();return[4,applyComponents(manifest_2)];case 7:if(!_b.sent()){return[2]}return[4,applySettings(manifest_2)];case 8:_b.sent();_b.label=9;case 9:_a++;return[3,5];case 10:return[2]}}))}))}};function applyApps(manifest){var _a,_b;return __awaiter(this,void 0,void 0,(function(){var env,installed,apps,_loop_1,_i,apps_1,app_1;return __generator(this,(function(_c){switch(_c.label){case 0:if(!manifest.apps)return[2];env=envOverride!==null&&envOverride!==void 0?envOverride:manifest.env;return[4,remote$1.getApps(env)];case 1:installed=_c.sent();if(!installed){console.log(chalk.red("Unable to fetch installed apps"));return[2]}apps=(_b=(_a=manifest.apps)===null||_a===void 0?void 0:_a.add)===null||_b===void 0?void 0:_b.map((function(r){return{manifest:r,control:app(r.path)}}));_loop_1=function(app_1){return __generator(this,(function(_d){switch(_d.label){case 0:if(app_1.manifest.skipIfDeactivated&&installed.find((function(r){return r.id===app_1.control.packageJson.name&&r.disabledUtc}))){console.log("Skipping disabled app ".concat(app_1.control.packageJson.name));return[2,"continue"]}return[4,app_1.control.build()];case 1:_d.sent();return[4,app_1.control.upload(env,true)];case 2:_d.sent();return[2]}}))};_i=0,apps_1=apps;_c.label=2;case 2:if(!(_i<apps_1.length))return[3,5];app_1=apps_1[_i];return[5,_loop_1(app_1)];case 3:_c.sent();_c.label=4;case 4:_i++;return[3,2];case 5:return[2]}}))}))}function applySettings(manifest){return __awaiter(this,void 0,void 0,(function(){function collect(obj,path){if(Array.isArray(obj)){obj.forEach((function(r){Object.keys(r).forEach((function(key){values.push({container:path.join("/"),key,value:r[key]})}))}))}else if(typeof obj==="object"){for(var key in obj){collect(obj[key],__spreadArray(__spreadArray([],path,true),[key],false))}}}var env,values;return __generator(this,(function(_a){switch(_a.label){case 0:if(!manifest.settings)return[2];env=envOverride!==null&&envOverride!==void 0?envOverride:manifest.env;values=[];collect(manifest.settings,[]);return[4,remote$1.importSettings(env,manifest.clearSettings,values)];case 1:_a.sent();return[2]}}))}))}function applyComponents(manifest){return __awaiter(this,void 0,void 0,(function(){var env,baseDir,_i,_a,component,source;return __generator(this,(function(_b){switch(_b.label){case 0:if(!manifest.components)return[2,true];env=envOverride!==null&&envOverride!==void 0?envOverride:manifest.env;baseDir=path.dirname(manifestPath);_i=0,_a=manifest.components;_b.label=1;case 1:if(!(_i<_a.length))return[3,4];component=_a[_i];source=fs.readFileSync(path.join(baseDir,component.file),"utf8");return[4,remote$1.saveComponent(env,component.id,source)];case 2:if(!_b.sent()){return[2,false]}_b.label=3;case 3:_i++;return[3,1];case 4:return[2,true]}}))}))}function validateComponents(manifest){return __awaiter(this,void 0,void 0,(function(){var env,baseDir,_i,_a,component,source;return __generator(this,(function(_b){switch(_b.label){case 0:if(!manifest.components)return[2,true];env=envOverride!==null&&envOverride!==void 0?envOverride:manifest.env;baseDir=path.dirname(manifestPath);_i=0,_a=manifest.components;_b.label=1;case 1:if(!(_i<_a.length))return[3,4];component=_a[_i];source=fs.readFileSync(path.join(baseDir,component.file),"utf8");return[4,remote$1.validateComponent(env,component.id,source)];case 2:if(!_b.sent()){return[2,false]}_b.label=3;case 3:_i++;return[3,1];case 4:return[2,true]}}))}))}}var __dirname=url.fileURLToPath(new URL(".",import.meta.url));var json=JSON.parse(fs.readFileSync(path.join(__dirname,"../package.json"),"utf-8"));var version=json.version;function create(){return __awaiter(this,void 0,void 0,(function(){var id,input,description,componentsDir;return __generator(this,(function(_a){switch(_a.label){case 0:if(fs.existsSync(path.join(process.cwd(),"package.json"))){console.log(chalk.red("'package.json' already exists. Run 'create' in an empty folder."));return[2]}id=path.parse(process.cwd()).base;return[4,readline.question("App id [".concat(id,"]:"))];case 1:input=_a.sent();if(input){id=input}return[4,readline.question("Description []:")];case 2:description=_a.sent();fs.writeFileSync(path.join(process.cwd(),"package.json"),'{\n "name": "'.concat(id,'",\n "description": "').concat(description,'",\n "author": {\n "name": "').concat(os.userInfo().username,'"\n },\n "version": "1.0.0",\n "main": "index.ts",\n "type": "module",\n "dependencies": {\n "@hantera/portal-app": "').concat(version,'",\n "vue": "^3.3.4"\n }\n}\n'));fs.writeFileSync(path.join(process.cwd(),"tsconfig.json"),'{\n "compilerOptions": {\n "target": "ESNext",\n "useDefineForClassFields": true,\n "module": "ESNext",\n "moduleResolution": "Node",\n "strict": true,\n "jsx": "preserve",\n "sourceMap": true,\n "resolveJsonModule": true,\n "isolatedModules": true,\n "esModuleInterop": true,\n "lib": ["ESNext", "DOM"],\n "skipLibCheck": true\n },\n "include": ["./**/*.ts", "./**/*.d.ts", "./**/*.tsx", "./**/*.vue"]\n}\n');fs.writeFileSync(path.join(process.cwd(),"index.ts"),"import { Portal, StandardSlots } from '@hantera/portal-app';\nimport MyComponent from './components/MyComponent.vue';\n\nexport default function(portal: Portal) {\n portal.registerComponent(StandardSlots.order.delivery.footer, MyComponent);\n}\n");componentsDir=path.join(process.cwd(),"components");if(!fs.existsSync(componentsDir)){fs.mkdirSync(componentsDir,484)}fs.writeFileSync(path.join(componentsDir,"MyComponent.vue"),"<script setup lang=\"ts\">\nimport { inject } from 'vue';\nimport { deliveryKey, models } from '@hantera/portal-app';\n\nconst delivery = inject<models.Delivery>(deliveryKey);\n<\/script>\n\n<template>\n Current delivery number: {{ delivery?.deliveryNumber }}\n</template>\n");fs.writeFileSync(path.join(process.cwd(),".gitignore"),".hantera/\nnode_modules/\n");console.log(chalk.green("App created. Now run 'h_ dev' to test it."));return[2]}}))}))}function login(env,email,password){return __awaiter(this,void 0,void 0,(function(){var serverUrl,response,payload;return __generator(this,(function(_a){switch(_a.label){case 0:env=env.replace(/[^A-Za-z0-9-]/,"");console.log("Logging in to '".concat(env,"'..."));if(!!email)return[3,2];return[4,readline.question("E-mail:")];case 1:email=_a.sent();_a.label=2;case 2:if(!!password)return[3,4];return[4,readline.question("Password:",{hideEchoBack:true})];case 3:password=_a.sent();_a.label=4;case 4:serverUrl=null;if(env==="localhost"){serverUrl="http://localhost:3100"}else{serverUrl="https://".concat(env,".portal.ams.hantera.cloud")}return[4,fetch("".concat(serverUrl,"/token"),{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email,password})})];case 5:response=_a.sent();if(!response.ok)return[3,7];return[4,response.json()];case 6:payload=_a.sent();config.environments[env]={token:payload.token,displayName:payload.instanceName};config.save();console.log(chalk.green("Logged in successfully"));return[3,8];case 7:console.log(chalk.red("Environment, e-mail and/or password incorrect"));_a.label=8;case 8:return[2]}}))}))}function logout(env){console.log("Logging out from '".concat(env,"'..."));delete config.environments[env];config.save();console.log(chalk.green("Logged out successfully"))}function listEnvironments(){var table=new AsciiTable3;table.setHeading("id","name","E-mail","Expires");for(var env in config.environments){var _a=config.environments[env].token.split(".");_a[0];var payloadRaw=_a[1];_a[2];var buff=Buffer.from(payloadRaw,"base64");var payload=JSON.parse(buff.toString("ascii"));table.addRow(env,config.environments[env].displayName,payload.email,timeConverter(payload.exp))}console.log(table.toString())}function timeConverter(UNIX_timestamp){var a=new Date(UNIX_timestamp*1e3);var months=["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"];var year=a.getFullYear();var month=months[a.getMonth()];var date=a.getDate();var hour=a.getHours();var min=a.getMinutes();var sec=a.getSeconds();var time=date+" "+month+" "+year+" "+hour+":"+min+":"+sec;return time}yargs(hideBin(process.argv)).scriptName("h_").showHelpOnFail(true).demandCommand().command("create","Create a new app in the current folder",(function(yargs){return yargs}),(function(args){return __awaiter(void 0,void 0,void 0,(function(){return __generator(this,(function(_a){switch(_a.label){case 0:return[4,create()];case 1:_a.sent();return[2]}}))}))})).command("install [-e env] [path]","Build and install the app",(function(yargs){return configurePath(yargs).option("environment",{alias:"e",type:"string",description:"The environment to install to, if not specified current environment will be used",demandOption:false})}),(function(args){return __awaiter(void 0,void 0,void 0,(function(){var a,env;return __generator(this,(function(_a){switch(_a.label){case 0:a=app(args["path"]);if(!a){return[2]}env=args.environment;if(!env){env=config.currentEnvironment}if(!env){console.log(chalk.red("No environment specified. Either pass '-e' option or use 'h_ use'"))}return[4,a.build()];case 1:_a.sent();return[4,a.upload(env)];case 2:_a.sent();return[2]}}))}))})).command("deactivate [-e env] <id>","Deactivates the specified app",(function(yargs){return configurePath(yargs).option("environment",{alias:"e",type:"string",description:"The environment to deactivate in, if not specified current environment will be used",demandOption:false}).positional("id",{type:"string",description:"The ID of the app to deactivate",demandOption:true})}),(function(args){return __awaiter(void 0,void 0,void 0,(function(){var r,env;return __generator(this,(function(_a){switch(_a.label){case 0:r=remote();if(!r){return[2]}env=args.environment;if(!env){env=config.currentEnvironment}if(!env){console.log(chalk.red("No environment specified. Either pass '-e' option or use 'h_ use'"))}return[4,r.deactivateApp(env,args.id)];case 1:_a.sent();return[2]}}))}))})).command("activate [-e env] [-v version] <id>","Activates an installed app. Could be a previous version or a deactivated app.",(function(yargs){return yargs.version(false).option("environment",{alias:"e",type:"string",description:"The environment to install to, if not specified current environment will be used",demandOption:false}).option("version",{alias:"v",type:"string",description:"Optionally specify the version to activate. If not set, the latest installed version will be activated.",demandOption:false}).positional("id",{type:"string",description:"The ID of the app to activate",demandOption:true})}),(function(args){return __awaiter(void 0,void 0,void 0,(function(){var r,env;return __generator(this,(function(_a){switch(_a.label){case 0:r=remote();if(!r){return[2]}env=args.environment;if(!env){env=config.currentEnvironment}if(!env){console.log(chalk.red("No environment specified. Either pass '-e' option or use 'h_ use'"))}return[4,r.activateApp(env,args.id,args.version)];case 1:_a.sent();return[2]}}))}))})).command("list [id]","Lists installed apps",(function(yargs){return yargs.option("env",{alias:"e",type:"string",default:config.currentEnvironment,description:"The environment to install to, if not specified current environment will be used",demandOption:false}).positional("id",{type:"string",description:"If specified, will fetch all detailed information about the app including all installed versions",demandOption:false})}),(function(args){return __awaiter(void 0,void 0,void 0,(function(){var r,env;return __generator(this,(function(_a){switch(_a.label){case 0:r=remote();if(!r){return[2]}env=args["env"];if(!env){console.log(chalk.red("No environment specified. Either pass '-e' option or use 'h_ use'"));return[2]}if(!args.id)return[3,2];return[4,r.appDetails(env,args.id)];case 1:_a.sent();return[3,4];case 2:return[4,r.listApps(env)];case 3:_a.sent();_a.label=4;case 4:return[2]}}))}))})).command("dev [path]","Run in local development mode",(function(yargs){return configurePath(yargs)}),(function(args){return __awaiter(void 0,void 0,void 0,(function(){var a;return __generator(this,(function(_a){switch(_a.label){case 0:a=app(args["path"]);if(!a){return[2]}return[4,a.dev()];case 1:_a.sent();return[2]}}))}))})).command("use [environment]","Gets or sets the default environment",(function(yargs){return yargs.positional("environment",{alias:"e",type:"string",description:"The environment to use",demandOption:false})}),(function(args){return __awaiter(void 0,void 0,void 0,(function(){return __generator(this,(function(_a){if(!args["environment"]){console.log("Current environment: ".concat(chalk.bold(config.currentEnvironment)));return[2]}config.currentEnvironment=args.environment;config.save();console.log("Current environment set to '".concat(args.environment,"'"));return[2]}))}))})).command("login [-e env] [-u email] [-p password]","Log in to the current or specified environment",(function(yargs){return yargs.option("environment",{alias:"e",type:"string",description:"The environment to login to, if not specified current environment will be used",demandOption:false}).option("email",{alias:"u",type:"string",demandOption:false}).option("password",{alias:"p",type:"string",demandOption:false})}),(function(args){return __awaiter(void 0,void 0,void 0,(function(){var env;return __generator(this,(function(_a){switch(_a.label){case 0:env=args.environment;if(!env){env=config.currentEnvironment}if(!env){console.log(chalk.red("No environment specified. Either pass '-e' option or use 'h_ use'"))}return[4,login(env,args.email,args.password)];case 1:_a.sent();return[2]}}))}))})).command("logout [-e env]","Log out from the current or specified environment",(function(yargs){return yargs.option("environment",{alias:"e",type:"string",description:"The environment to logout of, if not specified current environment will be used",demandOption:false})}),(function(args){return __awaiter(void 0,void 0,void 0,(function(){var env;return __generator(this,(function(_a){switch(_a.label){case 0:env=args.environment;if(!env){env=config.currentEnvironment}if(!env){console.log(chalk.red("No environment specified. Either pass '-e' option or use 'h_ use'"))}return[4,logout(env)];case 1:_a.sent();return[2]}}))}))})).command(["apply [-e env] <file>"],"Applies a manifest file",(function(yargs){return yargs.option("environment",{alias:"e",type:"string",description:"Overrides the 'env' specified in the manifest file",demandOption:false}).positional("file",{type:"string",description:"The manifest file to apply",demandOption:true})}),(function(args){try{var m=manifest(args.file,args.environment);m.apply()}catch(e){console.log(chalk.red(e))}})).command(["environments","envs"],"Lists all logged in environments",(function(yargs){return yargs}),(function(args){listEnvironments()})).command(["search update [-e env] [--rebuild] <node...>"],"Rebuild search indices",(function(yargs){return yargs.option("environment",{alias:"e",type:"string",description:"The environment to logout of, if not specified current environment will be used",demandOption:false}).option("rebuild",{alias:"r",type:"boolean",description:"If set, indices will be cleared before refreshing them. Faster but will leave search partially inoperable during build.",demandOption:false}).positional("node",{description:"The nodes to rebuild. Pass 'all' to rebuild all indices",demandOption:true})}),(function(args){var env=args.environment;if(!env){env=config.currentEnvironment}if(!env){console.log(chalk.red("No environment specified. Either pass '-e' option or use 'h_ use'"))}var nodes=args.node;var rebuild=args.rebuild;var question;if(rebuild){question=chalk.yellow("Rebuilding index for ".concat(nodes," in '").concat(env,"', this will clear the index before rebuilding, proceed? [y/N]"))}else{question="Update index for ".concat(nodes," in '").concat(env,"', proceed? [y/N]")}var answer=readline.question(question);if(!answer||!(answer==="Y"||answer==="y")){console.log("Aborting");return}if(nodes.length===1&&nodes[0]==="all"){nodes=[]}remote().updateSearchIndices(env,nodes,args.rebuild)})).command(["signals [-e env] [-w watch] [path]"],"Print signals",(function(yargs){return yargs.option("environment",{alias:"e",type:"string",description:"The environment to logout of, if not specified current environment will be used",demandOption:false}).option("watch",{alias:"w",type:"boolean",description:"Refreshes signals every seconds",demandOption:false}).positional("path",{description:"Filter signals by path",demandOption:false})}),(function(args){var env=args.environment;if(!env){env=config.currentEnvironment}if(!env){console.log(chalk.red("No environment specified. Either pass '-e' option or use 'h_ use'"))}if(args.watch){console.clear();console.log("Loading signals...");setInterval((function(){remote().printSignals(env,args.path,true)}),1e3)}else{remote().printSignals(env,args.path)}})).strict().parse();function configurePath(yargs){yargs.positional("path",{default:".",describe:"Local path to the app",type:"string"});return yargs}
|
|
2
|
+
import yargs from"yargs";import{hideBin}from"yargs/helpers";import chalk from"chalk";import path from"path";import fs from"fs";import nodeFetch,{FormData,File}from"node-fetch";import open from"open";import express from"express";import crypto from"crypto";import keytar from"keytar";import{AsciiTable3}from"ascii-table3";import yaml,{stringify,parseAllDocuments}from"yaml";import readline from"readline-sync";import os from"os";import{execSync}from"child_process";import boxen from"boxen";import{createServer,build}from"vite";import vue from"@vitejs/plugin-vue";import mkcert from"vite-plugin-mkcert";import mime from"mime-types";import{BlobWriter,ZipWriter,BlobReader,TextReader}from"@zip.js/zip.js";const configFolder=path.join(process.env.APPDATA||(process.platform=="darwin"?process.env.HOME+"/Library/Preferences":process.env.HOME+"/.local/share"),"hantera-cli");if(!fs.existsSync(configFolder)){fs.mkdirSync(configFolder,484)}const configFile=path.join(configFolder,"hantera-cli.config.json");function loadConfig(){let configContent="{}";if(fs.existsSync(configFile)){configContent=fs.readFileSync(configFile,"utf8")}try{const result=JSON.parse(configContent);if(!result.environments){result.environments={}}return result}catch{console.log(chalk.red("Unable to parse config file. Ignoring."));return{}}}const config={...loadConfig(),save(){fs.writeFileSync(configFile,JSON.stringify(config))}};function getServerUrl(env){if(env==="localhost"){return"http://localhost:3300"}else{return`https://${env}.core.ams.hantera.cloud`}}function remote(){return{async printSignals(env,path,clearConsole=false){var token=config.environments[env]?.token;if(!token){console.log(chalk.red(`No login found for '${env}'`))}const serverUrl=getServerUrl(env);try{let response=await nodeFetch(`${serverUrl}/api/system/signals/${path??""}`,{method:"GET",headers:{"Content-Type":"application/json",Authorization:`Bearer ${token}`}});if(!response.ok){console.log(chalk.red(`Unable to get signals: (${response.status} ${response.statusText}) ${await response.text()}`));return false}else{var result=await response.json();if(clearConsole){console.clear()}result.forEach((signal=>{if(signal.status==="ok"){print(" OK ",chalk.green,signal.id,signal.message)}else if(signal.status==="warning"){print("WARN",chalk.yellow,signal.id,signal.message)}else if(signal.status==="error"){print("ERR ",chalk.red,signal.id,signal.message)}else if(signal.status==="pending"){print("PEND",chalk.gray,signal.id,signal.message)}else if(signal.status==="processing"){print("PROC",chalk.gray,signal.id,signal.message)}function print(status,color,signalId,message){console.log("["+color(status)+`] ${signalId.join("/")}${message?": "+message:""}`)}}));console.log("Updated: "+(new Date).toLocaleTimeString())}}catch(err){if(clearConsole){console.clear()}console.log(chalk.red(`Unable to get signals: ${err}`));console.log("Updated: "+(new Date).toLocaleTimeString())}}}}let enabled=false;function enable(){enabled=true}function verbose(func){if(!enabled){return Promise.resolve()}const value=func();if(value instanceof Promise){return new Promise((resolve=>{value.then((v=>{console.log(chalk.gray(v));resolve()}))}))}else{console.log(chalk.gray(value));return Promise.resolve()}}const service="hantera-cli";async function getSessions(){return(await keytar.findCredentials(service)).map((c=>{try{return JSON.parse(c.password)}catch(e){return null}})).filter((c=>c?.refreshExpiresAt>Date.now()))}async function saveSession(token){await keytar.setPassword(service,token.tenantId,JSON.stringify(token))}async function removeSession(sessionId){await keytar.deletePassword(service,sessionId)}async function setDefaultSession(sessionId){await keytar.setPassword(service,"default",sessionId)}async function getDefaultSession(){return await keytar.getPassword(service,"default")}async function fetch$1(sessionId="default",relativePath,init){var tokenRaw=await keytar.getPassword(service,sessionId);if(!tokenRaw){throw new Error("No token found for the environment")}const token=JSON.parse(tokenRaw);if(token.expiresAt<Date.now()&&(!token.refreshExpiresAt||token.refreshExpiresAt<Date.now())){throw new Error("No token found for the environment")}if(token.expiresAt<Date.now()){if(token.refreshExpiresAt<Date.now()){throw new Error("Tenant session expired")}verbose((()=>"Token expired, attempting to refresh"));const payload=new URLSearchParams;payload.append("grant_type","refresh_token");payload.append("refresh_token",token.refreshToken);payload.append("code_verifier",token.codeVerifier);var response=await nodeFetch(`${token.serverUrl}/oauth/token`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:payload.toString()});if(!response.ok){throw new Error(`Failed to refresh token (${response.statusText}): ${await response.text()}`)}const data=await response.json();const expiresAt=Date.now()+data.expires_in*1e3;const refreshExpiresAt=data.refresh_expires_in?Date.now()+data.refresh_expires_in*1e3:expiresAt;token.accessToken=data.access_token;token.refreshToken=data.refresh_token;token.expiresAt=expiresAt;token.refreshExpiresAt=refreshExpiresAt;token.tenantId=data.tenant_id;token.tenantName=data.tenant_name;await saveSession(token)}if(!init){init={}}if(!init.headers){init.headers={}}init.headers["Authorization"]=`Bearer ${token.accessToken}`;let url;if(token.tenantId==="localhost"){url="http://localhost:3300"}else{url=`https://${token.tenantId}.core.ams.hantera.cloud`}if(!relativePath.startsWith("/")){relativePath="/"+relativePath}await verbose((()=>{let result=`${init.method||"GET"} ${url+relativePath}`;if(init.headers){result+="\n"+Object.keys(init.headers).map((k=>`${k}: ${init.headers[k]}`)).join("\n")+"\n"}if(init.body&&typeof init.body==="object"&&init.headers["Content-Type"]==="application/json"){result+=`\n${JSON.stringify(init.body,null,2)}\n`}else if(init.body){result+=`\n${init.body}\n`}return result}));if(init.body&&typeof init.body==="object"&&init.headers["Content-Type"]==="application/json"){await verbose((()=>"Converting body to JSON"));init.body=JSON.stringify(init.body)}return nodeFetch(url+relativePath,init)}const clientId="00000000-0000-0000-0000-000000000010";var login={command:"login <host>",describe:"Command logging in to a Hantera tenant",builder:yargs=>yargs.option("host",{describe:"The id or hostname of the tenant to login to.",type:"string"}),handler:async argv=>{if(!argv.host){console.log(chalk.red(`No host specified`))}console.log(`Logging in to '${argv.host}'...`);let serverUrl=null;if(argv.host==="localhost"){serverUrl="http://localhost:3300"}else{serverUrl=`https://${argv.host}.core.ams.hantera.cloud`}const state=Math.random().toString(36).substring(7);let redirectUri="";const codeVerifier=Math.random().toString(36).substring(7);let codeChallenge=crypto.createHash("sha256").update(codeVerifier).digest("base64");codeChallenge=codeChallenge.replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"");const web=express();let connections=new Set;web.get("/callback",(async(req,res)=>{if(req.query.state!==state){console.error("Invalid state reported by the server.");res.status(400).send("Invalid state");server.close((()=>{process.exit(1)}));return}try{const response=await nodeFetch(`${serverUrl}/oauth/token`,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({grant_type:"authorization_code",client_id:clientId,redirect_uri:redirectUri,code:req.query.code,code_verifier:codeVerifier})});if(!response.ok){throw response.statusText}const data=await response.json();const expiresAt=Date.now()+data.expires_in*1e3;const refreshExpiresAt=data.refresh_expires_in?Date.now()+data.refresh_expires_in*1e3:expiresAt;var token={accessToken:data.access_token,refreshToken:data.refresh_token,expiresAt,refreshExpiresAt,tenantId:data.tenant_id,tenantName:data.tenant_name,codeVerifier,serverUrl};saveSession(token);console.log(chalk.green("Successfully logged in to "+token.tenantName))}catch(e){console.error(chalk.red("Failed to fetch token:",e));res.redirect(req.query.error_uri+encodeURIComponent(e));res.end();server.close((()=>{process.exit(1)}));return}res.redirect(req.query.success_uri);res.end();setTimeout((()=>{server.close();connections.forEach((conn=>conn.destroy()))}),100)}));const server=web.listen(0,(()=>{const port=server.address().port;redirectUri=`http://localhost:${port}/callback`;const scope="registry:* components:* apps:* actors:* rules:* graph:*";const authorizeUrl=`${serverUrl}/oauth/authorize?client_id=${clientId}&redirect_uri=${encodeURIComponent(redirectUri)}&response_type=code&scope=${scope}&state=${state}&code_challenge=${codeChallenge}&code_challenge_method=S256`;open(authorizeUrl,{wait:false})}));server.on("connection",(conn=>{connections.add(conn);conn.on("close",(()=>connections.delete(conn)))}))}};var sessions={command:"sessions",describe:"Lists active sessions",builder:yargs=>yargs,handler:async argv=>{const table=new AsciiTable3;table.setHeading("ID","Name");var sessions=await getSessions();sessions.forEach((session=>{table.addRow(session.tenantId,session.tenantName)}));console.log(table.toString())}};var logout={command:"logout <session>",describe:"Logs out of a session",builder:yargs=>yargs.option("session",{describe:"The id of the session to logout of",type:"string"}),handler:async argv=>{const session=(await getSessions()).find((s=>s.tenantId===argv.session));if(!session){console.log(chalk.yellow(`Session ${argv.session} not found`));return}removeSession(session.tenantId);console.log(chalk.green(`Logged out of session ${session.tenantName} (${session.tenantId})`))}};var use={command:"use [session]",describe:"Gets or sets the default session to use for management commands",builder:yargs=>yargs.option("session",{describe:"The session to use",type:"string"}),handler:async argv=>{if(argv.session){await setDefaultSession(argv.session);console.log("Default session set to:",chalk.italic(argv.session))}else{const current=await getDefaultSession();if(!current){console.log(chalk.yellow("No session set"));console.log("Use 'h_ manage use <session>' to set the default session");return}console.log("Current session:",chalk.italic(current))}}};function printErrors(errors){if(errors?.errors!==undefined&&Array.isArray(errors.errors)){errors=errors.errors}if(Array.isArray(errors)){errors.forEach((err=>{console.log(chalk.red(`[${err.code}]: ${err.message}`));if(err.details&&Object.keys(err.details).length>0){console.log(chalk.red(err.details))}}))}else{console.log(chalk.red(`[${errors.code}]: ${errors.message}`));if(errors.details&&Object.keys(errors.details).length>0){console.log(chalk.red(errors.details))}}}function parsePath$3(resource){const matches=resource.match(/^\/?(?:resources\/)?components(?:\/([^\?]+))?$/);if(!matches){throw new Error("Invalid resource path")}const[,path]=matches;return path}var components={get:async(sessionId,resource)=>{const path=parsePath$3(resource);const response=await fetch$1(sessionId,`/resources/components/${path||""}?searchType=prefix`);if(response.status!==200){throw new Error(`Failed to get components: ${response.statusText}`)}return(await response.json()).map(mapToManifest$2)},apply:async(sessionId,manifests)=>{for(const manifest of manifests){const componentId=parsePath$3(manifest.uri);if(!componentId){throw new Error("Invalid resource path")}const response=await fetch$1(sessionId,`/resources/components/${componentId}`,{method:"POST",headers:{"Content-Type":"application/json"},body:{...manifest.spec}});if(!response.ok){console.log(chalk.red(`Failed to apply ${manifest.uri}`));const e=await response.json();if(e.errors){printErrors(e.errors)}else{console.log(chalk.red(e))}continue}await verbose((async()=>{const updated=await response.json();return"Updated component:\n"+JSON.stringify(updated,null,2)}));console.log(chalk.green(`Applied ${manifest.uri}`))}},remove:async(sessionId,resource)=>{const componentId=parsePath$3(resource);if(!componentId){throw new Error("Invalid resource path")}const response=await fetch$1(sessionId,`/resources/components/${componentId}`,{method:"DELETE"});if(response.status!==200){throw await response.json()}}};function mapToManifest$2(c){return{uri:`/resources/components/${c.componentId}`,spec:{displayName:c.displayName,description:c.description,runtime:c.runtime,componentVersion:c.componentVersion,code:c.code}}}function parsePath$2(resource){const matches=resource.match(/^\/?(?:resources\/)?registry(?:\/([^\?]+))?$/);if(!matches){throw new Error("Invalid resource path")}const[,path]=matches;return path}var registry={get:async(sessionId,resource)=>{const path=parsePath$2(resource);const response=await fetch$1(sessionId,`/resources/registry/${path||""}?searchType=prefix`);if(response.status!==200){throw new Error(`Failed to get registry entries: ${response.statusText}`)}return(await response.json()).map(mapToManifest$1)},apply:async(sessionId,manifests)=>{const payload=manifests.map((m=>({key:parsePath$2(m.uri),value:m.spec.value,isSecret:m.spec.isSecret})));const response=await fetch$1(sessionId,"/resources/registry",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(payload)});if(!response.ok){console.log(chalk.red(`Failed to apply manifests:`));printErrors(await response.json());return}const updated=await response.json();if(updated.length===0){console.log(chalk.yellow(`No registry keys needed updating`));return}else{console.log(chalk.green(`Updated registry keys:`));for(const update of updated){console.log(chalk.green(`- ${update.key}`));console.log(chalk.green(` - Old: ${update.oldValue}`));console.log(chalk.green(` - New: ${update.newValue}`))}}},remove:async(sessionId,resource)=>{const path=parsePath$2(resource);const response=await fetch$1(sessionId,`/resources/registry/${path}`,{method:"DELETE"});if(response.status!==200){throw await response.json()}}};function mapToManifest$1(c){return{uri:`/resources/registry/${c.key}`,spec:{value:c.value,isSecret:false}}}function parsePath$1(resource){const matches=resource.match(/^\/?(?:resources\/)?rules(?:\/([^\?]+))?$/);if(!matches){throw new Error("Invalid resource path")}const[,path]=matches;return path}var rules={get:async(sessionId,resource)=>{const path=parsePath$1(resource);const response=await fetch$1(sessionId,`/resources/rules/${path||""}?searchType=prefix`);if(response.status!==200){throw new Error(`Failed to get rules: ${response.statusText}`)}return(await response.json()).map(mapToManifest)},apply:async(sessionId,manifests)=>{for(const manifest of manifests){const ruleId=parsePath$1(manifest.uri);if(!ruleId){throw new Error("Invalid resource path")}const response=await fetch$1(sessionId,`/resources/rules/${ruleId}`,{method:"POST",headers:{"Content-Type":"application/json"},body:{...manifest.spec}});if(!response.ok){console.log(chalk.red(`Failed to apply ${manifest.uri}`));const e=await response.json();if(e.errors){printErrors(e.errors)}else{console.log(chalk.red(e))}continue}await verbose((async()=>{const updated=await response.json();return"Updated rule:\n"+JSON.stringify(updated,null,2)}));console.log(chalk.green(`Applied ${manifest.uri}`))}},remove:async(sessionId,resource)=>{const ruleId=parsePath$1(resource);if(!ruleId){throw new Error("Invalid resource path")}const response=await fetch$1(sessionId,`/resources/rules/${ruleId}`,{method:"DELETE"});if(response.status!==200){throw await response.json()}}};function mapToManifest(rule){return{uri:`/resources/rules/${rule.ruleId}`,spec:{displayName:rule.displayName,activeFrom:rule.activeFrom,activeTo:rule.activeTo,components:rule.components?.map((c=>({namespace:c.componentNamespace,name:c.componentName,parameters:c.parameters})))}}}function parsePath(resource){const matches=resource.match(/^\/?(?:resources\/)?actors\/([a-z]+?)\/([a-fA-F0-9-]+)\/?$/);if(!matches){throw new Error("Invalid resource actor path: "+resource)}const[,actorType,actorId]=matches;return{actorType,actorId}}var actors={get:async(sessionId,resource)=>{const{actorType,actorId}=parsePath(resource);const response=await fetch$1(sessionId,`/resources/actors/${actorType}/${actorId}`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify([{type:"debugDump"}])});if(response.status!==200){throw new Error(`Failed to get debug dump: ${response.statusText}`)}return await response.json()},apply:async(sessionId,manifests)=>{throw new Error("'apply' is not supported on actors")},remove:async(sessionId,resource)=>{throw new Error("'remove' is not supported on actors")}};var adapters={getAdapter(resourcePath){const matches=resourcePath.match(/^\/?(?:resources\/)?(\w+?)(?:\/|$)/);if(!matches){console.log(chalk.red("Invalid resource path"));return}const[,resource]=matches;if(resource==="components"){return components}else if(resource==="registry"){return registry}else if(resource==="rules"){return rules}else if(resource==="actors"){return actors}else{console.log(chalk.red("Invalid resource or not supported"));return}}};var get={command:"get <resource>",describe:"Gets the manifest for the given resource (if supported)",builder:yargs=>yargs.positional("resource",{describe:"The resource path to get",type:"string",demandOption:true}).option("session",{alias:"s",describe:"The session to use",type:"string",demandOption:false}).option("out",{alias:"o",describe:"The file to output to",type:"string",demandOption:false}),handler:async argv=>{var sessionId=await getDefaultSession()||argv.session;if(!sessionId){console.log(chalk.red("No session set. Use h_ manage use <session> to set the default session or pass the session with -s <session>"));return}let adapter=adapters.getAdapter(argv.resource);if(!adapter){console.log(chalk.red(`Invalid resource path '${argv.resource}'`));return}try{const manifests=await(adapter?.get(sessionId,argv.resource));if(!manifests){console.log(chalk.red("Failed to get manifest"));return}let result;if(Array.isArray(manifests)){result=manifests.map((s=>stringify(s))).join("---\n")}else{result=stringify(manifests)}if(argv.out){console.log(chalk.green(`Writing to ${argv.out}`));fs.writeFileSync(argv.out,result)}else{console.log(result)}}catch(e){console.log(chalk.red(`Failed to get ${argv.resource}`));if(e.errors){printErrors(e.errors)}else{console.log(chalk.red(e))}}}};var remove={command:"remove <resource>",describe:"Removes the given resource (if supported)",builder:yargs=>yargs.positional("resource",{describe:"The resource to remove",type:"string",demandOption:true}).option("session",{alias:"s",describe:"The session to use",type:"string",demandOption:false}),handler:async argv=>{var sessionId=await getDefaultSession()||argv.session;if(!sessionId){console.log(chalk.red("No session set. Use h_ manage use <session> to set the default session or pass the session with -s <session>"));return}let adapter=adapters.getAdapter(argv.resource);if(!adapter){console.log(chalk.red(`Invalid resource path '${argv.resource}'`));return}try{await adapter.remove(sessionId,argv.resource);console.log(chalk.green(`Removed ${argv.resource}`))}catch(e){console.log(chalk.red(`Failed to remove ${argv.resource}`));printErrors(e.errors)}}};var apply={command:"apply [file]",describe:"Applies the given manifest file to the remote Hantera installation. If not specified, stdin is used.",builder:yargs=>yargs.positional("file",{describe:"The file to apply",type:"string"}).option("session",{alias:"s",describe:"The session to use",type:"string",demandOption:false}),handler:async argv=>{var sessionId=await getDefaultSession()||argv.session;if(!sessionId){console.log(chalk.red("No session set. Use h_ manage use <session> to set the default session or pass the session with -s <session>"));return}let data="";if(argv.file){data=fs.readFileSync(argv.file,"utf8")}else if(!process.stdin.isTTY){process.stdin.on("data",(chunk=>{data+=chunk}));process.stdin.on("end",(()=>{console.log("Received input:");console.log(data)}))}else{console.log(chalk.red("No input provided"));return}const manifests=parseAllDocuments(data).map((r=>r.toJS()));if(!manifests){throw`'${argv.file}' is empty or invalid.`}const mappedManifests=new Map;for(const manifest of manifests){const adapter=adapters.getAdapter(manifest.uri);if(!adapter){console.log(chalk.red(`Invalid resource path '${manifest.uri}'`));continue}mappedManifests.set(manifest,adapter)}for(const[manifest,adapter]of mappedManifests.entries()){try{await adapter.apply(sessionId,[manifest])}catch(e){console.log(chalk.red(`Failed to apply ${manifests.length} manifests`));console.log(e)}}}};var list={command:"list",describe:"Lists installed apps",builder:yargs=>yargs.option("session",{alias:"s",describe:"The session to use",type:"string",demandOption:false}),handler:async argv=>{var sessionId=await getDefaultSession()||argv.session;if(!sessionId){console.log(chalk.red("No session set. Use h_ manage use <session> to set the default session or pass the session with -s <session>"));return}try{const response=await fetch$1(sessionId,"/resources/apps");if(!response.ok){throw new Error(`Failed to get apps: ${response.statusText}`)}const apps=await response.json();const table=new AsciiTable3(`Apps in '${sessionId}'`);table.setHeading("Id","Name","Current Version","Authors","Description");table.setWidth(5,30).setWrapped(4);let count=0;for(var app of apps){count+=1;table.addRow(app.id,app.name,app.currentVersion,app.authors.join("\n"),app.description)}if(count>0){console.log(table.toString())}else{console.log("No apps installed")}}catch(e){if(e.errors){printErrors(e.errors)}else{console.log(chalk.red(e))}}}};var details={command:"details <appId>",describe:"Gets details of an app",builder:yargs=>yargs.positional("appId",{describe:"The id of the app",type:"string"}).option("session",{alias:"s",describe:"The session to use",type:"string",demandOption:false}),handler:async argv=>{var sessionId=await getDefaultSession()||argv.session;if(!sessionId){console.log(chalk.red("No session set. Use h_ manage use <session> to set the default session or pass the session with -s <session>"));return}try{const response=await fetch$1(sessionId,"/resources/apps/"+argv.appId);if(response.status===404){console.log(chalk.red(`App '${argv.appId}' not found`));return}if(!response.ok){throw new Error(`Failed to get apps: ${response.statusText}`)}const app=await response.json();console.log(chalk.bold("App Details"));console.log("-------------");console.log("Id:",app.id);console.log("Name:",app.name);if(app.description){console.log("Description:");console.log(app.description)}if(app.authors?.length>0){console.log("Authors:");for(var author of app.authors){console.log("- "+author)}}console.log("Installed Versions:");for(var version of app.installedVersions){if(version===app.currentVersion){console.log(chalk.green(`- ${version} (active)`))}else{console.log(`- ${version}`)}}if(!app.currentVersion){console.log(chalk.yellow("No active version"))}else{if(app.files?.length>0){console.log();const table=new AsciiTable3("Files");table.setHeading("Path","Mime Type","Size","Metadata");for(var file of app.files){table.addRow(file.path,file.mimeType,file.size,JSON.stringify(file.metadata))}console.log(table.toString())}}}catch(e){if(e.errors){printErrors(e.errors)}else{console.log(chalk.red(e))}}}};var install={command:"install <hapk file>",describe:"Gets details of an app",builder:yargs=>yargs.positional("hapk file",{describe:"The app package to install",type:"string"}).option("session",{alias:"s",describe:"The session to use",type:"string",demandOption:false}),handler:async argv=>{var sessionId=await getDefaultSession()||argv.session;if(!sessionId){console.log(chalk.red("No session set. Use h_ manage use <session> to set the default session or pass the session with -s <session>"));return}try{var packagePath=path.resolve(argv.hapkfile);if(!fs.existsSync(packagePath)){console.log(chalk.red(`File not found: ${packagePath}`));return}const formData=new FormData;const packageFile=new File([fs.readFileSync(packagePath)],path.basename(packagePath),{type:"application/zip"});formData.set("package",packageFile,path.basename(packagePath));const response=await fetch$1(sessionId,"/resources/apps",{method:"POST",body:formData});if(!response.ok){throw new Error(`Failed to install app (${response.statusText}): ${await response.text()}`)}const app=await response.json();console.log(chalk.green(`Installed app ${app.name} (${app.id}) version ${app.currentVersion}`))}catch(e){if(e.errors){printErrors(e.errors)}else{console.log(chalk.red(e))}}}};var activate={command:"activate <appId> [-v <version>]",describe:"Activate a deactivated app or change active version",builder:yargs=>yargs.positional("appId",{describe:"The id of the app",type:"string"}).option("session",{alias:"s",describe:"The session to use",type:"string",demandOption:false}).option("app-version",{alias:"v",describe:"The version to activate",type:"string",demandOption:false}),handler:async argv=>{var sessionId=await getDefaultSession()||argv.session;if(!sessionId){console.log(chalk.red("No session set. Use h_ manage use <session> to set the default session or pass the session with -s <session>"));return}try{const appId=argv.appId;let version=argv["app-version"];if(!version){version=await getLatestVersion(sessionId,appId)}const response=await fetch$1(sessionId,"/resources/apps/"+appId,{method:"POST",headers:{"Content-Type":"application/json"},body:{version}});if(response.status===404){console.log(chalk.red(`App '${argv.appId}' not found`));return}if(!response.ok){throw new Error(`Failed to activate app (${response.statusText}): ${await response.text()}`)}console.log(chalk.green(`Activated app ${appId} version ${version}`))}catch(e){if(e.errors){printErrors(e.errors)}else{console.log(chalk.red(e))}}}};async function getLatestVersion(sessionId,appId){const response=await fetch$1(sessionId,"/resources/apps/"+appId);if(response.status===404){throw new Error(`App '${appId}' not found`)}if(!response.ok){throw new Error(`Failed to get current app version (${response.statusText}): ${await response.text()}`)}const app=await response.json();app.installedVersions.sort(((a,b)=>a.localeCompare(b,undefined,{numeric:true,sensitivity:"base"})));return app.installedVersions[app.installedVersions.length-1]}var deactivate={command:"deactivate <appId>",describe:"Deactivates an app",builder:yargs=>yargs.positional("appId",{describe:"The id of the app",type:"string"}).option("session",{alias:"s",describe:"The session to use",type:"string",demandOption:false}),handler:async argv=>{var sessionId=await getDefaultSession()||argv.session;if(!sessionId){console.log(chalk.red("No session set. Use h_ manage use <session> to set the default session or pass the session with -s <session>"));return}try{const appId=argv.appId;const response=await fetch$1(sessionId,"/resources/apps/"+appId,{method:"POST",headers:{"Content-Type":"application/json"},body:{version:null}});if(response.status===404){console.log(chalk.red(`App '${argv.appId}' not found`));return}if(!response.ok){throw new Error(`Failed to activate app (${response.statusText}): ${await response.text()}`)}console.log(chalk.green(`Deactivated app ${appId}`))}catch(e){if(e.errors){printErrors(e.errors)}else{console.log(chalk.red(e))}}}};var apps={command:"apps <command>",describe:"Commands for managing tenant",builder(yargs){return yargs.command(list).command(details).command(install).command(activate).command(deactivate).demandCommand(1,"You need at least one sub-command")}};var updateSearch={command:"update-search <node...>",describe:"Update/rebuild search indices",builder:yargs=>yargs.positional("node",{description:"The nodes to rebuild. Pass 'all' to rebuild all indices",demandOption:true}).option("rebuild",{alias:"r",type:"boolean",description:`If set, indices will be cleared before refreshing them. Faster but will leave search partially inoperable during build.`,demandOption:false}).option("session",{alias:"s",describe:"The session to use",type:"string",demandOption:false}),handler:async argv=>{var sessionId=await getDefaultSession()||argv.session;if(!sessionId){console.log(chalk.red("No session set. Use h_ manage use <session> to set the default session or pass the session with -s <session>"));return}const session=(await getSessions()).find((r=>r.tenantId===sessionId));if(!session){console.log(chalk.red(`Session '${sessionId}' not found`));return}let nodes=argv.node;const rebuild=argv.rebuild;let question;if(rebuild){question=chalk.yellow(`Rebuilding index for ${nodes} in '${session.tenantName}', this will clear the index before rebuilding, proceed? [y/N]`)}else{question=`Update index for ${nodes} in '${session.tenantName}', proceed? [y/N]`}const answer=readline.question(question);if(!answer||!(answer==="Y"||answer==="y")){console.log("Aborting");return}if(nodes.length===1&&nodes[0]==="all"){nodes=[]}try{const payload={nodes,rebuild};console.log(`Scheduling index update..`);const response=await fetch$1(sessionId,"/api/system/searchIndex/update",{method:"POST",headers:{"Content-Type":"application/json"},body:payload});if(!response.ok){throw new Error(`Unable to schedule rebuild: (${response.status} ${response.statusText}) ${await response.text()}`)}console.log(chalk.green(`Rebuild scheduled successfully!`));console.log(`This operation may take a while to complete. Use 'h_ manage signals processes/graph' to check progress.`)}catch(e){if(e.errors){printErrors(e.errors)}else{console.log(chalk.red(e))}}}};var signals={command:"signals <path>",describe:"Update/rebuild search indices",builder:yargs=>yargs.positional("path",{description:"Filter signals by path",demandOption:false}).option("watch",{alias:"w",type:"boolean",description:`Refreshes signals every seconds`,demandOption:false}).option("session",{alias:"s",describe:"The session to use",type:"string",demandOption:false}),handler:async argv=>{var sessionId=await getDefaultSession()||argv.session;if(!sessionId){console.log(chalk.red("No session set. Use h_ manage use <session> to set the default session or pass the session with -s <session>"));return}const session=(await getSessions()).find((r=>r.tenantId===sessionId));if(!session){console.log(chalk.red(`Session '${sessionId}' not found`));return}if(argv.watch){console.clear();console.log("Loading signals...");setInterval((()=>{printSignals(true)}),1e3)}else{await printSignals()}async function printSignals(clearConsole=false){try{const response=await fetch$1(sessionId,`/api/system/signals/${argv.path??""}`,{method:"GET"});if(!response.ok){throw new Error(`Unable to get signals: (${response.status} ${response.statusText}) ${await response.text()}`)}var result=await response.json();if(clearConsole){console.clear()}result.forEach((signal=>{if(signal.status==="ok"){print(" OK ",chalk.green,signal.id,signal.message)}else if(signal.status==="warning"){print("WARN",chalk.yellow,signal.id,signal.message)}else if(signal.status==="error"){print("ERR ",chalk.red,signal.id,signal.message)}else if(signal.status==="pending"){print("PEND",chalk.gray,signal.id,signal.message)}else if(signal.status==="processing"){print("PROC",chalk.gray,signal.id,signal.message)}function print(status,color,signalId,message){console.log("["+color(status)+`] ${signalId.join("/")}${message?": "+message:""}`)}}));console.log("Updated: "+(new Date).toLocaleTimeString())}catch(e){if(e.errors){printErrors(e.errors)}else{console.log(chalk.red(e))}}}}};var manage={command:"manage <command>",describe:"Commands for managing tenant",builder(yargs){return yargs.command(login).command(logout).command(sessions).command(use).command(get).command(apply).command(remove).command(apps).command(updateSearch).command(signals).demandCommand(1,"You need at least one sub-command")}};var $new={command:"new",describe:"Creates a new app",builder:yargs=>yargs,handler:async argv=>{let appName=question("App Name",(value=>{if(!value){console.log(chalk.red("App Name is required."));return false}return true}));let defaultAppId=appName.replace(/[^a-z0-9]/gi,"-").replace(/^-+|-+$/g,"").toLowerCase();const appId=question(`App ID [${defaultAppId}]`,(value=>{if(!value){value=defaultAppId}if(!/^[a-z0-9_-]+$/.test(value)){console.log(chalk.red("App ID can only contain lowercase letters, numbers, dash and underscope."));return false}return true}))||defaultAppId;let appFolder=path.resolve(question(`Path [./${appId}/]`)||`./${appId}/`);let description=question("Description");let author=question(`Author [${os.userInfo().username}]`)||os.userInfo().username;let setupPortalApp=question("Setup portal app? (y/n)",(value=>{if(value!=="y"&&value!=="n"){console.log(chalk.red('Invalid value. Please enter "y" or "n".'));return false}return true}))==="y";const appConfig={id:appId,name:appName,description,authors:[author]};if(setupPortalApp){appConfig.extensions={portal:"./portal"}}if(!fs.existsSync(appFolder)){fs.mkdirSync(appFolder)}const filePath=path.join(appFolder,"h_app.yaml");if(fs.existsSync(filePath)){console.log(chalk.red(`'h_app.yaml' already exists. Run 'h_ app new' in an empty folder.`));return}console.log(chalk.gray(`Creating ${filePath}...`));fs.writeFileSync(filePath,stringify(appConfig));console.log(chalk.green("Done."));const ignore=[".hantera/"];if(setupPortalApp){const portalFolder=path.join(path.resolve(appFolder),"portal");if(!fs.existsSync(portalFolder)){console.log(chalk.gray(`Creating ${portalFolder}...`));fs.mkdirSync(portalFolder);console.log(chalk.green("Done."))}await createPortalApp(appId,appFolder,portalFolder);const relativePortalFolder=path.relative(appFolder,portalFolder);ignore.push(path.join(relativePortalFolder,"node_modules"))}console.log(chalk.gray(`Creating ${path.join(appFolder,".gitignore")}...`));fs.writeFileSync(path.join(appFolder,".gitignore"),ignore.join("\n"));console.log(chalk.green("Done."));console.log(`App '${appId}' created in '${appFolder}'. Run '${chalk.green("h_ app package")}' to create a hapk package.`)}};function question(label,validator){let value="";while(true){value=readline.question(label+": ");if(validator&&!validator(value)){continue}break}return value}async function createPortalApp(appId,appFolder,portalFolder){if(fs.existsSync(path.join(portalFolder,"package.json"))){console.log(chalk.red(`'package.json' already exists. Run 'h_ app new' in an empty folder.`));return}const response=await fetch("https://registry.npmjs.org/@hantera/portal-app");const json=await response.json();const portalAppVersion=json["dist-tags"].latest;console.log(chalk.gray(`Creating ${path.join(portalFolder,"package.json")}...`));fs.writeFileSync(path.join(portalFolder,"package.json"),`{\n "name": "${appId}",\n "version": "1.0.0",\n "main": "index.ts",\n "type": "module",\n "dependencies": {\n "@hantera/portal-app": "${portalAppVersion}",\n "vue": "^3.4.37"\n }\n}\n`);console.log(chalk.green("Done."));console.log(chalk.gray(`Creating ${path.join(portalFolder,"tsconfig.json")}...`));fs.writeFileSync(path.join(portalFolder,"tsconfig.json"),`{\n "compilerOptions": {\n "target": "ESNext",\n "useDefineForClassFields": true,\n "module": "ESNext",\n "moduleResolution": "Node",\n "strict": true,\n "jsx": "preserve",\n "sourceMap": true,\n "resolveJsonModule": true,\n "isolatedModules": true,\n "esModuleInterop": true,\n "lib": ["ESNext", "DOM"],\n "skipLibCheck": true\n },\n "include": ["./**/*.ts", "./**/*.d.ts", "./**/*.tsx", "./**/*.vue"]\n}\n`);console.log(chalk.green("Done."));console.log(chalk.gray(`Creating ${path.join(portalFolder,"index.ts")}...`));fs.writeFileSync(path.join(portalFolder,"index.ts"),`import { Portal, StandardSlots } from '@hantera/portal-app';\nimport MyComponent from './components/MyComponent.vue';\n\nexport default function(portal: Portal) {\n portal.registerComponent(StandardSlots.order.delivery.footer, MyComponent);\n}\n`);console.log(chalk.green("Done."));const componentsDir=path.join(portalFolder,"components");if(!fs.existsSync(componentsDir)){console.log(chalk.gray(`Creating ${componentsDir}...`));fs.mkdirSync(componentsDir,484);console.log(chalk.green("Done."))}console.log(chalk.gray(`Creating ${path.join(componentsDir,"MyComponent.vue")}...`));fs.writeFileSync(path.join(componentsDir,"MyComponent.vue"),`<script setup lang="ts">\nimport { inject } from 'vue';\nimport { deliveryKey, models } from '@hantera/portal-app';\n\nconst delivery = inject<models.Delivery>(deliveryKey);\n<\/script>\n\n<template>\n Current delivery number: {{ delivery?.deliveryNumber }}\n</template>\n`);console.log(chalk.green("Done."));console.log(chalk.gray(`Installing dependencies...`));execSync("npm install",{cwd:portalFolder,stdio:"inherit"});console.log(chalk.green("Done."));console.log("\n");console.log(`Portal app created. Run '${chalk.green("h_ app dev")}' to start the local development server.`)}function packageToImportMapKey$1(p){return"__portal_"+p.replace("@","").replace("/","_").replace("-","_")}function portalResolve$1(packages){const packageIds=packages.map(packageToImportMapKey$1);return{name:"vite-plugin-portal-resolve",enforce:"pre",config(config){config.optimizeDeps={...config.optimizeDeps??{},exclude:[...config.optimizeDeps?.exclude??[],...packages]};if(!config.build){config.build={}}if(!config.build.rollupOptions){config.build.rollupOptions={}}config.build.rollupOptions.external=[...config.build.rollupOptions.external??[],...packages.map(packageToImportMapKey$1)]},configResolved(resolvedConfig){const VALID_ID_PREFIX=`/@id/`;const reg=new RegExp(`${VALID_ID_PREFIX}(${packages.map((r=>packageToImportMapKey$1(r))).join("|")})`,"g");resolvedConfig.plugins.push({name:"vite-plugin-portal-resolve-replace-idprefix",transform:code=>{const result=reg.test(code)?code.replace(reg,((m,s1)=>s1)):code;return result}})},async resolveId(source,importer,options){if(packages.includes(source)){return{id:packageToImportMapKey$1(source),external:true,resolvedBy:"vite-plugin-portal-resolve"}}},load(id){if(packageIds.indexOf(id)!==-1){return`export default {};`}}}}function packageToImportMapKey(p){return"__portal_"+p.replace("@","").replace("/","_").replace("-","_")}function portalResolve(packages){const reg=new RegExp(`(import (?:.+?) from ["'])(${packages.map((r=>r.replace("/","\\/"))).join("|")})(["'];?)`,"g");return{name:"vite-plugin-portal-resolve",enforce:"pre",config(config){config.optimizeDeps={...config.optimizeDeps??{},exclude:[...config.optimizeDeps?.exclude??[],...packages]};if(!config.build){config.build={}}if(!config.build.rollupOptions){config.build.rollupOptions={}}config.build.rollupOptions.external=[...config.build.rollupOptions.external??[],...packages.map(packageToImportMapKey)]},configResolved(resolvedConfig){resolvedConfig.plugins.push({name:"vite-plugin-portal-resolve-replace-idprefix",transform:code=>{const result=reg.test(code)?code.replace(reg,((m,s1,s2,s3)=>s1+packageToImportMapKey(s2)+s3)):code;return result}})}}}function developmentConfig(cacheFolder){return{configFile:false,mode:"development",root:cacheFolder,plugins:[vue(),portalResolve$1(["vue","@hantera/portal-app"]),mkcert()],logLevel:"error",server:{port:4734},build:{target:"esnext"}}}function buildConfig(portalFolder,entry,outFolder){const result=developmentConfig(portalFolder);result.mode="production";delete result.server;result.logLevel="warn";result.build.lib={entry,name:"hantera-app",fileName:"index",formats:["es"]};result.plugins=[vue(),portalResolve(["vue","@hantera/portal-app"])];result.build.emptyOutDir=true;result.build.outDir=outFolder;return result}var dev={command:"dev [path]",describe:"Starts a portal app in local development mode",builder:yargs=>yargs.positional("path",{describe:"Path to the app",type:"string",default:"."}),handler:async argv=>{const appFolder=path.resolve(argv.path);const appConfigPath=path.join(appFolder,"h_app.yaml");if(!fs.existsSync(appConfigPath)){console.log(chalk.red(`'h_app.yaml' not found in path '${appFolder}'`));return}const appConfig=yaml.parse(fs.readFileSync(appConfigPath,"utf8"));if(!appConfig.extensions?.portal){console.log(chalk.red(`'h_app.yaml' missing 'extensions.portal' property.`));return}const portalFolder=path.join(appFolder,appConfig.extensions.portal);if(!fs.existsSync(path.join(portalFolder,"package.json"))){console.log(chalk.red(`'package.json' not found in path '${portalFolder}'`));return}const packageJson=JSON.parse(fs.readFileSync(path.join(portalFolder,"package.json"),"utf8"));const entryPath=path.normalize(path.join(portalFolder,packageJson.main||"index.ts"));let cacheDir=path.join(appFolder,".hantera");if(!fs.existsSync(cacheDir)){fs.mkdirSync(cacheDir,484)}cacheDir=path.join(cacheDir,"portal");if(!fs.existsSync(cacheDir)){fs.mkdirSync(cacheDir,484)}fs.writeFile(path.join(cacheDir,"index.html"),`<!DOCTYPE html>\n <html lang="en">\n <head>\n </head>\n <body>\n <script type="module" src="loader.ts"><\/script>\n </body>\n </html>\n `,(err=>{if(err){console.error(err)}}));const loader_ts=`export const appId = ${JSON.stringify(packageJson.name)};\n export { default as default } from '${path.relative(cacheDir,entryPath).replaceAll("\\","/").replaceAll(".ts","")}';`;fs.writeFile(path.join(cacheDir,"loader.ts"),loader_ts,(err=>{if(err){console.error(err)}}));const server=await createServer(developmentConfig(cacheDir));await server.listen();console.log(chalk.green("Local app development is running.."));console.log(boxen(chalk.black(`To enable local development mode in Hantera portal:\n- Go to Developer settings\n- Click "Enable Local Development"`),{borderStyle:"none",backgroundColor:"blue",padding:1}))}};var pack={command:"pack [path] [-v 1.0.0]",describe:"Builds and package the app",builder:yargs=>yargs.positional("path",{describe:"Path to the app",type:"string",default:"."}).option("package-version",{alias:"v",describe:"Version of the app",type:"string",default:"1.0.0"}),handler:async argv=>{const appFolder=path.resolve(argv.path);const appConfigPath=path.join(appFolder,"h_app.yaml");if(!fs.existsSync(appConfigPath)){console.log(chalk.red(`'h_app.yaml' not found in path '${appFolder}'`));return}const appConfig=yaml.parse(fs.readFileSync(appConfigPath,"utf8"));const packageManifest={id:appConfig.id,name:appConfig.name,description:appConfig.description,authors:appConfig.authors,version:argv.packageVersion,files:[],components:[]};if(!packageManifest.id){console.log(chalk.red(`'id' property is required in 'h_app.yaml'`));return}if(!packageManifest.name){console.log(chalk.red(`'name' property is required in 'h_app.yaml'`));return}const zipFileWriter=new BlobWriter;const zipWriter=new ZipWriter(zipFileWriter);if(Array.isArray(appConfig.files)){for(const file of appConfig.files){if(!file.source){console.log(chalk.red(`'source' property is required for each file in 'h_app.yaml'`));return}let id=file.id;if(!id){id=path.basename(file.source)}id=id.replace("\\","/");if(id.startsWith("portal/")){console.log(chalk.red(`File ID cannot start with 'portal/'`));return}let mimeType=file.mimeType;if(!mimeType){mimeType=mime.lookup(file.source)||"application/octet-stream"}packageManifest.files.push({id,mimeType,metadata:file.metadata||{}});const entryId=path.join("files",id).replace("\\","/");const fileReader=new BlobReader(new Blob([fs.readFileSync(path.resolve(file.source))]));console.log(entryId);await zipWriter.add(entryId,fileReader)}}if(Array.isArray(appConfig.components)){for(const component of appConfig.components){if(!component.source){console.log(chalk.red(`'source' property is required for each component in 'h_app.yaml'`));return}let id=component.id;if(!id){id=path.basename(component.source)}id=id.replaceAll("\\","/");let runtime=component.runtime;if(!runtime){runtime=path.extname(component.source).substring(1)}if(runtime!=="rule"&&runtime!="discount"){console.log(chalk.red(`Unsupported runtime '${runtime}' for component '${id}'`));return}packageManifest.components.push({id,displayName:component.displayName,description:component.description,runtime});const entryId=path.join("components",id).replaceAll("\\","/");const fileReader=new BlobReader(new Blob([fs.readFileSync(path.resolve(component.source))]));await zipWriter.add(entryId,fileReader)}}if(appConfig.extensions?.portal){const portalFolder=path.join(appFolder,appConfig.extensions.portal);if(!fs.existsSync(path.join(portalFolder,"package.json"))){console.log(chalk.red(`'package.json' not found in path '${portalFolder}'`));return}const packageJson=JSON.parse(fs.readFileSync(path.join(portalFolder,"package.json"),"utf8"));const entryPath=path.normalize(path.join(portalFolder,packageJson.main||"index.ts"));const distFolder=path.join(appFolder,".hantera","portal","dist");fs.rmSync(distFolder,{recursive:true,force:true});await build(buildConfig(portalFolder,entryPath,distFolder));const files=fs.readdirSync(distFolder);for(const file of files){const filePath=path.join(distFolder,file);const mimeType=path.extname(file)===".js"?"application/javascript":"text/css";const fileId=path.join("portal",file).replaceAll("\\","/");packageManifest.files.push({id:fileId,mimeType,metadata:{portal:"true"}});const entryId=path.join("files","portal",file).replaceAll("\\","/");const fileReader=new BlobReader(new Blob([fs.readFileSync(filePath)]));await zipWriter.add(entryId,fileReader)}}const manifestReader=new TextReader(JSON.stringify(packageManifest,null,2));await zipWriter.add("manifest.json",manifestReader);await zipWriter.close();const zipFileBlob=await zipFileWriter.getData();const zipFileArrayBuffer=await zipFileBlob.arrayBuffer();const packagePath=path.join(appFolder,`${packageManifest.id}-${packageManifest.version}.hapk`);fs.writeFileSync(packagePath,Buffer.from(zipFileArrayBuffer));console.log(`App '${packageManifest.id}' packaged in '${packagePath}'.`)}};var app={command:"app <command>",describe:"Commands for authoring apps",builder(yargs){return yargs.command($new).command(dev).command(pack).demandCommand(1,"You need at least one sub-command")}};const commands=[app,manage];if(process.argv.find((v=>v==="--verbose"))){enable()}yargs(hideBin(process.argv.filter((r=>r!=="--verbose")))).scriptName("h_").showHelpOnFail(true).command(commands).demandCommand().command(["signals [-e env] [-w watch] [path]"],"Print signals",(yargs=>yargs.option("environment",{alias:"e",type:"string",description:`The environment to logout of, if not specified current environment will be used`,demandOption:false}).option("watch",{alias:"w",type:"boolean",description:`Refreshes signals every seconds`,demandOption:false}).positional("path",{description:"Filter signals by path",demandOption:false})),(args=>{let env=args.environment;if(!env){env=config.currentEnvironment}if(!env){console.log(chalk.red(`No environment specified. Either pass '-e' option or use 'h_ use'`))}if(args.watch){console.clear();console.log("Loading signals...");setInterval((()=>{remote().printSignals(env,args.path,true)}),1e3)}else{remote().printSignals(env,args.path)}})).strict().parse();
|
package/package.json
CHANGED
|
@@ -1,39 +1,46 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@hantera/cli",
|
|
3
|
-
"version": "
|
|
4
|
-
"type": "module",
|
|
5
|
-
"main": "dist/index.js",
|
|
6
|
-
"scripts": {
|
|
7
|
-
"build": "rollup -c ./rollup.config.js",
|
|
8
|
-
"install-global": "npm install -g ."
|
|
9
|
-
},
|
|
10
|
-
"bin": {
|
|
11
|
-
"h_": "./dist/index.js"
|
|
12
|
-
},
|
|
13
|
-
"files": [
|
|
14
|
-
"/dist"
|
|
15
|
-
],
|
|
16
|
-
"dependencies": {
|
|
17
|
-
"@hantera/cli": "file:",
|
|
18
|
-
"@vitejs/plugin-vue": "^
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
"
|
|
25
|
-
"
|
|
26
|
-
"
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
"
|
|
35
|
-
"
|
|
36
|
-
"
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@hantera/cli",
|
|
3
|
+
"version": "20240922.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"build": "rollup -c ./rollup.config.js",
|
|
8
|
+
"install-global": "npm install -g ."
|
|
9
|
+
},
|
|
10
|
+
"bin": {
|
|
11
|
+
"h_": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"files": [
|
|
14
|
+
"/dist"
|
|
15
|
+
],
|
|
16
|
+
"dependencies": {
|
|
17
|
+
"@hantera/cli": "file:",
|
|
18
|
+
"@vitejs/plugin-vue": "^5.1.2",
|
|
19
|
+
"@zip.js/zip.js": "^2.7.45",
|
|
20
|
+
"ascii-table3": "^0.8.2",
|
|
21
|
+
"boxen": "^7.1.0",
|
|
22
|
+
"chalk": "^5.2.0",
|
|
23
|
+
"esbuild": "^0.23.1",
|
|
24
|
+
"express": "^4.19.2",
|
|
25
|
+
"json-colorizer": "^3.0.1",
|
|
26
|
+
"keytar": "^7.9.0",
|
|
27
|
+
"mime-types": "^2.1.35",
|
|
28
|
+
"node-fetch": "^3.3.1",
|
|
29
|
+
"open": "^10.1.0",
|
|
30
|
+
"readline-sync": "^1.4.10",
|
|
31
|
+
"tslib": "^2.5.3",
|
|
32
|
+
"typescript": "^5.5.4",
|
|
33
|
+
"vite": "^5.4.2",
|
|
34
|
+
"vite-plugin-mkcert": "^1.16.0",
|
|
35
|
+
"vue": "^3.4.37",
|
|
36
|
+
"vue-tsc": "^2.0.26",
|
|
37
|
+
"yaml": "^2.3.1",
|
|
38
|
+
"yargs": "^17.7.2"
|
|
39
|
+
},
|
|
40
|
+
"devDependencies": {
|
|
41
|
+
"@rollup/plugin-terser": "^0.4.3",
|
|
42
|
+
"@rollup/plugin-typescript": "^11.1.1",
|
|
43
|
+
"rollup": "^3.25.2"
|
|
44
|
+
},
|
|
45
|
+
"license": "MIT"
|
|
46
|
+
}
|