sendscript 1.0.6 → 2.0.1

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.
@@ -3,7 +3,7 @@ name: Publish Package
3
3
  on:
4
4
  push:
5
5
  tags:
6
- - 'v*'
6
+ - '*'
7
7
 
8
8
  permissions:
9
9
  id-token: write # Required for OIDC
@@ -22,4 +22,4 @@ jobs:
22
22
  - run: npm ci
23
23
  - run: npm run build --if-present
24
24
  - run: npm test
25
- - run: npm publish
25
+ - run: npm publish
@@ -0,0 +1,45 @@
1
+ name: Release on tag
2
+
3
+ on:
4
+ push:
5
+ tags:
6
+ - '*'
7
+
8
+ permissions:
9
+ contents: write
10
+
11
+ jobs:
12
+ test:
13
+ runs-on: ubuntu-latest
14
+ strategy:
15
+ matrix:
16
+ node: ['lts/*', 'latest']
17
+
18
+ steps:
19
+ - uses: actions/checkout@v4
20
+
21
+ - uses: actions/setup-node@v4
22
+ with:
23
+ node-version: ${{ matrix.node }}
24
+ cache: npm
25
+
26
+ - run: npm ci
27
+ - run: npm test
28
+
29
+ release:
30
+ needs: test
31
+ runs-on: ubuntu-latest
32
+
33
+ steps:
34
+ - uses: actions/checkout@v4
35
+
36
+ - uses: actions/setup-node@v4
37
+ with:
38
+ node-version: 'latest'
39
+ cache: npm
40
+
41
+ - run: npm ci
42
+ - name: Create GitHub Release
43
+ uses: softprops/action-gh-release@v2
44
+ with:
45
+ generate_release_notes: true
package/CHANGELOG.md CHANGED
@@ -4,8 +4,30 @@ 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
+ #### [v2.0.1](https://github.com/bas080/sendscript/compare/v2.0.0...v2.0.1)
8
+
9
+ - Publish to npm on tag push [`357ac0e`](https://github.com/bas080/sendscript/commit/357ac0ef3384f294e4f9bb179d5a675afda5fd19)
10
+
11
+ ### [v2.0.0](https://github.com/bas080/sendscript/compare/v1.1.0...v2.0.0)
12
+
13
+ > 8 April 2026
14
+
15
+ - Rewrite to have parse take schema to prevent accessing refs [`df16f85`](https://github.com/bas080/sendscript/commit/df16f85c79299aa8bcd3e44b6cc127bd7198eace)
16
+ - Run tests before release and publish on release [`10442d6`](https://github.com/bas080/sendscript/commit/10442d6766a098926ee98daee08dba23eea0fb14)
17
+ - Create release on tag with github workflows [`4ec222b`](https://github.com/bas080/sendscript/commit/4ec222bf51fc1d3cce9fc54fdd1e9639b5d259cd)
18
+
19
+ #### [v1.1.0](https://github.com/bas080/sendscript/compare/v1.0.6...v1.1.0)
20
+
21
+ > 7 April 2026
22
+
23
+ - Support custom serialization of leaf nodes [`d56f1b7`](https://github.com/bas080/sendscript/commit/d56f1b750e2d7faf72d69f9ba8e9bb62ef5ebce7)
24
+ - Support nested modules [`88e69e5`](https://github.com/bas080/sendscript/commit/88e69e5c05ddb85aac1797a020e92519c986e89f)
25
+ - Document new nesting and leaf serialization feature [`b3ee9f6`](https://github.com/bas080/sendscript/commit/b3ee9f693dc6137b01c9f0072aa2dd1e940f07c9)
26
+
7
27
  #### [v1.0.6](https://github.com/bas080/sendscript/compare/v1.0.5...v1.0.6)
8
28
 
29
+ > 6 April 2026
30
+
9
31
  - Update tap to 21.6.3 [`c1769d9`](https://github.com/bas080/sendscript/commit/c1769d9a24148e63d27b0e5a7456213bec64763e)
10
32
  - Add introduction to readme [`a21a494`](https://github.com/bas080/sendscript/commit/a21a494616d5ad8c99f9a2904ef529ea85104a99)
11
33
 
package/README.md CHANGED
@@ -17,6 +17,12 @@ Write JS code that you can run on servers, browsers or other clients.
17
17
  - [Repl](#repl)
18
18
  - [Async/Await](#asyncawait)
19
19
  - [TypeScript](#typescript)
20
+ - [Schema and Nested Modules](#schema-and-nested-modules)
21
+ * [Defining a Nested Module](#defining-a-nested-module)
22
+ - [Validation (using Zod)](#validation-using-zod)
23
+ * [Validating structured input](#validating-structured-input)
24
+ - [Leaf Serializer](#leaf-serializer)
25
+ * [Example with superjson](#example-with-superjson)
20
26
  - [Tests](#tests)
21
27
  - [Formatting](#formatting)
22
28
  - [Changelog](#changelog)
@@ -47,15 +53,16 @@ using more advanced (de)serialization libraries.
47
53
  SendScript produces an intermediate JSON representation of the program. Let's see what that looks like.
48
54
 
49
55
  ```js
50
- import stringify from 'sendscript/stringify.mjs'
51
- import module from 'sendscript/module.mjs'
56
+ import Stringify from 'sendscript/stringify.mjs'
57
+ import references from 'sendscript/references.mjs'
52
58
 
53
- const { add } = module(['add'])
59
+ const { add } = references(['add'])
60
+ const stringify = Stringify()
54
61
 
55
62
  console.log(stringify(add(1,2)))
56
63
  ```
57
64
  ```json
58
- ["call",["ref","add"],[1,2]]
65
+ ["call",["ref","add"],[["leaf","1"],["leaf","2"]]]
59
66
  ```
60
67
 
61
68
  We can then parse that JSON and it will evaluate down to a value.
@@ -69,7 +76,7 @@ const module = {
69
76
  }
70
77
  }
71
78
 
72
- const parse = Parse(module)
79
+ const parse = Parse(['add'], module)
73
80
 
74
81
  const program = '["call",["ref","add"],[1,2]]'
75
82
 
@@ -125,7 +132,8 @@ import { Server } from 'socket.io'
125
132
  import Parse from 'sendscript/parse.mjs'
126
133
  import * as math from './math.mjs'
127
134
 
128
- const parse = Parse(math)
135
+ const schema = Object.keys(math)
136
+ const parse = Parse(schema, math)
129
137
  const server = new Server()
130
138
  const port = process.env.PORT || 3000
131
139
 
@@ -152,11 +160,13 @@ Now for a client that sends a program to the server.
152
160
  // ./example/client.socket.io.mjs
153
161
 
154
162
  import socketClient from 'socket.io-client'
155
- import stringify from 'sendscript/stringify.mjs'
156
- import module from 'sendscript/module.mjs'
157
- import * as math from './math.mjs'
163
+ import Stringify from 'sendscript/stringify.mjs'
164
+ import references from 'sendscript/references.mjs'
158
165
  import assert from 'node:assert'
159
166
 
167
+ const { add, square } = references(['add', 'square'])
168
+ const stringify = Stringify()
169
+
160
170
  const port = process.env.PORT || 3000
161
171
  const client = socketClient(`http://localhost:${port}`)
162
172
 
@@ -170,8 +180,6 @@ const send = program => {
170
180
  })
171
181
  }
172
182
 
173
- const { add, square } = module(math)
174
-
175
183
  // The program to be sent over the wire
176
184
  const program = square(add(1, add(add(2, 3), 4)))
177
185
 
@@ -247,52 +255,31 @@ export const add = (a: number, b: number) => a + b
247
255
  export const square = (a: number) => a * a
248
256
  ```
249
257
 
250
- 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.
251
-
252
- ```bash
253
- cat ./example/typescript/math.client.ts
254
- ```
255
- ```ts
256
- import module from 'sendscript/module.mjs'
257
- import type * as mathTypes from './math.ts'
258
-
259
- const math = module([
260
- 'add',
261
- 'square'
262
- ]) as typeof mathTypes
263
-
264
- export default math
265
- ```
266
-
267
- We now use the client version of this module.
258
+ We can then coerce the types of the instrumented stubs.
268
259
 
269
260
  ```bash
270
261
  cat ./example/typescript/client.ts
271
262
  ```
272
263
  ```ts
273
- import stringify from 'sendscript/stringify.mjs'
264
+ import math from './math.client.ts'
265
+ import Stringify from 'sendscript/stringify.mjs'
274
266
 
275
- async function send<T>(program: T): Promise<T>{
267
+ const stringify = Stringify()
268
+
269
+ // The return type of this function matches the type passed as the return of the program.
270
+ async function send<T>(program: T): Promise<T> {
276
271
  return (await fetch('/api', {
277
272
  method: 'POST',
278
273
  body: stringify(program)
279
274
  })).json()
280
275
  }
281
276
 
282
- import math from './math.client.ts'
283
-
284
- const { add, square } = math
285
-
286
277
  send(square(add(1, 2)))
287
278
  ```
288
279
 
289
280
  We'll also generate the docs for this module.
290
281
 
291
282
  ```bash
292
- npm install --no-save \
293
- typedoc \
294
- typedoc-plugin-markdown
295
-
296
283
  npx typedoc --plugin typedoc-plugin-markdown --out ./example/typescript/docs ./example/typescript/math.ts
297
284
  ```
298
285
 
@@ -303,6 +290,135 @@ You can see the docs [here](./example/typescript/docs/globals.md)
303
290
  > experience, it does not represent the actual type.
304
291
  > Values are subject to serialization and deserialization.
305
292
 
293
+
294
+ ## Schema and Nested Modules
295
+
296
+ Sendscript allows you to define your API as a **nested object of functions**, making it easy to organize your DSL into modules and submodules. Each function is instrumented so that when serialized, it produces a structured reference that can be safely sent and executed elsewhere.
297
+
298
+ ### Defining a Nested Module
299
+
300
+ You can define a schema as **an array of function names**
301
+
302
+ ```js
303
+
304
+ const schema = [
305
+ 'help',
306
+ 'version',
307
+
308
+ ['math', [
309
+ 'add',
310
+ 'sub'
311
+ ]],
312
+ ['vector', [
313
+ 'add',
314
+ 'multiply'
315
+ ]],
316
+ ['utils', [
317
+ 'identity',
318
+ 'always'
319
+ ]],
320
+ })
321
+ ```
322
+
323
+ Functions are referenced via their **path in the module tree**:
324
+
325
+ ```js
326
+ const { math, vector } = references(schema)
327
+
328
+ math.add(
329
+ 1,
330
+ vector.length(
331
+ vector.multiply([1,2], 3)
332
+ )
333
+ )
334
+ ```
335
+
336
+ ## Validation (using Zod)
337
+
338
+ SendScript focuses on program serialization and execution. For runtime input validation, you can use [Zod](https://zod.dev).
339
+
340
+ ### Validating structured input
341
+
342
+ ```js
343
+ const userSchema = z.object({
344
+ id: z.string().uuid(),
345
+ name: z.string(),
346
+ roles: z.array(z.string())
347
+ })
348
+
349
+ export function createUser(user) {
350
+ userSchema.parse(user)
351
+
352
+ return { success: true }
353
+ }
354
+ ```
355
+
356
+ **Benefits**:
357
+
358
+ - Ensures arguments match expected types and shapes.
359
+ - Throws structured errors that can be propagated to clients.
360
+ - Works with TypeScript for automatic type inference.
361
+
362
+ ## Leaf Serializer
363
+
364
+ By default, SendScript uses JSON for serialization, which limits support to primitives and plain objects/arrays. To support richer JavaScript types like `Date`, `RegExp`, `BigInt`, `Map`, `Set`, and `undefined`, you can provide custom serialization functions.
365
+
366
+ The `stringify` function accepts an optional `leafSerializer` parameter, and `parse` accepts an optional `leafDeserializer` parameter. These functions control how non-SendScript values (leaves) are encoded and decoded.
367
+
368
+ ### Example with superjson
369
+
370
+ Here's how to use [superjson](https://github.com/blitz-js/superjson) to support extended types:
371
+
372
+ ```js
373
+ import SuperJSON from 'superjson'
374
+ import Stringify from 'sendscript/stringify.mjs'
375
+ import references from 'sendscript/references.mjs'
376
+ import Parse from 'sendscript/parse.mjs'
377
+
378
+ const leafSerializer = (value) => {
379
+ if (value === undefined) return JSON.stringify({ __undefined__: true })
380
+ return JSON.stringify(SuperJSON.serialize(value))
381
+ }
382
+
383
+ const leafDeserializer = (text) => {
384
+ const parsed = JSON.parse(text)
385
+ if (parsed && parsed.__undefined__ === true) return undefined
386
+ return SuperJSON.deserialize(parsed)
387
+ }
388
+
389
+ const schema = ['processData']
390
+
391
+ const { processData } = references(schema)
392
+ const stringify = Stringify(leafSerializer)
393
+
394
+ // Program with Date, RegExp, and other types
395
+ const program = {
396
+ createdAt: new Date('2020-01-01T00:00:00.000Z'),
397
+ pattern: /foo/gi,
398
+ count: BigInt('9007199254740992'),
399
+ items: new Set([1, 2, 3]),
400
+ mapping: new Map([['a', 1], ['b', 2]])
401
+ }
402
+
403
+ // Serialize with custom leaf serializer
404
+ const json = stringify(processData(program))
405
+
406
+ // The environment
407
+ const env = {
408
+ processData: (data) => ({
409
+ success: true,
410
+ received: data
411
+ })
412
+ }
413
+
414
+ // Parse with custom leaf deserializer
415
+ const parse = Parse(schema, env, leadDeserializer)
416
+
417
+ const result = parse(json)
418
+ ```
419
+
420
+ The leaf wrapper format is `['leaf', serializedPayload]`, making it unambiguous and safe from colliding with SendScript operators.
421
+
306
422
  ## Tests
307
423
 
308
424
  Tests with 100% code coverage.
@@ -313,19 +429,19 @@ npm t -- report text-summary
313
429
  ```
314
430
  ```
315
431
 
316
- > sendscript@1.0.6 test
432
+ > sendscript@2.0.1 test
317
433
  > tap -R silent
318
434
 
319
435
 
320
- > sendscript@1.0.6 test
436
+ > sendscript@2.0.1 test
321
437
  > tap report text-summary
322
438
 
323
439
 
324
440
  =============================== Coverage summary ===============================
325
- Statements : 100% ( 245/245 )
326
- Branches : 100% ( 74/74 )
327
- Functions : 100% ( 18/18 )
328
- Lines : 100% ( 245/245 )
441
+ Statements : 100% ( 348/348 )
442
+ Branches : 100% ( 145/145 )
443
+ Functions : 100% ( 24/24 )
444
+ Lines : 100% ( 348/348 )
329
445
  ================================================================================
330
446
  ```
331
447
 
package/README.mz CHANGED
@@ -30,10 +30,11 @@ using more advanced (de)serialization libraries.
30
30
  SendScript produces an intermediate JSON representation of the program. Let's see what that looks like.
31
31
 
32
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'
33
+ import Stringify from 'sendscript/stringify.mjs'
34
+ import references from 'sendscript/references.mjs'
35
35
 
36
- const { add } = module(['add'])
36
+ const { add } = references(['add'])
37
+ const stringify = Stringify()
37
38
 
38
39
  console.log(stringify(add(1,2)))
39
40
  ```
@@ -49,7 +50,7 @@ const module = {
49
50
  }
50
51
  }
51
52
 
52
- const parse = Parse(module)
53
+ const parse = Parse(['add'], module)
53
54
 
54
55
  const program = '["call",["ref","add"],[1,2]]'
55
56
 
@@ -102,7 +103,8 @@ import { Server } from 'socket.io'
102
103
  import Parse from 'sendscript/parse.mjs'
103
104
  import * as math from './math.mjs'
104
105
 
105
- const parse = Parse(math)
106
+ const schema = Object.keys(math)
107
+ const parse = Parse(schema, math)
106
108
  const server = new Server()
107
109
  const port = process.env.PORT || 3000
108
110
 
@@ -129,11 +131,13 @@ Now for a client that sends a program to the server.
129
131
  // ./example/client.socket.io.mjs
130
132
 
131
133
  import socketClient from 'socket.io-client'
132
- import stringify from 'sendscript/stringify.mjs'
133
- import module from 'sendscript/module.mjs'
134
- import * as math from './math.mjs'
134
+ import Stringify from 'sendscript/stringify.mjs'
135
+ import references from 'sendscript/references.mjs'
135
136
  import assert from 'node:assert'
136
137
 
138
+ const { add, square } = references(['add', 'square'])
139
+ const stringify = Stringify()
140
+
137
141
  const port = process.env.PORT || 3000
138
142
  const client = socketClient(`http://localhost:${port}`)
139
143
 
@@ -147,8 +151,6 @@ const send = program => {
147
151
  })
148
152
  }
149
153
 
150
- const { add, square } = module(math)
151
-
152
154
  // The program to be sent over the wire
153
155
  const program = square(add(1, add(add(2, 3), 4)))
154
156
 
@@ -217,13 +219,7 @@ Let's say we have this module which we use on the server.
217
219
  cat ./example/typescript/math.ts
218
220
  ```
219
221
 
220
- 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.
221
-
222
- ```bash|ts bash
223
- cat ./example/typescript/math.client.ts
224
- ```
225
-
226
- We now use the client version of this module.
222
+ We can then coerce the types of the instrumented stubs.
227
223
 
228
224
  ```bash|ts bash
229
225
  cat ./example/typescript/client.ts
@@ -232,10 +228,6 @@ cat ./example/typescript/client.ts
232
228
  We'll also generate the docs for this module.
233
229
 
234
230
  ```bash bash 1>&2
235
- npm install --no-save \
236
- typedoc \
237
- typedoc-plugin-markdown
238
-
239
231
  npx typedoc --plugin typedoc-plugin-markdown --out ./example/typescript/docs ./example/typescript/math.ts
240
232
  ```
241
233
 
@@ -246,6 +238,135 @@ You can see the docs [here](./example/typescript/docs/globals.md)
246
238
  > experience, it does not represent the actual type.
247
239
  > Values are subject to serialization and deserialization.
248
240
 
241
+
242
+ ## Schema and Nested Modules
243
+
244
+ Sendscript allows you to define your API as a **nested object of functions**, making it easy to organize your DSL into modules and submodules. Each function is instrumented so that when serialized, it produces a structured reference that can be safely sent and executed elsewhere.
245
+
246
+ ### Defining a Nested Module
247
+
248
+ You can define a schema as **an array of function names**
249
+
250
+ ```js
251
+
252
+ const schema = [
253
+ 'help',
254
+ 'version',
255
+
256
+ ['math', [
257
+ 'add',
258
+ 'sub'
259
+ ]],
260
+ ['vector', [
261
+ 'add',
262
+ 'multiply'
263
+ ]],
264
+ ['utils', [
265
+ 'identity',
266
+ 'always'
267
+ ]],
268
+ })
269
+ ```
270
+
271
+ Functions are referenced via their **path in the module tree**:
272
+
273
+ ```js
274
+ const { math, vector } = references(schema)
275
+
276
+ math.add(
277
+ 1,
278
+ vector.length(
279
+ vector.multiply([1,2], 3)
280
+ )
281
+ )
282
+ ```
283
+
284
+ ## Validation (using Zod)
285
+
286
+ SendScript focuses on program serialization and execution. For runtime input validation, you can use [Zod](https://zod.dev).
287
+
288
+ ### Validating structured input
289
+
290
+ ```js
291
+ const userSchema = z.object({
292
+ id: z.string().uuid(),
293
+ name: z.string(),
294
+ roles: z.array(z.string())
295
+ })
296
+
297
+ export function createUser(user) {
298
+ userSchema.parse(user)
299
+
300
+ return { success: true }
301
+ }
302
+ ```
303
+
304
+ **Benefits**:
305
+
306
+ - Ensures arguments match expected types and shapes.
307
+ - Throws structured errors that can be propagated to clients.
308
+ - Works with TypeScript for automatic type inference.
309
+
310
+ ## Leaf Serializer
311
+
312
+ By default, SendScript uses JSON for serialization, which limits support to primitives and plain objects/arrays. To support richer JavaScript types like `Date`, `RegExp`, `BigInt`, `Map`, `Set`, and `undefined`, you can provide custom serialization functions.
313
+
314
+ The `stringify` function accepts an optional `leafSerializer` parameter, and `parse` accepts an optional `leafDeserializer` parameter. These functions control how non-SendScript values (leaves) are encoded and decoded.
315
+
316
+ ### Example with superjson
317
+
318
+ Here's how to use [superjson](https://github.com/blitz-js/superjson) to support extended types:
319
+
320
+ ```js
321
+ import SuperJSON from 'superjson'
322
+ import Stringify from 'sendscript/stringify.mjs'
323
+ import references from 'sendscript/references.mjs'
324
+ import Parse from 'sendscript/parse.mjs'
325
+
326
+ const leafSerializer = (value) => {
327
+ if (value === undefined) return JSON.stringify({ __undefined__: true })
328
+ return JSON.stringify(SuperJSON.serialize(value))
329
+ }
330
+
331
+ const leafDeserializer = (text) => {
332
+ const parsed = JSON.parse(text)
333
+ if (parsed && parsed.__undefined__ === true) return undefined
334
+ return SuperJSON.deserialize(parsed)
335
+ }
336
+
337
+ const schema = ['processData']
338
+
339
+ const { processData } = references(schema)
340
+ const stringify = Stringify(leafSerializer)
341
+
342
+ // Program with Date, RegExp, and other types
343
+ const program = {
344
+ createdAt: new Date('2020-01-01T00:00:00.000Z'),
345
+ pattern: /foo/gi,
346
+ count: BigInt('9007199254740992'),
347
+ items: new Set([1, 2, 3]),
348
+ mapping: new Map([['a', 1], ['b', 2]])
349
+ }
350
+
351
+ // Serialize with custom leaf serializer
352
+ const json = stringify(processData(program))
353
+
354
+ // The environment
355
+ const env = {
356
+ processData: (data) => ({
357
+ success: true,
358
+ received: data
359
+ })
360
+ }
361
+
362
+ // Parse with custom leaf deserializer
363
+ const parse = Parse(schema, env, leadDeserializer)
364
+
365
+ const result = parse(json)
366
+ ```
367
+
368
+ The leaf wrapper format is `['leaf', serializedPayload]`, making it unambiguous and safe from colliding with SendScript operators.
369
+
249
370
  ## Tests
250
371
 
251
372
  Tests with 100% code coverage.
@@ -1,11 +1,13 @@
1
1
  // ./example/client.socket.io.mjs
2
2
 
3
3
  import socketClient from 'socket.io-client'
4
- import stringify from 'sendscript/stringify.mjs'
5
- import module from 'sendscript/module.mjs'
6
- import * as math from './math.mjs'
4
+ import Stringify from 'sendscript/stringify.mjs'
5
+ import references from 'sendscript/references.mjs'
7
6
  import assert from 'node:assert'
8
7
 
8
+ const { add, square } = references(['add', 'square'])
9
+ const stringify = Stringify()
10
+
9
11
  const port = process.env.PORT || 3000
10
12
  const client = socketClient(`http://localhost:${port}`)
11
13
 
@@ -19,8 +21,6 @@ const send = program => {
19
21
  })
20
22
  }
21
23
 
22
- const { add, square } = module(math)
23
-
24
24
  // The program to be sent over the wire
25
25
  const program = square(add(1, add(add(2, 3), 4)))
26
26
 
@@ -4,7 +4,8 @@ import { Server } from 'socket.io'
4
4
  import Parse from 'sendscript/parse.mjs'
5
5
  import * as math from './math.mjs'
6
6
 
7
- const parse = Parse(math)
7
+ const schema = Object.keys(math)
8
+ const parse = Parse(schema, math)
8
9
  const server = new Server()
9
10
  const port = process.env.PORT || 3000
10
11
 
@@ -1,14 +1,14 @@
1
- import stringify from 'sendscript/stringify.mjs'
1
+ import math from './math.client.ts'
2
+ import Stringify from 'sendscript/stringify.mjs'
2
3
 
3
- async function send<T>(program: T): Promise<T>{
4
+ const stringify = Stringify()
5
+
6
+ // The return type of this function matches the type passed as the return of the program.
7
+ async function send<T>(program: T): Promise<T> {
4
8
  return (await fetch('/api', {
5
9
  method: 'POST',
6
10
  body: stringify(program)
7
11
  })).json()
8
12
  }
9
13
 
10
- import math from './math.client.ts'
11
-
12
- const { add, square } = math
13
-
14
14
  send(square(add(1, 2)))
@@ -8,7 +8,7 @@
8
8
 
9
9
  > **add**(`a`, `b`): `number`
10
10
 
11
- Defined in: [math.ts:1](https://github.com/bas080/sendscript/blob/c1769d9a24148e63d27b0e5a7456213bec64763e/example/typescript/math.ts#L1)
11
+ Defined in: [math.ts:1](https://github.com/bas080/sendscript/blob/357ac0ef3384f294e4f9bb179d5a675afda5fd19/example/typescript/math.ts#L1)
12
12
 
13
13
  ## Parameters
14
14
 
@@ -8,7 +8,7 @@
8
8
 
9
9
  > **square**(`a`): `number`
10
10
 
11
- Defined in: [math.ts:2](https://github.com/bas080/sendscript/blob/c1769d9a24148e63d27b0e5a7456213bec64763e/example/typescript/math.ts#L2)
11
+ Defined in: [math.ts:2](https://github.com/bas080/sendscript/blob/357ac0ef3384f294e4f9bb179d5a675afda5fd19/example/typescript/math.ts#L2)
12
12
 
13
13
  ## Parameters
14
14