@syncular/server-hono 0.0.6-125 → 0.0.6-135

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.
@@ -0,0 +1,39 @@
1
+ export function parseBearerToken(
2
+ authHeader: string | null | undefined
3
+ ): string | null {
4
+ const value = authHeader?.trim();
5
+ if (!value?.startsWith('Bearer ')) {
6
+ return null;
7
+ }
8
+ const token = value.slice(7).trim();
9
+ return token.length > 0 ? token : null;
10
+ }
11
+
12
+ export function parseWebSocketAuthToken(data: string): string | null {
13
+ try {
14
+ const parsed = JSON.parse(data);
15
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
16
+ return null;
17
+ }
18
+ const payload = parsed as Record<string, unknown>;
19
+ if (payload.type !== 'auth' || typeof payload.token !== 'string') {
20
+ return null;
21
+ }
22
+ const token = payload.token.trim();
23
+ return token.length > 0 ? token : null;
24
+ } catch {
25
+ return null;
26
+ }
27
+ }
28
+
29
+ export function closeUnauthenticatedSocket(ws: {
30
+ send: (data: string) => void;
31
+ close: (code?: number, reason?: string) => void;
32
+ }): void {
33
+ try {
34
+ ws.send(JSON.stringify({ type: 'error', message: 'UNAUTHENTICATED' }));
35
+ } catch {
36
+ // ignore send errors
37
+ }
38
+ ws.close(4001, 'Unauthenticated');
39
+ }
@@ -30,6 +30,11 @@ import { cors } from 'hono/cors';
30
30
  import { describeRoute, resolver, validator as zValidator } from 'hono-openapi';
31
31
  import { type Generated, type Kysely, type Selectable, sql } from 'kysely';
32
32
  import { z } from 'zod';
33
+ import {
34
+ closeUnauthenticatedSocket,
35
+ parseBearerToken,
36
+ parseWebSocketAuthToken,
37
+ } from './live-auth';
33
38
  import {
34
39
  type ApiKeyType,
35
40
  ApiKeyTypeSchema,
@@ -414,8 +419,12 @@ export function createConsoleRoutes<
414
419
  DB extends SyncCoreDb,
415
420
  Auth extends SyncServerAuth,
416
421
  F extends SqlFamily = SqlFamily,
417
- >(options: CreateConsoleRoutesOptions<DB, Auth, F>): Hono {
418
- const routes = new Hono();
422
+ >(
423
+ options: CreateConsoleRoutesOptions<DB, Auth, F>
424
+ ): Hono<{ Variables: { consoleAuth: ConsoleAuthResult } }> {
425
+ const routes = new Hono<{
426
+ Variables: { consoleAuth: ConsoleAuthResult };
427
+ }>();
419
428
 
420
429
  routes.onError((error, context) => {
421
430
  const message =
@@ -592,14 +601,22 @@ export function createConsoleRoutes<
592
601
  await next();
593
602
  });
594
603
 
595
- // Auth middleware
596
- const requireAuth = async (c: Context): Promise<ConsoleAuthResult | null> => {
604
+ // Route auth middleware. Keep /events/live exempt to preserve websocket
605
+ // message-based auth handshake fallback when no Authorization header is sent.
606
+ routes.use('*', async (c, next) => {
607
+ if (c.req.method === 'OPTIONS' || c.req.path.endsWith('/events/live')) {
608
+ await next();
609
+ return;
610
+ }
611
+
597
612
  const auth = await options.authenticate(c);
598
613
  if (!auth) {
599
- return null;
614
+ return c.json({ error: 'UNAUTHENTICATED' }, 401);
600
615
  }
601
- return auth;
602
- };
616
+
617
+ c.set('consoleAuth', auth);
618
+ await next();
619
+ });
603
620
 
604
621
  const requestEventSelectColumns = [
605
622
  'event_id',
@@ -961,8 +978,6 @@ export function createConsoleRoutes<
961
978
  }),
962
979
  zValidator('query', ConsolePartitionQuerySchema),
963
980
  async (c) => {
964
- const auth = await requireAuth(c);
965
- if (!auth) return c.json({ error: 'UNAUTHENTICATED' }, 401);
966
981
  const { partitionId } = c.req.valid('query');
967
982
 
968
983
  const stats: SyncStats = await readSyncStats(options.db, {
@@ -971,7 +986,7 @@ export function createConsoleRoutes<
971
986
 
972
987
  logSyncEvent({
973
988
  event: 'console.stats',
974
- consoleUserId: auth.consoleUserId,
989
+ consoleUserId: c.var.consoleAuth.consoleUserId,
975
990
  });
976
991
 
977
992
  return c.json(stats, 200);
@@ -1006,9 +1021,6 @@ export function createConsoleRoutes<
1006
1021
  }),
1007
1022
  zValidator('query', TimeseriesQuerySchema),
1008
1023
  async (c) => {
1009
- const auth = await requireAuth(c);
1010
- if (!auth) return c.json({ error: 'UNAUTHENTICATED' }, 401);
1011
-
1012
1024
  const { interval, range, partitionId } = c.req.valid('query');
1013
1025
 
1014
1026
  const rangeMs = rangeToMs(range);
@@ -1205,9 +1217,6 @@ export function createConsoleRoutes<
1205
1217
  }),
1206
1218
  zValidator('query', LatencyQuerySchema),
1207
1219
  async (c) => {
1208
- const auth = await requireAuth(c);
1209
- if (!auth) return c.json({ error: 'UNAUTHENTICATED' }, 401);
1210
-
1211
1220
  const { range, partitionId } = c.req.valid('query');
1212
1221
 
1213
1222
  const rangeMs = rangeToMs(range);
@@ -1321,9 +1330,6 @@ export function createConsoleRoutes<
1321
1330
  }),
1322
1331
  zValidator('query', ConsoleTimelineQuerySchema),
1323
1332
  async (c) => {
1324
- const auth = await requireAuth(c);
1325
- if (!auth) return c.json({ error: 'UNAUTHENTICATED' }, 401);
1326
-
1327
1333
  const {
1328
1334
  limit,
1329
1335
  offset,
@@ -1553,9 +1559,6 @@ export function createConsoleRoutes<
1553
1559
  }),
1554
1560
  zValidator('query', ConsolePartitionedPaginationQuerySchema),
1555
1561
  async (c) => {
1556
- const auth = await requireAuth(c);
1557
- if (!auth) return c.json({ error: 'UNAUTHENTICATED' }, 401);
1558
-
1559
1562
  const { limit, offset, partitionId } = c.req.valid('query');
1560
1563
 
1561
1564
  let query = db
@@ -1651,9 +1654,6 @@ export function createConsoleRoutes<
1651
1654
  zValidator('param', commitSeqParamSchema),
1652
1655
  zValidator('query', commitDetailQuerySchema),
1653
1656
  async (c) => {
1654
- const auth = await requireAuth(c);
1655
- if (!auth) return c.json({ error: 'UNAUTHENTICATED' }, 401);
1656
-
1657
1657
  const { seq } = c.req.valid('param');
1658
1658
  const { partitionId } = c.req.valid('query');
1659
1659
 
@@ -1772,9 +1772,6 @@ export function createConsoleRoutes<
1772
1772
  }),
1773
1773
  zValidator('query', ConsolePartitionedPaginationQuerySchema),
1774
1774
  async (c) => {
1775
- const auth = await requireAuth(c);
1776
- if (!auth) return c.json({ error: 'UNAUTHENTICATED' }, 401);
1777
-
1778
1775
  const { limit, offset, partitionId } = c.req.valid('query');
1779
1776
 
1780
1777
  let clientsQuery = db
@@ -1940,9 +1937,6 @@ export function createConsoleRoutes<
1940
1937
  },
1941
1938
  }),
1942
1939
  async (c) => {
1943
- const auth = await requireAuth(c);
1944
- if (!auth) return c.json({ error: 'UNAUTHENTICATED' }, 401);
1945
-
1946
1940
  const items: ConsoleHandler[] = options.handlers.map((handler) => ({
1947
1941
  table: handler.table,
1948
1942
  dependsOn: handler.dependsOn,
@@ -1983,9 +1977,6 @@ export function createConsoleRoutes<
1983
1977
  }),
1984
1978
  zValidator('query', ConsoleOperationsQuerySchema),
1985
1979
  async (c) => {
1986
- const auth = await requireAuth(c);
1987
- if (!auth) return c.json({ error: 'UNAUTHENTICATED' }, 401);
1988
-
1989
1980
  const { limit, offset, operationType, partitionId } =
1990
1981
  c.req.valid('query');
1991
1982
 
@@ -2055,9 +2046,6 @@ export function createConsoleRoutes<
2055
2046
  },
2056
2047
  }),
2057
2048
  async (c) => {
2058
- const auth = await requireAuth(c);
2059
- if (!auth) return c.json({ error: 'UNAUTHENTICATED' }, 401);
2060
-
2061
2049
  const watermarkCommitSeq = await computePruneWatermarkCommitSeq(
2062
2050
  options.db,
2063
2051
  options.prune
@@ -2106,9 +2094,6 @@ export function createConsoleRoutes<
2106
2094
  },
2107
2095
  }),
2108
2096
  async (c) => {
2109
- const auth = await requireAuth(c);
2110
- if (!auth) return c.json({ error: 'UNAUTHENTICATED' }, 401);
2111
-
2112
2097
  const watermarkCommitSeq = await computePruneWatermarkCommitSeq(
2113
2098
  options.db,
2114
2099
  options.prune
@@ -2121,13 +2106,13 @@ export function createConsoleRoutes<
2121
2106
 
2122
2107
  logSyncEvent({
2123
2108
  event: 'console.prune',
2124
- consoleUserId: auth.consoleUserId,
2109
+ consoleUserId: c.var.consoleAuth.consoleUserId,
2125
2110
  deletedCommits,
2126
2111
  watermarkCommitSeq,
2127
2112
  });
2128
2113
  await recordOperationEvent({
2129
2114
  operationType: 'prune',
2130
- consoleUserId: auth.consoleUserId,
2115
+ consoleUserId: c.var.consoleAuth.consoleUserId,
2131
2116
  requestPayload: {
2132
2117
  watermarkCommitSeq,
2133
2118
  keepNewestCommits: options.prune?.keepNewestCommits ?? null,
@@ -2167,9 +2152,6 @@ export function createConsoleRoutes<
2167
2152
  },
2168
2153
  }),
2169
2154
  async (c) => {
2170
- const auth = await requireAuth(c);
2171
- if (!auth) return c.json({ error: 'UNAUTHENTICATED' }, 401);
2172
-
2173
2155
  const fullHistoryHours = options.compact?.fullHistoryHours ?? 24 * 7;
2174
2156
 
2175
2157
  const deletedChanges = await compactChanges(options.db, {
@@ -2179,13 +2161,13 @@ export function createConsoleRoutes<
2179
2161
 
2180
2162
  logSyncEvent({
2181
2163
  event: 'console.compact',
2182
- consoleUserId: auth.consoleUserId,
2164
+ consoleUserId: c.var.consoleAuth.consoleUserId,
2183
2165
  deletedChanges,
2184
2166
  fullHistoryHours,
2185
2167
  });
2186
2168
  await recordOperationEvent({
2187
2169
  operationType: 'compact',
2188
- consoleUserId: auth.consoleUserId,
2170
+ consoleUserId: c.var.consoleAuth.consoleUserId,
2189
2171
  requestPayload: { fullHistoryHours },
2190
2172
  resultPayload: { deletedChanges },
2191
2173
  });
@@ -2243,9 +2225,6 @@ export function createConsoleRoutes<
2243
2225
  }),
2244
2226
  zValidator('json', NotifyDataChangeRequestSchema),
2245
2227
  async (c) => {
2246
- const auth = await requireAuth(c);
2247
- if (!auth) return c.json({ error: 'UNAUTHENTICATED' }, 401);
2248
-
2249
2228
  const body = c.req.valid('json');
2250
2229
 
2251
2230
  const result = await notifyExternalDataChange({
@@ -2257,14 +2236,14 @@ export function createConsoleRoutes<
2257
2236
 
2258
2237
  logSyncEvent({
2259
2238
  event: 'console.notify_data_change',
2260
- consoleUserId: auth.consoleUserId,
2239
+ consoleUserId: c.var.consoleAuth.consoleUserId,
2261
2240
  tables: body.tables,
2262
2241
  commitSeq: result.commitSeq,
2263
2242
  deletedChunks: result.deletedChunks,
2264
2243
  });
2265
2244
  await recordOperationEvent({
2266
2245
  operationType: 'notify_data_change',
2267
- consoleUserId: auth.consoleUserId,
2246
+ consoleUserId: c.var.consoleAuth.consoleUserId,
2268
2247
  partitionId: body.partitionId ?? null,
2269
2248
  requestPayload: {
2270
2249
  tables: body.tables,
@@ -2315,9 +2294,6 @@ export function createConsoleRoutes<
2315
2294
  zValidator('param', clientIdParamSchema),
2316
2295
  zValidator('query', evictClientQuerySchema),
2317
2296
  async (c) => {
2318
- const auth = await requireAuth(c);
2319
- if (!auth) return c.json({ error: 'UNAUTHENTICATED' }, 401);
2320
-
2321
2297
  const { id: clientId } = c.req.valid('param');
2322
2298
  const { partitionId } = c.req.valid('query');
2323
2299
 
@@ -2335,13 +2311,13 @@ export function createConsoleRoutes<
2335
2311
 
2336
2312
  logSyncEvent({
2337
2313
  event: 'console.evict_client',
2338
- consoleUserId: auth.consoleUserId,
2314
+ consoleUserId: c.var.consoleAuth.consoleUserId,
2339
2315
  clientId,
2340
2316
  evicted,
2341
2317
  });
2342
2318
  await recordOperationEvent({
2343
2319
  operationType: 'evict_client',
2344
- consoleUserId: auth.consoleUserId,
2320
+ consoleUserId: c.var.consoleAuth.consoleUserId,
2345
2321
  partitionId: partitionId ?? null,
2346
2322
  targetClientId: clientId,
2347
2323
  requestPayload: { clientId, partitionId: partitionId ?? null },
@@ -2383,9 +2359,6 @@ export function createConsoleRoutes<
2383
2359
  }),
2384
2360
  zValidator('query', eventsQuerySchema),
2385
2361
  async (c) => {
2386
- const auth = await requireAuth(c);
2387
- if (!auth) return c.json({ error: 'UNAUTHENTICATED' }, 401);
2388
-
2389
2362
  const {
2390
2363
  limit,
2391
2364
  offset,
@@ -2488,18 +2461,10 @@ export function createConsoleRoutes<
2488
2461
  heartbeatInterval: ReturnType<typeof setInterval> | null;
2489
2462
  authTimeout: ReturnType<typeof setTimeout> | null;
2490
2463
  isAuthenticated: boolean;
2464
+ startAuthenticatedSession: (() => void) | null;
2491
2465
  }
2492
2466
  >();
2493
2467
 
2494
- const closeUnauthenticated = (ws: WebSocketLike) => {
2495
- try {
2496
- ws.send(JSON.stringify({ type: 'error', message: 'UNAUTHENTICATED' }));
2497
- } catch {
2498
- // ignore send errors
2499
- }
2500
- ws.close(4001, 'Unauthenticated');
2501
- };
2502
-
2503
2468
  const cleanup = (ws: WebSocketLike) => {
2504
2469
  const state = wsState.get(ws);
2505
2470
  if (!state) return;
@@ -2553,16 +2518,18 @@ export function createConsoleRoutes<
2553
2518
 
2554
2519
  return {
2555
2520
  onOpen(_event, ws) {
2556
- const state = {
2557
- listener: null,
2558
- heartbeatInterval: null,
2559
- authTimeout: null,
2560
- isAuthenticated: false,
2561
- } as {
2521
+ const state: {
2562
2522
  listener: ConsoleEventListener | null;
2563
2523
  heartbeatInterval: ReturnType<typeof setInterval> | null;
2564
2524
  authTimeout: ReturnType<typeof setTimeout> | null;
2565
2525
  isAuthenticated: boolean;
2526
+ startAuthenticatedSession: (() => void) | null;
2527
+ } = {
2528
+ listener: null,
2529
+ heartbeatInterval: null,
2530
+ authTimeout: null,
2531
+ isAuthenticated: false,
2532
+ startAuthenticatedSession: null,
2566
2533
  };
2567
2534
  wsState.set(ws, state);
2568
2535
 
@@ -2629,6 +2596,7 @@ export function createConsoleRoutes<
2629
2596
  }, heartbeatIntervalMs);
2630
2597
  state.heartbeatInterval = heartbeatInterval;
2631
2598
  };
2599
+ state.startAuthenticatedSession = startAuthenticatedSession;
2632
2600
 
2633
2601
  if (initialAuth) {
2634
2602
  startAuthenticatedSession();
@@ -2640,7 +2608,7 @@ export function createConsoleRoutes<
2640
2608
  if (!current || current.isAuthenticated) {
2641
2609
  return;
2642
2610
  }
2643
- closeUnauthenticated(ws);
2611
+ closeUnauthenticatedSocket(ws);
2644
2612
  cleanup(ws);
2645
2613
  }, 5_000);
2646
2614
  },
@@ -2651,30 +2619,15 @@ export function createConsoleRoutes<
2651
2619
  }
2652
2620
 
2653
2621
  if (typeof event.data !== 'string') {
2654
- closeUnauthenticated(ws);
2622
+ closeUnauthenticatedSocket(ws);
2655
2623
  cleanup(ws);
2656
2624
  return;
2657
2625
  }
2658
2626
 
2659
- let token = '';
2660
- try {
2661
- const parsed = JSON.parse(event.data) as {
2662
- type?: unknown;
2663
- token?: unknown;
2664
- };
2665
- if (
2666
- parsed.type === 'auth' &&
2667
- typeof parsed.token === 'string' &&
2668
- parsed.token.trim().length > 0
2669
- ) {
2670
- token = parsed.token;
2671
- }
2672
- } catch {
2673
- // Ignore parse errors and close as unauthenticated below.
2674
- }
2627
+ const token = parseWebSocketAuthToken(event.data);
2675
2628
 
2676
2629
  if (!token) {
2677
- closeUnauthenticated(ws);
2630
+ closeUnauthenticatedSocket(ws);
2678
2631
  cleanup(ws);
2679
2632
  return;
2680
2633
  }
@@ -2685,71 +2638,11 @@ export function createConsoleRoutes<
2685
2638
  return;
2686
2639
  }
2687
2640
  if (!auth) {
2688
- closeUnauthenticated(ws);
2641
+ closeUnauthenticatedSocket(ws);
2689
2642
  cleanup(ws);
2690
2643
  return;
2691
2644
  }
2692
-
2693
- currentState.isAuthenticated = true;
2694
- if (currentState.authTimeout) {
2695
- clearTimeout(currentState.authTimeout);
2696
- currentState.authTimeout = null;
2697
- }
2698
-
2699
- const listener: ConsoleEventListener = (liveEvent) => {
2700
- if (partitionId) {
2701
- const eventPartitionId = liveEvent.data.partitionId;
2702
- if (
2703
- typeof eventPartitionId !== 'string' ||
2704
- eventPartitionId !== partitionId
2705
- ) {
2706
- return;
2707
- }
2708
- }
2709
- try {
2710
- ws.send(JSON.stringify(liveEvent));
2711
- } catch {
2712
- // Connection closed
2713
- }
2714
- };
2715
-
2716
- emitter.addListener(listener);
2717
- currentState.listener = listener;
2718
-
2719
- ws.send(
2720
- JSON.stringify({
2721
- type: 'connected',
2722
- timestamp: new Date().toISOString(),
2723
- })
2724
- );
2725
-
2726
- const replayEvents = emitter.replay({
2727
- since: replaySince,
2728
- limit: replayLimit,
2729
- partitionId,
2730
- });
2731
- for (const replayEvent of replayEvents) {
2732
- try {
2733
- ws.send(JSON.stringify(replayEvent));
2734
- } catch {
2735
- // Connection closed
2736
- break;
2737
- }
2738
- }
2739
-
2740
- const heartbeatInterval = setInterval(() => {
2741
- try {
2742
- ws.send(
2743
- JSON.stringify({
2744
- type: 'heartbeat',
2745
- timestamp: new Date().toISOString(),
2746
- })
2747
- );
2748
- } catch {
2749
- clearInterval(heartbeatInterval);
2750
- }
2751
- }, heartbeatIntervalMs);
2752
- currentState.heartbeatInterval = heartbeatInterval;
2645
+ currentState.startAuthenticatedSession?.();
2753
2646
  },
2754
2647
  onClose(_event, ws) {
2755
2648
  cleanup(ws);
@@ -2803,9 +2696,6 @@ export function createConsoleRoutes<
2803
2696
  zValidator('param', eventIdParamSchema),
2804
2697
  zValidator('query', eventDetailQuerySchema),
2805
2698
  async (c) => {
2806
- const auth = await requireAuth(c);
2807
- if (!auth) return c.json({ error: 'UNAUTHENTICATED' }, 401);
2808
-
2809
2699
  const { id: eventId } = c.req.valid('param');
2810
2700
  const { partitionId } = c.req.valid('query');
2811
2701
 
@@ -2869,9 +2759,6 @@ export function createConsoleRoutes<
2869
2759
  zValidator('param', eventIdParamSchema),
2870
2760
  zValidator('query', eventDetailQuerySchema),
2871
2761
  async (c) => {
2872
- const auth = await requireAuth(c);
2873
- if (!auth) return c.json({ error: 'UNAUTHENTICATED' }, 401);
2874
-
2875
2762
  const { id: eventId } = c.req.valid('param');
2876
2763
  const { partitionId } = c.req.valid('query');
2877
2764
 
@@ -2957,9 +2844,6 @@ export function createConsoleRoutes<
2957
2844
  },
2958
2845
  }),
2959
2846
  async (c) => {
2960
- const auth = await requireAuth(c);
2961
- if (!auth) return c.json({ error: 'UNAUTHENTICATED' }, 401);
2962
-
2963
2847
  const res = await db.deleteFrom('sync_request_events').executeTakeFirst();
2964
2848
 
2965
2849
  const deletedCount = Number(res?.numDeletedRows ?? 0);
@@ -2967,7 +2851,7 @@ export function createConsoleRoutes<
2967
2851
 
2968
2852
  logSyncEvent({
2969
2853
  event: 'console.clear_events',
2970
- consoleUserId: auth.consoleUserId,
2854
+ consoleUserId: c.var.consoleAuth.consoleUserId,
2971
2855
  deletedCount,
2972
2856
  payloadDeletedCount,
2973
2857
  });
@@ -3004,15 +2888,12 @@ export function createConsoleRoutes<
3004
2888
  },
3005
2889
  }),
3006
2890
  async (c) => {
3007
- const auth = await requireAuth(c);
3008
- if (!auth) return c.json({ error: 'UNAUTHENTICATED' }, 401);
3009
-
3010
2891
  const pruneResult = await runEventsPrune();
3011
2892
  const deletedCount = pruneResult.totalDeleted;
3012
2893
 
3013
2894
  logSyncEvent({
3014
2895
  event: 'console.prune_events',
3015
- consoleUserId: auth.consoleUserId,
2896
+ consoleUserId: c.var.consoleAuth.consoleUserId,
3016
2897
  deletedCount,
3017
2898
  requestEventsDeleted: pruneResult.requestEventsDeleted,
3018
2899
  operationEventsDeleted: pruneResult.operationEventsDeleted,
@@ -3054,9 +2935,6 @@ export function createConsoleRoutes<
3054
2935
  }),
3055
2936
  zValidator('query', apiKeysQuerySchema),
3056
2937
  async (c) => {
3057
- const auth = await requireAuth(c);
3058
- if (!auth) return c.json({ error: 'UNAUTHENTICATED' }, 401);
3059
-
3060
2938
  const {
3061
2939
  limit,
3062
2940
  offset,
@@ -3190,9 +3068,6 @@ export function createConsoleRoutes<
3190
3068
  }),
3191
3069
  zValidator('json', ConsoleApiKeyCreateRequestSchema),
3192
3070
  async (c) => {
3193
- const auth = await requireAuth(c);
3194
- if (!auth) return c.json({ error: 'UNAUTHENTICATED' }, 401);
3195
-
3196
3071
  const body = c.req.valid('json');
3197
3072
 
3198
3073
  // Generate key components
@@ -3232,7 +3107,7 @@ export function createConsoleRoutes<
3232
3107
 
3233
3108
  logSyncEvent({
3234
3109
  event: 'console.create_api_key',
3235
- consoleUserId: auth.consoleUserId,
3110
+ consoleUserId: c.var.consoleAuth.consoleUserId,
3236
3111
  keyId,
3237
3112
  keyType: body.keyType,
3238
3113
  });
@@ -3291,9 +3166,6 @@ export function createConsoleRoutes<
3291
3166
  }),
3292
3167
  zValidator('param', apiKeyIdParamSchema),
3293
3168
  async (c) => {
3294
- const auth = await requireAuth(c);
3295
- if (!auth) return c.json({ error: 'UNAUTHENTICATED' }, 401);
3296
-
3297
3169
  const { id: keyId } = c.req.valid('param');
3298
3170
 
3299
3171
  const row = await db
@@ -3362,9 +3234,6 @@ export function createConsoleRoutes<
3362
3234
  }),
3363
3235
  zValidator('param', apiKeyIdParamSchema),
3364
3236
  async (c) => {
3365
- const auth = await requireAuth(c);
3366
- if (!auth) return c.json({ error: 'UNAUTHENTICATED' }, 401);
3367
-
3368
3237
  const { id: keyId } = c.req.valid('param');
3369
3238
  const now = new Date().toISOString();
3370
3239
 
@@ -3379,7 +3248,7 @@ export function createConsoleRoutes<
3379
3248
 
3380
3249
  logSyncEvent({
3381
3250
  event: 'console.revoke_api_key',
3382
- consoleUserId: auth.consoleUserId,
3251
+ consoleUserId: c.var.consoleAuth.consoleUserId,
3383
3252
  keyId,
3384
3253
  revoked,
3385
3254
  });
@@ -3422,9 +3291,6 @@ export function createConsoleRoutes<
3422
3291
  }),
3423
3292
  zValidator('json', ConsoleApiKeyBulkRevokeRequestSchema),
3424
3293
  async (c) => {
3425
- const auth = await requireAuth(c);
3426
- if (!auth) return c.json({ error: 'UNAUTHENTICATED' }, 401);
3427
-
3428
3294
  const body = c.req.valid('json');
3429
3295
  const keyIds = [...new Set(body.keyIds.map((keyId) => keyId.trim()))]
3430
3296
  .filter((keyId) => keyId.length > 0)
@@ -3487,7 +3353,7 @@ export function createConsoleRoutes<
3487
3353
 
3488
3354
  logSyncEvent({
3489
3355
  event: 'console.bulk_revoke_api_keys',
3490
- consoleUserId: auth.consoleUserId,
3356
+ consoleUserId: c.var.consoleAuth.consoleUserId,
3491
3357
  requestedCount: response.requestedCount,
3492
3358
  revokedCount: response.revokedCount,
3493
3359
  alreadyRevokedCount: response.alreadyRevokedCount,
@@ -3532,9 +3398,6 @@ export function createConsoleRoutes<
3532
3398
  }),
3533
3399
  zValidator('param', apiKeyIdParamSchema),
3534
3400
  async (c) => {
3535
- const auth = await requireAuth(c);
3536
- if (!auth) return c.json({ error: 'UNAUTHENTICATED' }, 401);
3537
-
3538
3401
  const { id: keyId } = c.req.valid('param');
3539
3402
  const now = new Date().toISOString();
3540
3403
 
@@ -3582,7 +3445,7 @@ export function createConsoleRoutes<
3582
3445
 
3583
3446
  logSyncEvent({
3584
3447
  event: 'console.stage_rotate_api_key',
3585
- consoleUserId: auth.consoleUserId,
3448
+ consoleUserId: c.var.consoleAuth.consoleUserId,
3586
3449
  oldKeyId: keyId,
3587
3450
  newKeyId,
3588
3451
  });
@@ -3643,9 +3506,6 @@ export function createConsoleRoutes<
3643
3506
  }),
3644
3507
  zValidator('param', apiKeyIdParamSchema),
3645
3508
  async (c) => {
3646
- const auth = await requireAuth(c);
3647
- if (!auth) return c.json({ error: 'UNAUTHENTICATED' }, 401);
3648
-
3649
3509
  const { id: keyId } = c.req.valid('param');
3650
3510
  const now = new Date().toISOString();
3651
3511
 
@@ -3703,7 +3563,7 @@ export function createConsoleRoutes<
3703
3563
 
3704
3564
  logSyncEvent({
3705
3565
  event: 'console.rotate_api_key',
3706
- consoleUserId: auth.consoleUserId,
3566
+ consoleUserId: c.var.consoleAuth.consoleUserId,
3707
3567
  oldKeyId: keyId,
3708
3568
  newKeyId,
3709
3569
  });
@@ -3759,9 +3619,6 @@ export function createConsoleRoutes<
3759
3619
  }),
3760
3620
  zValidator('query', ConsoleBlobListQuerySchema),
3761
3621
  async (c) => {
3762
- const auth = await requireAuth(c);
3763
- if (!auth) return c.json({ error: 'UNAUTHENTICATED' }, 401);
3764
-
3765
3622
  if (!bucket) {
3766
3623
  return c.json({ error: 'BLOB_STORAGE_NOT_CONFIGURED' }, 501);
3767
3624
  }
@@ -3813,9 +3670,6 @@ export function createConsoleRoutes<
3813
3670
  },
3814
3671
  }),
3815
3672
  async (c) => {
3816
- const auth = await requireAuth(c);
3817
- if (!auth) return c.json({ error: 'UNAUTHENTICATED' }, 401);
3818
-
3819
3673
  if (!bucket) {
3820
3674
  return c.json({ error: 'BLOB_STORAGE_NOT_CONFIGURED' }, 501);
3821
3675
  }
@@ -3868,9 +3722,6 @@ export function createConsoleRoutes<
3868
3722
  },
3869
3723
  }),
3870
3724
  async (c) => {
3871
- const auth = await requireAuth(c);
3872
- if (!auth) return c.json({ error: 'UNAUTHENTICATED' }, 401);
3873
-
3874
3725
  if (!bucket) {
3875
3726
  return c.json({ error: 'BLOB_STORAGE_NOT_CONFIGURED' }, 501);
3876
3727
  }
@@ -3923,12 +3774,9 @@ export function createTokenAuthenticator(
3923
3774
  return async (c: Context) => {
3924
3775
  if (!expectedToken) return null;
3925
3776
 
3926
- const authHeader = c.req.header('Authorization')?.trim();
3927
- if (authHeader?.startsWith('Bearer ')) {
3928
- const bearerToken = authHeader.slice(7).trim();
3929
- if (bearerToken === expectedToken) {
3930
- return { consoleUserId: 'token' };
3931
- }
3777
+ const bearerToken = parseBearerToken(c.req.header('Authorization'));
3778
+ if (bearerToken === expectedToken) {
3779
+ return { consoleUserId: 'token' };
3932
3780
  }
3933
3781
 
3934
3782
  return null;