alice-bob

transport agnostic strongly typed duplex rpc interfaces

Usage no npm install needed!

<script type="module">
  import aliceBob from 'https://cdn.skypack.dev/alice-bob';
</script>

README

👫
alice-bob

transport agnostic strongly typed duplex rpc interfaces

🔧 Install · 🧩 Example · 📜 API docs · 🔥 Releases · 💪🏼 Contribute · 🖐️ Help


Install

$ npm i alice-bob

Example

// alice

import { fork } from 'child_process'
import { join } from 'path'

import { Alice } from 'alice-bob'

// we import Bob's interface and call it Remote
// bob will show as Agent<Remote> in intellisense
import type { Interface as Remote } from './bob'

export interface Interface {
  hiya: (message: { from: string }) => Promise<void>
}

// for intellisense reasons we alias our interface to `Local`
// so that alice shows as Agent<Local> and bob as Agent<Remote>
type Local = Interface

// start bob
const child = fork(join(__dirname, 'bob'))

// create an Alice instance with given `send` function as the
// constructor parameter. Note that Alice, Bob both inherit from
// the AliceBob class, the only thing they change is they have
// the names "alice" and "bob" preconfigured in their agents
const [alice, bob] = new Alice<Local, Remote>(
  data => void child.send(data)
).agents()

// all messages from bob passed to alice.receive
child.on('message', alice.receive)

// we can set debug=true|false at any time
alice.debug = true

// methods can be added also lazily at any time at any scope..
alice.hiya = async ({ from }) => {
  alice.log(from, 'says: hiya!')
  // => alice: bob says: hiya!
  // `agent.log()` prepends the agent's name to the output
}

const sayHello = async () => {
  const result = await bob.hello('there', { iam: alice.name })
  alice.log('bob responded with:', result)
  // => alice: bob responded with: hi alice

  process.exit(0)
}

sayHello()
// bob

import { Bob } from 'alice-bob'
import type { Interface as Remote } from './alice'

export interface Interface {
  hello: (message: string, data: { iam: string }) => Promise<string>
}

type Local = Interface

const [bob, alice] = new Bob<Local, Remote>().agents({ debug: true })

// we connect our transport in just these two lines
process.on('message', bob.receive)

// send method can be provided at any time
bob.send = data => void process.send!(data)

bob.hello = async (message, { iam }) => {
  bob.log(iam + ' says: hello ' + message)

  // we can call alice methods as well
  await alice.hiya({ from: 'bob' })

  // if we throw here the remote's `await`
  // will throw as well with this message
  // throw new Error('failed :(')

  return 'hi ' + iam
}

API

Table of Contents

Payload

src/index.ts:6-19

Payload.

id

src/index.ts:10-10

Payload id.

Type: number

method

src/index.ts:14-14

Method to call.

Type: any

args

src/index.ts:18-18

The arguments passed to the method.

Type: Array<any>

Agent

src/index.ts:28-70

Agent.

Type: any

debug

src/index.ts:32-32

Whether or not to log debugging information.

Type: boolean

name

src/index.ts:38-38

The name of the agent. Defaults to either 'alice' or 'bob' depending on the constructor used, Alice or Bob.

Type: string

send

src/index.ts:43-43

The send method overriden by the user to any transport.

Type: PayloadMethod<Agent<B, A>>

deferredSend

src/index.ts:49-49

Returns the send method. Used in contexts where it might change between sessions, like browser refresh/hot/livereload.

Type: function (): PayloadMethod<Agent<B, A>>

log

src/index.ts:59-59

Overridable logging function. Defaults to console.log() and prepends agent.name.

Type: function (...args: Array<any>): void

AliceBob

src/index.ts:78-283

AliceBob class.

Parameters

  • send PayloadMethod<Agent<A, B>>? The send payload method provided by the user. Will be called with a payload to be sent.

local

src/index.ts:91-91

The local Agent.

Type: Agent<A, B>

remote

src/index.ts:95-95

The remote Agent.

Type: Agent<B, A>

agents

src/index.ts:275-282

Returns the agents tuple [alice, bob].

Example:

const [alice, bob] = new Alice<Local, Remote>().agents()

// to enable debugging on local (alice)
const [alice, bob] = new Alice<Local, Remote>().agents({ debug: true })

// use different names:
const [alice, bob] = new Alice<Local, Remote>().agents(
  { name: 'server', debug: true },
  { name: 'client' }
)
Parameters
  • local (Partial<Agent<A, B>> | null)? Local agent overrides.
  • remote (Partial<Agent<B, A>> | null)? Remote agent overrides.

Alice

src/index.ts:291-301

Extends AliceBob

Alice class.

Parameters

  • send PayloadMethod<Agent<A, B>>? The send payload method provided by the user. Will be called with a payload to be sent.

Bob

src/index.ts:309-319

Extends AliceBob

Bob class.

Parameters

  • send PayloadMethod<Agent<A, B>>? The send payload method provided by the user. Will be called with a payload to be sent.

Contribute

Fork or edit and submit a PR.

All contributions are welcome!

License

MIT © 2021 stagas