@soulcraft/sdk 2.0.1 → 2.1.0

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 (92) 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/admin.d.ts +39 -0
  14. package/dist/modules/hall/admin.d.ts.map +1 -0
  15. package/dist/modules/hall/admin.js +115 -0
  16. package/dist/modules/hall/admin.js.map +1 -0
  17. package/dist/modules/hall/browser.d.ts +83 -27
  18. package/dist/modules/hall/browser.d.ts.map +1 -1
  19. package/dist/modules/hall/browser.js +238 -49
  20. package/dist/modules/hall/browser.js.map +1 -1
  21. package/dist/modules/hall/media.d.ts +164 -0
  22. package/dist/modules/hall/media.d.ts.map +1 -0
  23. package/dist/modules/hall/media.js +182 -0
  24. package/dist/modules/hall/media.js.map +1 -0
  25. package/dist/modules/hall/server.d.ts +119 -6
  26. package/dist/modules/hall/server.d.ts.map +1 -1
  27. package/dist/modules/hall/server.js +299 -9
  28. package/dist/modules/hall/server.js.map +1 -1
  29. package/dist/modules/hall/types.d.ts +705 -25
  30. package/dist/modules/hall/types.d.ts.map +1 -1
  31. package/dist/modules/hall/types.js +12 -7
  32. package/dist/modules/hall/types.js.map +1 -1
  33. package/dist/server/hall-handlers.d.ts +60 -14
  34. package/dist/server/hall-handlers.d.ts.map +1 -1
  35. package/dist/server/hall-handlers.js +61 -12
  36. package/dist/server/hall-handlers.js.map +1 -1
  37. package/dist/server/hono-router.d.ts +2 -9
  38. package/dist/server/hono-router.d.ts.map +1 -1
  39. package/dist/server/hono-router.js +2 -46
  40. package/dist/server/hono-router.js.map +1 -1
  41. package/dist/server/index.d.ts +4 -19
  42. package/dist/server/index.d.ts.map +1 -1
  43. package/dist/server/index.js +10 -29
  44. package/dist/server/index.js.map +1 -1
  45. package/dist/types.d.ts +2 -41
  46. package/dist/types.d.ts.map +1 -1
  47. package/docs/ADR-005-hall-integration.md +449 -0
  48. package/package.json +1 -1
  49. package/dist/client/create-client-sdk.d.ts +0 -113
  50. package/dist/client/create-client-sdk.d.ts.map +0 -1
  51. package/dist/client/create-client-sdk.js +0 -169
  52. package/dist/client/create-client-sdk.js.map +0 -1
  53. package/dist/modules/app-context/index.d.ts +0 -214
  54. package/dist/modules/app-context/index.d.ts.map +0 -1
  55. package/dist/modules/app-context/index.js +0 -569
  56. package/dist/modules/app-context/index.js.map +0 -1
  57. package/dist/modules/billing/firestore-provider.d.ts +0 -60
  58. package/dist/modules/billing/firestore-provider.d.ts.map +0 -1
  59. package/dist/modules/billing/firestore-provider.js +0 -315
  60. package/dist/modules/billing/firestore-provider.js.map +0 -1
  61. package/dist/modules/brainy/proxy.d.ts +0 -48
  62. package/dist/modules/brainy/proxy.d.ts.map +0 -1
  63. package/dist/modules/brainy/proxy.js +0 -95
  64. package/dist/modules/brainy/proxy.js.map +0 -1
  65. package/dist/server/create-sdk.d.ts +0 -74
  66. package/dist/server/create-sdk.d.ts.map +0 -1
  67. package/dist/server/create-sdk.js +0 -104
  68. package/dist/server/create-sdk.js.map +0 -1
  69. package/dist/server/from-license.d.ts +0 -252
  70. package/dist/server/from-license.d.ts.map +0 -1
  71. package/dist/server/from-license.js +0 -349
  72. package/dist/server/from-license.js.map +0 -1
  73. package/dist/server/handlers.d.ts +0 -312
  74. package/dist/server/handlers.d.ts.map +0 -1
  75. package/dist/server/handlers.js +0 -376
  76. package/dist/server/handlers.js.map +0 -1
  77. package/dist/server/postmessage-handler.d.ts +0 -152
  78. package/dist/server/postmessage-handler.d.ts.map +0 -1
  79. package/dist/server/postmessage-handler.js +0 -138
  80. package/dist/server/postmessage-handler.js.map +0 -1
  81. package/dist/transports/http.d.ts +0 -86
  82. package/dist/transports/http.d.ts.map +0 -1
  83. package/dist/transports/http.js +0 -137
  84. package/dist/transports/http.js.map +0 -1
  85. package/dist/transports/postmessage.d.ts +0 -159
  86. package/dist/transports/postmessage.d.ts.map +0 -1
  87. package/dist/transports/postmessage.js +0 -207
  88. package/dist/transports/postmessage.js.map +0 -1
  89. package/dist/transports/workshop.d.ts +0 -173
  90. package/dist/transports/workshop.d.ts.map +0 -1
  91. package/dist/transports/workshop.js +0 -307
  92. package/dist/transports/workshop.js.map +0 -1
@@ -3,21 +3,14 @@
3
3
  * @description Server entry point for @soulcraft/sdk. Exports everything needed to
4
4
  * run the SDK in a product backend (Hono, SvelteKit, or any Bun/Node server).
5
5
  *
6
- * ## SDK 2.0 — Namespace router (recommended)
7
- *
8
6
  * Use `createSoulcraftRouter()` to mount a single Hono router that handles ALL
9
7
  * 25 SDK namespaces via a unified `/api/rpc` endpoint. Products configure which
10
8
  * namespaces are active via `NamespaceProviders`.
11
9
  *
12
- * ## Legacy — Brainy-only handlers
13
- *
14
- * `createBrainyHandler()` and `createBrainyWsHandler()` still work for backward
15
- * compatibility but only handle the `brainy` namespace.
16
- *
17
10
  * This entry point must never be imported in browser bundles — it has hard
18
11
  * server-only dependencies (`@soulcraft/brainy`, `lru-cache`, `crypto`, `fs`).
19
12
  *
20
- * @example SDK 2.0 — unified router
13
+ * @example Unified router
21
14
  * ```typescript
22
15
  * import { createSoulcraftRouter, BrainyInstancePool } from '@soulcraft/sdk/server'
23
16
  *
@@ -33,44 +26,32 @@
33
26
  */
34
27
  // ── Instance pool ─────────────────────────────────────────────────────────────
35
28
  export { BrainyInstancePool, computeEmailHash, } from './instance-pool.js';
36
- // ── Handler factories ─────────────────────────────────────────────────────────
37
- export { createBrainyHandler, createBrainyWsHandler, } from './handlers.js';
38
29
  // ── Y.js document manager (collaborative editing) ─────────────────────────────
39
30
  export { YDocManager } from '../modules/brainy/ydoc-manager.js';
40
- // ── PostMessage handler (Workshop parent-frame kit iframe) ──────────────────
41
- export { createBrainyPostMessageHandler } from './postmessage-handler.js';
42
- // ── Hall module factory + TURN utilities ─────────────────────────────────────
43
- export { createHallModule, generateTurnCredentials, HallClient, } from './hall-handlers.js';
31
+ // ── Hall module factory + media client + TURN utilities ──────────────────────
32
+ export { createHallModule, createHallMediaClient, generateTurnCredentials, HallClient, HallMediaClient, } from './hall-handlers.js';
44
33
  // ── Auth middleware + session factories ───────────────────────────────────────
45
34
  export { createAuthMiddleware, createRemoteSessionVerifier, createDevSessionVerifier, createDevLoginHandler, createDevCookieVerifier, createGuestSessionHandler, createGuestCookieVerifier, AUTH_USER_KEY, } from '../modules/auth/middleware.js';
46
35
  export { createBackchannelLogoutHandler } from '../modules/auth/backchannel.js';
47
36
  // ── Service token verification ────────────────────────────────────────────────
48
37
  export { verifyServiceToken, extractBearerToken, } from '../modules/auth/service-token.js';
49
- // ── Auth config helpers (also on shared entry, duplicated here for convenience) ─
38
+ // ── Auth config helpers ──────────────────────────────────────────────────────
50
39
  export { SOULCRAFT_USER_FIELDS, SOULCRAFT_SESSION_CONFIG, getAuthMode, getOIDCClientConfig, } from '../modules/auth/config.js';
51
40
  // ── Product registry — single source of truth for all Soulcraft products ─────
52
41
  export { SOULCRAFT_PRODUCTS, deriveOrigins, deriveRedirectUrls, } from '../modules/auth/products.js';
53
- // ── createSDK factory ─────────────────────────────────────────────────────────
54
- export { createSDK } from './create-sdk.js';
55
- // ── createServerSDK.fromLicense() — license-driven server SDK ─────────────────
56
- export { createServerSDK } from './from-license.js';
57
- // ── Module factories (for advanced use — createSDK assembles these automatically) ─
42
+ // ── Module factories ─────────────────────────────────────────────────────────
58
43
  export { createBillingModule } from '../modules/billing/index.js';
59
44
  export { createLicenseModule } from '../modules/license/index.js';
60
45
  export { createKitsModule } from '../modules/kits/index.js';
61
46
  export { createNotificationsModule } from '../modules/notifications/index.js';
62
47
  export { createCapabilityToken, verifyCapabilityToken } from '../modules/brainy/auth.js';
63
48
  export { LocalTransport } from '../transports/local.js';
64
- // ── Namespace router (Symmetrical SDK 2.0) ──────────────────────────────────
49
+ // ── Namespace router ─────────────────────────────────────────────────────────
65
50
  export { createNamespaceRouter } from './namespace-router.js';
66
- // ── Hono router factory (Symmetrical SDK 2.0) ──────────────────────────────
51
+ // ── Hono router factory ─────────────────────────────────────────────────────
67
52
  export { createSoulcraftRouter } from './hono-router.js';
68
- // ── Namespace handler factories (Symmetrical SDK 2.0) ───────────────────────
53
+ // ── Namespace handler factories ──────────────────────────────────────────────
69
54
  // Each factory creates a NamespaceProvider wired into `providers` on the router.
70
- export {
71
- // Handler factories
72
- createAnnotationsHandler, createAuthHandler, createChatHandler, createCertificationHandler, createCollectionsHandler, createCommerceHandler, createConfigHandler, createExportHandler, createFormatsHandler, createGraphHandler, createImportHandler, createMediaHandler, createProjectHandler, createPublishHandler, createPulseHandler, createRealtimeHandler, createSearchHandler, createSessionHandler, createSettingsHandler, createWorkspaceHandler, } from './handlers/index.js';
73
- export {
74
- // Chat engine utilities
75
- analyzeComplexity, calculateComplexityScore, selectTieredRouting, createDefaultModelSelector, estimateCost, formatCost, DEFAULT_MODELS, DEFAULT_MODEL_TIERS, streamMessage, sendMessage, } from './handlers/index.js';
55
+ export { createAnnotationsHandler, createAuthHandler, createChatHandler, createCertificationHandler, createCollectionsHandler, createCommerceHandler, createConfigHandler, createExportHandler, createFormatsHandler, createGraphHandler, createImportHandler, createMediaHandler, createProjectHandler, createPublishHandler, createPulseHandler, createRealtimeHandler, createSearchHandler, createSessionHandler, createSettingsHandler, createWorkspaceHandler, } from './handlers/index.js';
56
+ export { analyzeComplexity, calculateComplexityScore, selectTieredRouting, createDefaultModelSelector, estimateCost, formatCost, DEFAULT_MODELS, DEFAULT_MODEL_TIERS, streamMessage, sendMessage, } from './handlers/index.js';
76
57
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,iFAAiF;AACjF,OAAO,EACL,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,oBAAoB,CAAA;AAM3B,iFAAiF;AACjF,OAAO,EACL,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,eAAe,CAAA;AAQtB,iFAAiF;AACjF,OAAO,EAAE,WAAW,EAAE,MAAM,mCAAmC,CAAA;AAE/D,iFAAiF;AACjF,OAAO,EAAE,8BAA8B,EAAE,MAAM,0BAA0B,CAAA;AAMzE,gFAAgF;AAChF,OAAO,EACL,gBAAgB,EAChB,uBAAuB,EACvB,UAAU,GACX,MAAM,oBAAoB,CAAA;AAqB3B,iFAAiF;AACjF,OAAO,EACL,oBAAoB,EACpB,2BAA2B,EAC3B,wBAAwB,EACxB,qBAAqB,EACrB,uBAAuB,EACvB,yBAAyB,EACzB,yBAAyB,EACzB,aAAa,GACd,MAAM,+BAA+B,CAAA;AAYtC,OAAO,EAAE,8BAA8B,EAAE,MAAM,gCAAgC,CAAA;AAM/E,iFAAiF;AACjF,OAAO,EACL,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,kCAAkC,CAAA;AAEzC,mFAAmF;AACnF,OAAO,EACL,qBAAqB,EACrB,wBAAwB,EACxB,WAAW,EACX,mBAAmB,GACpB,MAAM,2BAA2B,CAAA;AAElC,gFAAgF;AAChF,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,kBAAkB,GACnB,MAAM,6BAA6B,CAAA;AAMpC,iFAAiF;AACjF,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAG3C,iFAAiF;AACjF,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AAQnD,qFAAqF;AACrF,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AAEjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AAEjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AAC3D,OAAO,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAA;AAK7E,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAA;AAExF,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAEvD,+EAA+E;AAC/E,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAA;AAY7D,8EAA8E;AAC9E,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAA;AAGxD,+EAA+E;AAC/E,iFAAiF;AACjF,OAAO;AACL,oBAAoB;AACpB,wBAAwB,EACxB,iBAAiB,EACjB,iBAAiB,EACjB,0BAA0B,EAC1B,wBAAwB,EACxB,qBAAqB,EACrB,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,EACpB,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,oBAAoB,EACpB,oBAAoB,EACpB,kBAAkB,EAClB,qBAAqB,EACrB,mBAAmB,EACnB,oBAAoB,EACpB,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,qBAAqB,CAAA;AA2D5B,OAAO;AACL,wBAAwB;AACxB,iBAAiB,EACjB,wBAAwB,EACxB,mBAAmB,EACnB,0BAA0B,EAC1B,YAAY,EACZ,UAAU,EACV,cAAc,EACd,mBAAmB,EACnB,aAAa,EACb,WAAW,GACZ,MAAM,qBAAqB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH,iFAAiF;AACjF,OAAO,EACL,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,oBAAoB,CAAA;AAM3B,iFAAiF;AACjF,OAAO,EAAE,WAAW,EAAE,MAAM,mCAAmC,CAAA;AAE/D,gFAAgF;AAChF,OAAO,EACL,gBAAgB,EAChB,qBAAqB,EACrB,uBAAuB,EACvB,UAAU,EACV,eAAe,GAChB,MAAM,oBAAoB,CAAA;AA4C3B,iFAAiF;AACjF,OAAO,EACL,oBAAoB,EACpB,2BAA2B,EAC3B,wBAAwB,EACxB,qBAAqB,EACrB,uBAAuB,EACvB,yBAAyB,EACzB,yBAAyB,EACzB,aAAa,GACd,MAAM,+BAA+B,CAAA;AAYtC,OAAO,EAAE,8BAA8B,EAAE,MAAM,gCAAgC,CAAA;AAM/E,iFAAiF;AACjF,OAAO,EACL,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,kCAAkC,CAAA;AAEzC,gFAAgF;AAChF,OAAO,EACL,qBAAqB,EACrB,wBAAwB,EACxB,WAAW,EACX,mBAAmB,GACpB,MAAM,2BAA2B,CAAA;AAElC,gFAAgF;AAChF,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,kBAAkB,GACnB,MAAM,6BAA6B,CAAA;AAMpC,gFAAgF;AAChF,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AAEjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AAEjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AAC3D,OAAO,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAA;AAK7E,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAA;AAExF,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAEvD,gFAAgF;AAChF,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAA;AAY7D,+EAA+E;AAC/E,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAA;AAGxD,gFAAgF;AAChF,iFAAiF;AACjF,OAAO,EACL,wBAAwB,EACxB,iBAAiB,EACjB,iBAAiB,EACjB,0BAA0B,EAC1B,wBAAwB,EACxB,qBAAqB,EACrB,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,EACpB,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,oBAAoB,EACpB,oBAAoB,EACpB,kBAAkB,EAClB,qBAAqB,EACrB,mBAAmB,EACnB,oBAAoB,EACpB,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,qBAAqB,CAAA;AA0D5B,OAAO,EACL,iBAAiB,EACjB,wBAAwB,EACxB,mBAAmB,EACnB,0BAA0B,EAC1B,YAAY,EACZ,UAAU,EACV,cAAc,EACd,mBAAmB,EACnB,aAAa,EACb,WAAW,GACZ,MAAM,qBAAqB,CAAA"}
package/dist/types.d.ts CHANGED
@@ -17,8 +17,6 @@ export type { SoulcraftProduct };
17
17
  import type { SoulcraftNamespaces } from './namespaces.js';
18
18
  /** Brainy instance pooling strategies. */
19
19
  export type InstanceStrategy = 'per-user' | 'per-tenant' | 'per-scope';
20
- /** Transport protocols supported by the client SDK. */
21
- export type Transport = 'http' | 'ws' | 'postmessage' | 'local' | 'auto';
22
20
  /**
23
21
  * @description The top-level SDK interface. Extends {@link SoulcraftNamespaces} with
24
22
  * lifecycle methods for server and client modes.
@@ -42,8 +40,8 @@ export type Transport = 'http' | 'ws' | 'postmessage' | 'local' | 'auto';
42
40
  *
43
41
  * @example Client
44
42
  * ```typescript
45
- * import { createSoulcraftProxy, HttpTransport } from '@soulcraft/sdk/client'
46
- * const sdk: SoulcraftSDK = createSoulcraftProxy(new HttpTransport('/api/rpc'))
43
+ * import { createSoulcraftProxy, HttpRpcTransport } from '@soulcraft/sdk/client'
44
+ * const sdk: SoulcraftSDK = createSoulcraftProxy(new HttpRpcTransport('/api'))
47
45
  * const graph = await sdk.graph.getData()
48
46
  * ```
49
47
  */
@@ -117,41 +115,4 @@ export interface ServerSDKOptions extends SDKOptions {
117
115
  reconnectDelayMs?: number;
118
116
  };
119
117
  }
120
- /**
121
- * @description Options for client mode — connects to a running SDK server over a transport.
122
- * Use `@soulcraft/sdk/client` entry point.
123
- *
124
- * @example Auto-negotiation (WS primary, HTTP fallback)
125
- * ```typescript
126
- * const sdk = createClientSDK({ product: 'venue', mode: 'client', transport: 'auto', baseUrl: '/api' })
127
- * ```
128
- */
129
- export interface ClientSDKOptions extends SDKOptions {
130
- mode: 'client';
131
- /**
132
- * Transport strategy.
133
- * - `'auto'` — Try WebSocket (MessagePack), fall back to HTTP (JSON). Recommended.
134
- * - `'ws'` — WebSocket only. Fails if WS unavailable.
135
- * - `'http'` — HTTP only. Stateless, works in serverless and proxy-restricted environments.
136
- * - `'postmessage'` — PostMessage only. For WebContainer iframes in dev mode.
137
- */
138
- transport: 'auto' | 'ws' | 'http' | 'postmessage';
139
- /** Base URL for API requests (e.g. `'https://workshop.soulcraft.com'` or `'/api'`). */
140
- baseUrl: string;
141
- /** Auth strategy: session cookies (same-origin) or a Bearer capability token. */
142
- auth?: 'cookie' | {
143
- token: string;
144
- };
145
- /** Request timeout in ms. Defaults to 30 000. */
146
- timeoutMs?: number;
147
- /**
148
- * WebSocket reconnect options. Only relevant when `transport` is `'auto'` or `'ws'`.
149
- * Defaults: initialDelayMs = 1000, maxDelayMs = 30000, maxRetries = Infinity.
150
- */
151
- reconnect?: {
152
- initialDelayMs?: number;
153
- maxDelayMs?: number;
154
- maxRetries?: number;
155
- };
156
- }
157
118
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAA;AAClE;;;GAGG;AACH,YAAY,EAAE,gBAAgB,EAAE,CAAA;AAEhC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AAE1D,0CAA0C;AAC1C,MAAM,MAAM,gBAAgB,GAAG,UAAU,GAAG,YAAY,GAAG,WAAW,CAAA;AAEtE,uDAAuD;AACvD,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,IAAI,GAAG,aAAa,GAAG,OAAO,GAAG,MAAM,CAAA;AAExE;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,WAAW,YAAa,SAAQ,mBAAmB;IACvD,qFAAqF;IACrF,QAAQ,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1B,yDAAyD;IACzD,OAAO,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACzB,iDAAiD;IACjD,UAAU,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,wDAAwD;IACxD,OAAO,EAAE,gBAAgB,CAAA;CAC1B;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAiB,SAAQ,UAAU;IAClD,IAAI,EAAE,QAAQ,CAAA;IACd,MAAM,EAAE;QACN,OAAO,EAAE,YAAY,GAAG,iBAAiB,CAAA;QACzC,QAAQ,EAAE,MAAM,CAAA;QAChB,SAAS,EAAE;YACT,QAAQ,EAAE,gBAAgB,CAAA;YAC1B,4EAA4E;YAC5E,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,MAAM,CAAA;YAC1D,YAAY,CAAC,EAAE,MAAM,CAAA;SACtB,CAAA;KACF,CAAA;IACD,IAAI,EAAE;QACJ,QAAQ,EAAE,MAAM,CAAA;QAChB,YAAY,EAAE,MAAM,CAAA;QACpB,iBAAiB,CAAC,EAAE,MAAM,CAAA;QAC1B,eAAe,CAAC,EAAE,MAAM,CAAA;KACzB,CAAA;IACD,OAAO,EAAE;QACP,mEAAmE;QACnE,cAAc,CAAC,EAAE,MAAM,CAAA;QACvB,SAAS,CAAC,EAAE,MAAM,CAAA;KACnB,CAAA;IACD;;;;OAIG;IACH,IAAI,CAAC,EAAE;QACL;;;WAGG;QACH,GAAG,EAAE,MAAM,CAAA;QACX;;;WAGG;QACH,WAAW,EAAE,MAAM,CAAA;QACnB;;;WAGG;QACH,MAAM,EAAE,MAAM,CAAA;QACd;;;WAGG;QACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAC1B,CAAA;CACF;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,gBAAiB,SAAQ,UAAU;IAClD,IAAI,EAAE,QAAQ,CAAA;IACd;;;;;;OAMG;IACH,SAAS,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,GAAG,aAAa,CAAA;IACjD,uFAAuF;IACvF,OAAO,EAAE,MAAM,CAAA;IACf,iFAAiF;IACjF,IAAI,CAAC,EAAE,QAAQ,GAAG;QAAE,KAAK,EAAE,MAAM,CAAA;KAAE,CAAA;IACnC,iDAAiD;IACjD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;OAGG;IACH,SAAS,CAAC,EAAE;QACV,cAAc,CAAC,EAAE,MAAM,CAAA;QACvB,UAAU,CAAC,EAAE,MAAM,CAAA;QACnB,UAAU,CAAC,EAAE,MAAM,CAAA;KACpB,CAAA;CACF"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAA;AAClE;;;GAGG;AACH,YAAY,EAAE,gBAAgB,EAAE,CAAA;AAEhC,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AAE1D,0CAA0C;AAC1C,MAAM,MAAM,gBAAgB,GAAG,UAAU,GAAG,YAAY,GAAG,WAAW,CAAA;AAGtE;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,WAAW,YAAa,SAAQ,mBAAmB;IACvD,qFAAqF;IACrF,QAAQ,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1B,yDAAyD;IACzD,OAAO,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;IACzB,iDAAiD;IACjD,UAAU,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAA;CAC7B;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,wDAAwD;IACxD,OAAO,EAAE,gBAAgB,CAAA;CAC1B;AAED;;;GAGG;AACH,MAAM,WAAW,gBAAiB,SAAQ,UAAU;IAClD,IAAI,EAAE,QAAQ,CAAA;IACd,MAAM,EAAE;QACN,OAAO,EAAE,YAAY,GAAG,iBAAiB,CAAA;QACzC,QAAQ,EAAE,MAAM,CAAA;QAChB,SAAS,EAAE;YACT,QAAQ,EAAE,gBAAgB,CAAA;YAC1B,4EAA4E;YAC5E,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,MAAM,CAAA;YAC1D,YAAY,CAAC,EAAE,MAAM,CAAA;SACtB,CAAA;KACF,CAAA;IACD,IAAI,EAAE;QACJ,QAAQ,EAAE,MAAM,CAAA;QAChB,YAAY,EAAE,MAAM,CAAA;QACpB,iBAAiB,CAAC,EAAE,MAAM,CAAA;QAC1B,eAAe,CAAC,EAAE,MAAM,CAAA;KACzB,CAAA;IACD,OAAO,EAAE;QACP,mEAAmE;QACnE,cAAc,CAAC,EAAE,MAAM,CAAA;QACvB,SAAS,CAAC,EAAE,MAAM,CAAA;KACnB,CAAA;IACD;;;;OAIG;IACH,IAAI,CAAC,EAAE;QACL;;;WAGG;QACH,GAAG,EAAE,MAAM,CAAA;QACX;;;WAGG;QACH,WAAW,EAAE,MAAM,CAAA;QACnB;;;WAGG;QACH,MAAM,EAAE,MAAM,CAAA;QACd;;;WAGG;QACH,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAC1B,CAAA;CACF"}
@@ -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.1",
3
+ "version": "2.1.0",
4
4
  "description": "The unified Soulcraft platform SDK — data, auth, AI, billing, and notifications",
5
5
  "type": "module",
6
6
  "publishConfig": {