websh is a javascript library to compose websites.

Usage no npm install needed!

<script type="module">
  import websh from 'https://cdn.skypack.dev/websh';


  • Web.sh

    This project aims to form kind of a shell for the web. It connects web-apps via window-messaging and let's you compose them like a shell-script. ** Tests

    +BEGIN_SRC sh

    npm install npm test


** API

All public symbols are exported from the Websh.js module in the root of the repository. All other modules should be considered private and subject to change. *** websh(driver?: Driver = inlineIframeDriver()): Websh

This function is the default export of the module and the
constructor for shell instances.  Each shell instance closes over
a driver that abstracts the mechanism to talk to an iframe
instance.  The default driver ~inlineIframeDriver~ creates a
full-screen iframe automatically and uses it as output.  If you
need more control over the creation and the style of the iframe
use the ~iframeDriver~.  The function returns a `Websh` instance
which is a function that expects the script as a string argument.

  import websh from './Websh.js'

  const sh = websh()
  sh('examples/input | examples/sed?regex=Foo&replace=bar | examples/cat')
    .then(output => {
      console.log(output)  // This is the received output

*** iframeDriver(iframeElement: DOMElement): Driver

This is a more flexible driver than the default
~inlineIframeDriver~ which let's you control the iframe yourself.

  import websh, { iframeDriver } from './Websh.js'

  const driver = iframeDriver(document.getElementById('my-iframe'))
  const sh = websh(driver)
  // ...

** Shell language

The shell-language is designed to be lightweight and easy to pick-up and learn. It's heavily inspired by unix shell scripts. *** Example

  # Pipelines
  https://mypage.com/prompt-input | https://secondpage.com/

  # Parameters

** Program interface

A script executes multiple so-called programs. These programs are web-apps that utilize the window messaging API to communicate with the system. *** Execution-flow

- The program is being loaded in an ~iframe~
- Then the content from the standard-input is being transmitted to
  the content-window of the iframe using the following command:

  #+BEGIN_SRC js
    iframe.contentWindow.postMessage(["stdin", [] /* Array of input lines */])

  This ~Array of input lines~ is an array filled with data from
  the output that the previous program generated.  If this is the
  first program being executed the ~Array of input lines~ is an
  empty array.
- The program should then use the input (or ignore if not need)
  and generate output using the ~print~ [[*System%20calls][system-call]]:

  #+BEGIN_SRC js
    window.parent.postMessage(["print", "Sample output" /* The output data */])

  The ~print~ system-call can be used multiple times to generate
  multiple "output lines".
- Once the program finishes it should use the ~exit~ system-call
  to handover the execution back to the system so that the next
  program can be called.

*** System calls

The system communication is handled by sys-call-like messages with
the following syntax:

#+BEGIN_SRC javascript
  ["print", { my: 'message' }]

- ~print(<chunks>, ...)~

  This command sends output chunks to the system.
- ~exit(<exitCode>)~

  This command exits the currently running process and hands-over
  an exit code.  A non-zero exit-code means failure and stops the
  execution of the script immediately.

** Security implications

  • Commands that operate on sensible user-data should use the second parameter of window.parent.postMessage() to avoid sending data to malicious targets. ** Known issues

  • Pipe characters in the query params to a command aren't handled correctly ** Missing features

  • The shell web-app should itself act like a program. E.g. sent the input to the first program and send back the output to the calling system. ** Thoughts / ideas

  • Environment variables: Global variables that are passed to each program