• Stars
    star
    191
  • Rank 202,877 (Top 4 %)
  • Language
    TypeScript
  • License
    MIT License
  • Created about 5 years ago
  • Updated 5 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A lightweight JSON RPC client & server

Async Call

async-call-rpc is a JSON RPC server and client written in TypeScript for any ES6+ environment.

Code coverage GitHub Workflow Status npm ES2015+

Links

CHANGELOG.md | Document of AsyncCall | Document of AsyncGeneratorCall | Playground

Chapters:

Features

  • Zero dependencies!
  • Running in any ES6+ environment (+globalThis), no requirement on any Web or Node API
  • Simple to define a server and simple to use as a client
  • Full TypeScript support
  • Support custom serializer to pass complex data types
  • Support async generator (Require both server and client supports 4 JSON RPC internal methods, and Symbol.asyncIterator, (async function* () {}).constructor.prototype available)

Cautions

  • NOT support ECMAScript 5 (ES6 Proxy is the core of this library)
  • This package is shipping ECMAScript 2018 syntax (including async function).
  • The async generator mode might leak memory on the server. Use it by your caution.
  • NOT support JSON RPC 1.0

The first concept: channel

The channel is the only thing you need to learn to use this library.

This library is designed to not rely on any specific platform. Only require things defined in the ECMAScript specification. In the ES spec, there is no I/O related API so it's impossible to communicate with the outer world.

You need to implement one of the following interfaces:

There are some built-in channel you can simplify the usage.

The following document will assume you have defined your channel.

Example

Server example

// server.ts
export function add(x: number, y: number) {
    return x + y
}
export const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms))

// init.ts
import { AsyncCall } from 'async-call-rpc'
import * as server from './server'
// create a server
AsyncCall(server, { channel })

Client example

import { AsyncCall } from 'async-call-rpc'
const server = AsyncCall<typeof server>({}, { channel })
server.add(2, 40).then(console.log) // 42

Isomorphic API

You can notice from the above example, define a server is using AsyncCall(serverImplementation, opt), define a client is using AsyncCall<typeof serverImplementation>({}, opt). So it is possible to define a server and a client at the same time.

Notifications and Batch requests

AsyncCall can send Notifications.

Using notifications means results or remote errors will be dropped. Local errors won't be omitted, e.g. serializer error or network error.

import { AsyncCall, notify } from 'async-call-rpc'
const server = notify(AsyncCall<typeof server>({}, { channel }))
server.online().then(console.log) // undefined

AsyncCall can send batch request too.

import { AsyncCall, batch } from 'async-call-rpc'
const [server, emit, drop] = batch(AsyncCall<typeof server>({}, { channel }))
const a = server.req1() // pending
const b = server.req2() // pending
const c = server.req3() // pending
emit() // to send all pending requests
// request a, b, c sent

const d = server.req1() // pending
drop() // to drop all pending requests (and corresponding Promises)
// d rejected

Installation

Install through npm

npm i async-call-rpc

yarn add async-call-rpc

Import from browser or Deno

You can access https://www.jsdelivr.com/package/npm/async-call-rpc?path=out to get the latest URL and SRI.

(Supports type definition for deno out-of-box!)

import { AsyncCall } from 'https://cdn.jsdelivr.net/npm/async-call-rpc@latest/out/base.mjs'

UMD

<script src="https://cdn.jsdelivr.net/npm/[email protected]/out/base.js"></script>
<script>
    const { AsyncCall } = globalThis.AsyncCall
</script>

In other JS environment

Load the out/base.mjs (ES Module) or out/base.js (UMD, CommonJS or AMD) to your project.

Entries

This library has 2 entry. base and full. base is the default entry point. The full version includes the AsyncGeneratorCall but the base version doesn't.

Browser / Deno

Please check out https://www.jsdelivr.com/package/npm/async-call-rpc?path=out

Node:

// Full version
require('async-rpc-call/full') // or
import * as RPC from 'async-rpc-call/full'

// Base version
require('async-rpc-call/base') // or
import * as RPC from 'async-rpc-call/base'

Builtin channels

They're not part of the core library but provided as utils to increase usability.

(Node) WebSocket

Server Client
Entry point async-call-rpc/utils/node/websocket.server.js
(Source code)
TBD
Entry point type CommonJS CommonJS
Dependencies ws ws
Example ./examples/node.websocket.server.js TBD

(Deno) WebSocket

Server Client
Entry point https://cdn.jsdelivr.net/npm/async-call-rpc@latest/utils/deno/websocket.server.ts
(Source code)
TBD
Entry point type ES Module ES Module
Dependencies Deno std Deno std
Example ./examples/deno.websocket.server.ts TBD

(Web) WebSocket

Client
Entry point https://cdn.jsdelivr.net/npm/async-call-rpc@latest/utils/web/websocket.client.js
(Source code)
Entry point type ES Module
Dependencies Nothing
Example ./examples/browser.websocket.client.js

(Web) BroadcastChannel

⚠️ Broadcast Channel is not supported by Safari yet ⚠️

Server & Client
Entry point https://cdn.jsdelivr.net/npm/async-call-rpc@latest/utils/web/broadcast.channel.js
(Source code)
Entry point type ES Module
Dependencies Nothing
Example TBD

(Web) Worker

⚠️ Import a ES Module in a Web Worker is only supported by Chrome yet! ⚠️

Host & Worker
Entry point https://cdn.jsdelivr.net/npm/async-call-rpc@latest/utils/web/worker.js
(Source code)
Entry point type ES Module
Dependencies Nothing
Example Main frame: ./examples/browser.worker-main.js
Worker: ./examples/browser.worker-worker.js

Main frame: new WorkerChannel(new Worker(...))

Worker: new WorkerChannel()

Builtin serializers

(Web, Deno and Node) BSON

Server
Entry point Node async-call-rpc/utils/node/bson.js
(Source code)
Entry point Browser/Deno https://cdn.jsdelivr.net/npm/async-call-rpc@latest/utils/web/bson.js
(Source code)
Dependencies bson

(Web, Deno and Node) Msgpack

Server
Entry point Node async-call-rpc/utils/node/msgpack.js
(Source code)
Entry point Browser/Deno https://cdn.jsdelivr.net/npm/async-call-rpc@latest/utils/web/msgpack.js
(Source code)
Dependencies @msgpack/msgpack
Example (Node) ./examples/node.websocket.server.js
Example (Deno) ./examples/deno.websocket.server.ts
Example (Web) ./examples/browser.websocket.client.js

Utils available if both server and client are created by this library

AsyncCall has some non-standard extensions to the JSON RPC specification that can help the library easier to use. Those features aren't enabled by default.

Implemented JSON RPC internal methods

These four methods are used to implement AsyncGeneratorCall support.

interface JSONRPC_Internal_Methods {
    // These 4 methods represent the Async Iterator protocol in ECMAScript
    // this method starts an async iterator, return the id
    'rpc.async-iterator.start'(method: string, params: unknown[]): Promise<string>
    // this method executes `next` method on the previous iterator started by `rpc.async-iterator.start`
    'rpc.async-iterator.next'(id: string, value: unknown): Promise<IteratorResult<unknown>>
    // this method executes `return` method on the previous iterator started by `rpc.async-iterator.start`
    'rpc.async-iterator.return'(id: string, value: unknown): Promise<IteratorResult<unknown>>
    // this method executes `throw` method on the previous iterator started by `rpc.async-iterator.start`
    'rpc.async-iterator.throw'(id: string, value: unknown): Promise<IteratorResult<unknown>>
}

Non-standard extension to JSON RPC specification

remoteStack on Request object

This library can send the client the call stack to the server to make the logger better.

Controlled by option.log.sendLocalStack. Default to false.

interface JSONRPC_Request_object {
    // This property include the caller's stack.
    remoteStack?: string
}

"undef" on Response object

This is a non-standard property appears when using JSONSerialization due to JSON doesn't support undefined. It's a hint to the client, that the result is undefined.

This behavior is controlled by the 3rd parameter of JSONSerialization(replacerAndReceiver?, space?, undefinedKeepingBehavior?: false | "keep" | "null" = "null"). Default to "null". To turn on this feature to "keep" undefined values, change the 3rd option to "keep".

interface JSONRPC_Response_object {
    // This property is a hint.
    // If the client is run in JavaScript, it should treat "result: null" as "result: undefined"
    undef?: boolean
}

The implementation-defined Error data

In the JSON RPC specification, this is implementation-defined. This is controlled by the option options.mapError

This library will try to "Recover" the Error object if there is enough information from another side.

interface JSONRPC_Error_object {
    // This property will help client to build a better Error object.
    data?: {
        stack?: string
        // Supported value for "type" field (Defined in ECMAScript specification):
        type?:
            | string
            | 'Error'
            | 'EvalError'
            | 'RangeError'
            | 'ReferenceError'
            | 'SyntaxError'
            | 'TypeError'
            | 'URIError'
            // Defined in HTML specification, only supported in Web
            | 'DOMException'
    }
}

More Repositories

1

proposal-enum

ADT enum proposal for ECMAScript
HTML
88
star
2

react-refresh-transformer

React Refresh transformers for tooling authors
JavaScript
66
star
3

ttypescript-browser-like-import-transformer

A custom transformer that can be used with ttypescript to transform ts imports to browser style imports
TypeScript
23
star
4

Sync-watch

Watch video with your friend. Local file or Youtube. Sync watch progress and chat.
TypeScript
22
star
5

i18n-codegen

A code generator for i18n files
TypeScript
16
star
6

proposal-ecmascript-parser

A ECMAScript proposal to introduce a built-in parser for ES
15
star
7

proposal-json-tryParse

JSON.canParse
9
star
8

loader-with-esmodule-example

Transpile files without any build step in browser directly
JavaScript
9
star
9

WebOps

AppOps for Web
TypeScript
8
star
10

oct-2020-typescript-compiler-101

Template repo for COSCon 2020 Workshop: TypeScript Compiler 101
TypeScript
7
star
11

ts-dual-package-example

JavaScript
6
star
12

demo-book-ticket-weapp

Demo: For Wechat WeApp, A ticket booking app. Using Taro w/ Typescript
TypeScript
5
star
13

ts-esm-migrate

Migrate code to NodeNext module resolution by add .js extension
JavaScript
4
star
14

schema2ts

Generate Typescript code from API Schema
TypeScript
4
star
15

Sync-watch-server

Server for sync watch. Thanks Gun.js
TypeScript
4
star
16

ecmarkup-language-service

Language service for ecmarkup
TypeScript
4
star
17

auto-chaoxing

超星视频平台辅助
TypeScript
4
star
18

jsx-jsonml-devtools-renderer

A JSX render for Chrome Devtools.
TypeScript
4
star
19

ef-language-service

Language service for efml
TypeScript
3
star
20

hybird-angular-react-custom-element

Playground of Angular+React+Custom Element
TypeScript
3
star
21

proposal-promise.delay-and-timeout

Promise.delay and Promise.timeout proposal
HTML
3
star
22

webextension-systemjs

A SystemJS loader for Web Extension content script
TypeScript
2
star
23

mcmod-faster-chat

A faster chat (by limit fps)!
Java
2
star
24

matrix-js-sdk-type

2
star
25

ts-nodenext-wrong-resolution-reproduction

TypeScript
2
star
26

typescript-marco-demo

TypeScript
2
star
27

commonjs-import.meta

A TypeScript transformer that add import.meta support for CommonJS module format.
TypeScript
2
star
28

pug-lint-loader

Unoffical pug-lint loader for Webpack
JavaScript
1
star
29

typescript-use-customCondition-to-redirect-monorepo-source-to-support-project-reference

repro
TypeScript
1
star
30

proposal-serializer

HTML
1
star
31

eslaf-paint

JavaScript
1
star
32

rollup-plugin-bug-287-reproduce

JavaScript
1
star
33

jack-dvorak

A programmer dvorak variant I use
1
star
34

proposal-strict-built-in-functions

1
star
35

reproduce

I'm tired of create a new repo every time when I need to report some bug. Let the bug report files go here.
1
star
36

proposal-arraybuffer-fixed-view

A proposal that allows to provide a fixed view to the ArrayBuffer
HTML
1
star