@devbookhq/sdk
Advanced tools
Comparing version 1.0.3 to 1.0.4
import { Env } from './constants'; | ||
export interface FS { | ||
get: (path: string) => Promise<string | undefined>; | ||
write: (path: string, content: string) => Promise<void>; | ||
} | ||
/** | ||
@@ -30,2 +34,3 @@ * States of a {@link Devbook} connection to a VM. | ||
private readonly contextID; | ||
get fs(): FS; | ||
private _isDestroyed; | ||
@@ -72,2 +77,4 @@ private get isDestroyed(); | ||
}); | ||
getFile(path: string): Promise<string | undefined>; | ||
writeFile(path: string, content: string): Promise<void>; | ||
/** | ||
@@ -74,0 +81,0 @@ * Run `command` in the VM. |
@@ -21,2 +21,3 @@ import * as rws from 'src/common-ts/RunnerWebSocket'; | ||
private fsWriteSubscribers; | ||
private fileContentSubscribers; | ||
private envs; | ||
@@ -31,2 +32,11 @@ private readonly unsubscribeConnHandler; | ||
destroy(): void; | ||
getFile({ templateID, path: filepath }: { | ||
templateID: Env; | ||
path: string; | ||
}): Promise<string | undefined>; | ||
updateFile({ templateID, path: filepath, content }: { | ||
templateID: Env; | ||
path: string; | ||
content: string; | ||
}): Promise<void>; | ||
executeCode({ templateID, executionID, code }: { | ||
@@ -45,2 +55,4 @@ templateID: Env; | ||
}): void; | ||
private subscribeFileContent; | ||
private unsubscribeFileContent; | ||
private subscribeFSWrite; | ||
@@ -53,2 +65,3 @@ private unsubscribeFSWrite; | ||
private vmenv_handleFSEventWrite; | ||
private vmenv_handleFileContent; | ||
private vmenv_handleStartAck; | ||
@@ -55,0 +68,0 @@ private vmenv_handleCmdOut; |
import { TemplateConfig } from 'src/common-ts/TemplateConfig'; | ||
import { WebSocketConnection } from 'src/core/webSocketConnection'; | ||
/** | ||
* Request to receive the `RunningEnvironment.DirContent` message in the future | ||
* containting the content of the directory at the given path. | ||
*/ | ||
declare function listDir(conn: WebSocketConnection, { environmentID, path, }: { | ||
environmentID: string; | ||
path: string; | ||
}): void; | ||
/** | ||
* Request to create a dir in the environment's filesystem. | ||
*/ | ||
declare function createDir(conn: WebSocketConnection, { environmentID, path, }: { | ||
environmentID: string; | ||
path: string; | ||
}): void; | ||
/** | ||
* Request to get a file from the environment's filesystem. | ||
*/ | ||
declare function getFile(conn: WebSocketConnection, { environmentID, path, }: { | ||
environmentID: string; | ||
path: string; | ||
}): void; | ||
declare function start(conn: WebSocketConnection, { environmentID, template, }: { | ||
@@ -27,2 +49,2 @@ environmentID: string; | ||
}): void; | ||
export { start, execCmd, writeFile, deleteFile, }; | ||
export { start, execCmd, writeFile, deleteFile, getFile, createDir, listDir, }; |
@@ -1,2 +0,2 @@ | ||
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react");class t{constructor(e,t=!1){this.logID=e,this.isEnabled=t}id(){return"function"==typeof this.logID?this.logID():this.logID}log(...e){this.isEnabled&&console.log(`[36m[${this.id()}][0m`,...e)}warn(...e){this.isEnabled&&console.warn(`[36m[${this.id()}][0m`,...e)}error(...e){console.error(`[31m[${this.id()} ERROR][0m`,...e)}} | ||
"use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("react"); | ||
/*! ***************************************************************************** | ||
@@ -15,3 +15,3 @@ Copyright (c) Microsoft Corporation. | ||
PERFORMANCE OF THIS SOFTWARE. | ||
***************************************************************************** */function n(e,t,n,s){return new(n||(n=Promise))((function(i,o){function r(e){try{c(s.next(e))}catch(e){o(e)}}function a(e){try{c(s.throw(e))}catch(e){o(e)}}function c(e){var t;e.done?i(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(r,a)}c((s=s.apply(e,t||[])).next())}))}function s(e){return new Promise((t=>setTimeout(t,e)))}var i,o,r;!function(e){e.Error="Runner.Error"}(i||(i={})),function(e){e.Start="RunningEnvironment.Start",e.StartAck="RunningEnvironment.StartAck",e.Eval="RunningEnvironment.Eval",e.FSEventCreate="RunningEnvironment.FSEventCreate",e.FSEventRemove="RunningEnvironment.FSEventRemove",e.FSEventWrite="RunningEnvironment.FSEventWrite",e.CreateDir="RunningEnvironment.CreateDir",e.ListDir="RunningEnvironment.ListDir",e.WriteFile="RunningEnvironment.WriteFile",e.GetFile="RunningEnvironment.GetFile",e.RemoveFile="RunningEnvironment.RemoveFile",e.DirContent="RunningEnvironment.DirContent",e.FileContent="RunningEnvironment.FileContent",e.Stdout="RunningEnvironment.Stdout",e.Stderr="RunningEnvironment.Stderr",e.ExecCmd="RunningEnvironment.ExecCmd",e.KillCmd="RunningEnvironment.KillCmd",e.ListRunningCmds="RunningEnvironment.ListRunningCmds",e.CmdOut="RunningEnvironment.CmdOut",e.CmdExit="RunningEnvironment.CmdExit",e.RunningCmds="RunningEnvironment.RunningCmds",e.RunCode="RunningEnvironment.Run"}(o||(o={})),function(e){e.Error="CodeCell.Error"}(r||(r={}));const a={Runner:i,RunningEnvironment:o,CodeCell:r};var c;exports.Env=void 0,(c=exports.Env||(exports.Env={})).NodeJS="nodejs-v16",c.Supabase="supabase";const l={"nodejs-v16":{id:"nodejs-v16",fileExtension:".js",image:"us-central1-docker.pkg.dev/devbookhq/devbook-runner-templates/nodejs-v16:latest",root_dir:"/home/runner",code_cells_dir:"/home/runner/src",toCommand:e=>`node "${e}"`},supabase:{id:"supabase",fileExtension:".js",image:"us-central1-docker.pkg.dev/devbookhq/devbook-runner-templates/supabase",root_dir:"/home/runner",code_cells_dir:"/home/runner/src",toCommand:e=>`node "${e}"`}};class h{constructor(){this.url="wss://orchestrator.usedevbook.com",this.logger=new t("WebSocketConnection"),this.handlers=[]}get state(){var e;return null===(e=this.client)||void 0===e?void 0:e.readyState}get isClosed(){if(void 0!==this.client)return this.client.readyState===this.client.CLOSED}get isClosing(){if(void 0!==this.client)return this.client.readyState===this.client.CLOSING}get isOpen(){if(void 0!==this.client)return this.client.readyState===this.client.OPEN}get isConnecting(){if(void 0!==this.client)return this.client.readyState===this.client.CONNECTING}subscribeHandler(e){return this.handlers.push(e),()=>{this.handlers=this.handlers.filter((t=>t!==e))}}connect(e){(!this.client||this.client.readyState!==this.client.CONNECTING&&this.client.readyState!==this.client.OPEN)&&(e||this.sessionID?(e?(this.logger.log(`Will try to connect to session "${e}"`),this.sessionID=e):!e&&this.sessionID&&this.logger.log(`Will try to connect to previous session "${this.sessionID}"`),this.client=new WebSocket(`${this.url}/session/ws/${this.sessionID}`),this.client.onopen=()=>this.handleOpen(),this.client.onmessage=e=>{this.logger.log("Received (raw)",{msg:e}),this.handleMessage(e)},this.client.onerror=e=>this.handleError(e),this.client.onclose=e=>this.handleClose(e)):this.logger.error("Cannot connect, no session ID passed to the function and no session ID saved from the previous session"))}send(e){this.client&&this.client.readyState===this.client.OPEN?(this.logger.log("Send",e),this._send(e)):this.logger.warn("Trying to send a message while not being in the `OPEN` state or without established connection, message will be discarded",e)}close(){var e;this.logger.log("Closing connection"),null===(e=this.client)||void 0===e||e.close(1e3)}handleOpen(){var e;this.logger.log("Connection opened",{readyState:null===(e=this.client)||void 0===e?void 0:e.readyState}),this.handlers.forEach((e=>e.onOpen()))}_send(e){var t,n;null===(t=this.client)||void 0===t||t.send((n=e,JSON.stringify(n,(()=>{const e=new WeakSet;return(t,n)=>{if("object"==typeof n&&null!==n){if(e.has(n))return;e.add(n)}return n}})(),2)))}handleClose(e){return n(this,void 0,void 0,(function*(){this.logger.log("Connection closed",e),this.handlers.forEach((e=>e.onClose())),this.logger.log("Will try to reconnect in 3s"),yield s(3e3),this.connect()}))}handleError(e){var t;this.logger.error("Connection error",e),null===(t=this.client)||void 0===t||t.close()}handleMessage(e){if(!e.data)return void this.logger.error("Message has empty data field",e);const t=JSON.parse(e.data);if(!t.type)return void this.logger.error("Message has no type",t);const n=t;Object.values(a.RunningEnvironment).includes(n.type)||Object.values(a.Runner).includes(n.type)||Object.values(a.CodeCell).includes(n.type)?n.type!==a.Runner.Error?(this.logger.log("Received (parsed)",n),this.handlers.forEach((e=>e.onMessage(n)))):this.logger.error("Runner error",n):this.logger.error('Message "type" field has unexpected value',n)}}var d,u;!function(e){e.Ok="Ok",e.Terminated="Terminated"}(d||(d={}));class g{constructor(e,n=new Date){this.id=e,this.lastPing=n,this.logger=new t("RunnerSession"),this.url="https://orchestrator.usedevbook.com"}ping(){return n(this,void 0,void 0,(function*(){this.logger.log(`Pinging session "${this.id}"`);const e=JSON.stringify({sessionID:this.id});try{const t=yield fetch(`${this.url}/session/ping`,{method:"POST",headers:{"Content-Type":"application/json"},body:e}),n=yield t.json();if(!t.ok)throw this.logger.error(t.headers,n),new Error("Non-OK response when trying to ping active Runner session");if(n.status===d.Terminated)throw new Error(`[keepAlive]: Session '${this.id}' is terminated`);this.lastPing=new Date}catch(e){throw this.logger.error(e),new Error("Failed to ping active Runner session")}}))}}!function(e){e.Connected="Connected",e.Connecting="Connecting",e.Disconnected="Disconnected"}(u||(u={}));class v{constructor(e){this.conn=e,this.logger=new t("SessionManager"),this.url="https://orchestrator.usedevbook.com",this.isGettingSessionActive=!1,this.status=u.Disconnected,this.logger.log("Initialize"),this.getSession()}get cachedSessionID(){return sessionStorage.getItem("dbk_sdk_session_id")}set cachedSessionID(e){null===e?(this.logger.log("Cleared last sessionID"),sessionStorage.removeItem("dbk_sdk_session_id")):(this.logger.log(`Saved sessionID "${e}" as last sessionID`),sessionStorage.setItem("dbk_sdk_session_id",e))}reset(){this.logger.log("Reset"),this.status=u.Disconnected,this.cachedSessionID=null,this.conn.close(),this.session=void 0}getSession(){var e;return n(this,void 0,void 0,(function*(){if(!this.isGettingSessionActive)for(this.isGettingSessionActive=!0;;){this.status=u.Connecting;try{const t=this.cachedSessionID?`${this.url}/session/${this.cachedSessionID}`:`${this.url}/session`;this.cachedSessionID?this.logger.log(`Restoring old Runner session "${this.cachedSessionID}"`):this.logger.log("Acquiring new Runner session");const n=yield fetch(t),i=yield n.json();if(!n.ok){this.logger.error("Non-OK response when trying to ping active Runner session. Will try again in 3s",n.headers,i),yield s(3e3);continue}for(this.session=new g(i.sessionID),this.logger.log(`Acquired session "${this.session.id}"`),this.cachedSessionID=this.session.id,this.status=u.Connected,this.conn.connect(this.session.id),this.logger.log(`Started pinging session "${this.session.id}"`);this.session;)try{yield this.session.ping(),yield s(5e3)}catch(e){this.logger.error(`Failed to ping session "${this.session.id}"`,e);break}this.logger.log(`Stopped pinging session "${null===(e=this.session)||void 0===e?void 0:e.id}"`),this.session=void 0,this.status=u.Disconnected,this.conn.close()}catch(e){this.logger.error("Failed to acquire Runner session. Will try again in 3s",e),yield s(3e3)}}}))}}function m(e,t){for(var n=0,s=e.length-1;s>=0;s--){var i=e[s];"."===i?e.splice(s,1):".."===i?(e.splice(s,1),n++):n&&(e.splice(s,1),n--)}if(t)for(;n--;n)e.unshift("..");return e}var p=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/,D=function(e){return p.exec(e).slice(1)};function f(){for(var e="",t=!1,n=arguments.length-1;n>=-1&&!t;n--){var s=n>=0?arguments[n]:"/";if("string"!=typeof s)throw new TypeError("Arguments to path.resolve must be strings");s&&(e=s+"/"+e,t="/"===s.charAt(0))}return(t?"/":"")+(e=m(E(e.split("/"),(function(e){return!!e})),!t).join("/"))||"."}function C(e){var t=S(e),n="/"===y(e,-1);return(e=m(E(e.split("/"),(function(e){return!!e})),!t).join("/"))||t||(e="."),e&&n&&(e+="/"),(t?"/":"")+e}function S(e){return"/"===e.charAt(0)}var b={extname:function(e){return D(e)[3]},basename:function(e,t){var n=D(e)[2];return t&&n.substr(-1*t.length)===t&&(n=n.substr(0,n.length-t.length)),n},dirname:function(e){var t=D(e),n=t[0],s=t[1];return n||s?(s&&(s=s.substr(0,s.length-1)),n+s):"."},sep:"/",delimiter:":",relative:function(e,t){function n(e){for(var t=0;t<e.length&&""===e[t];t++);for(var n=e.length-1;n>=0&&""===e[n];n--);return t>n?[]:e.slice(t,n-t+1)}e=f(e).substr(1),t=f(t).substr(1);for(var s=n(e.split("/")),i=n(t.split("/")),o=Math.min(s.length,i.length),r=o,a=0;a<o;a++)if(s[a]!==i[a]){r=a;break}var c=[];for(a=r;a<s.length;a++)c.push("..");return(c=c.concat(i.slice(r))).join("/")},join:function(){var e=Array.prototype.slice.call(arguments,0);return C(E(e,(function(e,t){if("string"!=typeof e)throw new TypeError("Arguments to path.join must be strings");return e})).join("/"))},isAbsolute:S,normalize:C,resolve:f};function E(e,t){if(e.filter)return e.filter(t);for(var n=[],s=0;s<e.length;s++)t(e[s],s,e)&&n.push(e[s]);return n}var y="b"==="ab".substr(-1)?function(e,t,n){return e.substr(t,n)}:function(e,t,n){return t<0&&(t=e.length+t),e.substr(t,n)};function I(e){return function(e){const t=Array.from(e).reduce(((e,t)=>0|31*e+t.charCodeAt(0)),0);return("0000000"+(t>>>0).toString(16)).slice(-8)}(e)}class x{constructor(e,t){this.contextID=e,this.templateID=t,this.isReady=!1,this.id=`${e}_${I(t)}`,this.template=l[this.templateID]}}function R(e,{environmentID:t,template:n}){const s={type:a.RunningEnvironment.Start,payload:{environmentID:t,template:n}};e.send(s)}function k(e,{environmentID:t,executionID:n,command:s}){const i={type:a.RunningEnvironment.ExecCmd,payload:{environmentID:t,executionID:n,command:s}};e.send(i)}class w{constructor(e){this.opts=e,this.fsWriteSubscribers=[],this.envs=[],this.logger=new t("EvaluationContext",e.debug),this.unsubscribeConnHandler=this.opts.conn.subscribeHandler({onOpen:this.handleConnectionOpen.bind(this),onMessage:this.handleConnectionMessage.bind(this),onClose:this.handleConnectionClose.bind(this)}),this.opts.conn.isOpen&&this.handleConnectionOpen(),this.opts.conn.isClosed&&this.handleConnectionClose()}get contextID(){return this.opts.contextID}restart(){return this.logger.log("Restart",this.opts.conn.sessionID),this.envs.forEach((e=>{e.isReady=!1,R(this.opts.conn,{environmentID:e.id,template:e.template})}))}destroy(){this.logger.log("Destroy"),this.unsubscribeConnHandler(),this.envs=[],this.fsWriteSubscribers=[]}executeCode({templateID:e,executionID:t,code:s}){return n(this,void 0,void 0,(function*(){this.logger.log("Execute code",{templateID:e,executionID:t});const n=this.envs.find((t=>t.templateID===e));if(!n)return void this.logger.error("Environment not found",{templateID:e,executionID:t});if(!n.isReady)return void this.logger.error("Environment is not ready",{templateID:e,executionID:t});const i=l[e].fileExtension,o=`${t}${i}`,r=b.join("/src",o);!function(e,{environmentID:t,path:n,content:s}){const i={type:a.RunningEnvironment.WriteFile,payload:{environmentID:t,path:n,content:s}};e.send(i)}(this.opts.conn,{environmentID:n.id,path:r,content:s});const c=b.join(l[e].root_dir,r),h=l[e].toCommand(c);k(this.opts.conn,{environmentID:n.id,executionID:t,command:h})}))}executeCommand({templateID:e,executionID:t,command:n}){this.logger.log("Execute shell command",{templateID:e,executionID:t,command:n});const s=this.envs.find((t=>t.templateID===e));s?s.isReady?k(this.opts.conn,{environmentID:s.id,executionID:t,command:n}):this.logger.error("Environment is not ready",{templateID:e,executionID:t,command:n}):this.logger.error("Environment not found",{templateID:e,executionID:t,command:n})}createRunningEnvironment({templateID:e}){var t,n;this.logger.log("Creating running environment",{templateID:e});if(this.envs.find((t=>t.templateID===e)))return;const s=new x(this.contextID,e);this.envs.push(s),R(this.opts.conn,{environmentID:s.id,template:s.template}),null===(n=(t=this.opts).onEnvChange)||void 0===n||n.call(t,s)}subscribeFSWrite(e){console.log("len",this.fsWriteSubscribers.length),this.fsWriteSubscribers.push(e)}unsubscribeFSWrite(e){console.log("len",this.fsWriteSubscribers.length);const t=this.fsWriteSubscribers.indexOf(e);t>-1&&this.fsWriteSubscribers.splice(t,1)}handleConnectionOpen(){var e,t;this.restart(),null===(t=(e=this.opts).onSessionChange)||void 0===t||t.call(e,{status:u.Connected})}handleConnectionClose(){var e,t;null===(t=(e=this.opts).onSessionChange)||void 0===t||t.call(e,{status:u.Connecting})}handleConnectionMessage(e){switch(this.logger.log("Handling message from remote Runner",{message:e}),e.type){case a.RunningEnvironment.StartAck:{const t=e;this.vmenv_handleStartAck(t.payload);break}case a.RunningEnvironment.CmdOut:{const t=e;this.vmenv_handleCmdOut(t.payload);break}case a.RunningEnvironment.CmdExit:{const t=e;this.vmenv_handleCmdExit(t.payload);break}case a.RunningEnvironment.FSEventWrite:{const t=e;this.vmenv_handleFSEventWrite(t.payload);break}default:this.logger.warn("Unknown message type",{message:e})}}vmenv_handleCmdExit(e){var t,n;void 0!==e.error&&(null===(n=(t=this.opts).onCmdOut)||void 0===n||n.call(t,{environmentID:e.environmentID,executionID:e.executionID,stderr:e.error}))}vmenv_handleFSEventWrite(e){this.logger.log('[vmenv] Handling "FSEventWrite"',e);this.envs.find((t=>t.id===e.environmentID))?this.fsWriteSubscribers.forEach((t=>t(e))):this.logger.warn("Environment not found",{payload:e})}vmenv_handleStartAck(e){var t,n;this.logger.log('[vmenv] Handling "StartAck"',{payload:e});const s=this.envs.find((t=>t.id===e.environmentID));s?(s.isReady=!0,null===(n=(t=this.opts).onEnvChange)||void 0===n||n.call(t,s)):this.logger.warn("Environment not found",{payload:e})}vmenv_handleCmdOut(e){var t,n;this.logger.log('[vmenv] Handling "CmdOut"',e),null===(n=(t=this.opts).onCmdOut)||void 0===n||n.call(t,e)}}class _{constructor(){this.logger=new t("Runner"),this.conn=new h,this.sessManager=new v(this.conn)}static get obj(){return _._obj||(_._obj=new _)}get session(){return this.sessManager.session}get status(){return this.sessManager.status}reset(){this.logger.log("Reset"),this.sessManager.reset()}createContext(e){return new w(Object.assign(Object.assign({},e),{conn:this.conn}))}__debug__loadNewSession(){this.logger.log("__debug__loadNewSession"),this.sessManager.reset()}}const O=(j="1234567890abcdefghijklmnopqrstuvwxyz",W=6,()=>{let e="",t=W;for(;t--;)e+=j[Math.random()*j.length|0];return e});var j,W,$;exports.DevbookStatus=void 0,($=exports.DevbookStatus||(exports.DevbookStatus={}))[$.Disconnected=0]="Disconnected",$[$.Connecting=1]="Connecting",$[$.Connected=2]="Connected";class F{constructor(e){this.opts=e,this._isDestroyed=!1,this._isEnvReady=!1,this._sessionStatus=u.Disconnected,this._status=exports.DevbookStatus.Disconnected;const t="default";this.contextID=t,this.executionID=O();const n=()=>this.executionID,s=e=>this.isEnvReady=e,i=e=>this.sessionStatus=e;this.context=_.obj.createContext({debug:e.debug,contextID:t,onEnvChange(e){s(e.isReady)},onSessionChange({status:e}){i(e)},onCmdOut(t){var s,i;t.executionID===n()&&(void 0!==t.stdout&&(null===(s=e.onStdout)||void 0===s||s.call(e,t.stdout)),void 0!==t.stderr&&(null===(i=e.onStderr)||void 0===i||i.call(e,t.stderr)))}}),this.context.createRunningEnvironment({templateID:e.env})}get isDestroyed(){return this._isDestroyed}set isDestroyed(e){this._isDestroyed=e,this.updateStatus()}get isEnvReady(){return this._isEnvReady}set isEnvReady(e){this._isEnvReady=e,this.updateStatus()}get sessionStatus(){return this._sessionStatus}set sessionStatus(e){this._sessionStatus=e,this.updateStatus()}get status(){return this._status}set status(e){var t,n;this._status=e,null===(n=(t=this.opts).onStatusChange)||void 0===n||n.call(t,e)}runCmd(e){this.status!==exports.DevbookStatus.Disconnected&&(this.executionID=O(),this.context.executeCommand({templateID:this.opts.env,executionID:this.executionID,command:e}))}runCode(e){this.status!==exports.DevbookStatus.Disconnected&&(this.executionID=O(),this.context.executeCode({templateID:this.opts.env,executionID:this.executionID,code:e}))}destroy(){this.context.destroy(),this.isDestroyed=!0}updateStatus(){if(this.isDestroyed)return void(this.status!==exports.DevbookStatus.Disconnected&&(this.status=exports.DevbookStatus.Disconnected));let e;switch(this.sessionStatus){case u.Disconnected:e=exports.DevbookStatus.Disconnected;break;case u.Connecting:e=exports.DevbookStatus.Connecting;break;case u.Connected:if(!this.isEnvReady){e=exports.DevbookStatus.Connecting;break}e=exports.DevbookStatus.Connected}this.status=e}}exports.Devbook=F,exports.useDevbook=function({env:t,debug:n}){const[s,i]=e.useState(),[o,r]=e.useState(exports.DevbookStatus.Disconnected),[a,c]=e.useState([]),[l,h]=e.useState([]),d=e.useCallback((e=>{s&&(h([]),c([]),s.runCmd(e))}),[s]),u=e.useCallback((e=>{s&&(h([]),c([]),s.runCode(e))}),[s]);return e.useEffect((function(){const e=new F({debug:n,env:t,onStatusChange(e){r(e)},onStderr(e){c((t=>[...t,e]))},onStdout(e){h((t=>[...t,e]))}});return h([]),c([]),i(e),()=>{e.destroy()}}),[t,n]),{stderr:a,stdout:l,runCmd:d,runCode:u,status:o}}; | ||
***************************************************************************** */function t(e,t,n,s){return new(n||(n=Promise))((function(i,o){function r(e){try{l(s.next(e))}catch(e){o(e)}}function a(e){try{l(s.throw(e))}catch(e){o(e)}}function l(e){var t;e.done?i(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(r,a)}l((s=s.apply(e,t||[])).next())}))}class n{constructor(e,t=!1){this.logID=e,this.isEnabled=t}id(){return"function"==typeof this.logID?this.logID():this.logID}log(...e){this.isEnabled&&console.log(`[36m[${this.id()}][0m`,...e)}warn(...e){this.isEnabled&&console.warn(`[36m[${this.id()}][0m`,...e)}error(...e){console.error(`[31m[${this.id()} ERROR][0m`,...e)}}function s(e){return new Promise((t=>setTimeout(t,e)))}var i,o,r;!function(e){e.Error="Runner.Error"}(i||(i={})),function(e){e.Start="RunningEnvironment.Start",e.StartAck="RunningEnvironment.StartAck",e.Eval="RunningEnvironment.Eval",e.FSEventCreate="RunningEnvironment.FSEventCreate",e.FSEventRemove="RunningEnvironment.FSEventRemove",e.FSEventWrite="RunningEnvironment.FSEventWrite",e.CreateDir="RunningEnvironment.CreateDir",e.ListDir="RunningEnvironment.ListDir",e.WriteFile="RunningEnvironment.WriteFile",e.GetFile="RunningEnvironment.GetFile",e.RemoveFile="RunningEnvironment.RemoveFile",e.DirContent="RunningEnvironment.DirContent",e.FileContent="RunningEnvironment.FileContent",e.Stdout="RunningEnvironment.Stdout",e.Stderr="RunningEnvironment.Stderr",e.ExecCmd="RunningEnvironment.ExecCmd",e.KillCmd="RunningEnvironment.KillCmd",e.ListRunningCmds="RunningEnvironment.ListRunningCmds",e.CmdOut="RunningEnvironment.CmdOut",e.CmdExit="RunningEnvironment.CmdExit",e.RunningCmds="RunningEnvironment.RunningCmds",e.RunCode="RunningEnvironment.Run"}(o||(o={})),function(e){e.Error="CodeCell.Error"}(r||(r={}));const a={Runner:i,RunningEnvironment:o,CodeCell:r};var l;exports.Env=void 0,(l=exports.Env||(exports.Env={})).NodeJS="nodejs-v16",l.Supabase="supabase";const c={"nodejs-v16":{id:"nodejs-v16",fileExtension:".js",image:"us-central1-docker.pkg.dev/devbookhq/devbook-runner-templates/nodejs-v16:latest",root_dir:"/home/runner",code_cells_dir:"/home/runner/src",toCommand:e=>`node "${e}"`},supabase:{id:"supabase",fileExtension:".js",image:"us-central1-docker.pkg.dev/devbookhq/devbook-runner-templates/supabase",root_dir:"/home/runner",code_cells_dir:"/home/runner/src",toCommand:e=>`node "${e}"`}};class h{constructor(){this.url="wss://orchestrator.usedevbook.com",this.logger=new n("WebSocketConnection"),this.handlers=[]}get state(){var e;return null===(e=this.client)||void 0===e?void 0:e.readyState}get isClosed(){if(void 0!==this.client)return this.client.readyState===this.client.CLOSED}get isClosing(){if(void 0!==this.client)return this.client.readyState===this.client.CLOSING}get isOpen(){if(void 0!==this.client)return this.client.readyState===this.client.OPEN}get isConnecting(){if(void 0!==this.client)return this.client.readyState===this.client.CONNECTING}subscribeHandler(e){return this.handlers.push(e),()=>{this.handlers=this.handlers.filter((t=>t!==e))}}connect(e){(!this.client||this.client.readyState!==this.client.CONNECTING&&this.client.readyState!==this.client.OPEN)&&(e||this.sessionID?(e?(this.logger.log(`Will try to connect to session "${e}"`),this.sessionID=e):!e&&this.sessionID&&this.logger.log(`Will try to connect to previous session "${this.sessionID}"`),this.client=new WebSocket(`${this.url}/session/ws/${this.sessionID}`),this.client.onopen=()=>this.handleOpen(),this.client.onmessage=e=>{this.logger.log("Received (raw)",{msg:e}),this.handleMessage(e)},this.client.onerror=e=>this.handleError(e),this.client.onclose=e=>this.handleClose(e)):this.logger.error("Cannot connect, no session ID passed to the function and no session ID saved from the previous session"))}send(e){this.client&&this.client.readyState===this.client.OPEN?(this.logger.log("Send",e),this._send(e)):this.logger.warn("Trying to send a message while not being in the `OPEN` state or without established connection, message will be discarded",e)}close(){var e;this.logger.log("Closing connection"),null===(e=this.client)||void 0===e||e.close(1e3)}handleOpen(){var e;this.logger.log("Connection opened",{readyState:null===(e=this.client)||void 0===e?void 0:e.readyState}),this.handlers.forEach((e=>e.onOpen()))}_send(e){var t,n;null===(t=this.client)||void 0===t||t.send((n=e,JSON.stringify(n,(()=>{const e=new WeakSet;return(t,n)=>{if("object"==typeof n&&null!==n){if(e.has(n))return;e.add(n)}return n}})(),2)))}handleClose(e){return t(this,void 0,void 0,(function*(){this.logger.log("Connection closed",e),this.handlers.forEach((e=>e.onClose())),this.logger.log("Will try to reconnect in 3s"),yield s(3e3),this.connect()}))}handleError(e){var t;this.logger.error("Connection error",e),null===(t=this.client)||void 0===t||t.close()}handleMessage(e){if(!e.data)return void this.logger.error("Message has empty data field",e);const t=JSON.parse(e.data);if(!t.type)return void this.logger.error("Message has no type",t);const n=t;Object.values(a.RunningEnvironment).includes(n.type)||Object.values(a.Runner).includes(n.type)||Object.values(a.CodeCell).includes(n.type)?n.type!==a.Runner.Error?(this.logger.log("Received (parsed)",n),this.handlers.forEach((e=>e.onMessage(n)))):this.logger.error("Runner error",n):this.logger.error('Message "type" field has unexpected value',n)}}var d,u;!function(e){e.Ok="Ok",e.Terminated="Terminated"}(d||(d={}));class g{constructor(e,t=new Date){this.id=e,this.lastPing=t,this.logger=new n("RunnerSession"),this.url="https://orchestrator.usedevbook.com"}ping(){return t(this,void 0,void 0,(function*(){this.logger.log(`Pinging session "${this.id}"`);const e=JSON.stringify({sessionID:this.id});try{const t=yield fetch(`${this.url}/session/ping`,{method:"POST",headers:{"Content-Type":"application/json"},body:e}),n=yield t.json();if(!t.ok)throw this.logger.error(t.headers,n),new Error("Non-OK response when trying to ping active Runner session");if(n.status===d.Terminated)throw new Error(`[keepAlive]: Session '${this.id}' is terminated`);this.lastPing=new Date}catch(e){throw this.logger.error(e),new Error("Failed to ping active Runner session")}}))}}!function(e){e.Connected="Connected",e.Connecting="Connecting",e.Disconnected="Disconnected"}(u||(u={}));class v{constructor(e){this.conn=e,this.logger=new n("SessionManager"),this.url="https://orchestrator.usedevbook.com",this.isGettingSessionActive=!1,this.status=u.Disconnected,this.logger.log("Initialize"),this.getSession()}get cachedSessionID(){return sessionStorage.getItem("dbk_sdk_session_id")}set cachedSessionID(e){null===e?(this.logger.log("Cleared last sessionID"),sessionStorage.removeItem("dbk_sdk_session_id")):(this.logger.log(`Saved sessionID "${e}" as last sessionID`),sessionStorage.setItem("dbk_sdk_session_id",e))}reset(){this.logger.log("Reset"),this.status=u.Disconnected,this.cachedSessionID=null,this.conn.close(),this.session=void 0}getSession(){var e;return t(this,void 0,void 0,(function*(){if(!this.isGettingSessionActive)for(this.isGettingSessionActive=!0;;){this.status=u.Connecting;try{const t=this.cachedSessionID?`${this.url}/session/${this.cachedSessionID}`:`${this.url}/session`;this.cachedSessionID?this.logger.log(`Restoring old Runner session "${this.cachedSessionID}"`):this.logger.log("Acquiring new Runner session");const n=yield fetch(t),i=yield n.json();if(!n.ok){this.logger.error("Non-OK response when trying to ping active Runner session. Will try again in 3s",n.headers,i),yield s(3e3);continue}for(this.session=new g(i.sessionID),this.logger.log(`Acquired session "${this.session.id}"`),this.cachedSessionID=this.session.id,this.status=u.Connected,this.conn.connect(this.session.id),this.logger.log(`Started pinging session "${this.session.id}"`);this.session;)try{yield this.session.ping(),yield s(5e3)}catch(e){this.logger.error(`Failed to ping session "${this.session.id}"`,e);break}this.logger.log(`Stopped pinging session "${null===(e=this.session)||void 0===e?void 0:e.id}"`),this.session=void 0,this.status=u.Disconnected,this.conn.close()}catch(e){this.logger.error("Failed to acquire Runner session. Will try again in 3s",e),yield s(3e3)}}}))}}function m(e,t){for(var n=0,s=e.length-1;s>=0;s--){var i=e[s];"."===i?e.splice(s,1):".."===i?(e.splice(s,1),n++):n&&(e.splice(s,1),n--)}if(t)for(;n--;n)e.unshift("..");return e}var p=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/,f=function(e){return p.exec(e).slice(1)};function D(){for(var e="",t=!1,n=arguments.length-1;n>=-1&&!t;n--){var s=n>=0?arguments[n]:"/";if("string"!=typeof s)throw new TypeError("Arguments to path.resolve must be strings");s&&(e=s+"/"+e,t="/"===s.charAt(0))}return(t?"/":"")+(e=m(E(e.split("/"),(function(e){return!!e})),!t).join("/"))||"."}function b(e){var t=C(e),n="/"===y(e,-1);return(e=m(E(e.split("/"),(function(e){return!!e})),!t).join("/"))||t||(e="."),e&&n&&(e+="/"),(t?"/":"")+e}function C(e){return"/"===e.charAt(0)}var S={extname:function(e){return f(e)[3]},basename:function(e,t){var n=f(e)[2];return t&&n.substr(-1*t.length)===t&&(n=n.substr(0,n.length-t.length)),n},dirname:function(e){var t=f(e),n=t[0],s=t[1];return n||s?(s&&(s=s.substr(0,s.length-1)),n+s):"."},sep:"/",delimiter:":",relative:function(e,t){function n(e){for(var t=0;t<e.length&&""===e[t];t++);for(var n=e.length-1;n>=0&&""===e[n];n--);return t>n?[]:e.slice(t,n-t+1)}e=D(e).substr(1),t=D(t).substr(1);for(var s=n(e.split("/")),i=n(t.split("/")),o=Math.min(s.length,i.length),r=o,a=0;a<o;a++)if(s[a]!==i[a]){r=a;break}var l=[];for(a=r;a<s.length;a++)l.push("..");return(l=l.concat(i.slice(r))).join("/")},join:function(){var e=Array.prototype.slice.call(arguments,0);return b(E(e,(function(e,t){if("string"!=typeof e)throw new TypeError("Arguments to path.join must be strings");return e})).join("/"))},isAbsolute:C,normalize:b,resolve:D};function E(e,t){if(e.filter)return e.filter(t);for(var n=[],s=0;s<e.length;s++)t(e[s],s,e)&&n.push(e[s]);return n}var y="b"==="ab".substr(-1)?function(e,t,n){return e.substr(t,n)}:function(e,t,n){return t<0&&(t=e.length+t),e.substr(t,n)};function I(e){return function(e){const t=Array.from(e).reduce(((e,t)=>0|31*e+t.charCodeAt(0)),0);return("0000000"+(t>>>0).toString(16)).slice(-8)}(e)}class x{constructor(e,t){this.contextID=e,this.templateID=t,this.isReady=!1,this.id=`${e}_${I(t)}`,this.template=c[this.templateID]}}function R(e,{environmentID:t,template:n}){const s={type:a.RunningEnvironment.Start,payload:{environmentID:t,template:n}};e.send(s)}function w(e,{environmentID:t,executionID:n,command:s}){const i={type:a.RunningEnvironment.ExecCmd,payload:{environmentID:t,executionID:n,command:s}};e.send(i)}function k(e,{environmentID:t,path:n,content:s}){const i={type:a.RunningEnvironment.WriteFile,payload:{environmentID:t,path:n,content:s}};e.send(i)}class _{constructor(e){this.opts=e,this.fsWriteSubscribers=[],this.fileContentSubscribers=[],this.envs=[],this.logger=new n("EvaluationContext",e.debug),this.unsubscribeConnHandler=this.opts.conn.subscribeHandler({onOpen:this.handleConnectionOpen.bind(this),onMessage:this.handleConnectionMessage.bind(this),onClose:this.handleConnectionClose.bind(this)}),this.opts.conn.isOpen&&this.handleConnectionOpen(),this.opts.conn.isClosed&&this.handleConnectionClose()}get contextID(){return this.opts.contextID}restart(){return this.logger.log("Restart",this.opts.conn.sessionID),this.envs.forEach((e=>{e.isReady=!1,R(this.opts.conn,{environmentID:e.id,template:e.template})}))}destroy(){this.logger.log("Destroy"),this.unsubscribeConnHandler(),this.envs=[],this.fsWriteSubscribers=[]}getFile({templateID:e,path:n}){return t(this,void 0,void 0,(function*(){this.logger.log("Get file",{templateID:e,path:S});const t=this.envs.find((t=>t.templateID===e));if(!t)return void this.logger.error("Environment not found",{templateID:e,path:S});if(!t.isReady)return void this.logger.error("Environment is not ready",{templateID:e,path:S});let s;const i=new Promise(((e,t)=>{s=e,setTimeout((()=>{t("Timeout")}),1e4)})),o=e=>{e.path.endsWith(n)&&s(e.content)};this.subscribeFileContent(o),function(e,{environmentID:t,path:n}){const s={type:a.RunningEnvironment.GetFile,payload:{environmentID:t,path:n}};e.send(s)}(this.opts.conn,{path:n,environmentID:t.id});try{return yield i}catch(e){throw new Error(`Error retriving file ${n}: ${e.message}`)}finally{this.unsubscribeFileContent(o)}}))}updateFile({templateID:e,path:n,content:s}){return t(this,void 0,void 0,(function*(){this.logger.log("Update file",{templateID:e,filepath:n});const t=this.envs.find((t=>t.templateID===e));if(!t)return void this.logger.error("Environment not found",{templateID:e,filepath:n});if(!t.isReady)return void this.logger.error("Environment is not ready",{templateID:e,filepath:n});let i;const o=new Promise(((e,t)=>{i=e,setTimeout((()=>{t("Timeout")}),1e4)})),r=e=>{e.path.endsWith(n)&&i()};this.subscribeFSWrite(r),k(this.opts.conn,{environmentID:t.id,path:n,content:s});try{yield o}catch(e){throw new Error(`File ${n} not written to VM: ${e.message}`)}finally{this.unsubscribeFSWrite(r)}}))}executeCode({templateID:e,executionID:n,code:s}){return t(this,void 0,void 0,(function*(){this.logger.log("Execute code",{templateID:e,executionID:n});const t=this.envs.find((t=>t.templateID===e));if(!t)return void this.logger.error("Environment not found",{templateID:e,executionID:n});if(!t.isReady)return void this.logger.error("Environment is not ready",{templateID:e,executionID:n});const i=c[e].fileExtension,o=`${n}${i}`,r=S.join("/src",o);k(this.opts.conn,{environmentID:t.id,path:r,content:s});const a=S.join(c[e].root_dir,r),l=c[e].toCommand(a);w(this.opts.conn,{environmentID:t.id,executionID:n,command:l})}))}executeCommand({templateID:e,executionID:t,command:n}){this.logger.log("Execute shell command",{templateID:e,executionID:t,command:n});const s=this.envs.find((t=>t.templateID===e));s?s.isReady?w(this.opts.conn,{environmentID:s.id,executionID:t,command:n}):this.logger.error("Environment is not ready",{templateID:e,executionID:t,command:n}):this.logger.error("Environment not found",{templateID:e,executionID:t,command:n})}createRunningEnvironment({templateID:e}){var t,n;this.logger.log("Creating running environment",{templateID:e});if(this.envs.find((t=>t.templateID===e)))return;const s=new x(this.contextID,e);this.envs.push(s),R(this.opts.conn,{environmentID:s.id,template:s.template}),null===(n=(t=this.opts).onEnvChange)||void 0===n||n.call(t,s)}subscribeFileContent(e){this.fileContentSubscribers.push(e)}unsubscribeFileContent(e){const t=this.fileContentSubscribers.indexOf(e);t>-1&&this.fileContentSubscribers.splice(t,1)}subscribeFSWrite(e){this.fsWriteSubscribers.push(e)}unsubscribeFSWrite(e){const t=this.fsWriteSubscribers.indexOf(e);t>-1&&this.fsWriteSubscribers.splice(t,1)}handleConnectionOpen(){var e,t;this.restart(),null===(t=(e=this.opts).onSessionChange)||void 0===t||t.call(e,{status:u.Connected})}handleConnectionClose(){var e,t;null===(t=(e=this.opts).onSessionChange)||void 0===t||t.call(e,{status:u.Connecting})}handleConnectionMessage(e){switch(this.logger.log("Handling message from remote Runner",{message:e}),e.type){case a.RunningEnvironment.StartAck:{const t=e;this.vmenv_handleStartAck(t.payload);break}case a.RunningEnvironment.CmdOut:{const t=e;this.vmenv_handleCmdOut(t.payload);break}case a.RunningEnvironment.CmdExit:{const t=e;this.vmenv_handleCmdExit(t.payload);break}case a.RunningEnvironment.FSEventWrite:{const t=e;this.vmenv_handleFSEventWrite(t.payload);break}case a.RunningEnvironment.FileContent:{const t=e;this.vmenv_handleFileContent(t.payload);break}default:this.logger.warn("Unknown message type",{message:e})}}vmenv_handleCmdExit(e){var t,n;void 0!==e.error&&(null===(n=(t=this.opts).onCmdOut)||void 0===n||n.call(t,{environmentID:e.environmentID,executionID:e.executionID,stderr:e.error}))}vmenv_handleFSEventWrite(e){this.logger.log('[vmenv] Handling "FSEventWrite"',e);this.envs.find((t=>t.id===e.environmentID))?this.fsWriteSubscribers.forEach((t=>t(e))):this.logger.warn("Environment not found",{payload:e})}vmenv_handleFileContent(e){this.logger.log('[vmenv] Handling "FileContent"',{environmentID:e.environmentID,path:e.path});this.envs.find((t=>t.id===e.environmentID))?this.fileContentSubscribers.forEach((t=>t(e))):this.logger.warn("Environment not found",{payload:e})}vmenv_handleStartAck(e){var t,n;this.logger.log('[vmenv] Handling "StartAck"',{payload:e});const s=this.envs.find((t=>t.id===e.environmentID));s?(s.isReady=!0,null===(n=(t=this.opts).onEnvChange)||void 0===n||n.call(t,s)):this.logger.warn("Environment not found",{payload:e})}vmenv_handleCmdOut(e){var t,n;this.logger.log('[vmenv] Handling "CmdOut"',e),null===(n=(t=this.opts).onCmdOut)||void 0===n||n.call(t,e)}}class F{constructor(){this.logger=new n("Runner"),this.conn=new h,this.sessManager=new v(this.conn)}static get obj(){return F._obj||(F._obj=new F)}get session(){return this.sessManager.session}get status(){return this.sessManager.status}reset(){this.logger.log("Reset"),this.sessManager.reset()}createContext(e){return new _(Object.assign(Object.assign({},e),{conn:this.conn}))}__debug__loadNewSession(){this.logger.log("__debug__loadNewSession"),this.sessManager.reset()}}const O=($="1234567890abcdefghijklmnopqrstuvwxyz",j=6,()=>{let e="",t=j;for(;t--;)e+=$[Math.random()*$.length|0];return e});var $,j,W;exports.DevbookStatus=void 0,(W=exports.DevbookStatus||(exports.DevbookStatus={}))[W.Disconnected=0]="Disconnected",W[W.Connecting=1]="Connecting",W[W.Connected=2]="Connected";class M{constructor(e){this.opts=e,this._isDestroyed=!1,this._isEnvReady=!1,this._sessionStatus=u.Disconnected,this._status=exports.DevbookStatus.Disconnected;const t="default";this.contextID=t,this.executionID=O();const n=()=>this.executionID,s=e=>this.isEnvReady=e,i=e=>this.sessionStatus=e;this.context=F.obj.createContext({debug:e.debug,contextID:t,onEnvChange(e){s(e.isReady)},onSessionChange({status:e}){i(e)},onCmdOut(t){var s,i;t.executionID===n()&&(void 0!==t.stdout&&(null===(s=e.onStdout)||void 0===s||s.call(e,t.stdout)),void 0!==t.stderr&&(null===(i=e.onStderr)||void 0===i||i.call(e,t.stderr)))}}),this.context.createRunningEnvironment({templateID:e.env})}get fs(){return{get:this.getFile.bind(this),write:this.writeFile.bind(this)}}get isDestroyed(){return this._isDestroyed}set isDestroyed(e){this._isDestroyed=e,this.updateStatus()}get isEnvReady(){return this._isEnvReady}set isEnvReady(e){this._isEnvReady=e,this.updateStatus()}get sessionStatus(){return this._sessionStatus}set sessionStatus(e){this._sessionStatus=e,this.updateStatus()}get status(){return this._status}set status(e){var t,n;this._status=e,null===(n=(t=this.opts).onStatusChange)||void 0===n||n.call(t,e)}getFile(e){return t(this,void 0,void 0,(function*(){if(this.status!==exports.DevbookStatus.Connected)throw new Error("Not connected to the VM yet.");return this.context.getFile({templateID:this.opts.env,path:e})}))}writeFile(e,n){return t(this,void 0,void 0,(function*(){if(this.status!==exports.DevbookStatus.Connected)throw new Error("Not connected to the VM yet.");return this.context.updateFile({templateID:this.opts.env,path:e,content:n})}))}runCmd(e){if(this.status!==exports.DevbookStatus.Connected)throw new Error("Not connected to the VM yet.");this.executionID=O(),this.context.executeCommand({templateID:this.opts.env,executionID:this.executionID,command:e})}runCode(e){if(this.status!==exports.DevbookStatus.Connected)throw new Error("Not connected to the VM yet.");this.executionID=O(),this.context.executeCode({templateID:this.opts.env,executionID:this.executionID,code:e})}destroy(){this.context.destroy(),this.isDestroyed=!0}updateStatus(){if(this.isDestroyed)return void(this.status!==exports.DevbookStatus.Disconnected&&(this.status=exports.DevbookStatus.Disconnected));let e;switch(this.sessionStatus){case u.Disconnected:e=exports.DevbookStatus.Disconnected;break;case u.Connecting:e=exports.DevbookStatus.Connecting;break;case u.Connected:if(!this.isEnvReady){e=exports.DevbookStatus.Connecting;break}e=exports.DevbookStatus.Connected}this.status=e}}exports.Devbook=M,exports.useDevbook=function({env:t,debug:n}){const[s,i]=e.useState(),[o,r]=e.useState(exports.DevbookStatus.Disconnected),[a,l]=e.useState([]),[c,h]=e.useState([]),d=e.useCallback((e=>{s&&(h([]),l([]),s.runCmd(e))}),[s]),u=e.useCallback((e=>{s&&(h([]),l([]),s.runCode(e))}),[s]);return e.useEffect((function(){const e=new M({debug:n,env:t,onStatusChange(e){r(e)},onStderr(e){l((t=>[...t,e]))},onStdout(e){h((t=>[...t,e]))}});return h([]),l([]),i(e),()=>{e.destroy()}}),[t,n]),{stderr:a,stdout:c,runCmd:d,runCode:u,status:o,fs:null==s?void 0:s.fs}}; | ||
//# sourceMappingURL=index.js.map |
import { DevbookStatus, Env } from 'src/core'; | ||
import { FS } from 'src/core/devbook'; | ||
/** | ||
@@ -55,2 +56,3 @@ * Options passed to the {@link useDevbook} hook. | ||
runCmd: (command: string) => void; | ||
fs?: FS; | ||
} | ||
@@ -57,0 +59,0 @@ /** |
import { Env } from './constants'; | ||
export interface FS { | ||
get: (path: string) => Promise<string | undefined>; | ||
write: (path: string, content: string) => Promise<void>; | ||
} | ||
/** | ||
@@ -30,2 +34,3 @@ * States of a {@link Devbook} connection to a VM. | ||
private readonly contextID; | ||
get fs(): FS; | ||
private _isDestroyed; | ||
@@ -72,2 +77,4 @@ private get isDestroyed(); | ||
}); | ||
getFile(path: string): Promise<string | undefined>; | ||
writeFile(path: string, content: string): Promise<void>; | ||
/** | ||
@@ -74,0 +81,0 @@ * Run `command` in the VM. |
@@ -21,2 +21,3 @@ import * as rws from 'src/common-ts/RunnerWebSocket'; | ||
private fsWriteSubscribers; | ||
private fileContentSubscribers; | ||
private envs; | ||
@@ -31,2 +32,11 @@ private readonly unsubscribeConnHandler; | ||
destroy(): void; | ||
getFile({ templateID, path: filepath }: { | ||
templateID: Env; | ||
path: string; | ||
}): Promise<string | undefined>; | ||
updateFile({ templateID, path: filepath, content }: { | ||
templateID: Env; | ||
path: string; | ||
content: string; | ||
}): Promise<void>; | ||
executeCode({ templateID, executionID, code }: { | ||
@@ -45,2 +55,4 @@ templateID: Env; | ||
}): void; | ||
private subscribeFileContent; | ||
private unsubscribeFileContent; | ||
private subscribeFSWrite; | ||
@@ -53,2 +65,3 @@ private unsubscribeFSWrite; | ||
private vmenv_handleFSEventWrite; | ||
private vmenv_handleFileContent; | ||
private vmenv_handleStartAck; | ||
@@ -55,0 +68,0 @@ private vmenv_handleCmdOut; |
import { TemplateConfig } from 'src/common-ts/TemplateConfig'; | ||
import { WebSocketConnection } from 'src/core/webSocketConnection'; | ||
/** | ||
* Request to receive the `RunningEnvironment.DirContent` message in the future | ||
* containting the content of the directory at the given path. | ||
*/ | ||
declare function listDir(conn: WebSocketConnection, { environmentID, path, }: { | ||
environmentID: string; | ||
path: string; | ||
}): void; | ||
/** | ||
* Request to create a dir in the environment's filesystem. | ||
*/ | ||
declare function createDir(conn: WebSocketConnection, { environmentID, path, }: { | ||
environmentID: string; | ||
path: string; | ||
}): void; | ||
/** | ||
* Request to get a file from the environment's filesystem. | ||
*/ | ||
declare function getFile(conn: WebSocketConnection, { environmentID, path, }: { | ||
environmentID: string; | ||
path: string; | ||
}): void; | ||
declare function start(conn: WebSocketConnection, { environmentID, template, }: { | ||
@@ -27,2 +49,2 @@ environmentID: string; | ||
}): void; | ||
export { start, execCmd, writeFile, deleteFile, }; | ||
export { start, execCmd, writeFile, deleteFile, getFile, createDir, listDir, }; |
@@ -1,2 +0,2 @@ | ||
import{useState as e,useCallback as n,useEffect as t}from"react";class s{constructor(e,n=!1){this.logID=e,this.isEnabled=n}id(){return"function"==typeof this.logID?this.logID():this.logID}log(...e){this.isEnabled&&console.log(`[36m[${this.id()}][0m`,...e)}warn(...e){this.isEnabled&&console.warn(`[36m[${this.id()}][0m`,...e)}error(...e){console.error(`[31m[${this.id()} ERROR][0m`,...e)}} | ||
import{useState as e,useCallback as t,useEffect as n}from"react"; | ||
/*! ***************************************************************************** | ||
@@ -15,3 +15,3 @@ Copyright (c) Microsoft Corporation. | ||
PERFORMANCE OF THIS SOFTWARE. | ||
***************************************************************************** */function i(e,n,t,s){return new(t||(t=Promise))((function(i,o){function r(e){try{c(s.next(e))}catch(e){o(e)}}function a(e){try{c(s.throw(e))}catch(e){o(e)}}function c(e){var n;e.done?i(e.value):(n=e.value,n instanceof t?n:new t((function(e){e(n)}))).then(r,a)}c((s=s.apply(e,n||[])).next())}))}function o(e){return new Promise((n=>setTimeout(n,e)))}var r,a,c;!function(e){e.Error="Runner.Error"}(r||(r={})),function(e){e.Start="RunningEnvironment.Start",e.StartAck="RunningEnvironment.StartAck",e.Eval="RunningEnvironment.Eval",e.FSEventCreate="RunningEnvironment.FSEventCreate",e.FSEventRemove="RunningEnvironment.FSEventRemove",e.FSEventWrite="RunningEnvironment.FSEventWrite",e.CreateDir="RunningEnvironment.CreateDir",e.ListDir="RunningEnvironment.ListDir",e.WriteFile="RunningEnvironment.WriteFile",e.GetFile="RunningEnvironment.GetFile",e.RemoveFile="RunningEnvironment.RemoveFile",e.DirContent="RunningEnvironment.DirContent",e.FileContent="RunningEnvironment.FileContent",e.Stdout="RunningEnvironment.Stdout",e.Stderr="RunningEnvironment.Stderr",e.ExecCmd="RunningEnvironment.ExecCmd",e.KillCmd="RunningEnvironment.KillCmd",e.ListRunningCmds="RunningEnvironment.ListRunningCmds",e.CmdOut="RunningEnvironment.CmdOut",e.CmdExit="RunningEnvironment.CmdExit",e.RunningCmds="RunningEnvironment.RunningCmds",e.RunCode="RunningEnvironment.Run"}(a||(a={})),function(e){e.Error="CodeCell.Error"}(c||(c={}));const l={Runner:r,RunningEnvironment:a,CodeCell:c};var h;!function(e){e.NodeJS="nodejs-v16",e.Supabase="supabase"}(h||(h={}));const d={"nodejs-v16":{id:"nodejs-v16",fileExtension:".js",image:"us-central1-docker.pkg.dev/devbookhq/devbook-runner-templates/nodejs-v16:latest",root_dir:"/home/runner",code_cells_dir:"/home/runner/src",toCommand:e=>`node "${e}"`},supabase:{id:"supabase",fileExtension:".js",image:"us-central1-docker.pkg.dev/devbookhq/devbook-runner-templates/supabase",root_dir:"/home/runner",code_cells_dir:"/home/runner/src",toCommand:e=>`node "${e}"`}};class u{constructor(){this.url="wss://orchestrator.usedevbook.com",this.logger=new s("WebSocketConnection"),this.handlers=[]}get state(){var e;return null===(e=this.client)||void 0===e?void 0:e.readyState}get isClosed(){if(void 0!==this.client)return this.client.readyState===this.client.CLOSED}get isClosing(){if(void 0!==this.client)return this.client.readyState===this.client.CLOSING}get isOpen(){if(void 0!==this.client)return this.client.readyState===this.client.OPEN}get isConnecting(){if(void 0!==this.client)return this.client.readyState===this.client.CONNECTING}subscribeHandler(e){return this.handlers.push(e),()=>{this.handlers=this.handlers.filter((n=>n!==e))}}connect(e){(!this.client||this.client.readyState!==this.client.CONNECTING&&this.client.readyState!==this.client.OPEN)&&(e||this.sessionID?(e?(this.logger.log(`Will try to connect to session "${e}"`),this.sessionID=e):!e&&this.sessionID&&this.logger.log(`Will try to connect to previous session "${this.sessionID}"`),this.client=new WebSocket(`${this.url}/session/ws/${this.sessionID}`),this.client.onopen=()=>this.handleOpen(),this.client.onmessage=e=>{this.logger.log("Received (raw)",{msg:e}),this.handleMessage(e)},this.client.onerror=e=>this.handleError(e),this.client.onclose=e=>this.handleClose(e)):this.logger.error("Cannot connect, no session ID passed to the function and no session ID saved from the previous session"))}send(e){this.client&&this.client.readyState===this.client.OPEN?(this.logger.log("Send",e),this._send(e)):this.logger.warn("Trying to send a message while not being in the `OPEN` state or without established connection, message will be discarded",e)}close(){var e;this.logger.log("Closing connection"),null===(e=this.client)||void 0===e||e.close(1e3)}handleOpen(){var e;this.logger.log("Connection opened",{readyState:null===(e=this.client)||void 0===e?void 0:e.readyState}),this.handlers.forEach((e=>e.onOpen()))}_send(e){var n,t;null===(n=this.client)||void 0===n||n.send((t=e,JSON.stringify(t,(()=>{const e=new WeakSet;return(n,t)=>{if("object"==typeof t&&null!==t){if(e.has(t))return;e.add(t)}return t}})(),2)))}handleClose(e){return i(this,void 0,void 0,(function*(){this.logger.log("Connection closed",e),this.handlers.forEach((e=>e.onClose())),this.logger.log("Will try to reconnect in 3s"),yield o(3e3),this.connect()}))}handleError(e){var n;this.logger.error("Connection error",e),null===(n=this.client)||void 0===n||n.close()}handleMessage(e){if(!e.data)return void this.logger.error("Message has empty data field",e);const n=JSON.parse(e.data);if(!n.type)return void this.logger.error("Message has no type",n);const t=n;Object.values(l.RunningEnvironment).includes(t.type)||Object.values(l.Runner).includes(t.type)||Object.values(l.CodeCell).includes(t.type)?t.type!==l.Runner.Error?(this.logger.log("Received (parsed)",t),this.handlers.forEach((e=>e.onMessage(t)))):this.logger.error("Runner error",t):this.logger.error('Message "type" field has unexpected value',t)}}var g,v;!function(e){e.Ok="Ok",e.Terminated="Terminated"}(g||(g={}));class m{constructor(e,n=new Date){this.id=e,this.lastPing=n,this.logger=new s("RunnerSession"),this.url="https://orchestrator.usedevbook.com"}ping(){return i(this,void 0,void 0,(function*(){this.logger.log(`Pinging session "${this.id}"`);const e=JSON.stringify({sessionID:this.id});try{const n=yield fetch(`${this.url}/session/ping`,{method:"POST",headers:{"Content-Type":"application/json"},body:e}),t=yield n.json();if(!n.ok)throw this.logger.error(n.headers,t),new Error("Non-OK response when trying to ping active Runner session");if(t.status===g.Terminated)throw new Error(`[keepAlive]: Session '${this.id}' is terminated`);this.lastPing=new Date}catch(e){throw this.logger.error(e),new Error("Failed to ping active Runner session")}}))}}!function(e){e.Connected="Connected",e.Connecting="Connecting",e.Disconnected="Disconnected"}(v||(v={}));class p{constructor(e){this.conn=e,this.logger=new s("SessionManager"),this.url="https://orchestrator.usedevbook.com",this.isGettingSessionActive=!1,this.status=v.Disconnected,this.logger.log("Initialize"),this.getSession()}get cachedSessionID(){return sessionStorage.getItem("dbk_sdk_session_id")}set cachedSessionID(e){null===e?(this.logger.log("Cleared last sessionID"),sessionStorage.removeItem("dbk_sdk_session_id")):(this.logger.log(`Saved sessionID "${e}" as last sessionID`),sessionStorage.setItem("dbk_sdk_session_id",e))}reset(){this.logger.log("Reset"),this.status=v.Disconnected,this.cachedSessionID=null,this.conn.close(),this.session=void 0}getSession(){var e;return i(this,void 0,void 0,(function*(){if(!this.isGettingSessionActive)for(this.isGettingSessionActive=!0;;){this.status=v.Connecting;try{const n=this.cachedSessionID?`${this.url}/session/${this.cachedSessionID}`:`${this.url}/session`;this.cachedSessionID?this.logger.log(`Restoring old Runner session "${this.cachedSessionID}"`):this.logger.log("Acquiring new Runner session");const t=yield fetch(n),s=yield t.json();if(!t.ok){this.logger.error("Non-OK response when trying to ping active Runner session. Will try again in 3s",t.headers,s),yield o(3e3);continue}for(this.session=new m(s.sessionID),this.logger.log(`Acquired session "${this.session.id}"`),this.cachedSessionID=this.session.id,this.status=v.Connected,this.conn.connect(this.session.id),this.logger.log(`Started pinging session "${this.session.id}"`);this.session;)try{yield this.session.ping(),yield o(5e3)}catch(e){this.logger.error(`Failed to ping session "${this.session.id}"`,e);break}this.logger.log(`Stopped pinging session "${null===(e=this.session)||void 0===e?void 0:e.id}"`),this.session=void 0,this.status=v.Disconnected,this.conn.close()}catch(e){this.logger.error("Failed to acquire Runner session. Will try again in 3s",e),yield o(3e3)}}}))}}function f(e,n){for(var t=0,s=e.length-1;s>=0;s--){var i=e[s];"."===i?e.splice(s,1):".."===i?(e.splice(s,1),t++):t&&(e.splice(s,1),t--)}if(n)for(;t--;t)e.unshift("..");return e}var D=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/,C=function(e){return D.exec(e).slice(1)};function E(){for(var e="",n=!1,t=arguments.length-1;t>=-1&&!n;t--){var s=t>=0?arguments[t]:"/";if("string"!=typeof s)throw new TypeError("Arguments to path.resolve must be strings");s&&(e=s+"/"+e,n="/"===s.charAt(0))}return(n?"/":"")+(e=f(I(e.split("/"),(function(e){return!!e})),!n).join("/"))||"."}function S(e){var n=y(e),t="/"===R(e,-1);return(e=f(I(e.split("/"),(function(e){return!!e})),!n).join("/"))||n||(e="."),e&&t&&(e+="/"),(n?"/":"")+e}function y(e){return"/"===e.charAt(0)}var b={extname:function(e){return C(e)[3]},basename:function(e,n){var t=C(e)[2];return n&&t.substr(-1*n.length)===n&&(t=t.substr(0,t.length-n.length)),t},dirname:function(e){var n=C(e),t=n[0],s=n[1];return t||s?(s&&(s=s.substr(0,s.length-1)),t+s):"."},sep:"/",delimiter:":",relative:function(e,n){function t(e){for(var n=0;n<e.length&&""===e[n];n++);for(var t=e.length-1;t>=0&&""===e[t];t--);return n>t?[]:e.slice(n,t-n+1)}e=E(e).substr(1),n=E(n).substr(1);for(var s=t(e.split("/")),i=t(n.split("/")),o=Math.min(s.length,i.length),r=o,a=0;a<o;a++)if(s[a]!==i[a]){r=a;break}var c=[];for(a=r;a<s.length;a++)c.push("..");return(c=c.concat(i.slice(r))).join("/")},join:function(){var e=Array.prototype.slice.call(arguments,0);return S(I(e,(function(e,n){if("string"!=typeof e)throw new TypeError("Arguments to path.join must be strings");return e})).join("/"))},isAbsolute:y,normalize:S,resolve:E};function I(e,n){if(e.filter)return e.filter(n);for(var t=[],s=0;s<e.length;s++)n(e[s],s,e)&&t.push(e[s]);return t}var R="b"==="ab".substr(-1)?function(e,n,t){return e.substr(n,t)}:function(e,n,t){return n<0&&(n=e.length+n),e.substr(n,t)};function x(e){return function(e){const n=Array.from(e).reduce(((e,n)=>0|31*e+n.charCodeAt(0)),0);return("0000000"+(n>>>0).toString(16)).slice(-8)}(e)}class w{constructor(e,n){this.contextID=e,this.templateID=n,this.isReady=!1,this.id=`${e}_${x(n)}`,this.template=d[this.templateID]}}function _(e,{environmentID:n,template:t}){const s={type:l.RunningEnvironment.Start,payload:{environmentID:n,template:t}};e.send(s)}function k(e,{environmentID:n,executionID:t,command:s}){const i={type:l.RunningEnvironment.ExecCmd,payload:{environmentID:n,executionID:t,command:s}};e.send(i)}class O{constructor(e){this.opts=e,this.fsWriteSubscribers=[],this.envs=[],this.logger=new s("EvaluationContext",e.debug),this.unsubscribeConnHandler=this.opts.conn.subscribeHandler({onOpen:this.handleConnectionOpen.bind(this),onMessage:this.handleConnectionMessage.bind(this),onClose:this.handleConnectionClose.bind(this)}),this.opts.conn.isOpen&&this.handleConnectionOpen(),this.opts.conn.isClosed&&this.handleConnectionClose()}get contextID(){return this.opts.contextID}restart(){return this.logger.log("Restart",this.opts.conn.sessionID),this.envs.forEach((e=>{e.isReady=!1,_(this.opts.conn,{environmentID:e.id,template:e.template})}))}destroy(){this.logger.log("Destroy"),this.unsubscribeConnHandler(),this.envs=[],this.fsWriteSubscribers=[]}executeCode({templateID:e,executionID:n,code:t}){return i(this,void 0,void 0,(function*(){this.logger.log("Execute code",{templateID:e,executionID:n});const s=this.envs.find((n=>n.templateID===e));if(!s)return void this.logger.error("Environment not found",{templateID:e,executionID:n});if(!s.isReady)return void this.logger.error("Environment is not ready",{templateID:e,executionID:n});const i=d[e].fileExtension,o=`${n}${i}`,r=b.join("/src",o);!function(e,{environmentID:n,path:t,content:s}){const i={type:l.RunningEnvironment.WriteFile,payload:{environmentID:n,path:t,content:s}};e.send(i)}(this.opts.conn,{environmentID:s.id,path:r,content:t});const a=b.join(d[e].root_dir,r),c=d[e].toCommand(a);k(this.opts.conn,{environmentID:s.id,executionID:n,command:c})}))}executeCommand({templateID:e,executionID:n,command:t}){this.logger.log("Execute shell command",{templateID:e,executionID:n,command:t});const s=this.envs.find((n=>n.templateID===e));s?s.isReady?k(this.opts.conn,{environmentID:s.id,executionID:n,command:t}):this.logger.error("Environment is not ready",{templateID:e,executionID:n,command:t}):this.logger.error("Environment not found",{templateID:e,executionID:n,command:t})}createRunningEnvironment({templateID:e}){var n,t;this.logger.log("Creating running environment",{templateID:e});if(this.envs.find((n=>n.templateID===e)))return;const s=new w(this.contextID,e);this.envs.push(s),_(this.opts.conn,{environmentID:s.id,template:s.template}),null===(t=(n=this.opts).onEnvChange)||void 0===t||t.call(n,s)}subscribeFSWrite(e){console.log("len",this.fsWriteSubscribers.length),this.fsWriteSubscribers.push(e)}unsubscribeFSWrite(e){console.log("len",this.fsWriteSubscribers.length);const n=this.fsWriteSubscribers.indexOf(e);n>-1&&this.fsWriteSubscribers.splice(n,1)}handleConnectionOpen(){var e,n;this.restart(),null===(n=(e=this.opts).onSessionChange)||void 0===n||n.call(e,{status:v.Connected})}handleConnectionClose(){var e,n;null===(n=(e=this.opts).onSessionChange)||void 0===n||n.call(e,{status:v.Connecting})}handleConnectionMessage(e){switch(this.logger.log("Handling message from remote Runner",{message:e}),e.type){case l.RunningEnvironment.StartAck:{const n=e;this.vmenv_handleStartAck(n.payload);break}case l.RunningEnvironment.CmdOut:{const n=e;this.vmenv_handleCmdOut(n.payload);break}case l.RunningEnvironment.CmdExit:{const n=e;this.vmenv_handleCmdExit(n.payload);break}case l.RunningEnvironment.FSEventWrite:{const n=e;this.vmenv_handleFSEventWrite(n.payload);break}default:this.logger.warn("Unknown message type",{message:e})}}vmenv_handleCmdExit(e){var n,t;void 0!==e.error&&(null===(t=(n=this.opts).onCmdOut)||void 0===t||t.call(n,{environmentID:e.environmentID,executionID:e.executionID,stderr:e.error}))}vmenv_handleFSEventWrite(e){this.logger.log('[vmenv] Handling "FSEventWrite"',e);this.envs.find((n=>n.id===e.environmentID))?this.fsWriteSubscribers.forEach((n=>n(e))):this.logger.warn("Environment not found",{payload:e})}vmenv_handleStartAck(e){var n,t;this.logger.log('[vmenv] Handling "StartAck"',{payload:e});const s=this.envs.find((n=>n.id===e.environmentID));s?(s.isReady=!0,null===(t=(n=this.opts).onEnvChange)||void 0===t||t.call(n,s)):this.logger.warn("Environment not found",{payload:e})}vmenv_handleCmdOut(e){var n,t;this.logger.log('[vmenv] Handling "CmdOut"',e),null===(t=(n=this.opts).onCmdOut)||void 0===t||t.call(n,e)}}class j{constructor(){this.logger=new s("Runner"),this.conn=new u,this.sessManager=new p(this.conn)}static get obj(){return j._obj||(j._obj=new j)}get session(){return this.sessManager.session}get status(){return this.sessManager.status}reset(){this.logger.log("Reset"),this.sessManager.reset()}createContext(e){return new O(Object.assign(Object.assign({},e),{conn:this.conn}))}__debug__loadNewSession(){this.logger.log("__debug__loadNewSession"),this.sessManager.reset()}}const W=($="1234567890abcdefghijklmnopqrstuvwxyz",F=6,()=>{let e="",n=F;for(;n--;)e+=$[Math.random()*$.length|0];return e});var $,F,A;!function(e){e[e.Disconnected=0]="Disconnected",e[e.Connecting=1]="Connecting",e[e.Connected=2]="Connected"}(A||(A={}));class N{constructor(e){this.opts=e,this._isDestroyed=!1,this._isEnvReady=!1,this._sessionStatus=v.Disconnected,this._status=A.Disconnected;const n="default";this.contextID=n,this.executionID=W();const t=()=>this.executionID,s=e=>this.isEnvReady=e,i=e=>this.sessionStatus=e;this.context=j.obj.createContext({debug:e.debug,contextID:n,onEnvChange(e){s(e.isReady)},onSessionChange({status:e}){i(e)},onCmdOut(n){var s,i;n.executionID===t()&&(void 0!==n.stdout&&(null===(s=e.onStdout)||void 0===s||s.call(e,n.stdout)),void 0!==n.stderr&&(null===(i=e.onStderr)||void 0===i||i.call(e,n.stderr)))}}),this.context.createRunningEnvironment({templateID:e.env})}get isDestroyed(){return this._isDestroyed}set isDestroyed(e){this._isDestroyed=e,this.updateStatus()}get isEnvReady(){return this._isEnvReady}set isEnvReady(e){this._isEnvReady=e,this.updateStatus()}get sessionStatus(){return this._sessionStatus}set sessionStatus(e){this._sessionStatus=e,this.updateStatus()}get status(){return this._status}set status(e){var n,t;this._status=e,null===(t=(n=this.opts).onStatusChange)||void 0===t||t.call(n,e)}runCmd(e){this.status!==A.Disconnected&&(this.executionID=W(),this.context.executeCommand({templateID:this.opts.env,executionID:this.executionID,command:e}))}runCode(e){this.status!==A.Disconnected&&(this.executionID=W(),this.context.executeCode({templateID:this.opts.env,executionID:this.executionID,code:e}))}destroy(){this.context.destroy(),this.isDestroyed=!0}updateStatus(){if(this.isDestroyed)return void(this.status!==A.Disconnected&&(this.status=A.Disconnected));let e;switch(this.sessionStatus){case v.Disconnected:e=A.Disconnected;break;case v.Connecting:e=A.Connecting;break;case v.Connected:if(!this.isEnvReady){e=A.Connecting;break}e=A.Connected}this.status=e}}function M({env:s,debug:i}){const[o,r]=e(),[a,c]=e(A.Disconnected),[l,h]=e([]),[d,u]=e([]),g=n((e=>{o&&(u([]),h([]),o.runCmd(e))}),[o]),v=n((e=>{o&&(u([]),h([]),o.runCode(e))}),[o]);return t((function(){const e=new N({debug:i,env:s,onStatusChange(e){c(e)},onStderr(e){h((n=>[...n,e]))},onStdout(e){u((n=>[...n,e]))}});return u([]),h([]),r(e),()=>{e.destroy()}}),[s,i]),{stderr:l,stdout:d,runCmd:g,runCode:v,status:a}}export{N as Devbook,A as DevbookStatus,h as Env,M as useDevbook}; | ||
***************************************************************************** */function s(e,t,n,s){return new(n||(n=Promise))((function(i,o){function r(e){try{l(s.next(e))}catch(e){o(e)}}function a(e){try{l(s.throw(e))}catch(e){o(e)}}function l(e){var t;e.done?i(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(r,a)}l((s=s.apply(e,t||[])).next())}))}class i{constructor(e,t=!1){this.logID=e,this.isEnabled=t}id(){return"function"==typeof this.logID?this.logID():this.logID}log(...e){this.isEnabled&&console.log(`[36m[${this.id()}][0m`,...e)}warn(...e){this.isEnabled&&console.warn(`[36m[${this.id()}][0m`,...e)}error(...e){console.error(`[31m[${this.id()} ERROR][0m`,...e)}}function o(e){return new Promise((t=>setTimeout(t,e)))}var r,a,l;!function(e){e.Error="Runner.Error"}(r||(r={})),function(e){e.Start="RunningEnvironment.Start",e.StartAck="RunningEnvironment.StartAck",e.Eval="RunningEnvironment.Eval",e.FSEventCreate="RunningEnvironment.FSEventCreate",e.FSEventRemove="RunningEnvironment.FSEventRemove",e.FSEventWrite="RunningEnvironment.FSEventWrite",e.CreateDir="RunningEnvironment.CreateDir",e.ListDir="RunningEnvironment.ListDir",e.WriteFile="RunningEnvironment.WriteFile",e.GetFile="RunningEnvironment.GetFile",e.RemoveFile="RunningEnvironment.RemoveFile",e.DirContent="RunningEnvironment.DirContent",e.FileContent="RunningEnvironment.FileContent",e.Stdout="RunningEnvironment.Stdout",e.Stderr="RunningEnvironment.Stderr",e.ExecCmd="RunningEnvironment.ExecCmd",e.KillCmd="RunningEnvironment.KillCmd",e.ListRunningCmds="RunningEnvironment.ListRunningCmds",e.CmdOut="RunningEnvironment.CmdOut",e.CmdExit="RunningEnvironment.CmdExit",e.RunningCmds="RunningEnvironment.RunningCmds",e.RunCode="RunningEnvironment.Run"}(a||(a={})),function(e){e.Error="CodeCell.Error"}(l||(l={}));const c={Runner:r,RunningEnvironment:a,CodeCell:l};var h;!function(e){e.NodeJS="nodejs-v16",e.Supabase="supabase"}(h||(h={}));const d={"nodejs-v16":{id:"nodejs-v16",fileExtension:".js",image:"us-central1-docker.pkg.dev/devbookhq/devbook-runner-templates/nodejs-v16:latest",root_dir:"/home/runner",code_cells_dir:"/home/runner/src",toCommand:e=>`node "${e}"`},supabase:{id:"supabase",fileExtension:".js",image:"us-central1-docker.pkg.dev/devbookhq/devbook-runner-templates/supabase",root_dir:"/home/runner",code_cells_dir:"/home/runner/src",toCommand:e=>`node "${e}"`}};class u{constructor(){this.url="wss://orchestrator.usedevbook.com",this.logger=new i("WebSocketConnection"),this.handlers=[]}get state(){var e;return null===(e=this.client)||void 0===e?void 0:e.readyState}get isClosed(){if(void 0!==this.client)return this.client.readyState===this.client.CLOSED}get isClosing(){if(void 0!==this.client)return this.client.readyState===this.client.CLOSING}get isOpen(){if(void 0!==this.client)return this.client.readyState===this.client.OPEN}get isConnecting(){if(void 0!==this.client)return this.client.readyState===this.client.CONNECTING}subscribeHandler(e){return this.handlers.push(e),()=>{this.handlers=this.handlers.filter((t=>t!==e))}}connect(e){(!this.client||this.client.readyState!==this.client.CONNECTING&&this.client.readyState!==this.client.OPEN)&&(e||this.sessionID?(e?(this.logger.log(`Will try to connect to session "${e}"`),this.sessionID=e):!e&&this.sessionID&&this.logger.log(`Will try to connect to previous session "${this.sessionID}"`),this.client=new WebSocket(`${this.url}/session/ws/${this.sessionID}`),this.client.onopen=()=>this.handleOpen(),this.client.onmessage=e=>{this.logger.log("Received (raw)",{msg:e}),this.handleMessage(e)},this.client.onerror=e=>this.handleError(e),this.client.onclose=e=>this.handleClose(e)):this.logger.error("Cannot connect, no session ID passed to the function and no session ID saved from the previous session"))}send(e){this.client&&this.client.readyState===this.client.OPEN?(this.logger.log("Send",e),this._send(e)):this.logger.warn("Trying to send a message while not being in the `OPEN` state or without established connection, message will be discarded",e)}close(){var e;this.logger.log("Closing connection"),null===(e=this.client)||void 0===e||e.close(1e3)}handleOpen(){var e;this.logger.log("Connection opened",{readyState:null===(e=this.client)||void 0===e?void 0:e.readyState}),this.handlers.forEach((e=>e.onOpen()))}_send(e){var t,n;null===(t=this.client)||void 0===t||t.send((n=e,JSON.stringify(n,(()=>{const e=new WeakSet;return(t,n)=>{if("object"==typeof n&&null!==n){if(e.has(n))return;e.add(n)}return n}})(),2)))}handleClose(e){return s(this,void 0,void 0,(function*(){this.logger.log("Connection closed",e),this.handlers.forEach((e=>e.onClose())),this.logger.log("Will try to reconnect in 3s"),yield o(3e3),this.connect()}))}handleError(e){var t;this.logger.error("Connection error",e),null===(t=this.client)||void 0===t||t.close()}handleMessage(e){if(!e.data)return void this.logger.error("Message has empty data field",e);const t=JSON.parse(e.data);if(!t.type)return void this.logger.error("Message has no type",t);const n=t;Object.values(c.RunningEnvironment).includes(n.type)||Object.values(c.Runner).includes(n.type)||Object.values(c.CodeCell).includes(n.type)?n.type!==c.Runner.Error?(this.logger.log("Received (parsed)",n),this.handlers.forEach((e=>e.onMessage(n)))):this.logger.error("Runner error",n):this.logger.error('Message "type" field has unexpected value',n)}}var g,v;!function(e){e.Ok="Ok",e.Terminated="Terminated"}(g||(g={}));class m{constructor(e,t=new Date){this.id=e,this.lastPing=t,this.logger=new i("RunnerSession"),this.url="https://orchestrator.usedevbook.com"}ping(){return s(this,void 0,void 0,(function*(){this.logger.log(`Pinging session "${this.id}"`);const e=JSON.stringify({sessionID:this.id});try{const t=yield fetch(`${this.url}/session/ping`,{method:"POST",headers:{"Content-Type":"application/json"},body:e}),n=yield t.json();if(!t.ok)throw this.logger.error(t.headers,n),new Error("Non-OK response when trying to ping active Runner session");if(n.status===g.Terminated)throw new Error(`[keepAlive]: Session '${this.id}' is terminated`);this.lastPing=new Date}catch(e){throw this.logger.error(e),new Error("Failed to ping active Runner session")}}))}}!function(e){e.Connected="Connected",e.Connecting="Connecting",e.Disconnected="Disconnected"}(v||(v={}));class p{constructor(e){this.conn=e,this.logger=new i("SessionManager"),this.url="https://orchestrator.usedevbook.com",this.isGettingSessionActive=!1,this.status=v.Disconnected,this.logger.log("Initialize"),this.getSession()}get cachedSessionID(){return sessionStorage.getItem("dbk_sdk_session_id")}set cachedSessionID(e){null===e?(this.logger.log("Cleared last sessionID"),sessionStorage.removeItem("dbk_sdk_session_id")):(this.logger.log(`Saved sessionID "${e}" as last sessionID`),sessionStorage.setItem("dbk_sdk_session_id",e))}reset(){this.logger.log("Reset"),this.status=v.Disconnected,this.cachedSessionID=null,this.conn.close(),this.session=void 0}getSession(){var e;return s(this,void 0,void 0,(function*(){if(!this.isGettingSessionActive)for(this.isGettingSessionActive=!0;;){this.status=v.Connecting;try{const t=this.cachedSessionID?`${this.url}/session/${this.cachedSessionID}`:`${this.url}/session`;this.cachedSessionID?this.logger.log(`Restoring old Runner session "${this.cachedSessionID}"`):this.logger.log("Acquiring new Runner session");const n=yield fetch(t),s=yield n.json();if(!n.ok){this.logger.error("Non-OK response when trying to ping active Runner session. Will try again in 3s",n.headers,s),yield o(3e3);continue}for(this.session=new m(s.sessionID),this.logger.log(`Acquired session "${this.session.id}"`),this.cachedSessionID=this.session.id,this.status=v.Connected,this.conn.connect(this.session.id),this.logger.log(`Started pinging session "${this.session.id}"`);this.session;)try{yield this.session.ping(),yield o(5e3)}catch(e){this.logger.error(`Failed to ping session "${this.session.id}"`,e);break}this.logger.log(`Stopped pinging session "${null===(e=this.session)||void 0===e?void 0:e.id}"`),this.session=void 0,this.status=v.Disconnected,this.conn.close()}catch(e){this.logger.error("Failed to acquire Runner session. Will try again in 3s",e),yield o(3e3)}}}))}}function f(e,t){for(var n=0,s=e.length-1;s>=0;s--){var i=e[s];"."===i?e.splice(s,1):".."===i?(e.splice(s,1),n++):n&&(e.splice(s,1),n--)}if(t)for(;n--;n)e.unshift("..");return e}var D=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/,C=function(e){return D.exec(e).slice(1)};function E(){for(var e="",t=!1,n=arguments.length-1;n>=-1&&!t;n--){var s=n>=0?arguments[n]:"/";if("string"!=typeof s)throw new TypeError("Arguments to path.resolve must be strings");s&&(e=s+"/"+e,t="/"===s.charAt(0))}return(t?"/":"")+(e=f(S(e.split("/"),(function(e){return!!e})),!t).join("/"))||"."}function b(e){var t=y(e),n="/"===R(e,-1);return(e=f(S(e.split("/"),(function(e){return!!e})),!t).join("/"))||t||(e="."),e&&n&&(e+="/"),(t?"/":"")+e}function y(e){return"/"===e.charAt(0)}var I={extname:function(e){return C(e)[3]},basename:function(e,t){var n=C(e)[2];return t&&n.substr(-1*t.length)===t&&(n=n.substr(0,n.length-t.length)),n},dirname:function(e){var t=C(e),n=t[0],s=t[1];return n||s?(s&&(s=s.substr(0,s.length-1)),n+s):"."},sep:"/",delimiter:":",relative:function(e,t){function n(e){for(var t=0;t<e.length&&""===e[t];t++);for(var n=e.length-1;n>=0&&""===e[n];n--);return t>n?[]:e.slice(t,n-t+1)}e=E(e).substr(1),t=E(t).substr(1);for(var s=n(e.split("/")),i=n(t.split("/")),o=Math.min(s.length,i.length),r=o,a=0;a<o;a++)if(s[a]!==i[a]){r=a;break}var l=[];for(a=r;a<s.length;a++)l.push("..");return(l=l.concat(i.slice(r))).join("/")},join:function(){var e=Array.prototype.slice.call(arguments,0);return b(S(e,(function(e,t){if("string"!=typeof e)throw new TypeError("Arguments to path.join must be strings");return e})).join("/"))},isAbsolute:y,normalize:b,resolve:E};function S(e,t){if(e.filter)return e.filter(t);for(var n=[],s=0;s<e.length;s++)t(e[s],s,e)&&n.push(e[s]);return n}var R="b"==="ab".substr(-1)?function(e,t,n){return e.substr(t,n)}:function(e,t,n){return t<0&&(t=e.length+t),e.substr(t,n)};function w(e){return function(e){const t=Array.from(e).reduce(((e,t)=>0|31*e+t.charCodeAt(0)),0);return("0000000"+(t>>>0).toString(16)).slice(-8)}(e)}class x{constructor(e,t){this.contextID=e,this.templateID=t,this.isReady=!1,this.id=`${e}_${w(t)}`,this.template=d[this.templateID]}}function _(e,{environmentID:t,template:n}){const s={type:c.RunningEnvironment.Start,payload:{environmentID:t,template:n}};e.send(s)}function F(e,{environmentID:t,executionID:n,command:s}){const i={type:c.RunningEnvironment.ExecCmd,payload:{environmentID:t,executionID:n,command:s}};e.send(i)}function k(e,{environmentID:t,path:n,content:s}){const i={type:c.RunningEnvironment.WriteFile,payload:{environmentID:t,path:n,content:s}};e.send(i)}class O{constructor(e){this.opts=e,this.fsWriteSubscribers=[],this.fileContentSubscribers=[],this.envs=[],this.logger=new i("EvaluationContext",e.debug),this.unsubscribeConnHandler=this.opts.conn.subscribeHandler({onOpen:this.handleConnectionOpen.bind(this),onMessage:this.handleConnectionMessage.bind(this),onClose:this.handleConnectionClose.bind(this)}),this.opts.conn.isOpen&&this.handleConnectionOpen(),this.opts.conn.isClosed&&this.handleConnectionClose()}get contextID(){return this.opts.contextID}restart(){return this.logger.log("Restart",this.opts.conn.sessionID),this.envs.forEach((e=>{e.isReady=!1,_(this.opts.conn,{environmentID:e.id,template:e.template})}))}destroy(){this.logger.log("Destroy"),this.unsubscribeConnHandler(),this.envs=[],this.fsWriteSubscribers=[]}getFile({templateID:e,path:t}){return s(this,void 0,void 0,(function*(){this.logger.log("Get file",{templateID:e,path:I});const n=this.envs.find((t=>t.templateID===e));if(!n)return void this.logger.error("Environment not found",{templateID:e,path:I});if(!n.isReady)return void this.logger.error("Environment is not ready",{templateID:e,path:I});let s;const i=new Promise(((e,t)=>{s=e,setTimeout((()=>{t("Timeout")}),1e4)})),o=e=>{e.path.endsWith(t)&&s(e.content)};this.subscribeFileContent(o),function(e,{environmentID:t,path:n}){const s={type:c.RunningEnvironment.GetFile,payload:{environmentID:t,path:n}};e.send(s)}(this.opts.conn,{path:t,environmentID:n.id});try{return yield i}catch(e){throw new Error(`Error retriving file ${t}: ${e.message}`)}finally{this.unsubscribeFileContent(o)}}))}updateFile({templateID:e,path:t,content:n}){return s(this,void 0,void 0,(function*(){this.logger.log("Update file",{templateID:e,filepath:t});const s=this.envs.find((t=>t.templateID===e));if(!s)return void this.logger.error("Environment not found",{templateID:e,filepath:t});if(!s.isReady)return void this.logger.error("Environment is not ready",{templateID:e,filepath:t});let i;const o=new Promise(((e,t)=>{i=e,setTimeout((()=>{t("Timeout")}),1e4)})),r=e=>{e.path.endsWith(t)&&i()};this.subscribeFSWrite(r),k(this.opts.conn,{environmentID:s.id,path:t,content:n});try{yield o}catch(e){throw new Error(`File ${t} not written to VM: ${e.message}`)}finally{this.unsubscribeFSWrite(r)}}))}executeCode({templateID:e,executionID:t,code:n}){return s(this,void 0,void 0,(function*(){this.logger.log("Execute code",{templateID:e,executionID:t});const s=this.envs.find((t=>t.templateID===e));if(!s)return void this.logger.error("Environment not found",{templateID:e,executionID:t});if(!s.isReady)return void this.logger.error("Environment is not ready",{templateID:e,executionID:t});const i=d[e].fileExtension,o=`${t}${i}`,r=I.join("/src",o);k(this.opts.conn,{environmentID:s.id,path:r,content:n});const a=I.join(d[e].root_dir,r),l=d[e].toCommand(a);F(this.opts.conn,{environmentID:s.id,executionID:t,command:l})}))}executeCommand({templateID:e,executionID:t,command:n}){this.logger.log("Execute shell command",{templateID:e,executionID:t,command:n});const s=this.envs.find((t=>t.templateID===e));s?s.isReady?F(this.opts.conn,{environmentID:s.id,executionID:t,command:n}):this.logger.error("Environment is not ready",{templateID:e,executionID:t,command:n}):this.logger.error("Environment not found",{templateID:e,executionID:t,command:n})}createRunningEnvironment({templateID:e}){var t,n;this.logger.log("Creating running environment",{templateID:e});if(this.envs.find((t=>t.templateID===e)))return;const s=new x(this.contextID,e);this.envs.push(s),_(this.opts.conn,{environmentID:s.id,template:s.template}),null===(n=(t=this.opts).onEnvChange)||void 0===n||n.call(t,s)}subscribeFileContent(e){this.fileContentSubscribers.push(e)}unsubscribeFileContent(e){const t=this.fileContentSubscribers.indexOf(e);t>-1&&this.fileContentSubscribers.splice(t,1)}subscribeFSWrite(e){this.fsWriteSubscribers.push(e)}unsubscribeFSWrite(e){const t=this.fsWriteSubscribers.indexOf(e);t>-1&&this.fsWriteSubscribers.splice(t,1)}handleConnectionOpen(){var e,t;this.restart(),null===(t=(e=this.opts).onSessionChange)||void 0===t||t.call(e,{status:v.Connected})}handleConnectionClose(){var e,t;null===(t=(e=this.opts).onSessionChange)||void 0===t||t.call(e,{status:v.Connecting})}handleConnectionMessage(e){switch(this.logger.log("Handling message from remote Runner",{message:e}),e.type){case c.RunningEnvironment.StartAck:{const t=e;this.vmenv_handleStartAck(t.payload);break}case c.RunningEnvironment.CmdOut:{const t=e;this.vmenv_handleCmdOut(t.payload);break}case c.RunningEnvironment.CmdExit:{const t=e;this.vmenv_handleCmdExit(t.payload);break}case c.RunningEnvironment.FSEventWrite:{const t=e;this.vmenv_handleFSEventWrite(t.payload);break}case c.RunningEnvironment.FileContent:{const t=e;this.vmenv_handleFileContent(t.payload);break}default:this.logger.warn("Unknown message type",{message:e})}}vmenv_handleCmdExit(e){var t,n;void 0!==e.error&&(null===(n=(t=this.opts).onCmdOut)||void 0===n||n.call(t,{environmentID:e.environmentID,executionID:e.executionID,stderr:e.error}))}vmenv_handleFSEventWrite(e){this.logger.log('[vmenv] Handling "FSEventWrite"',e);this.envs.find((t=>t.id===e.environmentID))?this.fsWriteSubscribers.forEach((t=>t(e))):this.logger.warn("Environment not found",{payload:e})}vmenv_handleFileContent(e){this.logger.log('[vmenv] Handling "FileContent"',{environmentID:e.environmentID,path:e.path});this.envs.find((t=>t.id===e.environmentID))?this.fileContentSubscribers.forEach((t=>t(e))):this.logger.warn("Environment not found",{payload:e})}vmenv_handleStartAck(e){var t,n;this.logger.log('[vmenv] Handling "StartAck"',{payload:e});const s=this.envs.find((t=>t.id===e.environmentID));s?(s.isReady=!0,null===(n=(t=this.opts).onEnvChange)||void 0===n||n.call(t,s)):this.logger.warn("Environment not found",{payload:e})}vmenv_handleCmdOut(e){var t,n;this.logger.log('[vmenv] Handling "CmdOut"',e),null===(n=(t=this.opts).onCmdOut)||void 0===n||n.call(t,e)}}class ${constructor(){this.logger=new i("Runner"),this.conn=new u,this.sessManager=new p(this.conn)}static get obj(){return $._obj||($._obj=new $)}get session(){return this.sessManager.session}get status(){return this.sessManager.status}reset(){this.logger.log("Reset"),this.sessManager.reset()}createContext(e){return new O(Object.assign(Object.assign({},e),{conn:this.conn}))}__debug__loadNewSession(){this.logger.log("__debug__loadNewSession"),this.sessManager.reset()}}const W=(j="1234567890abcdefghijklmnopqrstuvwxyz",N=6,()=>{let e="",t=N;for(;t--;)e+=j[Math.random()*j.length|0];return e});var j,N,M;!function(e){e[e.Disconnected=0]="Disconnected",e[e.Connecting=1]="Connecting",e[e.Connected=2]="Connected"}(M||(M={}));class A{constructor(e){this.opts=e,this._isDestroyed=!1,this._isEnvReady=!1,this._sessionStatus=v.Disconnected,this._status=M.Disconnected;const t="default";this.contextID=t,this.executionID=W();const n=()=>this.executionID,s=e=>this.isEnvReady=e,i=e=>this.sessionStatus=e;this.context=$.obj.createContext({debug:e.debug,contextID:t,onEnvChange(e){s(e.isReady)},onSessionChange({status:e}){i(e)},onCmdOut(t){var s,i;t.executionID===n()&&(void 0!==t.stdout&&(null===(s=e.onStdout)||void 0===s||s.call(e,t.stdout)),void 0!==t.stderr&&(null===(i=e.onStderr)||void 0===i||i.call(e,t.stderr)))}}),this.context.createRunningEnvironment({templateID:e.env})}get fs(){return{get:this.getFile.bind(this),write:this.writeFile.bind(this)}}get isDestroyed(){return this._isDestroyed}set isDestroyed(e){this._isDestroyed=e,this.updateStatus()}get isEnvReady(){return this._isEnvReady}set isEnvReady(e){this._isEnvReady=e,this.updateStatus()}get sessionStatus(){return this._sessionStatus}set sessionStatus(e){this._sessionStatus=e,this.updateStatus()}get status(){return this._status}set status(e){var t,n;this._status=e,null===(n=(t=this.opts).onStatusChange)||void 0===n||n.call(t,e)}getFile(e){return s(this,void 0,void 0,(function*(){if(this.status!==M.Connected)throw new Error("Not connected to the VM yet.");return this.context.getFile({templateID:this.opts.env,path:e})}))}writeFile(e,t){return s(this,void 0,void 0,(function*(){if(this.status!==M.Connected)throw new Error("Not connected to the VM yet.");return this.context.updateFile({templateID:this.opts.env,path:e,content:t})}))}runCmd(e){if(this.status!==M.Connected)throw new Error("Not connected to the VM yet.");this.executionID=W(),this.context.executeCommand({templateID:this.opts.env,executionID:this.executionID,command:e})}runCode(e){if(this.status!==M.Connected)throw new Error("Not connected to the VM yet.");this.executionID=W(),this.context.executeCode({templateID:this.opts.env,executionID:this.executionID,code:e})}destroy(){this.context.destroy(),this.isDestroyed=!0}updateStatus(){if(this.isDestroyed)return void(this.status!==M.Disconnected&&(this.status=M.Disconnected));let e;switch(this.sessionStatus){case v.Disconnected:e=M.Disconnected;break;case v.Connecting:e=M.Connecting;break;case v.Connected:if(!this.isEnvReady){e=M.Connecting;break}e=M.Connected}this.status=e}}function T({env:s,debug:i}){const[o,r]=e(),[a,l]=e(M.Disconnected),[c,h]=e([]),[d,u]=e([]),g=t((e=>{o&&(u([]),h([]),o.runCmd(e))}),[o]),v=t((e=>{o&&(u([]),h([]),o.runCode(e))}),[o]);return n((function(){const e=new A({debug:i,env:s,onStatusChange(e){l(e)},onStderr(e){h((t=>[...t,e]))},onStdout(e){u((t=>[...t,e]))}});return u([]),h([]),r(e),()=>{e.destroy()}}),[s,i]),{stderr:c,stdout:d,runCmd:g,runCode:v,status:a,fs:null==o?void 0:o.fs}}export{A as Devbook,M as DevbookStatus,h as Env,T as useDevbook}; | ||
//# sourceMappingURL=index.js.map |
import { DevbookStatus, Env } from 'src/core'; | ||
import { FS } from 'src/core/devbook'; | ||
/** | ||
@@ -55,2 +56,3 @@ * Options passed to the {@link useDevbook} hook. | ||
runCmd: (command: string) => void; | ||
fs?: FS; | ||
} | ||
@@ -57,0 +59,0 @@ /** |
import { Env } from './constants'; | ||
export interface FS { | ||
get: (path: string) => Promise<string | undefined>; | ||
write: (path: string, content: string) => Promise<void>; | ||
} | ||
/** | ||
@@ -30,2 +34,3 @@ * States of a {@link Devbook} connection to a VM. | ||
private readonly contextID; | ||
get fs(): FS; | ||
private _isDestroyed; | ||
@@ -72,2 +77,4 @@ private get isDestroyed(); | ||
}); | ||
getFile(path: string): Promise<string | undefined>; | ||
writeFile(path: string, content: string): Promise<void>; | ||
/** | ||
@@ -74,0 +81,0 @@ * Run `command` in the VM. |
@@ -21,2 +21,3 @@ import * as rws from 'src/common-ts/RunnerWebSocket'; | ||
private fsWriteSubscribers; | ||
private fileContentSubscribers; | ||
private envs; | ||
@@ -31,2 +32,11 @@ private readonly unsubscribeConnHandler; | ||
destroy(): void; | ||
getFile({ templateID, path: filepath }: { | ||
templateID: Env; | ||
path: string; | ||
}): Promise<string | undefined>; | ||
updateFile({ templateID, path: filepath, content }: { | ||
templateID: Env; | ||
path: string; | ||
content: string; | ||
}): Promise<void>; | ||
executeCode({ templateID, executionID, code }: { | ||
@@ -45,2 +55,4 @@ templateID: Env; | ||
}): void; | ||
private subscribeFileContent; | ||
private unsubscribeFileContent; | ||
private subscribeFSWrite; | ||
@@ -53,2 +65,3 @@ private unsubscribeFSWrite; | ||
private vmenv_handleFSEventWrite; | ||
private vmenv_handleFileContent; | ||
private vmenv_handleStartAck; | ||
@@ -55,0 +68,0 @@ private vmenv_handleCmdOut; |
import { TemplateConfig } from 'src/common-ts/TemplateConfig'; | ||
import { WebSocketConnection } from 'src/core/webSocketConnection'; | ||
/** | ||
* Request to receive the `RunningEnvironment.DirContent` message in the future | ||
* containting the content of the directory at the given path. | ||
*/ | ||
declare function listDir(conn: WebSocketConnection, { environmentID, path, }: { | ||
environmentID: string; | ||
path: string; | ||
}): void; | ||
/** | ||
* Request to create a dir in the environment's filesystem. | ||
*/ | ||
declare function createDir(conn: WebSocketConnection, { environmentID, path, }: { | ||
environmentID: string; | ||
path: string; | ||
}): void; | ||
/** | ||
* Request to get a file from the environment's filesystem. | ||
*/ | ||
declare function getFile(conn: WebSocketConnection, { environmentID, path, }: { | ||
environmentID: string; | ||
path: string; | ||
}): void; | ||
declare function start(conn: WebSocketConnection, { environmentID, template, }: { | ||
@@ -27,2 +49,2 @@ environmentID: string; | ||
}): void; | ||
export { start, execCmd, writeFile, deleteFile, }; | ||
export { start, execCmd, writeFile, deleteFile, getFile, createDir, listDir, }; |
@@ -1,16 +0,16 @@ | ||
!function(e,n){"object"==typeof exports&&"undefined"!=typeof module?n(exports,require("react")):"function"==typeof define&&define.amd?define(["exports","react"],n):n((e="undefined"!=typeof globalThis?globalThis:e||self)["@devbookhq/sdk"]={},e.react)}(this,(function(e,n){"use strict";class t{constructor(e,n=!1){this.logID=e,this.isEnabled=n}id(){return"function"==typeof this.logID?this.logID():this.logID}log(...e){this.isEnabled&&console.log(`[36m[${this.id()}][0m`,...e)}warn(...e){this.isEnabled&&console.warn(`[36m[${this.id()}][0m`,...e)}error(...e){console.error(`[31m[${this.id()} ERROR][0m`,...e)}} | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("react")):"function"==typeof define&&define.amd?define(["exports","react"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self)["@devbookhq/sdk"]={},e.react)}(this,(function(e,t){"use strict"; | ||
/*! ***************************************************************************** | ||
Copyright (c) Microsoft Corporation. | ||
Copyright (c) Microsoft Corporation. | ||
Permission to use, copy, modify, and/or distribute this software for any | ||
purpose with or without fee is hereby granted. | ||
Permission to use, copy, modify, and/or distribute this software for any | ||
purpose with or without fee is hereby granted. | ||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH | ||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | ||
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, | ||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM | ||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR | ||
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR | ||
PERFORMANCE OF THIS SOFTWARE. | ||
***************************************************************************** */function s(e,n,t,s){return new(t||(t=Promise))((function(i,o){function r(e){try{c(s.next(e))}catch(e){o(e)}}function a(e){try{c(s.throw(e))}catch(e){o(e)}}function c(e){var n;e.done?i(e.value):(n=e.value,n instanceof t?n:new t((function(e){e(n)}))).then(r,a)}c((s=s.apply(e,n||[])).next())}))}function i(e){return new Promise((n=>setTimeout(n,e)))}var o,r,a;!function(e){e.Error="Runner.Error"}(o||(o={})),function(e){e.Start="RunningEnvironment.Start",e.StartAck="RunningEnvironment.StartAck",e.Eval="RunningEnvironment.Eval",e.FSEventCreate="RunningEnvironment.FSEventCreate",e.FSEventRemove="RunningEnvironment.FSEventRemove",e.FSEventWrite="RunningEnvironment.FSEventWrite",e.CreateDir="RunningEnvironment.CreateDir",e.ListDir="RunningEnvironment.ListDir",e.WriteFile="RunningEnvironment.WriteFile",e.GetFile="RunningEnvironment.GetFile",e.RemoveFile="RunningEnvironment.RemoveFile",e.DirContent="RunningEnvironment.DirContent",e.FileContent="RunningEnvironment.FileContent",e.Stdout="RunningEnvironment.Stdout",e.Stderr="RunningEnvironment.Stderr",e.ExecCmd="RunningEnvironment.ExecCmd",e.KillCmd="RunningEnvironment.KillCmd",e.ListRunningCmds="RunningEnvironment.ListRunningCmds",e.CmdOut="RunningEnvironment.CmdOut",e.CmdExit="RunningEnvironment.CmdExit",e.RunningCmds="RunningEnvironment.RunningCmds",e.RunCode="RunningEnvironment.Run"}(r||(r={})),function(e){e.Error="CodeCell.Error"}(a||(a={}));const c={Runner:o,RunningEnvironment:r,CodeCell:a},l="orchestrator.usedevbook.com",h="dbk_sdk_session_id",u=3e3;var d;e.Env=void 0,(d=e.Env||(e.Env={})).NodeJS="nodejs-v16",d.Supabase="supabase";const g={"nodejs-v16":{id:"nodejs-v16",fileExtension:".js",image:"us-central1-docker.pkg.dev/devbookhq/devbook-runner-templates/nodejs-v16:latest",root_dir:"/home/runner",code_cells_dir:"/home/runner/src",toCommand:e=>`node "${e}"`},supabase:{id:"supabase",fileExtension:".js",image:"us-central1-docker.pkg.dev/devbookhq/devbook-runner-templates/supabase",root_dir:"/home/runner",code_cells_dir:"/home/runner/src",toCommand:e=>`node "${e}"`}};class v{constructor(){this.url=`wss://${l}`,this.logger=new t("WebSocketConnection"),this.handlers=[]}get state(){var e;return null===(e=this.client)||void 0===e?void 0:e.readyState}get isClosed(){if(void 0!==this.client)return this.client.readyState===this.client.CLOSED}get isClosing(){if(void 0!==this.client)return this.client.readyState===this.client.CLOSING}get isOpen(){if(void 0!==this.client)return this.client.readyState===this.client.OPEN}get isConnecting(){if(void 0!==this.client)return this.client.readyState===this.client.CONNECTING}subscribeHandler(e){return this.handlers.push(e),()=>{this.handlers=this.handlers.filter((n=>n!==e))}}connect(e){(!this.client||this.client.readyState!==this.client.CONNECTING&&this.client.readyState!==this.client.OPEN)&&(e||this.sessionID?(e?(this.logger.log(`Will try to connect to session "${e}"`),this.sessionID=e):!e&&this.sessionID&&this.logger.log(`Will try to connect to previous session "${this.sessionID}"`),this.client=new WebSocket(`${this.url}/session/ws/${this.sessionID}`),this.client.onopen=()=>this.handleOpen(),this.client.onmessage=e=>{this.logger.log("Received (raw)",{msg:e}),this.handleMessage(e)},this.client.onerror=e=>this.handleError(e),this.client.onclose=e=>this.handleClose(e)):this.logger.error("Cannot connect, no session ID passed to the function and no session ID saved from the previous session"))}send(e){this.client&&this.client.readyState===this.client.OPEN?(this.logger.log("Send",e),this._send(e)):this.logger.warn("Trying to send a message while not being in the `OPEN` state or without established connection, message will be discarded",e)}close(){var e;this.logger.log("Closing connection"),null===(e=this.client)||void 0===e||e.close(1e3)}handleOpen(){var e;this.logger.log("Connection opened",{readyState:null===(e=this.client)||void 0===e?void 0:e.readyState}),this.handlers.forEach((e=>e.onOpen()))}_send(e){var n,t;null===(n=this.client)||void 0===n||n.send((t=e,JSON.stringify(t,(()=>{const e=new WeakSet;return(n,t)=>{if("object"==typeof t&&null!==t){if(e.has(t))return;e.add(t)}return t}})(),2)))}handleClose(e){return s(this,void 0,void 0,(function*(){this.logger.log("Connection closed",e),this.handlers.forEach((e=>e.onClose())),this.logger.log("Will try to reconnect in 3s"),yield i(3e3),this.connect()}))}handleError(e){var n;this.logger.error("Connection error",e),null===(n=this.client)||void 0===n||n.close()}handleMessage(e){if(!e.data)return void this.logger.error("Message has empty data field",e);const n=JSON.parse(e.data);if(!n.type)return void this.logger.error("Message has no type",n);const t=n;Object.values(c.RunningEnvironment).includes(t.type)||Object.values(c.Runner).includes(t.type)||Object.values(c.CodeCell).includes(t.type)?t.type!==c.Runner.Error?(this.logger.log("Received (parsed)",t),this.handlers.forEach((e=>e.onMessage(t)))):this.logger.error("Runner error",t):this.logger.error('Message "type" field has unexpected value',t)}}var m,p;!function(e){e.Ok="Ok",e.Terminated="Terminated"}(m||(m={}));class f{constructor(e,n=new Date){this.id=e,this.lastPing=n,this.logger=new t("RunnerSession"),this.url=`https://${l}`}ping(){return s(this,void 0,void 0,(function*(){this.logger.log(`Pinging session "${this.id}"`);const e=JSON.stringify({sessionID:this.id});try{const n=yield fetch(`${this.url}/session/ping`,{method:"POST",headers:{"Content-Type":"application/json"},body:e}),t=yield n.json();if(!n.ok)throw this.logger.error(n.headers,t),new Error("Non-OK response when trying to ping active Runner session");if(t.status===m.Terminated)throw new Error(`[keepAlive]: Session '${this.id}' is terminated`);this.lastPing=new Date}catch(e){throw this.logger.error(e),new Error("Failed to ping active Runner session")}}))}}!function(e){e.Connected="Connected",e.Connecting="Connecting",e.Disconnected="Disconnected"}(p||(p={}));class D{constructor(e){this.conn=e,this.logger=new t("SessionManager"),this.url=`https://${l}`,this.isGettingSessionActive=!1,this.status=p.Disconnected,this.logger.log("Initialize"),this.getSession()}get cachedSessionID(){return sessionStorage.getItem(h)}set cachedSessionID(e){null===e?(this.logger.log("Cleared last sessionID"),sessionStorage.removeItem(h)):(this.logger.log(`Saved sessionID "${e}" as last sessionID`),sessionStorage.setItem(h,e))}reset(){this.logger.log("Reset"),this.status=p.Disconnected,this.cachedSessionID=null,this.conn.close(),this.session=void 0}getSession(){var e;return s(this,void 0,void 0,(function*(){if(!this.isGettingSessionActive)for(this.isGettingSessionActive=!0;;){this.status=p.Connecting;try{const n=this.cachedSessionID?`${this.url}/session/${this.cachedSessionID}`:`${this.url}/session`;this.cachedSessionID?this.logger.log(`Restoring old Runner session "${this.cachedSessionID}"`):this.logger.log("Acquiring new Runner session");const t=yield fetch(n),s=yield t.json();if(!t.ok){this.logger.error("Non-OK response when trying to ping active Runner session. Will try again in 3s",t.headers,s),yield i(u);continue}for(this.session=new f(s.sessionID),this.logger.log(`Acquired session "${this.session.id}"`),this.cachedSessionID=this.session.id,this.status=p.Connected,this.conn.connect(this.session.id),this.logger.log(`Started pinging session "${this.session.id}"`);this.session;)try{yield this.session.ping(),yield i(5e3)}catch(e){this.logger.error(`Failed to ping session "${this.session.id}"`,e);break}this.logger.log(`Stopped pinging session "${null===(e=this.session)||void 0===e?void 0:e.id}"`),this.session=void 0,this.status=p.Disconnected,this.conn.close()}catch(e){this.logger.error("Failed to acquire Runner session. Will try again in 3s",e),yield i(u)}}}))}}function C(e,n){for(var t=0,s=e.length-1;s>=0;s--){var i=e[s];"."===i?e.splice(s,1):".."===i?(e.splice(s,1),t++):t&&(e.splice(s,1),t--)}if(n)for(;t--;t)e.unshift("..");return e}var S=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/,b=function(e){return S.exec(e).slice(1)};function E(){for(var e="",n=!1,t=arguments.length-1;t>=-1&&!n;t--){var s=t>=0?arguments[t]:"/";if("string"!=typeof s)throw new TypeError("Arguments to path.resolve must be strings");s&&(e=s+"/"+e,n="/"===s.charAt(0))}return(n?"/":"")+(e=C(x(e.split("/"),(function(e){return!!e})),!n).join("/"))||"."}function y(e){var n=I(e),t="/"===k(e,-1);return(e=C(x(e.split("/"),(function(e){return!!e})),!n).join("/"))||n||(e="."),e&&t&&(e+="/"),(n?"/":"")+e}function I(e){return"/"===e.charAt(0)}var R={extname:function(e){return b(e)[3]},basename:function(e,n){var t=b(e)[2];return n&&t.substr(-1*n.length)===n&&(t=t.substr(0,t.length-n.length)),t},dirname:function(e){var n=b(e),t=n[0],s=n[1];return t||s?(s&&(s=s.substr(0,s.length-1)),t+s):"."},sep:"/",delimiter:":",relative:function(e,n){function t(e){for(var n=0;n<e.length&&""===e[n];n++);for(var t=e.length-1;t>=0&&""===e[t];t--);return n>t?[]:e.slice(n,t-n+1)}e=E(e).substr(1),n=E(n).substr(1);for(var s=t(e.split("/")),i=t(n.split("/")),o=Math.min(s.length,i.length),r=o,a=0;a<o;a++)if(s[a]!==i[a]){r=a;break}var c=[];for(a=r;a<s.length;a++)c.push("..");return(c=c.concat(i.slice(r))).join("/")},join:function(){var e=Array.prototype.slice.call(arguments,0);return y(x(e,(function(e,n){if("string"!=typeof e)throw new TypeError("Arguments to path.join must be strings");return e})).join("/"))},isAbsolute:I,normalize:y,resolve:E};function x(e,n){if(e.filter)return e.filter(n);for(var t=[],s=0;s<e.length;s++)n(e[s],s,e)&&t.push(e[s]);return t}var k="b"==="ab".substr(-1)?function(e,n,t){return e.substr(n,t)}:function(e,n,t){return n<0&&(n=e.length+n),e.substr(n,t)};function w(e){return function(e){const n=Array.from(e).reduce(((e,n)=>0|31*e+n.charCodeAt(0)),0);return("0000000"+(n>>>0).toString(16)).slice(-8)}(e)}class _{constructor(e,n){this.contextID=e,this.templateID=n,this.isReady=!1,this.id=`${e}_${w(n)}`,this.template=g[this.templateID]}}function O(e,{environmentID:n,template:t}){const s={type:c.RunningEnvironment.Start,payload:{environmentID:n,template:t}};e.send(s)}function j(e,{environmentID:n,executionID:t,command:s}){const i={type:c.RunningEnvironment.ExecCmd,payload:{environmentID:n,executionID:t,command:s}};e.send(i)}class ${constructor(e){this.opts=e,this.fsWriteSubscribers=[],this.envs=[],this.logger=new t("EvaluationContext",e.debug),this.unsubscribeConnHandler=this.opts.conn.subscribeHandler({onOpen:this.handleConnectionOpen.bind(this),onMessage:this.handleConnectionMessage.bind(this),onClose:this.handleConnectionClose.bind(this)}),this.opts.conn.isOpen&&this.handleConnectionOpen(),this.opts.conn.isClosed&&this.handleConnectionClose()}get contextID(){return this.opts.contextID}restart(){return this.logger.log("Restart",this.opts.conn.sessionID),this.envs.forEach((e=>{e.isReady=!1,O(this.opts.conn,{environmentID:e.id,template:e.template})}))}destroy(){this.logger.log("Destroy"),this.unsubscribeConnHandler(),this.envs=[],this.fsWriteSubscribers=[]}executeCode({templateID:e,executionID:n,code:t}){return s(this,void 0,void 0,(function*(){this.logger.log("Execute code",{templateID:e,executionID:n});const s=this.envs.find((n=>n.templateID===e));if(!s)return void this.logger.error("Environment not found",{templateID:e,executionID:n});if(!s.isReady)return void this.logger.error("Environment is not ready",{templateID:e,executionID:n});const i=g[e].fileExtension,o=`${n}${i}`,r=R.join("/src",o);!function(e,{environmentID:n,path:t,content:s}){const i={type:c.RunningEnvironment.WriteFile,payload:{environmentID:n,path:t,content:s}};e.send(i)}(this.opts.conn,{environmentID:s.id,path:r,content:t});const a=R.join(g[e].root_dir,r),l=g[e].toCommand(a);j(this.opts.conn,{environmentID:s.id,executionID:n,command:l})}))}executeCommand({templateID:e,executionID:n,command:t}){this.logger.log("Execute shell command",{templateID:e,executionID:n,command:t});const s=this.envs.find((n=>n.templateID===e));s?s.isReady?j(this.opts.conn,{environmentID:s.id,executionID:n,command:t}):this.logger.error("Environment is not ready",{templateID:e,executionID:n,command:t}):this.logger.error("Environment not found",{templateID:e,executionID:n,command:t})}createRunningEnvironment({templateID:e}){var n,t;this.logger.log("Creating running environment",{templateID:e});if(this.envs.find((n=>n.templateID===e)))return;const s=new _(this.contextID,e);this.envs.push(s),O(this.opts.conn,{environmentID:s.id,template:s.template}),null===(t=(n=this.opts).onEnvChange)||void 0===t||t.call(n,s)}subscribeFSWrite(e){console.log("len",this.fsWriteSubscribers.length),this.fsWriteSubscribers.push(e)}unsubscribeFSWrite(e){console.log("len",this.fsWriteSubscribers.length);const n=this.fsWriteSubscribers.indexOf(e);n>-1&&this.fsWriteSubscribers.splice(n,1)}handleConnectionOpen(){var e,n;this.restart(),null===(n=(e=this.opts).onSessionChange)||void 0===n||n.call(e,{status:p.Connected})}handleConnectionClose(){var e,n;null===(n=(e=this.opts).onSessionChange)||void 0===n||n.call(e,{status:p.Connecting})}handleConnectionMessage(e){switch(this.logger.log("Handling message from remote Runner",{message:e}),e.type){case c.RunningEnvironment.StartAck:{const n=e;this.vmenv_handleStartAck(n.payload);break}case c.RunningEnvironment.CmdOut:{const n=e;this.vmenv_handleCmdOut(n.payload);break}case c.RunningEnvironment.CmdExit:{const n=e;this.vmenv_handleCmdExit(n.payload);break}case c.RunningEnvironment.FSEventWrite:{const n=e;this.vmenv_handleFSEventWrite(n.payload);break}default:this.logger.warn("Unknown message type",{message:e})}}vmenv_handleCmdExit(e){var n,t;void 0!==e.error&&(null===(t=(n=this.opts).onCmdOut)||void 0===t||t.call(n,{environmentID:e.environmentID,executionID:e.executionID,stderr:e.error}))}vmenv_handleFSEventWrite(e){this.logger.log('[vmenv] Handling "FSEventWrite"',e);this.envs.find((n=>n.id===e.environmentID))?this.fsWriteSubscribers.forEach((n=>n(e))):this.logger.warn("Environment not found",{payload:e})}vmenv_handleStartAck(e){var n,t;this.logger.log('[vmenv] Handling "StartAck"',{payload:e});const s=this.envs.find((n=>n.id===e.environmentID));s?(s.isReady=!0,null===(t=(n=this.opts).onEnvChange)||void 0===t||t.call(n,s)):this.logger.warn("Environment not found",{payload:e})}vmenv_handleCmdOut(e){var n,t;this.logger.log('[vmenv] Handling "CmdOut"',e),null===(t=(n=this.opts).onCmdOut)||void 0===t||t.call(n,e)}}class W{constructor(){this.logger=new t("Runner"),this.conn=new v,this.sessManager=new D(this.conn)}static get obj(){return W._obj||(W._obj=new W)}get session(){return this.sessManager.session}get status(){return this.sessManager.status}reset(){this.logger.log("Reset"),this.sessManager.reset()}createContext(e){return new $(Object.assign(Object.assign({},e),{conn:this.conn}))}__debug__loadNewSession(){this.logger.log("__debug__loadNewSession"),this.sessManager.reset()}}const F=(A="1234567890abcdefghijklmnopqrstuvwxyz",N=6,()=>{let e="",n=N;for(;n--;)e+=A[Math.random()*A.length|0];return e});var A,N,M;e.DevbookStatus=void 0,(M=e.DevbookStatus||(e.DevbookStatus={}))[M.Disconnected=0]="Disconnected",M[M.Connecting=1]="Connecting",M[M.Connected=2]="Connected";class T{constructor(n){this.opts=n,this._isDestroyed=!1,this._isEnvReady=!1,this._sessionStatus=p.Disconnected,this._status=e.DevbookStatus.Disconnected;const t="default";this.contextID=t,this.executionID=F();const s=()=>this.executionID,i=e=>this.isEnvReady=e,o=e=>this.sessionStatus=e;this.context=W.obj.createContext({debug:n.debug,contextID:t,onEnvChange(e){i(e.isReady)},onSessionChange({status:e}){o(e)},onCmdOut(e){var t,i;e.executionID===s()&&(void 0!==e.stdout&&(null===(t=n.onStdout)||void 0===t||t.call(n,e.stdout)),void 0!==e.stderr&&(null===(i=n.onStderr)||void 0===i||i.call(n,e.stderr)))}}),this.context.createRunningEnvironment({templateID:n.env})}get isDestroyed(){return this._isDestroyed}set isDestroyed(e){this._isDestroyed=e,this.updateStatus()}get isEnvReady(){return this._isEnvReady}set isEnvReady(e){this._isEnvReady=e,this.updateStatus()}get sessionStatus(){return this._sessionStatus}set sessionStatus(e){this._sessionStatus=e,this.updateStatus()}get status(){return this._status}set status(e){var n,t;this._status=e,null===(t=(n=this.opts).onStatusChange)||void 0===t||t.call(n,e)}runCmd(n){this.status!==e.DevbookStatus.Disconnected&&(this.executionID=F(),this.context.executeCommand({templateID:this.opts.env,executionID:this.executionID,command:n}))}runCode(n){this.status!==e.DevbookStatus.Disconnected&&(this.executionID=F(),this.context.executeCode({templateID:this.opts.env,executionID:this.executionID,code:n}))}destroy(){this.context.destroy(),this.isDestroyed=!0}updateStatus(){if(this.isDestroyed)return void(this.status!==e.DevbookStatus.Disconnected&&(this.status=e.DevbookStatus.Disconnected));let n;switch(this.sessionStatus){case p.Disconnected:n=e.DevbookStatus.Disconnected;break;case p.Connecting:n=e.DevbookStatus.Connecting;break;case p.Connected:if(!this.isEnvReady){n=e.DevbookStatus.Connecting;break}n=e.DevbookStatus.Connected}this.status=n}}e.Devbook=T,e.useDevbook=function({env:t,debug:s}){const[i,o]=n.useState(),[r,a]=n.useState(e.DevbookStatus.Disconnected),[c,l]=n.useState([]),[h,u]=n.useState([]),d=n.useCallback((e=>{i&&(u([]),l([]),i.runCmd(e))}),[i]),g=n.useCallback((e=>{i&&(u([]),l([]),i.runCode(e))}),[i]);return n.useEffect((function(){const e=new T({debug:s,env:t,onStatusChange(e){a(e)},onStderr(e){l((n=>[...n,e]))},onStdout(e){u((n=>[...n,e]))}});return u([]),l([]),o(e),()=>{e.destroy()}}),[t,s]),{stderr:c,stdout:h,runCmd:d,runCode:g,status:r}},Object.defineProperty(e,"__esModule",{value:!0})})); | ||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH | ||
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY | ||
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, | ||
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM | ||
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR | ||
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR | ||
PERFORMANCE OF THIS SOFTWARE. | ||
***************************************************************************** */function n(e,t,n,s){return new(n||(n=Promise))((function(i,o){function r(e){try{l(s.next(e))}catch(e){o(e)}}function a(e){try{l(s.throw(e))}catch(e){o(e)}}function l(e){var t;e.done?i(e.value):(t=e.value,t instanceof n?t:new n((function(e){e(t)}))).then(r,a)}l((s=s.apply(e,t||[])).next())}))}class s{constructor(e,t=!1){this.logID=e,this.isEnabled=t}id(){return"function"==typeof this.logID?this.logID():this.logID}log(...e){this.isEnabled&&console.log(`[36m[${this.id()}][0m`,...e)}warn(...e){this.isEnabled&&console.warn(`[36m[${this.id()}][0m`,...e)}error(...e){console.error(`[31m[${this.id()} ERROR][0m`,...e)}}function i(e){return new Promise((t=>setTimeout(t,e)))}var o,r,a;!function(e){e.Error="Runner.Error"}(o||(o={})),function(e){e.Start="RunningEnvironment.Start",e.StartAck="RunningEnvironment.StartAck",e.Eval="RunningEnvironment.Eval",e.FSEventCreate="RunningEnvironment.FSEventCreate",e.FSEventRemove="RunningEnvironment.FSEventRemove",e.FSEventWrite="RunningEnvironment.FSEventWrite",e.CreateDir="RunningEnvironment.CreateDir",e.ListDir="RunningEnvironment.ListDir",e.WriteFile="RunningEnvironment.WriteFile",e.GetFile="RunningEnvironment.GetFile",e.RemoveFile="RunningEnvironment.RemoveFile",e.DirContent="RunningEnvironment.DirContent",e.FileContent="RunningEnvironment.FileContent",e.Stdout="RunningEnvironment.Stdout",e.Stderr="RunningEnvironment.Stderr",e.ExecCmd="RunningEnvironment.ExecCmd",e.KillCmd="RunningEnvironment.KillCmd",e.ListRunningCmds="RunningEnvironment.ListRunningCmds",e.CmdOut="RunningEnvironment.CmdOut",e.CmdExit="RunningEnvironment.CmdExit",e.RunningCmds="RunningEnvironment.RunningCmds",e.RunCode="RunningEnvironment.Run"}(r||(r={})),function(e){e.Error="CodeCell.Error"}(a||(a={}));const l={Runner:o,RunningEnvironment:r,CodeCell:a},c="orchestrator.usedevbook.com",h="dbk_sdk_session_id",d=3e3;var u;e.Env=void 0,(u=e.Env||(e.Env={})).NodeJS="nodejs-v16",u.Supabase="supabase";const g={"nodejs-v16":{id:"nodejs-v16",fileExtension:".js",image:"us-central1-docker.pkg.dev/devbookhq/devbook-runner-templates/nodejs-v16:latest",root_dir:"/home/runner",code_cells_dir:"/home/runner/src",toCommand:e=>`node "${e}"`},supabase:{id:"supabase",fileExtension:".js",image:"us-central1-docker.pkg.dev/devbookhq/devbook-runner-templates/supabase",root_dir:"/home/runner",code_cells_dir:"/home/runner/src",toCommand:e=>`node "${e}"`}};class v{constructor(){this.url=`wss://${c}`,this.logger=new s("WebSocketConnection"),this.handlers=[]}get state(){var e;return null===(e=this.client)||void 0===e?void 0:e.readyState}get isClosed(){if(void 0!==this.client)return this.client.readyState===this.client.CLOSED}get isClosing(){if(void 0!==this.client)return this.client.readyState===this.client.CLOSING}get isOpen(){if(void 0!==this.client)return this.client.readyState===this.client.OPEN}get isConnecting(){if(void 0!==this.client)return this.client.readyState===this.client.CONNECTING}subscribeHandler(e){return this.handlers.push(e),()=>{this.handlers=this.handlers.filter((t=>t!==e))}}connect(e){(!this.client||this.client.readyState!==this.client.CONNECTING&&this.client.readyState!==this.client.OPEN)&&(e||this.sessionID?(e?(this.logger.log(`Will try to connect to session "${e}"`),this.sessionID=e):!e&&this.sessionID&&this.logger.log(`Will try to connect to previous session "${this.sessionID}"`),this.client=new WebSocket(`${this.url}/session/ws/${this.sessionID}`),this.client.onopen=()=>this.handleOpen(),this.client.onmessage=e=>{this.logger.log("Received (raw)",{msg:e}),this.handleMessage(e)},this.client.onerror=e=>this.handleError(e),this.client.onclose=e=>this.handleClose(e)):this.logger.error("Cannot connect, no session ID passed to the function and no session ID saved from the previous session"))}send(e){this.client&&this.client.readyState===this.client.OPEN?(this.logger.log("Send",e),this._send(e)):this.logger.warn("Trying to send a message while not being in the `OPEN` state or without established connection, message will be discarded",e)}close(){var e;this.logger.log("Closing connection"),null===(e=this.client)||void 0===e||e.close(1e3)}handleOpen(){var e;this.logger.log("Connection opened",{readyState:null===(e=this.client)||void 0===e?void 0:e.readyState}),this.handlers.forEach((e=>e.onOpen()))}_send(e){var t,n;null===(t=this.client)||void 0===t||t.send((n=e,JSON.stringify(n,(()=>{const e=new WeakSet;return(t,n)=>{if("object"==typeof n&&null!==n){if(e.has(n))return;e.add(n)}return n}})(),2)))}handleClose(e){return n(this,void 0,void 0,(function*(){this.logger.log("Connection closed",e),this.handlers.forEach((e=>e.onClose())),this.logger.log("Will try to reconnect in 3s"),yield i(3e3),this.connect()}))}handleError(e){var t;this.logger.error("Connection error",e),null===(t=this.client)||void 0===t||t.close()}handleMessage(e){if(!e.data)return void this.logger.error("Message has empty data field",e);const t=JSON.parse(e.data);if(!t.type)return void this.logger.error("Message has no type",t);const n=t;Object.values(l.RunningEnvironment).includes(n.type)||Object.values(l.Runner).includes(n.type)||Object.values(l.CodeCell).includes(n.type)?n.type!==l.Runner.Error?(this.logger.log("Received (parsed)",n),this.handlers.forEach((e=>e.onMessage(n)))):this.logger.error("Runner error",n):this.logger.error('Message "type" field has unexpected value',n)}}var m,p;!function(e){e.Ok="Ok",e.Terminated="Terminated"}(m||(m={}));class f{constructor(e,t=new Date){this.id=e,this.lastPing=t,this.logger=new s("RunnerSession"),this.url=`https://${c}`}ping(){return n(this,void 0,void 0,(function*(){this.logger.log(`Pinging session "${this.id}"`);const e=JSON.stringify({sessionID:this.id});try{const t=yield fetch(`${this.url}/session/ping`,{method:"POST",headers:{"Content-Type":"application/json"},body:e}),n=yield t.json();if(!t.ok)throw this.logger.error(t.headers,n),new Error("Non-OK response when trying to ping active Runner session");if(n.status===m.Terminated)throw new Error(`[keepAlive]: Session '${this.id}' is terminated`);this.lastPing=new Date}catch(e){throw this.logger.error(e),new Error("Failed to ping active Runner session")}}))}}!function(e){e.Connected="Connected",e.Connecting="Connecting",e.Disconnected="Disconnected"}(p||(p={}));class D{constructor(e){this.conn=e,this.logger=new s("SessionManager"),this.url=`https://${c}`,this.isGettingSessionActive=!1,this.status=p.Disconnected,this.logger.log("Initialize"),this.getSession()}get cachedSessionID(){return sessionStorage.getItem(h)}set cachedSessionID(e){null===e?(this.logger.log("Cleared last sessionID"),sessionStorage.removeItem(h)):(this.logger.log(`Saved sessionID "${e}" as last sessionID`),sessionStorage.setItem(h,e))}reset(){this.logger.log("Reset"),this.status=p.Disconnected,this.cachedSessionID=null,this.conn.close(),this.session=void 0}getSession(){var e;return n(this,void 0,void 0,(function*(){if(!this.isGettingSessionActive)for(this.isGettingSessionActive=!0;;){this.status=p.Connecting;try{const t=this.cachedSessionID?`${this.url}/session/${this.cachedSessionID}`:`${this.url}/session`;this.cachedSessionID?this.logger.log(`Restoring old Runner session "${this.cachedSessionID}"`):this.logger.log("Acquiring new Runner session");const n=yield fetch(t),s=yield n.json();if(!n.ok){this.logger.error("Non-OK response when trying to ping active Runner session. Will try again in 3s",n.headers,s),yield i(d);continue}for(this.session=new f(s.sessionID),this.logger.log(`Acquired session "${this.session.id}"`),this.cachedSessionID=this.session.id,this.status=p.Connected,this.conn.connect(this.session.id),this.logger.log(`Started pinging session "${this.session.id}"`);this.session;)try{yield this.session.ping(),yield i(5e3)}catch(e){this.logger.error(`Failed to ping session "${this.session.id}"`,e);break}this.logger.log(`Stopped pinging session "${null===(e=this.session)||void 0===e?void 0:e.id}"`),this.session=void 0,this.status=p.Disconnected,this.conn.close()}catch(e){this.logger.error("Failed to acquire Runner session. Will try again in 3s",e),yield i(d)}}}))}}function b(e,t){for(var n=0,s=e.length-1;s>=0;s--){var i=e[s];"."===i?e.splice(s,1):".."===i?(e.splice(s,1),n++):n&&(e.splice(s,1),n--)}if(t)for(;n--;n)e.unshift("..");return e}var C=/^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/,S=function(e){return C.exec(e).slice(1)};function E(){for(var e="",t=!1,n=arguments.length-1;n>=-1&&!t;n--){var s=n>=0?arguments[n]:"/";if("string"!=typeof s)throw new TypeError("Arguments to path.resolve must be strings");s&&(e=s+"/"+e,t="/"===s.charAt(0))}return(t?"/":"")+(e=b(w(e.split("/"),(function(e){return!!e})),!t).join("/"))||"."}function y(e){var t=I(e),n="/"===x(e,-1);return(e=b(w(e.split("/"),(function(e){return!!e})),!t).join("/"))||t||(e="."),e&&n&&(e+="/"),(t?"/":"")+e}function I(e){return"/"===e.charAt(0)}var R={extname:function(e){return S(e)[3]},basename:function(e,t){var n=S(e)[2];return t&&n.substr(-1*t.length)===t&&(n=n.substr(0,n.length-t.length)),n},dirname:function(e){var t=S(e),n=t[0],s=t[1];return n||s?(s&&(s=s.substr(0,s.length-1)),n+s):"."},sep:"/",delimiter:":",relative:function(e,t){function n(e){for(var t=0;t<e.length&&""===e[t];t++);for(var n=e.length-1;n>=0&&""===e[n];n--);return t>n?[]:e.slice(t,n-t+1)}e=E(e).substr(1),t=E(t).substr(1);for(var s=n(e.split("/")),i=n(t.split("/")),o=Math.min(s.length,i.length),r=o,a=0;a<o;a++)if(s[a]!==i[a]){r=a;break}var l=[];for(a=r;a<s.length;a++)l.push("..");return(l=l.concat(i.slice(r))).join("/")},join:function(){var e=Array.prototype.slice.call(arguments,0);return y(w(e,(function(e,t){if("string"!=typeof e)throw new TypeError("Arguments to path.join must be strings");return e})).join("/"))},isAbsolute:I,normalize:y,resolve:E};function w(e,t){if(e.filter)return e.filter(t);for(var n=[],s=0;s<e.length;s++)t(e[s],s,e)&&n.push(e[s]);return n}var x="b"==="ab".substr(-1)?function(e,t,n){return e.substr(t,n)}:function(e,t,n){return t<0&&(t=e.length+t),e.substr(t,n)};function k(e){return function(e){const t=Array.from(e).reduce(((e,t)=>0|31*e+t.charCodeAt(0)),0);return("0000000"+(t>>>0).toString(16)).slice(-8)}(e)}class _{constructor(e,t){this.contextID=e,this.templateID=t,this.isReady=!1,this.id=`${e}_${k(t)}`,this.template=g[this.templateID]}}function F(e,{environmentID:t,template:n}){const s={type:l.RunningEnvironment.Start,payload:{environmentID:t,template:n}};e.send(s)}function O(e,{environmentID:t,executionID:n,command:s}){const i={type:l.RunningEnvironment.ExecCmd,payload:{environmentID:t,executionID:n,command:s}};e.send(i)}function $(e,{environmentID:t,path:n,content:s}){const i={type:l.RunningEnvironment.WriteFile,payload:{environmentID:t,path:n,content:s}};e.send(i)}class j{constructor(e){this.opts=e,this.fsWriteSubscribers=[],this.fileContentSubscribers=[],this.envs=[],this.logger=new s("EvaluationContext",e.debug),this.unsubscribeConnHandler=this.opts.conn.subscribeHandler({onOpen:this.handleConnectionOpen.bind(this),onMessage:this.handleConnectionMessage.bind(this),onClose:this.handleConnectionClose.bind(this)}),this.opts.conn.isOpen&&this.handleConnectionOpen(),this.opts.conn.isClosed&&this.handleConnectionClose()}get contextID(){return this.opts.contextID}restart(){return this.logger.log("Restart",this.opts.conn.sessionID),this.envs.forEach((e=>{e.isReady=!1,F(this.opts.conn,{environmentID:e.id,template:e.template})}))}destroy(){this.logger.log("Destroy"),this.unsubscribeConnHandler(),this.envs=[],this.fsWriteSubscribers=[]}getFile({templateID:e,path:t}){return n(this,void 0,void 0,(function*(){this.logger.log("Get file",{templateID:e,path:R});const n=this.envs.find((t=>t.templateID===e));if(!n)return void this.logger.error("Environment not found",{templateID:e,path:R});if(!n.isReady)return void this.logger.error("Environment is not ready",{templateID:e,path:R});let s;const i=new Promise(((e,t)=>{s=e,setTimeout((()=>{t("Timeout")}),1e4)})),o=e=>{e.path.endsWith(t)&&s(e.content)};this.subscribeFileContent(o),function(e,{environmentID:t,path:n}){const s={type:l.RunningEnvironment.GetFile,payload:{environmentID:t,path:n}};e.send(s)}(this.opts.conn,{path:t,environmentID:n.id});try{return yield i}catch(e){throw new Error(`Error retriving file ${t}: ${e.message}`)}finally{this.unsubscribeFileContent(o)}}))}updateFile({templateID:e,path:t,content:s}){return n(this,void 0,void 0,(function*(){this.logger.log("Update file",{templateID:e,filepath:t});const n=this.envs.find((t=>t.templateID===e));if(!n)return void this.logger.error("Environment not found",{templateID:e,filepath:t});if(!n.isReady)return void this.logger.error("Environment is not ready",{templateID:e,filepath:t});let i;const o=new Promise(((e,t)=>{i=e,setTimeout((()=>{t("Timeout")}),1e4)})),r=e=>{e.path.endsWith(t)&&i()};this.subscribeFSWrite(r),$(this.opts.conn,{environmentID:n.id,path:t,content:s});try{yield o}catch(e){throw new Error(`File ${t} not written to VM: ${e.message}`)}finally{this.unsubscribeFSWrite(r)}}))}executeCode({templateID:e,executionID:t,code:s}){return n(this,void 0,void 0,(function*(){this.logger.log("Execute code",{templateID:e,executionID:t});const n=this.envs.find((t=>t.templateID===e));if(!n)return void this.logger.error("Environment not found",{templateID:e,executionID:t});if(!n.isReady)return void this.logger.error("Environment is not ready",{templateID:e,executionID:t});const i=g[e].fileExtension,o=`${t}${i}`,r=R.join("/src",o);$(this.opts.conn,{environmentID:n.id,path:r,content:s});const a=R.join(g[e].root_dir,r),l=g[e].toCommand(a);O(this.opts.conn,{environmentID:n.id,executionID:t,command:l})}))}executeCommand({templateID:e,executionID:t,command:n}){this.logger.log("Execute shell command",{templateID:e,executionID:t,command:n});const s=this.envs.find((t=>t.templateID===e));s?s.isReady?O(this.opts.conn,{environmentID:s.id,executionID:t,command:n}):this.logger.error("Environment is not ready",{templateID:e,executionID:t,command:n}):this.logger.error("Environment not found",{templateID:e,executionID:t,command:n})}createRunningEnvironment({templateID:e}){var t,n;this.logger.log("Creating running environment",{templateID:e});if(this.envs.find((t=>t.templateID===e)))return;const s=new _(this.contextID,e);this.envs.push(s),F(this.opts.conn,{environmentID:s.id,template:s.template}),null===(n=(t=this.opts).onEnvChange)||void 0===n||n.call(t,s)}subscribeFileContent(e){this.fileContentSubscribers.push(e)}unsubscribeFileContent(e){const t=this.fileContentSubscribers.indexOf(e);t>-1&&this.fileContentSubscribers.splice(t,1)}subscribeFSWrite(e){this.fsWriteSubscribers.push(e)}unsubscribeFSWrite(e){const t=this.fsWriteSubscribers.indexOf(e);t>-1&&this.fsWriteSubscribers.splice(t,1)}handleConnectionOpen(){var e,t;this.restart(),null===(t=(e=this.opts).onSessionChange)||void 0===t||t.call(e,{status:p.Connected})}handleConnectionClose(){var e,t;null===(t=(e=this.opts).onSessionChange)||void 0===t||t.call(e,{status:p.Connecting})}handleConnectionMessage(e){switch(this.logger.log("Handling message from remote Runner",{message:e}),e.type){case l.RunningEnvironment.StartAck:{const t=e;this.vmenv_handleStartAck(t.payload);break}case l.RunningEnvironment.CmdOut:{const t=e;this.vmenv_handleCmdOut(t.payload);break}case l.RunningEnvironment.CmdExit:{const t=e;this.vmenv_handleCmdExit(t.payload);break}case l.RunningEnvironment.FSEventWrite:{const t=e;this.vmenv_handleFSEventWrite(t.payload);break}case l.RunningEnvironment.FileContent:{const t=e;this.vmenv_handleFileContent(t.payload);break}default:this.logger.warn("Unknown message type",{message:e})}}vmenv_handleCmdExit(e){var t,n;void 0!==e.error&&(null===(n=(t=this.opts).onCmdOut)||void 0===n||n.call(t,{environmentID:e.environmentID,executionID:e.executionID,stderr:e.error}))}vmenv_handleFSEventWrite(e){this.logger.log('[vmenv] Handling "FSEventWrite"',e);this.envs.find((t=>t.id===e.environmentID))?this.fsWriteSubscribers.forEach((t=>t(e))):this.logger.warn("Environment not found",{payload:e})}vmenv_handleFileContent(e){this.logger.log('[vmenv] Handling "FileContent"',{environmentID:e.environmentID,path:e.path});this.envs.find((t=>t.id===e.environmentID))?this.fileContentSubscribers.forEach((t=>t(e))):this.logger.warn("Environment not found",{payload:e})}vmenv_handleStartAck(e){var t,n;this.logger.log('[vmenv] Handling "StartAck"',{payload:e});const s=this.envs.find((t=>t.id===e.environmentID));s?(s.isReady=!0,null===(n=(t=this.opts).onEnvChange)||void 0===n||n.call(t,s)):this.logger.warn("Environment not found",{payload:e})}vmenv_handleCmdOut(e){var t,n;this.logger.log('[vmenv] Handling "CmdOut"',e),null===(n=(t=this.opts).onCmdOut)||void 0===n||n.call(t,e)}}class W{constructor(){this.logger=new s("Runner"),this.conn=new v,this.sessManager=new D(this.conn)}static get obj(){return W._obj||(W._obj=new W)}get session(){return this.sessManager.session}get status(){return this.sessManager.status}reset(){this.logger.log("Reset"),this.sessManager.reset()}createContext(e){return new j(Object.assign(Object.assign({},e),{conn:this.conn}))}__debug__loadNewSession(){this.logger.log("__debug__loadNewSession"),this.sessManager.reset()}}const M=(N="1234567890abcdefghijklmnopqrstuvwxyz",A=6,()=>{let e="",t=A;for(;t--;)e+=N[Math.random()*N.length|0];return e});var N,A,T;e.DevbookStatus=void 0,(T=e.DevbookStatus||(e.DevbookStatus={}))[T.Disconnected=0]="Disconnected",T[T.Connecting=1]="Connecting",T[T.Connected=2]="Connected";class P{constructor(t){this.opts=t,this._isDestroyed=!1,this._isEnvReady=!1,this._sessionStatus=p.Disconnected,this._status=e.DevbookStatus.Disconnected;const n="default";this.contextID=n,this.executionID=M();const s=()=>this.executionID,i=e=>this.isEnvReady=e,o=e=>this.sessionStatus=e;this.context=W.obj.createContext({debug:t.debug,contextID:n,onEnvChange(e){i(e.isReady)},onSessionChange({status:e}){o(e)},onCmdOut(e){var n,i;e.executionID===s()&&(void 0!==e.stdout&&(null===(n=t.onStdout)||void 0===n||n.call(t,e.stdout)),void 0!==e.stderr&&(null===(i=t.onStderr)||void 0===i||i.call(t,e.stderr)))}}),this.context.createRunningEnvironment({templateID:t.env})}get fs(){return{get:this.getFile.bind(this),write:this.writeFile.bind(this)}}get isDestroyed(){return this._isDestroyed}set isDestroyed(e){this._isDestroyed=e,this.updateStatus()}get isEnvReady(){return this._isEnvReady}set isEnvReady(e){this._isEnvReady=e,this.updateStatus()}get sessionStatus(){return this._sessionStatus}set sessionStatus(e){this._sessionStatus=e,this.updateStatus()}get status(){return this._status}set status(e){var t,n;this._status=e,null===(n=(t=this.opts).onStatusChange)||void 0===n||n.call(t,e)}getFile(t){return n(this,void 0,void 0,(function*(){if(this.status!==e.DevbookStatus.Connected)throw new Error("Not connected to the VM yet.");return this.context.getFile({templateID:this.opts.env,path:t})}))}writeFile(t,s){return n(this,void 0,void 0,(function*(){if(this.status!==e.DevbookStatus.Connected)throw new Error("Not connected to the VM yet.");return this.context.updateFile({templateID:this.opts.env,path:t,content:s})}))}runCmd(t){if(this.status!==e.DevbookStatus.Connected)throw new Error("Not connected to the VM yet.");this.executionID=M(),this.context.executeCommand({templateID:this.opts.env,executionID:this.executionID,command:t})}runCode(t){if(this.status!==e.DevbookStatus.Connected)throw new Error("Not connected to the VM yet.");this.executionID=M(),this.context.executeCode({templateID:this.opts.env,executionID:this.executionID,code:t})}destroy(){this.context.destroy(),this.isDestroyed=!0}updateStatus(){if(this.isDestroyed)return void(this.status!==e.DevbookStatus.Disconnected&&(this.status=e.DevbookStatus.Disconnected));let t;switch(this.sessionStatus){case p.Disconnected:t=e.DevbookStatus.Disconnected;break;case p.Connecting:t=e.DevbookStatus.Connecting;break;case p.Connected:if(!this.isEnvReady){t=e.DevbookStatus.Connecting;break}t=e.DevbookStatus.Connected}this.status=t}}e.Devbook=P,e.useDevbook=function({env:n,debug:s}){const[i,o]=t.useState(),[r,a]=t.useState(e.DevbookStatus.Disconnected),[l,c]=t.useState([]),[h,d]=t.useState([]),u=t.useCallback((e=>{i&&(d([]),c([]),i.runCmd(e))}),[i]),g=t.useCallback((e=>{i&&(d([]),c([]),i.runCode(e))}),[i]);return t.useEffect((function(){const e=new P({debug:s,env:n,onStatusChange(e){a(e)},onStderr(e){c((t=>[...t,e]))},onStdout(e){d((t=>[...t,e]))}});return d([]),c([]),o(e),()=>{e.destroy()}}),[n,s]),{stderr:l,stdout:h,runCmd:u,runCode:g,status:r,fs:null==i?void 0:i.fs}},Object.defineProperty(e,"__esModule",{value:!0})})); | ||
//# sourceMappingURL=index.js.map |
import { DevbookStatus, Env } from 'src/core'; | ||
import { FS } from 'src/core/devbook'; | ||
/** | ||
@@ -55,2 +56,3 @@ * Options passed to the {@link useDevbook} hook. | ||
runCmd: (command: string) => void; | ||
fs?: FS; | ||
} | ||
@@ -57,0 +59,0 @@ /** |
{ | ||
"name": "@devbookhq/sdk", | ||
"version": "1.0.3", | ||
"version": "1.0.4", | ||
"description": "Devbook allows visitors of your docs to interact with and execute any code snippet or shell command in a private VM", | ||
@@ -27,6 +27,6 @@ "homepage": "https://usedevbook.com", | ||
"@rollup/plugin-node-resolve": "^13.1.3", | ||
"@types/node": "^17.0.10", | ||
"@types/node": "^17.0.12", | ||
"@types/react": "^17.0.38", | ||
"@types/react-dom": "^17.0.11", | ||
"rollup": "^2.64.0", | ||
"rollup": "^2.66.1", | ||
"rollup-plugin-auto-external": "^2.0.0", | ||
@@ -36,3 +36,3 @@ "rollup-plugin-polyfill-node": "^0.8.0", | ||
"rollup-plugin-typescript2": "^0.31.1", | ||
"typescript": "^4.5.4" | ||
"typescript": "^4.5.5" | ||
}, | ||
@@ -39,0 +39,0 @@ "files": [ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
359269
3015