Stone.jsDocs
Paradigm

Adapters

AWS API Gateway WebSocket

Realtime, serverless. An API Gateway WebSocket API invokes a fresh Lambda per socket event, so @stone-js/aws-apigw-ws-adapter maps $connect, $disconnect and messages onto @stone-js/realtime: presence lives in DynamoDB, your @On* gateways fire, and replies go out through the API Gateway Management API. The exact gateway code you run on the Node ws adapter runs here unchanged, the context collapses the difference.

#Install

terminalbash
npm i @stone-js/aws-apigw-ws-adapter @stone-js/realtime
npm i @aws-sdk/client-apigatewaymanagementapi @aws-sdk/client-dynamodb @aws-sdk/lib-dynamodb

#Enable it

Add the adapter to the manifest, on top of @stone-js/realtime. The adapter is the default in a Lambda environment.

app/Application.tsts
import { StoneApp } from '@stone-js/core'
import { Realtime } from '@stone-js/realtime'
import { ApiGatewayWs } from '@stone-js/aws-apigw-ws-adapter'

@ApiGatewayWs()
@Realtime({ driver: 'memory' })   // bootstraps the RealtimeManager
@StoneApp({ name: 'chat' })
export class Application {}

#Use the serverless broadcaster

With no held socket, presence must be shared across invocations. Register the DynamoDB-backed broadcaster as the realtime default; the adapter resolves it and points it at each event's management endpoint.

app/ApiGatewayWsRealtimeProvider.tsts
import { RealtimeManager } from '@stone-js/realtime'
import { ApiGatewayWsBroadcaster, DynamoDbConnectionStore } from '@stone-js/aws-apigw-ws-adapter'

export class ApiGatewayWsRealtimeProvider {
  register () {
    RealtimeManager.getInstance()
      ?.register('apigw-ws', ApiGatewayWsBroadcaster.create({
        store: DynamoDbConnectionStore.create({ table: 'ws_connections' })
      }))
      .setDefaultConnection('apigw-ws')
  }
}

#Register the handler

run() returns the (event, context) Lambda handler; wire it to your API's routes ($connect, $disconnect, $default).

index.jsts
export const handler = await stoneApp.run()

#Gateways

The same gateway API as everywhere else, one method per event:

app/Chat.tsts
import { RealtimeGateway, OnConnect, OnEvent, connectionOf } from '@stone-js/realtime'

@RealtimeGateway()
export class Chat {
  constructor (private readonly realtime) {}

  @OnConnect() onConnect (_, event) { const connection = connectionOf(event) /* … */ }

  @OnEvent('room:1', 'message')
  async onMessage (payload, event) {
    await this.realtime.to('room:1').emit('message', payload)   // fans out via postToConnection
  }
}

#Configuration

keyTypeDescription
DynamoDbConnectionStore.tablestone_ws_connectionsThe DynamoDB table holding connections and channel memberships.

Stone.js

Your app exists in every runtime. Until you run it.

An open-source project by Stone Foundation
Created by Mr. Stone (Evens Pierre)