@soulcraft/sdk 2.6.1 → 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.
- package/dist/modules/auth/backchannel.d.ts +13 -39
- package/dist/modules/auth/backchannel.d.ts.map +1 -1
- package/dist/modules/auth/backchannel.js +12 -144
- package/dist/modules/auth/backchannel.js.map +1 -1
- package/dist/modules/auth/middleware.d.ts +45 -157
- package/dist/modules/auth/middleware.d.ts.map +1 -1
- package/dist/modules/auth/middleware.js +40 -322
- package/dist/modules/auth/middleware.js.map +1 -1
- package/dist/modules/auth/products.d.ts +1 -1
- package/dist/modules/auth/products.js +1 -1
- package/dist/modules/auth/request-backchannel.d.ts +94 -0
- package/dist/modules/auth/request-backchannel.d.ts.map +1 -0
- package/dist/modules/auth/request-backchannel.js +206 -0
- package/dist/modules/auth/request-backchannel.js.map +1 -0
- package/dist/modules/auth/request-middleware.d.ts +438 -0
- package/dist/modules/auth/request-middleware.d.ts.map +1 -0
- package/dist/modules/auth/request-middleware.js +650 -0
- package/dist/modules/auth/request-middleware.js.map +1 -0
- package/dist/modules/auth/service-token.d.ts +8 -7
- package/dist/modules/auth/service-token.d.ts.map +1 -1
- package/dist/modules/auth/service-token.js +8 -7
- package/dist/modules/auth/service-token.js.map +1 -1
- package/dist/modules/auth/sveltekit.d.ts +1 -1
- package/dist/modules/auth/sveltekit.d.ts.map +1 -1
- package/dist/modules/auth/sveltekit.js +1 -1
- package/dist/modules/auth/sveltekit.js.map +1 -1
- package/dist/namespaces.d.ts +1 -1
- package/dist/server/handlers/export.js +1 -1
- package/dist/server/handlers/export.js.map +1 -1
- package/dist/server/handlers/workspace.d.ts +1 -1
- package/dist/server/handlers/workspace.d.ts.map +1 -1
- package/dist/server/handlers/workspace.js +3 -4
- package/dist/server/handlers/workspace.js.map +1 -1
- package/dist/server/index.d.ts +5 -12
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +4 -9
- package/dist/server/index.js.map +1 -1
- package/dist/server/instance-pool.d.ts.map +1 -1
- package/dist/server/instance-pool.js +1 -0
- package/dist/server/instance-pool.js.map +1 -1
- package/dist/server/namespace-router.d.ts +1 -1
- package/dist/server/namespace-router.js +1 -1
- package/dist/server/rpc-handler.d.ts +2 -9
- package/dist/server/rpc-handler.d.ts.map +1 -1
- package/dist/server/rpc-handler.js +2 -9
- package/dist/server/rpc-handler.js.map +1 -1
- package/docs/ADR-001-sdk-design.md +3 -3
- package/docs/ADR-004-product-registry.md +1 -1
- package/docs/ADR-005-hall-integration.md +1 -1
- package/docs/ADR-006-rpc-cache.md +2 -2
- package/docs/IMPLEMENTATION-PLAN.md +7 -7
- package/docs/KIT-APP-GUIDE.md +100 -99
- package/docs/USAGE.md +30 -40
- package/docs/kit-sdk-guide.md +59 -60
- package/package.json +2 -7
- package/dist/server/hono-router.d.ts +0 -70
- package/dist/server/hono-router.d.ts.map +0 -1
- package/dist/server/hono-router.js +0 -167
- package/dist/server/hono-router.js.map +0 -1
|
@@ -224,7 +224,7 @@ class BrainyInstancePool {
|
|
|
224
224
|
Migrated from `brainy-client/src/server/`:
|
|
225
225
|
|
|
226
226
|
```typescript
|
|
227
|
-
//
|
|
227
|
+
// Framework-agnostic HTTP RPC handler:
|
|
228
228
|
createBrainyHandler(config: BrainyHandlerConfig): (c: Context) => Promise<Response>
|
|
229
229
|
|
|
230
230
|
// Bun WebSocket handler:
|
|
@@ -298,9 +298,9 @@ Includes: OIDC client plugin (`genericOAuth`), PKCE, `crossSubDomainCookies`,
|
|
|
298
298
|
`additionalFields` (platformRole + emailHash), `databaseHooks.user.create.before`
|
|
299
299
|
(computes emailHash, sets defaultRole).
|
|
300
300
|
|
|
301
|
-
#### `src/modules/auth/middleware.ts`
|
|
301
|
+
#### `src/modules/auth/request-middleware.ts`
|
|
302
302
|
```typescript
|
|
303
|
-
//
|
|
303
|
+
// Auth middleware:
|
|
304
304
|
createAuthMiddleware(auth: BetterAuth): MiddlewareHandler
|
|
305
305
|
requireAuth(auth: BetterAuth): MiddlewareHandler
|
|
306
306
|
optionalAuth(auth: BetterAuth): MiddlewareHandler
|
|
@@ -316,9 +316,9 @@ createRemoteSessionVerifier(options: {
|
|
|
316
316
|
}): (cookieHeader: string) => Promise<SoulcraftSession | null>
|
|
317
317
|
```
|
|
318
318
|
|
|
319
|
-
#### `src/modules/auth/backchannel.ts`
|
|
319
|
+
#### `src/modules/auth/request-backchannel.ts`
|
|
320
320
|
```typescript
|
|
321
|
-
//
|
|
321
|
+
// Request handler for POST /api/auth/backchannel-logout:
|
|
322
322
|
createBackchannelLogoutHandler(options: {
|
|
323
323
|
auth: BetterAuth
|
|
324
324
|
clientSecret: string
|
|
@@ -428,7 +428,7 @@ From `chat/ui-actions.ts`:
|
|
|
428
428
|
#### `src/modules/ai/companion.ts`
|
|
429
429
|
From `routes/ai.ts`:
|
|
430
430
|
- `AiPersona` type — name, description, systemPrompt, voice, etc.
|
|
431
|
-
- `createAiHandler(options)` —
|
|
431
|
+
- `createAiHandler(options)` — request handler factory for `/api/ai/*`
|
|
432
432
|
- `AiGenerateRequest`, `AiChatRequest`, `AiChatResponse` types
|
|
433
433
|
- Max tokens: 1024 default, 2048 ceiling
|
|
434
434
|
- Stateless generate + session-based chat endpoints
|
|
@@ -467,7 +467,7 @@ class PlatformEventBus extends EventEmitter {
|
|
|
467
467
|
createEventBus(): PlatformEventBus
|
|
468
468
|
```
|
|
469
469
|
|
|
470
|
-
SSE stream factory (for
|
|
470
|
+
SSE stream factory (for server endpoints):
|
|
471
471
|
```typescript
|
|
472
472
|
createSSEStream(options: {
|
|
473
473
|
bus: PlatformEventBus
|
package/docs/KIT-APP-GUIDE.md
CHANGED
|
@@ -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 +
|
|
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 {
|
|
34
|
-
|
|
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
|
|
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
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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
|
-
|
|
51
|
-
|
|
52
|
-
|
|
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 —
|
|
71
|
-
import { BrainyInstancePool, createSDK,
|
|
72
|
-
import type { SoulcraftSessionUser
|
|
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 (
|
|
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
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
654
|
+
createRequestAuthMiddleware,
|
|
655
|
+
createRemoteSessionVerifier,
|
|
656
|
+
createDevSessionVerifier,
|
|
657
|
+
getUser,
|
|
648
658
|
} from '@soulcraft/sdk/server'
|
|
649
659
|
|
|
650
|
-
const
|
|
651
|
-
|
|
652
|
-
|
|
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 } =
|
|
664
|
+
const { requireAuth, optionalAuth } = createRequestAuthMiddleware(verifySession)
|
|
667
665
|
|
|
668
|
-
|
|
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
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
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
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
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
|
|
789
|
-
|
|
790
|
-
|
|
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 } =
|
|
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
|
-
// ──
|
|
808
|
+
// ── Route handlers ────────────────────────────────────────────────────────────
|
|
817
809
|
|
|
818
|
-
|
|
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
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
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
|
-
|
|
828
|
-
|
|
829
|
-
|
|
821
|
+
return new Response(JSON.stringify({ items }), {
|
|
822
|
+
headers: { 'Content-Type': 'application/json' },
|
|
823
|
+
})
|
|
830
824
|
})
|
|
825
|
+
}
|
|
831
826
|
|
|
832
|
-
|
|
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
|
-
|
|
836
|
-
|
|
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
|
-
|
|
840
|
-
|
|
835
|
+
const kit = await sdk.kits.load(KIT_ID)
|
|
836
|
+
const skills = await sdk.skills.list({ kitId: KIT_ID })
|
|
841
837
|
|
|
842
|
-
|
|
843
|
-
|
|
838
|
+
const systemPrompt = [
|
|
839
|
+
kit?.shared?.aiPersona,
|
|
840
|
+
...skills.map(s => s.content),
|
|
841
|
+
].filter(Boolean).join('\n\n---\n\n')
|
|
844
842
|
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
843
|
+
const response = await sdk.ai.complete({
|
|
844
|
+
messages: [{ role: 'user', content: question }],
|
|
845
|
+
systemPrompt,
|
|
846
|
+
model: AI_MODELS.sonnet,
|
|
847
|
+
})
|
|
849
848
|
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
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:
|
|
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 (
|
|
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
|
|
516
|
-
|
|
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
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
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
|
-
//
|
|
549
|
-
|
|
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
|
-
|
|
552
|
-
|
|
553
|
-
|
|
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
|
-
|
|
557
|
-
|
|
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 (
|
|
814
|
-
import { BrainyInstancePool,
|
|
815
|
-
import type { SoulcraftSessionUser
|
|
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'
|
package/docs/kit-sdk-guide.md
CHANGED
|
@@ -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,
|
|
35
|
+
For server-side use (Node.js, Bun, SvelteKit server routes):
|
|
36
36
|
|
|
37
37
|
```typescript
|
|
38
|
-
import { BrainyInstancePool, createSDK,
|
|
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
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
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
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
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
|
-
// ──
|
|
395
|
-
const app = new Hono()
|
|
379
|
+
// ── Route handlers ────────────────────────────────────────────────────────────
|
|
396
380
|
|
|
397
|
-
|
|
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
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
387
|
+
const items = await sdk.brainy.find({
|
|
388
|
+
query: 'inventory items in stock',
|
|
389
|
+
type: 'Product',
|
|
390
|
+
limit: 50,
|
|
391
|
+
})
|
|
403
392
|
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
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
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
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
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
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": "
|
|
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": {
|
|
@@ -36,12 +36,11 @@
|
|
|
36
36
|
"publish:npm": "npm publish --access restricted"
|
|
37
37
|
},
|
|
38
38
|
"peerDependencies": {
|
|
39
|
-
"@soulcraft/brainy": ">=7.
|
|
39
|
+
"@soulcraft/brainy": ">=7.19.11",
|
|
40
40
|
"@soulcraft/cortex": ">=2.1.5",
|
|
41
41
|
"@soulcraft/kit-schema": ">=2.0.0",
|
|
42
42
|
"@soulcraft/kits": ">=1.0.0",
|
|
43
43
|
"better-auth": ">=1.0.0",
|
|
44
|
-
"hono": ">=4.0.0",
|
|
45
44
|
"stripe": ">=20.0.0"
|
|
46
45
|
},
|
|
47
46
|
"peerDependenciesMeta": {
|
|
@@ -62,9 +61,6 @@
|
|
|
62
61
|
},
|
|
63
62
|
"stripe": {
|
|
64
63
|
"optional": true
|
|
65
|
-
},
|
|
66
|
-
"hono": {
|
|
67
|
-
"optional": true
|
|
68
64
|
}
|
|
69
65
|
},
|
|
70
66
|
"dependencies": {
|
|
@@ -78,7 +74,6 @@
|
|
|
78
74
|
},
|
|
79
75
|
"devDependencies": {
|
|
80
76
|
"@types/node": "^22.0.0",
|
|
81
|
-
"hono": "^4.12.3",
|
|
82
77
|
"typescript": "^5.7.0",
|
|
83
78
|
"vitest": "^3.0.0"
|
|
84
79
|
}
|