@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.
- package/dist/client/index.d.ts +5 -38
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +5 -47
- package/dist/client/index.js.map +1 -1
- package/dist/client/namespace-proxy.d.ts +3 -4
- package/dist/client/namespace-proxy.d.ts.map +1 -1
- package/dist/client/namespace-proxy.js +3 -4
- package/dist/client/namespace-proxy.js.map +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -4
- package/dist/index.js.map +1 -1
- package/dist/modules/hall/browser.d.ts +83 -27
- package/dist/modules/hall/browser.d.ts.map +1 -1
- package/dist/modules/hall/browser.js +238 -49
- package/dist/modules/hall/browser.js.map +1 -1
- package/dist/modules/hall/media.d.ts +164 -0
- package/dist/modules/hall/media.d.ts.map +1 -0
- package/dist/modules/hall/media.js +182 -0
- package/dist/modules/hall/media.js.map +1 -0
- package/dist/modules/hall/server.d.ts +83 -6
- package/dist/modules/hall/server.d.ts.map +1 -1
- package/dist/modules/hall/server.js +206 -9
- package/dist/modules/hall/server.js.map +1 -1
- package/dist/modules/hall/types.d.ts +548 -25
- package/dist/modules/hall/types.d.ts.map +1 -1
- package/dist/modules/hall/types.js +12 -7
- package/dist/modules/hall/types.js.map +1 -1
- package/dist/server/hall-handlers.d.ts +40 -12
- package/dist/server/hall-handlers.d.ts.map +1 -1
- package/dist/server/hall-handlers.js +40 -12
- package/dist/server/hall-handlers.js.map +1 -1
- package/dist/server/handlers/chat/engine.d.ts.map +1 -1
- package/dist/server/handlers/chat/engine.js +5 -1
- package/dist/server/handlers/chat/engine.js.map +1 -1
- package/dist/server/handlers/chat/types.d.ts +17 -2
- package/dist/server/handlers/chat/types.d.ts.map +1 -1
- package/dist/server/hono-router.d.ts +2 -9
- package/dist/server/hono-router.d.ts.map +1 -1
- package/dist/server/hono-router.js +2 -46
- package/dist/server/hono-router.js.map +1 -1
- package/dist/server/index.d.ts +4 -19
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +10 -29
- package/dist/server/index.js.map +1 -1
- package/dist/types.d.ts +2 -41
- package/dist/types.d.ts.map +1 -1
- package/docs/ADR-005-hall-integration.md +449 -0
- package/package.json +1 -1
- package/dist/client/create-client-sdk.d.ts +0 -113
- package/dist/client/create-client-sdk.d.ts.map +0 -1
- package/dist/client/create-client-sdk.js +0 -169
- package/dist/client/create-client-sdk.js.map +0 -1
- package/dist/modules/app-context/index.d.ts +0 -214
- package/dist/modules/app-context/index.d.ts.map +0 -1
- package/dist/modules/app-context/index.js +0 -569
- package/dist/modules/app-context/index.js.map +0 -1
- package/dist/modules/billing/firestore-provider.d.ts +0 -60
- package/dist/modules/billing/firestore-provider.d.ts.map +0 -1
- package/dist/modules/billing/firestore-provider.js +0 -315
- package/dist/modules/billing/firestore-provider.js.map +0 -1
- package/dist/modules/brainy/proxy.d.ts +0 -48
- package/dist/modules/brainy/proxy.d.ts.map +0 -1
- package/dist/modules/brainy/proxy.js +0 -95
- package/dist/modules/brainy/proxy.js.map +0 -1
- package/dist/server/create-sdk.d.ts +0 -74
- package/dist/server/create-sdk.d.ts.map +0 -1
- package/dist/server/create-sdk.js +0 -104
- package/dist/server/create-sdk.js.map +0 -1
- package/dist/server/from-license.d.ts +0 -252
- package/dist/server/from-license.d.ts.map +0 -1
- package/dist/server/from-license.js +0 -349
- package/dist/server/from-license.js.map +0 -1
- package/dist/server/handlers.d.ts +0 -312
- package/dist/server/handlers.d.ts.map +0 -1
- package/dist/server/handlers.js +0 -376
- package/dist/server/handlers.js.map +0 -1
- package/dist/server/postmessage-handler.d.ts +0 -152
- package/dist/server/postmessage-handler.d.ts.map +0 -1
- package/dist/server/postmessage-handler.js +0 -138
- package/dist/server/postmessage-handler.js.map +0 -1
- package/dist/transports/http.d.ts +0 -86
- package/dist/transports/http.d.ts.map +0 -1
- package/dist/transports/http.js +0 -137
- package/dist/transports/http.js.map +0 -1
- package/dist/transports/postmessage.d.ts +0 -159
- package/dist/transports/postmessage.d.ts.map +0 -1
- package/dist/transports/postmessage.js +0 -207
- package/dist/transports/postmessage.js.map +0 -1
- package/dist/transports/workshop.d.ts +0 -173
- package/dist/transports/workshop.d.ts.map +0 -1
- package/dist/transports/workshop.js +0 -307
- package/dist/transports/workshop.js.map +0 -1
package/dist/server/handlers.js
DELETED
|
@@ -1,376 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module server/handlers
|
|
3
|
-
* @description HTTP RPC and WebSocket handler factories for mounting Brainy server endpoints.
|
|
4
|
-
*
|
|
5
|
-
* Products mount exactly two routes:
|
|
6
|
-
* - `POST /api/brainy/rpc` — handled by {@link createBrainyHandler}
|
|
7
|
-
* - `GET /api/brainy/ws` — WebSocket upgrade handled by {@link createBrainyWsHandler}
|
|
8
|
-
*
|
|
9
|
-
* Both factories are framework-agnostic — they accept and return `Request` / `Response`
|
|
10
|
-
* objects (Fetch API), making them compatible with SvelteKit, Hono, and raw Bun.serve.
|
|
11
|
-
*
|
|
12
|
-
* ## HTTP RPC handler
|
|
13
|
-
*
|
|
14
|
-
* Accepts `{ method: string, args: unknown[] }` as a JSON body and returns
|
|
15
|
-
* `{ result: unknown }` or `{ error: { code, message } }`. All authentication and
|
|
16
|
-
* authorization is delegated to the caller-supplied callbacks.
|
|
17
|
-
*
|
|
18
|
-
* ## WebSocket handler
|
|
19
|
-
*
|
|
20
|
-
* Accepts binary MessagePack frames. See wire protocol in `transports/ws.ts`.
|
|
21
|
-
* The `broadcastChange()` method on the returned handler pushes `BrainyChangeEvent`
|
|
22
|
-
* objects to connected clients.
|
|
23
|
-
*
|
|
24
|
-
* @example SvelteKit route mounting the HTTP handler
|
|
25
|
-
* ```typescript
|
|
26
|
-
* // src/routes/api/brainy/rpc/+server.ts
|
|
27
|
-
* import { createBrainyHandler } from '@soulcraft/sdk/server'
|
|
28
|
-
* import { pool } from '$lib/server/sdk'
|
|
29
|
-
* import { verifySession } from '$lib/server/auth'
|
|
30
|
-
*
|
|
31
|
-
* const handler = createBrainyHandler({
|
|
32
|
-
* resolveBrain: async (req) => {
|
|
33
|
-
* const userId = req.headers.get('x-user-id') ?? ''
|
|
34
|
-
* const workspaceId = req.headers.get('x-workspace-id') ?? ''
|
|
35
|
-
* return pool.forUser(userId, workspaceId)
|
|
36
|
-
* },
|
|
37
|
-
* authenticate: async (req) => verifySession(req.headers.get('cookie') ?? ''),
|
|
38
|
-
* })
|
|
39
|
-
*
|
|
40
|
-
* export const POST: RequestHandler = ({ request }) => handler(request)
|
|
41
|
-
* ```
|
|
42
|
-
*
|
|
43
|
-
* @example Bun.serve WebSocket upgrade
|
|
44
|
-
* ```typescript
|
|
45
|
-
* import { createBrainyWsHandler } from '@soulcraft/sdk/server'
|
|
46
|
-
* import { pool } from './sdk'
|
|
47
|
-
* import { verifyCapabilityToken } from '@soulcraft/sdk'
|
|
48
|
-
*
|
|
49
|
-
* const wsHandler = createBrainyWsHandler({
|
|
50
|
-
* resolveBrain: (scope) => pool.forTenant(scope),
|
|
51
|
-
* authenticate: (token, scope) => verifyCapabilityToken(token, process.env.VENUE_RPC_SECRET!),
|
|
52
|
-
* })
|
|
53
|
-
*
|
|
54
|
-
* Bun.serve({
|
|
55
|
-
* async fetch(req, server) {
|
|
56
|
-
* if (req.url.endsWith('/api/brainy/ws')) {
|
|
57
|
-
* const session = await wsHandler.handleUpgrade(req)
|
|
58
|
-
* if (!session) return new Response('Unauthorized', { status: 401 })
|
|
59
|
-
* server.upgrade(req, { data: session })
|
|
60
|
-
* return undefined
|
|
61
|
-
* }
|
|
62
|
-
* return new Response('Not found', { status: 404 })
|
|
63
|
-
* },
|
|
64
|
-
* websocket: {
|
|
65
|
-
* async message(ws, data) {
|
|
66
|
-
* await wsHandler.handleMessage(ws.data, data as ArrayBuffer, (msg) => ws.send(msg))
|
|
67
|
-
* },
|
|
68
|
-
* },
|
|
69
|
-
* })
|
|
70
|
-
* ```
|
|
71
|
-
*/
|
|
72
|
-
import { encode, decode } from '@msgpack/msgpack';
|
|
73
|
-
import { LocalTransport } from '../transports/local.js';
|
|
74
|
-
import { YDocManager } from '../modules/brainy/ydoc-manager.js';
|
|
75
|
-
/**
|
|
76
|
-
* Creates a Fetch-API-compatible HTTP handler for Brainy RPC calls.
|
|
77
|
-
*
|
|
78
|
-
* Mount at `POST /api/brainy/rpc` in your product's router.
|
|
79
|
-
*
|
|
80
|
-
* @param config - Handler configuration.
|
|
81
|
-
* @returns `(request: Request) => Promise<Response>`
|
|
82
|
-
*/
|
|
83
|
-
export function createBrainyHandler(config) {
|
|
84
|
-
const { resolveBrain, authenticate, authorize, blockedMethods = [] } = config;
|
|
85
|
-
return async function brainyRpcHandler(request) {
|
|
86
|
-
// ── Auth ──────────────────────────────────────────────────────────────
|
|
87
|
-
const auth = await authenticate(request);
|
|
88
|
-
if (!auth)
|
|
89
|
-
return _jsonError(401, 'UNAUTHORIZED', 'Authentication required');
|
|
90
|
-
// ── Parse ─────────────────────────────────────────────────────────────
|
|
91
|
-
let body;
|
|
92
|
-
try {
|
|
93
|
-
body = (await request.json());
|
|
94
|
-
}
|
|
95
|
-
catch {
|
|
96
|
-
return _jsonError(400, 'BAD_REQUEST', 'Request body must be valid JSON');
|
|
97
|
-
}
|
|
98
|
-
if (typeof body.method !== 'string' || !Array.isArray(body.args)) {
|
|
99
|
-
return _jsonError(400, 'BAD_REQUEST', '{ method: string, args: unknown[] } required');
|
|
100
|
-
}
|
|
101
|
-
const method = body.method;
|
|
102
|
-
const args = body.args;
|
|
103
|
-
// ── Blocklist ─────────────────────────────────────────────────────────
|
|
104
|
-
if (blockedMethods.includes(method)) {
|
|
105
|
-
return _jsonError(403, 'FORBIDDEN', `Method '${method}' is not available via RPC`);
|
|
106
|
-
}
|
|
107
|
-
// ── Authorize ─────────────────────────────────────────────────────────
|
|
108
|
-
if (authorize) {
|
|
109
|
-
const allowed = await authorize(method, args, auth);
|
|
110
|
-
if (!allowed) {
|
|
111
|
-
return _jsonError(403, 'FORBIDDEN', `Not authorized to call '${method}'`);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
// ── Resolve brain + dispatch ──────────────────────────────────────────
|
|
115
|
-
let brain;
|
|
116
|
-
try {
|
|
117
|
-
brain = await resolveBrain(request);
|
|
118
|
-
}
|
|
119
|
-
catch (err) {
|
|
120
|
-
console.error('[SDK/handler] resolveBrain threw:', err);
|
|
121
|
-
return _jsonError(503, 'BRAIN_UNAVAILABLE', 'Brainy instance not available');
|
|
122
|
-
}
|
|
123
|
-
const transport = new LocalTransport(brain);
|
|
124
|
-
try {
|
|
125
|
-
const result = await transport.call(method, args);
|
|
126
|
-
return new Response(JSON.stringify({ result }), {
|
|
127
|
-
status: 200,
|
|
128
|
-
headers: { 'Content-Type': 'application/json' },
|
|
129
|
-
});
|
|
130
|
-
}
|
|
131
|
-
catch (err) {
|
|
132
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
133
|
-
return _jsonError(500, 'RPC_ERROR', message);
|
|
134
|
-
}
|
|
135
|
-
};
|
|
136
|
-
}
|
|
137
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
138
|
-
// Factory
|
|
139
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
140
|
-
/**
|
|
141
|
-
* Creates a server-side WebSocket handler for bidirectional Brainy RPC, real-time
|
|
142
|
-
* change push, and optional Y.js collaborative document editing.
|
|
143
|
-
*
|
|
144
|
-
* ## Y.js collaborative editing
|
|
145
|
-
*
|
|
146
|
-
* Pass a `ydocManager` in the config to enable co-editing. The handler will
|
|
147
|
-
* automatically route `y-sync`, `y-update`, and `y-awareness` messages through the
|
|
148
|
-
* manager. The product server must:
|
|
149
|
-
*
|
|
150
|
-
* 1. Maintain a `Map<scope, Map<peerId, sendFn>>` of connected peers.
|
|
151
|
-
* 2. Set `session.broadcast` after `handleUpgrade()` to fan out Y.js frames.
|
|
152
|
-
* 3. Call `handleClose(session)` when a peer disconnects.
|
|
153
|
-
*
|
|
154
|
-
* @example Workshop server wiring with Y.js
|
|
155
|
-
* ```typescript
|
|
156
|
-
* import { createBrainyWsHandler, YDocManager } from '@soulcraft/sdk/server'
|
|
157
|
-
*
|
|
158
|
-
* const ydocManager = new YDocManager()
|
|
159
|
-
* const wsHandler = createBrainyWsHandler({ resolveBrain, authenticate, ydocManager })
|
|
160
|
-
*
|
|
161
|
-
* // Map<scope, Map<peerId, send>>
|
|
162
|
-
* const peers = new Map<string, Map<string, (msg: Uint8Array) => void>>()
|
|
163
|
-
*
|
|
164
|
-
* Bun.serve({
|
|
165
|
-
* async fetch(req, server) {
|
|
166
|
-
* if (new URL(req.url).pathname === '/api/brainy/ws') {
|
|
167
|
-
* const session = await wsHandler.handleUpgrade(req)
|
|
168
|
-
* if (!session) return new Response('Unauthorized', { status: 401 })
|
|
169
|
-
* // Register peer in broadcast map
|
|
170
|
-
* if (!peers.has(session.scope)) peers.set(session.scope, new Map())
|
|
171
|
-
* server.upgrade(req, { data: session })
|
|
172
|
-
* return undefined
|
|
173
|
-
* }
|
|
174
|
-
* },
|
|
175
|
-
* websocket: {
|
|
176
|
-
* open(ws) {
|
|
177
|
-
* const session = ws.data as WsSession
|
|
178
|
-
* peers.get(session.scope)!.set(session.peerId, (msg) => ws.send(msg))
|
|
179
|
-
* session.broadcast = (msg, excludeId) => {
|
|
180
|
-
* for (const [id, send] of peers.get(session.scope) ?? []) {
|
|
181
|
-
* if (id !== excludeId) send(msg)
|
|
182
|
-
* }
|
|
183
|
-
* }
|
|
184
|
-
* ws.send(encode({ type: 'ready', scope: session.scope }))
|
|
185
|
-
* },
|
|
186
|
-
* async message(ws, data) {
|
|
187
|
-
* await wsHandler.handleMessage(ws.data, data as ArrayBuffer, (msg) => ws.send(msg))
|
|
188
|
-
* },
|
|
189
|
-
* async close(ws) {
|
|
190
|
-
* const session = ws.data as WsSession
|
|
191
|
-
* peers.get(session.scope)?.delete(session.peerId)
|
|
192
|
-
* await wsHandler.handleClose(session)
|
|
193
|
-
* },
|
|
194
|
-
* },
|
|
195
|
-
* })
|
|
196
|
-
* ```
|
|
197
|
-
*
|
|
198
|
-
* @param config - Handler configuration.
|
|
199
|
-
* @returns A {@link BrainyWsHandler} instance.
|
|
200
|
-
*/
|
|
201
|
-
export function createBrainyWsHandler(config) {
|
|
202
|
-
const { resolveBrain, authenticate, authorize, blockedMethods = [], ydocManager } = config;
|
|
203
|
-
return {
|
|
204
|
-
async handleUpgrade(request) {
|
|
205
|
-
const url = new URL(request.url);
|
|
206
|
-
const scope = url.searchParams.get('scope') ?? '';
|
|
207
|
-
// Browser sends token as ?token= query param; Bun/Node uses Authorization header.
|
|
208
|
-
const authHeader = request.headers.get('authorization') ?? '';
|
|
209
|
-
const token = authHeader.startsWith('Bearer ')
|
|
210
|
-
? authHeader.slice(7)
|
|
211
|
-
: (url.searchParams.get('token') ?? '');
|
|
212
|
-
const auth = await authenticate(token, scope);
|
|
213
|
-
if (!auth)
|
|
214
|
-
return null;
|
|
215
|
-
const brain = await resolveBrain(scope);
|
|
216
|
-
const transport = new LocalTransport(brain);
|
|
217
|
-
const peerId = _generatePeerId();
|
|
218
|
-
// broadcast is a no-op until the product server's websocket.open() sets it.
|
|
219
|
-
const session = {
|
|
220
|
-
scope,
|
|
221
|
-
auth,
|
|
222
|
-
brain,
|
|
223
|
-
transport,
|
|
224
|
-
peerId,
|
|
225
|
-
broadcast: () => { },
|
|
226
|
-
};
|
|
227
|
-
return session;
|
|
228
|
-
},
|
|
229
|
-
async handleMessage(session, data, send) {
|
|
230
|
-
let decoded;
|
|
231
|
-
try {
|
|
232
|
-
decoded = decode(data instanceof ArrayBuffer ? new Uint8Array(data) : data);
|
|
233
|
-
}
|
|
234
|
-
catch {
|
|
235
|
-
return; // Malformed frame — silently ignore
|
|
236
|
-
}
|
|
237
|
-
if (!decoded || typeof decoded !== 'object')
|
|
238
|
-
return;
|
|
239
|
-
const msg = decoded;
|
|
240
|
-
// ── Y.js messages ────────────────────────────────────────────────────
|
|
241
|
-
if (typeof msg['type'] === 'string' && msg['type'].startsWith('y-')) {
|
|
242
|
-
await _handleYjsMessage(msg, session, send, ydocManager);
|
|
243
|
-
return;
|
|
244
|
-
}
|
|
245
|
-
// ── Brainy RPC ───────────────────────────────────────────────────────
|
|
246
|
-
const req = msg;
|
|
247
|
-
if (typeof req.id !== 'string' || typeof req.method !== 'string' || !Array.isArray(req.args)) {
|
|
248
|
-
return;
|
|
249
|
-
}
|
|
250
|
-
const { id, method, args } = req;
|
|
251
|
-
if (blockedMethods.includes(method)) {
|
|
252
|
-
send(encode({ id, error: { code: 'FORBIDDEN', message: `Method '${method}' blocked` } }));
|
|
253
|
-
return;
|
|
254
|
-
}
|
|
255
|
-
if (authorize) {
|
|
256
|
-
const allowed = await authorize(method, args, session.auth);
|
|
257
|
-
if (!allowed) {
|
|
258
|
-
send(encode({ id, error: { code: 'FORBIDDEN', message: `Not authorized: '${method}'` } }));
|
|
259
|
-
return;
|
|
260
|
-
}
|
|
261
|
-
}
|
|
262
|
-
try {
|
|
263
|
-
const result = await session.transport.call(method, args);
|
|
264
|
-
send(encode({ id, result }));
|
|
265
|
-
}
|
|
266
|
-
catch (err) {
|
|
267
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
268
|
-
send(encode({ id, error: { code: 'RPC_ERROR', message } }));
|
|
269
|
-
}
|
|
270
|
-
},
|
|
271
|
-
async handleClose(session) {
|
|
272
|
-
if (!ydocManager)
|
|
273
|
-
return;
|
|
274
|
-
// Notify YDocManager for every file this peer had open.
|
|
275
|
-
// The manager tracks peers per-file; onPeerDisconnect flushes + discards
|
|
276
|
-
// when the last peer leaves a document.
|
|
277
|
-
//
|
|
278
|
-
// We don't track which files each peer opened at the session level —
|
|
279
|
-
// YDocManager.onPeerDisconnect is idempotent for peers that never joined a doc.
|
|
280
|
-
// The product server can also call this selectively if it tracks open files.
|
|
281
|
-
//
|
|
282
|
-
// For simplicity, the manager handles the "peer not known for this file" case
|
|
283
|
-
// gracefully (no-op).
|
|
284
|
-
await ydocManager.onPeerDisconnectAll(session.scope, session.peerId);
|
|
285
|
-
},
|
|
286
|
-
broadcastChange(event, send) {
|
|
287
|
-
send(encode(event));
|
|
288
|
-
},
|
|
289
|
-
};
|
|
290
|
-
}
|
|
291
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
292
|
-
// Internal helpers
|
|
293
|
-
// ─────────────────────────────────────────────────────────────────────────────
|
|
294
|
-
/**
|
|
295
|
-
* Builds a JSON error response with `{ error: { code, message } }` body.
|
|
296
|
-
*
|
|
297
|
-
* @param status - HTTP status code.
|
|
298
|
-
* @param code - Machine-readable error code.
|
|
299
|
-
* @param message - Human-readable description.
|
|
300
|
-
* @returns A `Response` with the error payload.
|
|
301
|
-
*/
|
|
302
|
-
function _jsonError(status, code, message) {
|
|
303
|
-
return new Response(JSON.stringify({ error: { code, message } }), {
|
|
304
|
-
status,
|
|
305
|
-
headers: { 'Content-Type': 'application/json' },
|
|
306
|
-
});
|
|
307
|
-
}
|
|
308
|
-
/**
|
|
309
|
-
* Routes a Y.js protocol message to the appropriate `YDocManager` method and
|
|
310
|
-
* broadcasts updates to other peers via `session.broadcast`.
|
|
311
|
-
*
|
|
312
|
-
* ## Sync protocol (Y.js standard two-phase handshake):
|
|
313
|
-
* 1. Client connects → sends `y-sync` with its state vector.
|
|
314
|
-
* 2. Server replies with `y-sync` diff (all updates client is missing).
|
|
315
|
-
* 3. Client applies diff → sends `y-update` for each pending local op.
|
|
316
|
-
* 4. From this point: all ops are `y-update` frames, broadcast to all other peers.
|
|
317
|
-
*
|
|
318
|
-
* ## Awareness:
|
|
319
|
-
* - `y-awareness` frames carry cursor positions, user name/color, selection ranges.
|
|
320
|
-
* - NOT persisted — forwarded immediately to all other peers then discarded.
|
|
321
|
-
*
|
|
322
|
-
* @param msg - Decoded Y.js message frame.
|
|
323
|
-
* @param session - The WebSocket session for the sending peer.
|
|
324
|
-
* @param send - Sends a response to THIS peer only.
|
|
325
|
-
* @param ydocManager - The server-side Y.Doc pool (may be undefined if collab disabled).
|
|
326
|
-
*/
|
|
327
|
-
async function _handleYjsMessage(msg, session, send, ydocManager) {
|
|
328
|
-
if (!ydocManager)
|
|
329
|
-
return;
|
|
330
|
-
switch (msg.type) {
|
|
331
|
-
case 'y-sync': {
|
|
332
|
-
// Phase 1 of the Y.js sync handshake.
|
|
333
|
-
// Client sends its state vector; server replies with the diff.
|
|
334
|
-
const clientSv = msg.stateVector instanceof Uint8Array
|
|
335
|
-
? msg.stateVector
|
|
336
|
-
: new Uint8Array(Object.values(msg.stateVector));
|
|
337
|
-
const diff = await ydocManager.getDiff(session.scope, msg.filePath, session.brain, clientSv);
|
|
338
|
-
// Reply only to this peer with the diff so it can catch up.
|
|
339
|
-
send(encode({ type: 'y-sync', filePath: msg.filePath, diff }));
|
|
340
|
-
break;
|
|
341
|
-
}
|
|
342
|
-
case 'y-update': {
|
|
343
|
-
// A CRDT update from this peer — apply it and fan out to all others.
|
|
344
|
-
const update = msg.update instanceof Uint8Array
|
|
345
|
-
? msg.update
|
|
346
|
-
: new Uint8Array(Object.values(msg.update));
|
|
347
|
-
// Ensure this peer is registered as active for this document.
|
|
348
|
-
await ydocManager.getOrCreate(session.scope, msg.filePath, session.brain, session.peerId);
|
|
349
|
-
await ydocManager.applyUpdate(session.scope, msg.filePath, update);
|
|
350
|
-
// Broadcast to all OTHER peers in this scope.
|
|
351
|
-
const frame = encode({ type: 'y-update', filePath: msg.filePath, update });
|
|
352
|
-
session.broadcast(frame, session.peerId);
|
|
353
|
-
break;
|
|
354
|
-
}
|
|
355
|
-
case 'y-awareness': {
|
|
356
|
-
// Cursor / presence update — forward to all other peers, do not persist.
|
|
357
|
-
const update = msg.update instanceof Uint8Array
|
|
358
|
-
? msg.update
|
|
359
|
-
: new Uint8Array(Object.values(msg.update));
|
|
360
|
-
const frame = encode({ type: 'y-awareness', update });
|
|
361
|
-
session.broadcast(frame, session.peerId);
|
|
362
|
-
break;
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
/**
|
|
367
|
-
* Generates a unique peer ID for a new WebSocket connection.
|
|
368
|
-
*
|
|
369
|
-
* Uses `crypto.randomUUID()` which is available in Bun, Node 19+, and modern browsers.
|
|
370
|
-
*
|
|
371
|
-
* @returns A UUID string.
|
|
372
|
-
*/
|
|
373
|
-
function _generatePeerId() {
|
|
374
|
-
return crypto.randomUUID();
|
|
375
|
-
}
|
|
376
|
-
//# sourceMappingURL=handlers.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"handlers.js","sourceRoot":"","sources":["../../src/server/handlers.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @module server/postmessage-handler
|
|
3
|
-
* @description Parent-frame PostMessage handler for Workshop WebContainer kit iframes.
|
|
4
|
-
*
|
|
5
|
-
* Workshop kit apps run as WebContainer iframes inside the Workshop editor. They use
|
|
6
|
-
* {@link PostMessageTransport} from `@soulcraft/sdk/client` to post Brainy RPC calls to the
|
|
7
|
-
* parent Workshop frame. This module provides the parent-side handler that receives those
|
|
8
|
-
* calls, dispatches them to the live Brainy instance, and posts the response back.
|
|
9
|
-
*
|
|
10
|
-
* ## Wire protocol
|
|
11
|
-
*
|
|
12
|
-
* **Inbound** (from kit iframe):
|
|
13
|
-
* ```json
|
|
14
|
-
* { "type": "brainy:request", "id": "<uuid>", "method": "find", "args": [{...}] }
|
|
15
|
-
* ```
|
|
16
|
-
*
|
|
17
|
-
* **Outbound** (to kit iframe):
|
|
18
|
-
* ```json
|
|
19
|
-
* { "type": "brainy:response", "id": "<uuid>", "result": [...] }
|
|
20
|
-
* { "type": "brainy:response", "id": "<uuid>", "error": { "code": "...", "message": "..." } }
|
|
21
|
-
* ```
|
|
22
|
-
*
|
|
23
|
-
* ## Usage (Workshop parent frame)
|
|
24
|
-
*
|
|
25
|
-
* ```typescript
|
|
26
|
-
* import { createBrainyPostMessageHandler } from '@soulcraft/sdk/server'
|
|
27
|
-
* import { createSDK, BrainyInstancePool } from '@soulcraft/sdk/server'
|
|
28
|
-
*
|
|
29
|
-
* const pool = new BrainyInstancePool({ ... })
|
|
30
|
-
*
|
|
31
|
-
* // Mount once per kit iframe window:
|
|
32
|
-
* const handler = createBrainyPostMessageHandler({
|
|
33
|
-
* resolveBrain: async (method) => {
|
|
34
|
-
* const brain = await pool.forUser(currentUser.emailHash, currentWorkspaceId)
|
|
35
|
-
* return brain
|
|
36
|
-
* },
|
|
37
|
-
* allowedOrigin: 'null', // WebContainer iframes have origin 'null'
|
|
38
|
-
* targetWindow: kitIframeRef.contentWindow!,
|
|
39
|
-
* })
|
|
40
|
-
*
|
|
41
|
-
* // When the kit iframe is torn down:
|
|
42
|
-
* handler.dispose()
|
|
43
|
-
* ```
|
|
44
|
-
*
|
|
45
|
-
* ## Security
|
|
46
|
-
*
|
|
47
|
-
* The handler validates the `event.origin` against `allowedOrigin` before dispatching.
|
|
48
|
-
* WebContainer iframes have `origin: 'null'` — pass `'null'` (string) for those.
|
|
49
|
-
* For externally hosted kit apps, pass the expected origin string.
|
|
50
|
-
*
|
|
51
|
-
* Optionally, set `allowedSource` to the `contentWindow` of the specific iframe to
|
|
52
|
-
* reject messages from other frames on the same origin.
|
|
53
|
-
*/
|
|
54
|
-
import type { Brainy } from '@soulcraft/brainy';
|
|
55
|
-
import type { BrainyChangeEvent } from '../modules/brainy/events.js';
|
|
56
|
-
/**
|
|
57
|
-
* Configuration for {@link createBrainyPostMessageHandler}.
|
|
58
|
-
*/
|
|
59
|
-
export interface BrainyPostMessageHandlerConfig {
|
|
60
|
-
/**
|
|
61
|
-
* Resolve the Brainy instance to use for a given RPC call.
|
|
62
|
-
*
|
|
63
|
-
* Called once per request. Workshop typically resolves from a `BrainyInstancePool`
|
|
64
|
-
* keyed to the current user and workspace.
|
|
65
|
-
*
|
|
66
|
-
* @param method - The Brainy method being called (e.g. `'find'`, `'vfs.readFile'`).
|
|
67
|
-
* @returns A live Brainy instance.
|
|
68
|
-
*/
|
|
69
|
-
resolveBrain: (method: string) => Promise<Brainy> | Brainy;
|
|
70
|
-
/**
|
|
71
|
-
* The expected `event.origin` of inbound messages.
|
|
72
|
-
*
|
|
73
|
-
* Messages from any other origin are silently ignored.
|
|
74
|
-
* Pass `'null'` (string) for WebContainer iframes, which always report origin `'null'`.
|
|
75
|
-
* Pass `'*'` to accept any origin (not recommended in production).
|
|
76
|
-
*/
|
|
77
|
-
allowedOrigin: string;
|
|
78
|
-
/**
|
|
79
|
-
* The window to which responses are posted.
|
|
80
|
-
*
|
|
81
|
-
* Defaults to the `source` of the inbound message event. Pass the kit iframe's
|
|
82
|
-
* `contentWindow` explicitly to further restrict which window receives responses.
|
|
83
|
-
*/
|
|
84
|
-
targetWindow?: Window;
|
|
85
|
-
/**
|
|
86
|
-
* The window on which to listen for inbound `message` events.
|
|
87
|
-
*
|
|
88
|
-
* Defaults to the global `window`. Override in tests or if the handler should
|
|
89
|
-
* listen on a specific frame's window.
|
|
90
|
-
*/
|
|
91
|
-
listenerWindow?: Window & typeof globalThis;
|
|
92
|
-
/**
|
|
93
|
-
* Optional hook to subscribe to Brainy change events and forward them to the kit iframe.
|
|
94
|
-
*
|
|
95
|
-
* Called once when the handler is mounted. The provided `emit` callback posts a
|
|
96
|
-
* `brainy:event` message to the kit iframe whenever a Brainy change fires. Return an
|
|
97
|
-
* unsubscribe function; it will be called on `dispose()`.
|
|
98
|
-
*
|
|
99
|
-
* @param emit - Call this with each {@link BrainyChangeEvent} to forward it to the iframe.
|
|
100
|
-
* @returns An unsubscribe function called on `dispose()`.
|
|
101
|
-
*
|
|
102
|
-
* @example
|
|
103
|
-
* ```typescript
|
|
104
|
-
* createBrainyPostMessageHandler({
|
|
105
|
-
* resolveBrain: () => pool.forUser(user.emailHash, workspaceId),
|
|
106
|
-
* allowedOrigin: 'null',
|
|
107
|
-
* targetWindow: iframe.contentWindow!,
|
|
108
|
-
* subscribeToEvents: (emit) => {
|
|
109
|
-
* const off = brainyChangeEmitter.on('change', emit)
|
|
110
|
-
* return off
|
|
111
|
-
* },
|
|
112
|
-
* })
|
|
113
|
-
* ```
|
|
114
|
-
*/
|
|
115
|
-
subscribeToEvents?: (emit: (event: BrainyChangeEvent) => void) => () => void;
|
|
116
|
-
}
|
|
117
|
-
/**
|
|
118
|
-
* A mounted PostMessage handler. Call `dispose()` when the kit iframe is torn down
|
|
119
|
-
* to remove the message listener and prevent memory leaks.
|
|
120
|
-
*/
|
|
121
|
-
export interface BrainyPostMessageHandler {
|
|
122
|
-
/**
|
|
123
|
-
* Remove the `message` event listener from the listener window.
|
|
124
|
-
*
|
|
125
|
-
* Call this when the associated kit iframe is unmounted or navigated away.
|
|
126
|
-
*/
|
|
127
|
-
dispose(): void;
|
|
128
|
-
}
|
|
129
|
-
/**
|
|
130
|
-
* Mount a PostMessage handler in the parent Workshop frame.
|
|
131
|
-
*
|
|
132
|
-
* Listens for `brainy:request` messages from kit iframes, dispatches each call to
|
|
133
|
-
* the resolved Brainy instance via a {@link LocalTransport}, and posts the result
|
|
134
|
-
* back as a `brainy:response` message.
|
|
135
|
-
*
|
|
136
|
-
* @param config - Handler configuration including brain resolver and allowed origin.
|
|
137
|
-
* @returns A {@link BrainyPostMessageHandler} with a `dispose()` method.
|
|
138
|
-
*
|
|
139
|
-
* @example
|
|
140
|
-
* ```typescript
|
|
141
|
-
* const handler = createBrainyPostMessageHandler({
|
|
142
|
-
* resolveBrain: () => pool.forUser(user.emailHash, workspaceId),
|
|
143
|
-
* allowedOrigin: 'null', // WebContainer iframes report origin 'null'
|
|
144
|
-
* targetWindow: iframe.contentWindow!,
|
|
145
|
-
* })
|
|
146
|
-
*
|
|
147
|
-
* // On iframe unmount:
|
|
148
|
-
* handler.dispose()
|
|
149
|
-
* ```
|
|
150
|
-
*/
|
|
151
|
-
export declare function createBrainyPostMessageHandler(config: BrainyPostMessageHandlerConfig): BrainyPostMessageHandler;
|
|
152
|
-
//# sourceMappingURL=postmessage-handler.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"postmessage-handler.d.ts","sourceRoot":"","sources":["../../src/server/postmessage-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoDG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAG/C,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAA;AAMpE;;GAEG;AACH,MAAM,WAAW,8BAA8B;IAC7C;;;;;;;;OAQG;IACH,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,GAAG,MAAM,CAAA;IAE1D;;;;;;OAMG;IACH,aAAa,EAAE,MAAM,CAAA;IAErB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IAErB;;;;;OAKG;IACH,cAAc,CAAC,EAAE,MAAM,GAAG,OAAO,UAAU,CAAA;IAE3C;;;;;;;;;;;;;;;;;;;;;;OAsBG;IACH,iBAAiB,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,KAAK,MAAM,IAAI,CAAA;CAC7E;AAED;;;GAGG;AACH,MAAM,WAAW,wBAAwB;IACvC;;;;OAIG;IACH,OAAO,IAAI,IAAI,CAAA;CAChB;AAMD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,8BAA8B,GACrC,wBAAwB,CA2D1B"}
|