sendscript 1.0.3 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,25 @@
1
+ name: Publish Package
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - 'v*'
7
+
8
+ permissions:
9
+ id-token: write # Required for OIDC
10
+ contents: read
11
+
12
+ jobs:
13
+ publish:
14
+ runs-on: ubuntu-latest
15
+ steps:
16
+ - uses: actions/checkout@v6
17
+
18
+ - uses: actions/setup-node@v6
19
+ with:
20
+ node-version: '24'
21
+ registry-url: 'https://registry.npmjs.org'
22
+ - run: npm ci
23
+ - run: npm run build --if-present
24
+ - run: npm test
25
+ - run: npm publish
package/CHANGELOG.md CHANGED
@@ -4,8 +4,29 @@ All notable changes to this project will be documented in this file. Dates are d
4
4
 
5
5
  Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
6
6
 
7
+ #### [v1.0.6](https://github.com/bas080/sendscript/compare/v1.0.5...v1.0.6)
8
+
9
+ - Update tap to 21.6.3 [`c1769d9`](https://github.com/bas080/sendscript/commit/c1769d9a24148e63d27b0e5a7456213bec64763e)
10
+ - Add introduction to readme [`a21a494`](https://github.com/bas080/sendscript/commit/a21a494616d5ad8c99f9a2904ef529ea85104a99)
11
+
12
+ #### [v1.0.5](https://github.com/bas080/sendscript/compare/v1.0.4...v1.0.5)
13
+
14
+ > 5 April 2026
15
+
16
+ - Add publish to npm workflow [`aaaa97d`](https://github.com/bas080/sendscript/commit/aaaa97d1024d6b5ed574a2cd103035949ec8280d)
17
+
18
+ #### [v1.0.4](https://github.com/bas080/sendscript/compare/v1.0.3...v1.0.4)
19
+
20
+ > 5 April 2026
21
+
22
+ - Update tap and debug deps [`bd28139`](https://github.com/bas080/sendscript/commit/bd28139b633a04ac1b705b71c6bd24e98655d3b4)
23
+ - Give example its own package.json [`4307988`](https://github.com/bas080/sendscript/commit/4307988467d866f461f27c42a92a304bfe7617d6)
24
+ - Add cli with repl command [`d811fcb`](https://github.com/bas080/sendscript/commit/d811fcbf2d95fe8729c3782aceec6aea3bff1367)
25
+
7
26
  #### [v1.0.3](https://github.com/bas080/sendscript/compare/v1.0.2...v1.0.3)
8
27
 
28
+ > 4 May 2025
29
+
9
30
  - Make examples import module not relative file [`0a5e1c8`](https://github.com/bas080/sendscript/commit/0a5e1c8ec2527d63d1e248f63568668058de388c)
10
31
  - Fix repository url in package.json [`d4f1e79`](https://github.com/bas080/sendscript/commit/d4f1e79a75daea28905c9b680b31e517526588d3)
11
32
 
@@ -0,0 +1,24 @@
1
+ # Contributing
2
+
3
+
4
+ For the README.mz examples to work we need sendscript to be linked.
5
+
6
+ ```bash bash > /dev/null
7
+ set -e
8
+
9
+ npm link
10
+ npm link sendscript
11
+ cd ./example
12
+ npm ci
13
+ npm link sendscript
14
+ ```
15
+
16
+ Generate the README from the mz file.
17
+
18
+ ```bash bash
19
+ markatzea ./README.mz | tee ./README.md
20
+
21
+ npx markdown-toc -i README.md
22
+
23
+ git add *.md ./example
24
+ ```
package/README.md CHANGED
@@ -9,10 +9,12 @@ Write JS code that you can run on servers, browsers or other clients.
9
9
 
10
10
  <!-- toc -->
11
11
 
12
+ - [Introduction](#introduction)
12
13
  - [Socket example](#socket-example)
13
14
  * [Module](#module)
14
15
  * [Server](#server)
15
16
  * [Client](#client)
17
+ - [Repl](#repl)
16
18
  - [Async/Await](#asyncawait)
17
19
  - [TypeScript](#typescript)
18
20
  - [Tests](#tests)
@@ -24,6 +26,75 @@ Write JS code that you can run on servers, browsers or other clients.
24
26
 
25
27
  <!-- tocstop -->
26
28
 
29
+ ## Introduction
30
+
31
+ There has been interest in improving APIs by allowing aggregations in a
32
+ single request. Examples include
33
+
34
+ - [JSON-RPC](https://json-rpc.dev/) which allows you to do multiple requests
35
+ but it does not allow you to compose the return value of one endpoint to be the
36
+ input/arguments of another.
37
+
38
+ - [GraphQL](https://graphql.org/) is very cool but also introduces a new languages and the
39
+ tooling that is required to wield it.
40
+
41
+ What SendScript attempts is to allow for very expressive queries and mutations to be performed
42
+ that read and write like ordinary JS. That means that the queries and complete programs
43
+ that are sent to the server from a client can also just run on the server as is. The only
44
+ limitation being the serialization which by default is limited by JSON and could be extended by
45
+ using more advanced (de)serialization libraries.
46
+
47
+ SendScript produces an intermediate JSON representation of the program. Let's see what that looks like.
48
+
49
+ ```js
50
+ import stringify from 'sendscript/stringify.mjs'
51
+ import module from 'sendscript/module.mjs'
52
+
53
+ const { add } = module(['add'])
54
+
55
+ console.log(stringify(add(1,2)))
56
+ ```
57
+ ```json
58
+ ["call",["ref","add"],[1,2]]
59
+ ```
60
+
61
+ We can then parse that JSON and it will evaluate down to a value.
62
+
63
+ ```js
64
+ import Parse from 'sendscript/parse.mjs'
65
+
66
+ const module = {
67
+ add(a, b) {
68
+ return a + b
69
+ }
70
+ }
71
+
72
+ const parse = Parse(module)
73
+
74
+ const program = '["call",["ref","add"],[1,2]]'
75
+
76
+ console.log(parse(program))
77
+ ```
78
+ ```json
79
+ 3
80
+ ```
81
+
82
+ SendScript does more than a simple function call. It supports function
83
+ composition and even await.
84
+
85
+ This package is nothing more than the absolute core of sendscript. It
86
+ includes:
87
+
88
+ - The `module` function to create stubs to write the programs.
89
+ - `stringify` which takes the program and returns a JSON string.
90
+ - `parse` which takes the `stringify` JSON string and a real module and returns the result.
91
+
92
+ The naming could use more love and there are many things to solve either in the core or around it.
93
+ Things like supporting more complex (de)serializers, errors and maybe mixing client functions with
94
+ sendscript programs. Contact me if I have piqued your interest.
95
+
96
+ ---
97
+
27
98
  SendScript leaves it up to you to choose HTTP, web-sockets or any other
28
99
  method of communication between servers and clients that best fits your
29
100
  needs.
@@ -32,16 +103,6 @@ needs.
32
103
 
33
104
  For this example we'll use [socket.io][socket.io].
34
105
 
35
- ```bash
36
- npm link &&
37
- npm install --no-save \
38
- socket.io \
39
- socket.io-client \
40
- sendscript
41
- ```
42
-
43
- > We use the `--no-save` option because it's only for demonstration purposes.
44
-
45
106
  ### Module
46
107
 
47
108
  We write a simple module.
@@ -140,6 +201,12 @@ pkill sendscript
140
201
  Result: 100
141
202
  ```
142
203
 
204
+ ## Repl
205
+
206
+ Sendscript ships with a barebones (no-dependencies) node-repl script. One can run it by simply typing `sendscript` in their console.
207
+
208
+ > Use the `DEBUG='*'` to enable all logs or `DEBUG='sendscript:*'` for printingonly sendscript logs.
209
+
143
210
  ## Async/Await
144
211
 
145
212
  SendScript supports async/await seamlessly within a single request. This avoids the performance pitfalls of waterfall-style messaging, which can be especially slow on high-latency networks.
@@ -226,7 +293,7 @@ npm install --no-save \
226
293
  typedoc \
227
294
  typedoc-plugin-markdown
228
295
 
229
- typedoc --plugin typedoc-plugin-markdown --out ./example/typescript/docs ./example/typescript/math.ts
296
+ npx typedoc --plugin typedoc-plugin-markdown --out ./example/typescript/docs ./example/typescript/math.ts
230
297
  ```
231
298
 
232
299
  You can see the docs [here](./example/typescript/docs/globals.md)
@@ -246,11 +313,11 @@ npm t -- report text-summary
246
313
  ```
247
314
  ```
248
315
 
249
- > sendscript@1.0.3 test
316
+ > sendscript@1.0.6 test
250
317
  > tap -R silent
251
318
 
252
319
 
253
- > sendscript@1.0.3 test
320
+ > sendscript@1.0.6 test
254
321
  > tap report text-summary
255
322
 
256
323
 
package/README.mz CHANGED
@@ -9,6 +9,69 @@ Write JS code that you can run on servers, browsers or other clients.
9
9
 
10
10
  <!-- toc -->
11
11
 
12
+ ## Introduction
13
+
14
+ There has been interest in improving APIs by allowing aggregations in a
15
+ single request. Examples include
16
+
17
+ - [JSON-RPC](https://json-rpc.dev/) which allows you to do multiple requests
18
+ but it does not allow you to compose the return value of one endpoint to be the
19
+ input/arguments of another.
20
+
21
+ - [GraphQL](https://graphql.org/) is very cool but also introduces a new languages and the
22
+ tooling that is required to wield it.
23
+
24
+ What SendScript attempts is to allow for very expressive queries and mutations to be performed
25
+ that read and write like ordinary JS. That means that the queries and complete programs
26
+ that are sent to the server from a client can also just run on the server as is. The only
27
+ limitation being the serialization which by default is limited by JSON and could be extended by
28
+ using more advanced (de)serialization libraries.
29
+
30
+ SendScript produces an intermediate JSON representation of the program. Let's see what that looks like.
31
+
32
+ ```js|json node --input-type=module | tee /tmp/sendscript.json
33
+ import stringify from 'sendscript/stringify.mjs'
34
+ import module from 'sendscript/module.mjs'
35
+
36
+ const { add } = module(['add'])
37
+
38
+ console.log(stringify(add(1,2)))
39
+ ```
40
+
41
+ We can then parse that JSON and it will evaluate down to a value.
42
+
43
+ ```js|json node --input-type=module
44
+ import Parse from 'sendscript/parse.mjs'
45
+
46
+ const module = {
47
+ add(a, b) {
48
+ return a + b
49
+ }
50
+ }
51
+
52
+ const parse = Parse(module)
53
+
54
+ const program = '["call",["ref","add"],[1,2]]'
55
+
56
+ console.log(parse(program))
57
+ ```
58
+
59
+ SendScript does more than a simple function call. It supports function
60
+ composition and even await.
61
+
62
+ This package is nothing more than the absolute core of sendscript. It
63
+ includes:
64
+
65
+ - The `module` function to create stubs to write the programs.
66
+ - `stringify` which takes the program and returns a JSON string.
67
+ - `parse` which takes the `stringify` JSON string and a real module and returns the result.
68
+
69
+ The naming could use more love and there are many things to solve either in the core or around it.
70
+ Things like supporting more complex (de)serializers, errors and maybe mixing client functions with
71
+ sendscript programs. Contact me if I have piqued your interest.
72
+
73
+ ---
74
+
12
75
  SendScript leaves it up to you to choose HTTP, web-sockets or any other
13
76
  method of communication between servers and clients that best fits your
14
77
  needs.
@@ -17,16 +80,6 @@ needs.
17
80
 
18
81
  For this example we'll use [socket.io][socket.io].
19
82
 
20
- ```bash bash > /dev/null
21
- npm link &&
22
- npm install --no-save \
23
- socket.io \
24
- socket.io-client \
25
- sendscript
26
- ```
27
-
28
- > We use the `--no-save` option because it's only for demonstration purposes.
29
-
30
83
  ### Module
31
84
 
32
85
  We write a simple module.
@@ -122,6 +175,12 @@ node ./example/client.socket.io.mjs
122
175
  pkill sendscript
123
176
  ```
124
177
 
178
+ ## Repl
179
+
180
+ Sendscript ships with a barebones (no-dependencies) node-repl script. One can run it by simply typing `sendscript` in their console.
181
+
182
+ > Use the `DEBUG='*'` to enable all logs or `DEBUG='sendscript:*'` for printingonly sendscript logs.
183
+
125
184
  ## Async/Await
126
185
 
127
186
  SendScript supports async/await seamlessly within a single request. This avoids the performance pitfalls of waterfall-style messaging, which can be especially slow on high-latency networks.
@@ -177,7 +236,7 @@ npm install --no-save \
177
236
  typedoc \
178
237
  typedoc-plugin-markdown
179
238
 
180
- typedoc --plugin typedoc-plugin-markdown --out ./example/typescript/docs ./example/typescript/math.ts
239
+ npx typedoc --plugin typedoc-plugin-markdown --out ./example/typescript/docs ./example/typescript/math.ts
181
240
  ```
182
241
 
183
242
  You can see the docs [here](./example/typescript/docs/globals.md)
package/cli.mjs ADDED
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+
3
+ import path from 'path'
4
+ import { pathToFileURL } from 'url'
5
+ import stringify from './stringify.mjs'
6
+ import repl from './repl.mjs'
7
+ import Parse from './parse.mjs'
8
+
9
+ const modulePath = pathToFileURL(path.resolve(process.cwd(), process.argv[2])).href
10
+ const mod = await import(modulePath)
11
+ const parse = Parse(mod)
12
+
13
+ const send = program => parse(stringify(program))
14
+
15
+ repl(send, mod)
@@ -0,0 +1,3 @@
1
+ # Sendscript Example
2
+
3
+ Showcases the use of sendscript in combination with TypeScript.
@@ -0,0 +1,242 @@
1
+ {
2
+ "name": "sendscript-example",
3
+ "lockfileVersion": 3,
4
+ "requires": true,
5
+ "packages": {
6
+ "": {
7
+ "name": "sendscript-example",
8
+ "dependencies": {
9
+ "socket.io": "^4.8.1",
10
+ "socket.io-client": "^4.8.1"
11
+ }
12
+ },
13
+ "node_modules/@socket.io/component-emitter": {
14
+ "version": "3.1.2",
15
+ "license": "MIT"
16
+ },
17
+ "node_modules/@types/cors": {
18
+ "version": "2.8.18",
19
+ "license": "MIT",
20
+ "dependencies": {
21
+ "@types/node": "*"
22
+ }
23
+ },
24
+ "node_modules/@types/node": {
25
+ "version": "22.15.17",
26
+ "license": "MIT",
27
+ "dependencies": {
28
+ "undici-types": "~6.21.0"
29
+ }
30
+ },
31
+ "node_modules/accepts": {
32
+ "version": "1.3.8",
33
+ "license": "MIT",
34
+ "dependencies": {
35
+ "mime-types": "~2.1.34",
36
+ "negotiator": "0.6.3"
37
+ },
38
+ "engines": {
39
+ "node": ">= 0.6"
40
+ }
41
+ },
42
+ "node_modules/base64id": {
43
+ "version": "2.0.0",
44
+ "license": "MIT",
45
+ "engines": {
46
+ "node": "^4.5.0 || >= 5.9"
47
+ }
48
+ },
49
+ "node_modules/cookie": {
50
+ "version": "0.7.2",
51
+ "license": "MIT",
52
+ "engines": {
53
+ "node": ">= 0.6"
54
+ }
55
+ },
56
+ "node_modules/cors": {
57
+ "version": "2.8.5",
58
+ "license": "MIT",
59
+ "dependencies": {
60
+ "object-assign": "^4",
61
+ "vary": "^1"
62
+ },
63
+ "engines": {
64
+ "node": ">= 0.10"
65
+ }
66
+ },
67
+ "node_modules/debug": {
68
+ "version": "4.3.7",
69
+ "license": "MIT",
70
+ "dependencies": {
71
+ "ms": "^2.1.3"
72
+ },
73
+ "engines": {
74
+ "node": ">=6.0"
75
+ },
76
+ "peerDependenciesMeta": {
77
+ "supports-color": {
78
+ "optional": true
79
+ }
80
+ }
81
+ },
82
+ "node_modules/engine.io": {
83
+ "version": "6.6.4",
84
+ "license": "MIT",
85
+ "dependencies": {
86
+ "@types/cors": "^2.8.12",
87
+ "@types/node": ">=10.0.0",
88
+ "accepts": "~1.3.4",
89
+ "base64id": "2.0.0",
90
+ "cookie": "~0.7.2",
91
+ "cors": "~2.8.5",
92
+ "debug": "~4.3.1",
93
+ "engine.io-parser": "~5.2.1",
94
+ "ws": "~8.17.1"
95
+ },
96
+ "engines": {
97
+ "node": ">=10.2.0"
98
+ }
99
+ },
100
+ "node_modules/engine.io-client": {
101
+ "version": "6.6.3",
102
+ "license": "MIT",
103
+ "dependencies": {
104
+ "@socket.io/component-emitter": "~3.1.0",
105
+ "debug": "~4.3.1",
106
+ "engine.io-parser": "~5.2.1",
107
+ "ws": "~8.17.1",
108
+ "xmlhttprequest-ssl": "~2.1.1"
109
+ }
110
+ },
111
+ "node_modules/engine.io-parser": {
112
+ "version": "5.2.3",
113
+ "license": "MIT",
114
+ "engines": {
115
+ "node": ">=10.0.0"
116
+ }
117
+ },
118
+ "node_modules/mime-db": {
119
+ "version": "1.52.0",
120
+ "license": "MIT",
121
+ "engines": {
122
+ "node": ">= 0.6"
123
+ }
124
+ },
125
+ "node_modules/mime-types": {
126
+ "version": "2.1.35",
127
+ "license": "MIT",
128
+ "dependencies": {
129
+ "mime-db": "1.52.0"
130
+ },
131
+ "engines": {
132
+ "node": ">= 0.6"
133
+ }
134
+ },
135
+ "node_modules/ms": {
136
+ "version": "2.1.3",
137
+ "license": "MIT"
138
+ },
139
+ "node_modules/negotiator": {
140
+ "version": "0.6.3",
141
+ "license": "MIT",
142
+ "engines": {
143
+ "node": ">= 0.6"
144
+ }
145
+ },
146
+ "node_modules/object-assign": {
147
+ "version": "4.1.1",
148
+ "license": "MIT",
149
+ "engines": {
150
+ "node": ">=0.10.0"
151
+ }
152
+ },
153
+ "node_modules/socket.io": {
154
+ "version": "4.8.1",
155
+ "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz",
156
+ "integrity": "sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==",
157
+ "license": "MIT",
158
+ "dependencies": {
159
+ "accepts": "~1.3.4",
160
+ "base64id": "~2.0.0",
161
+ "cors": "~2.8.5",
162
+ "debug": "~4.3.2",
163
+ "engine.io": "~6.6.0",
164
+ "socket.io-adapter": "~2.5.2",
165
+ "socket.io-parser": "~4.2.4"
166
+ },
167
+ "engines": {
168
+ "node": ">=10.2.0"
169
+ }
170
+ },
171
+ "node_modules/socket.io-adapter": {
172
+ "version": "2.5.5",
173
+ "license": "MIT",
174
+ "dependencies": {
175
+ "debug": "~4.3.4",
176
+ "ws": "~8.17.1"
177
+ }
178
+ },
179
+ "node_modules/socket.io-client": {
180
+ "version": "4.8.1",
181
+ "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.8.1.tgz",
182
+ "integrity": "sha512-hJVXfu3E28NmzGk8o1sHhN3om52tRvwYeidbj7xKy2eIIse5IoKX3USlS6Tqt3BHAtflLIkCQBkzVrEEfWUyYQ==",
183
+ "license": "MIT",
184
+ "dependencies": {
185
+ "@socket.io/component-emitter": "~3.1.0",
186
+ "debug": "~4.3.2",
187
+ "engine.io-client": "~6.6.1",
188
+ "socket.io-parser": "~4.2.4"
189
+ },
190
+ "engines": {
191
+ "node": ">=10.0.0"
192
+ }
193
+ },
194
+ "node_modules/socket.io-parser": {
195
+ "version": "4.2.4",
196
+ "license": "MIT",
197
+ "dependencies": {
198
+ "@socket.io/component-emitter": "~3.1.0",
199
+ "debug": "~4.3.1"
200
+ },
201
+ "engines": {
202
+ "node": ">=10.0.0"
203
+ }
204
+ },
205
+ "node_modules/undici-types": {
206
+ "version": "6.21.0",
207
+ "license": "MIT"
208
+ },
209
+ "node_modules/vary": {
210
+ "version": "1.1.2",
211
+ "license": "MIT",
212
+ "engines": {
213
+ "node": ">= 0.8"
214
+ }
215
+ },
216
+ "node_modules/ws": {
217
+ "version": "8.17.1",
218
+ "license": "MIT",
219
+ "engines": {
220
+ "node": ">=10.0.0"
221
+ },
222
+ "peerDependencies": {
223
+ "bufferutil": "^4.0.1",
224
+ "utf-8-validate": ">=5.0.2"
225
+ },
226
+ "peerDependenciesMeta": {
227
+ "bufferutil": {
228
+ "optional": true
229
+ },
230
+ "utf-8-validate": {
231
+ "optional": true
232
+ }
233
+ }
234
+ },
235
+ "node_modules/xmlhttprequest-ssl": {
236
+ "version": "2.1.2",
237
+ "engines": {
238
+ "node": ">=0.4.0"
239
+ }
240
+ }
241
+ }
242
+ }
@@ -0,0 +1,9 @@
1
+ {
2
+ "name": "sendscript-example",
3
+ "private": true,
4
+ "type": "module",
5
+ "dependencies": {
6
+ "socket.io": "^4.8.1",
7
+ "socket.io-client": "^4.8.1"
8
+ }
9
+ }
@@ -1,211 +1,7 @@
1
- **sendscript**
1
+ **sendscript-example**
2
2
 
3
3
  ***
4
4
 
5
- # SendScript
5
+ # Sendscript Example
6
6
 
7
- Write JS code that you can run on servers, browsers or other clients.
8
-
9
- [![NPM](https://img.shields.io/npm/v/sendscript?color=blue&style=flat-square)](https://www.npmjs.com/package/sendscript)
10
- [![100% Code Coverage](https://img.shields.io/badge/coverage-100%25-brightgreen?style=flat-square)](#tests)
11
- [![Standard Code Style](https://img.shields.io/badge/code_style-standard-brightgreen.svg?style=flat-square)](https://standardjs.com)
12
- [![License](https://img.shields.io/npm/l/sendscript?color=brightgreen&style=flat-square)](./LICENSE.txt)
13
-
14
- <!-- toc -->
15
-
16
- SendScript leaves it up to you to choose HTTP, web-sockets or any other
17
- method of communication between servers and clients that best fits your
18
- needs.
19
-
20
- ## Socket example
21
-
22
- For this example we'll use [socket.io][socket.io].
23
-
24
- ```bash
25
- npm link &&
26
- npm install --no-save \
27
- socket.io \
28
- socket.io-client \
29
- sendscript
30
- ```
31
-
32
- > We use the `--no-save` option because it's only for demonstration purposes.
33
-
34
- ### Module
35
-
36
- We write a simple module.
37
-
38
- ```js
39
- // ./example/math.mjs
40
-
41
- export const add = (a, b) => a + b
42
- export const square = a => a * a
43
- ```
44
-
45
- ### Server
46
-
47
- Here a socket.io server that runs SendScript programs.
48
-
49
- ```js
50
- // ./example/server.socket.io.mjs
51
-
52
- import { Server } from 'socket.io'
53
- import Parse from 'sendscript/parse.mjs'
54
- import * as math from './math.mjs'
55
-
56
- const parse = Parse(math)
57
- const server = new Server()
58
- const port = process.env.PORT || 3000
59
-
60
- server.on('connection', (socket) => {
61
- socket.on('message', async (program, callback) => {
62
- try {
63
- const result = parse(program)
64
- callback(null, result) // Pass null as the first argument to indicate success
65
- } catch (error) {
66
- callback(error) // Pass the error to the callback
67
- }
68
- })
69
- })
70
-
71
- server.listen(port)
72
- process.title = 'sendscript'
73
- ```
74
-
75
- ### Client
76
-
77
- Now for a client that sends a program to the server.
78
-
79
- ```js
80
- // ./example/client.socket.io.mjs
81
-
82
- import socketClient from 'socket.io-client'
83
- import stringify from 'sendscript/stringify.mjs'
84
- import module from 'sendscript/module.mjs'
85
- import * as math from './math.mjs'
86
- import assert from 'node:assert'
87
-
88
- const port = process.env.PORT || 3000
89
- const client = socketClient(`http://localhost:${port}`)
90
-
91
- const send = program => {
92
- return new Promise((resolve, reject) => {
93
- client.emit('message', stringify(program), (error, result) => {
94
- error
95
- ? reject(error)
96
- : resolve(result)
97
- })
98
- })
99
- }
100
-
101
- const { add, square } = module(math)
102
-
103
- // The program to be sent over the wire
104
- const program = square(add(1, add(add(2, 3), 4)))
105
-
106
- const result = await send(program)
107
-
108
- console.log('Result: ', result)
109
-
110
- assert.equal(result, 100)
111
-
112
- process.exit(0)
113
- ```
114
-
115
- Now we run this server and a client script.
116
-
117
- ```bash
118
- set -e
119
-
120
- # Run the server
121
- node ./example/server.socket.io.mjs&
122
-
123
- # Run the client example
124
- node ./example/client.socket.io.mjs
125
-
126
- pkill sendscript
127
- ```
128
- ```
129
- Result: 100
130
- ```
131
-
132
- ## Async/Await
133
-
134
- SendScript supports async/await seamlessly within a single request. This avoids the performance pitfalls of waterfall-style messaging, which can be especially slow on high-latency networks.
135
-
136
- While it's possible to chain promises manually or use utility functions, native async/await support makes your code more readable, modern, and easier to reason about — aligning SendScript with today’s JavaScript best practices.
137
-
138
- ```js
139
- const userId = 'user-123'
140
- const program = {
141
- unread: await fetchUnreadMessages(userId),
142
- emptyTrash: await emptyTrash(userId),
143
- archived: await archiveMessages(selectMessages({ old: true }))
144
- }
145
-
146
- const result = await send(program)
147
- ```
148
-
149
- This operation is done in a single round-trip. The result is an object with the defined properties and returned values.
150
-
151
- ## TypeScript
152
-
153
- There is a good use-case to write a module in TypeScript.
154
-
155
- 1. Obviously the module would have the benefits that TypeScript offers when
156
- coding.
157
- 2. You can use tools like [typedoc][typedoc] to generate docs from your types to
158
- share with consumers of your API.
159
- 3. You can use the types of the module to coerce your client to adopt the
160
- module's type.
161
-
162
- Let's say we have this module which we use on the server.
163
-
164
- ```bash
165
- cat ./example/typescript/math.ts
166
- ```
167
- ```ts
168
- export const add = (a: number, b: number) => a + b
169
- export const square = (a: number) => a * a
170
- ```
171
-
172
- We want to use this module on the client. We create a client version of that module and coerce the types to match those of the server.
173
-
174
- ```bash
175
- cat ./example/typescript/math.client.ts
176
- ```
177
- ```ts
178
- import module from 'sendscript/module.mjs'
179
- import type * as mathTypes from './math.ts'
180
-
181
- const math = module([
182
- 'add',
183
- 'square'
184
- ]) as typeof mathTypes
185
-
186
- export default math
187
- ```
188
-
189
- We now use the client version of this module.
190
-
191
- ```bash
192
- cat ./example/typescript/client.ts
193
- ```
194
- ```ts
195
- import stringify from 'sendscript/stringify.mjs'
196
-
197
- async function send<T>(program: T): Promise<T>{
198
- return (await fetch('/api', {
199
- method: 'POST',
200
- body: stringify(program)
201
- })).json()
202
- }
203
-
204
- import math from './math.client.ts'
205
-
206
- const { add, square } = math
207
-
208
- send(square(add(1, 2)))
209
- ```
210
-
211
- We'll also generate the docs for this module.
7
+ Showcases the use of sendscript in combination with TypeScript.
@@ -1,14 +1,14 @@
1
- [**sendscript**](../README.md)
1
+ [**sendscript-example**](../README.md)
2
2
 
3
3
  ***
4
4
 
5
- [sendscript](../globals.md) / add
5
+ [sendscript-example](../globals.md) / add
6
6
 
7
7
  # Function: add()
8
8
 
9
9
  > **add**(`a`, `b`): `number`
10
10
 
11
- Defined in: [math.ts:1](https://github.com/bas080/sendscript/blob/0a5e1c8ec2527d63d1e248f63568668058de388c/example/typescript/math.ts#L1)
11
+ Defined in: [math.ts:1](https://github.com/bas080/sendscript/blob/c1769d9a24148e63d27b0e5a7456213bec64763e/example/typescript/math.ts#L1)
12
12
 
13
13
  ## Parameters
14
14
 
@@ -1,14 +1,14 @@
1
- [**sendscript**](../README.md)
1
+ [**sendscript-example**](../README.md)
2
2
 
3
3
  ***
4
4
 
5
- [sendscript](../globals.md) / square
5
+ [sendscript-example](../globals.md) / square
6
6
 
7
7
  # Function: square()
8
8
 
9
9
  > **square**(`a`): `number`
10
10
 
11
- Defined in: [math.ts:2](https://github.com/bas080/sendscript/blob/0a5e1c8ec2527d63d1e248f63568668058de388c/example/typescript/math.ts#L2)
11
+ Defined in: [math.ts:2](https://github.com/bas080/sendscript/blob/c1769d9a24148e63d27b0e5a7456213bec64763e/example/typescript/math.ts#L2)
12
12
 
13
13
  ## Parameters
14
14
 
@@ -1,8 +1,8 @@
1
- [**sendscript**](README.md)
1
+ [**sendscript-example**](README.md)
2
2
 
3
3
  ***
4
4
 
5
- # sendscript
5
+ # sendscript-example
6
6
 
7
7
  ## Functions
8
8
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sendscript",
3
- "version": "1.0.3",
3
+ "version": "1.0.6",
4
4
  "description": "Blur the line between server and client code.",
5
5
  "module": true,
6
6
  "main": "index.mjs",
@@ -17,15 +17,15 @@
17
17
  },
18
18
  "scripts": {
19
19
  "test": "tap",
20
- "version": "npm run docs && git add *.md example",
21
- "docs": "markatzea README.mz | tee README.md && npx markdown-toc -i README.md"
20
+ "version": "npm run docs",
21
+ "docs": "markatzea CONTRIBUTING.md"
22
22
  },
23
23
  "author": "Bas Huis",
24
24
  "license": "MIT",
25
25
  "devDependencies": {
26
- "tap": "^21.0.1"
26
+ "tap": "^21.6.3"
27
27
  },
28
28
  "dependencies": {
29
- "debug": "^4.3.7"
29
+ "debug": "^4.4.3"
30
30
  }
31
31
  }
package/repl.mjs ADDED
@@ -0,0 +1,15 @@
1
+ import instrument from './module.mjs'
2
+ import repl from 'node:repl'
3
+
4
+ export default async function sendscriptRepl (send, module) {
5
+ Object.assign(global, instrument(module))
6
+
7
+ async function cb (cmd, context, filename, callback) {
8
+ callback(null, await send(eval(cmd))) // eslint-disable-line no-eval
9
+ }
10
+
11
+ return repl.start({
12
+ prompt: '> ',
13
+ eval: cb
14
+ })
15
+ }
package/schema.json DELETED
@@ -1,53 +0,0 @@
1
- {
2
- "$schema": "http://json-schema.org/draft-07/schema#",
3
- "title": "JSON S-expression Language Schema",
4
- "description": "Schema for a custom JSON S-expression language.",
5
- "definitions": {
6
- "ref": {
7
- "title": "Reference Operator",
8
- "description": "A reference to a function or identifier.",
9
- "type": "array",
10
- "minItems": 2,
11
- "maxItems": 2,
12
- "items": [
13
- { "enum": ["ref"], "title": "Operator", "description": "The operator type, representing a reference to a function or identifier." },
14
- { "type": "string", "title": "Identifier", "description": "The identifier or function name." }
15
- ]
16
- },
17
- "call": {
18
- "title": "Call Operator",
19
- "description": "A function call.",
20
- "type": "array",
21
- "minItems": 2,
22
- "maxItems": 3,
23
- "items": [
24
- { "const": "call", "title": "Operator", "description": "The operator type, representing a function call." },
25
- { "$ref": "#/definitions/ref", "title": "Reference", "description": "The reference to a function or identifier." },
26
- {
27
- "type": "array",
28
- "items": {
29
- "$ref": "#"
30
- },
31
- "title": "Arguments",
32
- "description": "The arguments passed to the function."
33
- }
34
- ]
35
- }
36
- },
37
- "oneOf": [
38
- { "$ref": "#/definitions/ref" },
39
- { "$ref": "#/definitions/call" },
40
- { "type": "number", "title": "Number", "description": "A JSON number." },
41
- { "type": "string", "title": "String", "description": "A JSON string." },
42
- { "type": "boolean", "title": "Boolean", "description": "A JSON boolean." },
43
- { "type": "null", "title": "Null", "description": "A JSON null value." },
44
- {
45
- "title": "Object",
46
- "description": "A generic JSON object with additional properties.",
47
- "type": "object",
48
- "additionalProperties": {
49
- "$ref": "#"
50
- }
51
- }
52
- ]
53
- }