# Channels

Live changes, Broadcast, and Presence.

[Read the database changes guide](/docs/live-changes/). Signatures below come from the published SDK declarations. Access SDK services through `db`; use their constructors only when integrating at a lower level.

## REALTIME_KIND


```ts
/** Public channel traffic. Relay storage of ephemeral events is not required by Nostr. */
declare const REALTIME_KIND = 20078;
```

## ChannelOptions


```ts
interface ChannelOptions {
  broadcast?: {
    self?: boolean;
  };
  /** Times are seconds. Heartbeats must occur before half the TTL has passed. */
  presence?: {
    ttl?: number;
    heartbeatInterval?: number;
  };
}
```

## BroadcastMessage


```ts
interface BroadcastMessage {
  type: "broadcast";
  event: string;
  payload: unknown;
}
```

## BroadcastPayload


```ts
interface BroadcastPayload extends BroadcastMessage {
  pubkey: string;
  sessionId: string;
  eventId: string;
}
```

## PresenceMeta


```ts
interface PresenceMeta {
  pubkey: string;
  sessionId: string;
  state: Record<string, unknown>;
  expiresAt: number;
}
```

## PresenceState


```ts
type PresenceState = Record<string, PresenceMeta[]>;
```

## PresencePayload


```ts
interface PresencePayload {
  event: "sync" | "join" | "leave";
  key?: string;
  newPresences?: PresenceMeta[];
  leftPresences?: PresenceMeta[];
}
```

## NostrbaseChannel


```ts
declare class NostrbaseChannel<DB extends SchemaShape<DB>> {}
```

### Properties


```ts
readonly name: string;
```

### constructor


```ts
constructor(client: NostrbaseClient<DB>, name: string, options?: ChannelOptions);
```

### on


```ts
on<K extends keyof DB & string>(
  type: "nostr_changes" | "postgres_changes",
  filter: ChangeFilter & {
    table: K;
  },
  callback: (payload: ChangePayload<DB[K]>) => void,
): this;

on(
  type: "broadcast",
  filter: {
    event: string;
  },
  callback: (payload: BroadcastPayload) => void,
): this;

on(
  type: "presence",
  filter: {
    event: PresencePayload["event"];
  },
  callback: (payload: PresencePayload) => void,
): this;
```

### presenceState


```ts
/** State is grouped by signing public key; each browser tab has a distinct session. */
presenceState(): PresenceState;
```

### send


```ts
/** Signed public ephemeral broadcast. Receiving subscriptions need no signer. */
send(message: BroadcastMessage): Promise<Result<WriteReceipt>>;
```

### track


```ts
track(state: Record<string, unknown>): Promise<Result<WriteReceipt>>;
```

### untrack


```ts
untrack(): Promise<Result<WriteReceipt>>;
```

### subscribe


```ts
/** Initial cached/relay records are delivered as INSERT. SUBSCRIBED means handlers are installed. */
subscribe(callback?: (status: ChannelStatus, error?: NostrbaseError) => void): this;
```

### unsubscribe


```ts
unsubscribe(): void;
```
