@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.
Files changed (59) hide show
  1. package/dist/modules/auth/backchannel.d.ts +13 -39
  2. package/dist/modules/auth/backchannel.d.ts.map +1 -1
  3. package/dist/modules/auth/backchannel.js +12 -144
  4. package/dist/modules/auth/backchannel.js.map +1 -1
  5. package/dist/modules/auth/middleware.d.ts +45 -157
  6. package/dist/modules/auth/middleware.d.ts.map +1 -1
  7. package/dist/modules/auth/middleware.js +40 -322
  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 +94 -0
  12. package/dist/modules/auth/request-backchannel.d.ts.map +1 -0
  13. package/dist/modules/auth/request-backchannel.js +206 -0
  14. package/dist/modules/auth/request-backchannel.js.map +1 -0
  15. package/dist/modules/auth/request-middleware.d.ts +438 -0
  16. package/dist/modules/auth/request-middleware.d.ts.map +1 -0
  17. package/dist/modules/auth/request-middleware.js +650 -0
  18. package/dist/modules/auth/request-middleware.js.map +1 -0
  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 +5 -12
  35. package/dist/server/index.d.ts.map +1 -1
  36. package/dist/server/index.js +4 -9
  37. package/dist/server/index.js.map +1 -1
  38. package/dist/server/instance-pool.d.ts.map +1 -1
  39. package/dist/server/instance-pool.js +1 -0
  40. package/dist/server/instance-pool.js.map +1 -1
  41. package/dist/server/namespace-router.d.ts +1 -1
  42. package/dist/server/namespace-router.js +1 -1
  43. package/dist/server/rpc-handler.d.ts +2 -9
  44. package/dist/server/rpc-handler.d.ts.map +1 -1
  45. package/dist/server/rpc-handler.js +2 -9
  46. package/dist/server/rpc-handler.js.map +1 -1
  47. package/docs/ADR-001-sdk-design.md +3 -3
  48. package/docs/ADR-004-product-registry.md +1 -1
  49. package/docs/ADR-005-hall-integration.md +1 -1
  50. package/docs/ADR-006-rpc-cache.md +2 -2
  51. package/docs/IMPLEMENTATION-PLAN.md +7 -7
  52. package/docs/KIT-APP-GUIDE.md +100 -99
  53. package/docs/USAGE.md +30 -40
  54. package/docs/kit-sdk-guide.md +59 -60
  55. package/package.json +2 -7
  56. package/dist/server/hono-router.d.ts +0 -70
  57. package/dist/server/hono-router.d.ts.map +0 -1
  58. package/dist/server/hono-router.js +0 -167
  59. package/dist/server/hono-router.js.map +0 -1
@@ -0,0 +1,206 @@
1
+ /**
2
+ * @module modules/auth/request-backchannel
3
+ * @description Framework-agnostic OIDC back-channel logout handler using Web Standard
4
+ * Request/Response.
5
+ *
6
+ * Implements the OpenID Connect Back-Channel Logout 1.0 specification. When a user
7
+ * signs out of the central IdP (`auth.soulcraft.com`), the IdP POSTs a signed
8
+ * `logout_token` (HS256 JWT) to every registered product's back-channel logout
9
+ * endpoint. This handler verifies the token and deletes all active sessions for
10
+ * the identified user, ensuring immediate logout across all products.
11
+ *
12
+ * ## Protocol
13
+ *
14
+ * 1. IdP POSTs `application/x-www-form-urlencoded` body with `logout_token` field
15
+ * 2. Handler verifies HS256 JWT signature using the OIDC client secret
16
+ * 3. Handler validates standard claims: `iss`, `aud`, `events` (must contain
17
+ * `http://schemas.openid.net/event/backchannel-logout`)
18
+ * 4. Handler deletes all better-auth sessions for the `sub` (user ID) claim
19
+ * 5. Returns 200 on success, 400 for malformed tokens, 401 for bad signatures
20
+ *
21
+ * ## Mounting
22
+ *
23
+ * ```typescript
24
+ * import { createRequestBackchannelLogoutHandler } from '@soulcraft/sdk/server'
25
+ *
26
+ * const handleLogout = createRequestBackchannelLogoutHandler({
27
+ * auth,
28
+ * clientSecret: process.env.SOULCRAFT_OIDC_CLIENT_SECRET!,
29
+ * idpUrl: process.env.SOULCRAFT_IDP_URL!,
30
+ * clientId: process.env.SOULCRAFT_OIDC_CLIENT_ID!,
31
+ * })
32
+ *
33
+ * // SvelteKit: export const POST = ({ request }) => handleLogout(request)
34
+ * // Bun: if (url.pathname === '/api/auth/backchannel-logout') return handleLogout(req)
35
+ * ```
36
+ */
37
+ // The OIDC back-channel logout events claim URI.
38
+ const BACKCHANNEL_LOGOUT_EVENT = 'http://schemas.openid.net/event/backchannel-logout';
39
+ // ─────────────────────────────────────────────────────────────────────────────
40
+ // JWT verification helpers (Web Crypto API — no external deps)
41
+ // ─────────────────────────────────────────────────────────────────────────────
42
+ /**
43
+ * @description Verify an HS256 JWT using the Web Crypto API.
44
+ *
45
+ * @param token - Raw JWT string (`header.payload.signature`).
46
+ * @param secret - HMAC secret for signature verification.
47
+ * @returns The decoded payload if the signature is valid, or null.
48
+ */
49
+ async function verifyHS256JWT(token, secret) {
50
+ const parts = token.split('.');
51
+ if (parts.length !== 3)
52
+ return null;
53
+ const [headerB64, payloadB64, sigB64] = parts;
54
+ // Import the HMAC key
55
+ let key;
56
+ try {
57
+ key = await crypto.subtle.importKey('raw', new TextEncoder().encode(secret), { name: 'HMAC', hash: 'SHA-256' }, false, ['verify']);
58
+ }
59
+ catch {
60
+ return null;
61
+ }
62
+ // Verify signature over `header.payload`
63
+ const signingInput = `${headerB64}.${payloadB64}`;
64
+ let sigBytes;
65
+ try {
66
+ sigBytes = Uint8Array.from(atob(sigB64.replace(/-/g, '+').replace(/_/g, '/')), (c) => c.charCodeAt(0));
67
+ }
68
+ catch {
69
+ return null;
70
+ }
71
+ const valid = await crypto.subtle.verify('HMAC', key, sigBytes.buffer, new TextEncoder().encode(signingInput));
72
+ if (!valid)
73
+ return null;
74
+ // Decode payload
75
+ try {
76
+ const padded = payloadB64.replace(/-/g, '+').replace(/_/g, '/') +
77
+ '=='.slice(0, (4 - (payloadB64.length % 4)) % 4);
78
+ return JSON.parse(atob(padded));
79
+ }
80
+ catch {
81
+ return null;
82
+ }
83
+ }
84
+ // ─────────────────────────────────────────────────────────────────────────────
85
+ // createRequestBackchannelLogoutHandler
86
+ // ─────────────────────────────────────────────────────────────────────────────
87
+ /**
88
+ * @description Creates a framework-agnostic request handler for the OIDC back-channel
89
+ * logout endpoint.
90
+ *
91
+ * The handler:
92
+ * 1. Parses the `logout_token` from the form-encoded or JSON body
93
+ * 2. Verifies the HS256 JWT signature using the OIDC client secret
94
+ * 3. Validates `iss` (must match idpUrl), `aud` (must match clientId),
95
+ * and `events` (must contain the back-channel logout event URI)
96
+ * 4. Calls `auth.api.revokeUserSessions({ body: { userId: sub } })` to
97
+ * immediately invalidate all sessions for the identified user
98
+ * 5. Returns 200 on success, 400 for malformed/missing token, 401 for
99
+ * invalid signature or failed claims validation
100
+ *
101
+ * @param config - Auth instance, client secret, IdP URL, and client ID.
102
+ * @returns An async request handler function `(req: Request) => Promise<Response>`.
103
+ *
104
+ * @example
105
+ * ```typescript
106
+ * import { createRequestBackchannelLogoutHandler } from '@soulcraft/sdk/server'
107
+ *
108
+ * const handleLogout = createRequestBackchannelLogoutHandler({
109
+ * auth,
110
+ * clientSecret: process.env.SOULCRAFT_OIDC_CLIENT_SECRET!,
111
+ * idpUrl: process.env.SOULCRAFT_IDP_URL!,
112
+ * clientId: process.env.SOULCRAFT_OIDC_CLIENT_ID!,
113
+ * })
114
+ *
115
+ * // SvelteKit +server.ts:
116
+ * export const POST = ({ request }) => handleLogout(request)
117
+ * ```
118
+ */
119
+ export function createRequestBackchannelLogoutHandler(config) {
120
+ const idpOrigin = config.idpUrl.replace(/\/$/, '');
121
+ return async function requestBackchannelLogoutHandler(req) {
122
+ // Parse the logout_token from the body
123
+ let logoutToken = null;
124
+ try {
125
+ const contentType = req.headers.get('content-type') ?? '';
126
+ if (contentType.includes('application/x-www-form-urlencoded')) {
127
+ const text = await req.text();
128
+ const params = new URLSearchParams(text);
129
+ logoutToken = params.get('logout_token');
130
+ }
131
+ else {
132
+ // Also accept JSON body for easier testing
133
+ const body = await req.json();
134
+ logoutToken = body['logout_token'] ?? null;
135
+ }
136
+ }
137
+ catch {
138
+ return new Response(JSON.stringify({ error: 'Failed to parse request body' }), {
139
+ status: 400,
140
+ headers: { 'Content-Type': 'application/json' },
141
+ });
142
+ }
143
+ if (!logoutToken || typeof logoutToken !== 'string') {
144
+ return new Response(JSON.stringify({ error: 'Missing logout_token' }), {
145
+ status: 400,
146
+ headers: { 'Content-Type': 'application/json' },
147
+ });
148
+ }
149
+ // Verify the JWT
150
+ const payload = await verifyHS256JWT(logoutToken, config.clientSecret);
151
+ if (!payload) {
152
+ return new Response(JSON.stringify({ error: 'Invalid logout_token signature' }), {
153
+ status: 401,
154
+ headers: { 'Content-Type': 'application/json' },
155
+ });
156
+ }
157
+ // Validate issuer
158
+ if (payload['iss'] !== idpOrigin) {
159
+ return new Response(JSON.stringify({ error: 'Invalid issuer' }), {
160
+ status: 401,
161
+ headers: { 'Content-Type': 'application/json' },
162
+ });
163
+ }
164
+ // Validate audience — may be a string or array of strings
165
+ const aud = payload['aud'];
166
+ const audList = Array.isArray(aud) ? aud : [String(aud ?? '')];
167
+ if (!audList.includes(config.clientId)) {
168
+ return new Response(JSON.stringify({ error: 'Invalid audience' }), {
169
+ status: 401,
170
+ headers: { 'Content-Type': 'application/json' },
171
+ });
172
+ }
173
+ // Validate events claim
174
+ const events = payload['events'];
175
+ if (!events || !(BACKCHANNEL_LOGOUT_EVENT in events)) {
176
+ return new Response(JSON.stringify({ error: 'Missing backchannel logout event' }), {
177
+ status: 400,
178
+ headers: { 'Content-Type': 'application/json' },
179
+ });
180
+ }
181
+ // Extract the subject user ID
182
+ const sub = payload['sub'];
183
+ if (!sub || typeof sub !== 'string') {
184
+ return new Response(JSON.stringify({ error: 'Missing sub claim' }), {
185
+ status: 400,
186
+ headers: { 'Content-Type': 'application/json' },
187
+ });
188
+ }
189
+ // Revoke all sessions for this user
190
+ try {
191
+ await config.auth.api.revokeUserSessions({ body: { userId: sub } });
192
+ }
193
+ catch (err) {
194
+ console.error(`[SDK/backchannel] Failed to revoke sessions for user ${sub}:`, err);
195
+ return new Response(JSON.stringify({ error: 'Failed to revoke sessions' }), {
196
+ status: 500,
197
+ headers: { 'Content-Type': 'application/json' },
198
+ });
199
+ }
200
+ return new Response(JSON.stringify({ ok: true }), {
201
+ status: 200,
202
+ headers: { 'Content-Type': 'application/json' },
203
+ });
204
+ };
205
+ }
206
+ //# sourceMappingURL=request-backchannel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-backchannel.js","sourceRoot":"","sources":["../../../src/modules/auth/request-backchannel.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,438 @@
1
+ /**
2
+ * @module modules/auth/request-middleware
3
+ * @description Framework-agnostic auth middleware, session verification, and dev/guest
4
+ * utilities for Soulcraft product backends.
5
+ *
6
+ * All middleware uses Web Standard `Request`/`Response` — no framework dependency.
7
+ * Compatible with SvelteKit, Bun.serve, Deno, Cloudflare Workers, and any server
8
+ * that speaks the Web Standard APIs.
9
+ *
10
+ * ## Session verification strategies
11
+ *
12
+ * Products select the right session verifier for their deployment context:
13
+ *
14
+ * ```
15
+ * Production (all products):
16
+ * createRemoteSessionVerifier({ idpUrl: 'https://auth.soulcraft.com' })
17
+ *
18
+ * Development (all products):
19
+ * createDevSessionVerifier({ role: 'owner' }) // auto-login, no OAuth needed
20
+ * ```
21
+ *
22
+ * ## Middleware signature
23
+ *
24
+ * All middleware follows the universal pattern:
25
+ * ```
26
+ * (req: Request, next: () => Promise<Response>) => Promise<Response>
27
+ * ```
28
+ *
29
+ * ## User retrieval
30
+ *
31
+ * After middleware runs, retrieve the resolved user with `getUser(req)`:
32
+ * ```typescript
33
+ * const user = getUser(req) // SoulcraftSessionUser | null
34
+ * ```
35
+ *
36
+ * ## Dev and guest cookie verifiers
37
+ *
38
+ * - `createDevCookieVerifier` — reads the dev session cookie issued by
39
+ * `createRequestDevLoginHandler`.
40
+ * - `createGuestCookieVerifier` — reads the guest session cookie issued by
41
+ * `createRequestGuestSessionHandler`.
42
+ *
43
+ * @example SvelteKit hooks
44
+ * ```typescript
45
+ * import {
46
+ * createRequestAuthMiddleware,
47
+ * createRemoteSessionVerifier,
48
+ * getUser,
49
+ * } from '@soulcraft/sdk/server'
50
+ *
51
+ * const verifySession = createRemoteSessionVerifier({ idpUrl: process.env.SOULCRAFT_IDP_URL! })
52
+ * const { requireAuth } = createRequestAuthMiddleware(verifySession)
53
+ *
54
+ * export const handle = async ({ event, resolve }) => {
55
+ * const response = await requireAuth(event.request, () => resolve(event))
56
+ * event.locals.user = getUser(event.request)
57
+ * return response
58
+ * }
59
+ * ```
60
+ *
61
+ * @example Bun.serve
62
+ * ```typescript
63
+ * import {
64
+ * createRequestAuthMiddleware,
65
+ * createRemoteSessionVerifier,
66
+ * getUser,
67
+ * } from '@soulcraft/sdk/server'
68
+ *
69
+ * const verifier = createRemoteSessionVerifier({ idpUrl: process.env.SOULCRAFT_IDP_URL! })
70
+ * const { optionalAuth } = createRequestAuthMiddleware(verifier)
71
+ *
72
+ * Bun.serve({
73
+ * fetch: (req) => optionalAuth(req, async () => {
74
+ * const user = getUser(req)
75
+ * return new Response(JSON.stringify({ user: user?.email ?? 'anonymous' }))
76
+ * }),
77
+ * })
78
+ * ```
79
+ */
80
+ import type { SoulcraftSessionUser, SoulcraftSession } from './types.js';
81
+ /** Minimal better-auth API surface the middleware depends on. */
82
+ export interface BetterAuthLike {
83
+ api: {
84
+ getSession(opts: {
85
+ headers: Headers;
86
+ }): Promise<{
87
+ user: Record<string, unknown>;
88
+ session: {
89
+ id: string;
90
+ expiresAt: Date | string | number;
91
+ };
92
+ } | null>;
93
+ };
94
+ }
95
+ /**
96
+ * A session verifier function — the common abstraction for session resolution
97
+ * across all products.
98
+ *
99
+ * Returned by `createRemoteSessionVerifier` and `createDevSessionVerifier`.
100
+ * Pass to `createRequestAuthMiddleware` for the framework-agnostic middleware.
101
+ */
102
+ export type SessionVerifier = (cookieHeader: string) => Promise<SoulcraftSession | null>;
103
+ /**
104
+ * Options for `createRequestAuthMiddleware()`.
105
+ */
106
+ export interface AuthMiddlewareOptions {
107
+ /**
108
+ * If true, a synthetic dev user is injected in non-production environments
109
+ * when a `BetterAuthLike` auth instance is provided and session lookup fails.
110
+ * Not used when a `SessionVerifier` function is provided — use
111
+ * `createDevSessionVerifier` instead for full dev auto-login in that mode.
112
+ * @default true
113
+ */
114
+ devAutoLogin?: boolean;
115
+ }
116
+ /**
117
+ * Options for `createRemoteSessionVerifier()`.
118
+ */
119
+ export interface RemoteSessionVerifierOptions {
120
+ /** The central IdP base URL, e.g. `"https://auth.soulcraft.com"`. */
121
+ idpUrl: string;
122
+ /** Session cache TTL in milliseconds. Default: 30 000 (30 seconds). */
123
+ cacheTtlMs?: number;
124
+ /** Maximum cached sessions. Default: 500. */
125
+ cacheMax?: number;
126
+ }
127
+ /**
128
+ * Options for `createDevSessionVerifier()`.
129
+ */
130
+ export interface DevSessionVerifierOptions {
131
+ /**
132
+ * The platform role to assign to the synthetic dev session.
133
+ * @default 'owner'
134
+ */
135
+ role?: SoulcraftSessionUser['platformRole'];
136
+ /**
137
+ * Email address for the synthetic dev user.
138
+ * @default 'dev@soulcraft.com'
139
+ */
140
+ email?: string;
141
+ /**
142
+ * Display name for the synthetic dev user.
143
+ * @default 'Dev User'
144
+ */
145
+ name?: string;
146
+ }
147
+ /**
148
+ * Options for `createRequestDevLoginHandler()`.
149
+ */
150
+ export interface DevLoginHandlerOptions {
151
+ /**
152
+ * Allowed platform roles. The role must be in this list for the handler to
153
+ * issue a session cookie. Defaults to all non-guest platform roles.
154
+ * @default ['creator','viewer','customer','staff','manager','owner','learner','instructor']
155
+ */
156
+ allowedRoles?: SoulcraftSessionUser['platformRole'][];
157
+ /**
158
+ * Cookie name for the issued dev session.
159
+ * @default 'soulcraft_dev_session'
160
+ */
161
+ cookieName?: string;
162
+ /**
163
+ * Session cookie max-age in seconds.
164
+ * @default 86400 (24 hours)
165
+ */
166
+ maxAgeSeconds?: number;
167
+ }
168
+ /**
169
+ * Options for `createRequestGuestSessionHandler()`.
170
+ */
171
+ export interface GuestSessionHandlerOptions {
172
+ /**
173
+ * Cookie name for the issued guest session.
174
+ * @default 'soulcraft_guest_session'
175
+ */
176
+ cookieName?: string;
177
+ /**
178
+ * Guest session max-age in seconds.
179
+ * @default 3600 (1 hour)
180
+ */
181
+ maxAgeSeconds?: number;
182
+ /**
183
+ * An optional callback invoked when a new guest session is created.
184
+ * Receives the generated guest ID. Useful for analytics or initializing
185
+ * a guest cart/basket in the product's store.
186
+ *
187
+ * @param guestId - The newly generated unique guest ID.
188
+ */
189
+ onGuestCreated?: (guestId: string) => Promise<void> | void;
190
+ }
191
+ /**
192
+ * @description A framework-agnostic middleware function that processes a Web Standard
193
+ * Request and either calls the next handler or short-circuits with its own Response.
194
+ */
195
+ export type RequestMiddleware = (req: Request, next: () => Promise<Response>) => Promise<Response>;
196
+ /**
197
+ * @description The object returned by `createRequestAuthMiddleware()`.
198
+ * Provides `requireAuth` and `optionalAuth` middleware using pure Request/Response.
199
+ */
200
+ export interface RequestAuthMiddleware {
201
+ /**
202
+ * Require authentication. Resolves the session from request cookies. If the
203
+ * session is valid, attaches the typed user to the request via WeakMap and
204
+ * calls `next()`. Returns HTTP 401 JSON response if unauthenticated.
205
+ */
206
+ requireAuth: RequestMiddleware;
207
+ /**
208
+ * Optional authentication. Resolves the session if one exists, but does not
209
+ * reject unauthenticated requests. User will be `null` for anonymous requests.
210
+ */
211
+ optionalAuth: RequestMiddleware;
212
+ }
213
+ /**
214
+ * @description Retrieves the resolved Soulcraft user attached to a Request by
215
+ * the request auth middleware.
216
+ *
217
+ * Returns the `SoulcraftSessionUser` if the request was authenticated, `null` if
218
+ * the request passed through `optionalAuth` without a session, or `null` if no
219
+ * middleware has processed this request.
220
+ *
221
+ * @param req - The Web Standard Request that was processed by middleware.
222
+ * @returns The resolved user, or null if unauthenticated or not yet processed.
223
+ *
224
+ * @example
225
+ * ```typescript
226
+ * const response = await requireAuth(request, async () => {
227
+ * const user = getUser(request)!
228
+ * return new Response(`Hello ${user.name}`)
229
+ * })
230
+ * ```
231
+ */
232
+ export declare function getUser(req: Request): SoulcraftSessionUser | null;
233
+ /**
234
+ * Creates a cached remote session verifier that proxies session lookups to
235
+ * the central IdP at `auth.soulcraft.com`.
236
+ *
237
+ * Used by products that operate as OIDC clients (Venue, Academy, and Workshop
238
+ * in production). Caches successful lookups in an LRU cache to avoid per-request
239
+ * HTTP round-trips to the IdP.
240
+ *
241
+ * The verifier sends the cookie header to the IdP's `/api/auth/get-session` endpoint
242
+ * and returns the resolved `SoulcraftSession` or `null` if the session is invalid.
243
+ *
244
+ * Pass the returned function to `createRequestAuthMiddleware`:
245
+ * ```typescript
246
+ * const verifySession = createRemoteSessionVerifier({ idpUrl: process.env.SOULCRAFT_IDP_URL! })
247
+ * const { requireAuth } = createRequestAuthMiddleware(verifySession)
248
+ * ```
249
+ *
250
+ * @param options - IdP URL, cache TTL, and max cache size.
251
+ * @returns A `SessionVerifier` — async function that accepts a cookie header string.
252
+ *
253
+ * @example
254
+ * ```typescript
255
+ * const verifySession = createRemoteSessionVerifier({
256
+ * idpUrl: 'https://auth.soulcraft.com',
257
+ * cacheTtlMs: 30_000,
258
+ * })
259
+ *
260
+ * const session = await verifySession(request.headers.get('cookie') ?? '')
261
+ * if (!session) return new Response('Unauthorized', { status: 401 })
262
+ * ```
263
+ */
264
+ export declare function createRemoteSessionVerifier(options: RemoteSessionVerifierOptions): SessionVerifier;
265
+ /**
266
+ * Creates a session verifier that always resolves to a synthetic dev session.
267
+ *
268
+ * Intended for products that run as OIDC clients but need local development auth
269
+ * without OAuth, network calls, SQLite, or real cookies. The returned verifier always
270
+ * succeeds — any request resolves to the configured synthetic user.
271
+ *
272
+ * Designed as a drop-in replacement for `createRemoteSessionVerifier` in local dev:
273
+ *
274
+ * ```typescript
275
+ * const verifySession = process.env.SOULCRAFT_IDP_URL
276
+ * ? createRemoteSessionVerifier({ idpUrl: process.env.SOULCRAFT_IDP_URL })
277
+ * : createDevSessionVerifier({ role: 'owner' })
278
+ *
279
+ * const { requireAuth } = createRequestAuthMiddleware(verifySession)
280
+ * ```
281
+ *
282
+ * **Never use in production.** The verifier performs no validation whatsoever.
283
+ *
284
+ * @param options - Optional synthetic user configuration.
285
+ * @returns A `SessionVerifier` with the same signature as `createRemoteSessionVerifier`.
286
+ *
287
+ * @example
288
+ * ```typescript
289
+ * const verifySession = process.env.SOULCRAFT_IDP_URL
290
+ * ? createRemoteSessionVerifier({ idpUrl: process.env.SOULCRAFT_IDP_URL })
291
+ * : createDevSessionVerifier({ role: 'owner' })
292
+ *
293
+ * export const handle = async ({ event, resolve }) => {
294
+ * const session = await verifySession(event.request.headers.get('cookie') ?? '')
295
+ * event.locals.session = session
296
+ * return resolve(event)
297
+ * }
298
+ * ```
299
+ */
300
+ export declare function createDevSessionVerifier(options?: DevSessionVerifierOptions): SessionVerifier;
301
+ /**
302
+ * Creates a session verifier that reads the cookie issued by `createRequestDevLoginHandler`.
303
+ *
304
+ * Use this together with `createRequestDevLoginHandler` when you want dev role-switching
305
+ * (e.g. clicking "Login as Staff" in a dev UI) rather than a fixed synthetic user.
306
+ *
307
+ * The verifier decodes the base64url cookie value and returns the embedded session.
308
+ * Falls back to `null` (unauthenticated) if the cookie is absent or expired.
309
+ *
310
+ * ```typescript
311
+ * // Only one of these in dev — pick what fits your workflow:
312
+ *
313
+ * // Option A: Fixed dev user, no login UI needed
314
+ * const verifySession = createDevSessionVerifier({ role: 'owner' })
315
+ *
316
+ * // Option B: Role-switching dev login UI
317
+ * const loginHandler = createRequestDevLoginHandler({ allowedRoles: ['owner', 'staff', 'customer'] })
318
+ * const verifySession = createDevCookieVerifier()
319
+ * ```
320
+ *
321
+ * @param cookieName - Must match the `cookieName` passed to `createRequestDevLoginHandler`. Default: `'soulcraft_dev_session'`.
322
+ * @returns A `SessionVerifier` compatible with `createRequestAuthMiddleware`.
323
+ */
324
+ export declare function createDevCookieVerifier(cookieName?: string): SessionVerifier;
325
+ /**
326
+ * Creates a session verifier that reads the cookie issued by `createRequestGuestSessionHandler`.
327
+ *
328
+ * Returns the guest `SoulcraftSession` or `null` if no valid guest cookie is present.
329
+ * Compose with `createRemoteSessionVerifier` to allow both authenticated and guest access:
330
+ *
331
+ * ```typescript
332
+ * const verifyReal = createRemoteSessionVerifier({ idpUrl: process.env.SOULCRAFT_IDP_URL! })
333
+ * const verifyGuest = createGuestCookieVerifier()
334
+ *
335
+ * const { optionalAuth } = createRequestAuthMiddleware(async (cookie) =>
336
+ * await verifyReal(cookie) ?? await verifyGuest(cookie)
337
+ * )
338
+ * ```
339
+ *
340
+ * @param cookieName - Must match the `cookieName` passed to `createRequestGuestSessionHandler`. Default: `'soulcraft_guest_session'`.
341
+ * @returns A `SessionVerifier` compatible with `createRequestAuthMiddleware`.
342
+ */
343
+ export declare function createGuestCookieVerifier(cookieName?: string): SessionVerifier;
344
+ /**
345
+ * @description Creates framework-agnostic auth middleware from a `SessionVerifier`
346
+ * function or a `BetterAuthLike` instance.
347
+ *
348
+ * Uses `WeakMap<Request, User>` to attach the resolved user to the request.
349
+ * Retrieve the resolved user after middleware with `getUser(req)`.
350
+ *
351
+ * **Preferred form (all products in OIDC-client mode):**
352
+ * Pass a `SessionVerifier` returned by `createRemoteSessionVerifier` or
353
+ * `createDevSessionVerifier`. The middleware reads the request cookie header and
354
+ * passes it to the verifier.
355
+ *
356
+ * **Legacy form (Workshop standalone mode):**
357
+ * Pass a `better-auth` instance directly. The middleware calls `auth.api.getSession`.
358
+ * In non-production environments and when `devAutoLogin` is enabled, a synthetic dev
359
+ * user is injected on failed lookups so local dev works without OAuth.
360
+ *
361
+ * @param authOrVerifier - A `better-auth` instance or a `SessionVerifier` function.
362
+ * @param options - Optional middleware configuration (only applies to `BetterAuthLike` form).
363
+ * @returns Middleware pair: `{ requireAuth, optionalAuth }`.
364
+ *
365
+ * @example Verifier form (Venue / Academy / Workshop in OIDC mode)
366
+ * ```typescript
367
+ * const verifySession = createRemoteSessionVerifier({ idpUrl: process.env.SOULCRAFT_IDP_URL! })
368
+ * const { requireAuth } = createRequestAuthMiddleware(verifySession)
369
+ *
370
+ * // Use in any server:
371
+ * const response = await requireAuth(request, () => handler(request))
372
+ * const user = getUser(request)!
373
+ * ```
374
+ *
375
+ * @example BetterAuth form (Workshop dev standalone)
376
+ * ```typescript
377
+ * import { auth } from './better-auth.js'
378
+ * const { requireAuth } = createRequestAuthMiddleware(auth)
379
+ * ```
380
+ */
381
+ export declare function createRequestAuthMiddleware(authOrVerifier: BetterAuthLike | SessionVerifier, options?: AuthMiddlewareOptions): RequestAuthMiddleware;
382
+ /**
383
+ * @description Creates a framework-agnostic request handler for a dev login endpoint.
384
+ *
385
+ * Mount at `/api/dev/login` to get a role-switching endpoint for local development.
386
+ * Accepts `?role=<platformRole>` and optional `?email=` / `?name=` / `?redirect=`
387
+ * query params. Issues a base64url session cookie and returns an HTTP 302 redirect.
388
+ *
389
+ * **Guards against production use:** the handler returns HTTP 404 when
390
+ * `NODE_ENV === 'production'` — safe to leave mounted in all environments.
391
+ *
392
+ * @param options - Allowed roles, cookie name, and max-age.
393
+ * @returns A request handler function `(req: Request) => Response`.
394
+ *
395
+ * @example
396
+ * ```typescript
397
+ * import { createRequestDevLoginHandler } from '@soulcraft/sdk/server'
398
+ *
399
+ * const devLogin = createRequestDevLoginHandler({ allowedRoles: ['owner', 'staff', 'customer'] })
400
+ *
401
+ * // SvelteKit: export const GET = ({ request }) => devLogin(request)
402
+ * // Bun: if (url.pathname === '/api/dev/login') return devLogin(req)
403
+ *
404
+ * // Usage: GET /api/dev/login?role=staff → sets cookie + redirects to /
405
+ * ```
406
+ */
407
+ export declare function createRequestDevLoginHandler(options?: DevLoginHandlerOptions): (req: Request) => Response;
408
+ /**
409
+ * @description Creates a framework-agnostic request handler that issues a guest
410
+ * session cookie.
411
+ *
412
+ * Venue visitors can browse and initiate bookings without creating an account.
413
+ * Mount at e.g. `/api/guest/session` to issue a session cookie with
414
+ * `platformRole: 'guest'` and a unique guest ID on each call (if no valid guest
415
+ * session already exists).
416
+ *
417
+ * The guest session cookie can be verified using `createGuestCookieVerifier`,
418
+ * which returns a `SessionVerifier` compatible with `createRequestAuthMiddleware`.
419
+ *
420
+ * @param options - Cookie name, max-age, and optional `onGuestCreated` callback.
421
+ * @returns An async request handler function `(req: Request) => Promise<Response>`.
422
+ *
423
+ * @example
424
+ * ```typescript
425
+ * import { createRequestGuestSessionHandler, createGuestCookieVerifier } from '@soulcraft/sdk/server'
426
+ *
427
+ * const guestSession = createRequestGuestSessionHandler({
428
+ * onGuestCreated: async (guestId) => {
429
+ * await db.guests.insert({ id: guestId, createdAt: new Date() })
430
+ * },
431
+ * })
432
+ *
433
+ * // SvelteKit: export const POST = ({ request }) => guestSession(request)
434
+ * // Bun: if (url.pathname === '/api/guest/session') return guestSession(req)
435
+ * ```
436
+ */
437
+ export declare function createRequestGuestSessionHandler(options?: GuestSessionHandlerOptions): (req: Request) => Promise<Response>;
438
+ //# sourceMappingURL=request-middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-middleware.d.ts","sourceRoot":"","sources":["../../../src/modules/auth/request-middleware.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8EG;AAIH,OAAO,KAAK,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAMxE,iEAAiE;AACjE,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE;QACH,UAAU,CAAC,IAAI,EAAE;YAAE,OAAO,EAAE,OAAO,CAAA;SAAE,GAAG,OAAO,CAAC;YAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;YAAC,OAAO,EAAE;gBAAE,EAAE,EAAE,MAAM,CAAC;gBAAC,SAAS,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,CAAA;aAAE,CAAA;SAAE,GAAG,IAAI,CAAC,CAAA;KACtJ,CAAA;CACF;AAED;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAAA;AAExF;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,OAAO,CAAA;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,4BAA4B;IAC3C,qEAAqE;IACrE,MAAM,EAAE,MAAM,CAAA;IACd,uEAAuE;IACvE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC;;;OAGG;IACH,IAAI,CAAC,EAAE,oBAAoB,CAAC,cAAc,CAAC,CAAA;IAC3C;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAA;CACd;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;;OAIG;IACH,YAAY,CAAC,EAAE,oBAAoB,CAAC,cAAc,CAAC,EAAE,CAAA;IACrD;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;CAC3D;AAED;;;GAGG;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,OAAO,CAAC,QAAQ,CAAC,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAA;AAElG;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC;;;;OAIG;IACH,WAAW,EAAE,iBAAiB,CAAA;IAE9B;;;OAGG;IACH,YAAY,EAAE,iBAAiB,CAAA;CAChC;AASD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,OAAO,CAAC,GAAG,EAAE,OAAO,GAAG,oBAAoB,GAAG,IAAI,CAEjE;AAsDD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,4BAA4B,GACpC,eAAe,CAkEjB;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,GAAE,yBAA8B,GACtC,eAAe,CAsBjB;AAMD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,uBAAuB,CACrC,UAAU,SAA0B,GACnC,eAAe,CAMjB;AAMD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,yBAAyB,CACvC,UAAU,SAA4B,GACrC,eAAe,CAMjB;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAgB,2BAA2B,CACzC,cAAc,EAAE,cAAc,GAAG,eAAe,EAChD,OAAO,GAAE,qBAA0B,GAClC,qBAAqB,CA8EvB;AAMD;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,wBAAgB,4BAA4B,CAC1C,OAAO,GAAE,sBAA2B,GACnC,CAAC,GAAG,EAAE,OAAO,KAAK,QAAQ,CAiE5B;AAMD;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,gCAAgC,CAC9C,OAAO,GAAE,0BAA+B,GACvC,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAuDrC"}