@soulcraft/sdk 1.0.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.
- package/dist/client/index.d.ts +62 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +60 -0
- package/dist/client/index.js.map +1 -0
- package/dist/index.d.ts +33 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/index.js.map +1 -0
- package/dist/modules/ai/index.d.ts +55 -0
- package/dist/modules/ai/index.d.ts.map +1 -0
- package/dist/modules/ai/index.js +263 -0
- package/dist/modules/ai/index.js.map +1 -0
- package/dist/modules/ai/types.d.ts +216 -0
- package/dist/modules/ai/types.d.ts.map +1 -0
- package/dist/modules/ai/types.js +30 -0
- package/dist/modules/ai/types.js.map +1 -0
- package/dist/modules/auth/backchannel.d.ts +85 -0
- package/dist/modules/auth/backchannel.d.ts.map +1 -0
- package/dist/modules/auth/backchannel.js +168 -0
- package/dist/modules/auth/backchannel.js.map +1 -0
- package/dist/modules/auth/config.d.ts +122 -0
- package/dist/modules/auth/config.d.ts.map +1 -0
- package/dist/modules/auth/config.js +158 -0
- package/dist/modules/auth/config.js.map +1 -0
- package/dist/modules/auth/middleware.d.ts +146 -0
- package/dist/modules/auth/middleware.d.ts.map +1 -0
- package/dist/modules/auth/middleware.js +204 -0
- package/dist/modules/auth/middleware.js.map +1 -0
- package/dist/modules/auth/types.d.ts +162 -0
- package/dist/modules/auth/types.d.ts.map +1 -0
- package/dist/modules/auth/types.js +14 -0
- package/dist/modules/auth/types.js.map +1 -0
- package/dist/modules/billing/types.d.ts +7 -0
- package/dist/modules/billing/types.d.ts.map +1 -0
- package/dist/modules/billing/types.js +7 -0
- package/dist/modules/billing/types.js.map +1 -0
- package/dist/modules/brainy/auth.d.ts +104 -0
- package/dist/modules/brainy/auth.d.ts.map +1 -0
- package/dist/modules/brainy/auth.js +144 -0
- package/dist/modules/brainy/auth.js.map +1 -0
- package/dist/modules/brainy/errors.d.ts +118 -0
- package/dist/modules/brainy/errors.d.ts.map +1 -0
- package/dist/modules/brainy/errors.js +142 -0
- package/dist/modules/brainy/errors.js.map +1 -0
- package/dist/modules/brainy/events.d.ts +63 -0
- package/dist/modules/brainy/events.d.ts.map +1 -0
- package/dist/modules/brainy/events.js +14 -0
- package/dist/modules/brainy/events.js.map +1 -0
- package/dist/modules/brainy/proxy.d.ts +48 -0
- package/dist/modules/brainy/proxy.d.ts.map +1 -0
- package/dist/modules/brainy/proxy.js +95 -0
- package/dist/modules/brainy/proxy.js.map +1 -0
- package/dist/modules/brainy/types.d.ts +83 -0
- package/dist/modules/brainy/types.d.ts.map +1 -0
- package/dist/modules/brainy/types.js +21 -0
- package/dist/modules/brainy/types.js.map +1 -0
- package/dist/modules/events/index.d.ts +41 -0
- package/dist/modules/events/index.d.ts.map +1 -0
- package/dist/modules/events/index.js +53 -0
- package/dist/modules/events/index.js.map +1 -0
- package/dist/modules/events/types.d.ts +129 -0
- package/dist/modules/events/types.d.ts.map +1 -0
- package/dist/modules/events/types.js +32 -0
- package/dist/modules/events/types.js.map +1 -0
- package/dist/modules/formats/types.d.ts +7 -0
- package/dist/modules/formats/types.d.ts.map +1 -0
- package/dist/modules/formats/types.js +7 -0
- package/dist/modules/formats/types.js.map +1 -0
- package/dist/modules/hall/types.d.ts +56 -0
- package/dist/modules/hall/types.d.ts.map +1 -0
- package/dist/modules/hall/types.js +16 -0
- package/dist/modules/hall/types.js.map +1 -0
- package/dist/modules/kits/types.d.ts +7 -0
- package/dist/modules/kits/types.d.ts.map +1 -0
- package/dist/modules/kits/types.js +7 -0
- package/dist/modules/kits/types.js.map +1 -0
- package/dist/modules/license/types.d.ts +7 -0
- package/dist/modules/license/types.d.ts.map +1 -0
- package/dist/modules/license/types.js +7 -0
- package/dist/modules/license/types.js.map +1 -0
- package/dist/modules/notifications/types.d.ts +7 -0
- package/dist/modules/notifications/types.d.ts.map +1 -0
- package/dist/modules/notifications/types.js +7 -0
- package/dist/modules/notifications/types.js.map +1 -0
- package/dist/modules/skills/index.d.ts +60 -0
- package/dist/modules/skills/index.d.ts.map +1 -0
- package/dist/modules/skills/index.js +253 -0
- package/dist/modules/skills/index.js.map +1 -0
- package/dist/modules/skills/types.d.ts +127 -0
- package/dist/modules/skills/types.d.ts.map +1 -0
- package/dist/modules/skills/types.js +23 -0
- package/dist/modules/skills/types.js.map +1 -0
- package/dist/modules/versions/types.d.ts +31 -0
- package/dist/modules/versions/types.d.ts.map +1 -0
- package/dist/modules/versions/types.js +9 -0
- package/dist/modules/versions/types.js.map +1 -0
- package/dist/modules/vfs/types.d.ts +26 -0
- package/dist/modules/vfs/types.d.ts.map +1 -0
- package/dist/modules/vfs/types.js +11 -0
- package/dist/modules/vfs/types.js.map +1 -0
- package/dist/server/create-sdk.d.ts +70 -0
- package/dist/server/create-sdk.d.ts.map +1 -0
- package/dist/server/create-sdk.js +125 -0
- package/dist/server/create-sdk.js.map +1 -0
- package/dist/server/hall-handlers.d.ts +195 -0
- package/dist/server/hall-handlers.d.ts.map +1 -0
- package/dist/server/hall-handlers.js +239 -0
- package/dist/server/hall-handlers.js.map +1 -0
- package/dist/server/handlers.d.ts +216 -0
- package/dist/server/handlers.d.ts.map +1 -0
- package/dist/server/handlers.js +214 -0
- package/dist/server/handlers.js.map +1 -0
- package/dist/server/index.d.ts +52 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +50 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/instance-pool.d.ts +299 -0
- package/dist/server/instance-pool.d.ts.map +1 -0
- package/dist/server/instance-pool.js +359 -0
- package/dist/server/instance-pool.js.map +1 -0
- package/dist/transports/http.d.ts +86 -0
- package/dist/transports/http.d.ts.map +1 -0
- package/dist/transports/http.js +134 -0
- package/dist/transports/http.js.map +1 -0
- package/dist/transports/local.d.ts +76 -0
- package/dist/transports/local.d.ts.map +1 -0
- package/dist/transports/local.js +101 -0
- package/dist/transports/local.js.map +1 -0
- package/dist/transports/sse.d.ts +99 -0
- package/dist/transports/sse.d.ts.map +1 -0
- package/dist/transports/sse.js +192 -0
- package/dist/transports/sse.js.map +1 -0
- package/dist/transports/transport.d.ts +68 -0
- package/dist/transports/transport.d.ts.map +1 -0
- package/dist/transports/transport.js +14 -0
- package/dist/transports/transport.js.map +1 -0
- package/dist/transports/ws.d.ts +135 -0
- package/dist/transports/ws.d.ts.map +1 -0
- package/dist/transports/ws.js +331 -0
- package/dist/transports/ws.js.map +1 -0
- package/dist/types.d.ts +152 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +8 -0
- package/dist/types.js.map +1 -0
- package/docs/ADR-001-sdk-design.md +282 -0
- package/docs/IMPLEMENTATION-PLAN.md +708 -0
- package/docs/USAGE.md +646 -0
- package/docs/kit-sdk-guide.md +474 -0
- package/package.json +61 -0
|
@@ -0,0 +1,216 @@
|
|
|
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 type { Brainy } from '@soulcraft/brainy';
|
|
73
|
+
import { LocalTransport } from '../transports/local.js';
|
|
74
|
+
import type { BrainyChangeEvent } from '../modules/brainy/events.js';
|
|
75
|
+
/**
|
|
76
|
+
* Configuration for {@link createBrainyHandler}.
|
|
77
|
+
*/
|
|
78
|
+
export interface BrainyHandlerConfig {
|
|
79
|
+
/**
|
|
80
|
+
* Resolves the Brainy instance to dispatch this request against.
|
|
81
|
+
*
|
|
82
|
+
* Called on every request. Use request headers (org slug, workspace ID, etc.)
|
|
83
|
+
* to select the correct instance from the pool.
|
|
84
|
+
*
|
|
85
|
+
* @param request - The incoming HTTP Request.
|
|
86
|
+
* @returns The Brainy instance for this request's scope.
|
|
87
|
+
*/
|
|
88
|
+
resolveBrain: (request: Request) => Promise<Brainy>;
|
|
89
|
+
/**
|
|
90
|
+
* Authenticates the incoming request.
|
|
91
|
+
*
|
|
92
|
+
* Return any truthy value (claims, session object, etc.) on success.
|
|
93
|
+
* Return `null` or `undefined` to reject the request with HTTP 401.
|
|
94
|
+
*
|
|
95
|
+
* @param request - The incoming HTTP Request.
|
|
96
|
+
* @returns An auth context on success, or `null` to reject.
|
|
97
|
+
*/
|
|
98
|
+
authenticate: (request: Request) => Promise<unknown | null>;
|
|
99
|
+
/**
|
|
100
|
+
* Optional per-call authorization check.
|
|
101
|
+
*
|
|
102
|
+
* Called after `authenticate()` succeeds. Return `false` or `null` to
|
|
103
|
+
* reject with HTTP 403.
|
|
104
|
+
*
|
|
105
|
+
* @param method - Dot-separated Brainy method name.
|
|
106
|
+
* @param args - Positional arguments from the request body.
|
|
107
|
+
* @param auth - The auth context returned by `authenticate()`.
|
|
108
|
+
* @returns `true` to allow, `false` / `null` to deny.
|
|
109
|
+
*/
|
|
110
|
+
authorize?: (method: string, args: unknown[], auth: unknown) => boolean | null | Promise<boolean | null>;
|
|
111
|
+
/**
|
|
112
|
+
* Methods that are blocked for all callers regardless of auth.
|
|
113
|
+
*
|
|
114
|
+
* @default []
|
|
115
|
+
*/
|
|
116
|
+
blockedMethods?: string[];
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Creates a Fetch-API-compatible HTTP handler for Brainy RPC calls.
|
|
120
|
+
*
|
|
121
|
+
* Mount at `POST /api/brainy/rpc` in your product's router.
|
|
122
|
+
*
|
|
123
|
+
* @param config - Handler configuration.
|
|
124
|
+
* @returns `(request: Request) => Promise<Response>`
|
|
125
|
+
*/
|
|
126
|
+
export declare function createBrainyHandler(config: BrainyHandlerConfig): (request: Request) => Promise<Response>;
|
|
127
|
+
/**
|
|
128
|
+
* Configuration for {@link createBrainyWsHandler}.
|
|
129
|
+
*/
|
|
130
|
+
export interface BrainyWsHandlerConfig {
|
|
131
|
+
/**
|
|
132
|
+
* Resolves the Brainy instance for the given scope (e.g. tenant slug).
|
|
133
|
+
*
|
|
134
|
+
* @param scope - The `?scope=` query param from the WebSocket URL.
|
|
135
|
+
* @returns The Brainy instance for this scope.
|
|
136
|
+
*/
|
|
137
|
+
resolveBrain: (scope: string) => Promise<Brainy>;
|
|
138
|
+
/**
|
|
139
|
+
* Authenticates the WebSocket upgrade request.
|
|
140
|
+
*
|
|
141
|
+
* The `token` is extracted from `Authorization: Bearer <token>`. Return `null`
|
|
142
|
+
* to close the socket with code 4001 (unauthorized).
|
|
143
|
+
*
|
|
144
|
+
* @param token - The bearer token from the Authorization header.
|
|
145
|
+
* @param scope - The requested scope from the URL.
|
|
146
|
+
* @returns An auth context on success, or `null` to reject.
|
|
147
|
+
*/
|
|
148
|
+
authenticate: (token: string, scope: string) => Promise<unknown | null>;
|
|
149
|
+
/**
|
|
150
|
+
* Optional per-call authorization check.
|
|
151
|
+
*
|
|
152
|
+
* @param method - Dot-separated Brainy method name.
|
|
153
|
+
* @param args - Positional arguments.
|
|
154
|
+
* @param auth - The auth context from `authenticate()`.
|
|
155
|
+
* @returns `true` to allow, `false` / `null` to deny.
|
|
156
|
+
*/
|
|
157
|
+
authorize?: (method: string, args: unknown[], auth: unknown) => boolean | null | Promise<boolean | null>;
|
|
158
|
+
/** Methods blocked for all callers. @default [] */
|
|
159
|
+
blockedMethods?: string[];
|
|
160
|
+
}
|
|
161
|
+
/** Per-connection session state stored on the WebSocket. */
|
|
162
|
+
export interface WsSession {
|
|
163
|
+
/** The tenant scope extracted from `?scope=`. */
|
|
164
|
+
scope: string;
|
|
165
|
+
/** The auth context returned by `authenticate()`. */
|
|
166
|
+
auth: unknown;
|
|
167
|
+
/** The resolved Brainy instance for this scope. */
|
|
168
|
+
brain: Brainy;
|
|
169
|
+
/** Local transport wrapping the Brainy instance for this session. */
|
|
170
|
+
transport: LocalTransport;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* The object returned by {@link createBrainyWsHandler}.
|
|
174
|
+
*/
|
|
175
|
+
export interface BrainyWsHandler {
|
|
176
|
+
/**
|
|
177
|
+
* Handles a WebSocket upgrade request.
|
|
178
|
+
*
|
|
179
|
+
* Extracts the token and scope from the request, authenticates, and resolves
|
|
180
|
+
* the Brainy instance. Returns `null` if authentication fails (caller should
|
|
181
|
+
* respond with 401 and not proceed with the upgrade).
|
|
182
|
+
*
|
|
183
|
+
* @param request - The HTTP upgrade Request.
|
|
184
|
+
* @returns Session state on success, or `null` on auth failure.
|
|
185
|
+
*/
|
|
186
|
+
handleUpgrade(request: Request): Promise<WsSession | null>;
|
|
187
|
+
/**
|
|
188
|
+
* Processes an incoming WebSocket message.
|
|
189
|
+
*
|
|
190
|
+
* Decodes the MessagePack frame, dispatches the RPC, and calls `send` with
|
|
191
|
+
* the encoded response.
|
|
192
|
+
*
|
|
193
|
+
* @param session - The session state from `handleUpgrade()`.
|
|
194
|
+
* @param data - Raw binary message frame.
|
|
195
|
+
* @param send - Callback to send a binary response to this client.
|
|
196
|
+
*/
|
|
197
|
+
handleMessage(session: WsSession, data: ArrayBuffer | Uint8Array, send: (msg: Uint8Array) => void): Promise<void>;
|
|
198
|
+
/**
|
|
199
|
+
* Broadcasts a Brainy change event to a connected client.
|
|
200
|
+
*
|
|
201
|
+
* Call this from your mutation hooks or after `brain.add()` / `brain.update()` /
|
|
202
|
+
* `brain.delete()` to push real-time updates to the client.
|
|
203
|
+
*
|
|
204
|
+
* @param event - The change event to broadcast.
|
|
205
|
+
* @param send - Callback to send the encoded event to the target client.
|
|
206
|
+
*/
|
|
207
|
+
broadcastChange(event: BrainyChangeEvent, send: (msg: Uint8Array) => void): void;
|
|
208
|
+
}
|
|
209
|
+
/**
|
|
210
|
+
* Creates a server-side WebSocket handler for bidirectional Brainy RPC + change push.
|
|
211
|
+
*
|
|
212
|
+
* @param config - Handler configuration.
|
|
213
|
+
* @returns A {@link BrainyWsHandler} instance.
|
|
214
|
+
*/
|
|
215
|
+
export declare function createBrainyWsHandler(config: BrainyWsHandlerConfig): BrainyWsHandler;
|
|
216
|
+
//# sourceMappingURL=handlers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../src/server/handlers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsEG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAA;AAC/C,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AACvD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAA;AAMpE;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;;;;;OAQG;IACH,YAAY,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;IAEnD;;;;;;;;OAQG;IACH,YAAY,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAA;IAE3D;;;;;;;;;;OAUG;IACH,SAAS,CAAC,EAAE,CACV,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,OAAO,EAAE,EACf,IAAI,EAAE,OAAO,KACV,OAAO,GAAG,IAAI,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAA;IAE7C;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,EAAE,CAAA;CAC1B;AAQD;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,MAAM,EAAE,mBAAmB,GAC1B,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CA0DzC;AAMD;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;;;OAKG;IACH,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAA;IAEhD;;;;;;;;;OASG;IACH,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAA;IAEvE;;;;;;;OAOG;IACH,SAAS,CAAC,EAAE,CACV,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,OAAO,EAAE,EACf,IAAI,EAAE,OAAO,KACV,OAAO,GAAG,IAAI,GAAG,OAAO,CAAC,OAAO,GAAG,IAAI,CAAC,CAAA;IAE7C,mDAAmD;IACnD,cAAc,CAAC,EAAE,MAAM,EAAE,CAAA;CAC1B;AAED,4DAA4D;AAC5D,MAAM,WAAW,SAAS;IACxB,iDAAiD;IACjD,KAAK,EAAE,MAAM,CAAA;IACb,qDAAqD;IACrD,IAAI,EAAE,OAAO,CAAA;IACb,mDAAmD;IACnD,KAAK,EAAE,MAAM,CAAA;IACb,qEAAqE;IACrE,SAAS,EAAE,cAAc,CAAA;CAC1B;AASD;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B;;;;;;;;;OASG;IACH,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAAA;IAE1D;;;;;;;;;OASG;IACH,aAAa,CACX,OAAO,EAAE,SAAS,EAClB,IAAI,EAAE,WAAW,GAAG,UAAU,EAC9B,IAAI,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,IAAI,GAC9B,OAAO,CAAC,IAAI,CAAC,CAAA;IAEhB;;;;;;;;OAQG;IACH,eAAe,CAAC,KAAK,EAAE,iBAAiB,EAAE,IAAI,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,IAAI,GAAG,IAAI,CAAA;CACjF;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,qBAAqB,GAAG,eAAe,CAkEpF"}
|
|
@@ -0,0 +1,214 @@
|
|
|
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
|
+
/**
|
|
75
|
+
* Creates a Fetch-API-compatible HTTP handler for Brainy RPC calls.
|
|
76
|
+
*
|
|
77
|
+
* Mount at `POST /api/brainy/rpc` in your product's router.
|
|
78
|
+
*
|
|
79
|
+
* @param config - Handler configuration.
|
|
80
|
+
* @returns `(request: Request) => Promise<Response>`
|
|
81
|
+
*/
|
|
82
|
+
export function createBrainyHandler(config) {
|
|
83
|
+
const { resolveBrain, authenticate, authorize, blockedMethods = [] } = config;
|
|
84
|
+
return async function brainyRpcHandler(request) {
|
|
85
|
+
// ── Auth ──────────────────────────────────────────────────────────────
|
|
86
|
+
const auth = await authenticate(request);
|
|
87
|
+
if (!auth)
|
|
88
|
+
return _jsonError(401, 'UNAUTHORIZED', 'Authentication required');
|
|
89
|
+
// ── Parse ─────────────────────────────────────────────────────────────
|
|
90
|
+
let body;
|
|
91
|
+
try {
|
|
92
|
+
body = (await request.json());
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
return _jsonError(400, 'BAD_REQUEST', 'Request body must be valid JSON');
|
|
96
|
+
}
|
|
97
|
+
if (typeof body.method !== 'string' || !Array.isArray(body.args)) {
|
|
98
|
+
return _jsonError(400, 'BAD_REQUEST', '{ method: string, args: unknown[] } required');
|
|
99
|
+
}
|
|
100
|
+
const method = body.method;
|
|
101
|
+
const args = body.args;
|
|
102
|
+
// ── Blocklist ─────────────────────────────────────────────────────────
|
|
103
|
+
if (blockedMethods.includes(method)) {
|
|
104
|
+
return _jsonError(403, 'FORBIDDEN', `Method '${method}' is not available via RPC`);
|
|
105
|
+
}
|
|
106
|
+
// ── Authorize ─────────────────────────────────────────────────────────
|
|
107
|
+
if (authorize) {
|
|
108
|
+
const allowed = await authorize(method, args, auth);
|
|
109
|
+
if (!allowed) {
|
|
110
|
+
return _jsonError(403, 'FORBIDDEN', `Not authorized to call '${method}'`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// ── Resolve brain + dispatch ──────────────────────────────────────────
|
|
114
|
+
let brain;
|
|
115
|
+
try {
|
|
116
|
+
brain = await resolveBrain(request);
|
|
117
|
+
}
|
|
118
|
+
catch (err) {
|
|
119
|
+
console.error('[SDK/handler] resolveBrain threw:', err);
|
|
120
|
+
return _jsonError(503, 'BRAIN_UNAVAILABLE', 'Brainy instance not available');
|
|
121
|
+
}
|
|
122
|
+
const transport = new LocalTransport(brain);
|
|
123
|
+
try {
|
|
124
|
+
const result = await transport.call(method, args);
|
|
125
|
+
return new Response(JSON.stringify({ result }), {
|
|
126
|
+
status: 200,
|
|
127
|
+
headers: { 'Content-Type': 'application/json' },
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
catch (err) {
|
|
131
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
132
|
+
return _jsonError(500, 'RPC_ERROR', message);
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Creates a server-side WebSocket handler for bidirectional Brainy RPC + change push.
|
|
138
|
+
*
|
|
139
|
+
* @param config - Handler configuration.
|
|
140
|
+
* @returns A {@link BrainyWsHandler} instance.
|
|
141
|
+
*/
|
|
142
|
+
export function createBrainyWsHandler(config) {
|
|
143
|
+
const { resolveBrain, authenticate, authorize, blockedMethods = [] } = config;
|
|
144
|
+
return {
|
|
145
|
+
async handleUpgrade(request) {
|
|
146
|
+
const url = new URL(request.url);
|
|
147
|
+
const scope = url.searchParams.get('scope') ?? '';
|
|
148
|
+
const authHeader = request.headers.get('authorization') ?? '';
|
|
149
|
+
const token = authHeader.startsWith('Bearer ') ? authHeader.slice(7) : '';
|
|
150
|
+
const auth = await authenticate(token, scope);
|
|
151
|
+
if (!auth)
|
|
152
|
+
return null;
|
|
153
|
+
const brain = await resolveBrain(scope);
|
|
154
|
+
const transport = new LocalTransport(brain);
|
|
155
|
+
return { scope, auth, brain, transport };
|
|
156
|
+
},
|
|
157
|
+
async handleMessage(session, data, send) {
|
|
158
|
+
let decoded;
|
|
159
|
+
try {
|
|
160
|
+
decoded = decode(data instanceof ArrayBuffer ? new Uint8Array(data) : data);
|
|
161
|
+
}
|
|
162
|
+
catch {
|
|
163
|
+
return; // Malformed frame — silently ignore
|
|
164
|
+
}
|
|
165
|
+
if (!decoded || typeof decoded !== 'object')
|
|
166
|
+
return;
|
|
167
|
+
const req = decoded;
|
|
168
|
+
if (typeof req.id !== 'string' || typeof req.method !== 'string' || !Array.isArray(req.args)) {
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
const { id, method, args } = req;
|
|
172
|
+
if (blockedMethods.includes(method)) {
|
|
173
|
+
send(encode({ id, error: { code: 'FORBIDDEN', message: `Method '${method}' blocked` } }));
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
if (authorize) {
|
|
177
|
+
const allowed = await authorize(method, args, session.auth);
|
|
178
|
+
if (!allowed) {
|
|
179
|
+
send(encode({ id, error: { code: 'FORBIDDEN', message: `Not authorized: '${method}'` } }));
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
try {
|
|
184
|
+
const result = await session.transport.call(method, args);
|
|
185
|
+
send(encode({ id, result }));
|
|
186
|
+
}
|
|
187
|
+
catch (err) {
|
|
188
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
189
|
+
send(encode({ id, error: { code: 'RPC_ERROR', message } }));
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
broadcastChange(event, send) {
|
|
193
|
+
send(encode(event));
|
|
194
|
+
},
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
198
|
+
// Internal helpers
|
|
199
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
200
|
+
/**
|
|
201
|
+
* Builds a JSON error response with `{ error: { code, message } }` body.
|
|
202
|
+
*
|
|
203
|
+
* @param status - HTTP status code.
|
|
204
|
+
* @param code - Machine-readable error code.
|
|
205
|
+
* @param message - Human-readable description.
|
|
206
|
+
* @returns A `Response` with the error payload.
|
|
207
|
+
*/
|
|
208
|
+
function _jsonError(status, code, message) {
|
|
209
|
+
return new Response(JSON.stringify({ error: { code, message } }), {
|
|
210
|
+
status,
|
|
211
|
+
headers: { 'Content-Type': 'application/json' },
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
//# sourceMappingURL=handlers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handlers.js","sourceRoot":"","sources":["../../src/server/handlers.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsEG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAA;AAEjD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAgEvD;;;;;;;GAOG;AACH,MAAM,UAAU,mBAAmB,CACjC,MAA2B;IAE3B,MAAM,EAAE,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,cAAc,GAAG,EAAE,EAAE,GAAG,MAAM,CAAA;IAE7E,OAAO,KAAK,UAAU,gBAAgB,CAAC,OAAgB;QACrD,yEAAyE;QACzE,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC,CAAA;QACxC,IAAI,CAAC,IAAI;YAAE,OAAO,UAAU,CAAC,GAAG,EAAE,cAAc,EAAE,yBAAyB,CAAC,CAAA;QAE5E,yEAAyE;QACzE,IAAI,IAAoB,CAAA;QACxB,IAAI,CAAC;YACH,IAAI,GAAG,CAAC,MAAM,OAAO,CAAC,IAAI,EAAE,CAAmB,CAAA;QACjD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,UAAU,CAAC,GAAG,EAAE,aAAa,EAAE,iCAAiC,CAAC,CAAA;QAC1E,CAAC;QAED,IAAI,OAAO,IAAI,CAAC,MAAM,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;YACjE,OAAO,UAAU,CAAC,GAAG,EAAE,aAAa,EAAE,8CAA8C,CAAC,CAAA;QACvF,CAAC;QAED,MAAM,MAAM,GAAG,IAAI,CAAC,MAAM,CAAA;QAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,IAAiB,CAAA;QAEnC,yEAAyE;QACzE,IAAI,cAAc,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;YACpC,OAAO,UAAU,CAAC,GAAG,EAAE,WAAW,EAAE,WAAW,MAAM,4BAA4B,CAAC,CAAA;QACpF,CAAC;QAED,yEAAyE;QACzE,IAAI,SAAS,EAAE,CAAC;YACd,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,CAAA;YACnD,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,OAAO,UAAU,CAAC,GAAG,EAAE,WAAW,EAAE,2BAA2B,MAAM,GAAG,CAAC,CAAA;YAC3E,CAAC;QACH,CAAC;QAED,yEAAyE;QACzE,IAAI,KAAa,CAAA;QACjB,IAAI,CAAC;YACH,KAAK,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC,CAAA;QACrC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,mCAAmC,EAAE,GAAG,CAAC,CAAA;YACvD,OAAO,UAAU,CAAC,GAAG,EAAE,mBAAmB,EAAE,+BAA+B,CAAC,CAAA;QAC9E,CAAC;QAED,MAAM,SAAS,GAAG,IAAI,cAAc,CAAC,KAAK,CAAC,CAAA;QAE3C,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;YACjD,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE;gBAC9C,MAAM,EAAE,GAAG;gBACX,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;aAChD,CAAC,CAAA;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;YAChE,OAAO,UAAU,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,CAAC,CAAA;QAC9C,CAAC;IACH,CAAC,CAAA;AACH,CAAC;AA+GD;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,MAA6B;IACjE,MAAM,EAAE,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,cAAc,GAAG,EAAE,EAAE,GAAG,MAAM,CAAA;IAE7E,OAAO;QACL,KAAK,CAAC,aAAa,CAAC,OAAgB;YAClC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;YAChC,MAAM,KAAK,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAA;YACjD,MAAM,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,IAAI,EAAE,CAAA;YAC7D,MAAM,KAAK,GAAG,UAAU,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;YAEzE,MAAM,IAAI,GAAG,MAAM,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC,CAAA;YAC7C,IAAI,CAAC,IAAI;gBAAE,OAAO,IAAI,CAAA;YAEtB,MAAM,KAAK,GAAG,MAAM,YAAY,CAAC,KAAK,CAAC,CAAA;YACvC,MAAM,SAAS,GAAG,IAAI,cAAc,CAAC,KAAK,CAAC,CAAA;YAE3C,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,SAAS,EAAE,CAAA;QAC1C,CAAC;QAED,KAAK,CAAC,aAAa,CACjB,OAAkB,EAClB,IAA8B,EAC9B,IAA+B;YAE/B,IAAI,OAAgB,CAAA;YACpB,IAAI,CAAC;gBACH,OAAO,GAAG,MAAM,CAAC,IAAI,YAAY,WAAW,CAAC,CAAC,CAAC,IAAI,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;YAC7E,CAAC;YAAC,MAAM,CAAC;gBACP,OAAM,CAAC,oCAAoC;YAC7C,CAAC;YAED,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ;gBAAE,OAAM;YACnD,MAAM,GAAG,GAAG,OAAuB,CAAA;YAEnC,IAAI,OAAO,GAAG,CAAC,EAAE,KAAK,QAAQ,IAAI,OAAO,GAAG,CAAC,MAAM,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC7F,OAAM;YACR,CAAC;YAED,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,GAAG,CAAA;YAEhC,IAAI,cAAc,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;gBACpC,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,WAAW,MAAM,WAAW,EAAE,EAAE,CAAC,CAAC,CAAA;gBACzF,OAAM;YACR,CAAC;YAED,IAAI,SAAS,EAAE,CAAC;gBACd,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;gBAC3D,IAAI,CAAC,OAAO,EAAE,CAAC;oBACb,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,oBAAoB,MAAM,GAAG,EAAE,EAAE,CAAC,CAAC,CAAA;oBAC1F,OAAM;gBACR,CAAC;YACH,CAAC;YAED,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAA;gBACzD,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,CAAC,CAAC,CAAA;YAC9B,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;gBAChE,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC,CAAA;YAC7D,CAAC;QACH,CAAC;QAED,eAAe,CAAC,KAAwB,EAAE,IAA+B;YACvE,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAA;QACrB,CAAC;KACF,CAAA;AACH,CAAC;AAED,gFAAgF;AAChF,mBAAmB;AACnB,gFAAgF;AAEhF;;;;;;;GAOG;AACH,SAAS,UAAU,CAAC,MAAc,EAAE,IAAY,EAAE,OAAe;IAC/D,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,CAAC,EAAE;QAChE,MAAM;QACN,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;KAChD,CAAC,CAAA;AACJ,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @soulcraft/sdk/server
|
|
3
|
+
* @description Server entry point for @soulcraft/sdk. Exports everything needed to
|
|
4
|
+
* run the SDK in a product backend (Hono, SvelteKit, or any Bun/Node server).
|
|
5
|
+
*
|
|
6
|
+
* Includes: Brainy instance pool, HTTP and WebSocket RPC handler factories, and
|
|
7
|
+
* capability token utilities.
|
|
8
|
+
*
|
|
9
|
+
* This entry point must never be imported in browser bundles — it has hard
|
|
10
|
+
* server-only dependencies (`@soulcraft/brainy`, `lru-cache`, `crypto`, `fs`).
|
|
11
|
+
*
|
|
12
|
+
* @example Workshop server setup
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import { BrainyInstancePool, createBrainyHandler, createBrainyWsHandler, computeEmailHash } from '@soulcraft/sdk/server'
|
|
15
|
+
* import { verifyCapabilityToken } from '@soulcraft/sdk'
|
|
16
|
+
*
|
|
17
|
+
* const pool = new BrainyInstancePool({
|
|
18
|
+
* storage: 'mmap-filesystem',
|
|
19
|
+
* dataPath: '/mnt/brainy-data',
|
|
20
|
+
* strategy: 'per-user',
|
|
21
|
+
* maxInstances: 200,
|
|
22
|
+
* flushOnEvict: true,
|
|
23
|
+
* })
|
|
24
|
+
*
|
|
25
|
+
* const rpcHandler = createBrainyHandler({
|
|
26
|
+
* resolveBrain: (req) => {
|
|
27
|
+
* const userId = req.headers.get('x-email-hash') ?? ''
|
|
28
|
+
* const workspaceId = req.headers.get('x-workspace-id') ?? ''
|
|
29
|
+
* return pool.forUser(userId, workspaceId)
|
|
30
|
+
* },
|
|
31
|
+
* authenticate: (req) => verifySession(req.headers.get('cookie') ?? ''),
|
|
32
|
+
* })
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export { BrainyInstancePool, BrainyInitializingError, computeEmailHash, } from './instance-pool.js';
|
|
36
|
+
export type { InstancePoolConfig, InstancePoolStats, } from './instance-pool.js';
|
|
37
|
+
export { createBrainyHandler, createBrainyWsHandler, } from './handlers.js';
|
|
38
|
+
export type { BrainyHandlerConfig, BrainyWsHandlerConfig, BrainyWsHandler, WsSession, } from './handlers.js';
|
|
39
|
+
export { createHallRoomHandler, generateTurnCredentials, } from './hall-handlers.js';
|
|
40
|
+
export type { HallRoomHandlerConfig, HallRoomHandler, HallSession, TurnCredentialOptions, TurnCredentials, } from './hall-handlers.js';
|
|
41
|
+
export { createAuthMiddleware, createRemoteSessionVerifier, AUTH_USER_KEY, } from '../modules/auth/middleware.js';
|
|
42
|
+
export type { AuthMiddlewareOptions, AuthMiddleware, AuthContext, BetterAuthLike, RemoteSessionVerifierOptions, } from '../modules/auth/middleware.js';
|
|
43
|
+
export { createBackchannelLogoutHandler } from '../modules/auth/backchannel.js';
|
|
44
|
+
export type { BackchannelLogoutConfig, BackchannelAuthLike, } from '../modules/auth/backchannel.js';
|
|
45
|
+
export { SOULCRAFT_USER_FIELDS, SOULCRAFT_SESSION_CONFIG, getAuthMode, getOIDCClientConfig, } from '../modules/auth/config.js';
|
|
46
|
+
export { createSDK } from './create-sdk.js';
|
|
47
|
+
export type { CreateSDKOptions } from './create-sdk.js';
|
|
48
|
+
export type { ServerSDKOptions } from '../types.js';
|
|
49
|
+
export { createCapabilityToken, verifyCapabilityToken } from '../modules/brainy/auth.js';
|
|
50
|
+
export type { CreateCapabilityTokenOptions, CapabilityTokenClaims } from '../modules/brainy/auth.js';
|
|
51
|
+
export { LocalTransport } from '../transports/local.js';
|
|
52
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAGH,OAAO,EACL,kBAAkB,EAClB,uBAAuB,EACvB,gBAAgB,GACjB,MAAM,oBAAoB,CAAA;AAC3B,YAAY,EACV,kBAAkB,EAClB,iBAAiB,GAClB,MAAM,oBAAoB,CAAA;AAG3B,OAAO,EACL,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,eAAe,CAAA;AACtB,YAAY,EACV,mBAAmB,EACnB,qBAAqB,EACrB,eAAe,EACf,SAAS,GACV,MAAM,eAAe,CAAA;AAGtB,OAAO,EACL,qBAAqB,EACrB,uBAAuB,GACxB,MAAM,oBAAoB,CAAA;AAC3B,YAAY,EACV,qBAAqB,EACrB,eAAe,EACf,WAAW,EACX,qBAAqB,EACrB,eAAe,GAChB,MAAM,oBAAoB,CAAA;AAG3B,OAAO,EACL,oBAAoB,EACpB,2BAA2B,EAC3B,aAAa,GACd,MAAM,+BAA+B,CAAA;AACtC,YAAY,EACV,qBAAqB,EACrB,cAAc,EACd,WAAW,EACX,cAAc,EACd,4BAA4B,GAC7B,MAAM,+BAA+B,CAAA;AACtC,OAAO,EAAE,8BAA8B,EAAE,MAAM,gCAAgC,CAAA;AAC/E,YAAY,EACV,uBAAuB,EACvB,mBAAmB,GACpB,MAAM,gCAAgC,CAAA;AAGvC,OAAO,EACL,qBAAqB,EACrB,wBAAwB,EACxB,WAAW,EACX,mBAAmB,GACpB,MAAM,2BAA2B,CAAA;AAGlC,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAC3C,YAAY,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAA;AAGvD,YAAY,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAA;AACnD,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAA;AACxF,YAAY,EAAE,4BAA4B,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAA;AACpG,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module @soulcraft/sdk/server
|
|
3
|
+
* @description Server entry point for @soulcraft/sdk. Exports everything needed to
|
|
4
|
+
* run the SDK in a product backend (Hono, SvelteKit, or any Bun/Node server).
|
|
5
|
+
*
|
|
6
|
+
* Includes: Brainy instance pool, HTTP and WebSocket RPC handler factories, and
|
|
7
|
+
* capability token utilities.
|
|
8
|
+
*
|
|
9
|
+
* This entry point must never be imported in browser bundles — it has hard
|
|
10
|
+
* server-only dependencies (`@soulcraft/brainy`, `lru-cache`, `crypto`, `fs`).
|
|
11
|
+
*
|
|
12
|
+
* @example Workshop server setup
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import { BrainyInstancePool, createBrainyHandler, createBrainyWsHandler, computeEmailHash } from '@soulcraft/sdk/server'
|
|
15
|
+
* import { verifyCapabilityToken } from '@soulcraft/sdk'
|
|
16
|
+
*
|
|
17
|
+
* const pool = new BrainyInstancePool({
|
|
18
|
+
* storage: 'mmap-filesystem',
|
|
19
|
+
* dataPath: '/mnt/brainy-data',
|
|
20
|
+
* strategy: 'per-user',
|
|
21
|
+
* maxInstances: 200,
|
|
22
|
+
* flushOnEvict: true,
|
|
23
|
+
* })
|
|
24
|
+
*
|
|
25
|
+
* const rpcHandler = createBrainyHandler({
|
|
26
|
+
* resolveBrain: (req) => {
|
|
27
|
+
* const userId = req.headers.get('x-email-hash') ?? ''
|
|
28
|
+
* const workspaceId = req.headers.get('x-workspace-id') ?? ''
|
|
29
|
+
* return pool.forUser(userId, workspaceId)
|
|
30
|
+
* },
|
|
31
|
+
* authenticate: (req) => verifySession(req.headers.get('cookie') ?? ''),
|
|
32
|
+
* })
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
// ── Instance pool ─────────────────────────────────────────────────────────────
|
|
36
|
+
export { BrainyInstancePool, BrainyInitializingError, computeEmailHash, } from './instance-pool.js';
|
|
37
|
+
// ── Handler factories ─────────────────────────────────────────────────────────
|
|
38
|
+
export { createBrainyHandler, createBrainyWsHandler, } from './handlers.js';
|
|
39
|
+
// ── Hall handler factories ────────────────────────────────────────────────────
|
|
40
|
+
export { createHallRoomHandler, generateTurnCredentials, } from './hall-handlers.js';
|
|
41
|
+
// ── Auth middleware + backchannel logout ──────────────────────────────────────
|
|
42
|
+
export { createAuthMiddleware, createRemoteSessionVerifier, AUTH_USER_KEY, } from '../modules/auth/middleware.js';
|
|
43
|
+
export { createBackchannelLogoutHandler } from '../modules/auth/backchannel.js';
|
|
44
|
+
// ── Auth config helpers (also on shared entry, duplicated here for convenience) ─
|
|
45
|
+
export { SOULCRAFT_USER_FIELDS, SOULCRAFT_SESSION_CONFIG, getAuthMode, getOIDCClientConfig, } from '../modules/auth/config.js';
|
|
46
|
+
// ── createSDK factory ─────────────────────────────────────────────────────────
|
|
47
|
+
export { createSDK } from './create-sdk.js';
|
|
48
|
+
export { createCapabilityToken, verifyCapabilityToken } from '../modules/brainy/auth.js';
|
|
49
|
+
export { LocalTransport } from '../transports/local.js';
|
|
50
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,iFAAiF;AACjF,OAAO,EACL,kBAAkB,EAClB,uBAAuB,EACvB,gBAAgB,GACjB,MAAM,oBAAoB,CAAA;AAM3B,iFAAiF;AACjF,OAAO,EACL,mBAAmB,EACnB,qBAAqB,GACtB,MAAM,eAAe,CAAA;AAQtB,iFAAiF;AACjF,OAAO,EACL,qBAAqB,EACrB,uBAAuB,GACxB,MAAM,oBAAoB,CAAA;AAS3B,iFAAiF;AACjF,OAAO,EACL,oBAAoB,EACpB,2BAA2B,EAC3B,aAAa,GACd,MAAM,+BAA+B,CAAA;AAQtC,OAAO,EAAE,8BAA8B,EAAE,MAAM,gCAAgC,CAAA;AAM/E,mFAAmF;AACnF,OAAO,EACL,qBAAqB,EACrB,wBAAwB,EACxB,WAAW,EACX,mBAAmB,GACpB,MAAM,2BAA2B,CAAA;AAElC,iFAAiF;AACjF,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAA;AAK3C,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAA;AAExF,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA"}
|