Skip to content
Merged
1 change: 0 additions & 1 deletion examples/room-manager/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
"@fastify/swagger": "^9.4.2",
"@types/node": "^22.13.16",
"pino-pretty": "^13.0.0",
"tsc": "^2.0.4",
"tsx": "^4.19.3",
"typescript": "~5.8.2"
},
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@
"typescript-eslint": "^8.29.0"
},
"scripts": {
"build": "yarn workspaces foreach -At run build",
"lint": "yarn workspaces foreach -At run lint",
"lint:check": "yarn workspaces foreach -At run lint:check",
"build": "yarn workspaces foreach -A --topological-dev run build",
"lint": "yarn workspaces foreach -A -p run lint",
"lint:check": "yarn workspaces foreach -A -p run lint:check",
"typecheck": "yarn workspaces foreach -A -p run typecheck",
"format:check": "yarn workspaces foreach -A -p run format:check",
"format": "yarn workspaces foreach -A -p run format",
Expand Down
25 changes: 21 additions & 4 deletions packages/composition/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@fishjam-cloud/composition",
"version": "0.29.0-rc.0",
"description": "Composition event bus contract for Fishjam templates",
"description": "React hooks and event bus for building Fishjam composition templates",
"homepage": "https://github.com/fishjam-cloud/js-server-sdk",
"author": "Fishjam Team",
"repository": {
Expand Down Expand Up @@ -32,10 +32,15 @@
"types": "./dist/index.d.ts",
"import": "./dist/index.mjs",
"require": "./dist/index.js"
},
"./core": {
"types": "./dist/core.d.ts",
"import": "./dist/core.mjs",
"require": "./dist/core.js"
}
},
"scripts": {
"build": "tsup --dts-resolve",
"build": "tsup",
"format": "prettier --write .",
"format:check": "prettier --check .",
"typecheck": "tsc --noEmit",
Expand All @@ -45,18 +50,30 @@
},
"tsup": {
"entry": [
"src/index.ts"
"src/index.ts",
"src/core.ts"
],
"minify": false,
"format": [
"cjs",
"esm"
],
"outDir": "dist"
"outDir": "dist",
"dts": true,
"clean": true
},
"peerDependencies": {
"@fishjam-cloud/js-server-sdk": "workspace:^",
"react": ">=18"
},
"devDependencies": {
"@fishjam-cloud/js-server-sdk": "workspace:*",
"@types/react": "^19.0.0",
"@types/react-dom": "^19.1.9",
"eslint": "^9.33.0",
"prettier": "^3.6.2",
"react": "^19.0.0",
"react-dom": "^19.0.0",
Comment thread
AHGIJMKLKKZNPJKQR marked this conversation as resolved.
"tsup": "^8.4.0",
"vitest": "^3.0.0"
},
Expand Down
2 changes: 2 additions & 0 deletions packages/composition/src/core.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { compositionStore } from './store';
export type { CompositionEvent, RoomSnapshot, CompositionStoreFeed } from './store';
10 changes: 10 additions & 0 deletions packages/composition/src/eventBus.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
export interface CompositionEventBus {
on<T = unknown>(eventName: string, callback: (data: T) => void): () => void;
}

declare global {
// eslint-disable-next-line no-var
var eventBus: CompositionEventBus;
}

export const eventBus = globalThis.eventBus;
47 changes: 47 additions & 0 deletions packages/composition/src/hooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { useCallback, useSyncExternalStore } from 'react';
import { compositionStore } from './store';
import type { PeerWithStreams, VadStatus } from './types';

/**
* All peers in the linked room, projected into composition streams. Flat list —
* the worker is not a peer, so there is no local/remote split.
*/
export function usePeers<PeerMetadata = unknown, ServerMetadata = unknown>(): PeerWithStreams<
PeerMetadata,
ServerMetadata
>[] {
const peers = useSyncExternalStore(compositionStore.subscribe, compositionStore.getPeers, compositionStore.getPeers);
return peers as PeerWithStreams<PeerMetadata, ServerMetadata>[];
}

/**
* The peer with the given `peerId`, or `undefined`.
*/
export function usePeer<PeerMetadata = unknown, ServerMetadata = unknown>(
peerId: string
): PeerWithStreams<PeerMetadata, ServerMetadata> | undefined {
const getSnapshot = useCallback(() => compositionStore.getPeer(peerId), [peerId]);
const peer = useSyncExternalStore(compositionStore.subscribe, getSnapshot, getSnapshot);
return peer as PeerWithStreams<PeerMetadata, ServerMetadata> | undefined;
}

/**
* The linked room's id, or `undefined` when no room is linked.
*/
export function useRoom(): { id: string } | undefined {
const roomId = useSyncExternalStore(
compositionStore.subscribe,
compositionStore.getRoomId,
compositionStore.getRoomId
);
return roomId ? { id: roomId } : undefined;
}

/**
* Voice-activity status for the peer identified by `peerId`: `'speech'` when any
* of the peer's forwarded audio inputs is speaking, otherwise `'silence'`.
*/
export function useSpeakingState(peerId: string): VadStatus {
const getSnapshot = useCallback(() => compositionStore.getVadStatus(peerId), [peerId]);
return useSyncExternalStore(compositionStore.subscribe, getSnapshot, getSnapshot);
}
Comment thread
AHGIJMKLKKZNPJKQR marked this conversation as resolved.
15 changes: 10 additions & 5 deletions packages/composition/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
export interface CompositionEventBus {
on<T = unknown>(eventName: string, callback: (data: T) => void): () => void;
}

export const eventBus = (globalThis as unknown as { eventBus: CompositionEventBus }).eventBus;
/**
* React hooks for composition templates receiving track forwardings from rooms.
* Templates have access to a room's state (peers, tracks, voice activity).
*
* @packageDocumentation
*/
export { usePeers, usePeer, useRoom, useSpeakingState } from './hooks';
export type { PeerWithStreams, Stream, TrackState, VideoTrackState, AudioTrackState, VadStatus } from './types';
export { eventBus } from './eventBus';
export type { CompositionEventBus } from './eventBus';
Loading
Loading