@soulcraft/sdk 2.0.0 → 2.0.2

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.
Files changed (93) hide show
  1. package/dist/client/index.d.ts +5 -38
  2. package/dist/client/index.d.ts.map +1 -1
  3. package/dist/client/index.js +5 -47
  4. package/dist/client/index.js.map +1 -1
  5. package/dist/client/namespace-proxy.d.ts +3 -4
  6. package/dist/client/namespace-proxy.d.ts.map +1 -1
  7. package/dist/client/namespace-proxy.js +3 -4
  8. package/dist/client/namespace-proxy.js.map +1 -1
  9. package/dist/index.d.ts +6 -6
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +4 -4
  12. package/dist/index.js.map +1 -1
  13. package/dist/modules/hall/browser.d.ts +83 -27
  14. package/dist/modules/hall/browser.d.ts.map +1 -1
  15. package/dist/modules/hall/browser.js +238 -49
  16. package/dist/modules/hall/browser.js.map +1 -1
  17. package/dist/modules/hall/media.d.ts +164 -0
  18. package/dist/modules/hall/media.d.ts.map +1 -0
  19. package/dist/modules/hall/media.js +182 -0
  20. package/dist/modules/hall/media.js.map +1 -0
  21. package/dist/modules/hall/server.d.ts +83 -6
  22. package/dist/modules/hall/server.d.ts.map +1 -1
  23. package/dist/modules/hall/server.js +206 -9
  24. package/dist/modules/hall/server.js.map +1 -1
  25. package/dist/modules/hall/types.d.ts +548 -25
  26. package/dist/modules/hall/types.d.ts.map +1 -1
  27. package/dist/modules/hall/types.js +12 -7
  28. package/dist/modules/hall/types.js.map +1 -1
  29. package/dist/server/hall-handlers.d.ts +40 -12
  30. package/dist/server/hall-handlers.d.ts.map +1 -1
  31. package/dist/server/hall-handlers.js +40 -12
  32. package/dist/server/hall-handlers.js.map +1 -1
  33. package/dist/server/handlers/chat/engine.d.ts.map +1 -1
  34. package/dist/server/handlers/chat/engine.js +5 -1
  35. package/dist/server/handlers/chat/engine.js.map +1 -1
  36. package/dist/server/handlers/chat/types.d.ts +17 -2
  37. package/dist/server/handlers/chat/types.d.ts.map +1 -1
  38. package/dist/server/hono-router.d.ts +2 -9
  39. package/dist/server/hono-router.d.ts.map +1 -1
  40. package/dist/server/hono-router.js +2 -46
  41. package/dist/server/hono-router.js.map +1 -1
  42. package/dist/server/index.d.ts +4 -19
  43. package/dist/server/index.d.ts.map +1 -1
  44. package/dist/server/index.js +10 -29
  45. package/dist/server/index.js.map +1 -1
  46. package/dist/types.d.ts +2 -41
  47. package/dist/types.d.ts.map +1 -1
  48. package/docs/ADR-005-hall-integration.md +449 -0
  49. package/package.json +1 -1
  50. package/dist/client/create-client-sdk.d.ts +0 -113
  51. package/dist/client/create-client-sdk.d.ts.map +0 -1
  52. package/dist/client/create-client-sdk.js +0 -169
  53. package/dist/client/create-client-sdk.js.map +0 -1
  54. package/dist/modules/app-context/index.d.ts +0 -214
  55. package/dist/modules/app-context/index.d.ts.map +0 -1
  56. package/dist/modules/app-context/index.js +0 -569
  57. package/dist/modules/app-context/index.js.map +0 -1
  58. package/dist/modules/billing/firestore-provider.d.ts +0 -60
  59. package/dist/modules/billing/firestore-provider.d.ts.map +0 -1
  60. package/dist/modules/billing/firestore-provider.js +0 -315
  61. package/dist/modules/billing/firestore-provider.js.map +0 -1
  62. package/dist/modules/brainy/proxy.d.ts +0 -48
  63. package/dist/modules/brainy/proxy.d.ts.map +0 -1
  64. package/dist/modules/brainy/proxy.js +0 -95
  65. package/dist/modules/brainy/proxy.js.map +0 -1
  66. package/dist/server/create-sdk.d.ts +0 -74
  67. package/dist/server/create-sdk.d.ts.map +0 -1
  68. package/dist/server/create-sdk.js +0 -104
  69. package/dist/server/create-sdk.js.map +0 -1
  70. package/dist/server/from-license.d.ts +0 -252
  71. package/dist/server/from-license.d.ts.map +0 -1
  72. package/dist/server/from-license.js +0 -349
  73. package/dist/server/from-license.js.map +0 -1
  74. package/dist/server/handlers.d.ts +0 -312
  75. package/dist/server/handlers.d.ts.map +0 -1
  76. package/dist/server/handlers.js +0 -376
  77. package/dist/server/handlers.js.map +0 -1
  78. package/dist/server/postmessage-handler.d.ts +0 -152
  79. package/dist/server/postmessage-handler.d.ts.map +0 -1
  80. package/dist/server/postmessage-handler.js +0 -138
  81. package/dist/server/postmessage-handler.js.map +0 -1
  82. package/dist/transports/http.d.ts +0 -86
  83. package/dist/transports/http.d.ts.map +0 -1
  84. package/dist/transports/http.js +0 -137
  85. package/dist/transports/http.js.map +0 -1
  86. package/dist/transports/postmessage.d.ts +0 -159
  87. package/dist/transports/postmessage.d.ts.map +0 -1
  88. package/dist/transports/postmessage.js +0 -207
  89. package/dist/transports/postmessage.js.map +0 -1
  90. package/dist/transports/workshop.d.ts +0 -173
  91. package/dist/transports/workshop.d.ts.map +0 -1
  92. package/dist/transports/workshop.js +0 -307
  93. package/dist/transports/workshop.js.map +0 -1
@@ -0,0 +1,449 @@
1
+ # ADR-005: Hall Integration — Real-Time Communication Layer
2
+
3
+ **Status:** Accepted
4
+ **Date:** 2026-03-12
5
+ **SDK version:** 1.7.0
6
+
7
+ ---
8
+
9
+ ## Context
10
+
11
+ Soulcraft needs a real-time communication layer for live sessions (Academy cohorts,
12
+ Workshop collaboration, Venue events). Hall is a standalone Rust server at
13
+ `hall.soulcraft.com` that provides WebRTC SFU, transcription, pub/sub, media processing,
14
+ and broadcast auto-scaling.
15
+
16
+ The SDK wraps Hall's wire protocol to give products a typed, ergonomic API for both
17
+ server backends and browser clients — without exposing raw WebSocket/msgpack details.
18
+
19
+ ---
20
+
21
+ ## Architecture
22
+
23
+ ### Server/Client Asymmetry
24
+
25
+ Hall uses a strict separation between control plane (server) and data plane (browser):
26
+
27
+ ```
28
+ ┌──────────────────┐ msgpack/WS ┌──────────────────┐
29
+ │ Product backend │ ◄──────────────────► │ Hall server │
30
+ │ (Hono/SvelteKit) │ control plane │ (Rust, SFU) │
31
+ └────────┬─────────┘ └────────┬─────────┘
32
+ │ │
33
+ │ POST /api/join │ WebRTC / WS
34
+ │ { token, hallUrl } │ data plane
35
+ │ │
36
+ ▼ ▼
37
+ ┌──────────────────┐ WebRTC + WS ┌──────────────────┐
38
+ │ Browser kit app │ ◄──────────────────► │ Hall SFU │
39
+ │ (joinHallRoom) │ audio/video/data │ │
40
+ └──────────────────┘ └──────────────────┘
41
+ ```
42
+
43
+ - **Server** (`@soulcraft/sdk/server`): `createHallModule()` returns a `HallModule` that
44
+ manages rooms, issues tokens, controls recording, manages pub/sub topics, uploads media,
45
+ and promotes/demotes peers in broadcast rooms.
46
+
47
+ - **Browser** (`@soulcraft/sdk/client`): `joinHallRoom()` joins a WebRTC room using a
48
+ short-lived token. `joinHallPubsub()` connects to topic-based messaging.
49
+
50
+ Products never pass their shared secret to the browser. All browser credentials are
51
+ short-lived tokens issued by the product backend.
52
+
53
+ ### SDK Files
54
+
55
+ | File | Role |
56
+ |------|------|
57
+ | `src/modules/hall/types.ts` | All TypeScript interfaces and wire protocol message types |
58
+ | `src/modules/hall/server.ts` | `HallClient` — product WebSocket connection to Hall |
59
+ | `src/modules/hall/browser.ts` | `joinHallRoom()`, `joinHallPubsub()` — browser clients |
60
+ | `src/modules/hall/media.ts` | `HallMediaClient` — HTTP client for media pipeline |
61
+ | `src/modules/hall/protocol.ts` | Generic msgpack encode/decode for Hall wire format |
62
+ | `src/server/hall-handlers.ts` | Re-export factories: `createHallModule`, `createHallMediaClient` |
63
+
64
+ ---
65
+
66
+ ## Wire Protocol
67
+
68
+ Hall uses **msgpack** over WebSocket with a tag/content encoding:
69
+
70
+ ```typescript
71
+ { t: 'createRoom', d: { roomId: 'cohort-123', options: { ... } } }
72
+ ```
73
+
74
+ The `t` field is the message type (string), `d` is the typed payload. This matches Rust
75
+ serde's `#[serde(tag = "t", content = "d")]` attribute. All field names are camelCase
76
+ (Rust uses `#[serde(rename_all = "camelCase")]`).
77
+
78
+ The full message unions are defined as `HallClientMessage` (17 variants) and
79
+ `HallServerMessage` (28 variants) in `types.ts`. These are internal to the SDK — products
80
+ never construct raw protocol messages.
81
+
82
+ ---
83
+
84
+ ## Feature Overview
85
+
86
+ ### 1. WebRTC SFU — Small Group Communication
87
+
88
+ For groups up to 30 participants with full bidirectional audio/video.
89
+
90
+ **Server side:**
91
+ ```typescript
92
+ const hall = createHallModule({
93
+ url: process.env.HALL_URL!,
94
+ productName: 'academy',
95
+ secret: process.env.HALL_ACADEMY_SECRET!,
96
+ })
97
+ await hall.connect()
98
+
99
+ const room = await hall.createRoom('cohort-123', {
100
+ enableTranscription: true,
101
+ concepts: await loadConcepts(cohortId),
102
+ })
103
+
104
+ room.on('transcript', (t) => saveTranscript(t))
105
+ room.on('conceptMention', (c) => brain.relate({ from: c.peerId, to: c.nodeId }))
106
+
107
+ const { token } = await hall.createSessionToken('cohort-123', userId)
108
+ // Return { token, hallUrl } to the browser
109
+ ```
110
+
111
+ **Browser side:**
112
+ ```typescript
113
+ import { joinHallRoom } from '@soulcraft/sdk/client'
114
+
115
+ const room = await joinHallRoom({ token, hallUrl })
116
+ room.addStream(await navigator.mediaDevices.getUserMedia({ video: true, audio: true }))
117
+
118
+ room.on('trackAdded', ({ peerId, streams }) => {
119
+ videoElement.srcObject = streams[0]
120
+ })
121
+ room.on('transcript', ({ peerId, text, isFinal }) => {
122
+ if (isFinal) appendTranscript(peerId, text)
123
+ })
124
+ ```
125
+
126
+ **AI features** — Hall runs Whisper ASR in-process and feeds transcripts through a BERT
127
+ model for concept matching against workspace knowledge graphs. Events flow from Hall →
128
+ product backend → (optionally) browser:
129
+
130
+ | Event | Description |
131
+ |-------|-------------|
132
+ | `transcript` | Whisper ASR transcript segment (partial or final) |
133
+ | `conceptMention` | BERT matched a concept node from the workspace graph |
134
+ | `relationProposed` | Inferred subject-verb-object relation for review |
135
+ | `speakerChanged` | Active speaker changed (RFC 6464 audio level detection) |
136
+
137
+ ### 2. Three-Tier Broadcast Auto-Scaling
138
+
139
+ For large audiences (webinars, lectures, live events). Hall automatically scales across
140
+ three tiers based on audience size:
141
+
142
+ ```
143
+ Tier 1: Participant (WebRTC SFU) — ≤30 peers, full bidirectional, ~50ms latency
144
+ Tier 2: WHEP Viewer (WebRTC recv) — sub-second latency, receive-only, ~200 peers
145
+ Tier 3: LL-HLS Viewer (HTTP stream) — 2–3s latency, unlimited scale
146
+ ```
147
+
148
+ **Server setup:**
149
+ ```typescript
150
+ const room = await hall.createRoom('lecture-456', {
151
+ maxParticipants: 5, // Only 5 can publish (speakers)
152
+ allowBroadcast: true, // Overflow joiners become viewers
153
+ enableRecording: true,
154
+ recordingComposite: true, // Mixed MP4 in addition to per-track MKV
155
+ recordingWebhookUrl: 'https://academy.soulcraft.com/api/recordings/complete',
156
+ })
157
+
158
+ // Monitor audience
159
+ room.on('viewerCount', ({ participants, whepViewers, hlsViewers }) => {
160
+ console.log(`${participants} speakers, ${whepViewers + hlsViewers} watching`)
161
+ })
162
+
163
+ // Promote a viewer to speaker
164
+ hall.promotePeer('lecture-456', 'student-789')
165
+
166
+ // Demote back to viewer
167
+ hall.demotePeer('lecture-456', 'student-789')
168
+ ```
169
+
170
+ **Browser — role awareness:**
171
+ ```typescript
172
+ const room = await joinHallRoom({ token, hallUrl })
173
+
174
+ room.on('roleChanged', ({ role, canPublish }) => {
175
+ if (canPublish) {
176
+ // Promoted — start publishing media
177
+ room.addStream(await navigator.mediaDevices.getUserMedia({ audio: true }))
178
+ } else {
179
+ // Demoted — SDK handles transport downgrade automatically
180
+ hidePublishUI()
181
+ }
182
+ })
183
+
184
+ // Viewers can also connect via WHEP or LL-HLS directly:
185
+ import { getWhepUrl, getHlsUrl } from '@soulcraft/sdk/client'
186
+
187
+ const whepUrl = getWhepUrl('https://hall.soulcraft.com', 'lecture-456')
188
+ const hlsUrl = getHlsUrl('https://hall.soulcraft.com', 'lecture-456')
189
+ ```
190
+
191
+ **Screen share simulcast:**
192
+ ```typescript
193
+ // Server controls the encoding strategy per-peer
194
+ hall.setScreenShareMode('lecture-456', speakerPeerId, 'static') // Presentations
195
+ hall.setScreenShareMode('lecture-456', speakerPeerId, 'motion') // Live demos
196
+ ```
197
+
198
+ ### 3. Pub/Sub — Topic-Based Messaging with Presence
199
+
200
+ Product-scoped topic routing with presence tracking, replay buffers, and both server-side
201
+ and browser-side APIs.
202
+
203
+ **Server side (product backend):**
204
+ ```typescript
205
+ // Subscribe and broadcast from the backend
206
+ hall.subscribeTopic('notifications', { service: 'academy' })
207
+ hall.broadcastTopic('notifications', { type: 'cohort-started', cohortId: '123' })
208
+
209
+ // Listen for pub/sub events
210
+ hall.onPubsub('topicMessage', ({ topic, senderId, payload }) => {
211
+ console.log(`[${topic}] ${senderId}: ${JSON.stringify(payload)}`)
212
+ })
213
+ hall.onPubsub('presenceUpdate', ({ topic, peerId, action }) => {
214
+ console.log(`${peerId} ${action} ${topic}`)
215
+ })
216
+
217
+ // Issue a browser pub/sub token
218
+ const { token } = await hall.createPubsubToken(userId, ['chat:*', 'presence:*'])
219
+ ```
220
+
221
+ **Browser side:**
222
+ ```typescript
223
+ import { joinHallPubsub } from '@soulcraft/sdk/client'
224
+
225
+ const pubsub = await joinHallPubsub({ token, hallUrl: 'wss://hall.soulcraft.com' })
226
+
227
+ pubsub.subscribe('chat:cohort-123', { username: 'Alice' })
228
+ pubsub.on('topicSubscribed', ({ topic, replay }) => {
229
+ // replay contains recent messages from the buffer
230
+ replay.forEach(({ senderId, payload }) => showMessage(senderId, payload))
231
+ })
232
+ pubsub.on('topicMessage', ({ senderId, payload }) => showMessage(senderId, payload))
233
+ pubsub.on('presenceUpdate', ({ peerId, action }) => updatePresence(peerId, action))
234
+
235
+ pubsub.broadcast('chat:cohort-123', { text: 'Hello everyone!' })
236
+
237
+ // Cleanup
238
+ pubsub.close()
239
+ ```
240
+
241
+ **Key pub/sub design decisions:**
242
+ - Topics are product-scoped — `academy` cannot see `workshop` topics
243
+ - Replay buffers are per-topic, configurable in `hall.toml`
244
+ - Presence metadata is arbitrary JSON, set at subscribe time
245
+ - Chat in rooms is bridged to pub/sub topic `room:{roomId}:chat`
246
+
247
+ ### 4. Media Pipeline — Upload, Transcode, Retrieve
248
+
249
+ HTTP-based media processing for audio, video, and images. Async notifications arrive
250
+ over the product WebSocket.
251
+
252
+ ```typescript
253
+ import { createHallMediaClient } from '@soulcraft/sdk/server'
254
+
255
+ const media = createHallMediaClient({
256
+ baseUrl: 'https://hall.soulcraft.com',
257
+ productName: 'workshop',
258
+ secret: process.env.HALL_WORKSHOP_SECRET!,
259
+ })
260
+
261
+ // Upload with transcoding
262
+ const { mediaId } = await media.upload(file, { transcode: 'video/mp4' })
263
+
264
+ // Listen for completion (on any room — media events are product-scoped)
265
+ room.on('mediaReady', ({ mediaId, duration, dimensions }) => {
266
+ const streamUrl = media.getStreamUrl(mediaId)
267
+ const thumbUrl = media.getThumbnailUrl(mediaId)
268
+ })
269
+ room.on('mediaError', ({ mediaId, error }) => {
270
+ console.error(`Media ${mediaId} failed: ${error}`)
271
+ })
272
+
273
+ // Query media info
274
+ const info = await media.getInfo(mediaId)
275
+
276
+ // Delete media
277
+ await media.delete(mediaId)
278
+ ```
279
+
280
+ **Auth model for media:**
281
+ - Upload/delete/info use `Authorization: Hall <productName>:<secret>` (server-only)
282
+ - Stream/thumbnail are public `GET /media/{mediaId}/*` endpoints (no auth, browser-safe)
283
+ - WHEP/HLS endpoints are public (browser embeds the URL directly)
284
+
285
+ ### 5. Recording
286
+
287
+ Per-track MKV recording with optional composite MP4. Recording can be started/stopped
288
+ programmatically or enabled at room creation.
289
+
290
+ ```typescript
291
+ // Start recording on demand
292
+ await hall.startRecording('cohort-123')
293
+
294
+ // ... later ...
295
+ await hall.stopRecording('cohort-123')
296
+
297
+ // The room emits a manifest with file paths
298
+ room.on('recordingManifest', (manifest) => {
299
+ console.log(`Tracks: ${manifest.audioTracks.length} audio, ${manifest.videoTracks.length} video`)
300
+ if (manifest.compositePath) console.log(`Composite: ${manifest.compositePath}`)
301
+ if (manifest.cloudUrls) console.log(`Cloud: ${manifest.cloudUrls.join(', ')}`)
302
+ // Upload to your own storage or use Hall's cloud upload (configured in hall.toml)
303
+ })
304
+
305
+ // Or configure recording at room creation
306
+ await hall.createRoom('lecture-456', {
307
+ enableRecording: true,
308
+ recordingComposite: true,
309
+ recordingWebhookUrl: 'https://academy.soulcraft.com/api/recordings/complete',
310
+ })
311
+ ```
312
+
313
+ **Webhook:** When configured, Hall POSTs `{ sessionId, manifest }` JSON to the webhook URL
314
+ on recording completion, with exponential backoff retry (3 attempts).
315
+
316
+ ---
317
+
318
+ ## Integration Patterns by Product
319
+
320
+ ### Academy — Cohort Sessions
321
+
322
+ Academy uses Hall for live cohort sessions with AI-powered concept tracking:
323
+
324
+ ```typescript
325
+ // Server: hooks.server.ts
326
+ const hall = createHallModule({ url, productName: 'academy', secret })
327
+ await hall.connect()
328
+
329
+ // API route: /api/cohort/:id/join
330
+ const room = await hall.createRoom(cohortId, {
331
+ enableTranscription: true,
332
+ concepts: await brain.find({ nounType: 'concept' }),
333
+ allowBroadcast: true,
334
+ maxParticipants: 10,
335
+ })
336
+ room.on('conceptMention', async (c) => {
337
+ await brain.relate({ from: c.peerId, verb: c.verbType, to: c.nodeId })
338
+ })
339
+ room.on('transcript', (t) => saveToLessonLog(cohortId, t))
340
+ const { token } = await hall.createSessionToken(cohortId, userId)
341
+ return { token, hallUrl: process.env.HALL_URL }
342
+ ```
343
+
344
+ ### Workshop — Collaborative Editing Sessions
345
+
346
+ Workshop uses Hall for real-time collaboration alongside Y.js document editing:
347
+
348
+ ```typescript
349
+ const room = await hall.createRoom(`workspace-${workspaceId}`, {
350
+ enableTranscription: false, // Text-only collaboration
351
+ })
352
+ // Use pub/sub for cursor positions, selection state, awareness
353
+ hall.subscribeTopic(`cursor:${workspaceId}`)
354
+ hall.onPubsub('topicMessage', ({ topic, payload }) => broadcastToYDoc(payload))
355
+ ```
356
+
357
+ ### Venue — Live Events and Broadcasts
358
+
359
+ Venue uses Hall for large-audience events with the full broadcast tier:
360
+
361
+ ```typescript
362
+ const room = await hall.createRoom(`event-${eventId}`, {
363
+ maxParticipants: 3, // Panel of speakers
364
+ allowBroadcast: true, // Unlimited audience
365
+ enableRecording: true,
366
+ recordingComposite: true,
367
+ })
368
+
369
+ // Browser viewers use WHEP or LL-HLS
370
+ const whepUrl = getWhepUrl(hallUrl, `event-${eventId}`)
371
+ const hlsUrl = getHlsUrl(hallUrl, `event-${eventId}`)
372
+ ```
373
+
374
+ ---
375
+
376
+ ## Environment Variables
377
+
378
+ | Variable | Description |
379
+ |----------|-------------|
380
+ | `HALL_URL` | WebSocket URL of the Hall server (`wss://hall.soulcraft.com`) |
381
+ | `HALL_<PRODUCT>_SECRET` | Product-specific shared secret (e.g. `HALL_ACADEMY_SECRET`) |
382
+
383
+ Secrets are configured in `hall.toml` on the Hall server under `[auth.products.<name>]`.
384
+
385
+ ---
386
+
387
+ ## Exports
388
+
389
+ ### From `@soulcraft/sdk/server`
390
+
391
+ | Export | Kind | Description |
392
+ |--------|------|-------------|
393
+ | `createHallModule` | Function | Create a server-side `HallModule` connection |
394
+ | `createHallMediaClient` | Function | Create an HTTP media pipeline client |
395
+ | `generateTurnCredentials` | Function | Generate ephemeral TURN credentials |
396
+ | `HallClient` | Class | Low-level WebSocket client (advanced use) |
397
+ | `HallMediaClient` | Class | Low-level HTTP media client (advanced use) |
398
+ | `HallModule` | Interface | Full server-side Hall API |
399
+ | `HallRoom` | Interface | Active room handle with event listeners |
400
+ | `HallRoomEvents` | Interface | Event map for room listeners |
401
+ | `HallPubsubEvents` | Interface | Event map for pub/sub listeners |
402
+
403
+ ### From `@soulcraft/sdk/client`
404
+
405
+ | Export | Kind | Description |
406
+ |--------|------|-------------|
407
+ | `joinHallRoom` | Function | Join a WebRTC room from the browser |
408
+ | `joinHallPubsub` | Function | Connect to pub/sub from the browser |
409
+ | `getWhepUrl` | Function | Get WHEP viewer URL for a broadcast room |
410
+ | `getHlsUrl` | Function | Get LL-HLS viewer URL for a broadcast room |
411
+ | `HallRoomHandle` | Interface | Browser room handle with events |
412
+ | `HallRoomHandleEvents` | Interface | Event map for browser room |
413
+ | `HallPubsubHandle` | Interface | Browser pub/sub handle with events |
414
+ | `HallPubsubHandleEvents` | Interface | Event map for browser pub/sub |
415
+
416
+ ### From `@soulcraft/sdk` (shared types)
417
+
418
+ All Hall types are re-exported from the shared entry for use in any environment.
419
+ `ChatMessage` and `MediaInfo` are exported as `HallChatMessage` and `HallMediaInfo`
420
+ to avoid collisions with the SDK 2.0 namespace types.
421
+
422
+ ---
423
+
424
+ ## Rejected Alternatives
425
+
426
+ ### 1. Embedding WebRTC in the SDK server
427
+
428
+ **Rejected:** Products could run their own SFU inside the SDK. This would couple the SDK
429
+ to WebRTC dependencies (libwebrtc, TURN), increase binary size, and duplicate what Hall
430
+ already does as a dedicated Rust server. The SDK is a control-plane wrapper, not a
431
+ media server.
432
+
433
+ ### 2. REST API for Hall control
434
+
435
+ **Rejected:** REST would add HTTP overhead and lose the event-push capability (transcripts,
436
+ concept mentions, media notifications). The persistent WebSocket connection gives
437
+ sub-millisecond event delivery and supports reconnect with state preservation.
438
+
439
+ ### 3. Unified browser transport (WebRTC + pub/sub on same connection)
440
+
441
+ **Rejected:** WebRTC peer connections and pub/sub topics have different lifecycles, auth
442
+ scopes, and reconnect semantics. Separate connections (`joinHallRoom` vs `joinHallPubsub`)
443
+ keep each concern simple and independently testable.
444
+
445
+ ### 4. GraphQL for media pipeline
446
+
447
+ **Rejected:** The media pipeline is simple CRUD + upload. REST with `Authorization` header
448
+ is the right fit. GraphQL subscriptions for transcode notifications would duplicate the
449
+ WebSocket event system that already exists.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@soulcraft/sdk",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "description": "The unified Soulcraft platform SDK — data, auth, AI, billing, and notifications",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -1,113 +0,0 @@
1
- /**
2
- * @module client/create-client-sdk
3
- * @description `createClientSDK` factory for browser/client-mode @soulcraft/sdk.
4
- *
5
- * Assembles a `SoulcraftSDK` from a `ClientSDKOptions` specification. Selects and
6
- * wires the appropriate transport (`http`, `ws`, or `sse`) and returns a full SDK
7
- * object whose `sdk.brainy.*` API works identically to server mode.
8
- *
9
- * ## Transport selection
10
- *
11
- * | `transport` | Use case |
12
- * |-------------|----------|
13
- * | `'http'` | Stateless RPC — kit apps, simple clients. No push events. |
14
- * | `'ws'` | Bidirectional RPC + real-time change push. Call `sdk.connect()` first. |
15
- * | `'sse'` | Receive-only push events. Pair with `'http'` for outbound RPC. |
16
- *
17
- * ## Auth
18
- *
19
- * - `auth: 'cookie'` — sends session cookies (same-origin browser use). HTTP only.
20
- * - `auth: { token }` — sends `Authorization: Bearer <token>`. HTTP and WS.
21
- * - Omit `auth` for unauthenticated requests (public endpoints).
22
- *
23
- * @example HTTP transport (kit app, cookie auth)
24
- * ```typescript
25
- * import { createClientSDK } from '@soulcraft/sdk/client'
26
- *
27
- * const sdk = createClientSDK({
28
- * mode: 'client',
29
- * product: 'workshop',
30
- * transport: 'http',
31
- * baseUrl: 'https://workshop.soulcraft.com',
32
- * auth: 'cookie',
33
- * })
34
- *
35
- * const results = await sdk.brainy.find({ query: 'candle kits', limit: 10 })
36
- * ```
37
- *
38
- * @example WebSocket transport (real-time change push)
39
- * ```typescript
40
- * import { createClientSDK } from '@soulcraft/sdk/client'
41
- *
42
- * const sdk = createClientSDK({
43
- * mode: 'client',
44
- * product: 'venue',
45
- * transport: 'ws',
46
- * baseUrl: 'wss://venue.soulcraft.com/api/brainy/ws',
47
- * auth: { token: capabilityToken },
48
- * })
49
- *
50
- * await sdk.connect!()
51
- * sdk.brainy.onDataChange((event) => refreshUI(event))
52
- * const items = await sdk.brainy.find({ query: 'inventory' })
53
- * ```
54
- *
55
- * @example SSE transport (receive-only change events + HTTP for outbound)
56
- * ```typescript
57
- * import { createClientSDK } from '@soulcraft/sdk/client'
58
- *
59
- * const sdk = createClientSDK({
60
- * mode: 'client',
61
- * product: 'venue',
62
- * transport: 'sse',
63
- * baseUrl: 'https://venue.soulcraft.com',
64
- * auth: 'cookie',
65
- * })
66
- *
67
- * // sdk.brainy.onDataChange() fires on live server changes.
68
- * // sdk.brainy.find() etc. are not available on SSE — wire an HttpTransport separately.
69
- * sdk.brainy.onDataChange((event) => console.log('change:', event))
70
- * ```
71
- */
72
- import type { SoulcraftSDK } from '../types.js';
73
- /**
74
- * Legacy client SDK options. Kept for backward compatibility with `createClientSDK()`.
75
- * New code should use `createSoulcraftProxy()` with a namespace-aware transport instead.
76
- */
77
- interface LegacyClientSDKOptions {
78
- mode: 'client';
79
- product: string;
80
- transport: 'http' | 'ws' | 'sse';
81
- baseUrl: string;
82
- auth?: 'cookie' | {
83
- token: string;
84
- };
85
- timeoutMs?: number;
86
- }
87
- /**
88
- * Create a client-mode `SoulcraftSDK` from the given options.
89
- *
90
- * Selects the transport specified by `options.transport`, wires auth, and returns
91
- * a `SoulcraftSDK` whose `sdk.brainy.*` surface is identical to server mode.
92
- *
93
- * For `'ws'` transport, call `await sdk.connect!()` before making any `sdk.brainy.*`
94
- * calls to establish the WebSocket connection.
95
- *
96
- * @param options - Client SDK options including transport, baseUrl, and auth.
97
- * @returns A `SoulcraftSDK` backed by the chosen transport.
98
- *
99
- * @example HTTP transport
100
- * ```typescript
101
- * const sdk = createClientSDK({
102
- * mode: 'client',
103
- * product: 'workshop',
104
- * transport: 'http',
105
- * baseUrl: 'https://workshop.soulcraft.com',
106
- * auth: 'cookie',
107
- * })
108
- * const results = await sdk.brainy.find({ query: 'candle inventory' })
109
- * ```
110
- */
111
- export declare function createClientSDK(options: LegacyClientSDKOptions): SoulcraftSDK;
112
- export {};
113
- //# sourceMappingURL=create-client-sdk.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"create-client-sdk.d.ts","sourceRoot":"","sources":["../../src/client/create-client-sdk.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsEG;AAOH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAG/C;;;GAGG;AACH,UAAU,sBAAsB;IAC9B,IAAI,EAAE,QAAQ,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,KAAK,CAAA;IAChC,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,CAAC,EAAE,QAAQ,GAAG;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;IACnC,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAMD;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,YAAY,CAwE7E"}