Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/design/API-DESIGN.md
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,7 @@ The Transferable class is functional on both sides, but the implementations diff

| Side | Class | Methods | Source |
|------|-------|---------|--------|
| Server (Lambda) | `RealtimeChannel` | Real AWS SDK calls (AppSync, IoT, etc.) | `aws-runtime` export |
| Server (Lambda) | `RealtimeChannel` | API Gateway Management API + DynamoDB connection registry | `aws-runtime` export |
| Server (Mock) | `RealtimeChannel` | In-process event emitter | `default` export |
| Client (Browser) | `RealtimeChannelClient` | WebSocket connection | Client plugin |

Expand Down
46 changes: 24 additions & 22 deletions docs/reference/ARCHITECTURE-LAYERS.md
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ export {};
realtime/
├── client-hook.ts # WebSocket client setup
├── index.ts # Server-side pub/sub
├── infra.ts # AppSync Event API
├── infra.ts # API Gateway WebSocket API + DynamoDB connection registry
└── mock.ts # In-memory pub/sub
```

Expand Down Expand Up @@ -317,28 +317,30 @@ export class RealtimeClientHook {

**index.ts:**
```typescript
import { IoTDataPlaneClient, PublishCommand } from '@aws-sdk/client-iot-data-plane';
import {
ApiGatewayManagementApiClient,
PostToConnectionCommand,
} from '@aws-sdk/client-apigatewaymanagementapi';

export class Realtime {
private client?: IoTDataPlaneClient;
private endpoint?: string;

constructor(public name: string, public options: any) {}

private getClient() {
if (!this.client) {
this.endpoint = process.env[`BLOCKS_${this.name}_ENDPOINT`];
this.client = new IoTDataPlaneClient({ endpoint: this.endpoint });
}
return this.client;
}

async publish(channel: string, message: any) {
const client = this.getClient();
await client.send(new PublishCommand({
topic: channel,
payload: Buffer.from(JSON.stringify(message))
}));
constructor(
private connections: {
forChannel(channel: string): Promise<string[]>;
},
) {}

async publish(channel: string, message: unknown) {
const client = new ApiGatewayManagementApiClient({
endpoint: process.env.BLOCKS_RT_CALLBACK_URL,
});
const connectionIds = await this.connections.forChannel(channel);

await Promise.all(connectionIds.map((connectionId) =>
client.send(new PostToConnectionCommand({
ConnectionId: connectionId,
Data: JSON.stringify(message),
})),
));
}
}
```
Expand All @@ -347,7 +349,7 @@ export class Realtime {
```typescript
import { Construct } from 'constructs';
import { CfnOutput } from 'aws-cdk-lib';
// AppSync or IoT Core setup...
// API Gateway WebSocket API, route integrations, and a DynamoDB connection registry.

export function materialize(scope: Construct, name: string, options: any) {
// Create WebSocket API infrastructure
Expand Down
44 changes: 23 additions & 21 deletions docs/reference/building-block-structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -299,28 +299,30 @@ Building Blocks with custom client protocols (WebSocket, etc.):

**index.ts:**
```typescript
import { IoTDataPlaneClient, PublishCommand } from '@aws-sdk/client-iot-data-plane';
import {
ApiGatewayManagementApiClient,
PostToConnectionCommand,
} from '@aws-sdk/client-apigatewaymanagementapi';

export class Realtime {
private client?: IoTDataPlaneClient;
private endpoint?: string;

constructor(public name: string, public options: any) {}

private getClient() {
if (!this.client) {
this.endpoint = process.env[`BLOCKS_${this.name}_ENDPOINT`];
this.client = new IoTDataPlaneClient({ endpoint: this.endpoint });
}
return this.client;
}

async publish(channel: string, message: any) {
const client = this.getClient();
await client.send(new PublishCommand({
topic: channel,
payload: Buffer.from(JSON.stringify(message))
}));
constructor(
private connections: {
forChannel(channel: string): Promise<string[]>;
},
) {}

async publish(channel: string, message: unknown) {
const client = new ApiGatewayManagementApiClient({
endpoint: process.env.BLOCKS_RT_CALLBACK_URL,
});
const connectionIds = await this.connections.forChannel(channel);

await Promise.all(connectionIds.map((connectionId) =>
client.send(new PostToConnectionCommand({
ConnectionId: connectionId,
Data: JSON.stringify(message),
})),
));
}
}
```
Expand All @@ -329,7 +331,7 @@ export class Realtime {
```typescript
import { Construct } from 'constructs';
import { CfnOutput } from 'aws-cdk-lib';
// AppSync or IoT Core setup...
// API Gateway WebSocket API, route integrations, and a DynamoDB connection registry.

export function materialize(scope: Construct, name: string, options: any) {
// Create WebSocket API infrastructure
Expand Down
2 changes: 1 addition & 1 deletion packages/bb-agent/src/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ export class AgentBase<TContext = DefaultToolContext> extends Scope {

/**
* @param scope - Blocks scope parent (determines resource naming and CDK discovery)
* @param id - unique agent ID (used in resource names, keep short for AppSync namespace limits)
* @param id - unique agent ID (used in resource names; keep it short for AWS resource naming limits)
* @param config - developer-facing agent configuration
* @param modelConfig - which model to use, picked by subclass (model.local or model.deployed)
* @param createSnapshotStorage - factory that receives the internal FileBucket and returns the appropriate SnapshotStorage
Expand Down
8 changes: 4 additions & 4 deletions packages/bb-realtime/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ globalEmitter.setMaxListeners(1000);
// ── Realtime ────────────────────────────────────────────────────────────────

/**
* Real-time pub/sub messaging backed by AWS AppSync Events.
* Real-time pub/sub messaging backed by API Gateway WebSocket + DynamoDB.
*
* **When to use:** You need to push data from the server to connected clients
* in real time — chat messages, live notifications, dashboard updates,
Expand All @@ -67,9 +67,9 @@ globalEmitter.setMaxListeners(1000);
* - Keep message payloads small — large payloads increase latency and cost
* - Return channel handles from API methods for seamless client hydration
*
* **Scaling:** WebSocket connections managed by AppSync Events. Automatic scaling.
* $1.00 per million operations. 200 subscriptions per connection (adjustable).
* Message fan-out cost is proportional to subscriber count.
* **Scaling:** API Gateway manages WebSocket connections. The Blocks handler
* fans each publish out to subscribed connections, so latency and cost scale
* with subscriber count. See the package README for limits and cost details.
*
* @example
* ```typescript
Expand Down
6 changes: 3 additions & 3 deletions packages/blocks/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,12 +159,12 @@ export { DistributedTable, DistributedTableErrors } from '@aws-blocks/bb-distrib
export type { DistributedTableOptions, ReadValidationMode, TableKeyConfig, TableKey, PutOptions as DTPutOptions, DeleteOptions as DTDeleteOptions, QueryOptions as DTQueryOptions, ScanOptions as DTScanOptions } from '@aws-blocks/bb-distributed-table';

/**
* **Real-time pub/sub messaging backed by AppSync Events.**
* **Real-time pub/sub messaging backed by API Gateway WebSocket + DynamoDB.**
*
* Use for pushing data to connected browser clients: chat, notifications,
* live dashboards, collaborative editing. Typed namespaces with schema
* validation on publish. Local dev uses WebSocket bridge; production uses
* AppSync Events API.
* validation on publish. Local dev uses a WebSocket bridge; production uses
* API Gateway WebSocket with DynamoDB-backed connection tracking.
*
* Package: `@aws-blocks/bb-realtime`
* Full docs: `README.md` in the package directory above.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ Blocks provides AuthBasic for username and password authentication with JWT sess

## Can I use Blocks for real-time features?

Yes, the Realtime Building Block provides typed pub/sub messaging backed by AppSync Events. It supports chat, notifications, live dashboards, and collaborative editing with typed namespaces and schema validation.
Yes, the Realtime Building Block provides typed pub/sub messaging backed by API Gateway WebSocket and DynamoDB. It supports chat, notifications, live dashboards, and collaborative editing with typed namespaces and schema validation.