@soulcraft/sdk 2.8.0 → 3.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.
Files changed (52) hide show
  1. package/dist/modules/auth/backchannel.d.ts +13 -52
  2. package/dist/modules/auth/backchannel.d.ts.map +1 -1
  3. package/dist/modules/auth/backchannel.js +12 -147
  4. package/dist/modules/auth/backchannel.js.map +1 -1
  5. package/dist/modules/auth/middleware.d.ts +45 -185
  6. package/dist/modules/auth/middleware.d.ts.map +1 -1
  7. package/dist/modules/auth/middleware.js +40 -331
  8. package/dist/modules/auth/middleware.js.map +1 -1
  9. package/dist/modules/auth/products.d.ts +1 -1
  10. package/dist/modules/auth/products.js +1 -1
  11. package/dist/modules/auth/request-backchannel.d.ts +39 -6
  12. package/dist/modules/auth/request-backchannel.d.ts.map +1 -1
  13. package/dist/modules/auth/request-backchannel.js +15 -5
  14. package/dist/modules/auth/request-backchannel.js.map +1 -1
  15. package/dist/modules/auth/request-middleware.d.ts +267 -24
  16. package/dist/modules/auth/request-middleware.d.ts.map +1 -1
  17. package/dist/modules/auth/request-middleware.js +264 -23
  18. package/dist/modules/auth/request-middleware.js.map +1 -1
  19. package/dist/modules/auth/service-token.d.ts +8 -7
  20. package/dist/modules/auth/service-token.d.ts.map +1 -1
  21. package/dist/modules/auth/service-token.js +8 -7
  22. package/dist/modules/auth/service-token.js.map +1 -1
  23. package/dist/modules/auth/sveltekit.d.ts +1 -1
  24. package/dist/modules/auth/sveltekit.d.ts.map +1 -1
  25. package/dist/modules/auth/sveltekit.js +1 -1
  26. package/dist/modules/auth/sveltekit.js.map +1 -1
  27. package/dist/namespaces.d.ts +1 -1
  28. package/dist/server/handlers/export.js +1 -1
  29. package/dist/server/handlers/export.js.map +1 -1
  30. package/dist/server/handlers/workspace.d.ts +1 -1
  31. package/dist/server/handlers/workspace.d.ts.map +1 -1
  32. package/dist/server/handlers/workspace.js +3 -4
  33. package/dist/server/handlers/workspace.js.map +1 -1
  34. package/dist/server/index.d.ts +4 -13
  35. package/dist/server/index.d.ts.map +1 -1
  36. package/dist/server/index.js +3 -11
  37. package/dist/server/index.js.map +1 -1
  38. package/dist/server/namespace-router.d.ts +1 -1
  39. package/dist/server/namespace-router.js +1 -1
  40. package/dist/server/rpc-handler.d.ts +2 -9
  41. package/dist/server/rpc-handler.d.ts.map +1 -1
  42. package/dist/server/rpc-handler.js +2 -9
  43. package/dist/server/rpc-handler.js.map +1 -1
  44. package/docs/ADR-001-sdk-design.md +3 -3
  45. package/docs/ADR-004-product-registry.md +1 -1
  46. package/docs/ADR-005-hall-integration.md +1 -1
  47. package/docs/ADR-006-rpc-cache.md +2 -2
  48. package/docs/IMPLEMENTATION-PLAN.md +7 -7
  49. package/docs/KIT-APP-GUIDE.md +100 -99
  50. package/docs/USAGE.md +30 -40
  51. package/docs/kit-sdk-guide.md +59 -60
  52. package/package.json +1 -1
@@ -13,7 +13,7 @@ A kit app is a full-stack application powered by three things:
13
13
  ```
14
14
  @soulcraft/kits → Domain config (kit.json manifest + SKILL.md prompts)
15
15
  @soulcraft/sdk → Runtime: data, AI, files, realtime, auth, notifications
16
- Your app code → Svelte frontend + Hono/Bun backend that wires them together
16
+ Your app code → Svelte frontend + Bun/SvelteKit backend that wires them together
17
17
  ```
18
18
 
19
19
  The SDK is your single source of truth for everything the app does at runtime.
@@ -29,9 +29,15 @@ bun add @soulcraft/sdk @soulcraft/brainy @soulcraft/kits
29
29
  ```
30
30
 
31
31
  ```typescript
32
- // server.ts — minimal kit app server
33
- import { Hono } from 'hono'
34
- import { BrainyInstancePool, createSDK, createAuthMiddleware } from '@soulcraft/sdk/server'
32
+ // server.ts — minimal kit app server (Bun)
33
+ import {
34
+ BrainyInstancePool,
35
+ createSDK,
36
+ createRequestAuthMiddleware,
37
+ createRemoteSessionVerifier,
38
+ createDevSessionVerifier,
39
+ getUser,
40
+ } from '@soulcraft/sdk/server'
35
41
  import { AI_MODELS } from '@soulcraft/sdk'
36
42
 
37
43
  const pool = new BrainyInstancePool({
@@ -41,15 +47,21 @@ const pool = new BrainyInstancePool({
41
47
  maxInstances: 100,
42
48
  })
43
49
 
44
- const app = new Hono()
50
+ const verifySession = process.env.SOULCRAFT_IDP_URL
51
+ ? createRemoteSessionVerifier({ idpUrl: process.env.SOULCRAFT_IDP_URL })
52
+ : createDevSessionVerifier({ role: 'owner' })
53
+ const { requireAuth } = createRequestAuthMiddleware(verifySession)
45
54
 
46
- app.get('/api/ask', async (c) => {
47
- const brain = await pool.forUser('user-hash', 'workspace-id')
48
- const sdk = createSDK({ brain })
55
+ async function handleAsk(req: Request): Promise<Response> {
56
+ return requireAuth(req, async () => {
57
+ const user = getUser(req)!
58
+ const url = new URL(req.url)
59
+ const brain = await pool.forUser(user.emailHash, 'workspace-id')
60
+ const sdk = createSDK({ brain })
49
61
 
50
- const kit = await sdk.kits.load('your-kit-id')
51
- const response = await sdk.ai.complete({
52
- messages: [{ role: 'user', content: c.req.query('q') ?? 'Hello' }],
62
+ const kit = await sdk.kits.load('your-kit-id')
63
+ const response = await sdk.ai.complete({
64
+ messages: [{ role: 'user', content: url.searchParams.get('q') ?? 'Hello' }],
53
65
  systemPrompt: kit?.shared?.aiPersona,
54
66
  model: AI_MODELS.sonnet,
55
67
  })
@@ -67,9 +79,9 @@ export default { port: 3000, fetch: app.fetch, idleTimeout: 255 }
67
79
  Three import paths — **always use the right one**:
68
80
 
69
81
  ```typescript
70
- // 1. SERVER — Hono routes, SvelteKit +server.ts, Bun scripts, background jobs
71
- import { BrainyInstancePool, createSDK, createAuthMiddleware } from '@soulcraft/sdk/server'
72
- import type { SoulcraftSessionUser, AuthContext } from '@soulcraft/sdk'
82
+ // 1. SERVER — SvelteKit +server.ts, Bun scripts, background jobs
83
+ import { BrainyInstancePool, createSDK, createRequestAuthMiddleware, getUser } from '@soulcraft/sdk/server'
84
+ import type { SoulcraftSessionUser } from '@soulcraft/sdk'
73
85
 
74
86
  // 2. BROWSER — Svelte components, SvelteKit +page.svelte, kit frontend code
75
87
  import { createBrainyProxy, HttpTransport, WsTransport, joinHallRoom } from '@soulcraft/sdk/client'
@@ -635,44 +647,39 @@ await pool.shutdown()
635
647
 
636
648
  ## Authentication
637
649
 
638
- ### Middleware (Hono)
650
+ ### Auth Middleware (Framework-Agnostic)
639
651
 
640
652
  ```typescript
641
- import { betterAuth } from 'better-auth'
642
- import { Database } from 'bun:sqlite'
643
653
  import {
644
- SOULCRAFT_USER_FIELDS,
645
- SOULCRAFT_SESSION_CONFIG,
646
- computeEmailHash,
647
- createAuthMiddleware,
654
+ createRequestAuthMiddleware,
655
+ createRemoteSessionVerifier,
656
+ createDevSessionVerifier,
657
+ getUser,
648
658
  } from '@soulcraft/sdk/server'
649
659
 
650
- const auth = betterAuth({
651
- database: new Database('./auth.db'),
652
- secret: process.env.BETTER_AUTH_SECRET!,
653
- session: SOULCRAFT_SESSION_CONFIG,
654
- user: { additionalFields: SOULCRAFT_USER_FIELDS },
655
- databaseHooks: {
656
- user: {
657
- create: {
658
- before: async (user) => ({
659
- data: { ...user, emailHash: computeEmailHash(user.email), platformRole: 'creator' }
660
- }),
661
- },
662
- },
663
- },
664
- })
660
+ const verifySession = process.env.SOULCRAFT_IDP_URL
661
+ ? createRemoteSessionVerifier({ idpUrl: process.env.SOULCRAFT_IDP_URL })
662
+ : createDevSessionVerifier({ role: 'owner' })
665
663
 
666
- const { requireAuth, optionalAuth } = createAuthMiddleware(auth)
664
+ const { requireAuth, optionalAuth } = createRequestAuthMiddleware(verifySession)
667
665
 
668
- app.all('/api/auth/*', (c) => auth.handler(c.req.raw))
666
+ // SvelteKit hooks.server.ts:
667
+ export const handle = async ({ event, resolve }) => {
668
+ const response = await requireAuth(event.request, () => resolve(event))
669
+ event.locals.user = getUser(event.request)
670
+ return response
671
+ }
669
672
 
670
- app.get('/api/data', requireAuth, async (c) => {
671
- const user = c.get('user')! // SoulcraftSessionUser — id, email, emailHash, platformRole
672
- const brain = await pool.forUser(user.emailHash, 'main')
673
- const sdk = createSDK({ brain })
674
- // ...
675
- })
673
+ // Or in a Bun route:
674
+ async function handleData(req: Request): Promise<Response> {
675
+ return requireAuth(req, async () => {
676
+ const user = getUser(req)! // SoulcraftSessionUser — id, email, emailHash, platformRole
677
+ const brain = await pool.forUser(user.emailHash, 'main')
678
+ const sdk = createSDK({ brain })
679
+ // ...
680
+ return new Response(JSON.stringify({ ok: true }))
681
+ })
682
+ }
676
683
  ```
677
684
 
678
685
  ### Capability Tokens (Cross-Product Server Calls)
@@ -766,16 +773,13 @@ await sdk.versions.restore('product-lavender-soy', 3)
766
773
  A complete kit app server combining auth, data, AI, and events:
767
774
 
768
775
  ```typescript
769
- import { Hono } from 'hono'
770
- import { betterAuth } from 'better-auth'
771
- import { Database } from 'bun:sqlite'
772
776
  import {
773
777
  BrainyInstancePool,
774
778
  createSDK,
775
- createAuthMiddleware,
776
- SOULCRAFT_USER_FIELDS,
777
- SOULCRAFT_SESSION_CONFIG,
778
- computeEmailHash,
779
+ createRequestAuthMiddleware,
780
+ createRemoteSessionVerifier,
781
+ createDevSessionVerifier,
782
+ getUser,
779
783
  } from '@soulcraft/sdk/server'
780
784
  import { AI_MODELS } from '@soulcraft/sdk'
781
785
 
@@ -785,23 +789,11 @@ const KIT_ID = 'your-kit-id'
785
789
 
786
790
  // ── Auth ──────────────────────────────────────────────────────────────────────
787
791
 
788
- const auth = betterAuth({
789
- database: new Database('./auth.db'),
790
- secret: process.env.BETTER_AUTH_SECRET!,
791
- session: SOULCRAFT_SESSION_CONFIG,
792
- user: { additionalFields: SOULCRAFT_USER_FIELDS },
793
- databaseHooks: {
794
- user: {
795
- create: {
796
- before: async (u) => ({
797
- data: { ...u, emailHash: computeEmailHash(u.email), platformRole: 'creator' },
798
- }),
799
- },
800
- },
801
- },
802
- })
792
+ const verifySession = process.env.SOULCRAFT_IDP_URL
793
+ ? createRemoteSessionVerifier({ idpUrl: process.env.SOULCRAFT_IDP_URL })
794
+ : createDevSessionVerifier({ role: 'owner' })
803
795
 
804
- const { requireAuth } = createAuthMiddleware(auth)
796
+ const { requireAuth } = createRequestAuthMiddleware(verifySession)
805
797
 
806
798
  // ── Brainy pool ───────────────────────────────────────────────────────────────
807
799
 
@@ -813,54 +805,63 @@ const pool = new BrainyInstancePool({
813
805
  flushOnEvict: true,
814
806
  })
815
807
 
816
- // ── App ───────────────────────────────────────────────────────────────────────
808
+ // ── Route handlers ────────────────────────────────────────────────────────────
817
809
 
818
- const app = new Hono()
810
+ async function handleItems(req: Request): Promise<Response> {
811
+ return requireAuth(req, async () => {
812
+ const user = getUser(req)!
813
+ const brain = await pool.forUser(user.emailHash, 'main')
814
+ const sdk = createSDK({ brain })
819
815
 
820
- app.all('/api/auth/*', (c) => auth.handler(c.req.raw))
821
-
822
- app.get('/api/items', requireAuth, async (c) => {
823
- const user = c.get('user')!
824
- const brain = await pool.forUser(user.emailHash, 'main')
825
- const sdk = createSDK({ brain })
816
+ const items = await sdk.brainy.find({
817
+ query: 'all items',
818
+ limit: 100,
819
+ })
826
820
 
827
- const items = await sdk.brainy.find({
828
- query: 'all items',
829
- limit: 100,
821
+ return new Response(JSON.stringify({ items }), {
822
+ headers: { 'Content-Type': 'application/json' },
823
+ })
830
824
  })
825
+ }
831
826
 
832
- return c.json({ items })
833
- })
827
+ async function handleAsk(req: Request): Promise<Response> {
828
+ return requireAuth(req, async () => {
829
+ const user = getUser(req)!
830
+ const { question } = await req.json() as { question: string }
834
831
 
835
- app.post('/api/ask', requireAuth, async (c) => {
836
- const user = c.get('user')!
837
- const { question } = await c.req.json<{ question: string }>()
832
+ const brain = await pool.forUser(user.emailHash, 'main')
833
+ const sdk = createSDK({ brain })
838
834
 
839
- const brain = await pool.forUser(user.emailHash, 'main')
840
- const sdk = createSDK({ brain })
835
+ const kit = await sdk.kits.load(KIT_ID)
836
+ const skills = await sdk.skills.list({ kitId: KIT_ID })
841
837
 
842
- const kit = await sdk.kits.load(KIT_ID)
843
- const skills = await sdk.skills.list({ kitId: KIT_ID })
838
+ const systemPrompt = [
839
+ kit?.shared?.aiPersona,
840
+ ...skills.map(s => s.content),
841
+ ].filter(Boolean).join('\n\n---\n\n')
844
842
 
845
- const systemPrompt = [
846
- kit?.shared?.aiPersona,
847
- ...skills.map(s => s.content),
848
- ].filter(Boolean).join('\n\n---\n\n')
843
+ const response = await sdk.ai.complete({
844
+ messages: [{ role: 'user', content: question }],
845
+ systemPrompt,
846
+ model: AI_MODELS.sonnet,
847
+ })
849
848
 
850
- const response = await sdk.ai.complete({
851
- messages: [{ role: 'user', content: question }],
852
- systemPrompt,
853
- model: AI_MODELS.sonnet,
849
+ return new Response(JSON.stringify({ answer: response.text }), {
850
+ headers: { 'Content-Type': 'application/json' },
851
+ })
854
852
  })
855
-
856
- return c.json({ answer: response.text })
857
- })
853
+ }
858
854
 
859
855
  // ── Server ────────────────────────────────────────────────────────────────────
860
856
 
861
857
  export default {
862
858
  port: Number(process.env.PORT ?? 3000),
863
- fetch: app.fetch,
859
+ fetch(req: Request): Promise<Response> | Response {
860
+ const url = new URL(req.url)
861
+ if (url.pathname === '/api/items') return handleItems(req)
862
+ if (url.pathname === '/api/ask' && req.method === 'POST') return handleAsk(req)
863
+ return new Response('Not found', { status: 404 })
864
+ },
864
865
  idleTimeout: 255, // CRITICAL: prevents Bun's 10s default from killing long Brainy inits
865
866
  }
866
867
  ```
package/docs/USAGE.md CHANGED
@@ -4,7 +4,7 @@ This guide is for engineers, AI assistants, kit developers, and anyone building
4
4
  the Soulcraft platform. It covers every implemented module with working examples.
5
5
 
6
6
  **Three rules to remember:**
7
- 1. Server code (Hono, SvelteKit routes, Bun backends) imports from `@soulcraft/sdk/server`
7
+ 1. Server code (SvelteKit routes, Bun backends) imports from `@soulcraft/sdk/server`
8
8
  2. Browser code (kit apps, Svelte components) imports from `@soulcraft/sdk/client`
9
9
  3. Shared types import from `@soulcraft/sdk`
10
10
 
@@ -512,49 +512,39 @@ console.log(claims.exp) // expiry timestamp (ms)
512
512
 
513
513
  ## Auth Middleware
514
514
 
515
- The SDK provides Hono middleware that resolves better-auth sessions and injects the
516
- typed user into request context.
515
+ The SDK provides framework-agnostic auth middleware using Web Standard
516
+ Request/Response. Works with SvelteKit, Bun.serve, Deno, and any server.
517
517
 
518
518
  ```typescript
519
- import { betterAuth } from 'better-auth'
520
519
  import {
521
- SOULCRAFT_USER_FIELDS,
522
- SOULCRAFT_SESSION_CONFIG,
523
- computeEmailHash,
524
- createAuthMiddleware,
520
+ createRequestAuthMiddleware,
521
+ createRemoteSessionVerifier,
522
+ createDevSessionVerifier,
523
+ getUser,
525
524
  } from '@soulcraft/sdk/server'
526
- import type { AuthContext } from '@soulcraft/sdk/server'
527
-
528
- // 1. Configure better-auth with Soulcraft fields:
529
- const auth = betterAuth({
530
- database: new Database('./auth.db'),
531
- secret: process.env.BETTER_AUTH_SECRET!,
532
- session: SOULCRAFT_SESSION_CONFIG, // 30-day sessions, 24h refresh
533
- user: { additionalFields: SOULCRAFT_USER_FIELDS },
534
- databaseHooks: {
535
- user: {
536
- create: {
537
- before: async (user) => ({
538
- data: { ...user, emailHash: computeEmailHash(user.email), platformRole: 'creator' }
539
- })
540
- }
541
- }
542
- },
543
- })
544
-
545
- // 2. Create middleware:
546
- const { requireAuth, optionalAuth } = createAuthMiddleware(auth)
547
525
 
548
- // 3. Use in routes:
549
- app.all('/api/auth/*', (c) => auth.handler(c.req.raw))
526
+ // 1. Create a session verifier:
527
+ const verifySession = process.env.SOULCRAFT_IDP_URL
528
+ ? createRemoteSessionVerifier({ idpUrl: process.env.SOULCRAFT_IDP_URL })
529
+ : createDevSessionVerifier({ role: 'owner' })
550
530
 
551
- app.get('/api/data', requireAuth, async (c) => {
552
- const user = c.get('user')! // SoulcraftSessionUser — always non-null after requireAuth
553
- // user.id, user.email, user.emailHash, user.platformRole
554
- })
531
+ // 2. Create middleware:
532
+ const { requireAuth, optionalAuth } = createRequestAuthMiddleware(verifySession)
533
+
534
+ // 3. Use in routes (SvelteKit example):
535
+ // hooks.server.ts
536
+ export const handle = async ({ event, resolve }) => {
537
+ const response = await requireAuth(event.request, () => resolve(event))
538
+ event.locals.user = getUser(event.request)
539
+ return response
540
+ }
555
541
 
556
- app.get('/api/public', optionalAuth, async (c) => {
557
- const user = c.get('user') // SoulcraftSessionUser | null
542
+ // 4. Use in routes (Bun example):
543
+ Bun.serve({
544
+ fetch: (req) => optionalAuth(req, async () => {
545
+ const user = getUser(req) // SoulcraftSessionUser | null
546
+ return new Response(JSON.stringify({ user: user?.email ?? 'anonymous' }))
547
+ }),
558
548
  })
559
549
  ```
560
550
 
@@ -810,9 +800,9 @@ When helping implement Soulcraft server code, follow this checklist:
810
800
 
811
801
  **1. Import correctly:**
812
802
  ```typescript
813
- // Server code (Hono, SvelteKit server routes, Bun scripts):
814
- import { BrainyInstancePool, createSDK, createAuthMiddleware, computeEmailHash } from '@soulcraft/sdk/server'
815
- import type { SoulcraftSessionUser, AuthContext } from '@soulcraft/sdk'
803
+ // Server code (SvelteKit server routes, Bun scripts):
804
+ import { BrainyInstancePool, createRequestAuthMiddleware, computeEmailHash, getUser } from '@soulcraft/sdk/server'
805
+ import type { SoulcraftSessionUser } from '@soulcraft/sdk'
816
806
 
817
807
  // Shared types only:
818
808
  import { AI_MODELS } from '@soulcraft/sdk'
@@ -32,10 +32,10 @@ Install the SDK in your server application:
32
32
  bun add @soulcraft/sdk @soulcraft/brainy
33
33
  ```
34
34
 
35
- For server-side use (Node.js, Bun, Hono, SvelteKit server routes):
35
+ For server-side use (Node.js, Bun, SvelteKit server routes):
36
36
 
37
37
  ```typescript
38
- import { BrainyInstancePool, createSDK, createAuthMiddleware } from '@soulcraft/sdk/server'
38
+ import { BrainyInstancePool, createSDK, createRequestAuthMiddleware, getUser } from '@soulcraft/sdk/server'
39
39
  import type { SoulcraftSessionUser } from '@soulcraft/sdk'
40
40
  ```
41
41
 
@@ -348,16 +348,13 @@ if (!claims) return c.json({ error: 'Unauthorized' }, 401)
348
348
  A minimal kit application combining auth, Brainy, and AI:
349
349
 
350
350
  ```typescript
351
- import { Hono } from 'hono'
352
- import { betterAuth } from 'better-auth'
353
- import { Database } from 'bun:sqlite'
354
351
  import {
355
352
  BrainyInstancePool,
356
353
  createSDK,
357
- createAuthMiddleware,
358
- SOULCRAFT_USER_FIELDS,
359
- SOULCRAFT_SESSION_CONFIG,
360
- computeEmailHash,
354
+ createRequestAuthMiddleware,
355
+ createRemoteSessionVerifier,
356
+ createDevSessionVerifier,
357
+ getUser,
361
358
  } from '@soulcraft/sdk/server'
362
359
  import { AI_MODELS } from '@soulcraft/sdk'
363
360
  import { kitRegistry } from '@soulcraft/kits'
@@ -366,22 +363,10 @@ import { kitRegistry } from '@soulcraft/kits'
366
363
  const kit = kitRegistry['wicks-and-whiskers']
367
364
 
368
365
  // ── Auth ──────────────────────────────────────────────────────────────────────
369
- const auth = betterAuth({
370
- database: new Database('./auth.db'),
371
- secret: process.env.BETTER_AUTH_SECRET!,
372
- session: SOULCRAFT_SESSION_CONFIG,
373
- user: { additionalFields: SOULCRAFT_USER_FIELDS },
374
- databaseHooks: {
375
- user: {
376
- create: {
377
- before: async (u) => ({
378
- data: { ...u, emailHash: computeEmailHash(u.email), platformRole: 'creator' }
379
- })
380
- }
381
- }
382
- },
383
- })
384
- const { requireAuth } = createAuthMiddleware(auth)
366
+ const verifySession = process.env.SOULCRAFT_IDP_URL
367
+ ? createRemoteSessionVerifier({ idpUrl: process.env.SOULCRAFT_IDP_URL })
368
+ : createDevSessionVerifier({ role: 'owner' })
369
+ const { requireAuth } = createRequestAuthMiddleware(verifySession)
385
370
 
386
371
  // ── Brainy pool ───────────────────────────────────────────────────────────────
387
372
  const pool = new BrainyInstancePool({
@@ -391,48 +376,62 @@ const pool = new BrainyInstancePool({
391
376
  maxInstances: 100,
392
377
  })
393
378
 
394
- // ── Hono app ──────────────────────────────────────────────────────────────────
395
- const app = new Hono()
379
+ // ── Route handlers ────────────────────────────────────────────────────────────
396
380
 
397
- app.all('/api/auth/*', (c) => auth.handler(c.req.raw))
381
+ async function handleInventory(req: Request): Promise<Response> {
382
+ return requireAuth(req, async () => {
383
+ const user = getUser(req)!
384
+ const brain = await pool.forUser(user.emailHash, 'main')
385
+ const sdk = createSDK({ brain })
398
386
 
399
- app.get('/api/inventory', requireAuth, async (c) => {
400
- const user = c.get('user')!
401
- const brain = await pool.forUser(user.emailHash, 'main')
402
- const sdk = createSDK({ brain })
387
+ const items = await sdk.brainy.find({
388
+ query: 'inventory items in stock',
389
+ type: 'Product',
390
+ limit: 50,
391
+ })
403
392
 
404
- const items = await sdk.brainy.find({
405
- query: 'inventory items in stock',
406
- type: 'Product',
407
- limit: 50,
393
+ return new Response(JSON.stringify({ kit: kit.name, items }), {
394
+ headers: { 'Content-Type': 'application/json' },
395
+ })
408
396
  })
397
+ }
409
398
 
410
- return c.json({ kit: kit.name, items })
411
- })
412
-
413
- app.post('/api/ask', requireAuth, async (c) => {
414
- const user = c.get('user')!
415
- const { question } = await c.req.json<{ question: string }>()
416
-
417
- const brain = await pool.forUser(user.emailHash, 'main')
418
- const sdk = createSDK({ brain })
419
-
420
- const skills = await sdk.skills.list({ kitId: 'wicks-and-whiskers' })
421
- const systemPrompt = [
422
- kit.shared.aiPersona,
423
- ...skills.map(s => s.content),
424
- ].join('\n\n')
425
-
426
- const response = await sdk.ai.complete({
427
- messages: [{ role: 'user', content: question }],
428
- systemPrompt,
429
- model: AI_MODELS.haiku,
399
+ async function handleAsk(req: Request): Promise<Response> {
400
+ return requireAuth(req, async () => {
401
+ const user = getUser(req)!
402
+ const { question } = await req.json() as { question: string }
403
+
404
+ const brain = await pool.forUser(user.emailHash, 'main')
405
+ const sdk = createSDK({ brain })
406
+
407
+ const skills = await sdk.skills.list({ kitId: 'wicks-and-whiskers' })
408
+ const systemPrompt = [
409
+ kit.shared.aiPersona,
410
+ ...skills.map(s => s.content),
411
+ ].join('\n\n')
412
+
413
+ const response = await sdk.ai.complete({
414
+ messages: [{ role: 'user', content: question }],
415
+ systemPrompt,
416
+ model: AI_MODELS.haiku,
417
+ })
418
+
419
+ return new Response(JSON.stringify({ answer: response.text }), {
420
+ headers: { 'Content-Type': 'application/json' },
421
+ })
430
422
  })
423
+ }
431
424
 
432
- return c.json({ answer: response.text })
433
- })
434
-
435
- export default app
425
+ // ── Bun server ────────────────────────────────────────────────────────────────
426
+ export default {
427
+ port: Number(process.env.PORT ?? 3000),
428
+ fetch(req: Request) {
429
+ const url = new URL(req.url)
430
+ if (url.pathname === '/api/inventory') return handleInventory(req)
431
+ if (url.pathname === '/api/ask' && req.method === 'POST') return handleAsk(req)
432
+ return new Response('Not found', { status: 404 })
433
+ },
434
+ }
436
435
  ```
437
436
 
438
437
  ---
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@soulcraft/sdk",
3
- "version": "2.8.0",
3
+ "version": "3.0.0",
4
4
  "description": "The unified Soulcraft platform SDK — data, auth, AI, billing, and notifications",
5
5
  "type": "module",
6
6
  "publishConfig": {