UNPKG

@devbookhq/sdk

Version:

SDK for managing Devbook sessions from JavaScript/TypeScript

3 lines (2 loc) 12.5 kB
!function(s,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("normalize-path"),require("rpc-websocket-client"),require("cross-fetch/polyfill"),require("openapi-typescript-fetch")):"function"==typeof define&&define.amd?define(["exports","normalize-path","rpc-websocket-client","cross-fetch/polyfill","openapi-typescript-fetch"],t):t((s="undefined"!=typeof globalThis?globalThis:s||self)["@devbookhq/sdk"]={},s.normalizePath,s.rpcWebsocketClient,null,s.openapiTypescriptFetch)}(this,(function(s,t,e,i,o){"use strict";function n(s){return s&&"object"==typeof s&&"default"in s?s:{default:s}}var r=n(t);function l(s,t,e,i){return new(e||(e=Promise))((function(o,n){function r(s){try{c(i.next(s))}catch(s){n(s)}}function l(s){try{c(i.throw(s))}catch(s){n(s)}}function c(s){var t;s.done?o(s.value):(t=s.value,t instanceof e?t:new e((function(s){s(t)}))).then(r,l)}c((i=i.apply(s,t||[])).next())}))}function c(s){let t="";const e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",i=e.length;for(let o=0;o<s;o++)t+=e.charAt(Math.floor(Math.random()*i));return t}function d(s){return"fulfilled"===s.status}function h(s){if(!s.every((s=>"fulfilled"===s.status)))return s.reduce(((s,t,e)=>"rejected"===t.status?s+"\n"+`[${e}]: `+`${JSON.stringify(t)}`:s),"errors:\n")}function a(){let s,t;return{promise:new Promise(((e,i)=>{s=e,t=i})),reject:t,resolve:s}}const u="codeSnippet";var p;s.CodeSnippetExecState=void 0,(p=s.CodeSnippetExecState||(s.CodeSnippetExecState={})).Running="Running",p.Stopped="Stopped";const v="filesystem";var f;s.FilesystemOperation=void 0,(f=s.FilesystemOperation||(s.FilesystemOperation={})).Create="Create",f.Write="Write",f.Remove="Remove",f.Rename="Rename",f.Chmod="Chmod";class g{constructor(s,t){this.sessConn=s,this.path=t,this.listeners=new Set}start(){return l(this,void 0,void 0,(function*(){this.rpcSubscriptionID||(this.handleFilesystemEvents=this.handleFilesystemEvents.bind(this),this.rpcSubscriptionID=yield this.sessConn.subscribe(v,this.handleFilesystemEvents,"watchDir",this.path))}))}stop(){return l(this,void 0,void 0,(function*(){this.listeners.clear(),this.rpcSubscriptionID&&(yield this.sessConn.unsubscribe(this.rpcSubscriptionID))}))}addEventListener(s){return this.listeners.add(s),()=>this.listeners.delete(s)}handleFilesystemEvents(s){this.listeners.forEach((t=>{t(s)}))}}const b="process",y=o.Fetcher.for();y.configure({baseUrl:"https://ondevbook.com"});class m{constructor(s,t=!1){this.logID=s,this.isEnabled=t}error(...s){console.error(`[${this.id()} ERROR]`,...s)}log(...s){this.isEnabled&&console.log(`[${this.id()}]`,...s)}id(){return"function"==typeof this.logID?this.logID():this.logID}}function S(s){return new Promise((t=>setTimeout(t,s)))}const w=y.path("/sessions").method("post").create({api_key:!0}),E=y.path("/sessions/{sessionID}/refresh").method("post").create({api_key:!0});class ${constructor(s){this.opts=s,this.isOpen=!1,this.rpc=new e.RpcWebSocketClient,this.subscribers=[],this.logger=new m("Session",s.debug),this.logger.log(`Session for code snippet "${s.id}" initialized`)}getHostname(s){if(this.opts.__debug_hostname)return s&&"remote"===this.opts.__debug_devEnv?`${s}-${this.opts.__debug_hostname}`:s?`${this.opts.__debug_hostname}:${s}`:this.opts.__debug_hostname;if(!this.session)return;const t=`${this.session.sessionID}-${this.session.clientID}.ondevbook.com`;return s?`${s}-${t}`:t}close(){var s,t,e,i,o,n;return l(this,void 0,void 0,(function*(){if(this.isOpen){this.logger.log("Closing",this.session),this.isOpen=!1,this.logger.log("Unsubscribing...");(yield Promise.allSettled(this.subscribers.map((s=>this.unsubscribe(s.subID))))).forEach((s=>{"rejected"===s.status&&this.logger.log(`Failed to unsubscribe: "${s.reason}"`)})),null===(t=null===(s=this.rpc.ws)||void 0===s?void 0:s.terminate)||void 0===t||t.call(s),null===(i=null===(e=this.rpc.ws)||void 0===e?void 0:e.close)||void 0===i||i.call(e),null===(n=null===(o=this.opts)||void 0===o?void 0:o.onClose)||void 0===n||n.call(o),this.logger.log("Disconected from the session")}}))}open(){return l(this,void 0,void 0,(function*(){if(this.isOpen||this.session)throw new Error("Session connect was already called");if(this.isOpen=!0,!this.opts.__debug_hostname)try{const s=yield w({api_key:this.opts.apiKey,codeSnippetID:this.opts.id,editEnabled:this.opts.editEnabled});this.session=s.data,this.logger.log("Aquired session:",this.session),this.refresh(this.session.sessionID)}catch(s){if(s instanceof w.Error){const t=s.getActualType();if(400===t.status)throw new Error(`Error creating session - (${t.status}) bad request: ${t.data.message}`);if(401===t.status)throw new Error(`Error creating session - (${t.status}) unauthenticated (you need to be authenticated to start an session with persistent edits): ${t.data.message}`);if(500===t.status)throw new Error(`Error creating session - (${t.status}) server error: ${t.data.message}`)}throw s}const s=this.getHostname(this.opts.__debug_port||49982);if(!s)throw new Error("Cannot get session's hostname");const t=`${"local"===this.opts.__debug_devEnv?"ws":"wss"}://${s}/ws`;this.rpc.onError((s=>{this.logger.log("Error in WS session:",this.session,s)}));let e,i,o=!1;const n=new Promise(((s,t)=>{e=()=>{o||(o=!0,s())},i=()=>{o||(o=!0,t())}}));this.rpc.onOpen((()=>{this.logger.log("Connected to session:",this.session),null==e||e()})),this.rpc.onClose((s=>l(this,void 0,void 0,(function*(){var e,o,n,r;if(this.logger.log("Closing WS connection to session:",this.session,s),this.isOpen){null===(o=(e=this.opts).onDisconnect)||void 0===o||o.call(e),yield S(600),this.logger.log("Reconnecting to session:",this.session);try{this.subscribers=[],yield this.rpc.connect(t),null===(r=(n=this.opts).onReconnect)||void 0===r||r.call(n),this.logger.log("Reconnected to session:",this.session)}catch(s){this.logger.log("Failed reconnecting to session:",this.session,s)}}else null==i||i()})))),this.rpc.onNotification.push(this.handleNotification.bind(this));try{this.logger.log("Connection to session:",this.session),yield this.rpc.connect(t)}catch(s){this.logger.log("Error connecting to session",this.session,s)}yield n}))}call(s,t,e){return l(this,void 0,void 0,(function*(){return this.rpc.call(`${s}_${t}`,e)}))}handleSubscriptions(...s){return l(this,void 0,void 0,(function*(){const t=yield Promise.allSettled(s);if(t.every((s=>"fulfilled"===s.status)))return t.map((s=>"fulfilled"===s.status?s.value:void 0));throw yield Promise.all(t.filter(d).map((s=>s.value?this.unsubscribe(s.value):void 0))),new Error(h(t))}))}unsubscribe(s){return l(this,void 0,void 0,(function*(){const t=this.subscribers.find((t=>t.subID===s));t&&(yield this.call(t.service,"unsubscribe",[t.subID]),this.subscribers=this.subscribers.filter((s=>s!==t)),this.logger.log(`Unsubscribed '${s}' from '${t.service}'`))}))}subscribe(s,t,e,...i){return l(this,void 0,void 0,(function*(){const o=yield this.call(s,"subscribe",[e,...i]);if("string"!=typeof o)throw new Error(`Cannot subscribe to ${s}_${e}${i.length>0?" with params ["+i.join(", ")+"]":""}. Expected response should have been a subscription ID, instead we got ${JSON.stringify(o)}`);return this.subscribers.push({handler:t,service:s,subID:o}),this.logger.log(`Subscribed to "${s}_${e}"${i.length>0?" with params ["+i.join(", ")+"] and":""} with id "${o}"`),o}))}handleNotification(s){this.subscribers.filter((t=>{var e;return t.subID===(null===(e=s.params)||void 0===e?void 0:e.subscription)})).forEach((t=>{var e;return t.handler(null===(e=s.params)||void 0===e?void 0:e.result)}))}refresh(s){return l(this,void 0,void 0,(function*(){this.logger.log(`Started refreshing session "${s}"`);try{for(;;){if(!this.isOpen)return void this.logger.log("Cannot refresh session - it was closed",this.session);yield S(5e3);try{this.logger.log(`Refreshed session "${s}"`),yield E({api_key:this.opts.apiKey,sessionID:s})}catch(t){if(t instanceof E.Error){const e=t.getActualType();if(404===e.status)return void this.logger.error(`Error refreshing session - (${e.status}): ${e.data.message}`);this.logger.error(`Refreshing session "${s}" failed - (${e.status})`)}}}}finally{this.logger.log(`Stopped refreshing session "${s}"`),this.close()}}))}}const D="terminal";var _;s.OutType=void 0,(_=s.OutType||(s.OutType={})).Stdout="Stdout",_.Stderr="Stderr",s.FilesystemWatcher=g,s.Session=class extends ${constructor(s){super(s),this.codeSnippetOpts=s.codeSnippet}open(){const s=Object.create(null,{open:{get:()=>super.open}});var t,e,i,o;return l(this,void 0,void 0,(function*(){yield s.open.call(this),yield this.handleSubscriptions((null===(t=this.codeSnippetOpts)||void 0===t?void 0:t.onStateChange)?this.subscribe(u,this.codeSnippetOpts.onStateChange,"state"):void 0,(null===(e=this.codeSnippetOpts)||void 0===e?void 0:e.onStderr)?this.subscribe(u,this.codeSnippetOpts.onStderr,"stderr"):void 0,(null===(i=this.codeSnippetOpts)||void 0===i?void 0:i.onStdout)?this.subscribe(u,this.codeSnippetOpts.onStdout,"stdout"):void 0,(null===(o=this.codeSnippetOpts)||void 0===o?void 0:o.onScanPorts)?this.subscribe(u,this.codeSnippetOpts.onScanPorts,"scanOpenedPorts"):void 0),this.codeSnippet={run:(s,t={})=>l(this,void 0,void 0,(function*(){var e,i;const o=yield this.call(u,"run",[s,t]);return null===(i=null===(e=this.codeSnippetOpts)||void 0===e?void 0:e.onStateChange)||void 0===i||i.call(e,o),o})),stop:()=>l(this,void 0,void 0,(function*(){var s,t;const e=yield this.call(u,"stop");return null===(t=null===(s=this.codeSnippetOpts)||void 0===s?void 0:s.onStateChange)||void 0===t||t.call(s,e),e}))},this.filesystem={list:s=>l(this,void 0,void 0,(function*(){return yield this.call(v,"list",[s])})),read:s=>l(this,void 0,void 0,(function*(){return yield this.call(v,"read",[s])})),remove:s=>l(this,void 0,void 0,(function*(){yield this.call(v,"remove",[s])})),write:(s,t)=>l(this,void 0,void 0,(function*(){yield this.call(v,"write",[s,t])})),writeBytes:(s,t)=>l(this,void 0,void 0,(function*(){const e=Buffer.from(t).toString("base64");yield this.call(v,"writeBase64",[s,e])})),readBytes:s=>l(this,void 0,void 0,(function*(){const t=yield this.call(v,"readBase64",[s]);return Buffer.from(t,"base64")})),makeDir:s=>l(this,void 0,void 0,(function*(){yield this.call(v,"makeDir",[s])})),watchDir:s=>{const t=r.default(s);return new g(this,t)}},this.terminal={createSession:({onData:s,size:t,onExit:e,envVars:i,cmd:o,rootdir:n,terminalID:r=c(12)})=>l(this,void 0,void 0,(function*(){const{promise:c,resolve:d}=a(),[u,p]=yield this.handleSubscriptions(this.subscribe(D,s,"onData",r),this.subscribe(D,d,"onExit",r)),{promise:v,resolve:f}=a();c.then((()=>l(this,void 0,void 0,(function*(){const s=h(yield Promise.allSettled([this.unsubscribe(p),this.unsubscribe(u)]));s&&this.logger.error(s),null==e||e(),f()}))));try{yield this.call(D,"start",[r,t.cols,t.rows,...void 0!==o?[i,o,n]:[]])}catch(s){throw d(),yield v,s}return{destroy:()=>l(this,void 0,void 0,(function*(){try{yield this.call(D,"destroy",[r])}finally{d(),yield v}})),resize:({cols:s,rows:t})=>l(this,void 0,void 0,(function*(){yield this.call(D,"resize",[r,s,t])})),sendData:s=>l(this,void 0,void 0,(function*(){yield this.call(D,"data",[r,s])})),terminalID:r}}))},this.process={start:({cmd:s,onStdout:t,onStderr:e,onExit:i,envVars:o={},rootdir:n="/",processID:r=c(12)})=>l(this,void 0,void 0,(function*(){const{promise:c,resolve:d}=a(),[u,p,v]=yield this.handleSubscriptions(this.subscribe(b,d,"onExit",r),t?this.subscribe(b,t,"onStdout",r):void 0,e?this.subscribe(b,e,"onStderr",r):void 0),{promise:f,resolve:g}=a();c.then((()=>l(this,void 0,void 0,(function*(){const s=h(yield Promise.allSettled([this.unsubscribe(u),p?this.unsubscribe(p):void 0,v?this.unsubscribe(v):void 0]));s&&this.logger.error(s),null==i||i(),g()}))));try{yield this.call(b,"start",[r,s,o,n])}catch(s){throw d(),yield f,s}return{kill:()=>l(this,void 0,void 0,(function*(){try{yield this.call(b,"kill",[r])}finally{d(),yield f}})),processID:r,sendStdin:s=>l(this,void 0,void 0,(function*(){yield this.call(b,"stdin",[r,s])}))}}))}}))}},s.api=y,s.createSessionProcess=function({cmd:s,manager:t,onStderr:e,onStdout:i,processID:o,rootdir:n}){return l(this,void 0,void 0,(function*(){if(!t)throw new Error("Cannot create process - process manager is not defined");const{resolve:r,promise:l}=a(),c=yield t.start({cmd:s,onStdout:i,onStderr:e,onExit:()=>{r()},rootdir:n,processID:o});return{exited:l,processID:c.processID,kill:c.kill,sendStdin:c.sendStdin}}))},Object.defineProperty(s,"__esModule",{value:!0})})); //# sourceMappingURL=index.js.map