@stone-js/aws-apigw-ws-adapter
v0.8.19
Published
AWS API Gateway WebSocket adapter for Stone.js: maps $connect/$disconnect/messages onto @stone-js/realtime, with a DynamoDB presence store and Management API fan-out.
Maintainers
Readme
Stone.js - AWS API Gateway WebSocket Adapter
AWS API Gateway WebSocket adapter for Stone.js. Runs your realtime app serverlessly: each socket event ($connect, $disconnect, a message) is a Lambda invocation, mapped onto @stone-js/realtime. The adapter keeps presence in DynamoDB (shared across the ephemeral invocations), fires your @On* gateways, and pushes messages back through the API Gateway Management API. The same gateway code runs here and on the Node ws adapter, no change.
Installation
npm install @stone-js/aws-apigw-ws-adapter @stone-js/realtime
# the AWS SDKs it uses (optional peers, imported lazily):
npm install @aws-sdk/client-apigatewaymanagementapi @aws-sdk/client-dynamodb @aws-sdk/lib-dynamodbPeer dependencies:
@stone-js/core,@stone-js/envand@stone-js/realtime. The three@aws-sdk/*packages are optional peers, imported lazily when used.
Enable it
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 {}Register the serverless broadcaster (DynamoDB-backed presence) as the realtime default with a small provider. The adapter then resolves it from the manager and points it at each event's management endpoint:
import { IServiceProvider } from '@stone-js/core'
import { RealtimeManager } from '@stone-js/realtime'
import { ApiGatewayWsBroadcaster, DynamoDbConnectionStore } from '@stone-js/aws-apigw-ws-adapter'
export class ApiGatewayWsRealtimeProvider implements IServiceProvider {
register (): void {
RealtimeManager.getInstance()
?.register('apigw-ws', ApiGatewayWsBroadcaster.create({
store: DynamoDbConnectionStore.create({ table: 'ws_connections' })
}))
.setDefaultConnection('apigw-ws')
}
}Gateways react to sockets
import { RealtimeGateway, OnConnect, OnEvent, connectionOf } from '@stone-js/realtime'
@RealtimeGateway()
export class Chat {
constructor (private readonly realtime) {}
@OnConnect() onConnect (_, event) { const connection = connectionOf(event) /* authorize… */ }
@OnEvent('room:1', 'message')
async onMessage (payload, event) {
await this.realtime.to('room:1').emit('message', payload) // fans out via postToConnection
}
}How it works
run()returns the(event, context)Lambda handler for your WebSocket API's routes.requestContext.eventTypeis mapped to a routing key:CONNECTadds the connection to the store;DISCONNECTremoves it;MESSAGEparses the frame.- Each event is normalized into an
IncomingEventand run through the kernel, where the light key-router routes it to the matching@On*gateway (@OnConnect,@OnEvent, ...). - Control frames (
{ type: 'subscribe' | 'unsubscribe', channel }) also update DynamoDB presence. - A
broadcastreads the channel's members from DynamoDB and posts to each via the Management API (the endpoint is taken from the event).
