New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@devbookhq/sdk

Package Overview
Dependencies
Maintainers
2
Versions
152
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@devbookhq/sdk - npm Package Compare versions

Comparing version 2.5.4 to 2.5.5

dist/cjs/session/filesystemWatcher.d.ts

2

dist/cjs/api/index.d.ts
import 'cross-fetch/polyfill';
import type { paths, components } from './schema.gen';
import type { components, paths } from './schema.gen';
declare const client: {

@@ -4,0 +4,0 @@ configure: (config: import("openapi-typescript-fetch/dist/cjs/types").FetchConfig) => void;

@@ -6,3 +6,3 @@ /**

export interface paths {
readonly "/health": {
readonly '/health': {
/** Health check */

@@ -13,7 +13,7 @@ readonly get: {

readonly 200: unknown;
readonly 401: components["responses"]["401"];
readonly 401: components['responses']['401'];
};
};
};
readonly "/sessions": {
readonly '/sessions': {
/** List all sessions */

@@ -23,3 +23,3 @@ readonly get: {

readonly query: {
readonly api_key?: components["parameters"]["apiKeyReq"];
readonly api_key?: components['parameters']['apiKeyReq'];
};

@@ -31,7 +31,7 @@ };

readonly content: {
readonly "application/json": readonly components["schemas"]["Session"][];
readonly 'application/json': readonly components['schemas']['Session'][];
};
};
readonly 401: components["responses"]["401"];
readonly 500: components["responses"]["500"];
readonly 401: components['responses']['401'];
readonly 500: components['responses']['500'];
};

@@ -43,3 +43,3 @@ };

readonly query: {
readonly api_key?: components["parameters"]["apiKeyOpt"];
readonly api_key?: components['parameters']['apiKeyOpt'];
};

@@ -51,12 +51,12 @@ };

readonly content: {
readonly "application/json": components["schemas"]["Session"];
readonly 'application/json': components['schemas']['Session'];
};
};
readonly 400: components["responses"]["400"];
readonly 401: components["responses"]["401"];
readonly 500: components["responses"]["500"];
readonly 400: components['responses']['400'];
readonly 401: components['responses']['401'];
readonly 500: components['responses']['500'];
};
readonly requestBody: {
readonly content: {
readonly "application/json": components["schemas"]["NewSession"];
readonly 'application/json': components['schemas']['NewSession'];
};

@@ -66,3 +66,3 @@ };

};
readonly "/sessions/{sessionID}": {
readonly '/sessions/{sessionID}': {
/** Delete a session on the server */

@@ -72,6 +72,6 @@ readonly delete: {

readonly query: {
readonly api_key?: components["parameters"]["apiKeyReq"];
readonly api_key?: components['parameters']['apiKeyReq'];
};
readonly path: {
readonly sessionID: components["parameters"]["sessionID"];
readonly sessionID: components['parameters']['sessionID'];
};

@@ -82,8 +82,8 @@ };

readonly 204: never;
readonly 401: components["responses"]["401"];
readonly 500: components["responses"]["500"];
readonly 401: components['responses']['401'];
readonly 500: components['responses']['500'];
};
};
};
readonly "/sessions/{sessionID}/refresh": {
readonly '/sessions/{sessionID}/refresh': {
/** Refresh the session extending its time to live */

@@ -93,6 +93,6 @@ readonly post: {

readonly query: {
readonly api_key?: components["parameters"]["apiKeyOpt"];
readonly api_key?: components['parameters']['apiKeyOpt'];
};
readonly path: {
readonly sessionID: components["parameters"]["sessionID"];
readonly sessionID: components['parameters']['sessionID'];
};

@@ -103,7 +103,7 @@ };

readonly 204: never;
readonly 401: components["responses"]["401"];
readonly 401: components['responses']['401'];
/** Error refreshing session - session not found */
readonly 404: {
readonly content: {
readonly "application/json": components["schemas"]["Error"];
readonly 'application/json': components['schemas']['Error'];
};

@@ -114,3 +114,3 @@ };

};
readonly "/envs/{codeSnippetID}": {
readonly '/envs/{codeSnippetID}': {
/** Create a new env for a code snippet */

@@ -120,6 +120,6 @@ readonly post: {

readonly query: {
readonly api_key?: components["parameters"]["apiKeyReq"];
readonly api_key?: components['parameters']['apiKeyReq'];
};
readonly path: {
readonly codeSnippetID: components["parameters"]["codeSnippetID"];
readonly codeSnippetID: components['parameters']['codeSnippetID'];
};

@@ -130,9 +130,9 @@ };

readonly 204: never;
readonly 400: components["responses"]["400"];
readonly 401: components["responses"]["401"];
readonly 500: components["responses"]["500"];
readonly 400: components['responses']['400'];
readonly 401: components['responses']['401'];
readonly 500: components['responses']['500'];
};
readonly requestBody: {
readonly content: {
readonly "application/json": components["schemas"]["NewEnvironment"];
readonly 'application/json': components['schemas']['NewEnvironment'];
};

@@ -145,6 +145,6 @@ };

readonly query: {
readonly api_key?: components["parameters"]["apiKeyReq"];
readonly api_key?: components['parameters']['apiKeyReq'];
};
readonly path: {
readonly codeSnippetID: components["parameters"]["codeSnippetID"];
readonly codeSnippetID: components['parameters']['codeSnippetID'];
};

@@ -158,7 +158,7 @@ };

readonly content: {
readonly "application/json": components["schemas"]["Error"];
readonly 'application/json': components['schemas']['Error'];
};
};
readonly 401: components["responses"]["401"];
readonly 500: components["responses"]["500"];
readonly 401: components['responses']['401'];
readonly 500: components['responses']['500'];
};

@@ -170,6 +170,6 @@ };

readonly query: {
readonly api_key?: components["parameters"]["apiKeyReq"];
readonly api_key?: components['parameters']['apiKeyReq'];
};
readonly path: {
readonly codeSnippetID: components["parameters"]["codeSnippetID"];
readonly codeSnippetID: components['parameters']['codeSnippetID'];
};

@@ -180,9 +180,9 @@ };

readonly 204: never;
readonly 400: components["responses"]["400"];
readonly 401: components["responses"]["401"];
readonly 500: components["responses"]["500"];
readonly 400: components['responses']['400'];
readonly 401: components['responses']['401'];
readonly 500: components['responses']['500'];
};
};
};
readonly "/envs/{codeSnippetID}/state": {
readonly '/envs/{codeSnippetID}/state': {
/** Update the state of the environment */

@@ -192,6 +192,6 @@ readonly put: {

readonly query: {
readonly api_key?: components["parameters"]["apiKeyReq"];
readonly api_key?: components['parameters']['apiKeyReq'];
};
readonly path: {
readonly codeSnippetID: components["parameters"]["codeSnippetID"];
readonly codeSnippetID: components['parameters']['codeSnippetID'];
};

@@ -202,8 +202,8 @@ };

readonly 204: never;
readonly 400: components["responses"]["400"];
readonly 401: components["responses"]["401"];
readonly 400: components['responses']['400'];
readonly 401: components['responses']['401'];
};
readonly requestBody: {
readonly content: {
readonly "application/json": components["schemas"]["EnvironmentStateUpdate"];
readonly 'application/json': components['schemas']['EnvironmentStateUpdate'];
};

@@ -213,3 +213,3 @@ };

};
readonly "/prisma-hub/db": {
readonly '/prisma-hub/db': {
/** Creates a new hub database */

@@ -221,6 +221,6 @@ readonly post: {

readonly content: {
readonly "application/json": components["schemas"]["HubDatabase"];
readonly 'application/json': components['schemas']['HubDatabase'];
};
};
readonly 500: components["responses"]["500"];
readonly 500: components['responses']['500'];
};

@@ -237,11 +237,11 @@ };

/** @enum {string} */
readonly Template: "Nodejs" | "Go" | "Bash" | "Rust" | "Python3" | "Typescript";
readonly Template: 'Nodejs' | 'Go' | 'Bash' | 'Rust' | 'Python3' | 'Typescript';
/** @enum {string} */
readonly EnvironmentState: "Building" | "Failed" | "Done";
readonly EnvironmentState: 'Building' | 'Failed' | 'Done';
readonly NewEnvironment: {
readonly template: components["schemas"]["Template"];
readonly template: components['schemas']['Template'];
readonly deps: readonly string[];
};
readonly EnvironmentStateUpdate: {
readonly state: components["schemas"]["EnvironmentState"];
readonly state: components['schemas']['EnvironmentState'];
};

@@ -281,3 +281,3 @@ readonly NewSession: {

readonly content: {
readonly "application/json": components["schemas"]["Error"];
readonly 'application/json': components['schemas']['Error'];
};

@@ -288,3 +288,3 @@ };

readonly content: {
readonly "application/json": components["schemas"]["Error"];
readonly 'application/json': components['schemas']['Error'];
};

@@ -295,3 +295,3 @@ };

readonly content: {
readonly "application/json": components["schemas"]["Error"];
readonly 'application/json': components['schemas']['Error'];
};

@@ -298,0 +298,0 @@ };

export { default as Session } from './session';
export type { SessionOpts, } from './session';
export { CodeSnippetExecState, } from './session/codeSnippet';
export type { SessionOpts } from './session';
export { CodeSnippetExecState } from './session/codeSnippet';
export type { CodeSnippetManager, CodeSnippetStateHandler, CodeSnippetStderrHandler, CodeSnippetStdoutHandler, CodeSnippetSubscriptionHandler, CodeSnippetSubscriptionHandlerType, OpenedPort, } from './session/codeSnippet';
export type { OutResponse, OutStderrResponse, OutStdoutResponse, } from './session/out';
export { OutType, } from './session/out';
export type { TerminalManager, TerminalSession, ChildProcess, } from './session/terminal';
export type { FilesystemManager, FileInfo, } from './session/filesystem';
export type { Process, ProcessManager, } from './session/process';
export type { EnvVars, } from './session/envVars';
export type { OutResponse, OutStderrResponse, OutStdoutResponse } from './session/out';
export { OutType } from './session/out';
export type { TerminalManager, TerminalSession, ChildProcess } from './session/terminal';
export type { FilesystemManager, FileInfo } from './session/filesystem';
export type { Process, ProcessManager } from './session/process';
export type { EnvVars } from './session/envVars';
export { default as api } from './api';
export type { components, paths, } from './api';
export type { components, paths } from './api';

@@ -1,2 +0,2 @@

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

@@ -0,3 +1,3 @@

import { EnvVars } from './envVars';
import { OutStderrResponse, OutStdoutResponse } from './out';
import { EnvVars } from './envVars';
export declare const codeSnippetService = "codeSnippet";

@@ -19,6 +19,6 @@ export declare enum CodeSnippetExecState {

export declare type CodeSnippetSubscriptionHandlerType = {
'state': CodeSnippetStateHandler;
'stderr': CodeSnippetStderrHandler;
'stdout': CodeSnippetStdoutHandler;
'scanOpenedPorts': ScanOpenedPortsHandler;
state: CodeSnippetStateHandler;
stderr: CodeSnippetStderrHandler;
stdout: CodeSnippetStdoutHandler;
scanOpenedPorts: ScanOpenedPortsHandler;
};

@@ -25,0 +25,0 @@ export interface CodeSnippetManager {

@@ -0,1 +1,2 @@

import FilesystemWatcher from "./filesystemWatcher";
export declare const filesystemService = "filesystem";

@@ -11,2 +12,3 @@ export interface FileInfo {

readonly listAllFiles: (path: string) => Promise<FileInfo[]>;
readonly watch: (path: string) => Promise<FilesystemWatcher>;
}

@@ -1,6 +0,6 @@

import SessionConnection, { SessionConnectionOpts } from './sessionConnection';
import { CodeSnippetManager, CodeSnippetStateHandler, CodeSnippetStderrHandler, CodeSnippetStdoutHandler, ScanOpenedPortsHandler } from './codeSnippet';
import { TerminalManager } from './terminal';
import { FilesystemManager } from './filesystem';
import { ProcessManager } from './process';
import SessionConnection, { SessionConnectionOpts } from './sessionConnection';
import { TerminalManager } from './terminal';
export interface CodeSnippetOpts {

@@ -16,3 +16,2 @@ onStateChange?: CodeSnippetStateHandler;

declare class Session extends SessionConnection {
private readonly codeSnippetOpts?;
codeSnippet?: CodeSnippetManager;

@@ -22,2 +21,3 @@ terminal?: TerminalManager;

process?: ProcessManager;
private readonly codeSnippetOpts?;
constructor(opts: SessionOpts);

@@ -24,0 +24,0 @@ open(): Promise<void>;

import { EnvVars } from './envVars';
import { OutStdoutResponse, OutStderrResponse } from './out';
import { OutStderrResponse, OutStdoutResponse } from './out';
export declare const processService = "process";

@@ -4,0 +4,0 @@ export interface Process {

import { components } from '../api';
import Logger from '../utils/logger';
import { processService } from './process';
import { codeSnippetService } from './codeSnippet';
import { filesystemService } from './filesystem';
import { processService } from './process';
import { terminalService } from './terminal';

@@ -32,8 +32,2 @@ declare type SubscriptionHandler = (result: any) => void;

constructor(opts: SessionConnectionOpts);
protected call(service: Service, method: string, params?: any[]): Promise<unknown>;
protected handleSubscriptions<T extends (ReturnType<SessionConnection['subscribe']> | undefined)[]>(...subs: T): Promise<{
[P in keyof T]: Awaited<T[P]>;
}>;
protected unsubscribe(subID: string): Promise<void>;
protected subscribe(service: Service, handler: SubscriptionHandler, method: string, ...params: any[]): Promise<string>;
/**

@@ -60,2 +54,8 @@ * Get the hostname for the session or for the specified session's port.

open(): Promise<void>;
call(service: Service, method: string, params?: any[]): Promise<unknown>;
handleSubscriptions<T extends (ReturnType<SessionConnection['subscribe']> | undefined)[]>(...subs: T): Promise<{
[P in keyof T]: Awaited<T[P]>;
}>;
unsubscribe(subID: string): Promise<void>;
subscribe(service: Service, handler: SubscriptionHandler, method: string, ...params: any[]): Promise<string>;
private handleNotification;

@@ -62,0 +62,0 @@ private refresh;

@@ -18,4 +18,4 @@ export declare const terminalService = "terminal";

readonly createSession: (opts: {
onData: (data: string) => void;
onExit?: () => void;
onData: (data: string) => void;
onChildProcessesChange?: (cps: ChildProcess[]) => void;

@@ -22,0 +22,0 @@ size: {

@@ -6,6 +6,6 @@ declare type LogID = string | (() => string);

constructor(logID: LogID, isEnabled?: boolean);
error(...args: any[]): void;
log(...args: any[]): void;
private id;
log(...args: any[]): void;
error(...args: any[]): void;
}
export default Logger;

@@ -5,5 +5,5 @@ export declare function assertFulfilled<T>(item: PromiseSettledResult<T>): item is PromiseFulfilledResult<T>;

export declare function createDeferredPromise<T = void>(): {
promise: Promise<T>;
reject: (reason?: unknown) => void;
resolve: (value: T) => void;
reject: (reason?: unknown) => void;
promise: Promise<T>;
};
import 'cross-fetch/polyfill';
import type { paths, components } from './schema.gen';
import type { components, paths } from './schema.gen';
declare const client: {

@@ -4,0 +4,0 @@ configure: (config: import("openapi-typescript-fetch/dist/cjs/types").FetchConfig) => void;

@@ -6,3 +6,3 @@ /**

export interface paths {
readonly "/health": {
readonly '/health': {
/** Health check */

@@ -13,7 +13,7 @@ readonly get: {

readonly 200: unknown;
readonly 401: components["responses"]["401"];
readonly 401: components['responses']['401'];
};
};
};
readonly "/sessions": {
readonly '/sessions': {
/** List all sessions */

@@ -23,3 +23,3 @@ readonly get: {

readonly query: {
readonly api_key?: components["parameters"]["apiKeyReq"];
readonly api_key?: components['parameters']['apiKeyReq'];
};

@@ -31,7 +31,7 @@ };

readonly content: {
readonly "application/json": readonly components["schemas"]["Session"][];
readonly 'application/json': readonly components['schemas']['Session'][];
};
};
readonly 401: components["responses"]["401"];
readonly 500: components["responses"]["500"];
readonly 401: components['responses']['401'];
readonly 500: components['responses']['500'];
};

@@ -43,3 +43,3 @@ };

readonly query: {
readonly api_key?: components["parameters"]["apiKeyOpt"];
readonly api_key?: components['parameters']['apiKeyOpt'];
};

@@ -51,12 +51,12 @@ };

readonly content: {
readonly "application/json": components["schemas"]["Session"];
readonly 'application/json': components['schemas']['Session'];
};
};
readonly 400: components["responses"]["400"];
readonly 401: components["responses"]["401"];
readonly 500: components["responses"]["500"];
readonly 400: components['responses']['400'];
readonly 401: components['responses']['401'];
readonly 500: components['responses']['500'];
};
readonly requestBody: {
readonly content: {
readonly "application/json": components["schemas"]["NewSession"];
readonly 'application/json': components['schemas']['NewSession'];
};

@@ -66,3 +66,3 @@ };

};
readonly "/sessions/{sessionID}": {
readonly '/sessions/{sessionID}': {
/** Delete a session on the server */

@@ -72,6 +72,6 @@ readonly delete: {

readonly query: {
readonly api_key?: components["parameters"]["apiKeyReq"];
readonly api_key?: components['parameters']['apiKeyReq'];
};
readonly path: {
readonly sessionID: components["parameters"]["sessionID"];
readonly sessionID: components['parameters']['sessionID'];
};

@@ -82,8 +82,8 @@ };

readonly 204: never;
readonly 401: components["responses"]["401"];
readonly 500: components["responses"]["500"];
readonly 401: components['responses']['401'];
readonly 500: components['responses']['500'];
};
};
};
readonly "/sessions/{sessionID}/refresh": {
readonly '/sessions/{sessionID}/refresh': {
/** Refresh the session extending its time to live */

@@ -93,6 +93,6 @@ readonly post: {

readonly query: {
readonly api_key?: components["parameters"]["apiKeyOpt"];
readonly api_key?: components['parameters']['apiKeyOpt'];
};
readonly path: {
readonly sessionID: components["parameters"]["sessionID"];
readonly sessionID: components['parameters']['sessionID'];
};

@@ -103,7 +103,7 @@ };

readonly 204: never;
readonly 401: components["responses"]["401"];
readonly 401: components['responses']['401'];
/** Error refreshing session - session not found */
readonly 404: {
readonly content: {
readonly "application/json": components["schemas"]["Error"];
readonly 'application/json': components['schemas']['Error'];
};

@@ -114,3 +114,3 @@ };

};
readonly "/envs/{codeSnippetID}": {
readonly '/envs/{codeSnippetID}': {
/** Create a new env for a code snippet */

@@ -120,6 +120,6 @@ readonly post: {

readonly query: {
readonly api_key?: components["parameters"]["apiKeyReq"];
readonly api_key?: components['parameters']['apiKeyReq'];
};
readonly path: {
readonly codeSnippetID: components["parameters"]["codeSnippetID"];
readonly codeSnippetID: components['parameters']['codeSnippetID'];
};

@@ -130,9 +130,9 @@ };

readonly 204: never;
readonly 400: components["responses"]["400"];
readonly 401: components["responses"]["401"];
readonly 500: components["responses"]["500"];
readonly 400: components['responses']['400'];
readonly 401: components['responses']['401'];
readonly 500: components['responses']['500'];
};
readonly requestBody: {
readonly content: {
readonly "application/json": components["schemas"]["NewEnvironment"];
readonly 'application/json': components['schemas']['NewEnvironment'];
};

@@ -145,6 +145,6 @@ };

readonly query: {
readonly api_key?: components["parameters"]["apiKeyReq"];
readonly api_key?: components['parameters']['apiKeyReq'];
};
readonly path: {
readonly codeSnippetID: components["parameters"]["codeSnippetID"];
readonly codeSnippetID: components['parameters']['codeSnippetID'];
};

@@ -158,7 +158,7 @@ };

readonly content: {
readonly "application/json": components["schemas"]["Error"];
readonly 'application/json': components['schemas']['Error'];
};
};
readonly 401: components["responses"]["401"];
readonly 500: components["responses"]["500"];
readonly 401: components['responses']['401'];
readonly 500: components['responses']['500'];
};

@@ -170,6 +170,6 @@ };

readonly query: {
readonly api_key?: components["parameters"]["apiKeyReq"];
readonly api_key?: components['parameters']['apiKeyReq'];
};
readonly path: {
readonly codeSnippetID: components["parameters"]["codeSnippetID"];
readonly codeSnippetID: components['parameters']['codeSnippetID'];
};

@@ -180,9 +180,9 @@ };

readonly 204: never;
readonly 400: components["responses"]["400"];
readonly 401: components["responses"]["401"];
readonly 500: components["responses"]["500"];
readonly 400: components['responses']['400'];
readonly 401: components['responses']['401'];
readonly 500: components['responses']['500'];
};
};
};
readonly "/envs/{codeSnippetID}/state": {
readonly '/envs/{codeSnippetID}/state': {
/** Update the state of the environment */

@@ -192,6 +192,6 @@ readonly put: {

readonly query: {
readonly api_key?: components["parameters"]["apiKeyReq"];
readonly api_key?: components['parameters']['apiKeyReq'];
};
readonly path: {
readonly codeSnippetID: components["parameters"]["codeSnippetID"];
readonly codeSnippetID: components['parameters']['codeSnippetID'];
};

@@ -202,8 +202,8 @@ };

readonly 204: never;
readonly 400: components["responses"]["400"];
readonly 401: components["responses"]["401"];
readonly 400: components['responses']['400'];
readonly 401: components['responses']['401'];
};
readonly requestBody: {
readonly content: {
readonly "application/json": components["schemas"]["EnvironmentStateUpdate"];
readonly 'application/json': components['schemas']['EnvironmentStateUpdate'];
};

@@ -213,3 +213,3 @@ };

};
readonly "/prisma-hub/db": {
readonly '/prisma-hub/db': {
/** Creates a new hub database */

@@ -221,6 +221,6 @@ readonly post: {

readonly content: {
readonly "application/json": components["schemas"]["HubDatabase"];
readonly 'application/json': components['schemas']['HubDatabase'];
};
};
readonly 500: components["responses"]["500"];
readonly 500: components['responses']['500'];
};

@@ -237,11 +237,11 @@ };

/** @enum {string} */
readonly Template: "Nodejs" | "Go" | "Bash" | "Rust" | "Python3" | "Typescript";
readonly Template: 'Nodejs' | 'Go' | 'Bash' | 'Rust' | 'Python3' | 'Typescript';
/** @enum {string} */
readonly EnvironmentState: "Building" | "Failed" | "Done";
readonly EnvironmentState: 'Building' | 'Failed' | 'Done';
readonly NewEnvironment: {
readonly template: components["schemas"]["Template"];
readonly template: components['schemas']['Template'];
readonly deps: readonly string[];
};
readonly EnvironmentStateUpdate: {
readonly state: components["schemas"]["EnvironmentState"];
readonly state: components['schemas']['EnvironmentState'];
};

@@ -281,3 +281,3 @@ readonly NewSession: {

readonly content: {
readonly "application/json": components["schemas"]["Error"];
readonly 'application/json': components['schemas']['Error'];
};

@@ -288,3 +288,3 @@ };

readonly content: {
readonly "application/json": components["schemas"]["Error"];
readonly 'application/json': components['schemas']['Error'];
};

@@ -295,3 +295,3 @@ };

readonly content: {
readonly "application/json": components["schemas"]["Error"];
readonly 'application/json': components['schemas']['Error'];
};

@@ -298,0 +298,0 @@ };

export { default as Session } from './session';
export type { SessionOpts, } from './session';
export { CodeSnippetExecState, } from './session/codeSnippet';
export type { SessionOpts } from './session';
export { CodeSnippetExecState } from './session/codeSnippet';
export type { CodeSnippetManager, CodeSnippetStateHandler, CodeSnippetStderrHandler, CodeSnippetStdoutHandler, CodeSnippetSubscriptionHandler, CodeSnippetSubscriptionHandlerType, OpenedPort, } from './session/codeSnippet';
export type { OutResponse, OutStderrResponse, OutStdoutResponse, } from './session/out';
export { OutType, } from './session/out';
export type { TerminalManager, TerminalSession, ChildProcess, } from './session/terminal';
export type { FilesystemManager, FileInfo, } from './session/filesystem';
export type { Process, ProcessManager, } from './session/process';
export type { EnvVars, } from './session/envVars';
export type { OutResponse, OutStderrResponse, OutStdoutResponse } from './session/out';
export { OutType } from './session/out';
export type { TerminalManager, TerminalSession, ChildProcess } from './session/terminal';
export type { FilesystemManager, FileInfo } from './session/filesystem';
export type { Process, ProcessManager } from './session/process';
export type { EnvVars } from './session/envVars';
export { default as api } from './api';
export type { components, paths, } from './api';
export type { components, paths } from './api';

@@ -1,2 +0,2 @@

import{RpcWebSocketClient as s}from"rpc-websocket-client";import"cross-fetch/polyfill";import{Fetcher as i}from"openapi-typescript-fetch";function t(s,i,t,e){return new(t||(t=Promise))((function(o,n){function r(s){try{c(e.next(s))}catch(s){n(s)}}function l(s){try{c(e.throw(s))}catch(s){n(s)}}function c(s){var i;s.done?o(s.value):(i=s.value,i instanceof t?i:new t((function(s){s(i)}))).then(r,l)}c((e=e.apply(s,i||[])).next())}))}const e=i.for();function o(s){return new Promise((i=>setTimeout(i,s)))}e.configure({baseUrl:"https://ondevbook.com"});class n{constructor(s,i=!1){this.logID=s,this.isEnabled=i}id(){return"function"==typeof this.logID?this.logID():this.logID}log(...s){this.isEnabled&&console.log(`[${this.id()}]`,...s)}error(...s){console.error(`[${this.id()} ERROR]`,...s)}}function r(s){return"fulfilled"===s.status}function l(s){if(!s.every((s=>"fulfilled"===s.status)))return s.reduce(((s,i,t)=>"rejected"===i.status?s+"\n"+`[${t}]: `+`${JSON.stringify(i)}`:s),"errors:\n")}function c(){let s,i;const t=new Promise(((t,e)=>{s=t,i=e}));return{resolve:s,reject:i,promise:t}}const d=e.path("/sessions").method("post").create({api_key:!0}),h=e.path("/sessions/{sessionID}/refresh").method("post").create({api_key:!0});var a;!function(s){s.Running="Running",s.Stopped="Stopped"}(a||(a={}));function u(s){let i="";const t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",e=t.length;for(let o=0;o<s;o++)i+=t.charAt(Math.floor(Math.random()*e));return i}class p extends class{constructor(i){this.opts=i,this.isOpen=!1,this.rpc=new s,this.subscribers=[],this.logger=new n("Session",i.debug),this.logger.log(`Session for code snippet "${i.id}" initialized`)}call(s,i,e){return t(this,void 0,void 0,(function*(){return this.rpc.call(`${s}_${i}`,e)}))}handleSubscriptions(...s){return t(this,void 0,void 0,(function*(){const i=yield Promise.allSettled(s);if(i.every((s=>"fulfilled"===s.status)))return i.map((s=>"fulfilled"===s.status?s.value:void 0));throw yield Promise.all(i.filter(r).map((s=>s.value?this.unsubscribe(s.value):void 0))),new Error(l(i))}))}unsubscribe(s){return t(this,void 0,void 0,(function*(){const i=this.subscribers.find((i=>i.subID===s));i&&(yield this.call(i.service,"unsubscribe",[i.subID]),this.subscribers=this.subscribers.filter((s=>s!==i)),this.logger.log(`Unsubscribed from "${i.service}"`))}))}subscribe(s,i,e,...o){return t(this,void 0,void 0,(function*(){const t=yield this.call(s,"subscribe",[e,...o]);if("string"!=typeof t)throw new Error(`Cannot subscribe to ${s}_${e}${o.length>0?" with params ["+o.join(", ")+"]":""}. Expected response should have been a subscription ID, instead we got ${JSON.stringify(t)}`);return this.subscribers.push({subID:t,handler:i,service:s}),this.logger.log(`Subscribed to "${s}_${e}"${o.length>0?" with params ["+o.join(", ")+"] and":""} with id "${t}"`),t}))}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 i=`${this.session.sessionID}-${this.session.clientID}.ondevbook.com`;return s?`${s}-${i}`:i}close(){var s,i,e;return t(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===(s=this.rpc.ws)||void 0===s||s.close(),null===(e=null===(i=this.opts)||void 0===i?void 0:i.onClose)||void 0===e||e.call(i),this.logger.log("Disconected from the session")}}))}open(){return t(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 d({codeSnippetID:this.opts.id,editEnabled:this.opts.editEnabled,api_key:this.opts.apiKey});this.session=s.data,this.logger.log("Aquired session:",this.session),this.refresh(this.session.sessionID)}catch(s){if(s instanceof d.Error){const i=s.getActualType();if(400===i.status)throw new Error(`Error creating session - (${i.status}) bad request: ${i.data.message}`);if(401===i.status)throw new Error(`Error creating session - (${i.status}) unauthenticated (you need to be authenticated to start an session with persistent edits): ${i.data.message}`);if(500===i.status)throw new Error(`Error creating session - (${i.status}) server error: ${i.data.message}`);throw s}}const s=this.getHostname(this.opts.__debug_port||49982);if(!s)throw new Error("Cannot get session's hostname");const i=`${"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,n,r=!1;const l=new Promise(((s,i)=>{e=()=>{r||(r=!0,s())},n=()=>{r||(r=!0,i())}}));this.rpc.onOpen((()=>{this.logger.log("Connected to session:",this.session),null==e||e()})),this.rpc.onClose((s=>t(this,void 0,void 0,(function*(){var t,e,r,l;if(this.logger.log("Closing WS connection to session:",this.session,s),this.isOpen){null===(e=(t=this.opts).onDisconnect)||void 0===e||e.call(t),yield o(100),this.logger.log("Reconnecting to session:",this.session);try{this.subscribers=[],yield this.rpc.connect(i),null===(l=(r=this.opts).onReconnect)||void 0===l||l.call(r),this.logger.log("Reconnected to session:",this.session)}catch(s){this.logger.log("Failed reconnecting to session:",this.session,s)}}else null==n||n()})))),this.rpc.onNotification.push(this.handleNotification.bind(this));try{this.logger.log("Connection to session:",this.session),yield this.rpc.connect(i)}catch(s){this.logger.log("Error connecting to session",this.session,s)}yield l}))}handleNotification(s){this.subscribers.filter((i=>{var t;return i.subID===(null===(t=s.params)||void 0===t?void 0:t.subscription)})).forEach((i=>{var t;return i.handler(null===(t=s.params)||void 0===t?void 0:t.result)}))}refresh(s){return t(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 o(5e3);try{this.logger.log(`Refreshed session "${s}"`),yield h({sessionID:s,api_key:this.opts.apiKey})}catch(i){if(i instanceof h.Error){const t=i.getActualType();if(404===t.status)return void this.logger.error(`Error refreshing session - (${t.status}): ${t.data.message}`);this.logger.error(`Refreshing session "${s}" failed - (${t.status})`)}}}}finally{this.logger.log(`Stopped refreshing session "${s}"`),this.close()}}))}}{constructor(s){super(s),this.codeSnippetOpts=s.codeSnippet}open(){const s=Object.create(null,{open:{get:()=>super.open}});var i,e,o,n;return t(this,void 0,void 0,(function*(){yield s.open.call(this),yield this.handleSubscriptions((null===(i=this.codeSnippetOpts)||void 0===i?void 0:i.onStateChange)?this.subscribe("codeSnippet",this.codeSnippetOpts.onStateChange,"state"):void 0,(null===(e=this.codeSnippetOpts)||void 0===e?void 0:e.onStderr)?this.subscribe("codeSnippet",this.codeSnippetOpts.onStderr,"stderr"):void 0,(null===(o=this.codeSnippetOpts)||void 0===o?void 0:o.onStdout)?this.subscribe("codeSnippet",this.codeSnippetOpts.onStdout,"stdout"):void 0,(null===(n=this.codeSnippetOpts)||void 0===n?void 0:n.onScanPorts)?this.subscribe("codeSnippet",this.codeSnippetOpts.onScanPorts,"scanOpenedPorts"):void 0),this.codeSnippet={run:(s,i={})=>t(this,void 0,void 0,(function*(){var t,e;const o=yield this.call("codeSnippet","run",[s,i]);return null===(e=null===(t=this.codeSnippetOpts)||void 0===t?void 0:t.onStateChange)||void 0===e||e.call(t,o),o})),stop:()=>t(this,void 0,void 0,(function*(){var s,i;const t=yield this.call("codeSnippet","stop");return null===(i=null===(s=this.codeSnippetOpts)||void 0===s?void 0:s.onStateChange)||void 0===i||i.call(s,t),t}))},this.filesystem={listAllFiles:s=>t(this,void 0,void 0,(function*(){return yield this.call("filesystem","listAllFiles",[s])})),removeFile:s=>t(this,void 0,void 0,(function*(){yield this.call("filesystem","removeFile",[s])})),writeFile:(s,i)=>t(this,void 0,void 0,(function*(){yield this.call("filesystem","writeFile",[s,i])})),readFile:s=>t(this,void 0,void 0,(function*(){return yield this.call("filesystem","readFile",[s])}))},this.terminal={killProcess:s=>t(this,void 0,void 0,(function*(){yield this.call("terminal","killProcess",[s])})),createSession:({onData:s,onChildProcessesChange:i,size:e,onExit:o,terminalID:n=u(12)})=>t(this,void 0,void 0,(function*(){const{promise:r,resolve:d}=c(),[h,a,u]=yield this.handleSubscriptions(this.subscribe("terminal",s,"onData",n),this.subscribe("terminal",d,"onExit",n),i?this.subscribe("terminal",i,"onChildProcessesChange",n):void 0),{promise:p,resolve:g}=c();r.then((()=>t(this,void 0,void 0,(function*(){const s=l(yield Promise.allSettled([this.unsubscribe(a),this.unsubscribe(h),u?this.unsubscribe(u):void 0]));s&&this.logger.error(s),null==o||o(),g()}))));try{yield this.call("terminal","start",[n,e.cols,e.rows])}catch(s){throw d(),yield p,s}return{terminalID:n,destroy:()=>t(this,void 0,void 0,(function*(){try{yield this.call("terminal","destroy",[n])}finally{d(),yield p}})),sendData:s=>t(this,void 0,void 0,(function*(){yield this.call("terminal","data",[n,s])})),resize:({cols:s,rows:i})=>t(this,void 0,void 0,(function*(){yield this.call("terminal","resize",[n,s,i])}))}}))},this.process={start:({cmd:s,onStdout:i,onStderr:e,onExit:o,envVars:n={},rootdir:r="/",processID:d=u(12)})=>t(this,void 0,void 0,(function*(){const{promise:h,resolve:a}=c(),[u,p,g]=yield this.handleSubscriptions(this.subscribe("process",a,"onExit",d),i?this.subscribe("process",i,"onStdout",d):void 0,e?this.subscribe("process",e,"onStderr",d):void 0),{promise:v,resolve:f}=c();h.then((()=>t(this,void 0,void 0,(function*(){const s=l(yield Promise.allSettled([this.unsubscribe(u),p?this.unsubscribe(p):void 0,g?this.unsubscribe(g):void 0]));s&&this.logger.error(s),null==o||o(),f()}))));try{yield this.call("process","start",[d,s,n,r])}catch(s){throw a(),yield v,s}return{processID:d,kill:()=>t(this,void 0,void 0,(function*(){try{yield this.call("process","kill",[d])}finally{a(),yield v}})),sendStdin:s=>t(this,void 0,void 0,(function*(){yield this.call("process","stdin",[d,s])}))}}))}}))}}var g;!function(s){s.Stdout="Stdout",s.Stderr="Stderr"}(g||(g={}));export{a as CodeSnippetExecState,g as OutType,p as Session,e as api};
import s from"normalize-path";import{RpcWebSocketClient as i}from"rpc-websocket-client";import"cross-fetch/polyfill";import{Fetcher as t}from"openapi-typescript-fetch";function e(s,i,t,e){return new(t||(t=Promise))((function(o,n){function r(s){try{c(e.next(s))}catch(s){n(s)}}function l(s){try{c(e.throw(s))}catch(s){n(s)}}function c(s){var i;s.done?o(s.value):(i=s.value,i instanceof t?i:new t((function(s){s(i)}))).then(r,l)}c((e=e.apply(s,i||[])).next())}))}function o(s){let i="";const t="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",e=t.length;for(let o=0;o<s;o++)i+=t.charAt(Math.floor(Math.random()*e));return i}function n(s){return"fulfilled"===s.status}function r(s){if(!s.every((s=>"fulfilled"===s.status)))return s.reduce(((s,i,t)=>"rejected"===i.status?s+"\n"+`[${t}]: `+`${JSON.stringify(i)}`:s),"errors:\n")}function l(){let s,i;return{promise:new Promise(((t,e)=>{s=t,i=e})),reject:i,resolve:s}}var c;!function(s){s.Running="Running",s.Stopped="Stopped"}(c||(c={}));var h;!function(s){s.Create="Create",s.Write="Write",s.Remove="Remove",s.Rename="Rename",s.Chmod="Chmod"}(h||(h={}));class d{constructor(s,i){this.sessConn=s,this.path=i,this.listeners=new Set}start(){return e(this,void 0,void 0,(function*(){this.rpcSubscriptionID||(this.handleFilesystemEvents=this.handleFilesystemEvents.bind(this),this.rpcSubscriptionID=yield this.sessConn.subscribe("filesystem",this.handleFilesystemEvents,"watch",this.path))}))}stop(){return e(this,void 0,void 0,(function*(){this.rpcSubscriptionID&&(yield this.sessConn.unsubscribe(this.rpcSubscriptionID)),this.listeners.clear()}))}handleFilesystemEvents(s){this.listeners.forEach((i=>{i(s)}))}addEventListener(s){return this.listeners.add(s),{remove:()=>{this.listeners.delete(s)}}}}const a=t.for();a.configure({baseUrl:"https://ondevbook.com"});class u{constructor(s,i=!1){this.logID=s,this.isEnabled=i}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 p(s){return new Promise((i=>setTimeout(i,s)))}const v=a.path("/sessions").method("post").create({api_key:!0}),g=a.path("/sessions/{sessionID}/refresh").method("post").create({api_key:!0});class f extends class{constructor(s){this.opts=s,this.isOpen=!1,this.rpc=new i,this.subscribers=[],this.logger=new u("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 i=`${this.session.sessionID}-${this.session.clientID}.ondevbook.com`;return s?`${s}-${i}`:i}close(){var s,i,t;return e(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===(s=this.rpc.ws)||void 0===s||s.close(),null===(t=null===(i=this.opts)||void 0===i?void 0:i.onClose)||void 0===t||t.call(i),this.logger.log("Disconected from the session")}}))}open(){return e(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 v({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 v.Error){const i=s.getActualType();if(400===i.status)throw new Error(`Error creating session - (${i.status}) bad request: ${i.data.message}`);if(401===i.status)throw new Error(`Error creating session - (${i.status}) unauthenticated (you need to be authenticated to start an session with persistent edits): ${i.data.message}`);if(500===i.status)throw new Error(`Error creating session - (${i.status}) server error: ${i.data.message}`);throw s}}const s=this.getHostname(this.opts.__debug_port||49982);if(!s)throw new Error("Cannot get session's hostname");const i=`${"local"===this.opts.__debug_devEnv?"ws":"wss"}://${s}/ws`;this.rpc.onError((s=>{this.logger.log("Error in WS session:",this.session,s)}));let t,o,n=!1;const r=new Promise(((s,i)=>{t=()=>{n||(n=!0,s())},o=()=>{n||(n=!0,i())}}));this.rpc.onOpen((()=>{this.logger.log("Connected to session:",this.session),null==t||t()})),this.rpc.onClose((s=>e(this,void 0,void 0,(function*(){var t,e,n,r;if(this.logger.log("Closing WS connection to session:",this.session,s),this.isOpen){null===(e=(t=this.opts).onDisconnect)||void 0===e||e.call(t),yield p(100),this.logger.log("Reconnecting to session:",this.session);try{this.subscribers=[],yield this.rpc.connect(i),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==o||o()})))),this.rpc.onNotification.push(this.handleNotification.bind(this));try{this.logger.log("Connection to session:",this.session),yield this.rpc.connect(i)}catch(s){this.logger.log("Error connecting to session",this.session,s)}yield r}))}call(s,i,t){return e(this,void 0,void 0,(function*(){return this.rpc.call(`${s}_${i}`,t)}))}handleSubscriptions(...s){return e(this,void 0,void 0,(function*(){const i=yield Promise.allSettled(s);if(i.every((s=>"fulfilled"===s.status)))return i.map((s=>"fulfilled"===s.status?s.value:void 0));throw yield Promise.all(i.filter(n).map((s=>s.value?this.unsubscribe(s.value):void 0))),new Error(r(i))}))}unsubscribe(s){return e(this,void 0,void 0,(function*(){const i=this.subscribers.find((i=>i.subID===s));i&&(yield this.call(i.service,"unsubscribe",[i.subID]),this.subscribers=this.subscribers.filter((s=>s!==i)),this.logger.log(`Unsubscribed from "${i.service}"`))}))}subscribe(s,i,t,...o){return e(this,void 0,void 0,(function*(){const e=yield this.call(s,"subscribe",[t,...o]);if("string"!=typeof e)throw new Error(`Cannot subscribe to ${s}_${t}${o.length>0?" with params ["+o.join(", ")+"]":""}. Expected response should have been a subscription ID, instead we got ${JSON.stringify(e)}`);return this.subscribers.push({handler:i,service:s,subID:e}),this.logger.log(`Subscribed to "${s}_${t}"${o.length>0?" with params ["+o.join(", ")+"] and":""} with id "${e}"`),e}))}handleNotification(s){this.subscribers.filter((i=>{var t;return i.subID===(null===(t=s.params)||void 0===t?void 0:t.subscription)})).forEach((i=>{var t;return i.handler(null===(t=s.params)||void 0===t?void 0:t.result)}))}refresh(s){return e(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 p(5e3);try{this.logger.log(`Refreshed session "${s}"`),yield g({api_key:this.opts.apiKey,sessionID:s})}catch(i){if(i instanceof g.Error){const t=i.getActualType();if(404===t.status)return void this.logger.error(`Error refreshing session - (${t.status}): ${t.data.message}`);this.logger.error(`Refreshing session "${s}" failed - (${t.status})`)}}}}finally{this.logger.log(`Stopped refreshing session "${s}"`),this.close()}}))}}{constructor(s){super(s),this.codeSnippetOpts=s.codeSnippet}open(){const i=Object.create(null,{open:{get:()=>super.open}});var t,n,c,h;return e(this,void 0,void 0,(function*(){yield i.open.call(this),yield this.handleSubscriptions((null===(t=this.codeSnippetOpts)||void 0===t?void 0:t.onStateChange)?this.subscribe("codeSnippet",this.codeSnippetOpts.onStateChange,"state"):void 0,(null===(n=this.codeSnippetOpts)||void 0===n?void 0:n.onStderr)?this.subscribe("codeSnippet",this.codeSnippetOpts.onStderr,"stderr"):void 0,(null===(c=this.codeSnippetOpts)||void 0===c?void 0:c.onStdout)?this.subscribe("codeSnippet",this.codeSnippetOpts.onStdout,"stdout"):void 0,(null===(h=this.codeSnippetOpts)||void 0===h?void 0:h.onScanPorts)?this.subscribe("codeSnippet",this.codeSnippetOpts.onScanPorts,"scanOpenedPorts"):void 0),this.codeSnippet={run:(s,i={})=>e(this,void 0,void 0,(function*(){var t,e;const o=yield this.call("codeSnippet","run",[s,i]);return null===(e=null===(t=this.codeSnippetOpts)||void 0===t?void 0:t.onStateChange)||void 0===e||e.call(t,o),o})),stop:()=>e(this,void 0,void 0,(function*(){var s,i;const t=yield this.call("codeSnippet","stop");return null===(i=null===(s=this.codeSnippetOpts)||void 0===s?void 0:s.onStateChange)||void 0===i||i.call(s,t),t}))},this.filesystem={listAllFiles:s=>e(this,void 0,void 0,(function*(){return yield this.call("filesystem","listAllFiles",[s])})),readFile:s=>e(this,void 0,void 0,(function*(){return yield this.call("filesystem","readFile",[s])})),removeFile:s=>e(this,void 0,void 0,(function*(){yield this.call("filesystem","removeFile",[s])})),writeFile:(s,i)=>e(this,void 0,void 0,(function*(){yield this.call("filesystem","writeFile",[s,i])})),watch:i=>e(this,void 0,void 0,(function*(){const t=s(i);return new d(this,t)}))},this.terminal={createSession:({onData:s,onChildProcessesChange:i,size:t,onExit:n,terminalID:c=o(12)})=>e(this,void 0,void 0,(function*(){const{promise:o,resolve:h}=l(),[d,a,u]=yield this.handleSubscriptions(this.subscribe("terminal",s,"onData",c),this.subscribe("terminal",h,"onExit",c),i?this.subscribe("terminal",i,"onChildProcessesChange",c):void 0),{promise:p,resolve:v}=l();o.then((()=>e(this,void 0,void 0,(function*(){const s=r(yield Promise.allSettled([this.unsubscribe(a),this.unsubscribe(d),u?this.unsubscribe(u):void 0]));s&&this.logger.error(s),null==n||n(),v()}))));try{yield this.call("terminal","start",[c,t.cols,t.rows])}catch(s){throw h(),yield p,s}return{destroy:()=>e(this,void 0,void 0,(function*(){try{yield this.call("terminal","destroy",[c])}finally{h(),yield p}})),resize:({cols:s,rows:i})=>e(this,void 0,void 0,(function*(){yield this.call("terminal","resize",[c,s,i])})),sendData:s=>e(this,void 0,void 0,(function*(){yield this.call("terminal","data",[c,s])})),terminalID:c}})),killProcess:s=>e(this,void 0,void 0,(function*(){yield this.call("terminal","killProcess",[s])}))},this.process={start:({cmd:s,onStdout:i,onStderr:t,onExit:n,envVars:c={},rootdir:h="/",processID:d=o(12)})=>e(this,void 0,void 0,(function*(){const{promise:o,resolve:a}=l(),[u,p,v]=yield this.handleSubscriptions(this.subscribe("process",a,"onExit",d),i?this.subscribe("process",i,"onStdout",d):void 0,t?this.subscribe("process",t,"onStderr",d):void 0),{promise:g,resolve:f}=l();o.then((()=>e(this,void 0,void 0,(function*(){const s=r(yield Promise.allSettled([this.unsubscribe(u),p?this.unsubscribe(p):void 0,v?this.unsubscribe(v):void 0]));s&&this.logger.error(s),null==n||n(),f()}))));try{yield this.call("process","start",[d,s,c,h])}catch(s){throw a(),yield g,s}return{kill:()=>e(this,void 0,void 0,(function*(){try{yield this.call("process","kill",[d])}finally{a(),yield g}})),processID:d,sendStdin:s=>e(this,void 0,void 0,(function*(){yield this.call("process","stdin",[d,s])}))}}))}}))}}var b;!function(s){s.Stdout="Stdout",s.Stderr="Stderr"}(b||(b={}));export{c as CodeSnippetExecState,b as OutType,f as Session,a as api};
//# sourceMappingURL=index.js.map

@@ -0,3 +1,3 @@

import { EnvVars } from './envVars';
import { OutStderrResponse, OutStdoutResponse } from './out';
import { EnvVars } from './envVars';
export declare const codeSnippetService = "codeSnippet";

@@ -19,6 +19,6 @@ export declare enum CodeSnippetExecState {

export declare type CodeSnippetSubscriptionHandlerType = {
'state': CodeSnippetStateHandler;
'stderr': CodeSnippetStderrHandler;
'stdout': CodeSnippetStdoutHandler;
'scanOpenedPorts': ScanOpenedPortsHandler;
state: CodeSnippetStateHandler;
stderr: CodeSnippetStderrHandler;
stdout: CodeSnippetStdoutHandler;
scanOpenedPorts: ScanOpenedPortsHandler;
};

@@ -25,0 +25,0 @@ export interface CodeSnippetManager {

@@ -0,1 +1,2 @@

import FilesystemWatcher from "./filesystemWatcher";
export declare const filesystemService = "filesystem";

@@ -11,2 +12,3 @@ export interface FileInfo {

readonly listAllFiles: (path: string) => Promise<FileInfo[]>;
readonly watch: (path: string) => Promise<FilesystemWatcher>;
}

@@ -1,6 +0,6 @@

import SessionConnection, { SessionConnectionOpts } from './sessionConnection';
import { CodeSnippetManager, CodeSnippetStateHandler, CodeSnippetStderrHandler, CodeSnippetStdoutHandler, ScanOpenedPortsHandler } from './codeSnippet';
import { TerminalManager } from './terminal';
import { FilesystemManager } from './filesystem';
import { ProcessManager } from './process';
import SessionConnection, { SessionConnectionOpts } from './sessionConnection';
import { TerminalManager } from './terminal';
export interface CodeSnippetOpts {

@@ -16,3 +16,2 @@ onStateChange?: CodeSnippetStateHandler;

declare class Session extends SessionConnection {
private readonly codeSnippetOpts?;
codeSnippet?: CodeSnippetManager;

@@ -22,2 +21,3 @@ terminal?: TerminalManager;

process?: ProcessManager;
private readonly codeSnippetOpts?;
constructor(opts: SessionOpts);

@@ -24,0 +24,0 @@ open(): Promise<void>;

import { EnvVars } from './envVars';
import { OutStdoutResponse, OutStderrResponse } from './out';
import { OutStderrResponse, OutStdoutResponse } from './out';
export declare const processService = "process";

@@ -4,0 +4,0 @@ export interface Process {

import { components } from '../api';
import Logger from '../utils/logger';
import { processService } from './process';
import { codeSnippetService } from './codeSnippet';
import { filesystemService } from './filesystem';
import { processService } from './process';
import { terminalService } from './terminal';

@@ -32,8 +32,2 @@ declare type SubscriptionHandler = (result: any) => void;

constructor(opts: SessionConnectionOpts);
protected call(service: Service, method: string, params?: any[]): Promise<unknown>;
protected handleSubscriptions<T extends (ReturnType<SessionConnection['subscribe']> | undefined)[]>(...subs: T): Promise<{
[P in keyof T]: Awaited<T[P]>;
}>;
protected unsubscribe(subID: string): Promise<void>;
protected subscribe(service: Service, handler: SubscriptionHandler, method: string, ...params: any[]): Promise<string>;
/**

@@ -60,2 +54,8 @@ * Get the hostname for the session or for the specified session's port.

open(): Promise<void>;
call(service: Service, method: string, params?: any[]): Promise<unknown>;
handleSubscriptions<T extends (ReturnType<SessionConnection['subscribe']> | undefined)[]>(...subs: T): Promise<{
[P in keyof T]: Awaited<T[P]>;
}>;
unsubscribe(subID: string): Promise<void>;
subscribe(service: Service, handler: SubscriptionHandler, method: string, ...params: any[]): Promise<string>;
private handleNotification;

@@ -62,0 +62,0 @@ private refresh;

@@ -18,4 +18,4 @@ export declare const terminalService = "terminal";

readonly createSession: (opts: {
onData: (data: string) => void;
onExit?: () => void;
onData: (data: string) => void;
onChildProcessesChange?: (cps: ChildProcess[]) => void;

@@ -22,0 +22,0 @@ size: {

@@ -6,6 +6,6 @@ declare type LogID = string | (() => string);

constructor(logID: LogID, isEnabled?: boolean);
error(...args: any[]): void;
log(...args: any[]): void;
private id;
log(...args: any[]): void;
error(...args: any[]): void;
}
export default Logger;

@@ -5,5 +5,5 @@ export declare function assertFulfilled<T>(item: PromiseSettledResult<T>): item is PromiseFulfilledResult<T>;

export declare function createDeferredPromise<T = void>(): {
promise: Promise<T>;
reject: (reason?: unknown) => void;
resolve: (value: T) => void;
reject: (reason?: unknown) => void;
promise: Promise<T>;
};
import 'cross-fetch/polyfill';
import type { paths, components } from './schema.gen';
import type { components, paths } from './schema.gen';
declare const client: {

@@ -4,0 +4,0 @@ configure: (config: import("openapi-typescript-fetch/dist/cjs/types").FetchConfig) => void;

@@ -6,3 +6,3 @@ /**

export interface paths {
readonly "/health": {
readonly '/health': {
/** Health check */

@@ -13,7 +13,7 @@ readonly get: {

readonly 200: unknown;
readonly 401: components["responses"]["401"];
readonly 401: components['responses']['401'];
};
};
};
readonly "/sessions": {
readonly '/sessions': {
/** List all sessions */

@@ -23,3 +23,3 @@ readonly get: {

readonly query: {
readonly api_key?: components["parameters"]["apiKeyReq"];
readonly api_key?: components['parameters']['apiKeyReq'];
};

@@ -31,7 +31,7 @@ };

readonly content: {
readonly "application/json": readonly components["schemas"]["Session"][];
readonly 'application/json': readonly components['schemas']['Session'][];
};
};
readonly 401: components["responses"]["401"];
readonly 500: components["responses"]["500"];
readonly 401: components['responses']['401'];
readonly 500: components['responses']['500'];
};

@@ -43,3 +43,3 @@ };

readonly query: {
readonly api_key?: components["parameters"]["apiKeyOpt"];
readonly api_key?: components['parameters']['apiKeyOpt'];
};

@@ -51,12 +51,12 @@ };

readonly content: {
readonly "application/json": components["schemas"]["Session"];
readonly 'application/json': components['schemas']['Session'];
};
};
readonly 400: components["responses"]["400"];
readonly 401: components["responses"]["401"];
readonly 500: components["responses"]["500"];
readonly 400: components['responses']['400'];
readonly 401: components['responses']['401'];
readonly 500: components['responses']['500'];
};
readonly requestBody: {
readonly content: {
readonly "application/json": components["schemas"]["NewSession"];
readonly 'application/json': components['schemas']['NewSession'];
};

@@ -66,3 +66,3 @@ };

};
readonly "/sessions/{sessionID}": {
readonly '/sessions/{sessionID}': {
/** Delete a session on the server */

@@ -72,6 +72,6 @@ readonly delete: {

readonly query: {
readonly api_key?: components["parameters"]["apiKeyReq"];
readonly api_key?: components['parameters']['apiKeyReq'];
};
readonly path: {
readonly sessionID: components["parameters"]["sessionID"];
readonly sessionID: components['parameters']['sessionID'];
};

@@ -82,8 +82,8 @@ };

readonly 204: never;
readonly 401: components["responses"]["401"];
readonly 500: components["responses"]["500"];
readonly 401: components['responses']['401'];
readonly 500: components['responses']['500'];
};
};
};
readonly "/sessions/{sessionID}/refresh": {
readonly '/sessions/{sessionID}/refresh': {
/** Refresh the session extending its time to live */

@@ -93,6 +93,6 @@ readonly post: {

readonly query: {
readonly api_key?: components["parameters"]["apiKeyOpt"];
readonly api_key?: components['parameters']['apiKeyOpt'];
};
readonly path: {
readonly sessionID: components["parameters"]["sessionID"];
readonly sessionID: components['parameters']['sessionID'];
};

@@ -103,7 +103,7 @@ };

readonly 204: never;
readonly 401: components["responses"]["401"];
readonly 401: components['responses']['401'];
/** Error refreshing session - session not found */
readonly 404: {
readonly content: {
readonly "application/json": components["schemas"]["Error"];
readonly 'application/json': components['schemas']['Error'];
};

@@ -114,3 +114,3 @@ };

};
readonly "/envs/{codeSnippetID}": {
readonly '/envs/{codeSnippetID}': {
/** Create a new env for a code snippet */

@@ -120,6 +120,6 @@ readonly post: {

readonly query: {
readonly api_key?: components["parameters"]["apiKeyReq"];
readonly api_key?: components['parameters']['apiKeyReq'];
};
readonly path: {
readonly codeSnippetID: components["parameters"]["codeSnippetID"];
readonly codeSnippetID: components['parameters']['codeSnippetID'];
};

@@ -130,9 +130,9 @@ };

readonly 204: never;
readonly 400: components["responses"]["400"];
readonly 401: components["responses"]["401"];
readonly 500: components["responses"]["500"];
readonly 400: components['responses']['400'];
readonly 401: components['responses']['401'];
readonly 500: components['responses']['500'];
};
readonly requestBody: {
readonly content: {
readonly "application/json": components["schemas"]["NewEnvironment"];
readonly 'application/json': components['schemas']['NewEnvironment'];
};

@@ -145,6 +145,6 @@ };

readonly query: {
readonly api_key?: components["parameters"]["apiKeyReq"];
readonly api_key?: components['parameters']['apiKeyReq'];
};
readonly path: {
readonly codeSnippetID: components["parameters"]["codeSnippetID"];
readonly codeSnippetID: components['parameters']['codeSnippetID'];
};

@@ -158,7 +158,7 @@ };

readonly content: {
readonly "application/json": components["schemas"]["Error"];
readonly 'application/json': components['schemas']['Error'];
};
};
readonly 401: components["responses"]["401"];
readonly 500: components["responses"]["500"];
readonly 401: components['responses']['401'];
readonly 500: components['responses']['500'];
};

@@ -170,6 +170,6 @@ };

readonly query: {
readonly api_key?: components["parameters"]["apiKeyReq"];
readonly api_key?: components['parameters']['apiKeyReq'];
};
readonly path: {
readonly codeSnippetID: components["parameters"]["codeSnippetID"];
readonly codeSnippetID: components['parameters']['codeSnippetID'];
};

@@ -180,9 +180,9 @@ };

readonly 204: never;
readonly 400: components["responses"]["400"];
readonly 401: components["responses"]["401"];
readonly 500: components["responses"]["500"];
readonly 400: components['responses']['400'];
readonly 401: components['responses']['401'];
readonly 500: components['responses']['500'];
};
};
};
readonly "/envs/{codeSnippetID}/state": {
readonly '/envs/{codeSnippetID}/state': {
/** Update the state of the environment */

@@ -192,6 +192,6 @@ readonly put: {

readonly query: {
readonly api_key?: components["parameters"]["apiKeyReq"];
readonly api_key?: components['parameters']['apiKeyReq'];
};
readonly path: {
readonly codeSnippetID: components["parameters"]["codeSnippetID"];
readonly codeSnippetID: components['parameters']['codeSnippetID'];
};

@@ -202,8 +202,8 @@ };

readonly 204: never;
readonly 400: components["responses"]["400"];
readonly 401: components["responses"]["401"];
readonly 400: components['responses']['400'];
readonly 401: components['responses']['401'];
};
readonly requestBody: {
readonly content: {
readonly "application/json": components["schemas"]["EnvironmentStateUpdate"];
readonly 'application/json': components['schemas']['EnvironmentStateUpdate'];
};

@@ -213,3 +213,3 @@ };

};
readonly "/prisma-hub/db": {
readonly '/prisma-hub/db': {
/** Creates a new hub database */

@@ -221,6 +221,6 @@ readonly post: {

readonly content: {
readonly "application/json": components["schemas"]["HubDatabase"];
readonly 'application/json': components['schemas']['HubDatabase'];
};
};
readonly 500: components["responses"]["500"];
readonly 500: components['responses']['500'];
};

@@ -237,11 +237,11 @@ };

/** @enum {string} */
readonly Template: "Nodejs" | "Go" | "Bash" | "Rust" | "Python3" | "Typescript";
readonly Template: 'Nodejs' | 'Go' | 'Bash' | 'Rust' | 'Python3' | 'Typescript';
/** @enum {string} */
readonly EnvironmentState: "Building" | "Failed" | "Done";
readonly EnvironmentState: 'Building' | 'Failed' | 'Done';
readonly NewEnvironment: {
readonly template: components["schemas"]["Template"];
readonly template: components['schemas']['Template'];
readonly deps: readonly string[];
};
readonly EnvironmentStateUpdate: {
readonly state: components["schemas"]["EnvironmentState"];
readonly state: components['schemas']['EnvironmentState'];
};

@@ -281,3 +281,3 @@ readonly NewSession: {

readonly content: {
readonly "application/json": components["schemas"]["Error"];
readonly 'application/json': components['schemas']['Error'];
};

@@ -288,3 +288,3 @@ };

readonly content: {
readonly "application/json": components["schemas"]["Error"];
readonly 'application/json': components['schemas']['Error'];
};

@@ -295,3 +295,3 @@ };

readonly content: {
readonly "application/json": components["schemas"]["Error"];
readonly 'application/json': components['schemas']['Error'];
};

@@ -298,0 +298,0 @@ };

export { default as Session } from './session';
export type { SessionOpts, } from './session';
export { CodeSnippetExecState, } from './session/codeSnippet';
export type { SessionOpts } from './session';
export { CodeSnippetExecState } from './session/codeSnippet';
export type { CodeSnippetManager, CodeSnippetStateHandler, CodeSnippetStderrHandler, CodeSnippetStdoutHandler, CodeSnippetSubscriptionHandler, CodeSnippetSubscriptionHandlerType, OpenedPort, } from './session/codeSnippet';
export type { OutResponse, OutStderrResponse, OutStdoutResponse, } from './session/out';
export { OutType, } from './session/out';
export type { TerminalManager, TerminalSession, ChildProcess, } from './session/terminal';
export type { FilesystemManager, FileInfo, } from './session/filesystem';
export type { Process, ProcessManager, } from './session/process';
export type { EnvVars, } from './session/envVars';
export type { OutResponse, OutStderrResponse, OutStdoutResponse } from './session/out';
export { OutType } from './session/out';
export type { TerminalManager, TerminalSession, ChildProcess } from './session/terminal';
export type { FilesystemManager, FileInfo } from './session/filesystem';
export type { Process, ProcessManager } from './session/process';
export type { EnvVars } from './session/envVars';
export { default as api } from './api';
export type { components, paths, } from './api';
export type { components, paths } from './api';

@@ -1,2 +0,2 @@

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

@@ -0,3 +1,3 @@

import { EnvVars } from './envVars';
import { OutStderrResponse, OutStdoutResponse } from './out';
import { EnvVars } from './envVars';
export declare const codeSnippetService = "codeSnippet";

@@ -19,6 +19,6 @@ export declare enum CodeSnippetExecState {

export declare type CodeSnippetSubscriptionHandlerType = {
'state': CodeSnippetStateHandler;
'stderr': CodeSnippetStderrHandler;
'stdout': CodeSnippetStdoutHandler;
'scanOpenedPorts': ScanOpenedPortsHandler;
state: CodeSnippetStateHandler;
stderr: CodeSnippetStderrHandler;
stdout: CodeSnippetStdoutHandler;
scanOpenedPorts: ScanOpenedPortsHandler;
};

@@ -25,0 +25,0 @@ export interface CodeSnippetManager {

@@ -0,1 +1,2 @@

import FilesystemWatcher from "./filesystemWatcher";
export declare const filesystemService = "filesystem";

@@ -11,2 +12,3 @@ export interface FileInfo {

readonly listAllFiles: (path: string) => Promise<FileInfo[]>;
readonly watch: (path: string) => Promise<FilesystemWatcher>;
}

@@ -1,6 +0,6 @@

import SessionConnection, { SessionConnectionOpts } from './sessionConnection';
import { CodeSnippetManager, CodeSnippetStateHandler, CodeSnippetStderrHandler, CodeSnippetStdoutHandler, ScanOpenedPortsHandler } from './codeSnippet';
import { TerminalManager } from './terminal';
import { FilesystemManager } from './filesystem';
import { ProcessManager } from './process';
import SessionConnection, { SessionConnectionOpts } from './sessionConnection';
import { TerminalManager } from './terminal';
export interface CodeSnippetOpts {

@@ -16,3 +16,2 @@ onStateChange?: CodeSnippetStateHandler;

declare class Session extends SessionConnection {
private readonly codeSnippetOpts?;
codeSnippet?: CodeSnippetManager;

@@ -22,2 +21,3 @@ terminal?: TerminalManager;

process?: ProcessManager;
private readonly codeSnippetOpts?;
constructor(opts: SessionOpts);

@@ -24,0 +24,0 @@ open(): Promise<void>;

import { EnvVars } from './envVars';
import { OutStdoutResponse, OutStderrResponse } from './out';
import { OutStderrResponse, OutStdoutResponse } from './out';
export declare const processService = "process";

@@ -4,0 +4,0 @@ export interface Process {

import { components } from '../api';
import Logger from '../utils/logger';
import { processService } from './process';
import { codeSnippetService } from './codeSnippet';
import { filesystemService } from './filesystem';
import { processService } from './process';
import { terminalService } from './terminal';

@@ -32,8 +32,2 @@ declare type SubscriptionHandler = (result: any) => void;

constructor(opts: SessionConnectionOpts);
protected call(service: Service, method: string, params?: any[]): Promise<unknown>;
protected handleSubscriptions<T extends (ReturnType<SessionConnection['subscribe']> | undefined)[]>(...subs: T): Promise<{
[P in keyof T]: Awaited<T[P]>;
}>;
protected unsubscribe(subID: string): Promise<void>;
protected subscribe(service: Service, handler: SubscriptionHandler, method: string, ...params: any[]): Promise<string>;
/**

@@ -60,2 +54,8 @@ * Get the hostname for the session or for the specified session's port.

open(): Promise<void>;
call(service: Service, method: string, params?: any[]): Promise<unknown>;
handleSubscriptions<T extends (ReturnType<SessionConnection['subscribe']> | undefined)[]>(...subs: T): Promise<{
[P in keyof T]: Awaited<T[P]>;
}>;
unsubscribe(subID: string): Promise<void>;
subscribe(service: Service, handler: SubscriptionHandler, method: string, ...params: any[]): Promise<string>;
private handleNotification;

@@ -62,0 +62,0 @@ private refresh;

@@ -18,4 +18,4 @@ export declare const terminalService = "terminal";

readonly createSession: (opts: {
onData: (data: string) => void;
onExit?: () => void;
onData: (data: string) => void;
onChildProcessesChange?: (cps: ChildProcess[]) => void;

@@ -22,0 +22,0 @@ size: {

@@ -6,6 +6,6 @@ declare type LogID = string | (() => string);

constructor(logID: LogID, isEnabled?: boolean);
error(...args: any[]): void;
log(...args: any[]): void;
private id;
log(...args: any[]): void;
error(...args: any[]): void;
}
export default Logger;

@@ -5,5 +5,5 @@ export declare function assertFulfilled<T>(item: PromiseSettledResult<T>): item is PromiseFulfilledResult<T>;

export declare function createDeferredPromise<T = void>(): {
promise: Promise<T>;
reject: (reason?: unknown) => void;
resolve: (value: T) => void;
reject: (reason?: unknown) => void;
promise: Promise<T>;
};
{
"name": "@devbookhq/sdk",
"version": "2.5.4",
"description": "Devbook allows visitors of your docs to interact with and execute any code snippet or shell command in a private VM",
"version": "2.5.5",
"description": "SDK for managing Devbook sessions from JavaScript/TypeScript",
"homepage": "https://usedevbook.com",

@@ -26,12 +26,23 @@ "license": "SEE LICENSE IN LICENSE",

"run": "node test/run.mjs",
"fix": "npx eslint **/src/**/*.{ts,tsx,js} --fix",
"generate": "openapi-typescript shared/api/openapi.yml -x api_key --immutable-types --output src/api/schema.gen.ts"
"fix": "npx eslint **/src/**/*.{ts,js} --fix",
"format": "prettier --check --ignore-path .gitignore .",
"format:fix": "prettier --write --ignore-path .gitignore .",
"generate": "openapi-typescript shared/api/openapi.yml -x api_key --immutable-types --output src/api/schema.gen.ts",
"prepare": "husky install"
},
"devDependencies": {
"@rollup/plugin-node-resolve": "^14.1.0",
"@trivago/prettier-plugin-sort-imports": "^3.3.0",
"@types/node": "^18.7.23",
"@types/normalize-path": "^3.0.0",
"@typescript-eslint/eslint-plugin": "^5.38.1",
"@typescript-eslint/parser": "^5.38.1",
"eslint": "^8.24.0",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-unused-imports": "^2.0.0",
"husky": "^8.0.1",
"lint-staged": "^13.0.3",
"openapi-typescript": "^5.4.1",
"prettier": "^2.7.1",
"rollup": "^2.79.1",

@@ -65,5 +76,6 @@ "rollup-plugin-auto-external": "^2.0.0",

"cross-fetch": "^3.1.5",
"normalize-path": "^3.0.0",
"openapi-typescript-fetch": "^1.1.3",
"rpc-websocket-client": "^1.1.4"
}
}
}
# Devbook SDK
SDK for managing Devbook sessions from JavaScript/TypeScript.
## Installation
```sh

@@ -8,43 +11,165 @@ npm install @devbookhq/sdk

or
```sh
yarn add @devbookhq/sdk
```
## Usage
### JS/TS
```js
### Open a New Session
You **start a new session** by creating a `Session` instance and calling the `session.open` method.
`<code-snippet-id>` is the ID of the environment from Devbook backend.
When creating the `Session` you can **register handlers for various session events** by passing the handlers to the `Session` constructor.
You can **manually close** the session by calling `session.close`. If you need to open the session again after calling `session.close` you have to create a new `Session` object and call `session.open` on it.
```ts
import { Session } from '@devbookhq/sdk'
async function main() {
const session = new Session({
id: '<code-snippet-id>',
codeSnippet: {
onStateChange(state) {
console.log(state)
},
onStderr(stderr) {
console.log(stderr)
},
onStdout(stdout) {
console.log(stdout)
},
},
})
const session = new Session({
id: '<code-snippet-id>',
// Options for connection to a special session with persistent changes
editEnabled: false,
apiKey: undefined,
// Event handlers
codeSnippet: {
onStateChange: state => console.log(state),
onStderr: stderr => console.log(stderr),
onStdout: stdout => console.log(stdout),
},
onDisconnect: () => console.log('disconnect'),
onReconnect: () => console.log('reconnect'),
onClose: () => console.log('close'),
})
try {
await session.open()
await session.codeSnippet?.run('console.error("test")')
} catch (e) {
console.error(e)
}
}
await session.open()
main()
// If you don't need the session anymore:
await session.close()
```
> You shall not call any other methods on the `session` object before the `session.open` finishes. Before this method successfully finishes you are **not** connected to the actual session and the fields `session.codeSnippet`, `session.terminal`, `session.filesystem`, and `session.process` are `undefined`.
### Run Code Snippet
You can **run arbitrary code** with the runtime predefined in the Devbook env by calling `session.codeSnippet.run`.
You receive the `stderr`, `stdout`, and the information about the code execution from the `onStderr`, `onStdout`, and `onStateChange` handlers that you can pass to the `Session` constructor inside the `codeSnippet` object.
There can be only **one running code snippet at the same time** — you can stop the one that is currently running by calling `session.codeSnippet.stop`.
```ts
await session.codeSnippet.run('echo 2')
await session.codeSnippet.stop()
```
### Interact with the Filesystem
You can **list all the files and directories** in a specific directory by calling the `session.filesystem.listAllFiles` method.
You can **create a file and/or modify its content** by calling the `session.filesystem.writeFile` method.
You can **read the file's content** by calling the `session.filesystem.readFile` method. The method throws an error if the file is not found.
You can **remove file** by calling the `session.filesystem.removeFile` method.
```ts
const files = await session.filesystem.listAllFiles('/')
await session.filesystem.writeFile('/new.sh', 'echo 2')
const content = await session.filesystem.readFile('/new.sh')
await session.filesystem.removeFile('/new.sh')
```
### Start a Terminal
You can **start a new terminal** in the session by calling `session.terminal.createSession`.
> If you want to connect to the same terminal when you reconnect to a session you can use the `terminalID` option when creating the terminal. This is currently used for debugging purposes and when you connect to a special persistent session (`editEnabled` option when creating a new `Session`).
> If you are using frontend terminal component like [Xtermjs](https://github.com/xtermjs/xterm.js/) you want to pass the data from `onData` handler to Xtermjs and forward the data from Xtermjs to the `term.sendData` method.
If you start any **child processes in the terminal** you can use the `onChildProcessesChange` handler and see when they start and exit. You can **kill** the child processes with `session.terminal.killProcess` method.
You can **manually destroy** the terminal by calling `term.destroy`.
```ts
const term = await session.terminal.createSession({
onExit: () => console.log,
onData: (data) => console.log(data),
onChildProcessesChange?: (cps) => console.log(cps),
size: { cols: 10, rows: 20 },
terminalID: '<terminal-id>',
})
await term.destroy()
await term.resize({ cols: 1, rows: 1})
await term.sendData('\n')
console.log(term.terminalID)
await session.terminal.killProcess('<child-process-pid>')
```
### Start a Process
You can **start a new process** in the session by calling `session.process.start`. The only required option is the `cmd`, but you can also define the `rootdir` and `envVars` options that the command should be executed with.
> If you want to connect to the same process when you reconnect to a session you can use the `processID` option when starting the process. This is currently primarily used for debugging purposes.
You **send the stdin to the process** by calling `proc.sendStdin`.
You can **manually kill** the process by calling `proc.kill`.
```ts
const proc = await session.process.start({
cmd: 'echo 2',
onStdout: stdout => consoel.log(stdout),
onStderr: stderr => console.log(stderr),
onExit: () => console.log('exit'),
envVars: { ['ENV']: 'prod' },
rootdir: '/',
processID: '<process-id>',
})
await proc.kill()
await proc.sendStdin('\n')
console.log(proc.processID)
```
## Development
You generate the types for Devbook API from OpenAPI spec by calling:
```sh
npm run generate
```
You build the SDK by calling:
```sh
npm run build
```
You release a new version of the NPM package by tagging commit with a tag in the `v*.*.*` format and pushing in to GitHub.
### Subtrees
#### shared
Shared is a subtree made from https://github.com/devbookhq/shared repository.
The subtree commands you need for controling this repo are:
```bash

@@ -51,0 +176,0 @@ git subtree add --prefix shared https://github.com/devbookhq/shared.git master

import 'cross-fetch/polyfill'
import { Fetcher } from 'openapi-typescript-fetch'
import { SESSION_DOMAIN } from '../constants'
import type {
paths,
components,
} from './schema.gen'
import type { components, paths } from './schema.gen'

@@ -11,0 +7,0 @@ const client = Fetcher.for<paths>()

@@ -7,3 +7,3 @@ /**

export interface paths {
readonly "/health": {
readonly '/health': {
/** Health check */

@@ -13,8 +13,8 @@ readonly get: {

/** Request was successful */
readonly 200: unknown;
readonly 401: components["responses"]["401"];
};
};
};
readonly "/sessions": {
readonly 200: unknown
readonly 401: components['responses']['401']
}
}
}
readonly '/sessions': {
/** List all sessions */

@@ -24,5 +24,5 @@ readonly get: {

readonly query: {
readonly api_key?: components["parameters"]["apiKeyReq"];
};
};
readonly api_key?: components['parameters']['apiKeyReq']
}
}
readonly responses: {

@@ -32,9 +32,9 @@ /** Successfully returned all sessions */

readonly content: {
readonly "application/json": readonly components["schemas"]["Session"][];
};
};
readonly 401: components["responses"]["401"];
readonly 500: components["responses"]["500"];
};
};
readonly 'application/json': readonly components['schemas']['Session'][]
}
}
readonly 401: components['responses']['401']
readonly 500: components['responses']['500']
}
}
/** Create a session on the server */

@@ -44,5 +44,5 @@ readonly post: {

readonly query: {
readonly api_key?: components["parameters"]["apiKeyOpt"];
};
};
readonly api_key?: components['parameters']['apiKeyOpt']
}
}
readonly responses: {

@@ -52,17 +52,17 @@ /** Successfully created a session */

readonly content: {
readonly "application/json": components["schemas"]["Session"];
};
};
readonly 400: components["responses"]["400"];
readonly 401: components["responses"]["401"];
readonly 500: components["responses"]["500"];
};
readonly 'application/json': components['schemas']['Session']
}
}
readonly 400: components['responses']['400']
readonly 401: components['responses']['401']
readonly 500: components['responses']['500']
}
readonly requestBody: {
readonly content: {
readonly "application/json": components["schemas"]["NewSession"];
};
};
};
};
readonly "/sessions/{sessionID}": {
readonly 'application/json': components['schemas']['NewSession']
}
}
}
}
readonly '/sessions/{sessionID}': {
/** Delete a session on the server */

@@ -72,17 +72,17 @@ readonly delete: {

readonly query: {
readonly api_key?: components["parameters"]["apiKeyReq"];
};
readonly api_key?: components['parameters']['apiKeyReq']
}
readonly path: {
readonly sessionID: components["parameters"]["sessionID"];
};
};
readonly sessionID: components['parameters']['sessionID']
}
}
readonly responses: {
/** Successfully deleted the session */
readonly 204: never;
readonly 401: components["responses"]["401"];
readonly 500: components["responses"]["500"];
};
};
};
readonly "/sessions/{sessionID}/refresh": {
readonly 204: never
readonly 401: components['responses']['401']
readonly 500: components['responses']['500']
}
}
}
readonly '/sessions/{sessionID}/refresh': {
/** Refresh the session extending its time to live */

@@ -92,22 +92,22 @@ readonly post: {

readonly query: {
readonly api_key?: components["parameters"]["apiKeyOpt"];
};
readonly api_key?: components['parameters']['apiKeyOpt']
}
readonly path: {
readonly sessionID: components["parameters"]["sessionID"];
};
};
readonly sessionID: components['parameters']['sessionID']
}
}
readonly responses: {
/** Successfully refreshed the session */
readonly 204: never;
readonly 401: components["responses"]["401"];
readonly 204: never
readonly 401: components['responses']['401']
/** Error refreshing session - session not found */
readonly 404: {
readonly content: {
readonly "application/json": components["schemas"]["Error"];
};
};
};
};
};
readonly "/envs/{codeSnippetID}": {
readonly 'application/json': components['schemas']['Error']
}
}
}
}
}
readonly '/envs/{codeSnippetID}': {
/** Create a new env for a code snippet */

@@ -117,21 +117,21 @@ readonly post: {

readonly query: {
readonly api_key?: components["parameters"]["apiKeyReq"];
};
readonly api_key?: components['parameters']['apiKeyReq']
}
readonly path: {
readonly codeSnippetID: components["parameters"]["codeSnippetID"];
};
};
readonly codeSnippetID: components['parameters']['codeSnippetID']
}
}
readonly responses: {
/** Successfully created an environment */
readonly 204: never;
readonly 400: components["responses"]["400"];
readonly 401: components["responses"]["401"];
readonly 500: components["responses"]["500"];
};
readonly 204: never
readonly 400: components['responses']['400']
readonly 401: components['responses']['401']
readonly 500: components['responses']['500']
}
readonly requestBody: {
readonly content: {
readonly "application/json": components["schemas"]["NewEnvironment"];
};
};
};
readonly 'application/json': components['schemas']['NewEnvironment']
}
}
}
/** Delete the code snippet environment */

@@ -141,21 +141,21 @@ readonly delete: {

readonly query: {
readonly api_key?: components["parameters"]["apiKeyReq"];
};
readonly api_key?: components['parameters']['apiKeyReq']
}
readonly path: {
readonly codeSnippetID: components["parameters"]["codeSnippetID"];
};
};
readonly codeSnippetID: components['parameters']['codeSnippetID']
}
}
readonly responses: {
/** Successfully deleted the environment */
readonly 204: never;
readonly 204: never
/** Cannot delete the environment */
readonly 400: {
readonly content: {
readonly "application/json": components["schemas"]["Error"];
};
};
readonly 401: components["responses"]["401"];
readonly 500: components["responses"]["500"];
};
};
readonly 'application/json': components['schemas']['Error']
}
}
readonly 401: components['responses']['401']
readonly 500: components['responses']['500']
}
}
/** Update the environment of the code snippet to match the edit environment */

@@ -165,18 +165,18 @@ readonly patch: {

readonly query: {
readonly api_key?: components["parameters"]["apiKeyReq"];
};
readonly api_key?: components['parameters']['apiKeyReq']
}
readonly path: {
readonly codeSnippetID: components["parameters"]["codeSnippetID"];
};
};
readonly codeSnippetID: components['parameters']['codeSnippetID']
}
}
readonly responses: {
/** Updated the edit environment for code snippet */
readonly 204: never;
readonly 400: components["responses"]["400"];
readonly 401: components["responses"]["401"];
readonly 500: components["responses"]["500"];
};
};
};
readonly "/envs/{codeSnippetID}/state": {
readonly 204: never
readonly 400: components['responses']['400']
readonly 401: components['responses']['401']
readonly 500: components['responses']['500']
}
}
}
readonly '/envs/{codeSnippetID}/state': {
/** Update the state of the environment */

@@ -186,22 +186,22 @@ readonly put: {

readonly query: {
readonly api_key?: components["parameters"]["apiKeyReq"];
};
readonly api_key?: components['parameters']['apiKeyReq']
}
readonly path: {
readonly codeSnippetID: components["parameters"]["codeSnippetID"];
};
};
readonly codeSnippetID: components['parameters']['codeSnippetID']
}
}
readonly responses: {
/** Publishing the edit environment for code snippet */
readonly 204: never;
readonly 400: components["responses"]["400"];
readonly 401: components["responses"]["401"];
};
readonly 204: never
readonly 400: components['responses']['400']
readonly 401: components['responses']['401']
}
readonly requestBody: {
readonly content: {
readonly "application/json": components["schemas"]["EnvironmentStateUpdate"];
};
};
};
};
readonly "/prisma-hub/db": {
readonly 'application/json': components['schemas']['EnvironmentStateUpdate']
}
}
}
}
readonly '/prisma-hub/db': {
/** Creates a new hub database */

@@ -213,9 +213,9 @@ readonly post: {

readonly content: {
readonly "application/json": components["schemas"]["HubDatabase"];
};
};
readonly 500: components["responses"]["500"];
};
};
};
readonly 'application/json': components['schemas']['HubDatabase']
}
}
readonly 500: components['responses']['500']
}
}
}
}

@@ -227,21 +227,15 @@

/** @description Connectiong string to the database. */
readonly dbURL: string;
};
readonly dbURL: string
}
/** @enum {string} */
readonly Template:
| "Nodejs"
| "Go"
| "Bash"
| "Rust"
| "Python3"
| "Typescript";
readonly Template: 'Nodejs' | 'Go' | 'Bash' | 'Rust' | 'Python3' | 'Typescript'
/** @enum {string} */
readonly EnvironmentState: "Building" | "Failed" | "Done";
readonly EnvironmentState: 'Building' | 'Failed' | 'Done'
readonly NewEnvironment: {
readonly template: components["schemas"]["Template"];
readonly deps: readonly string[];
};
readonly template: components['schemas']['Template']
readonly deps: readonly string[]
}
readonly EnvironmentStateUpdate: {
readonly state: components["schemas"]["EnvironmentState"];
};
readonly state: components['schemas']['EnvironmentState']
}
readonly NewSession: {

@@ -252,16 +246,16 @@ /**

*/
readonly editEnabled?: boolean;
readonly editEnabled?: boolean
/** @description Identifier of a code snippet which which is the environment associated */
readonly codeSnippetID: string;
};
readonly codeSnippetID: string
}
readonly Session: {
/** @description Identifier of a code snippet which which is the environment associated */
readonly codeSnippetID: string;
readonly codeSnippetID: string
/** @description Information if the session is a shared persistent edit session */
readonly editEnabled: boolean;
readonly editEnabled: boolean
/** @description Identifier of the session */
readonly sessionID: string;
readonly sessionID: string
/** @description Identifier of the client */
readonly clientID: string;
};
readonly clientID: string
}
readonly Error: {

@@ -272,7 +266,7 @@ /**

*/
readonly code: number;
readonly code: number
/** @description Error */
readonly message: string;
};
};
readonly message: string
}
}
readonly responses: {

@@ -282,24 +276,24 @@ /** Bad request */

readonly content: {
readonly "application/json": components["schemas"]["Error"];
};
};
readonly 'application/json': components['schemas']['Error']
}
}
/** Authentication error */
readonly 401: {
readonly content: {
readonly "application/json": components["schemas"]["Error"];
};
};
readonly 'application/json': components['schemas']['Error']
}
}
/** Server error */
readonly 500: {
readonly content: {
readonly "application/json": components["schemas"]["Error"];
};
};
};
readonly 'application/json': components['schemas']['Error']
}
}
}
readonly parameters: {
readonly apiKeyOpt: string;
readonly apiKeyReq: string;
readonly codeSnippetID: string;
readonly sessionID: string;
};
readonly apiKeyOpt: string
readonly apiKeyReq: string
readonly codeSnippetID: string
readonly sessionID: string
}
}

@@ -306,0 +300,0 @@

export { default as Session } from './session'
export type { SessionOpts } from './session'
export { CodeSnippetExecState } from './session/codeSnippet'
export type {
SessionOpts,
} from './session'
export {
CodeSnippetExecState,
} from './session/codeSnippet'
export type {
CodeSnippetManager,

@@ -15,34 +11,11 @@ CodeSnippetStateHandler,

CodeSnippetSubscriptionHandlerType,
OpenedPort,
} from './session/codeSnippet'
export type {
OutResponse,
OutStderrResponse,
OutStdoutResponse,
} from './session/out'
export {
OutType,
} from './session/out'
export type {
TerminalManager,
TerminalSession,
ChildProcess,
} from './session/terminal'
export type {
FilesystemManager,
FileInfo,
} from './session/filesystem'
export type {
Process,
ProcessManager,
} from './session/process'
export type {
EnvVars,
} from './session/envVars'
export type { OutResponse, OutStderrResponse, OutStdoutResponse } from './session/out'
export { OutType } from './session/out'
export type { TerminalManager, TerminalSession, ChildProcess } from './session/terminal'
export type { FilesystemManager, FileInfo } from './session/filesystem'
export type { Process, ProcessManager } from './session/process'
export type { EnvVars } from './session/envVars'
export { default as api } from './api'
export type {
components,
paths,
} from './api'
export type { components, paths } from './api'

@@ -1,6 +0,3 @@

import {
OutStderrResponse,
OutStdoutResponse,
} from './out'
import { EnvVars } from './envVars'
import { OutStderrResponse, OutStdoutResponse } from './out'

@@ -26,12 +23,12 @@ export const codeSnippetService = 'codeSnippet'

export type CodeSnippetSubscriptionHandler =
CodeSnippetStateHandler |
CodeSnippetStderrHandler |
CodeSnippetStdoutHandler |
ScanOpenedPortsHandler
| CodeSnippetStateHandler
| CodeSnippetStderrHandler
| CodeSnippetStdoutHandler
| ScanOpenedPortsHandler
export type CodeSnippetSubscriptionHandlerType = {
'state': CodeSnippetStateHandler
'stderr': CodeSnippetStderrHandler
'stdout': CodeSnippetStdoutHandler
'scanOpenedPorts': ScanOpenedPortsHandler
state: CodeSnippetStateHandler
stderr: CodeSnippetStderrHandler
stdout: CodeSnippetStdoutHandler
scanOpenedPorts: ScanOpenedPortsHandler
}

@@ -38,0 +35,0 @@

@@ -1,1 +0,3 @@

export type EnvVars = { [key: string]: string }
export type EnvVars = {
[key: string]: string
}

@@ -0,1 +1,3 @@

import FilesystemWatcher from "./filesystemWatcher"
export const filesystemService = 'filesystem'

@@ -13,2 +15,3 @@

readonly listAllFiles: (path: string) => Promise<FileInfo[]>
readonly watch: (path: string) => Promise<FilesystemWatcher>
}

@@ -1,5 +0,6 @@

import SessionConnection, {
SessionConnectionOpts,
} from './sessionConnection'
import normalizePath from 'normalize-path'
import { id } from '../utils/id'
import { createDeferredPromise, formatSettledErrors } from '../utils/promise'
import {
CodeSnippetExecState,
CodeSnippetManager,

@@ -9,24 +10,14 @@ CodeSnippetStateHandler,

CodeSnippetStdoutHandler,
ScanOpenedPortsHandler,
codeSnippetService,
CodeSnippetExecState,
ScanOpenedPortsHandler,
} from './codeSnippet'
import {
TerminalManager,
terminalService,
} from './terminal'
import {
FileInfo,
FilesystemManager,
FileInfo,
filesystemService,
} from './filesystem'
import {
ProcessManager,
processService,
} from './process'
import { id } from '../utils/id'
import {
createDeferredPromise,
formatSettledErrors,
} from '../utils/promise'
import FilesystemWatcher from './filesystemWatcher'
import { ProcessManager, processService } from './process'
import SessionConnection, { SessionConnectionOpts } from './sessionConnection'
import { TerminalManager, terminalService } from './terminal'

@@ -45,4 +36,2 @@ export interface CodeSnippetOpts {

class Session extends SessionConnection {
private readonly codeSnippetOpts?: CodeSnippetOpts
codeSnippet?: CodeSnippetManager

@@ -53,2 +42,4 @@ terminal?: TerminalManager

private readonly codeSnippetOpts?: CodeSnippetOpts
constructor(opts: SessionOpts) {

@@ -73,3 +64,7 @@ super(opts)

this.codeSnippetOpts?.onScanPorts
? this.subscribe(codeSnippetService, this.codeSnippetOpts.onScanPorts, 'scanOpenedPorts')
? this.subscribe(
codeSnippetService,
this.codeSnippetOpts.onScanPorts,
'scanOpenedPorts',
)
: undefined,

@@ -81,3 +76,6 @@ )

run: async (code, envVars = {}) => {
const state = await this.call(codeSnippetService, 'run', [code, envVars]) as CodeSnippetExecState
const state = (await this.call(codeSnippetService, 'run', [
code,
envVars,
])) as CodeSnippetExecState
this.codeSnippetOpts?.onStateChange?.(state)

@@ -87,3 +85,6 @@ return state

stop: async () => {
const state = await this.call(codeSnippetService, 'stop') as CodeSnippetExecState
const state = (await this.call(
codeSnippetService,
'stop',
)) as CodeSnippetExecState
this.codeSnippetOpts?.onStateChange?.(state)

@@ -96,6 +97,9 @@ return state

this.filesystem = {
listAllFiles: async (path) => {
return await this.call(filesystemService, 'listAllFiles', [path]) as FileInfo[]
listAllFiles: async path => {
return (await this.call(filesystemService, 'listAllFiles', [path])) as FileInfo[]
},
removeFile: async (path) => {
readFile: async path => {
return (await this.call(filesystemService, 'readFile', [path])) as string
},
removeFile: async path => {
await this.call(filesystemService, 'removeFile', [path])

@@ -106,4 +110,5 @@ },

},
readFile: async (path) => {
return await this.call(filesystemService, 'readFile', [path]) as string
watch: async (path: string) => {
const npath = normalizePath(path)
return new FilesystemWatcher(this, npath)
},

@@ -114,5 +119,2 @@ }

this.terminal = {
killProcess: async (pid) => {
await this.call(terminalService, 'killProcess', [pid])
},
createSession: async ({

@@ -125,21 +127,20 @@ onData,

}) => {
const {
promise: terminalExited,
resolve: triggerExit,
} = createDeferredPromise()
const { promise: terminalExited, resolve: triggerExit } = createDeferredPromise()
const [
onDataSubID,
onExitSubID,
onChildProcessesChangeSubID,
] = await this.handleSubscriptions(
this.subscribe(terminalService, onData, 'onData', terminalID),
this.subscribe(terminalService, triggerExit, 'onExit', terminalID),
onChildProcessesChange ? this.subscribe(terminalService, onChildProcessesChange, 'onChildProcessesChange', terminalID) : undefined,
)
const [onDataSubID, onExitSubID, onChildProcessesChangeSubID] =
await this.handleSubscriptions(
this.subscribe(terminalService, onData, 'onData', terminalID),
this.subscribe(terminalService, triggerExit, 'onExit', terminalID),
onChildProcessesChange
? this.subscribe(
terminalService,
onChildProcessesChange,
'onChildProcessesChange',
terminalID,
)
: undefined,
)
const {
promise: unsubscribing,
resolve: handleFinishUnsubscribing,
} = createDeferredPromise()
const { promise: unsubscribing, resolve: handleFinishUnsubscribing } =
createDeferredPromise()

@@ -150,3 +151,5 @@ terminalExited.then(async () => {

this.unsubscribe(onDataSubID),
onChildProcessesChangeSubID ? this.unsubscribe(onChildProcessesChangeSubID) : undefined,
onChildProcessesChangeSubID
? this.unsubscribe(onChildProcessesChangeSubID)
: undefined,
])

@@ -163,3 +166,2 @@

try {

@@ -174,3 +176,2 @@ await this.call(terminalService, 'start', [terminalID, size.cols, size.rows])

return {
terminalID,
destroy: async () => {

@@ -184,10 +185,14 @@ try {

},
sendData: async (data) => {
await this.call(terminalService, 'data', [terminalID, data])
},
resize: async ({ cols, rows }) => {
await this.call(terminalService, 'resize', [terminalID, cols, rows])
},
sendData: async data => {
await this.call(terminalService, 'data', [terminalID, data])
},
terminalID,
}
}
},
killProcess: async pid => {
await this.call(terminalService, 'killProcess', [pid])
},
}

@@ -206,23 +211,18 @@

}) => {
const { promise: processExited, resolve: triggerExit } = createDeferredPromise()
const {
promise: processExited,
resolve: triggerExit,
} = createDeferredPromise()
const [onExitSubID, onStdoutSubID, onStderrSubID] =
await this.handleSubscriptions(
this.subscribe(processService, triggerExit, 'onExit', processID),
onStdout
? this.subscribe(processService, onStdout, 'onStdout', processID)
: undefined,
onStderr
? this.subscribe(processService, onStderr, 'onStderr', processID)
: undefined,
)
const [
onExitSubID,
onStdoutSubID,
onStderrSubID,
] = await this.handleSubscriptions(
this.subscribe(processService, triggerExit, 'onExit', processID),
onStdout ? this.subscribe(processService, onStdout, 'onStdout', processID) : undefined,
onStderr ? this.subscribe(processService, onStderr, 'onStderr', processID) : undefined,
)
const { promise: unsubscribing, resolve: handleFinishUnsubscribing } =
createDeferredPromise()
const {
promise: unsubscribing,
resolve: handleFinishUnsubscribing,
} = createDeferredPromise()
processExited.then(async () => {

@@ -253,3 +253,2 @@ const results = await Promise.allSettled([

return {
processID,
kill: async () => {

@@ -263,7 +262,8 @@ try {

},
sendStdin: async (data) => {
processID,
sendStdin: async data => {
await this.call(processService, 'stdin', [processID, data])
},
}
}
},
}

@@ -270,0 +270,0 @@ }

import { EnvVars } from './envVars'
import {
OutStdoutResponse,
OutStderrResponse,
} from './out'
import { OutStderrResponse, OutStdoutResponse } from './out'

@@ -17,10 +14,10 @@ export const processService = 'process'

readonly start: (opts: {
cmd: string,
onStdout?: (o: OutStdoutResponse) => void,
onStderr?: (o: OutStderrResponse) => void,
onExit?: () => void,
envVars?: EnvVars,
rootdir?: string,
processID?: string,
cmd: string
onStdout?: (o: OutStdoutResponse) => void
onStderr?: (o: OutStderrResponse) => void
onExit?: () => void
envVars?: EnvVars
rootdir?: string
processID?: string
}) => Promise<Process>
}

@@ -1,10 +0,4 @@

import {
RpcWebSocketClient,
IRpcNotification,
} from 'rpc-websocket-client'
import { IRpcNotification, RpcWebSocketClient } from 'rpc-websocket-client'
import api, {
components,
} from '../api'
import wait from '../utils/wait'
import api, { components } from '../api'
import {

@@ -18,10 +12,8 @@ SESSION_DOMAIN,

import Logger from '../utils/logger'
import { processService } from './process'
import { assertFulfilled, formatSettledErrors } from '../utils/promise'
import wait from '../utils/wait'
import { codeSnippetService } from './codeSnippet'
import { filesystemService } from './filesystem'
import { processService } from './process'
import { terminalService } from './terminal'
import {
assertFulfilled,
formatSettledErrors,
} from '../utils/promise'

@@ -31,3 +23,4 @@ // eslint-disable-next-line @typescript-eslint/no-explicit-any

type Service = typeof processService
type Service =
| typeof processService
| typeof codeSnippetService

@@ -61,3 +54,6 @@ | typeof filesystemService

const createSession = api.path('/sessions').method('post').create({ api_key: true })
const refreshSession = api.path('/sessions/{sessionID}/refresh').method('post').create({ api_key: true })
const refreshSession = api
.path('/sessions/{sessionID}/refresh')
.method('post')
.create({ api_key: true })

@@ -77,56 +73,7 @@ abstract class SessionConnection {

// eslint-disable-next-line @typescript-eslint/no-explicit-any
protected async call(service: Service, method: string, params?: any[]) {
return this.rpc.call(`${service}_${method}`, params)
}
protected async handleSubscriptions<T extends (ReturnType<SessionConnection['subscribe']> | undefined)[]>(...subs: T): Promise<{ [P in keyof T]: Awaited<T[P]> }> {
const results = await Promise.allSettled(subs)
if (results.every(r => r.status === 'fulfilled')) {
return results.map(r => r.status === 'fulfilled' ? r.value : undefined) as { [P in keyof T]: Awaited<T[P]> }
}
await Promise.all(
results
.filter(assertFulfilled)
.map(r => r.value ? this.unsubscribe(r.value) : undefined)
)
throw new Error(formatSettledErrors(results))
}
protected async unsubscribe(subID: string) {
const subscription = this.subscribers.find(s => s.subID === subID)
if (!subscription) return
await this.call(subscription.service, 'unsubscribe', [subscription.subID])
this.subscribers = this.subscribers.filter(s => s !== subscription)
this.logger.log(`Unsubscribed from "${subscription.service}"`)
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
protected async subscribe(service: Service, handler: SubscriptionHandler, method: string, ...params: any[]) {
const subID = await this.call(service, 'subscribe', [method, ...params])
if (typeof subID !== 'string') {
throw new Error(`Cannot subscribe to ${service}_${method}${params.length > 0 ? ' with params [' + params.join(', ') + ']' : ''}. Expected response should have been a subscription ID, instead we got ${JSON.stringify(subID)}`)
}
this.subscribers.push({
subID,
handler,
service,
})
this.logger.log(`Subscribed to "${service}_${method}"${params.length > 0 ? ' with params [' + params.join(', ') + '] and' : ''} with id "${subID}"`)
return subID
}
/**
* Get the hostname for the session or for the specified session's port.
*
*
* `getHostname` method requires `this` context - you may need to bind it.
*
*
* @param port specify if you want to connect to a specific port of the session

@@ -161,3 +108,3 @@ * @returns hostname of the session or session's port

* Close the connection to the session
*
*
* `close` method requires `this` context - you may need to bind it.

@@ -188,3 +135,3 @@ */

* Open a connection to a new session
*
*
* `open` method requires `this` context - you may need to bind it.

@@ -202,5 +149,5 @@ */

const res = await createSession({
api_key: this.opts.apiKey,
codeSnippetID: this.opts.id,
editEnabled: this.opts.editEnabled,
api_key: this.opts.apiKey,
})

@@ -215,9 +162,15 @@ this.session = res.data

if (error.status === 400) {
throw new Error(`Error creating session - (${error.status}) bad request: ${error.data.message}`)
throw new Error(
`Error creating session - (${error.status}) bad request: ${error.data.message}`,
)
}
if (error.status === 401) {
throw new Error(`Error creating session - (${error.status}) unauthenticated (you need to be authenticated to start an session with persistent edits): ${error.data.message}`)
throw new Error(
`Error creating session - (${error.status}) unauthenticated (you need to be authenticated to start an session with persistent edits): ${error.data.message}`,
)
}
if (error.status === 500) {
throw new Error(`Error creating session - (${error.status}) server error: ${error.data.message}`)
throw new Error(
`Error creating session - (${error.status}) server error: ${error.data.message}`,
)
}

@@ -232,3 +185,3 @@ throw e

if (!hostname) {
throw new Error('Cannot get session\'s hostname')
throw new Error("Cannot get session's hostname")
}

@@ -239,3 +192,3 @@

this.rpc.onError((e) => {
this.rpc.onError(e => {
this.logger.log('Error in WS session:', this.session, e)

@@ -266,3 +219,3 @@ })

this.rpc.onClose(async (e) => {
this.rpc.onClose(async e => {
this.logger.log('Closing WS connection to session:', this.session, e)

@@ -303,2 +256,75 @@ if (this.isOpen) {

// eslint-disable-next-line @typescript-eslint/no-explicit-any
async call(service: Service, method: string, params?: any[]) {
return this.rpc.call(`${service}_${method}`, params)
}
async handleSubscriptions<
T extends (ReturnType<SessionConnection['subscribe']> | undefined)[],
>(
...subs: T
): Promise<{
[P in keyof T]: Awaited<T[P]>
}> {
const results = await Promise.allSettled(subs)
if (results.every(r => r.status === 'fulfilled')) {
return results.map(r => (r.status === 'fulfilled' ? r.value : undefined)) as {
[P in keyof T]: Awaited<T[P]>
}
}
await Promise.all(
results
.filter(assertFulfilled)
.map(r => (r.value ? this.unsubscribe(r.value) : undefined)),
)
throw new Error(formatSettledErrors(results))
}
async unsubscribe(subID: string) {
const subscription = this.subscribers.find(s => s.subID === subID)
if (!subscription) return
await this.call(subscription.service, 'unsubscribe', [subscription.subID])
this.subscribers = this.subscribers.filter(s => s !== subscription)
this.logger.log(`Unsubscribed from "${subscription.service}"`)
}
// eslint-disable-next-line @typescript-eslint/no-explicit-any
async subscribe(
service: Service,
handler: SubscriptionHandler,
method: string,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
...params: any[]
) {
const subID = await this.call(service, 'subscribe', [method, ...params])
if (typeof subID !== 'string') {
throw new Error(
`Cannot subscribe to ${service}_${method}${
params.length > 0 ? ' with params [' + params.join(', ') + ']' : ''
}. Expected response should have been a subscription ID, instead we got ${JSON.stringify(
subID,
)}`,
)
}
this.subscribers.push({
handler,
service,
subID,
})
this.logger.log(
`Subscribed to "${service}_${method}"${
params.length > 0 ? ' with params [' + params.join(', ') + '] and' : ''
} with id "${subID}"`,
)
return subID
}
private handleNotification(data: IRpcNotification) {

@@ -326,4 +352,4 @@ this.subscribers

await refreshSession({
api_key: this.opts.apiKey,
sessionID,
api_key: this.opts.apiKey,
})

@@ -334,6 +360,10 @@ } catch (e) {

if (error.status === 404) {
this.logger.error(`Error refreshing session - (${error.status}): ${error.data.message}`)
this.logger.error(
`Error refreshing session - (${error.status}): ${error.data.message}`,
)
return
}
this.logger.error(`Refreshing session "${sessionID}" failed - (${error.status})`)
this.logger.error(
`Refreshing session "${sessionID}" failed - (${error.status})`,
)
}

@@ -340,0 +370,0 @@ }

@@ -5,3 +5,3 @@ export const terminalService = 'terminal'

readonly sendData: (data: string) => Promise<void>
readonly resize: ({ cols, rows }: { cols: number, rows: number }) => Promise<void>
readonly resize: ({ cols, rows }: { cols: number; rows: number }) => Promise<void>
readonly destroy: () => Promise<void>

@@ -19,8 +19,8 @@ readonly terminalID: string

readonly createSession: (opts: {
onExit?: () => void,
onData: (data: string) => void,
onChildProcessesChange?: (cps: ChildProcess[]) => void,
size: { cols: number, rows: number },
terminalID?: string,
onData: (data: string) => void
onExit?: () => void
onChildProcessesChange?: (cps: ChildProcess[]) => void
size: { cols: number; rows: number }
terminalID?: string
}) => Promise<TerminalSession>
}

@@ -6,6 +6,5 @@ export function id(length: number) {

for (let i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() *
charactersLength))
result += characters.charAt(Math.floor(Math.random() * charactersLength))
}
return result
}

@@ -5,10 +5,6 @@ /* eslint-disable @typescript-eslint/no-explicit-any */

class Logger {
constructor(
public readonly logID: LogID,
public readonly isEnabled = false
) { }
constructor(public readonly logID: LogID, public readonly isEnabled = false) {}
private id() {
if (typeof this.logID === 'function') return this.logID()
return this.logID
error(...args: any[]) {
console.error(`\x1b[31m[${this.id()} ERROR]\x1b[0m`, ...args)
}

@@ -22,4 +18,5 @@

error(...args: any[]) {
console.error(`\x1b[31m[${this.id()} ERROR]\x1b[0m`, ...args)
private id() {
if (typeof this.logID === 'function') return this.logID()
return this.logID
}

@@ -26,0 +23,0 @@ }

@@ -1,6 +0,10 @@

export function assertFulfilled<T>(item: PromiseSettledResult<T>): item is PromiseFulfilledResult<T> {
export function assertFulfilled<T>(
item: PromiseSettledResult<T>,
): item is PromiseFulfilledResult<T> {
return item.status === 'fulfilled'
}
export function assertRejected<T>(item: PromiseSettledResult<T>): item is PromiseRejectedResult {
export function assertRejected<T>(
item: PromiseSettledResult<T>,
): item is PromiseRejectedResult {
return item.status === 'rejected'

@@ -12,14 +16,13 @@ }

return settled
.reduce((prev, curr, i) => {
if (curr.status === 'rejected') {
return prev + '\n' + `[${i}]: ` + `${JSON.stringify(curr)}`
}
return prev
}, 'errors:\n')
return settled.reduce((prev, curr, i) => {
if (curr.status === 'rejected') {
return prev + '\n' + `[${i}]: ` + `${JSON.stringify(curr)}`
}
return prev
}, 'errors:\n')
}
export function createDeferredPromise<T = void>() {
let resolve: ((value: T) => void)
let reject: ((reason?: unknown) => void)
let resolve: (value: T) => void
let reject: (reason?: unknown) => void
const promise = new Promise<T>((res, rej) => {

@@ -31,8 +34,8 @@ resolve = res

return {
promise,
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
reject: reject!,
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
resolve: resolve!,
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
reject: reject!,
promise,
}
}
}

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

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc