@signalling/sdk 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +202 -0
- package/dist/index.d.mts +1568 -0
- package/dist/index.d.ts +1568 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +2 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +53 -0
package/README.md
ADDED
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# `@signalling/sdk`
|
|
2
|
+
|
|
3
|
+
A browser-first JavaScript SDK for the **Confrnce signalling API**. It is
|
|
4
|
+
explicitly designed as an **API wrapper, not a parallel stack** — every public
|
|
5
|
+
method maps onto a real route or wire-protocol artefact on the server.
|
|
6
|
+
The integrator writes their own UI; the SDK handles auth, DPoP signing, the
|
|
7
|
+
WebSocket handshake, WebRTC peer orchestration, and room state.
|
|
8
|
+
|
|
9
|
+
## Standalone distribution
|
|
10
|
+
|
|
11
|
+
This folder is **self-contained**. Third parties can vendor it alone (copy the
|
|
12
|
+
directory, `npm install`, `npm run build`) or split it into a dedicated Git
|
|
13
|
+
repository — no backend or monorepo checkout is required. Protocol details
|
|
14
|
+
(DPoP, WebSocket handshake) are summarized under `docs/` in this package.
|
|
15
|
+
|
|
16
|
+
> **Internal reference:** If you also maintain the server repo, architectural
|
|
17
|
+
> notes may live alongside the backend (e.g. `AUTH_FLOW.md`). This README is the
|
|
18
|
+
> SDK consumer entry point.
|
|
19
|
+
|
|
20
|
+
## Table of contents
|
|
21
|
+
|
|
22
|
+
- [Why this SDK](#why-this-sdk)
|
|
23
|
+
- [What's inside](#whats-inside)
|
|
24
|
+
- [Installation](#installation)
|
|
25
|
+
- [Quickstart](#quickstart)
|
|
26
|
+
- [Public API](#public-api)
|
|
27
|
+
- [Backend contract this SDK wraps](#backend-contract-this-sdk-wraps)
|
|
28
|
+
- [Documentation](#documentation)
|
|
29
|
+
|
|
30
|
+
## Why this SDK
|
|
31
|
+
|
|
32
|
+
Without the SDK, an integrator has to:
|
|
33
|
+
|
|
34
|
+
- run the OIDC + PKCE handshake themselves;
|
|
35
|
+
- generate a non-extractable P-256 keypair, persist it in IndexedDB, never
|
|
36
|
+
let it leave the device;
|
|
37
|
+
- sign every outbound HTTP request with a fresh DPoP JWT, including the
|
|
38
|
+
`htm` / `htu` / `iat` / `jti` / `nonce` claims;
|
|
39
|
+
- handle `Use-DPoP-Nonce` retry loops;
|
|
40
|
+
- run a two-stage WebSocket handshake (HTTP ticket + WS upgrade + DPoP first
|
|
41
|
+
frame within 5 s + ack), strip query / fragment from `htu`, decode the
|
|
42
|
+
ticket nonce out of the JWT body, and react to a dozen 4xxx close codes;
|
|
43
|
+
- wire `RTCPeerConnection` instances, fan SDP offers / answers / ICE
|
|
44
|
+
candidates over the room WebSocket, fall back to TURN when ICE fails,
|
|
45
|
+
surface the local screen-share lifecycle.
|
|
46
|
+
|
|
47
|
+
This SDK does all of that for you. Under the hood, every call ultimately hits
|
|
48
|
+
the backend’s HTTP routes and WebSocket wire format your server documents.
|
|
49
|
+
|
|
50
|
+
## What's inside
|
|
51
|
+
|
|
52
|
+
```text
|
|
53
|
+
src/
|
|
54
|
+
api/ REST client (DPoP-signed; nonce-retry)
|
|
55
|
+
auth/ Login / bind / logout / me
|
|
56
|
+
dpop/ WebCrypto P-256 keypair + JWS proofs (IndexedDB-persisted)
|
|
57
|
+
websocket/ Ticket → upgrade → DPoP first-frame → ack
|
|
58
|
+
room/ REST wrapper + local clientId tracking
|
|
59
|
+
webrtc/ Peer orchestration over the room WebSocket
|
|
60
|
+
devices/ getUserMedia / getDisplayMedia / device enumeration
|
|
61
|
+
internal/ base64url, logger, typed event emitter (NOT exported)
|
|
62
|
+
types/ Public domain types + error classes
|
|
63
|
+
index.ts SignallingSDK + Call composition
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Installation
|
|
67
|
+
|
|
68
|
+
```bash
|
|
69
|
+
npm install @signalling/sdk
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The package ships ESM (`dist/index.mjs`), CJS (`dist/index.js`), and TS
|
|
73
|
+
declarations. No runtime dependencies are required.
|
|
74
|
+
|
|
75
|
+
## Quickstart
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
import { SignallingSDK } from "@signalling/sdk";
|
|
79
|
+
|
|
80
|
+
// 1. Initialise (eagerly loads the DPoP keypair from IndexedDB)
|
|
81
|
+
const sdk = await SignallingSDK.create({
|
|
82
|
+
baseUrl: "https://api.example.com",
|
|
83
|
+
authMode: "bff",
|
|
84
|
+
logLevel: "info",
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// 2. Authenticate (BFF redirect → Keycloak → /auth/complete page)
|
|
88
|
+
if (!(await sdk.auth.isAuthenticated())) {
|
|
89
|
+
// First load: send the user to Keycloak.
|
|
90
|
+
sdk.auth.login("/dashboard");
|
|
91
|
+
// ...
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// 3. On the SPA's /auth/complete page:
|
|
95
|
+
const bindToken = sdk.auth.bindTokenFromFragment();
|
|
96
|
+
if (bindToken) {
|
|
97
|
+
const { returnTo } = await sdk.auth.completeBind(bindToken);
|
|
98
|
+
window.location.assign(returnTo || "/");
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
// 4. Create or join a room.
|
|
102
|
+
const room = await sdk.rooms.create(); // { roomId, clientId }
|
|
103
|
+
const call = await sdk.calls.joinRoom({
|
|
104
|
+
roomId: room.roomId,
|
|
105
|
+
media: { audio: true, video: true },
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// 5. React to events.
|
|
109
|
+
call.on("peer.joined", (p) => console.log("joined:", p.clientId));
|
|
110
|
+
call.on("stream.added", ({ clientId, stream }) => attachToDom(clientId, stream));
|
|
111
|
+
call.on("peer.left", (p) => removeFromDom(p.clientId));
|
|
112
|
+
call.on("connection.closed", ({ code }) => console.warn("WS closed:", code));
|
|
113
|
+
|
|
114
|
+
// 6. Tear down on unmount.
|
|
115
|
+
await call.leave();
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## Public API
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
class SignallingSDK {
|
|
122
|
+
static create(config: SignallingSDKConfig): Promise<SignallingSDK>;
|
|
123
|
+
|
|
124
|
+
// Module entry points (all stateful).
|
|
125
|
+
auth: AuthClient; // login / completeBind / logout / me / updateProfile
|
|
126
|
+
rooms: RoomManager; // create / join / view / leave / screenshare / permissions
|
|
127
|
+
devices: DeviceManager; // getLocalStream / getScreenShare / listInventory
|
|
128
|
+
api: ApiClient; // raw REST surface (escape hatch)
|
|
129
|
+
ws: WebSocketClient; // raw WebSocket (escape hatch)
|
|
130
|
+
webrtc: WebRTCManager; // raw RTCPeerConnection orchestration
|
|
131
|
+
dpop: DPoPManager; // raw DPoP signer
|
|
132
|
+
logger: Logger;
|
|
133
|
+
|
|
134
|
+
// High-level orchestration: join + ws + webrtc in one call.
|
|
135
|
+
calls: { joinRoom(config: CallConfig): Promise<Call> };
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
class Call extends TypedEventEmitter<CallEventMap> {
|
|
139
|
+
readonly roomId: number | string;
|
|
140
|
+
readonly clientId: string;
|
|
141
|
+
localStream: MediaStream | null;
|
|
142
|
+
|
|
143
|
+
setMicEnabled(on: boolean): void;
|
|
144
|
+
setCameraEnabled(on: boolean): void;
|
|
145
|
+
setLocalStream(s: MediaStream | null): Promise<void>;
|
|
146
|
+
startScreenShare(): Promise<MediaStream>;
|
|
147
|
+
stopScreenShare(): Promise<void>;
|
|
148
|
+
leave(): Promise<void>;
|
|
149
|
+
}
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
The full strongly-typed event map (`CallEventMap`, `WebRTCEventMap`,
|
|
153
|
+
`WebSocketEventMap`, `AuthEventMap`) is exported from the entry point.
|
|
154
|
+
|
|
155
|
+
## Backend contract this SDK wraps
|
|
156
|
+
|
|
157
|
+
Every public method ultimately reaches one of:
|
|
158
|
+
|
|
159
|
+
| SDK method | Backend route |
|
|
160
|
+
|---------------------------------------------|-------------------------------------------------------------------|
|
|
161
|
+
| `sdk.auth.login()` | `GET /auth/login` *(browser navigation)* |
|
|
162
|
+
| `sdk.auth.completeBind(token)` | `POST /auth/dpop/bind` |
|
|
163
|
+
| `sdk.auth.getCurrentUser()` | `GET /me` |
|
|
164
|
+
| `sdk.auth.updateProfile(...)` | `PATCH /me` |
|
|
165
|
+
| `sdk.auth.logout()` | `POST /auth/logout` |
|
|
166
|
+
| `sdk.auth.logoutAll()` | `POST /auth/logout-all` |
|
|
167
|
+
| `sdk.auth.openAccountConsole()` | `GET /auth/account` *(browser navigation)* |
|
|
168
|
+
| `sdk.rooms.create()` | `POST /createroom` |
|
|
169
|
+
| `sdk.rooms.join(id)` | `POST /joinroom/{roomId}` |
|
|
170
|
+
| `sdk.rooms.view(id)` | `GET /viewroom/{roomId}` |
|
|
171
|
+
| `sdk.rooms.leave()` | `DELETE /leaveroom/{roomId}/{clientId}` |
|
|
172
|
+
| `sdk.rooms.startScreenShare()` | `POST /room/{roomId}/{clientId}/screen-share/start` |
|
|
173
|
+
| `sdk.rooms.stopScreenShare()` | `POST /room/{roomId}/{clientId}/screen-share/stop` |
|
|
174
|
+
| `sdk.rooms.myPermissions()` | `GET /room/{roomId}/{clientId}/permissions` |
|
|
175
|
+
| `sdk.rooms.updatePermissions(...)` | `PUT /room/{roomId}/{clientId}/permissions` |
|
|
176
|
+
| `sdk.api.getTurnCredentials()` | `POST /v1/turn/credentials` |
|
|
177
|
+
| `sdk.api.searchUserByEmail(email)` | `GET /users/search?email=...` |
|
|
178
|
+
| `sdk.api.issueWSTicket()` | `POST /auth/ws-ticket` |
|
|
179
|
+
| Internal — used by `ws.connectRoom` | `WS /ws/{roomId}/{clientId}?ticket=...` |
|
|
180
|
+
| Internal — used by `ws.connectGlobal` | `WS /global/ws?ticket=...` |
|
|
181
|
+
|
|
182
|
+
Every authed REST call carries a `DPoP: <jws>` header generated fresh by
|
|
183
|
+
`DPoPManager`. Every WS upgrade is followed by a single
|
|
184
|
+
`{ "type": "dpop_handshake", "proof": "..." }` frame; the SDK waits for
|
|
185
|
+
`{ "type": "dpop_handshake_ack" }` before passing application messages
|
|
186
|
+
through.
|
|
187
|
+
|
|
188
|
+
## Documentation
|
|
189
|
+
|
|
190
|
+
The `docs/` folder contains task-oriented guides:
|
|
191
|
+
|
|
192
|
+
- [`docs/quickstart.md`](./docs/quickstart.md) — installation, init, first call
|
|
193
|
+
- [`docs/auth.md`](./docs/auth.md) — BFF flow, Bearer mode for native apps, DPoP, completeBind, logout
|
|
194
|
+
- [`docs/deployment.md`](./docs/deployment.md) — publish + consume the SDK, Keycloak prerequisites for both modes
|
|
195
|
+
- [`docs/rooms-and-calls.md`](./docs/rooms-and-calls.md) — rooms, events, screen share
|
|
196
|
+
- [`docs/media.md`](./docs/media.md) — device enumeration, getUserMedia, TURN
|
|
197
|
+
- [`docs/api-reference.md`](./docs/api-reference.md) — full method index
|
|
198
|
+
- [`docs/troubleshooting.md`](./docs/troubleshooting.md) — common errors + fixes
|
|
199
|
+
|
|
200
|
+
If you change a public method here, update the matching doc in the same PR.
|
|
201
|
+
The docs are checked manually in code review against the shipped surface.
|
|
202
|
+
"# signalling-js-sdk"
|