@soulcraft/sdk 2.4.1 → 2.6.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/sveltekit.d.ts +208 -0
- package/dist/modules/auth/sveltekit.d.ts.map +1 -0
- package/dist/modules/auth/sveltekit.js +263 -0
- package/dist/modules/auth/sveltekit.js.map +1 -0
- package/dist/server/index.d.ts +24 -13
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +25 -14
- package/dist/server/index.js.map +1 -1
- package/dist/server/rpc-handler.d.ts +79 -0
- package/dist/server/rpc-handler.d.ts.map +1 -0
- package/dist/server/rpc-handler.js +185 -0
- package/dist/server/rpc-handler.js.map +1 -0
- package/package.json +5 -1
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module modules/auth/sveltekit
|
|
3
|
+
* @description Opinionated SvelteKit auth integration for Soulcraft products.
|
|
4
|
+
*
|
|
5
|
+
* `createSoulcraftAuth()` returns everything a SvelteKit product needs for auth:
|
|
6
|
+
* a `Handle` hook, a backchannel-logout request handler, and a logout request handler.
|
|
7
|
+
* One function, zero choices.
|
|
8
|
+
*
|
|
9
|
+
* ## What it does
|
|
10
|
+
*
|
|
11
|
+
* - **Session resolution** — reads the IdP cross-domain cookie, verifies via
|
|
12
|
+
* `createRemoteSessionVerifier` (30s LRU cache) in production or
|
|
13
|
+
* `createDevCookieVerifier` in dev mode
|
|
14
|
+
* - **Stale cookie recovery** — detects "cookie present but session null" and
|
|
15
|
+
* clears the stale cookie via `Set-Cookie: Max-Age=0`, breaking redirect loops
|
|
16
|
+
* - **CSRF bypass** — rewrites the `origin` header for `POST /api/auth/backchannel-logout`
|
|
17
|
+
* so SvelteKit's built-in CSRF check doesn't block server-to-server IdP calls
|
|
18
|
+
* - **User enrichment** — optional `enrichUser` callback for product-specific
|
|
19
|
+
* role resolution (e.g. Venue staff lookup, Portal admin check)
|
|
20
|
+
* - **Backchannel logout** — verifies the HS256 JWT logout token from the IdP
|
|
21
|
+
* - **Logout** — clears local cookies and returns the IdP end-session URL
|
|
22
|
+
*
|
|
23
|
+
* ## Usage
|
|
24
|
+
*
|
|
25
|
+
* ```typescript
|
|
26
|
+
* // hooks.server.ts
|
|
27
|
+
* import { createSoulcraftAuth } from '@soulcraft/sdk/server'
|
|
28
|
+
*
|
|
29
|
+
* const auth = createSoulcraftAuth({ product: 'venue' })
|
|
30
|
+
* export const handle = auth.handle
|
|
31
|
+
*
|
|
32
|
+
* // routes/api/auth/backchannel-logout/+server.ts
|
|
33
|
+
* export const POST = auth.backchannelHandler
|
|
34
|
+
*
|
|
35
|
+
* // routes/api/auth/logout/+server.ts
|
|
36
|
+
* export const POST = auth.logoutHandler
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* @example With user enrichment (Venue staff role)
|
|
40
|
+
* ```typescript
|
|
41
|
+
* const auth = createSoulcraftAuth({
|
|
42
|
+
* product: 'venue',
|
|
43
|
+
* enrichUser: async (user, event) => {
|
|
44
|
+
* const staff = await lookupStaff(event.locals.brain, user.id)
|
|
45
|
+
* return { ...user, role: staff?.role ?? 'customer' }
|
|
46
|
+
* }
|
|
47
|
+
* })
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
import type { SessionVerifier } from './middleware.js';
|
|
51
|
+
import type { SoulcraftSessionUser } from './types.js';
|
|
52
|
+
/**
|
|
53
|
+
* Minimal SvelteKit RequestEvent shape. Structurally compatible with
|
|
54
|
+
* `@sveltejs/kit`'s `RequestEvent` without requiring it as a dependency.
|
|
55
|
+
*/
|
|
56
|
+
export interface SvelteKitEvent {
|
|
57
|
+
request: Request;
|
|
58
|
+
url: URL;
|
|
59
|
+
locals: Record<string, unknown>;
|
|
60
|
+
cookies: {
|
|
61
|
+
delete(name: string, opts?: {
|
|
62
|
+
path?: string;
|
|
63
|
+
}): void;
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Minimal SvelteKit Handle function shape. Structurally compatible with
|
|
68
|
+
* `@sveltejs/kit`'s `Handle` type.
|
|
69
|
+
*/
|
|
70
|
+
export type SvelteKitHandle = (input: {
|
|
71
|
+
event: SvelteKitEvent;
|
|
72
|
+
resolve: (event: SvelteKitEvent) => Promise<Response>;
|
|
73
|
+
}) => Promise<Response>;
|
|
74
|
+
/**
|
|
75
|
+
* Minimal SvelteKit RequestHandler shape for `+server.ts` exports.
|
|
76
|
+
*/
|
|
77
|
+
export type SvelteKitRequestHandler = (event: SvelteKitEvent) => Promise<Response>;
|
|
78
|
+
/**
|
|
79
|
+
* @description Configuration for `createSoulcraftAuth()`.
|
|
80
|
+
*/
|
|
81
|
+
export interface SoulcraftAuthOptions {
|
|
82
|
+
/**
|
|
83
|
+
* The product identifier. Used as the OIDC `client_id` when building the
|
|
84
|
+
* IdP end-session URL for logout. Also used as the default for
|
|
85
|
+
* `SOULCRAFT_OIDC_CLIENT_ID` when the env var is not set.
|
|
86
|
+
*/
|
|
87
|
+
product: string;
|
|
88
|
+
/**
|
|
89
|
+
* Optional session verifier override. When omitted, the verifier is
|
|
90
|
+
* auto-selected based on environment:
|
|
91
|
+
* - `SOULCRAFT_IDP_URL` set → `createRemoteSessionVerifier`
|
|
92
|
+
* - `SOULCRAFT_IDP_URL` unset → `createDevCookieVerifier`
|
|
93
|
+
*/
|
|
94
|
+
verifier?: SessionVerifier;
|
|
95
|
+
/**
|
|
96
|
+
* Optional callback to enrich the user object with product-specific fields
|
|
97
|
+
* after session resolution. Called on every authenticated request.
|
|
98
|
+
*
|
|
99
|
+
* The returned object replaces `event.locals.user`. Return the original
|
|
100
|
+
* user (or a superset) — never return null.
|
|
101
|
+
*
|
|
102
|
+
* @param user - The resolved `SoulcraftSessionUser` from the IdP.
|
|
103
|
+
* @param event - The SvelteKit request event (access `locals`, `url`, etc.).
|
|
104
|
+
* @returns The enriched user object to store in `event.locals.user`.
|
|
105
|
+
*
|
|
106
|
+
* @example Venue staff role lookup
|
|
107
|
+
* ```typescript
|
|
108
|
+
* enrichUser: async (user, event) => {
|
|
109
|
+
* const staff = await findStaffByAuthId(event.locals.brain, user.id)
|
|
110
|
+
* return { ...user, role: staff?.role ?? 'customer' }
|
|
111
|
+
* }
|
|
112
|
+
* ```
|
|
113
|
+
*/
|
|
114
|
+
enrichUser?: (user: SoulcraftSessionUser, event: SvelteKitEvent) => Promise<Record<string, unknown>> | Record<string, unknown>;
|
|
115
|
+
/**
|
|
116
|
+
* Name of the dev session cookie. Must match the cookie name used by
|
|
117
|
+
* `/api/dev/login` in the product. Default: `'soulcraft_dev_session'`.
|
|
118
|
+
*/
|
|
119
|
+
devCookieName?: string;
|
|
120
|
+
/**
|
|
121
|
+
* Path prefix for the backchannel-logout endpoint. The CSRF bypass
|
|
122
|
+
* rewrites the origin header for POST requests to this path.
|
|
123
|
+
* Default: `'/api/auth/backchannel-logout'`.
|
|
124
|
+
*/
|
|
125
|
+
backchannelPath?: string;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* @description The return value of `createSoulcraftAuth()`.
|
|
129
|
+
*/
|
|
130
|
+
export interface SoulcraftAuth {
|
|
131
|
+
/**
|
|
132
|
+
* SvelteKit `Handle` hook that resolves sessions, clears stale cookies,
|
|
133
|
+
* and bypasses CSRF for the backchannel-logout endpoint.
|
|
134
|
+
*
|
|
135
|
+
* Use with `sequence()` if you have other hooks:
|
|
136
|
+
* ```typescript
|
|
137
|
+
* export const handle = sequence(auth.handle, myOtherHook)
|
|
138
|
+
* ```
|
|
139
|
+
*/
|
|
140
|
+
handle: SvelteKitHandle;
|
|
141
|
+
/**
|
|
142
|
+
* SvelteKit request handler for `POST /api/auth/backchannel-logout`.
|
|
143
|
+
*
|
|
144
|
+
* Verifies the HS256 JWT logout token from the IdP. Returns 200 on
|
|
145
|
+
* success, 400 for malformed tokens. Since SvelteKit products hold no
|
|
146
|
+
* local sessions (auth state lives at the IdP), this endpoint only
|
|
147
|
+
* verifies the token and acknowledges receipt.
|
|
148
|
+
*
|
|
149
|
+
* Mount in `routes/api/auth/backchannel-logout/+server.ts`:
|
|
150
|
+
* ```typescript
|
|
151
|
+
* export const POST = auth.backchannelHandler
|
|
152
|
+
* ```
|
|
153
|
+
*/
|
|
154
|
+
backchannelHandler: SvelteKitRequestHandler;
|
|
155
|
+
/**
|
|
156
|
+
* SvelteKit request handler for `POST /api/auth/logout`.
|
|
157
|
+
*
|
|
158
|
+
* Clears the local session cookie (dev or guest) and returns the IdP
|
|
159
|
+
* end-session URL as `{ redirect: string }`. The client navigates to
|
|
160
|
+
* this URL to complete platform-wide sign-out.
|
|
161
|
+
*
|
|
162
|
+
* Mount in `routes/api/auth/logout/+server.ts`:
|
|
163
|
+
* ```typescript
|
|
164
|
+
* export const POST = auth.logoutHandler
|
|
165
|
+
* ```
|
|
166
|
+
*/
|
|
167
|
+
logoutHandler: SvelteKitRequestHandler;
|
|
168
|
+
/**
|
|
169
|
+
* The session verifier function, exposed for direct use in server load
|
|
170
|
+
* functions or API routes that need session data outside the hook.
|
|
171
|
+
*/
|
|
172
|
+
verifySession: SessionVerifier;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* @description Creates the complete SvelteKit auth integration for a Soulcraft product.
|
|
176
|
+
*
|
|
177
|
+
* Returns a `handle` hook, a `backchannelHandler`, and a `logoutHandler` — everything
|
|
178
|
+
* needed for auth in a SvelteKit product. One function call replaces ~100 lines of
|
|
179
|
+
* hand-rolled auth code in each product's hooks.server.ts.
|
|
180
|
+
*
|
|
181
|
+
* **Environment variables read:**
|
|
182
|
+
* - `SOULCRAFT_IDP_URL` — IdP base URL. Present → production mode. Absent → dev mode.
|
|
183
|
+
* - `SOULCRAFT_OIDC_CLIENT_ID` — OIDC client ID. Falls back to `options.product`.
|
|
184
|
+
* - `SOULCRAFT_OIDC_CLIENT_SECRET` — OIDC client secret. Required for backchannel logout.
|
|
185
|
+
* - `BETTER_AUTH_URL` — This product's base URL. Used for `post_logout_redirect_uri`.
|
|
186
|
+
*
|
|
187
|
+
* @param options - Product name, optional verifier override, optional user enrichment.
|
|
188
|
+
* @returns `{ handle, backchannelHandler, logoutHandler, verifySession }`.
|
|
189
|
+
*
|
|
190
|
+
* @example Minimal setup (Workshop, Academy)
|
|
191
|
+
* ```typescript
|
|
192
|
+
* const auth = createSoulcraftAuth({ product: 'workshop' })
|
|
193
|
+
* export const handle = auth.handle
|
|
194
|
+
* ```
|
|
195
|
+
*
|
|
196
|
+
* @example With enrichment (Venue)
|
|
197
|
+
* ```typescript
|
|
198
|
+
* const auth = createSoulcraftAuth({
|
|
199
|
+
* product: 'venue',
|
|
200
|
+
* enrichUser: async (user, event) => {
|
|
201
|
+
* const staff = await findStaff(event.locals.brain, user.id)
|
|
202
|
+
* return { ...user, role: staff?.role ?? 'customer' }
|
|
203
|
+
* }
|
|
204
|
+
* })
|
|
205
|
+
* ```
|
|
206
|
+
*/
|
|
207
|
+
export declare function createSoulcraftAuth(options: SoulcraftAuthOptions): SoulcraftAuth;
|
|
208
|
+
//# sourceMappingURL=sveltekit.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sveltekit.d.ts","sourceRoot":"","sources":["../../../src/modules/auth/sveltekit.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;AAGH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAA;AACtD,OAAO,KAAK,EAAE,oBAAoB,EAAoB,MAAM,YAAY,CAAA;AAMxE;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAA;IAChB,GAAG,EAAE,GAAG,CAAA;IACR,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC/B,OAAO,EAAE;QACP,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;YAAE,IAAI,CAAC,EAAE,MAAM,CAAA;SAAE,GAAG,IAAI,CAAA;KACrD,CAAA;CACF;AAED;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,KAAK,EAAE;IACpC,KAAK,EAAE,cAAc,CAAA;IACrB,OAAO,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAA;CACtD,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAA;AAEvB;;GAEG;AACH,MAAM,MAAM,uBAAuB,GAAG,CAAC,KAAK,EAAE,cAAc,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAA;AAMlF;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,OAAO,EAAE,MAAM,CAAA;IAEf;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,eAAe,CAAA;IAE1B;;;;;;;;;;;;;;;;;;OAkBG;IACH,UAAU,CAAC,EAAE,CACX,IAAI,EAAE,oBAAoB,EAC1B,KAAK,EAAE,cAAc,KAClB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAE/D;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IAEtB;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAA;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;;;;OAQG;IACH,MAAM,EAAE,eAAe,CAAA;IAEvB;;;;;;;;;;;;OAYG;IACH,kBAAkB,EAAE,uBAAuB,CAAA;IAE3C;;;;;;;;;;;OAWG;IACH,aAAa,EAAE,uBAAuB,CAAA;IAEtC;;;OAGG;IACH,aAAa,EAAE,eAAe,CAAA;CAC/B;AAuFD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,oBAAoB,GAAG,aAAa,CAiJhF"}
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module modules/auth/sveltekit
|
|
3
|
+
* @description Opinionated SvelteKit auth integration for Soulcraft products.
|
|
4
|
+
*
|
|
5
|
+
* `createSoulcraftAuth()` returns everything a SvelteKit product needs for auth:
|
|
6
|
+
* a `Handle` hook, a backchannel-logout request handler, and a logout request handler.
|
|
7
|
+
* One function, zero choices.
|
|
8
|
+
*
|
|
9
|
+
* ## What it does
|
|
10
|
+
*
|
|
11
|
+
* - **Session resolution** — reads the IdP cross-domain cookie, verifies via
|
|
12
|
+
* `createRemoteSessionVerifier` (30s LRU cache) in production or
|
|
13
|
+
* `createDevCookieVerifier` in dev mode
|
|
14
|
+
* - **Stale cookie recovery** — detects "cookie present but session null" and
|
|
15
|
+
* clears the stale cookie via `Set-Cookie: Max-Age=0`, breaking redirect loops
|
|
16
|
+
* - **CSRF bypass** — rewrites the `origin` header for `POST /api/auth/backchannel-logout`
|
|
17
|
+
* so SvelteKit's built-in CSRF check doesn't block server-to-server IdP calls
|
|
18
|
+
* - **User enrichment** — optional `enrichUser` callback for product-specific
|
|
19
|
+
* role resolution (e.g. Venue staff lookup, Portal admin check)
|
|
20
|
+
* - **Backchannel logout** — verifies the HS256 JWT logout token from the IdP
|
|
21
|
+
* - **Logout** — clears local cookies and returns the IdP end-session URL
|
|
22
|
+
*
|
|
23
|
+
* ## Usage
|
|
24
|
+
*
|
|
25
|
+
* ```typescript
|
|
26
|
+
* // hooks.server.ts
|
|
27
|
+
* import { createSoulcraftAuth } from '@soulcraft/sdk/server'
|
|
28
|
+
*
|
|
29
|
+
* const auth = createSoulcraftAuth({ product: 'venue' })
|
|
30
|
+
* export const handle = auth.handle
|
|
31
|
+
*
|
|
32
|
+
* // routes/api/auth/backchannel-logout/+server.ts
|
|
33
|
+
* export const POST = auth.backchannelHandler
|
|
34
|
+
*
|
|
35
|
+
* // routes/api/auth/logout/+server.ts
|
|
36
|
+
* export const POST = auth.logoutHandler
|
|
37
|
+
* ```
|
|
38
|
+
*
|
|
39
|
+
* @example With user enrichment (Venue staff role)
|
|
40
|
+
* ```typescript
|
|
41
|
+
* const auth = createSoulcraftAuth({
|
|
42
|
+
* product: 'venue',
|
|
43
|
+
* enrichUser: async (user, event) => {
|
|
44
|
+
* const staff = await lookupStaff(event.locals.brain, user.id)
|
|
45
|
+
* return { ...user, role: staff?.role ?? 'customer' }
|
|
46
|
+
* }
|
|
47
|
+
* })
|
|
48
|
+
* ```
|
|
49
|
+
*/
|
|
50
|
+
import { createRemoteSessionVerifier, createDevCookieVerifier } from './middleware.js';
|
|
51
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
52
|
+
// Constants
|
|
53
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
54
|
+
/**
|
|
55
|
+
* The cross-subdomain session cookie name set by the IdP.
|
|
56
|
+
* better-auth prefixes with `__Secure-` when `useSecureCookies: true`.
|
|
57
|
+
*/
|
|
58
|
+
const SESSION_COOKIE = '__Secure-better-auth.session_token';
|
|
59
|
+
/**
|
|
60
|
+
* Set-Cookie header value that expires the stale session cookie.
|
|
61
|
+
* Attributes mirror the IdP's original cookie so the browser accepts it.
|
|
62
|
+
*/
|
|
63
|
+
const CLEAR_SESSION_COOKIE = `${SESSION_COOKIE}=; Domain=.soulcraft.com; Path=/; Max-Age=0; Secure; HttpOnly; SameSite=Lax`;
|
|
64
|
+
/** OIDC Back-Channel Logout event URI (per spec). */
|
|
65
|
+
const BACKCHANNEL_LOGOUT_EVENT = 'http://schemas.openid.net/event/backchannel-logout';
|
|
66
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
67
|
+
// JWT verification (Web Crypto API — no external deps)
|
|
68
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
69
|
+
/**
|
|
70
|
+
* Verify an HS256 JWT using the Web Crypto API.
|
|
71
|
+
*
|
|
72
|
+
* @param token - Raw JWT string (`header.payload.signature`).
|
|
73
|
+
* @param secret - HMAC secret for signature verification.
|
|
74
|
+
* @returns The decoded payload if the signature is valid, or null.
|
|
75
|
+
*/
|
|
76
|
+
async function verifyHS256JWT(token, secret) {
|
|
77
|
+
const parts = token.split('.');
|
|
78
|
+
if (parts.length !== 3)
|
|
79
|
+
return null;
|
|
80
|
+
const [headerB64, payloadB64, sigB64] = parts;
|
|
81
|
+
let key;
|
|
82
|
+
try {
|
|
83
|
+
key = await crypto.subtle.importKey('raw', new TextEncoder().encode(secret), { name: 'HMAC', hash: 'SHA-256' }, false, ['verify']);
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
const signingInput = `${headerB64}.${payloadB64}`;
|
|
89
|
+
let sigBytes;
|
|
90
|
+
try {
|
|
91
|
+
sigBytes = Uint8Array.from(atob(sigB64.replace(/-/g, '+').replace(/_/g, '/')), (c) => c.charCodeAt(0));
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
return null;
|
|
95
|
+
}
|
|
96
|
+
const valid = await crypto.subtle.verify('HMAC', key, sigBytes.buffer, new TextEncoder().encode(signingInput));
|
|
97
|
+
if (!valid)
|
|
98
|
+
return null;
|
|
99
|
+
try {
|
|
100
|
+
const padded = payloadB64.replace(/-/g, '+').replace(/_/g, '/') +
|
|
101
|
+
'=='.slice(0, (4 - (payloadB64.length % 4)) % 4);
|
|
102
|
+
return JSON.parse(atob(padded));
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
109
|
+
// createSoulcraftAuth
|
|
110
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
111
|
+
/**
|
|
112
|
+
* @description Creates the complete SvelteKit auth integration for a Soulcraft product.
|
|
113
|
+
*
|
|
114
|
+
* Returns a `handle` hook, a `backchannelHandler`, and a `logoutHandler` — everything
|
|
115
|
+
* needed for auth in a SvelteKit product. One function call replaces ~100 lines of
|
|
116
|
+
* hand-rolled auth code in each product's hooks.server.ts.
|
|
117
|
+
*
|
|
118
|
+
* **Environment variables read:**
|
|
119
|
+
* - `SOULCRAFT_IDP_URL` — IdP base URL. Present → production mode. Absent → dev mode.
|
|
120
|
+
* - `SOULCRAFT_OIDC_CLIENT_ID` — OIDC client ID. Falls back to `options.product`.
|
|
121
|
+
* - `SOULCRAFT_OIDC_CLIENT_SECRET` — OIDC client secret. Required for backchannel logout.
|
|
122
|
+
* - `BETTER_AUTH_URL` — This product's base URL. Used for `post_logout_redirect_uri`.
|
|
123
|
+
*
|
|
124
|
+
* @param options - Product name, optional verifier override, optional user enrichment.
|
|
125
|
+
* @returns `{ handle, backchannelHandler, logoutHandler, verifySession }`.
|
|
126
|
+
*
|
|
127
|
+
* @example Minimal setup (Workshop, Academy)
|
|
128
|
+
* ```typescript
|
|
129
|
+
* const auth = createSoulcraftAuth({ product: 'workshop' })
|
|
130
|
+
* export const handle = auth.handle
|
|
131
|
+
* ```
|
|
132
|
+
*
|
|
133
|
+
* @example With enrichment (Venue)
|
|
134
|
+
* ```typescript
|
|
135
|
+
* const auth = createSoulcraftAuth({
|
|
136
|
+
* product: 'venue',
|
|
137
|
+
* enrichUser: async (user, event) => {
|
|
138
|
+
* const staff = await findStaff(event.locals.brain, user.id)
|
|
139
|
+
* return { ...user, role: staff?.role ?? 'customer' }
|
|
140
|
+
* }
|
|
141
|
+
* })
|
|
142
|
+
* ```
|
|
143
|
+
*/
|
|
144
|
+
export function createSoulcraftAuth(options) {
|
|
145
|
+
const { product, enrichUser, devCookieName = 'soulcraft_dev_session', backchannelPath = '/api/auth/backchannel-logout', } = options;
|
|
146
|
+
// ── Session verifier selection ──────────────────────────────────────────
|
|
147
|
+
const idpUrl = process.env['SOULCRAFT_IDP_URL'];
|
|
148
|
+
const verifySession = options.verifier
|
|
149
|
+
?? (idpUrl
|
|
150
|
+
? createRemoteSessionVerifier({ idpUrl })
|
|
151
|
+
: createDevCookieVerifier(devCookieName));
|
|
152
|
+
// ── Handle hook ─────────────────────────────────────────────────────────
|
|
153
|
+
const handle = async ({ event, resolve }) => {
|
|
154
|
+
// CSRF bypass for backchannel-logout — the IdP sends server-to-server
|
|
155
|
+
// POST requests without a browser origin header. Rewrite it so
|
|
156
|
+
// SvelteKit's CSRF check passes. The endpoint itself verifies the JWT.
|
|
157
|
+
if (event.url.pathname === backchannelPath &&
|
|
158
|
+
event.request.method === 'POST') {
|
|
159
|
+
const headers = new Headers(event.request.headers);
|
|
160
|
+
headers.set('origin', event.url.origin);
|
|
161
|
+
event.request = new Request(event.request, { headers });
|
|
162
|
+
}
|
|
163
|
+
// Resolve session
|
|
164
|
+
const cookieHeader = event.request.headers.get('cookie') ?? '';
|
|
165
|
+
const session = await verifySession(cookieHeader);
|
|
166
|
+
// Stale cookie recovery — if cookie present but session null, clear it
|
|
167
|
+
const hasSessionCookie = cookieHeader.includes(SESSION_COOKIE);
|
|
168
|
+
if (hasSessionCookie && !session) {
|
|
169
|
+
const response = await resolve(event);
|
|
170
|
+
response.headers.append('Set-Cookie', CLEAR_SESSION_COOKIE);
|
|
171
|
+
return response;
|
|
172
|
+
}
|
|
173
|
+
// Attach session and user to locals
|
|
174
|
+
event.locals['session'] = session
|
|
175
|
+
? { sessionId: session.sessionId, expiresAt: session.expiresAt }
|
|
176
|
+
: null;
|
|
177
|
+
if (session) {
|
|
178
|
+
const user = enrichUser
|
|
179
|
+
? await enrichUser(session.user, event)
|
|
180
|
+
: session.user;
|
|
181
|
+
event.locals['user'] = user;
|
|
182
|
+
}
|
|
183
|
+
else {
|
|
184
|
+
event.locals['user'] = null;
|
|
185
|
+
}
|
|
186
|
+
return resolve(event);
|
|
187
|
+
};
|
|
188
|
+
// ── Backchannel logout handler ──────────────────────────────────────────
|
|
189
|
+
const backchannelHandler = async ({ request }) => {
|
|
190
|
+
const clientSecret = process.env['SOULCRAFT_OIDC_CLIENT_SECRET'];
|
|
191
|
+
const idpUrlEnv = process.env['SOULCRAFT_IDP_URL'];
|
|
192
|
+
const clientId = process.env['SOULCRAFT_OIDC_CLIENT_ID'] ?? product;
|
|
193
|
+
// Only operates in OIDC client mode
|
|
194
|
+
if (!clientSecret || !idpUrlEnv) {
|
|
195
|
+
return new Response(null, { status: 200 });
|
|
196
|
+
}
|
|
197
|
+
// Parse logout_token from form body
|
|
198
|
+
let logoutToken = null;
|
|
199
|
+
try {
|
|
200
|
+
const body = await request.text();
|
|
201
|
+
const params = new URLSearchParams(body);
|
|
202
|
+
logoutToken = params.get('logout_token');
|
|
203
|
+
}
|
|
204
|
+
catch {
|
|
205
|
+
return new Response('malformed request body', { status: 400 });
|
|
206
|
+
}
|
|
207
|
+
if (!logoutToken) {
|
|
208
|
+
return new Response('missing logout_token', { status: 400 });
|
|
209
|
+
}
|
|
210
|
+
// Verify JWT signature and claims
|
|
211
|
+
const payload = await verifyHS256JWT(logoutToken, clientSecret);
|
|
212
|
+
if (!payload) {
|
|
213
|
+
return new Response('invalid logout_token', { status: 400 });
|
|
214
|
+
}
|
|
215
|
+
// Validate issuer
|
|
216
|
+
const expectedIss = idpUrlEnv.replace(/\/$/, '');
|
|
217
|
+
if (payload['iss'] !== expectedIss) {
|
|
218
|
+
return new Response('invalid issuer', { status: 400 });
|
|
219
|
+
}
|
|
220
|
+
// Validate audience
|
|
221
|
+
const aud = payload['aud'];
|
|
222
|
+
const audList = Array.isArray(aud) ? aud : [String(aud ?? '')];
|
|
223
|
+
if (!audList.includes(clientId)) {
|
|
224
|
+
return new Response('invalid audience', { status: 400 });
|
|
225
|
+
}
|
|
226
|
+
// Validate events claim
|
|
227
|
+
const events = payload['events'];
|
|
228
|
+
if (!events || !(BACKCHANNEL_LOGOUT_EVENT in events)) {
|
|
229
|
+
return new Response('missing backchannel-logout event claim', { status: 400 });
|
|
230
|
+
}
|
|
231
|
+
// Validate sub claim
|
|
232
|
+
if (!payload['sub'] || typeof payload['sub'] !== 'string') {
|
|
233
|
+
return new Response('missing sub claim', { status: 400 });
|
|
234
|
+
}
|
|
235
|
+
// SvelteKit products hold no local sessions — auth state lives at the IdP.
|
|
236
|
+
// The SDK verifier's 30s LRU cache will expire naturally.
|
|
237
|
+
return new Response(null, { status: 200 });
|
|
238
|
+
};
|
|
239
|
+
// ── Logout handler ──────────────────────────────────────────────────────
|
|
240
|
+
const logoutHandler = async ({ cookies, url }) => {
|
|
241
|
+
const idpUrlEnv = process.env['SOULCRAFT_IDP_URL'];
|
|
242
|
+
if (!idpUrlEnv) {
|
|
243
|
+
// Dev mode — clear the dev session cookie and redirect home
|
|
244
|
+
cookies.delete(devCookieName, { path: '/' });
|
|
245
|
+
return new Response(JSON.stringify({ redirect: '/' }), {
|
|
246
|
+
headers: { 'Content-Type': 'application/json' },
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
// OIDC mode — build the IdP end-session URL
|
|
250
|
+
const clientId = process.env['SOULCRAFT_OIDC_CLIENT_ID'] ?? product;
|
|
251
|
+
const baseUrl = process.env['BETTER_AUTH_URL'] ?? `${url.protocol}//${url.host}`;
|
|
252
|
+
const params = new URLSearchParams({
|
|
253
|
+
client_id: clientId,
|
|
254
|
+
post_logout_redirect_uri: `${baseUrl}/`,
|
|
255
|
+
});
|
|
256
|
+
const endSessionUrl = `${idpUrlEnv}/api/auth/oauth2/endsession?${params}`;
|
|
257
|
+
return new Response(JSON.stringify({ redirect: endSessionUrl }), {
|
|
258
|
+
headers: { 'Content-Type': 'application/json' },
|
|
259
|
+
});
|
|
260
|
+
};
|
|
261
|
+
return { handle, backchannelHandler, logoutHandler, verifySession };
|
|
262
|
+
}
|
|
263
|
+
//# sourceMappingURL=sveltekit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sveltekit.js","sourceRoot":"","sources":["../../../src/modules/auth/sveltekit.ts"],"names":[],"mappings":"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"}
|
package/dist/server/index.d.ts
CHANGED
|
@@ -1,28 +1,35 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @module @soulcraft/sdk/server
|
|
3
3
|
* @description Server entry point for @soulcraft/sdk. Exports everything needed to
|
|
4
|
-
* run the SDK in a product backend (
|
|
4
|
+
* run the SDK in a product backend (SvelteKit, Bun, Hono, or any server).
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* 25 SDK namespaces via a unified `/api/rpc` endpoint. Products configure which
|
|
8
|
-
* namespaces are active via `NamespaceProviders`.
|
|
6
|
+
* ## RPC Handler (recommended)
|
|
9
7
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
8
|
+
* Use `createRpcHandler()` to get a framework-agnostic `(Request) => Response`
|
|
9
|
+
* handler for the unified `/api/rpc` endpoint. Works with any server that speaks
|
|
10
|
+
* Web Standard `Request`/`Response` — no framework dependency.
|
|
12
11
|
*
|
|
13
|
-
* @example Unified router
|
|
14
12
|
* ```typescript
|
|
15
|
-
* import {
|
|
16
|
-
*
|
|
17
|
-
* const pool = new BrainyInstancePool({ storage: 'filesystem', dataPath: './data', strategy: 'per-user' })
|
|
13
|
+
* import { createRpcHandler } from '@soulcraft/sdk/server'
|
|
18
14
|
*
|
|
19
|
-
* const
|
|
15
|
+
* const handleRpc = createRpcHandler({
|
|
20
16
|
* resolveBrain: async (ctx) => pool.forUser(ctx.user.emailHash, ctx.workspaceId),
|
|
21
17
|
* authenticate: async (ctx) => verifySession(ctx.request),
|
|
22
|
-
* providers: {
|
|
18
|
+
* providers: { graph: graphHandler, search: searchHandler },
|
|
23
19
|
* })
|
|
24
|
-
*
|
|
20
|
+
*
|
|
21
|
+
* // SvelteKit: export const POST = ({ request }) => handleRpc(request)
|
|
22
|
+
* // Bun: Bun.serve({ fetch: (req) => handleRpc(req) })
|
|
23
|
+
* // Hono: app.post('/api/rpc', (c) => handleRpc(c.req.raw))
|
|
25
24
|
* ```
|
|
25
|
+
*
|
|
26
|
+
* ## Hono Router (legacy)
|
|
27
|
+
*
|
|
28
|
+
* `createSoulcraftRouter()` returns a Hono app — use if your server is Hono-based.
|
|
29
|
+
* Requires `hono` as a peer dependency.
|
|
30
|
+
*
|
|
31
|
+
* This entry point must never be imported in browser bundles — it has hard
|
|
32
|
+
* server-only dependencies (`@soulcraft/brainy`, `lru-cache`, `crypto`, `fs`).
|
|
26
33
|
*/
|
|
27
34
|
export { BrainyInstancePool, computeEmailHash, } from './instance-pool.js';
|
|
28
35
|
export type { InstancePoolConfig, InstancePoolStats, } from './instance-pool.js';
|
|
@@ -34,6 +41,8 @@ export { createAuthMiddleware, createRemoteSessionVerifier, createDevSessionVeri
|
|
|
34
41
|
export type { AuthMiddlewareOptions, AuthMiddleware, AuthContext, BetterAuthLike, SessionVerifier, RemoteSessionVerifierOptions, DevSessionVerifierOptions, DevLoginHandlerOptions, GuestSessionHandlerOptions, } from '../modules/auth/middleware.js';
|
|
35
42
|
export { createBackchannelLogoutHandler } from '../modules/auth/backchannel.js';
|
|
36
43
|
export type { BackchannelLogoutConfig, BackchannelAuthLike, } from '../modules/auth/backchannel.js';
|
|
44
|
+
export { createSoulcraftAuth } from '../modules/auth/sveltekit.js';
|
|
45
|
+
export type { SoulcraftAuthOptions, SoulcraftAuth, SvelteKitHandle, SvelteKitEvent, SvelteKitRequestHandler, } from '../modules/auth/sveltekit.js';
|
|
37
46
|
export { verifyServiceToken, extractBearerToken, } from '../modules/auth/service-token.js';
|
|
38
47
|
export { SOULCRAFT_USER_FIELDS, SOULCRAFT_SESSION_CONFIG, getAuthMode, getOIDCClientConfig, } from '../modules/auth/config.js';
|
|
39
48
|
export { SOULCRAFT_PRODUCTS, deriveOrigins, deriveRedirectUrls, } from '../modules/auth/products.js';
|
|
@@ -55,6 +64,8 @@ export { createNamespaceRouter } from './namespace-router.js';
|
|
|
55
64
|
export type { NamespaceRouterConfig, NamespaceRouter, NamespaceProvider, NamespaceProviders, RequestContext, UserContext, HandlerContext, PreAuthenticatedContext, DispatchResult, } from './namespace-router.js';
|
|
56
65
|
export { createNamespaceWsHandler } from './ws-handler.js';
|
|
57
66
|
export type { NamespaceWsHandlerConfig, NamespaceWsHandler, WsSession, } from './ws-handler.js';
|
|
67
|
+
export { createRpcHandler } from './rpc-handler.js';
|
|
68
|
+
export type { RpcHandlerConfig } from './rpc-handler.js';
|
|
58
69
|
export { createSoulcraftRouter } from './hono-router.js';
|
|
59
70
|
export type { SoulcraftRouterConfig } from './hono-router.js';
|
|
60
71
|
export { createAnnotationsHandler, createAuthHandler, createChatHandler, createCertificationHandler, createCollectionsHandler, createCommerceHandler, createConfigHandler, createExportHandler, createFormatsHandler, createGraphHandler, createImportHandler, createMediaHandler, createProjectHandler, createPublishHandler, createPulseHandler, createRealtimeHandler, createSearchHandler, createSessionHandler, createSettingsHandler, createWorkspaceHandler, } from './handlers/index.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"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"}
|
package/dist/server/index.js
CHANGED
|
@@ -1,28 +1,35 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @module @soulcraft/sdk/server
|
|
3
3
|
* @description Server entry point for @soulcraft/sdk. Exports everything needed to
|
|
4
|
-
* run the SDK in a product backend (
|
|
4
|
+
* run the SDK in a product backend (SvelteKit, Bun, Hono, or any server).
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
* 25 SDK namespaces via a unified `/api/rpc` endpoint. Products configure which
|
|
8
|
-
* namespaces are active via `NamespaceProviders`.
|
|
6
|
+
* ## RPC Handler (recommended)
|
|
9
7
|
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
8
|
+
* Use `createRpcHandler()` to get a framework-agnostic `(Request) => Response`
|
|
9
|
+
* handler for the unified `/api/rpc` endpoint. Works with any server that speaks
|
|
10
|
+
* Web Standard `Request`/`Response` — no framework dependency.
|
|
12
11
|
*
|
|
13
|
-
* @example Unified router
|
|
14
12
|
* ```typescript
|
|
15
|
-
* import {
|
|
16
|
-
*
|
|
17
|
-
* const pool = new BrainyInstancePool({ storage: 'filesystem', dataPath: './data', strategy: 'per-user' })
|
|
13
|
+
* import { createRpcHandler } from '@soulcraft/sdk/server'
|
|
18
14
|
*
|
|
19
|
-
* const
|
|
15
|
+
* const handleRpc = createRpcHandler({
|
|
20
16
|
* resolveBrain: async (ctx) => pool.forUser(ctx.user.emailHash, ctx.workspaceId),
|
|
21
17
|
* authenticate: async (ctx) => verifySession(ctx.request),
|
|
22
|
-
* providers: {
|
|
18
|
+
* providers: { graph: graphHandler, search: searchHandler },
|
|
23
19
|
* })
|
|
24
|
-
*
|
|
20
|
+
*
|
|
21
|
+
* // SvelteKit: export const POST = ({ request }) => handleRpc(request)
|
|
22
|
+
* // Bun: Bun.serve({ fetch: (req) => handleRpc(req) })
|
|
23
|
+
* // Hono: app.post('/api/rpc', (c) => handleRpc(c.req.raw))
|
|
25
24
|
* ```
|
|
25
|
+
*
|
|
26
|
+
* ## Hono Router (legacy)
|
|
27
|
+
*
|
|
28
|
+
* `createSoulcraftRouter()` returns a Hono app — use if your server is Hono-based.
|
|
29
|
+
* Requires `hono` as a peer dependency.
|
|
30
|
+
*
|
|
31
|
+
* This entry point must never be imported in browser bundles — it has hard
|
|
32
|
+
* server-only dependencies (`@soulcraft/brainy`, `lru-cache`, `crypto`, `fs`).
|
|
26
33
|
*/
|
|
27
34
|
// ── Instance pool ─────────────────────────────────────────────────────────────
|
|
28
35
|
export { BrainyInstancePool, computeEmailHash, } from './instance-pool.js';
|
|
@@ -33,6 +40,8 @@ export { createHallModule, createHallMediaClient, generateTurnCredentials, HallC
|
|
|
33
40
|
// ── Auth middleware + session factories ───────────────────────────────────────
|
|
34
41
|
export { createAuthMiddleware, createRemoteSessionVerifier, createDevSessionVerifier, createDevLoginHandler, createDevCookieVerifier, createGuestSessionHandler, createGuestCookieVerifier, AUTH_USER_KEY, } from '../modules/auth/middleware.js';
|
|
35
42
|
export { createBackchannelLogoutHandler } from '../modules/auth/backchannel.js';
|
|
43
|
+
// ── SvelteKit auth integration ────────────────────────────────────────────────
|
|
44
|
+
export { createSoulcraftAuth } from '../modules/auth/sveltekit.js';
|
|
36
45
|
// ── Service token verification ────────────────────────────────────────────────
|
|
37
46
|
export { verifyServiceToken, extractBearerToken, } from '../modules/auth/service-token.js';
|
|
38
47
|
// ── Auth config helpers ──────────────────────────────────────────────────────
|
|
@@ -52,7 +61,9 @@ export { createCachedDispatch, LruCacheProvider, DEFAULT_CACHEABLE_METHODS } fro
|
|
|
52
61
|
export { createNamespaceRouter } from './namespace-router.js';
|
|
53
62
|
// ── Namespace WebSocket handler ─────────────────────────────────────────────
|
|
54
63
|
export { createNamespaceWsHandler } from './ws-handler.js';
|
|
55
|
-
// ──
|
|
64
|
+
// ── RPC handler (framework-agnostic, recommended) ───────────────────────────
|
|
65
|
+
export { createRpcHandler } from './rpc-handler.js';
|
|
66
|
+
// ── Hono router factory (legacy — requires hono as peer dependency) ─────────
|
|
56
67
|
export { createSoulcraftRouter } from './hono-router.js';
|
|
57
68
|
// ── Namespace handler factories ──────────────────────────────────────────────
|
|
58
69
|
// Each factory creates a NamespaceProvider wired into `providers` on the router.
|
package/dist/server/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,iFAAiF;AACjF,OAAO,EACL,kBAAkB,EAClB,gBAAgB,GACjB,MAAM,oBAAoB,CAAA;AAM3B,iFAAiF;AACjF,OAAO,EAAE,WAAW,EAAE,MAAM,mCAAmC,CAAA;AAE/D,gFAAgF;AAChF,OAAO,EACL,gBAAgB,EAChB,qBAAqB,EACrB,uBAAuB,EACvB,UAAU,EACV,eAAe,GAChB,MAAM,oBAAoB,CAAA;AA4C3B,iFAAiF;AACjF,OAAO,EACL,oBAAoB,EACpB,2BAA2B,EAC3B,wBAAwB,EACxB,qBAAqB,EACrB,uBAAuB,EACvB,yBAAyB,EACzB,yBAAyB,EACzB,aAAa,GACd,MAAM,+BAA+B,CAAA;AAYtC,OAAO,EAAE,8BAA8B,EAAE,MAAM,gCAAgC,CAAA;AAM/E,iFAAiF;AACjF,OAAO,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAA;AASlE,iFAAiF;AACjF,OAAO,EACL,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,kCAAkC,CAAA;AAEzC,gFAAgF;AAChF,OAAO,EACL,qBAAqB,EACrB,wBAAwB,EACxB,WAAW,EACX,mBAAmB,GACpB,MAAM,2BAA2B,CAAA;AAElC,gFAAgF;AAChF,OAAO,EACL,kBAAkB,EAClB,aAAa,EACb,kBAAkB,GACnB,MAAM,6BAA6B,CAAA;AAMpC,gFAAgF;AAChF,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AAEjE,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAA;AAEjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAA;AAC3D,OAAO,EAAE,yBAAyB,EAAE,MAAM,mCAAmC,CAAA;AAK7E,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAA;AAExF,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAA;AAEvD,iFAAiF;AACjF,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAA;AAGlG,gFAAgF;AAChF,OAAO,EAAE,qBAAqB,EAAE,MAAM,uBAAuB,CAAA;AAa7D,+EAA+E;AAC/E,OAAO,EAAE,wBAAwB,EAAE,MAAM,iBAAiB,CAAA;AAO1D,+EAA+E;AAC/E,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA;AAGnD,+EAA+E;AAC/E,OAAO,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAA;AAGxD,gFAAgF;AAChF,iFAAiF;AACjF,OAAO,EACL,wBAAwB,EACxB,iBAAiB,EACjB,iBAAiB,EACjB,0BAA0B,EAC1B,wBAAwB,EACxB,qBAAqB,EACrB,mBAAmB,EACnB,mBAAmB,EACnB,oBAAoB,EACpB,kBAAkB,EAClB,mBAAmB,EACnB,kBAAkB,EAClB,oBAAoB,EACpB,oBAAoB,EACpB,kBAAkB,EAClB,qBAAqB,EACrB,mBAAmB,EACnB,oBAAoB,EACpB,qBAAqB,EACrB,sBAAsB,GACvB,MAAM,qBAAqB,CAAA;AA4D5B,OAAO,EACL,iBAAiB,EACjB,wBAAwB,EACxB,mBAAmB,EACnB,0BAA0B,EAC1B,YAAY,EACZ,UAAU,EACV,cAAc,EACd,mBAAmB,EACnB,aAAa,EACb,WAAW,EACX,sBAAsB,GACvB,MAAM,qBAAqB,CAAA"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module server/rpc-handler
|
|
3
|
+
* @description Framework-agnostic RPC request handler for the Soulcraft SDK.
|
|
4
|
+
*
|
|
5
|
+
* Creates a standard `(request: Request) => Promise<Response>` handler that
|
|
6
|
+
* parses the JSON body, validates RPC fields, dispatches to the namespace
|
|
7
|
+
* router, and serializes the result — all using Web Standard APIs only.
|
|
8
|
+
*
|
|
9
|
+
* No framework dependency (no Hono, no Express, no SvelteKit). Works with
|
|
10
|
+
* any server that speaks `Request`/`Response`:
|
|
11
|
+
*
|
|
12
|
+
* @example SvelteKit
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import { createRpcHandler } from '@soulcraft/sdk/server'
|
|
15
|
+
*
|
|
16
|
+
* const handleRpc = createRpcHandler({ resolveBrain, authenticate, providers })
|
|
17
|
+
*
|
|
18
|
+
* export const POST: RequestHandler = ({ request }) => handleRpc(request)
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* @example Bun.serve
|
|
22
|
+
* ```typescript
|
|
23
|
+
* const handleRpc = createRpcHandler({ resolveBrain, authenticate, providers })
|
|
24
|
+
*
|
|
25
|
+
* Bun.serve({
|
|
26
|
+
* fetch(req) {
|
|
27
|
+
* if (new URL(req.url).pathname === '/api/rpc') return handleRpc(req)
|
|
28
|
+
* return new Response('Not found', { status: 404 })
|
|
29
|
+
* }
|
|
30
|
+
* })
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* @example Hono (if you still use it)
|
|
34
|
+
* ```typescript
|
|
35
|
+
* const handleRpc = createRpcHandler({ resolveBrain, authenticate, providers })
|
|
36
|
+
*
|
|
37
|
+
* app.post('/api/rpc', (c) => handleRpc(c.req.raw))
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
import type { NamespaceRouterConfig } from './namespace-router.js';
|
|
41
|
+
import type { RpcCacheConfig } from './rpc-cache.js';
|
|
42
|
+
/**
|
|
43
|
+
* @description Configuration for {@link createRpcHandler}.
|
|
44
|
+
* Extends {@link NamespaceRouterConfig} with optional RPC response caching.
|
|
45
|
+
*/
|
|
46
|
+
export interface RpcHandlerConfig extends NamespaceRouterConfig {
|
|
47
|
+
/**
|
|
48
|
+
* Optional RPC response cache configuration.
|
|
49
|
+
* When provided, cacheable read methods are served from an in-process LRU cache
|
|
50
|
+
* with singleflight deduplication. Write methods flush the scope automatically.
|
|
51
|
+
*
|
|
52
|
+
* @see {@link RpcCacheConfig}
|
|
53
|
+
*/
|
|
54
|
+
cache?: RpcCacheConfig;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Creates a framework-agnostic RPC request handler.
|
|
58
|
+
*
|
|
59
|
+
* Takes a standard Web `Request`, parses the JSON body, validates the RPC
|
|
60
|
+
* envelope, dispatches to the namespace router, and returns a standard `Response`.
|
|
61
|
+
* Streaming results are delivered as SSE (`text/event-stream`).
|
|
62
|
+
*
|
|
63
|
+
* @param config - Namespace router configuration (auth, brain resolution, providers).
|
|
64
|
+
* @returns An async function: `(request: Request) => Promise<Response>`.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```typescript
|
|
68
|
+
* const handleRpc = createRpcHandler({
|
|
69
|
+
* resolveBrain: async (ctx) => pool.forUser(ctx.user!.emailHash, ctx.workspaceId),
|
|
70
|
+
* authenticate: async (ctx) => verifySession(ctx.request),
|
|
71
|
+
* providers: { graph: graphHandler, search: searchHandler },
|
|
72
|
+
* })
|
|
73
|
+
*
|
|
74
|
+
* // Use in any server framework:
|
|
75
|
+
* const response = await handleRpc(request)
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
export declare function createRpcHandler(config: RpcHandlerConfig): (request: Request) => Promise<Response>;
|
|
79
|
+
//# sourceMappingURL=rpc-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rpc-handler.d.ts","sourceRoot":"","sources":["../../src/server/rpc-handler.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAIH,OAAO,KAAK,EAAE,qBAAqB,EAAkB,MAAM,uBAAuB,CAAA;AAClF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAGpD;;;GAGG;AACH,MAAM,WAAW,gBAAiB,SAAQ,qBAAqB;IAC7D;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,cAAc,CAAA;CACvB;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAsClG"}
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module server/rpc-handler
|
|
3
|
+
* @description Framework-agnostic RPC request handler for the Soulcraft SDK.
|
|
4
|
+
*
|
|
5
|
+
* Creates a standard `(request: Request) => Promise<Response>` handler that
|
|
6
|
+
* parses the JSON body, validates RPC fields, dispatches to the namespace
|
|
7
|
+
* router, and serializes the result — all using Web Standard APIs only.
|
|
8
|
+
*
|
|
9
|
+
* No framework dependency (no Hono, no Express, no SvelteKit). Works with
|
|
10
|
+
* any server that speaks `Request`/`Response`:
|
|
11
|
+
*
|
|
12
|
+
* @example SvelteKit
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import { createRpcHandler } from '@soulcraft/sdk/server'
|
|
15
|
+
*
|
|
16
|
+
* const handleRpc = createRpcHandler({ resolveBrain, authenticate, providers })
|
|
17
|
+
*
|
|
18
|
+
* export const POST: RequestHandler = ({ request }) => handleRpc(request)
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* @example Bun.serve
|
|
22
|
+
* ```typescript
|
|
23
|
+
* const handleRpc = createRpcHandler({ resolveBrain, authenticate, providers })
|
|
24
|
+
*
|
|
25
|
+
* Bun.serve({
|
|
26
|
+
* fetch(req) {
|
|
27
|
+
* if (new URL(req.url).pathname === '/api/rpc') return handleRpc(req)
|
|
28
|
+
* return new Response('Not found', { status: 404 })
|
|
29
|
+
* }
|
|
30
|
+
* })
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* @example Hono (if you still use it)
|
|
34
|
+
* ```typescript
|
|
35
|
+
* const handleRpc = createRpcHandler({ resolveBrain, authenticate, providers })
|
|
36
|
+
*
|
|
37
|
+
* app.post('/api/rpc', (c) => handleRpc(c.req.raw))
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
import { createNamespaceRouter } from './namespace-router.js';
|
|
41
|
+
import { createCachedDispatch } from './rpc-cache.js';
|
|
42
|
+
/**
|
|
43
|
+
* Creates a framework-agnostic RPC request handler.
|
|
44
|
+
*
|
|
45
|
+
* Takes a standard Web `Request`, parses the JSON body, validates the RPC
|
|
46
|
+
* envelope, dispatches to the namespace router, and returns a standard `Response`.
|
|
47
|
+
* Streaming results are delivered as SSE (`text/event-stream`).
|
|
48
|
+
*
|
|
49
|
+
* @param config - Namespace router configuration (auth, brain resolution, providers).
|
|
50
|
+
* @returns An async function: `(request: Request) => Promise<Response>`.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```typescript
|
|
54
|
+
* const handleRpc = createRpcHandler({
|
|
55
|
+
* resolveBrain: async (ctx) => pool.forUser(ctx.user!.emailHash, ctx.workspaceId),
|
|
56
|
+
* authenticate: async (ctx) => verifySession(ctx.request),
|
|
57
|
+
* providers: { graph: graphHandler, search: searchHandler },
|
|
58
|
+
* })
|
|
59
|
+
*
|
|
60
|
+
* // Use in any server framework:
|
|
61
|
+
* const response = await handleRpc(request)
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
export function createRpcHandler(config) {
|
|
65
|
+
const baseRouter = createNamespaceRouter(config);
|
|
66
|
+
const router = config.cache
|
|
67
|
+
? createCachedDispatch(baseRouter, config.cache)
|
|
68
|
+
: baseRouter;
|
|
69
|
+
return async (request) => {
|
|
70
|
+
// ── Parse JSON body ────────────────────────────────────────────────────
|
|
71
|
+
let body;
|
|
72
|
+
try {
|
|
73
|
+
body = await request.json();
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
return _jsonResponse({ error: { code: 'BAD_REQUEST', message: 'Request body must be valid JSON' } }, 400);
|
|
77
|
+
}
|
|
78
|
+
// ── Validate required RPC fields ───────────────────────────────────────
|
|
79
|
+
if (typeof body.ns !== 'string' || typeof body.method !== 'string' || !Array.isArray(body.args)) {
|
|
80
|
+
return _jsonResponse({ error: { code: 'BAD_REQUEST', message: '{ ns: string, method: string, args: unknown[] } required' } }, 400);
|
|
81
|
+
}
|
|
82
|
+
const rpc = {
|
|
83
|
+
id: typeof body.id === 'string' ? body.id : crypto.randomUUID(),
|
|
84
|
+
ns: body.ns,
|
|
85
|
+
method: body.method,
|
|
86
|
+
args: body.args,
|
|
87
|
+
stream: body.stream ?? false,
|
|
88
|
+
};
|
|
89
|
+
// ── Dispatch ──────────────────────────────────────────────────────────
|
|
90
|
+
const result = await router.dispatch(rpc, request);
|
|
91
|
+
return _toResponse(result);
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
95
|
+
// Response helpers (framework-agnostic, Web Standard only)
|
|
96
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
97
|
+
/**
|
|
98
|
+
* Converts a {@link DispatchResult} into a standard Web `Response`.
|
|
99
|
+
*
|
|
100
|
+
* @param result - The dispatch result from the namespace router.
|
|
101
|
+
* @returns A Response — JSON for normal results, SSE for streaming results.
|
|
102
|
+
*/
|
|
103
|
+
function _toResponse(result) {
|
|
104
|
+
if (result.type === 'response') {
|
|
105
|
+
const { response } = result;
|
|
106
|
+
const status = response.error ? _errorStatusCode(response.error.code) : 200;
|
|
107
|
+
const headers = { 'Content-Type': 'application/json' };
|
|
108
|
+
// Merge cache headers (Cache-Control, ETag, X-Cache) when present.
|
|
109
|
+
if (result.headers) {
|
|
110
|
+
for (const [key, value] of Object.entries(result.headers)) {
|
|
111
|
+
headers[key] = value;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return new Response(JSON.stringify(response), { status, headers });
|
|
115
|
+
}
|
|
116
|
+
// Streaming result — deliver as SSE.
|
|
117
|
+
const { id, iterable } = result;
|
|
118
|
+
const stream = new ReadableStream({
|
|
119
|
+
async start(controller) {
|
|
120
|
+
const encoder = new TextEncoder();
|
|
121
|
+
try {
|
|
122
|
+
for await (const chunk of iterable) {
|
|
123
|
+
const frame = { id, chunk };
|
|
124
|
+
controller.enqueue(encoder.encode(`data: ${JSON.stringify(frame)}\n\n`));
|
|
125
|
+
}
|
|
126
|
+
const doneFrame = { id, done: true };
|
|
127
|
+
controller.enqueue(encoder.encode(`data: ${JSON.stringify(doneFrame)}\n\n`));
|
|
128
|
+
}
|
|
129
|
+
catch (err) {
|
|
130
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
131
|
+
const errorFrame = { id, error: message };
|
|
132
|
+
controller.enqueue(encoder.encode(`data: ${JSON.stringify(errorFrame)}\n\n`));
|
|
133
|
+
}
|
|
134
|
+
finally {
|
|
135
|
+
controller.close();
|
|
136
|
+
}
|
|
137
|
+
},
|
|
138
|
+
});
|
|
139
|
+
return new Response(stream, {
|
|
140
|
+
status: 200,
|
|
141
|
+
headers: {
|
|
142
|
+
'Content-Type': 'text/event-stream',
|
|
143
|
+
'Cache-Control': 'no-cache',
|
|
144
|
+
'Connection': 'keep-alive',
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Creates a JSON Response with the given status code.
|
|
150
|
+
*
|
|
151
|
+
* @param data - The response body.
|
|
152
|
+
* @param status - HTTP status code.
|
|
153
|
+
* @returns A Response with `Content-Type: application/json`.
|
|
154
|
+
*/
|
|
155
|
+
function _jsonResponse(data, status) {
|
|
156
|
+
return new Response(JSON.stringify(data), {
|
|
157
|
+
status,
|
|
158
|
+
headers: { 'Content-Type': 'application/json' },
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Maps RPC error codes to HTTP status codes.
|
|
163
|
+
*
|
|
164
|
+
* @param code - The error code from the dispatch result.
|
|
165
|
+
* @returns HTTP status code.
|
|
166
|
+
*/
|
|
167
|
+
function _errorStatusCode(code) {
|
|
168
|
+
switch (code) {
|
|
169
|
+
case 'UNAUTHORIZED':
|
|
170
|
+
case 'AUTH_ERROR':
|
|
171
|
+
return 401;
|
|
172
|
+
case 'FORBIDDEN':
|
|
173
|
+
return 403;
|
|
174
|
+
case 'NAMESPACE_NOT_FOUND':
|
|
175
|
+
case 'METHOD_NOT_FOUND':
|
|
176
|
+
return 404;
|
|
177
|
+
case 'BRAIN_UNAVAILABLE':
|
|
178
|
+
return 503;
|
|
179
|
+
case 'BAD_REQUEST':
|
|
180
|
+
return 400;
|
|
181
|
+
default:
|
|
182
|
+
return 500;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
//# sourceMappingURL=rpc-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rpc-handler.js","sourceRoot":"","sources":["../../src/server/rpc-handler.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@soulcraft/sdk",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.0",
|
|
4
4
|
"description": "The unified Soulcraft platform SDK — data, auth, AI, billing, and notifications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -41,6 +41,7 @@
|
|
|
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",
|
|
44
45
|
"stripe": ">=20.0.0"
|
|
45
46
|
},
|
|
46
47
|
"peerDependenciesMeta": {
|
|
@@ -61,6 +62,9 @@
|
|
|
61
62
|
},
|
|
62
63
|
"stripe": {
|
|
63
64
|
"optional": true
|
|
65
|
+
},
|
|
66
|
+
"hono": {
|
|
67
|
+
"optional": true
|
|
64
68
|
}
|
|
65
69
|
},
|
|
66
70
|
"dependencies": {
|