subscribe
Executes a callback when an on-chain object is updated. The client will receive two messages, one when the transaction is first seen in the mempool, and another when it is confirmed on-chain. The callback receives the new revision of the object and the hex of the transaction encoding the update. This function uses Server-Sent Events (SSEs) to provide real-time updates.
Type
subscribe(
id: string,
onMessage: ({ rev, hex }: { rev: string; hex: string }) => void,
onError?: (error: Event) => void,
): Promise<() => void>
Parameters
id
The id of an on-chain object.
onMessage
The function to call when the object is updated. The callback has two parameters, the new revision of the object and the hex of the transaction encoding the update.
onError
The function to call when an error is thrown.
Return Value
A function to close the connection to the server.
Description
The function enables real-time updates via Server-Sent Events (SSEs). The function takes an on-chain ID and a callback function as arguments. The callback is triggered whenever a method is called on the on-chain object with the specified ID. The callback receives two parameters: the new revision of the object and the hex of the transaction encoding the update.
When invoked, the function establishes a connection to the server to listen for updates related to the specified on-chain ID. It returns a function that can be called to close the connection when real-time updates are no longer needed.
Example
import { Computer, Contract } from '@bitcoin-computer/lib'
import { chain, expect, network, url } from '../../utils/index.js'
describe('subscribe', () => {
// A smart contract
class Counter extends Contract {
n: number
constructor() {
super({ n: 0 })
}
inc() {
this.n += 1
}
}
let computer: Computer
let close: () => void
beforeEach('Before Computer', async () => {
computer = new Computer({ chain, network, url })
await computer.faucet(10e8)
})
it('Should work when subscribing by id', async () => {
// Create on-chain object
const c = await computer.new(Counter, [])
// Subscribe to updates on object c
let eventCount = 0
const close = await computer.subscribe(c._id, ({ rev, hex }) => {
expect(rev).to.be.a('string')
expect(hex).to.be.a('string')
eventCount += 1
})
// Update on-chain object
await c.inc()
await c.inc()
// Wait for events using a Promise
await new Promise<void>((resolve, reject) => {
let retryCount = 0
// Retry every 200 ms
const interval = setInterval(() => {
retryCount += 1
// if at least two events have been received the test passes
if (eventCount >= 2) {
clearInterval(interval)
resolve()
}
// After 4 s the test fails
if (retryCount > 20) {
clearInterval(interval)
close()
reject(new Error('Missed SSE'))
}
}, 200)
})
// Close connection to the server
close()
})
it('Should not emit events for unsubscribed keys', async () => {
let eventCount = 0
const nonValidId = 'error:0'
const c = await computer.new(Counter, [])
close = await computer.subscribe(nonValidId, ({}) => {
eventCount += 1
})
await c.inc()
await c.inc()
await new Promise<void>((resolve, reject) => {
let retryCount = 0
const interval = setInterval(() => {
retryCount += 1
if (retryCount > 10) {
clearInterval(interval)
if (eventCount === 0) {
resolve() // Success: no events
} else {
reject(new Error('Received unexpected SSE for unsubscribed key'))
}
}
}, 200)
})
close()
})
})