SendScript
Write JS code that you can run on servers, browsers or other clients.

SendScript leaves it up to you to choose HTTP, web-sockets or any other method of
communication between servers and clients that best fits your needs.
Socket example
For this example we'll use socket.io.
npm install --no-save socket.io socket.io-client
We use the --no-save
option because it's only for demonstration purposes.
Module
We write a simple module that only has an add function
export const add = (a, b) => a + b
Server
Here a simple module for running a socket.io server that runs SendScript programs.
import { Server } from 'socket.io'
import exec from '../exec.mjs'
import * as math from './math.mjs'
const server = new Server()
const port = process.env.PORT || 3000
server.on('connection', (socket) => {
socket.on('message', async (program, callback) => {
try {
const result = await exec(math, program)
callback(null, result)
} catch (error) {
callback(error)
}
})
})
server.listen(port)
process.title = 'sendscript'
Client
Now for a client that sends a program to the server.
import socketClient from 'socket.io-client'
import dsl from '../dsl.mjs'
const port = process.env.PORT || 3000
const client = socketClient(`http://localhost:${port}`)
const exec = program => {
return new Promise((resolve, reject) => {
client.emit('message', program, (error, result) => {
error
? reject(error)
: resolve(result)
})
})
}
const { add } = dsl(['add'], exec)
console.log(
await add(1, add(add(2, 3), 4))
)
process.exit(0)
Now we run this server and a client script.
node ./example/server.socket.io.mjs&
node ./example/client.socket.io.mjs
pkill sendscript
10
Reference
SendScript is essentially a way to serialize a program to then send over the wire
and execute it somewhere else.
We only have two modules. One that helps you write programs that can be sent
over the wire and another for running that program.
sendscript/dsl.mjs
The dsl module exports a function that takes two arguments.
- The schema, which represents the values that are available.
- The function that will be called with the serializable version of the
program.
It returns an object that contains functions which are defined in the schema.
These functions are a JavaScript DSL for writing programs that can be sent to
a server.
import dsl from './dsl.mjs'
const { add, subtract } = dsl(
['add', 'subtract'],
serializableProgram => sendSomewhereToBeExecuted(serializableProgram)
)
await add(1, 2)
await subtract(1, 2)
await add(1, subtract(2, 3))
The add and subtract functions are thennable. The execute function is called as
soon as await or .then
is used.
Notice that you do not have to await the subtract call. You only need to
await when you want to execute the program.
This DSL is composable and wrappable.
sendscript/exec.mjs
The exec function takes an environment object and any valid SendScript program.
import exec from './exec.mjs'
exec({
add: (a, b) => a + b,
subtract: (a, b) => a - b
}, ['add', 1, [subtract, 1, 2]])
The array you see here is the LISP that SendScript uses to represent programs.
You could use SendScript without knowing the details of how the LISP works. It is an
implementation detail and might change over time.
Tests
Tests with 100% code coverage.
npx c8 --100 npm t -- -R classic
> sendscript@0.0.0 test
> tap *.test.mjs --no-cov -R classic
curry.test.mjs ........................................ 4/4
dsl.test.mjs .......................................... 5/5
exec.test.mjs ....................................... 15/15
total ............................................... 24/24
24 passing (400.194ms)
ok
-----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
-----------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
curry.mjs | 100 | 100 | 100 | 100 |
debug.mjs | 100 | 100 | 100 | 100 |
dsl.mjs | 100 | 100 | 100 | 100 |
error.mjs | 100 | 100 | 100 | 100 |
exec.mjs | 100 | 100 | 100 | 100 |
-----------|---------|----------|---------|---------|-------------------
Formatting
Standard because no config.
npx standard
Changelog
The changelog is generated using the useful
auto-changelog project.
npx auto-changelog -p
License
See the LICENSE.txt file for details.