@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,650 @@
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 { LRUCache } from 'lru-cache';
81
+ import { computeEmailHash } from './config.js';
82
+ // ─────────────────────────────────────────────────────────────────────────────
83
+ // WeakMap user storage
84
+ // ─────────────────────────────────────────────────────────────────────────────
85
+ /** Internal WeakMap that associates a Request with its resolved user. */
86
+ const userMap = new WeakMap();
87
+ /**
88
+ * @description Retrieves the resolved Soulcraft user attached to a Request by
89
+ * the request auth middleware.
90
+ *
91
+ * Returns the `SoulcraftSessionUser` if the request was authenticated, `null` if
92
+ * the request passed through `optionalAuth` without a session, or `null` if no
93
+ * middleware has processed this request.
94
+ *
95
+ * @param req - The Web Standard Request that was processed by middleware.
96
+ * @returns The resolved user, or null if unauthenticated or not yet processed.
97
+ *
98
+ * @example
99
+ * ```typescript
100
+ * const response = await requireAuth(request, async () => {
101
+ * const user = getUser(request)!
102
+ * return new Response(`Hello ${user.name}`)
103
+ * })
104
+ * ```
105
+ */
106
+ export function getUser(req) {
107
+ return userMap.get(req) ?? null;
108
+ }
109
+ // ─────────────────────────────────────────────────────────────────────────────
110
+ // Shared internal helpers
111
+ // ─────────────────────────────────────────────────────────────────────────────
112
+ /** Resolve a raw user record from a better-auth session into a `SoulcraftSessionUser`. */
113
+ function _resolveUser(raw) {
114
+ const email = String(raw['email'] ?? '');
115
+ const emailHash = raw['emailHash']
116
+ ? String(raw['emailHash'])
117
+ : computeEmailHash(email);
118
+ return {
119
+ id: String(raw['id'] ?? ''),
120
+ email,
121
+ name: String(raw['name'] ?? ''),
122
+ image: raw['image'] ?? null,
123
+ platformRole: raw['platformRole'] ?? 'creator',
124
+ emailHash,
125
+ ...(raw['handle'] ? { handle: String(raw['handle']) } : {}),
126
+ };
127
+ }
128
+ /** Parse a simple `name=value` cookie from a raw cookie header string. */
129
+ function _parseCookie(cookieHeader, name) {
130
+ for (const part of cookieHeader.split(';')) {
131
+ const [k, ...rest] = part.trim().split('=');
132
+ if (k?.trim() === name)
133
+ return rest.join('=').trim();
134
+ }
135
+ return undefined;
136
+ }
137
+ /** Encode a dev/guest session payload as a compact JSON+base64url string (unsigned). */
138
+ function _encodeSessionCookie(session) {
139
+ return Buffer.from(JSON.stringify(session)).toString('base64url');
140
+ }
141
+ /** Decode a session payload encoded by `_encodeSessionCookie`. Returns null on any error. */
142
+ function _decodeSessionCookie(value) {
143
+ try {
144
+ const raw = JSON.parse(Buffer.from(value, 'base64url').toString('utf-8'));
145
+ if (!raw.user || !raw.sessionId || !raw.expiresAt)
146
+ return null;
147
+ if (raw.expiresAt < Date.now())
148
+ return null;
149
+ return raw;
150
+ }
151
+ catch {
152
+ return null;
153
+ }
154
+ }
155
+ // ─────────────────────────────────────────────────────────────────────────────
156
+ // createRemoteSessionVerifier
157
+ // ─────────────────────────────────────────────────────────────────────────────
158
+ /**
159
+ * Creates a cached remote session verifier that proxies session lookups to
160
+ * the central IdP at `auth.soulcraft.com`.
161
+ *
162
+ * Used by products that operate as OIDC clients (Venue, Academy, and Workshop
163
+ * in production). Caches successful lookups in an LRU cache to avoid per-request
164
+ * HTTP round-trips to the IdP.
165
+ *
166
+ * The verifier sends the cookie header to the IdP's `/api/auth/get-session` endpoint
167
+ * and returns the resolved `SoulcraftSession` or `null` if the session is invalid.
168
+ *
169
+ * Pass the returned function to `createRequestAuthMiddleware`:
170
+ * ```typescript
171
+ * const verifySession = createRemoteSessionVerifier({ idpUrl: process.env.SOULCRAFT_IDP_URL! })
172
+ * const { requireAuth } = createRequestAuthMiddleware(verifySession)
173
+ * ```
174
+ *
175
+ * @param options - IdP URL, cache TTL, and max cache size.
176
+ * @returns A `SessionVerifier` — async function that accepts a cookie header string.
177
+ *
178
+ * @example
179
+ * ```typescript
180
+ * const verifySession = createRemoteSessionVerifier({
181
+ * idpUrl: 'https://auth.soulcraft.com',
182
+ * cacheTtlMs: 30_000,
183
+ * })
184
+ *
185
+ * const session = await verifySession(request.headers.get('cookie') ?? '')
186
+ * if (!session) return new Response('Unauthorized', { status: 401 })
187
+ * ```
188
+ */
189
+ export function createRemoteSessionVerifier(options) {
190
+ const cacheTtl = options.cacheTtlMs ?? 30_000;
191
+ const cacheMax = options.cacheMax ?? 500;
192
+ const sessionUrl = `${options.idpUrl.replace(/\/$/, '')}/api/auth/get-session`;
193
+ const cache = new LRUCache({
194
+ max: cacheMax,
195
+ ttl: cacheTtl,
196
+ });
197
+ return async function verifyRemoteSession(cookieHeader) {
198
+ if (!cookieHeader)
199
+ return null;
200
+ // Use cookie header as cache key — it contains the session token
201
+ const cached = cache.get(cookieHeader);
202
+ if (cached !== undefined)
203
+ return cached;
204
+ let response;
205
+ try {
206
+ response = await fetch(sessionUrl, {
207
+ headers: { cookie: cookieHeader },
208
+ credentials: 'include',
209
+ });
210
+ }
211
+ catch {
212
+ return null;
213
+ }
214
+ if (!response.ok)
215
+ return null;
216
+ let data;
217
+ try {
218
+ data = await response.json();
219
+ }
220
+ catch {
221
+ return null;
222
+ }
223
+ // `get-session` returns the JSON literal `null` when no session is active.
224
+ // The fetch succeeds (200 OK) and `response.json()` parses it without error,
225
+ // but `data` is null — not an object. Guard before any property access.
226
+ if (!data || typeof data !== 'object')
227
+ return null;
228
+ const rawUser = data['user'];
229
+ const rawSession = data['session'];
230
+ if (!rawUser || !rawSession)
231
+ return null;
232
+ const email = String(rawUser['email'] ?? '');
233
+ const session = {
234
+ user: {
235
+ id: String(rawUser['id'] ?? ''),
236
+ email,
237
+ name: String(rawUser['name'] ?? ''),
238
+ image: rawUser['image'] ?? null,
239
+ platformRole: rawUser['platformRole'] ?? 'creator',
240
+ emailHash: rawUser['emailHash'] ? String(rawUser['emailHash']) : computeEmailHash(email),
241
+ ...(rawUser['handle'] ? { handle: String(rawUser['handle']) } : {}),
242
+ },
243
+ sessionId: String(rawSession['id'] ?? ''),
244
+ expiresAt: Number(rawSession['expiresAt'] ?? 0),
245
+ };
246
+ cache.set(cookieHeader, session);
247
+ return session;
248
+ };
249
+ }
250
+ // ─────────────────────────────────────────────────────────────────────────────
251
+ // createDevSessionVerifier
252
+ // ─────────────────────────────────────────────────────────────────────────────
253
+ /**
254
+ * Creates a session verifier that always resolves to a synthetic dev session.
255
+ *
256
+ * Intended for products that run as OIDC clients but need local development auth
257
+ * without OAuth, network calls, SQLite, or real cookies. The returned verifier always
258
+ * succeeds — any request resolves to the configured synthetic user.
259
+ *
260
+ * Designed as a drop-in replacement for `createRemoteSessionVerifier` in local dev:
261
+ *
262
+ * ```typescript
263
+ * const verifySession = process.env.SOULCRAFT_IDP_URL
264
+ * ? createRemoteSessionVerifier({ idpUrl: process.env.SOULCRAFT_IDP_URL })
265
+ * : createDevSessionVerifier({ role: 'owner' })
266
+ *
267
+ * const { requireAuth } = createRequestAuthMiddleware(verifySession)
268
+ * ```
269
+ *
270
+ * **Never use in production.** The verifier performs no validation whatsoever.
271
+ *
272
+ * @param options - Optional synthetic user configuration.
273
+ * @returns A `SessionVerifier` with the same signature as `createRemoteSessionVerifier`.
274
+ *
275
+ * @example
276
+ * ```typescript
277
+ * const verifySession = process.env.SOULCRAFT_IDP_URL
278
+ * ? createRemoteSessionVerifier({ idpUrl: process.env.SOULCRAFT_IDP_URL })
279
+ * : createDevSessionVerifier({ role: 'owner' })
280
+ *
281
+ * export const handle = async ({ event, resolve }) => {
282
+ * const session = await verifySession(event.request.headers.get('cookie') ?? '')
283
+ * event.locals.session = session
284
+ * return resolve(event)
285
+ * }
286
+ * ```
287
+ */
288
+ export function createDevSessionVerifier(options = {}) {
289
+ const role = options.role ?? 'owner';
290
+ const email = options.email ?? 'dev@soulcraft.com';
291
+ const name = options.name ?? 'Dev User';
292
+ const session = {
293
+ user: {
294
+ id: 'dev-user-001',
295
+ email,
296
+ name,
297
+ image: null,
298
+ platformRole: role,
299
+ emailHash: computeEmailHash(email),
300
+ handle: 'dev',
301
+ },
302
+ sessionId: 'dev-session-001',
303
+ expiresAt: Date.now() + 30 * 24 * 60 * 60 * 1000,
304
+ };
305
+ return async function verifyDevSession() {
306
+ return session;
307
+ };
308
+ }
309
+ // ─────────────────────────────────────────────────────────────────────────────
310
+ // createDevCookieVerifier
311
+ // ─────────────────────────────────────────────────────────────────────────────
312
+ /**
313
+ * Creates a session verifier that reads the cookie issued by `createRequestDevLoginHandler`.
314
+ *
315
+ * Use this together with `createRequestDevLoginHandler` when you want dev role-switching
316
+ * (e.g. clicking "Login as Staff" in a dev UI) rather than a fixed synthetic user.
317
+ *
318
+ * The verifier decodes the base64url cookie value and returns the embedded session.
319
+ * Falls back to `null` (unauthenticated) if the cookie is absent or expired.
320
+ *
321
+ * ```typescript
322
+ * // Only one of these in dev — pick what fits your workflow:
323
+ *
324
+ * // Option A: Fixed dev user, no login UI needed
325
+ * const verifySession = createDevSessionVerifier({ role: 'owner' })
326
+ *
327
+ * // Option B: Role-switching dev login UI
328
+ * const loginHandler = createRequestDevLoginHandler({ allowedRoles: ['owner', 'staff', 'customer'] })
329
+ * const verifySession = createDevCookieVerifier()
330
+ * ```
331
+ *
332
+ * @param cookieName - Must match the `cookieName` passed to `createRequestDevLoginHandler`. Default: `'soulcraft_dev_session'`.
333
+ * @returns A `SessionVerifier` compatible with `createRequestAuthMiddleware`.
334
+ */
335
+ export function createDevCookieVerifier(cookieName = 'soulcraft_dev_session') {
336
+ return async function verifyDevCookie(cookieHeader) {
337
+ const value = _parseCookie(cookieHeader, cookieName);
338
+ if (!value)
339
+ return null;
340
+ return _decodeSessionCookie(value);
341
+ };
342
+ }
343
+ // ─────────────────────────────────────────────────────────────────────────────
344
+ // createGuestCookieVerifier
345
+ // ─────────────────────────────────────────────────────────────────────────────
346
+ /**
347
+ * Creates a session verifier that reads the cookie issued by `createRequestGuestSessionHandler`.
348
+ *
349
+ * Returns the guest `SoulcraftSession` or `null` if no valid guest cookie is present.
350
+ * Compose with `createRemoteSessionVerifier` to allow both authenticated and guest access:
351
+ *
352
+ * ```typescript
353
+ * const verifyReal = createRemoteSessionVerifier({ idpUrl: process.env.SOULCRAFT_IDP_URL! })
354
+ * const verifyGuest = createGuestCookieVerifier()
355
+ *
356
+ * const { optionalAuth } = createRequestAuthMiddleware(async (cookie) =>
357
+ * await verifyReal(cookie) ?? await verifyGuest(cookie)
358
+ * )
359
+ * ```
360
+ *
361
+ * @param cookieName - Must match the `cookieName` passed to `createRequestGuestSessionHandler`. Default: `'soulcraft_guest_session'`.
362
+ * @returns A `SessionVerifier` compatible with `createRequestAuthMiddleware`.
363
+ */
364
+ export function createGuestCookieVerifier(cookieName = 'soulcraft_guest_session') {
365
+ return async function verifyGuestCookie(cookieHeader) {
366
+ const value = _parseCookie(cookieHeader, cookieName);
367
+ if (!value)
368
+ return null;
369
+ return _decodeSessionCookie(value);
370
+ };
371
+ }
372
+ // ─────────────────────────────────────────────────────────────────────────────
373
+ // createRequestAuthMiddleware
374
+ // ─────────────────────────────────────────────────────────────────────────────
375
+ /**
376
+ * @description Creates framework-agnostic auth middleware from a `SessionVerifier`
377
+ * function or a `BetterAuthLike` instance.
378
+ *
379
+ * Uses `WeakMap<Request, User>` to attach the resolved user to the request.
380
+ * Retrieve the resolved user after middleware with `getUser(req)`.
381
+ *
382
+ * **Preferred form (all products in OIDC-client mode):**
383
+ * Pass a `SessionVerifier` returned by `createRemoteSessionVerifier` or
384
+ * `createDevSessionVerifier`. The middleware reads the request cookie header and
385
+ * passes it to the verifier.
386
+ *
387
+ * **Legacy form (Workshop standalone mode):**
388
+ * Pass a `better-auth` instance directly. The middleware calls `auth.api.getSession`.
389
+ * In non-production environments and when `devAutoLogin` is enabled, a synthetic dev
390
+ * user is injected on failed lookups so local dev works without OAuth.
391
+ *
392
+ * @param authOrVerifier - A `better-auth` instance or a `SessionVerifier` function.
393
+ * @param options - Optional middleware configuration (only applies to `BetterAuthLike` form).
394
+ * @returns Middleware pair: `{ requireAuth, optionalAuth }`.
395
+ *
396
+ * @example Verifier form (Venue / Academy / Workshop in OIDC mode)
397
+ * ```typescript
398
+ * const verifySession = createRemoteSessionVerifier({ idpUrl: process.env.SOULCRAFT_IDP_URL! })
399
+ * const { requireAuth } = createRequestAuthMiddleware(verifySession)
400
+ *
401
+ * // Use in any server:
402
+ * const response = await requireAuth(request, () => handler(request))
403
+ * const user = getUser(request)!
404
+ * ```
405
+ *
406
+ * @example BetterAuth form (Workshop dev standalone)
407
+ * ```typescript
408
+ * import { auth } from './better-auth.js'
409
+ * const { requireAuth } = createRequestAuthMiddleware(auth)
410
+ * ```
411
+ */
412
+ export function createRequestAuthMiddleware(authOrVerifier, options = {}) {
413
+ const isVerifier = typeof authOrVerifier === 'function';
414
+ if (isVerifier) {
415
+ const verify = authOrVerifier;
416
+ const requireAuth = async (req, next) => {
417
+ const cookieHeader = req.headers.get('cookie') ?? '';
418
+ const session = await verify(cookieHeader);
419
+ if (!session) {
420
+ return new Response(JSON.stringify({ error: 'Authentication required' }), {
421
+ status: 401,
422
+ headers: { 'Content-Type': 'application/json' },
423
+ });
424
+ }
425
+ userMap.set(req, session.user);
426
+ return next();
427
+ };
428
+ const optionalAuth = async (req, next) => {
429
+ const cookieHeader = req.headers.get('cookie') ?? '';
430
+ const session = await verify(cookieHeader);
431
+ userMap.set(req, session?.user ?? null);
432
+ return next();
433
+ };
434
+ return { requireAuth, optionalAuth };
435
+ }
436
+ // BetterAuthLike form (Workshop standalone)
437
+ const auth = authOrVerifier;
438
+ const devAutoLogin = options.devAutoLogin ?? true;
439
+ const isDev = process.env['NODE_ENV'] !== 'production';
440
+ const DEV_USER = {
441
+ id: 'dev-user-001',
442
+ email: 'dev@localhost',
443
+ name: 'Dev User',
444
+ image: null,
445
+ emailHash: computeEmailHash('dev@localhost'),
446
+ platformRole: 'creator',
447
+ handle: 'dev',
448
+ };
449
+ const requireAuth = async (req, next) => {
450
+ if (isDev && devAutoLogin) {
451
+ if (!userMap.has(req))
452
+ userMap.set(req, DEV_USER);
453
+ return next();
454
+ }
455
+ const session = await auth.api.getSession({ headers: req.headers });
456
+ if (!session?.user) {
457
+ return new Response(JSON.stringify({ error: 'Authentication required' }), {
458
+ status: 401,
459
+ headers: { 'Content-Type': 'application/json' },
460
+ });
461
+ }
462
+ userMap.set(req, _resolveUser(session.user));
463
+ return next();
464
+ };
465
+ const optionalAuth = async (req, next) => {
466
+ if (isDev && devAutoLogin) {
467
+ if (!userMap.has(req))
468
+ userMap.set(req, DEV_USER);
469
+ return next();
470
+ }
471
+ const session = await auth.api.getSession({ headers: req.headers });
472
+ if (session?.user) {
473
+ userMap.set(req, _resolveUser(session.user));
474
+ }
475
+ else {
476
+ userMap.set(req, null);
477
+ }
478
+ return next();
479
+ };
480
+ return { requireAuth, optionalAuth };
481
+ }
482
+ // ─────────────────────────────────────────────────────────────────────────────
483
+ // createRequestDevLoginHandler
484
+ // ─────────────────────────────────────────────────────────────────────────────
485
+ /**
486
+ * @description Creates a framework-agnostic request handler for a dev login endpoint.
487
+ *
488
+ * Mount at `/api/dev/login` to get a role-switching endpoint for local development.
489
+ * Accepts `?role=<platformRole>` and optional `?email=` / `?name=` / `?redirect=`
490
+ * query params. Issues a base64url session cookie and returns an HTTP 302 redirect.
491
+ *
492
+ * **Guards against production use:** the handler returns HTTP 404 when
493
+ * `NODE_ENV === 'production'` — safe to leave mounted in all environments.
494
+ *
495
+ * @param options - Allowed roles, cookie name, and max-age.
496
+ * @returns A request handler function `(req: Request) => Response`.
497
+ *
498
+ * @example
499
+ * ```typescript
500
+ * import { createRequestDevLoginHandler } from '@soulcraft/sdk/server'
501
+ *
502
+ * const devLogin = createRequestDevLoginHandler({ allowedRoles: ['owner', 'staff', 'customer'] })
503
+ *
504
+ * // SvelteKit: export const GET = ({ request }) => devLogin(request)
505
+ * // Bun: if (url.pathname === '/api/dev/login') return devLogin(req)
506
+ *
507
+ * // Usage: GET /api/dev/login?role=staff → sets cookie + redirects to /
508
+ * ```
509
+ */
510
+ export function createRequestDevLoginHandler(options = {}) {
511
+ const DEFAULT_ROLES = [
512
+ 'creator', 'viewer', 'customer', 'staff', 'manager', 'owner', 'learner', 'instructor',
513
+ ];
514
+ const allowedRoles = options.allowedRoles ?? DEFAULT_ROLES;
515
+ const cookieName = options.cookieName ?? 'soulcraft_dev_session';
516
+ const maxAgeSeconds = options.maxAgeSeconds ?? 86_400;
517
+ return function requestDevLoginHandler(req) {
518
+ if (process.env['NODE_ENV'] === 'production') {
519
+ return new Response(JSON.stringify({ error: 'Not found' }), {
520
+ status: 404,
521
+ headers: { 'Content-Type': 'application/json' },
522
+ });
523
+ }
524
+ const url = new URL(req.url);
525
+ const role = url.searchParams.get('role');
526
+ if (!role || !allowedRoles.includes(role)) {
527
+ return new Response(JSON.stringify({
528
+ error: `Invalid role. Allowed: ${allowedRoles.join(', ')}`,
529
+ allowedRoles,
530
+ }), {
531
+ status: 400,
532
+ headers: { 'Content-Type': 'application/json' },
533
+ });
534
+ }
535
+ const email = url.searchParams.get('email') ?? `dev-${role}@soulcraft.com`;
536
+ const name = url.searchParams.get('name') ?? `Dev ${role.charAt(0).toUpperCase() + role.slice(1)}`;
537
+ const redirect = url.searchParams.get('redirect') ?? '/';
538
+ const session = {
539
+ user: {
540
+ id: `dev-user-${role}`,
541
+ email,
542
+ name,
543
+ image: null,
544
+ platformRole: role,
545
+ emailHash: computeEmailHash(email),
546
+ },
547
+ sessionId: `dev-session-${Date.now()}`,
548
+ expiresAt: Date.now() + maxAgeSeconds * 1000,
549
+ };
550
+ const cookieValue = _encodeSessionCookie(session);
551
+ const cookieHeader = [
552
+ `${cookieName}=${cookieValue}`,
553
+ `Path=/`,
554
+ `HttpOnly`,
555
+ `SameSite=Lax`,
556
+ `Max-Age=${maxAgeSeconds}`,
557
+ ].join('; ');
558
+ return new Response(null, {
559
+ status: 302,
560
+ headers: {
561
+ Location: redirect,
562
+ 'Set-Cookie': cookieHeader,
563
+ },
564
+ });
565
+ };
566
+ }
567
+ // ─────────────────────────────────────────────────────────────────────────────
568
+ // createRequestGuestSessionHandler
569
+ // ─────────────────────────────────────────────────────────────────────────────
570
+ /**
571
+ * @description Creates a framework-agnostic request handler that issues a guest
572
+ * session cookie.
573
+ *
574
+ * Venue visitors can browse and initiate bookings without creating an account.
575
+ * Mount at e.g. `/api/guest/session` to issue a session cookie with
576
+ * `platformRole: 'guest'` and a unique guest ID on each call (if no valid guest
577
+ * session already exists).
578
+ *
579
+ * The guest session cookie can be verified using `createGuestCookieVerifier`,
580
+ * which returns a `SessionVerifier` compatible with `createRequestAuthMiddleware`.
581
+ *
582
+ * @param options - Cookie name, max-age, and optional `onGuestCreated` callback.
583
+ * @returns An async request handler function `(req: Request) => Promise<Response>`.
584
+ *
585
+ * @example
586
+ * ```typescript
587
+ * import { createRequestGuestSessionHandler, createGuestCookieVerifier } from '@soulcraft/sdk/server'
588
+ *
589
+ * const guestSession = createRequestGuestSessionHandler({
590
+ * onGuestCreated: async (guestId) => {
591
+ * await db.guests.insert({ id: guestId, createdAt: new Date() })
592
+ * },
593
+ * })
594
+ *
595
+ * // SvelteKit: export const POST = ({ request }) => guestSession(request)
596
+ * // Bun: if (url.pathname === '/api/guest/session') return guestSession(req)
597
+ * ```
598
+ */
599
+ export function createRequestGuestSessionHandler(options = {}) {
600
+ const cookieName = options.cookieName ?? 'soulcraft_guest_session';
601
+ const maxAgeSeconds = options.maxAgeSeconds ?? 3_600;
602
+ const onGuestCreated = options.onGuestCreated;
603
+ return async function requestGuestSessionHandler(req) {
604
+ // Return existing guest session if still valid
605
+ const cookieHeader = req.headers.get('cookie') ?? '';
606
+ const existingValue = _parseCookie(cookieHeader, cookieName);
607
+ if (existingValue) {
608
+ const existing = _decodeSessionCookie(existingValue);
609
+ if (existing) {
610
+ return new Response(JSON.stringify({ guestId: existing.user.id, existing: true }), {
611
+ status: 200,
612
+ headers: { 'Content-Type': 'application/json' },
613
+ });
614
+ }
615
+ }
616
+ // Create a new guest session
617
+ const guestId = `guest-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
618
+ const email = `${guestId}@guest.soulcraft.com`;
619
+ const session = {
620
+ user: {
621
+ id: guestId,
622
+ email,
623
+ name: 'Guest',
624
+ image: null,
625
+ platformRole: 'guest',
626
+ emailHash: computeEmailHash(email),
627
+ },
628
+ sessionId: `guest-session-${Date.now()}`,
629
+ expiresAt: Date.now() + maxAgeSeconds * 1000,
630
+ };
631
+ if (onGuestCreated)
632
+ await onGuestCreated(guestId);
633
+ const cookieValue = _encodeSessionCookie(session);
634
+ const setCookieHeader = [
635
+ `${cookieName}=${cookieValue}`,
636
+ `Path=/`,
637
+ `HttpOnly`,
638
+ `SameSite=Lax`,
639
+ `Max-Age=${maxAgeSeconds}`,
640
+ ].join('; ');
641
+ return new Response(JSON.stringify({ guestId, existing: false }), {
642
+ status: 200,
643
+ headers: {
644
+ 'Content-Type': 'application/json',
645
+ 'Set-Cookie': setCookieHeader,
646
+ },
647
+ });
648
+ };
649
+ }
650
+ //# sourceMappingURL=request-middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"request-middleware.js","sourceRoot":"","sources":["../../../src/modules/auth/request-middleware.ts"],"names":[],"mappings":"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"}