Skip to main content

Transport Layer and SDK

The transport layer is how your application talks to the crawler. EasyLayer ships five built-in transports, and every one of them uses the same query format. Switch transports without changing your application code.


Available Transports​

TransportUse caseParallel queries
HTTP RPCServer apps, serverless, webhooksNo (single-flight)
WebSocketReal-time event streamsNo
IPC ParentYour app spawns the crawler as a child processYes (correlationId)
IPC ChildCrawler spawns your app as a child processYes
Electron IPCDesktop app (main process to renderer)N/A
SharedWorkerBrowser extension or SPAN/A

Client SDK​

Install @easylayer/transport-sdk in your application. It provides a single Client class that wraps all transports.

npm install @easylayer/transport-sdk

subscribe() and query()​

Two methods cover all use cases:

  • subscribe(eventType, handler) — receive events pushed by the crawler as they happen
  • query(name, dto?) — request current or historical state
import { Client } from '@easylayer/transport-sdk';

const client = new Client({
transport: {
type: 'http',
inbound: { webhookUrl: '`http://0.0.0.0:4000/events',` pongPassword: 'pw' },
query: { baseUrl: '`http://localhost:3000'` },
},
});

// Receive events in real time
client.subscribe('Deposit', (event) => {
console.log('New deposit at block', event.blockHeight, event.payload);
});

// Query current state
const [model] = await client.query('GetModelsQuery', { modelIds: ['wallet-tracker'] });
console.log(model.state.balances);

HTTP Transport​

The HTTP client mounts a webhook handler on your existing server. Inbound events arrive as POST requests; outbound queries are POST requests to the crawler.

import { createServer } from 'http';
const client = new Client({
transport: {
type: 'http',
inbound: { webhookUrl: '`http://0.0.0.0:4000/events',` pongPassword: 'secret' },
query: { baseUrl: '`http://localhost:3000'` },
},
});
createServer(client.nodeHttpHandler()).listen(4000);
// or: app.use(client.expressRouter())

WebSocket Transport​

For persistent connections and real-time event streams.

const client = new Client({
transport: {
type: 'ws',
options: { url: 'ws://localhost:3001', pongPassword: 'secret' },
},
});
await client.connect();
client.subscribe('BlockConfirmed', (event) => { /* ... */ });

connect() never rejects. If the initial connection fails, it starts a background reconnect loop silently.


IPC Transport​

For Node.js microservice setups where the crawler and your app run as separate processes.

// Parent process spawns crawler as child
import { spawn } from 'child_process';
const crawlerProcess = spawn('node', ['crawler.js']);

const client = new Client({
transport: { type: 'ipc-parent', options: { process: crawlerProcess, pongPassword: 'secret' } },
});

IPC supports parallel queries via correlationId matching, which makes it the highest-throughput option for process-local communication.


Electron Transport​

For desktop applications. The crawler runs in the main process; your UI queries it from the renderer.

// In the renderer process
const client = new Client({
transport: { type: 'electron-renderer', options: { channel: 'crawler', pongPassword: 'secret' } },
});

SharedWorker (Browser)​

For browser extensions and SPAs where the crawler runs inside a SharedWorker with IndexedDB storage.

// In the extension or SPA
const client = new Client({
transport: { type: 'shared-worker', options: { workerUrl: './crawler.worker.js', pongPassword: 'secret' } },
});

How Event Delivery Works​

The crawler keeps an outbox table. When your model produces events, they go into the outbox. The transport reads the outbox, sends a batch to your client, and waits for an acknowledgment (ACK). Once the ACK arrives, the batch is deleted from the outbox.

If your handler throws or takes too long (default timeout: 3000 ms), the crawler retries. This gives you at-least-once delivery for every event.

To increase the timeout for slow handlers (e.g. writing to a database on every event):

const client = new Client({
transport: {
type: 'ws',
options: { url: 'ws://localhost:3001', pongPassword: 'secret', processTimeoutMs: 10_000 },
},
});

Built-in Query Types​

QueryDescription
GetModelsQueryCurrent state of one or more models (optionally at a specific block height)
FetchEventsQueryPaginated event history with optional filtering
GetNetworkStatsQuerySync status, block height, chain info
GetNetworkLastBlockQueryLatest indexed block