@soulcraft/sdk 2.0.0 → 2.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (93) hide show
  1. package/dist/client/index.d.ts +5 -38
  2. package/dist/client/index.d.ts.map +1 -1
  3. package/dist/client/index.js +5 -47
  4. package/dist/client/index.js.map +1 -1
  5. package/dist/client/namespace-proxy.d.ts +3 -4
  6. package/dist/client/namespace-proxy.d.ts.map +1 -1
  7. package/dist/client/namespace-proxy.js +3 -4
  8. package/dist/client/namespace-proxy.js.map +1 -1
  9. package/dist/index.d.ts +6 -6
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +4 -4
  12. package/dist/index.js.map +1 -1
  13. package/dist/modules/hall/browser.d.ts +83 -27
  14. package/dist/modules/hall/browser.d.ts.map +1 -1
  15. package/dist/modules/hall/browser.js +238 -49
  16. package/dist/modules/hall/browser.js.map +1 -1
  17. package/dist/modules/hall/media.d.ts +164 -0
  18. package/dist/modules/hall/media.d.ts.map +1 -0
  19. package/dist/modules/hall/media.js +182 -0
  20. package/dist/modules/hall/media.js.map +1 -0
  21. package/dist/modules/hall/server.d.ts +83 -6
  22. package/dist/modules/hall/server.d.ts.map +1 -1
  23. package/dist/modules/hall/server.js +206 -9
  24. package/dist/modules/hall/server.js.map +1 -1
  25. package/dist/modules/hall/types.d.ts +548 -25
  26. package/dist/modules/hall/types.d.ts.map +1 -1
  27. package/dist/modules/hall/types.js +12 -7
  28. package/dist/modules/hall/types.js.map +1 -1
  29. package/dist/server/hall-handlers.d.ts +40 -12
  30. package/dist/server/hall-handlers.d.ts.map +1 -1
  31. package/dist/server/hall-handlers.js +40 -12
  32. package/dist/server/hall-handlers.js.map +1 -1
  33. package/dist/server/handlers/chat/engine.d.ts.map +1 -1
  34. package/dist/server/handlers/chat/engine.js +5 -1
  35. package/dist/server/handlers/chat/engine.js.map +1 -1
  36. package/dist/server/handlers/chat/types.d.ts +17 -2
  37. package/dist/server/handlers/chat/types.d.ts.map +1 -1
  38. package/dist/server/hono-router.d.ts +2 -9
  39. package/dist/server/hono-router.d.ts.map +1 -1
  40. package/dist/server/hono-router.js +2 -46
  41. package/dist/server/hono-router.js.map +1 -1
  42. package/dist/server/index.d.ts +4 -19
  43. package/dist/server/index.d.ts.map +1 -1
  44. package/dist/server/index.js +10 -29
  45. package/dist/server/index.js.map +1 -1
  46. package/dist/types.d.ts +2 -41
  47. package/dist/types.d.ts.map +1 -1
  48. package/docs/ADR-005-hall-integration.md +449 -0
  49. package/package.json +1 -1
  50. package/dist/client/create-client-sdk.d.ts +0 -113
  51. package/dist/client/create-client-sdk.d.ts.map +0 -1
  52. package/dist/client/create-client-sdk.js +0 -169
  53. package/dist/client/create-client-sdk.js.map +0 -1
  54. package/dist/modules/app-context/index.d.ts +0 -214
  55. package/dist/modules/app-context/index.d.ts.map +0 -1
  56. package/dist/modules/app-context/index.js +0 -569
  57. package/dist/modules/app-context/index.js.map +0 -1
  58. package/dist/modules/billing/firestore-provider.d.ts +0 -60
  59. package/dist/modules/billing/firestore-provider.d.ts.map +0 -1
  60. package/dist/modules/billing/firestore-provider.js +0 -315
  61. package/dist/modules/billing/firestore-provider.js.map +0 -1
  62. package/dist/modules/brainy/proxy.d.ts +0 -48
  63. package/dist/modules/brainy/proxy.d.ts.map +0 -1
  64. package/dist/modules/brainy/proxy.js +0 -95
  65. package/dist/modules/brainy/proxy.js.map +0 -1
  66. package/dist/server/create-sdk.d.ts +0 -74
  67. package/dist/server/create-sdk.d.ts.map +0 -1
  68. package/dist/server/create-sdk.js +0 -104
  69. package/dist/server/create-sdk.js.map +0 -1
  70. package/dist/server/from-license.d.ts +0 -252
  71. package/dist/server/from-license.d.ts.map +0 -1
  72. package/dist/server/from-license.js +0 -349
  73. package/dist/server/from-license.js.map +0 -1
  74. package/dist/server/handlers.d.ts +0 -312
  75. package/dist/server/handlers.d.ts.map +0 -1
  76. package/dist/server/handlers.js +0 -376
  77. package/dist/server/handlers.js.map +0 -1
  78. package/dist/server/postmessage-handler.d.ts +0 -152
  79. package/dist/server/postmessage-handler.d.ts.map +0 -1
  80. package/dist/server/postmessage-handler.js +0 -138
  81. package/dist/server/postmessage-handler.js.map +0 -1
  82. package/dist/transports/http.d.ts +0 -86
  83. package/dist/transports/http.d.ts.map +0 -1
  84. package/dist/transports/http.js +0 -137
  85. package/dist/transports/http.js.map +0 -1
  86. package/dist/transports/postmessage.d.ts +0 -159
  87. package/dist/transports/postmessage.d.ts.map +0 -1
  88. package/dist/transports/postmessage.js +0 -207
  89. package/dist/transports/postmessage.js.map +0 -1
  90. package/dist/transports/workshop.d.ts +0 -173
  91. package/dist/transports/workshop.d.ts.map +0 -1
  92. package/dist/transports/workshop.js +0 -307
  93. package/dist/transports/workshop.js.map +0 -1
@@ -1,349 +0,0 @@
1
- /**
2
- * @module server/from-license
3
- * @description License-driven server SDK factory.
4
- *
5
- * `createServerSDK.fromLicense({ product })` is the recommended production entry point
6
- * for product backends. It replaces the manual environment-variable wiring required by
7
- * `createSDK()` with a single boot-time call to Portal:
8
- *
9
- * ```
10
- * SOULCRAFT_LICENSE_KEY=SC-XXXX-XXXX-XXXX ← only secret needed
11
- * ```
12
- *
13
- * At startup the factory:
14
- * 1. Reads `SOULCRAFT_LICENSE_KEY` from the environment.
15
- * 2. POSTs `POST https://soulcraft.com/api/license/activate` with the key and product name.
16
- * 3. Receives a config bundle (`anthropicApiKey`, `portalCreditSecret`, `hallSecret`, etc.).
17
- * 4. Injects the bundle values into `process.env` so all SDK module factories pick them
18
- * up automatically — no factory API changes required.
19
- * 5. Writes the bundle to `.soulcraft-config.json` in the working directory for offline
20
- * restarts (e.g. if Portal is temporarily unreachable after a product restart).
21
- * 6. Schedules a background re-validation every 4 hours to pick up rotated secrets.
22
- *
23
- * The returned `ServerSDK` object is long-lived (one per process). Its `createSDK(brain)`
24
- * method returns a per-request `SoulcraftSDK`, identical to calling `createSDK({ brain })`
25
- * directly, but with all secrets already wired from the bundle.
26
- *
27
- * ## Backward compatibility
28
- *
29
- * `createSDK()` is unchanged — products that manage their own env vars continue to work
30
- * exactly as before. `fromLicense()` is additive.
31
- *
32
- * ## Offline / degraded start
33
- *
34
- * If Portal is unreachable on first boot, the factory falls back to a cached bundle from
35
- * `.soulcraft-config.json`. If no cache exists either, it throws — a product cannot start
36
- * in production without a resolved config bundle.
37
- *
38
- * @example Academy startup
39
- * ```typescript
40
- * import { createServerSDK, BrainyInstancePool } from '@soulcraft/sdk/server'
41
- *
42
- * const server = await createServerSDK.fromLicense({ product: 'academy' })
43
- *
44
- * const pool = new BrainyInstancePool({
45
- * storage: 'mmap-filesystem',
46
- * dataPath: '/mnt/brainy-data',
47
- * strategy: 'per-user',
48
- * })
49
- *
50
- * // Per-request:
51
- * app.get('/api/brainy', requireAuth, async (c) => {
52
- * const brain = await pool.forUser(user.emailHash, 'main')
53
- * const sdk = server.createSDK(brain)
54
- * const items = await sdk.brainy.find({ query: 'candle inventory' })
55
- * return c.json({ items })
56
- * })
57
- *
58
- * // On shutdown:
59
- * process.on('SIGTERM', () => server.shutdown())
60
- * ```
61
- */
62
- import { readFileSync, writeFileSync, renameSync } from 'node:fs';
63
- import { resolve } from 'node:path';
64
- import { createSDK } from './create-sdk.js';
65
- import { createHallModule } from './hall-handlers.js';
66
- import { SDK_VERSION } from '../version.js';
67
- // ─────────────────────────────────────────────────────────────────────────────
68
- // Constants
69
- // ─────────────────────────────────────────────────────────────────────────────
70
- /** Portal license activation endpoint. */
71
- const ACTIVATE_URL = 'https://soulcraft.com/api/license/activate';
72
- /** Re-validation interval: 4 hours. */
73
- const REVALIDATE_INTERVAL_MS = 4 * 60 * 60 * 1000;
74
- /**
75
- * Returns the path to the cached config bundle.
76
- *
77
- * Resolved lazily at call-time so the path is always relative to the working
78
- * directory at the time of the call, not at module load time.
79
- */
80
- function getCachePath() {
81
- return resolve(process.cwd(), '.soulcraft-config.json');
82
- }
83
- // ─────────────────────────────────────────────────────────────────────────────
84
- // Internal helpers
85
- // ─────────────────────────────────────────────────────────────────────────────
86
- /**
87
- * Call the Portal `licenseActivate` endpoint and return the full response.
88
- *
89
- * @throws {Error} If the network call fails or Portal returns a non-200 status.
90
- */
91
- async function _activate(key, product) {
92
- const response = await fetch(ACTIVATE_URL, {
93
- method: 'POST',
94
- headers: { 'Content-Type': 'application/json' },
95
- body: JSON.stringify({ key, product, sdkVersion: SDK_VERSION }),
96
- signal: AbortSignal.timeout(15_000),
97
- });
98
- if (response.status === 403) {
99
- const body = (await response.json().catch(() => ({})));
100
- throw new Error(`License key rejected by Portal: ${body.reason ?? 'key_not_found'}. ` +
101
- `Check SOULCRAFT_LICENSE_KEY is correct and the license has not expired.`);
102
- }
103
- if (!response.ok) {
104
- throw new Error(`Portal license activation failed (HTTP ${response.status}). ` +
105
- `The service may be temporarily unavailable.`);
106
- }
107
- return response.json();
108
- }
109
- /**
110
- * Read the cached bundle from `.soulcraft-config.json`.
111
- * Returns `undefined` if the file does not exist or cannot be parsed.
112
- */
113
- function _readCache() {
114
- try {
115
- const raw = readFileSync(getCachePath(), 'utf8');
116
- return JSON.parse(raw);
117
- }
118
- catch {
119
- return undefined;
120
- }
121
- }
122
- /**
123
- * Write the activation response to `.soulcraft-config.json`.
124
- * Failures are non-fatal — if the disk is read-only, the cache is simply not written.
125
- */
126
- function _writeCache(product, response) {
127
- try {
128
- const bundle = {
129
- activatedAt: new Date().toISOString(),
130
- product,
131
- response,
132
- };
133
- writeFileSync(getCachePath(), JSON.stringify(bundle, null, 2), 'utf8');
134
- }
135
- catch {
136
- // Non-fatal — read-only FS or permission error.
137
- }
138
- }
139
- /**
140
- * Inject config bundle values into `process.env`.
141
- *
142
- * Only sets variables that are present in the bundle and not already set by the host
143
- * environment. Host-set values take precedence, allowing per-deployment overrides.
144
- */
145
- function _injectEnv(config) {
146
- const mappings = [
147
- ['anthropicApiKey', 'ANTHROPIC_API_KEY'],
148
- ['portalCreditSecret', 'PORTAL_CREDIT_SECRET'],
149
- ['hallUrl', 'HALL_URL'],
150
- ['stripeSecretKey', 'STRIPE_SECRET_KEY'],
151
- ['stripeWebhookSecret', 'STRIPE_WEBHOOK_SECRET'],
152
- ['workshopDeploySecret', 'WORKSHOP_DEPLOY_SECRET'],
153
- ['academyPublishSecret', 'ACADEMY_PUBLISH_SECRET'],
154
- ['venueRpcSecret', 'VENUE_RPC_SECRET'],
155
- ['postmarkToken', 'POSTMARK_SERVER_TOKEN'],
156
- ['postmarkFromEmail', 'POSTMARK_FROM_EMAIL'],
157
- ['twilioSid', 'TWILIO_ACCOUNT_SID'],
158
- ['twilioToken', 'TWILIO_AUTH_TOKEN'],
159
- ['twilioFromNumber', 'TWILIO_FROM_NUMBER'],
160
- ];
161
- for (const [configKey, envKey] of mappings) {
162
- const value = config[configKey];
163
- if (value && !process.env[envKey]) {
164
- process.env[envKey] = value;
165
- }
166
- }
167
- }
168
- /**
169
- * Write a Cortex license key to `.soulcraft.json` in the working directory.
170
- *
171
- * Uses an atomic tmp-then-rename write so a concurrent Cortex process never
172
- * reads a partial file. Must be called BEFORE `createSDK(brain)` — Cortex
173
- * reads `.soulcraft.json` during Brainy plugin initialization.
174
- *
175
- * Failures are non-fatal: if the filesystem is read-only or permissions are
176
- * missing, Cortex falls back to its own activation code exchange.
177
- *
178
- * @param cortexLicenseKey - The Cortex Ed25519 JWT (`sc_cortex_...`) to persist.
179
- */
180
- function _writeSoulcraftJson(cortexLicenseKey) {
181
- try {
182
- const targetPath = resolve(process.cwd(), '.soulcraft.json');
183
- const tmpPath = targetPath + '.tmp';
184
- writeFileSync(tmpPath, JSON.stringify({ cortex: cortexLicenseKey }, null, 2) + '\n', 'utf8');
185
- renameSync(tmpPath, targetPath);
186
- }
187
- catch {
188
- // Non-fatal — Cortex exchanges its own activation code independently.
189
- }
190
- }
191
- // ─────────────────────────────────────────────────────────────────────────────
192
- // fromLicense factory
193
- // ─────────────────────────────────────────────────────────────────────────────
194
- /**
195
- * Activate the SDK from a Soulcraft license key.
196
- *
197
- * Calls Portal's `licenseActivate` endpoint, injects the returned config bundle
198
- * into `process.env`, and returns a `ServerSDK` ready for per-request use.
199
- *
200
- * Falls back to a cached bundle (`.soulcraft-config.json`) if Portal is unreachable.
201
- * Throws if neither Portal nor a valid cache is available.
202
- *
203
- * @param options - Product name and optional license key override.
204
- * @returns A `ServerSDK` instance, fully wired from the license bundle.
205
- *
206
- * @throws {Error} If the license key is invalid, expired, or Portal is unreachable with no cache.
207
- *
208
- * @example
209
- * ```typescript
210
- * const server = await createServerSDK.fromLicense({ product: 'academy' })
211
- * const pool = new BrainyInstancePool({ storage: 'mmap-filesystem', dataPath: '/mnt/brainy-data', strategy: 'per-user' })
212
- *
213
- * app.use(requireAuth)
214
- * app.get('/api/brainy', async (c) => {
215
- * const brain = await pool.forUser(c.get('user').emailHash, 'main')
216
- * const sdk = server.createSDK(brain)
217
- * return c.json(await sdk.brainy.find({ query: c.req.query('q') ?? '' }))
218
- * })
219
- *
220
- * process.on('SIGTERM', () => server.shutdown())
221
- * ```
222
- */
223
- async function fromLicense(options) {
224
- const { product } = options;
225
- const key = options.licenseKey ?? process.env['SOULCRAFT_LICENSE_KEY'];
226
- if (!key) {
227
- throw new Error('SOULCRAFT_LICENSE_KEY is not set. ' +
228
- 'Set this environment variable to your Soulcraft license key, ' +
229
- 'or pass licenseKey explicitly to fromLicense().');
230
- }
231
- // ── Activate ──────────────────────────────────────────────────────────────
232
- let activateResponse;
233
- try {
234
- activateResponse = await _activate(key, product);
235
- _writeCache(product, activateResponse);
236
- }
237
- catch (err) {
238
- // Portal unreachable — try the cached bundle.
239
- const cached = _readCache();
240
- if (cached?.product === product && cached.response.valid) {
241
- console.warn(`[SDK] Portal unreachable (${err instanceof Error ? err.message : String(err)}). ` +
242
- `Using cached config from ${cached.activatedAt}.`);
243
- activateResponse = cached.response;
244
- }
245
- else {
246
- throw new Error(`Failed to activate SDK license and no valid cache found. ` +
247
- `Original error: ${err instanceof Error ? err.message : String(err)}`);
248
- }
249
- }
250
- if (!activateResponse.valid) {
251
- throw new Error(`License key is not valid: ${activateResponse.reason ?? 'unknown reason'}. ` +
252
- `Check that your license has not expired.`);
253
- }
254
- const config = activateResponse.config;
255
- const tier = activateResponse.tier ?? 'free';
256
- let venueOrgConfig = activateResponse.venueOrgConfig ?? {};
257
- // ── Inject env ────────────────────────────────────────────────────────────
258
- _injectEnv(config);
259
- // ── Write Cortex license to .soulcraft.json ───────────────────────────────
260
- // Must run before createSDK(brain) — Cortex reads .soulcraft.json at Brainy
261
- // plugin initialization time, not at first use.
262
- if (config.cortexLicenseKey) {
263
- _writeSoulcraftJson(config.cortexLicenseKey);
264
- }
265
- // ── Wire Hall ─────────────────────────────────────────────────────────────
266
- let hall;
267
- if (config.hallSecret && config.hallUrl) {
268
- hall = createHallModule({
269
- url: config.hallUrl,
270
- productName: product,
271
- secret: config.hallSecret,
272
- });
273
- await hall.connect();
274
- }
275
- // ── Background re-validation ──────────────────────────────────────────────
276
- let _revalidateTimer;
277
- async function _revalidate() {
278
- try {
279
- const fresh = await _activate(key, product);
280
- _writeCache(product, fresh);
281
- _injectEnv(fresh.config);
282
- if (fresh.config.cortexLicenseKey) {
283
- _writeSoulcraftJson(fresh.config.cortexLicenseKey);
284
- }
285
- venueOrgConfig = fresh.venueOrgConfig ?? {};
286
- }
287
- catch {
288
- // Non-fatal — the in-memory injected values remain valid until next attempt.
289
- }
290
- }
291
- _revalidateTimer = setInterval(() => { void _revalidate(); }, REVALIDATE_INTERVAL_MS);
292
- if (_revalidateTimer.unref)
293
- _revalidateTimer.unref();
294
- // ── Return ServerSDK ──────────────────────────────────────────────────────
295
- return {
296
- createSDK(brain) {
297
- return createSDK({ brain });
298
- },
299
- get hall() {
300
- return hall;
301
- },
302
- get config() {
303
- return config;
304
- },
305
- get tier() {
306
- return tier;
307
- },
308
- get venueOrgConfig() {
309
- return venueOrgConfig;
310
- },
311
- shutdown() {
312
- if (_revalidateTimer) {
313
- clearInterval(_revalidateTimer);
314
- _revalidateTimer = undefined;
315
- }
316
- if (hall) {
317
- void hall.close();
318
- }
319
- },
320
- };
321
- }
322
- // ─────────────────────────────────────────────────────────────────────────────
323
- // createServerSDK namespace
324
- // ─────────────────────────────────────────────────────────────────────────────
325
- /**
326
- * Server SDK factory namespace.
327
- *
328
- * The primary entry point is `createServerSDK.fromLicense({ product })`.
329
- * For lower-level control (custom Brainy instance, no license key), use
330
- * `createSDK({ brain })` directly.
331
- *
332
- * @example
333
- * ```typescript
334
- * import { createServerSDK, BrainyInstancePool } from '@soulcraft/sdk/server'
335
- *
336
- * const server = await createServerSDK.fromLicense({ product: 'workshop' })
337
- * const pool = new BrainyInstancePool({ storage: 'mmap-filesystem', dataPath: '/mnt/data', strategy: 'per-user' })
338
- *
339
- * app.get('/api/brainy', requireAuth, async (c) => {
340
- * const brain = await pool.forUser(c.get('user').emailHash, 'main')
341
- * const sdk = server.createSDK(brain)
342
- * return c.json(await sdk.brainy.find({ query: c.req.query('q') ?? '' }))
343
- * })
344
- * ```
345
- */
346
- export const createServerSDK = {
347
- fromLicense,
348
- };
349
- //# sourceMappingURL=from-license.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"from-license.js","sourceRoot":"","sources":["../../src/server/from-license.ts"],"names":[],"mappings":"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"}
@@ -1,312 +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 type { Brainy } from '@soulcraft/brainy';
73
- import { LocalTransport } from '../transports/local.js';
74
- import type { BrainyChangeEvent } from '../modules/brainy/events.js';
75
- import { YDocManager } from '../modules/brainy/ydoc-manager.js';
76
- /**
77
- * Configuration for {@link createBrainyHandler}.
78
- */
79
- export interface BrainyHandlerConfig {
80
- /**
81
- * Resolves the Brainy instance to dispatch this request against.
82
- *
83
- * Called on every request. Use request headers (org slug, workspace ID, etc.)
84
- * to select the correct instance from the pool.
85
- *
86
- * @param request - The incoming HTTP Request.
87
- * @returns The Brainy instance for this request's scope.
88
- */
89
- resolveBrain: (request: Request) => Promise<Brainy>;
90
- /**
91
- * Authenticates the incoming request.
92
- *
93
- * Return any truthy value (claims, session object, etc.) on success.
94
- * Return `null` or `undefined` to reject the request with HTTP 401.
95
- *
96
- * @param request - The incoming HTTP Request.
97
- * @returns An auth context on success, or `null` to reject.
98
- */
99
- authenticate: (request: Request) => Promise<unknown | null>;
100
- /**
101
- * Optional per-call authorization check.
102
- *
103
- * Called after `authenticate()` succeeds. Return `false` or `null` to
104
- * reject with HTTP 403.
105
- *
106
- * @param method - Dot-separated Brainy method name.
107
- * @param args - Positional arguments from the request body.
108
- * @param auth - The auth context returned by `authenticate()`.
109
- * @returns `true` to allow, `false` / `null` to deny.
110
- */
111
- authorize?: (method: string, args: unknown[], auth: unknown) => boolean | null | Promise<boolean | null>;
112
- /**
113
- * Methods that are blocked for all callers regardless of auth.
114
- *
115
- * @default []
116
- */
117
- blockedMethods?: string[];
118
- }
119
- /**
120
- * Creates a Fetch-API-compatible HTTP handler for Brainy RPC calls.
121
- *
122
- * Mount at `POST /api/brainy/rpc` in your product's router.
123
- *
124
- * @param config - Handler configuration.
125
- * @returns `(request: Request) => Promise<Response>`
126
- */
127
- export declare function createBrainyHandler(config: BrainyHandlerConfig): (request: Request) => Promise<Response>;
128
- /**
129
- * Configuration for {@link createBrainyWsHandler}.
130
- */
131
- export interface BrainyWsHandlerConfig {
132
- /**
133
- * Resolves the Brainy instance for the given scope (e.g. tenant slug).
134
- *
135
- * @param scope - The `?scope=` query param from the WebSocket URL.
136
- * @returns The Brainy instance for this scope.
137
- */
138
- resolveBrain: (scope: string) => Promise<Brainy>;
139
- /**
140
- * Authenticates the WebSocket upgrade request.
141
- *
142
- * The `token` is extracted from `Authorization: Bearer <token>` (Bun/Node) or
143
- * `?token=` query param (browser). Return `null` to reject with close code 4001.
144
- *
145
- * @param token - The bearer token from the header or query string.
146
- * @param scope - The requested scope from the URL.
147
- * @returns An auth context on success, or `null` to reject.
148
- */
149
- authenticate: (token: string, scope: string) => Promise<unknown | null>;
150
- /**
151
- * Optional per-call authorization check for Brainy RPC methods.
152
- *
153
- * @param method - Dot-separated Brainy method name.
154
- * @param args - Positional arguments.
155
- * @param auth - The auth context from `authenticate()`.
156
- * @returns `true` to allow, `false` / `null` to deny.
157
- */
158
- authorize?: (method: string, args: unknown[], auth: unknown) => boolean | null | Promise<boolean | null>;
159
- /** Methods blocked for all callers. @default [] */
160
- blockedMethods?: string[];
161
- /**
162
- * Optional Y.js document manager for real-time collaborative editing.
163
- *
164
- * When provided, the handler routes `y-sync`, `y-update`, and `y-awareness`
165
- * messages through the `YDocManager` instead of the Brainy RPC dispatcher.
166
- * Y.js update broadcasts are sent to all other peers via the `broadcast` callback
167
- * on the session — the product server must populate this callback when a peer
168
- * connects (see {@link WsSession.broadcast}).
169
- */
170
- ydocManager?: YDocManager;
171
- }
172
- /** Per-connection session state stored on the WebSocket data field. */
173
- export interface WsSession {
174
- /** The tenant scope extracted from `?scope=`. */
175
- scope: string;
176
- /** The auth context returned by `authenticate()`. */
177
- auth: unknown;
178
- /** The resolved Brainy instance for this scope. */
179
- brain: Brainy;
180
- /** Local transport wrapping the Brainy instance for this session. */
181
- transport: LocalTransport;
182
- /**
183
- * Unique peer ID for this connection. Used by `YDocManager` to track per-file
184
- * peer counts so it knows when the last peer has disconnected.
185
- */
186
- peerId: string;
187
- /**
188
- * Broadcast callback set by the product server after upgrade.
189
- *
190
- * Called by the handler to fan out `y-update` and `y-awareness` messages to all
191
- * other peers connected to this scope. The product server owns the connection map
192
- * (keyed by scope) and provides this callback so the SDK doesn't need to manage
193
- * WebSocket handles directly.
194
- *
195
- * @param msg - Encoded MessagePack frame to send to all OTHER peers in this scope.
196
- * @param excludePeerId - The peer that sent the message — must be excluded from broadcast.
197
- */
198
- broadcast: (msg: Uint8Array, excludePeerId: string) => void;
199
- }
200
- /**
201
- * The object returned by {@link createBrainyWsHandler}.
202
- */
203
- export interface BrainyWsHandler {
204
- /**
205
- * Handles a WebSocket upgrade request.
206
- *
207
- * Extracts the token and scope from the request, authenticates, and resolves
208
- * the Brainy instance. Returns `null` if authentication fails (caller should
209
- * respond with 401 and not proceed with the upgrade).
210
- *
211
- * After a successful upgrade the product server must set `session.broadcast` to
212
- * a function that sends a `Uint8Array` to all other peers in the same scope.
213
- *
214
- * @param request - The HTTP upgrade Request.
215
- * @returns Session state on success, or `null` on auth failure.
216
- */
217
- handleUpgrade(request: Request): Promise<WsSession | null>;
218
- /**
219
- * Processes an incoming WebSocket message.
220
- *
221
- * Decodes the MessagePack frame and routes it to either:
222
- * - The Brainy RPC dispatcher (frames with an `id` field), or
223
- * - The `YDocManager` (frames with `type: 'y-sync' | 'y-update' | 'y-awareness'`).
224
- *
225
- * Y.js update and awareness frames are also broadcast to other peers via
226
- * `session.broadcast`.
227
- *
228
- * @param session - The session state from `handleUpgrade()`.
229
- * @param data - Raw binary message frame.
230
- * @param send - Callback to send a binary response to THIS client only.
231
- */
232
- handleMessage(session: WsSession, data: ArrayBuffer | Uint8Array, send: (msg: Uint8Array) => void): Promise<void>;
233
- /**
234
- * Called when a peer's WebSocket connection closes.
235
- *
236
- * Notifies the `YDocManager` so it can flush and discard Y.Docs that no longer
237
- * have any active peers.
238
- *
239
- * @param session - The session state of the disconnecting peer.
240
- */
241
- handleClose(session: WsSession): Promise<void>;
242
- /**
243
- * Broadcasts a Brainy change event to a connected client.
244
- *
245
- * @param event - The change event to broadcast.
246
- * @param send - Callback to send the encoded event to the target client.
247
- */
248
- broadcastChange(event: BrainyChangeEvent, send: (msg: Uint8Array) => void): void;
249
- }
250
- /**
251
- * Creates a server-side WebSocket handler for bidirectional Brainy RPC, real-time
252
- * change push, and optional Y.js collaborative document editing.
253
- *
254
- * ## Y.js collaborative editing
255
- *
256
- * Pass a `ydocManager` in the config to enable co-editing. The handler will
257
- * automatically route `y-sync`, `y-update`, and `y-awareness` messages through the
258
- * manager. The product server must:
259
- *
260
- * 1. Maintain a `Map<scope, Map<peerId, sendFn>>` of connected peers.
261
- * 2. Set `session.broadcast` after `handleUpgrade()` to fan out Y.js frames.
262
- * 3. Call `handleClose(session)` when a peer disconnects.
263
- *
264
- * @example Workshop server wiring with Y.js
265
- * ```typescript
266
- * import { createBrainyWsHandler, YDocManager } from '@soulcraft/sdk/server'
267
- *
268
- * const ydocManager = new YDocManager()
269
- * const wsHandler = createBrainyWsHandler({ resolveBrain, authenticate, ydocManager })
270
- *
271
- * // Map<scope, Map<peerId, send>>
272
- * const peers = new Map<string, Map<string, (msg: Uint8Array) => void>>()
273
- *
274
- * Bun.serve({
275
- * async fetch(req, server) {
276
- * if (new URL(req.url).pathname === '/api/brainy/ws') {
277
- * const session = await wsHandler.handleUpgrade(req)
278
- * if (!session) return new Response('Unauthorized', { status: 401 })
279
- * // Register peer in broadcast map
280
- * if (!peers.has(session.scope)) peers.set(session.scope, new Map())
281
- * server.upgrade(req, { data: session })
282
- * return undefined
283
- * }
284
- * },
285
- * websocket: {
286
- * open(ws) {
287
- * const session = ws.data as WsSession
288
- * peers.get(session.scope)!.set(session.peerId, (msg) => ws.send(msg))
289
- * session.broadcast = (msg, excludeId) => {
290
- * for (const [id, send] of peers.get(session.scope) ?? []) {
291
- * if (id !== excludeId) send(msg)
292
- * }
293
- * }
294
- * ws.send(encode({ type: 'ready', scope: session.scope }))
295
- * },
296
- * async message(ws, data) {
297
- * await wsHandler.handleMessage(ws.data, data as ArrayBuffer, (msg) => ws.send(msg))
298
- * },
299
- * async close(ws) {
300
- * const session = ws.data as WsSession
301
- * peers.get(session.scope)?.delete(session.peerId)
302
- * await wsHandler.handleClose(session)
303
- * },
304
- * },
305
- * })
306
- * ```
307
- *
308
- * @param config - Handler configuration.
309
- * @returns A {@link BrainyWsHandler} instance.
310
- */
311
- export declare function createBrainyWsHandler(config: BrainyWsHandlerConfig): BrainyWsHandler;
312
- //# sourceMappingURL=handlers.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"handlers.d.ts","sourceRoot":"","sources":["../../src/server/handlers.ts"],"names":[],"mappings":"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"}