@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.
- package/dist/console/gateway.d.ts.map +1 -1
- package/dist/console/gateway.js +799 -1200
- package/dist/console/gateway.js.map +1 -1
- package/dist/console/live-auth.d.ts +7 -0
- package/dist/console/live-auth.d.ts.map +1 -0
- package/dist/console/live-auth.js +35 -0
- package/dist/console/live-auth.js.map +1 -0
- package/dist/console/routes.d.ts +5 -1
- package/dist/console/routes.d.ts.map +1 -1
- package/dist/console/routes.js +39 -191
- package/dist/console/routes.js.map +1 -1
- package/dist/routes.d.ts +1 -1
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +86 -4
- package/dist/routes.js.map +1 -1
- package/dist/ws.d.ts +5 -12
- package/dist/ws.d.ts.map +1 -1
- package/dist/ws.js +30 -202
- package/dist/ws.js.map +1 -1
- package/package.json +6 -6
- package/src/__tests__/create-server.test.ts +26 -0
- package/src/__tests__/sync-maintenance.test.ts +257 -0
- package/src/console/gateway.ts +985 -1591
- package/src/console/live-auth.ts +39 -0
- package/src/console/routes.ts +59 -211
- package/src/routes.ts +102 -4
- package/src/ws.ts +44 -213
package/dist/console/routes.js
CHANGED
|
@@ -21,6 +21,7 @@ import { cors } from 'hono/cors';
|
|
|
21
21
|
import { describeRoute, resolver, validator as zValidator } from 'hono-openapi';
|
|
22
22
|
import { sql } from 'kysely';
|
|
23
23
|
import { z } from 'zod';
|
|
24
|
+
import { closeUnauthenticatedSocket, parseBearerToken, parseWebSocketAuthToken, } from './live-auth.js';
|
|
24
25
|
import { ApiKeyTypeSchema, ConsoleApiKeyBulkRevokeRequestSchema, ConsoleApiKeyBulkRevokeResponseSchema, ConsoleApiKeyCreateRequestSchema, ConsoleApiKeyCreateResponseSchema, ConsoleApiKeyRevokeResponseSchema, ConsoleApiKeySchema, ConsoleBlobDeleteResponseSchema, ConsoleBlobListQuerySchema, ConsoleBlobListResponseSchema, ConsoleClearEventsResultSchema, ConsoleClientSchema, ConsoleCommitDetailSchema, ConsoleCommitListItemSchema, ConsoleCompactResultSchema, ConsoleEvictResultSchema, ConsoleHandlerSchema, ConsoleOperationEventSchema, ConsoleOperationsQuerySchema, ConsolePaginatedResponseSchema, ConsolePaginationQuerySchema, ConsolePartitionedPaginationQuerySchema, ConsolePartitionQuerySchema, ConsolePruneEventsResultSchema, ConsolePrunePreviewSchema, ConsolePruneResultSchema, ConsoleRequestEventSchema, ConsoleRequestPayloadSchema, ConsoleTimelineItemSchema, ConsoleTimelineQuerySchema, LatencyQuerySchema, LatencyStatsResponseSchema, SyncStatsSchema, TimeseriesQuerySchema, TimeseriesStatsResponseSchema, } from './schemas.js';
|
|
25
26
|
/**
|
|
26
27
|
* Create a simple console event emitter for broadcasting live events.
|
|
@@ -345,14 +346,20 @@ export function createConsoleRoutes(options) {
|
|
|
345
346
|
}
|
|
346
347
|
await next();
|
|
347
348
|
});
|
|
348
|
-
//
|
|
349
|
-
|
|
349
|
+
// Route auth middleware. Keep /events/live exempt to preserve websocket
|
|
350
|
+
// message-based auth handshake fallback when no Authorization header is sent.
|
|
351
|
+
routes.use('*', async (c, next) => {
|
|
352
|
+
if (c.req.method === 'OPTIONS' || c.req.path.endsWith('/events/live')) {
|
|
353
|
+
await next();
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
350
356
|
const auth = await options.authenticate(c);
|
|
351
357
|
if (!auth) {
|
|
352
|
-
return
|
|
358
|
+
return c.json({ error: 'UNAUTHENTICATED' }, 401);
|
|
353
359
|
}
|
|
354
|
-
|
|
355
|
-
|
|
360
|
+
c.set('consoleAuth', auth);
|
|
361
|
+
await next();
|
|
362
|
+
});
|
|
356
363
|
const requestEventSelectColumns = [
|
|
357
364
|
'event_id',
|
|
358
365
|
'partition_id',
|
|
@@ -641,16 +648,13 @@ export function createConsoleRoutes(options) {
|
|
|
641
648
|
},
|
|
642
649
|
},
|
|
643
650
|
}), zValidator('query', ConsolePartitionQuerySchema), async (c) => {
|
|
644
|
-
const auth = await requireAuth(c);
|
|
645
|
-
if (!auth)
|
|
646
|
-
return c.json({ error: 'UNAUTHENTICATED' }, 401);
|
|
647
651
|
const { partitionId } = c.req.valid('query');
|
|
648
652
|
const stats = await readSyncStats(options.db, {
|
|
649
653
|
partitionId,
|
|
650
654
|
});
|
|
651
655
|
logSyncEvent({
|
|
652
656
|
event: 'console.stats',
|
|
653
|
-
consoleUserId:
|
|
657
|
+
consoleUserId: c.var.consoleAuth.consoleUserId,
|
|
654
658
|
});
|
|
655
659
|
return c.json(stats, 200);
|
|
656
660
|
});
|
|
@@ -677,9 +681,6 @@ export function createConsoleRoutes(options) {
|
|
|
677
681
|
},
|
|
678
682
|
},
|
|
679
683
|
}), zValidator('query', TimeseriesQuerySchema), async (c) => {
|
|
680
|
-
const auth = await requireAuth(c);
|
|
681
|
-
if (!auth)
|
|
682
|
-
return c.json({ error: 'UNAUTHENTICATED' }, 401);
|
|
683
684
|
const { interval, range, partitionId } = c.req.valid('query');
|
|
684
685
|
const rangeMs = rangeToMs(range);
|
|
685
686
|
const startTime = new Date(Date.now() - rangeMs);
|
|
@@ -838,9 +839,6 @@ export function createConsoleRoutes(options) {
|
|
|
838
839
|
},
|
|
839
840
|
},
|
|
840
841
|
}), zValidator('query', LatencyQuerySchema), async (c) => {
|
|
841
|
-
const auth = await requireAuth(c);
|
|
842
|
-
if (!auth)
|
|
843
|
-
return c.json({ error: 'UNAUTHENTICATED' }, 401);
|
|
844
842
|
const { range, partitionId } = c.req.valid('query');
|
|
845
843
|
const rangeMs = rangeToMs(range);
|
|
846
844
|
const startTime = new Date(Date.now() - rangeMs);
|
|
@@ -929,9 +927,6 @@ export function createConsoleRoutes(options) {
|
|
|
929
927
|
},
|
|
930
928
|
},
|
|
931
929
|
}), zValidator('query', ConsoleTimelineQuerySchema), async (c) => {
|
|
932
|
-
const auth = await requireAuth(c);
|
|
933
|
-
if (!auth)
|
|
934
|
-
return c.json({ error: 'UNAUTHENTICATED' }, 401);
|
|
935
930
|
const { limit, offset, view, partitionId, eventType, actorId, clientId, requestId, traceId, table, outcome, search, from, to, } = c.req.valid('query');
|
|
936
931
|
const items = [];
|
|
937
932
|
const normalizedSearchTerm = search?.trim().toLowerCase() || null;
|
|
@@ -1106,9 +1101,6 @@ export function createConsoleRoutes(options) {
|
|
|
1106
1101
|
},
|
|
1107
1102
|
},
|
|
1108
1103
|
}), zValidator('query', ConsolePartitionedPaginationQuerySchema), async (c) => {
|
|
1109
|
-
const auth = await requireAuth(c);
|
|
1110
|
-
if (!auth)
|
|
1111
|
-
return c.json({ error: 'UNAUTHENTICATED' }, 401);
|
|
1112
1104
|
const { limit, offset, partitionId } = c.req.valid('query');
|
|
1113
1105
|
let query = db
|
|
1114
1106
|
.selectFrom('sync_commits')
|
|
@@ -1188,9 +1180,6 @@ export function createConsoleRoutes(options) {
|
|
|
1188
1180
|
},
|
|
1189
1181
|
},
|
|
1190
1182
|
}), zValidator('param', commitSeqParamSchema), zValidator('query', commitDetailQuerySchema), async (c) => {
|
|
1191
|
-
const auth = await requireAuth(c);
|
|
1192
|
-
if (!auth)
|
|
1193
|
-
return c.json({ error: 'UNAUTHENTICATED' }, 401);
|
|
1194
1183
|
const { seq } = c.req.valid('param');
|
|
1195
1184
|
const { partitionId } = c.req.valid('query');
|
|
1196
1185
|
let commitQuery = db
|
|
@@ -1289,9 +1278,6 @@ export function createConsoleRoutes(options) {
|
|
|
1289
1278
|
},
|
|
1290
1279
|
},
|
|
1291
1280
|
}), zValidator('query', ConsolePartitionedPaginationQuerySchema), async (c) => {
|
|
1292
|
-
const auth = await requireAuth(c);
|
|
1293
|
-
if (!auth)
|
|
1294
|
-
return c.json({ error: 'UNAUTHENTICATED' }, 401);
|
|
1295
1281
|
const { limit, offset, partitionId } = c.req.valid('query');
|
|
1296
1282
|
let clientsQuery = db
|
|
1297
1283
|
.selectFrom('sync_client_cursors')
|
|
@@ -1417,9 +1403,6 @@ export function createConsoleRoutes(options) {
|
|
|
1417
1403
|
},
|
|
1418
1404
|
},
|
|
1419
1405
|
}), async (c) => {
|
|
1420
|
-
const auth = await requireAuth(c);
|
|
1421
|
-
if (!auth)
|
|
1422
|
-
return c.json({ error: 'UNAUTHENTICATED' }, 401);
|
|
1423
1406
|
const items = options.handlers.map((handler) => ({
|
|
1424
1407
|
table: handler.table,
|
|
1425
1408
|
dependsOn: handler.dependsOn,
|
|
@@ -1450,9 +1433,6 @@ export function createConsoleRoutes(options) {
|
|
|
1450
1433
|
},
|
|
1451
1434
|
},
|
|
1452
1435
|
}), zValidator('query', ConsoleOperationsQuerySchema), async (c) => {
|
|
1453
|
-
const auth = await requireAuth(c);
|
|
1454
|
-
if (!auth)
|
|
1455
|
-
return c.json({ error: 'UNAUTHENTICATED' }, 401);
|
|
1456
1436
|
const { limit, offset, operationType, partitionId } = c.req.valid('query');
|
|
1457
1437
|
let query = db
|
|
1458
1438
|
.selectFrom('sync_operation_events')
|
|
@@ -1508,9 +1488,6 @@ export function createConsoleRoutes(options) {
|
|
|
1508
1488
|
},
|
|
1509
1489
|
},
|
|
1510
1490
|
}), async (c) => {
|
|
1511
|
-
const auth = await requireAuth(c);
|
|
1512
|
-
if (!auth)
|
|
1513
|
-
return c.json({ error: 'UNAUTHENTICATED' }, 401);
|
|
1514
1491
|
const watermarkCommitSeq = await computePruneWatermarkCommitSeq(options.db, options.prune);
|
|
1515
1492
|
// Count commits that would be deleted
|
|
1516
1493
|
const countRow = await db
|
|
@@ -1546,9 +1523,6 @@ export function createConsoleRoutes(options) {
|
|
|
1546
1523
|
},
|
|
1547
1524
|
},
|
|
1548
1525
|
}), async (c) => {
|
|
1549
|
-
const auth = await requireAuth(c);
|
|
1550
|
-
if (!auth)
|
|
1551
|
-
return c.json({ error: 'UNAUTHENTICATED' }, 401);
|
|
1552
1526
|
const watermarkCommitSeq = await computePruneWatermarkCommitSeq(options.db, options.prune);
|
|
1553
1527
|
const deletedCommits = await pruneSync(options.db, {
|
|
1554
1528
|
watermarkCommitSeq,
|
|
@@ -1556,13 +1530,13 @@ export function createConsoleRoutes(options) {
|
|
|
1556
1530
|
});
|
|
1557
1531
|
logSyncEvent({
|
|
1558
1532
|
event: 'console.prune',
|
|
1559
|
-
consoleUserId:
|
|
1533
|
+
consoleUserId: c.var.consoleAuth.consoleUserId,
|
|
1560
1534
|
deletedCommits,
|
|
1561
1535
|
watermarkCommitSeq,
|
|
1562
1536
|
});
|
|
1563
1537
|
await recordOperationEvent({
|
|
1564
1538
|
operationType: 'prune',
|
|
1565
|
-
consoleUserId:
|
|
1539
|
+
consoleUserId: c.var.consoleAuth.consoleUserId,
|
|
1566
1540
|
requestPayload: {
|
|
1567
1541
|
watermarkCommitSeq,
|
|
1568
1542
|
keepNewestCommits: options.prune?.keepNewestCommits ?? null,
|
|
@@ -1595,9 +1569,6 @@ export function createConsoleRoutes(options) {
|
|
|
1595
1569
|
},
|
|
1596
1570
|
},
|
|
1597
1571
|
}), async (c) => {
|
|
1598
|
-
const auth = await requireAuth(c);
|
|
1599
|
-
if (!auth)
|
|
1600
|
-
return c.json({ error: 'UNAUTHENTICATED' }, 401);
|
|
1601
1572
|
const fullHistoryHours = options.compact?.fullHistoryHours ?? 24 * 7;
|
|
1602
1573
|
const deletedChanges = await compactChanges(options.db, {
|
|
1603
1574
|
dialect: options.dialect,
|
|
@@ -1605,13 +1576,13 @@ export function createConsoleRoutes(options) {
|
|
|
1605
1576
|
});
|
|
1606
1577
|
logSyncEvent({
|
|
1607
1578
|
event: 'console.compact',
|
|
1608
|
-
consoleUserId:
|
|
1579
|
+
consoleUserId: c.var.consoleAuth.consoleUserId,
|
|
1609
1580
|
deletedChanges,
|
|
1610
1581
|
fullHistoryHours,
|
|
1611
1582
|
});
|
|
1612
1583
|
await recordOperationEvent({
|
|
1613
1584
|
operationType: 'compact',
|
|
1614
|
-
consoleUserId:
|
|
1585
|
+
consoleUserId: c.var.consoleAuth.consoleUserId,
|
|
1615
1586
|
requestPayload: { fullHistoryHours },
|
|
1616
1587
|
resultPayload: { deletedChanges },
|
|
1617
1588
|
});
|
|
@@ -1658,9 +1629,6 @@ export function createConsoleRoutes(options) {
|
|
|
1658
1629
|
},
|
|
1659
1630
|
},
|
|
1660
1631
|
}), zValidator('json', NotifyDataChangeRequestSchema), async (c) => {
|
|
1661
|
-
const auth = await requireAuth(c);
|
|
1662
|
-
if (!auth)
|
|
1663
|
-
return c.json({ error: 'UNAUTHENTICATED' }, 401);
|
|
1664
1632
|
const body = c.req.valid('json');
|
|
1665
1633
|
const result = await notifyExternalDataChange({
|
|
1666
1634
|
db: options.db,
|
|
@@ -1670,14 +1638,14 @@ export function createConsoleRoutes(options) {
|
|
|
1670
1638
|
});
|
|
1671
1639
|
logSyncEvent({
|
|
1672
1640
|
event: 'console.notify_data_change',
|
|
1673
|
-
consoleUserId:
|
|
1641
|
+
consoleUserId: c.var.consoleAuth.consoleUserId,
|
|
1674
1642
|
tables: body.tables,
|
|
1675
1643
|
commitSeq: result.commitSeq,
|
|
1676
1644
|
deletedChunks: result.deletedChunks,
|
|
1677
1645
|
});
|
|
1678
1646
|
await recordOperationEvent({
|
|
1679
1647
|
operationType: 'notify_data_change',
|
|
1680
|
-
consoleUserId:
|
|
1648
|
+
consoleUserId: c.var.consoleAuth.consoleUserId,
|
|
1681
1649
|
partitionId: body.partitionId ?? null,
|
|
1682
1650
|
requestPayload: {
|
|
1683
1651
|
tables: body.tables,
|
|
@@ -1718,9 +1686,6 @@ export function createConsoleRoutes(options) {
|
|
|
1718
1686
|
},
|
|
1719
1687
|
},
|
|
1720
1688
|
}), zValidator('param', clientIdParamSchema), zValidator('query', evictClientQuerySchema), async (c) => {
|
|
1721
|
-
const auth = await requireAuth(c);
|
|
1722
|
-
if (!auth)
|
|
1723
|
-
return c.json({ error: 'UNAUTHENTICATED' }, 401);
|
|
1724
1689
|
const { id: clientId } = c.req.valid('param');
|
|
1725
1690
|
const { partitionId } = c.req.valid('query');
|
|
1726
1691
|
let deleteQuery = db
|
|
@@ -1733,13 +1698,13 @@ export function createConsoleRoutes(options) {
|
|
|
1733
1698
|
const evicted = Number(res?.numDeletedRows ?? 0) > 0;
|
|
1734
1699
|
logSyncEvent({
|
|
1735
1700
|
event: 'console.evict_client',
|
|
1736
|
-
consoleUserId:
|
|
1701
|
+
consoleUserId: c.var.consoleAuth.consoleUserId,
|
|
1737
1702
|
clientId,
|
|
1738
1703
|
evicted,
|
|
1739
1704
|
});
|
|
1740
1705
|
await recordOperationEvent({
|
|
1741
1706
|
operationType: 'evict_client',
|
|
1742
|
-
consoleUserId:
|
|
1707
|
+
consoleUserId: c.var.consoleAuth.consoleUserId,
|
|
1743
1708
|
partitionId: partitionId ?? null,
|
|
1744
1709
|
targetClientId: clientId,
|
|
1745
1710
|
requestPayload: { clientId, partitionId: partitionId ?? null },
|
|
@@ -1771,9 +1736,6 @@ export function createConsoleRoutes(options) {
|
|
|
1771
1736
|
},
|
|
1772
1737
|
},
|
|
1773
1738
|
}), zValidator('query', eventsQuerySchema), async (c) => {
|
|
1774
|
-
const auth = await requireAuth(c);
|
|
1775
|
-
if (!auth)
|
|
1776
|
-
return c.json({ error: 'UNAUTHENTICATED' }, 401);
|
|
1777
1739
|
const { limit, offset, partitionId, eventType, actorId, clientId, requestId, traceId, outcome, } = c.req.valid('query');
|
|
1778
1740
|
let query = db
|
|
1779
1741
|
.selectFrom('sync_request_events')
|
|
@@ -1839,15 +1801,6 @@ export function createConsoleRoutes(options) {
|
|
|
1839
1801
|
const upgradeWebSocket = options.websocket.upgradeWebSocket;
|
|
1840
1802
|
const heartbeatIntervalMs = options.websocket.heartbeatIntervalMs ?? 30000;
|
|
1841
1803
|
const wsState = new WeakMap();
|
|
1842
|
-
const closeUnauthenticated = (ws) => {
|
|
1843
|
-
try {
|
|
1844
|
-
ws.send(JSON.stringify({ type: 'error', message: 'UNAUTHENTICATED' }));
|
|
1845
|
-
}
|
|
1846
|
-
catch {
|
|
1847
|
-
// ignore send errors
|
|
1848
|
-
}
|
|
1849
|
-
ws.close(4001, 'Unauthenticated');
|
|
1850
|
-
};
|
|
1851
1804
|
const cleanup = (ws) => {
|
|
1852
1805
|
const state = wsState.get(ws);
|
|
1853
1806
|
if (!state)
|
|
@@ -1900,6 +1853,7 @@ export function createConsoleRoutes(options) {
|
|
|
1900
1853
|
heartbeatInterval: null,
|
|
1901
1854
|
authTimeout: null,
|
|
1902
1855
|
isAuthenticated: false,
|
|
1856
|
+
startAuthenticatedSession: null,
|
|
1903
1857
|
};
|
|
1904
1858
|
wsState.set(ws, state);
|
|
1905
1859
|
const startAuthenticatedSession = () => {
|
|
@@ -1958,6 +1912,7 @@ export function createConsoleRoutes(options) {
|
|
|
1958
1912
|
}, heartbeatIntervalMs);
|
|
1959
1913
|
state.heartbeatInterval = heartbeatInterval;
|
|
1960
1914
|
};
|
|
1915
|
+
state.startAuthenticatedSession = startAuthenticatedSession;
|
|
1961
1916
|
if (initialAuth) {
|
|
1962
1917
|
startAuthenticatedSession();
|
|
1963
1918
|
return;
|
|
@@ -1967,7 +1922,7 @@ export function createConsoleRoutes(options) {
|
|
|
1967
1922
|
if (!current || current.isAuthenticated) {
|
|
1968
1923
|
return;
|
|
1969
1924
|
}
|
|
1970
|
-
|
|
1925
|
+
closeUnauthenticatedSocket(ws);
|
|
1971
1926
|
cleanup(ws);
|
|
1972
1927
|
}, 5_000);
|
|
1973
1928
|
},
|
|
@@ -1977,24 +1932,13 @@ export function createConsoleRoutes(options) {
|
|
|
1977
1932
|
return;
|
|
1978
1933
|
}
|
|
1979
1934
|
if (typeof event.data !== 'string') {
|
|
1980
|
-
|
|
1935
|
+
closeUnauthenticatedSocket(ws);
|
|
1981
1936
|
cleanup(ws);
|
|
1982
1937
|
return;
|
|
1983
1938
|
}
|
|
1984
|
-
|
|
1985
|
-
try {
|
|
1986
|
-
const parsed = JSON.parse(event.data);
|
|
1987
|
-
if (parsed.type === 'auth' &&
|
|
1988
|
-
typeof parsed.token === 'string' &&
|
|
1989
|
-
parsed.token.trim().length > 0) {
|
|
1990
|
-
token = parsed.token;
|
|
1991
|
-
}
|
|
1992
|
-
}
|
|
1993
|
-
catch {
|
|
1994
|
-
// Ignore parse errors and close as unauthenticated below.
|
|
1995
|
-
}
|
|
1939
|
+
const token = parseWebSocketAuthToken(event.data);
|
|
1996
1940
|
if (!token) {
|
|
1997
|
-
|
|
1941
|
+
closeUnauthenticatedSocket(ws);
|
|
1998
1942
|
cleanup(ws);
|
|
1999
1943
|
return;
|
|
2000
1944
|
}
|
|
@@ -2004,62 +1948,11 @@ export function createConsoleRoutes(options) {
|
|
|
2004
1948
|
return;
|
|
2005
1949
|
}
|
|
2006
1950
|
if (!auth) {
|
|
2007
|
-
|
|
1951
|
+
closeUnauthenticatedSocket(ws);
|
|
2008
1952
|
cleanup(ws);
|
|
2009
1953
|
return;
|
|
2010
1954
|
}
|
|
2011
|
-
currentState.
|
|
2012
|
-
if (currentState.authTimeout) {
|
|
2013
|
-
clearTimeout(currentState.authTimeout);
|
|
2014
|
-
currentState.authTimeout = null;
|
|
2015
|
-
}
|
|
2016
|
-
const listener = (liveEvent) => {
|
|
2017
|
-
if (partitionId) {
|
|
2018
|
-
const eventPartitionId = liveEvent.data.partitionId;
|
|
2019
|
-
if (typeof eventPartitionId !== 'string' ||
|
|
2020
|
-
eventPartitionId !== partitionId) {
|
|
2021
|
-
return;
|
|
2022
|
-
}
|
|
2023
|
-
}
|
|
2024
|
-
try {
|
|
2025
|
-
ws.send(JSON.stringify(liveEvent));
|
|
2026
|
-
}
|
|
2027
|
-
catch {
|
|
2028
|
-
// Connection closed
|
|
2029
|
-
}
|
|
2030
|
-
};
|
|
2031
|
-
emitter.addListener(listener);
|
|
2032
|
-
currentState.listener = listener;
|
|
2033
|
-
ws.send(JSON.stringify({
|
|
2034
|
-
type: 'connected',
|
|
2035
|
-
timestamp: new Date().toISOString(),
|
|
2036
|
-
}));
|
|
2037
|
-
const replayEvents = emitter.replay({
|
|
2038
|
-
since: replaySince,
|
|
2039
|
-
limit: replayLimit,
|
|
2040
|
-
partitionId,
|
|
2041
|
-
});
|
|
2042
|
-
for (const replayEvent of replayEvents) {
|
|
2043
|
-
try {
|
|
2044
|
-
ws.send(JSON.stringify(replayEvent));
|
|
2045
|
-
}
|
|
2046
|
-
catch {
|
|
2047
|
-
// Connection closed
|
|
2048
|
-
break;
|
|
2049
|
-
}
|
|
2050
|
-
}
|
|
2051
|
-
const heartbeatInterval = setInterval(() => {
|
|
2052
|
-
try {
|
|
2053
|
-
ws.send(JSON.stringify({
|
|
2054
|
-
type: 'heartbeat',
|
|
2055
|
-
timestamp: new Date().toISOString(),
|
|
2056
|
-
}));
|
|
2057
|
-
}
|
|
2058
|
-
catch {
|
|
2059
|
-
clearInterval(heartbeatInterval);
|
|
2060
|
-
}
|
|
2061
|
-
}, heartbeatIntervalMs);
|
|
2062
|
-
currentState.heartbeatInterval = heartbeatInterval;
|
|
1955
|
+
currentState.startAuthenticatedSession?.();
|
|
2063
1956
|
},
|
|
2064
1957
|
onClose(_event, ws) {
|
|
2065
1958
|
cleanup(ws);
|
|
@@ -2105,9 +1998,6 @@ export function createConsoleRoutes(options) {
|
|
|
2105
1998
|
},
|
|
2106
1999
|
},
|
|
2107
2000
|
}), zValidator('param', eventIdParamSchema), zValidator('query', eventDetailQuerySchema), async (c) => {
|
|
2108
|
-
const auth = await requireAuth(c);
|
|
2109
|
-
if (!auth)
|
|
2110
|
-
return c.json({ error: 'UNAUTHENTICATED' }, 401);
|
|
2111
2001
|
const { id: eventId } = c.req.valid('param');
|
|
2112
2002
|
const { partitionId } = c.req.valid('query');
|
|
2113
2003
|
let eventQuery = db
|
|
@@ -2158,9 +2048,6 @@ export function createConsoleRoutes(options) {
|
|
|
2158
2048
|
},
|
|
2159
2049
|
},
|
|
2160
2050
|
}), zValidator('param', eventIdParamSchema), zValidator('query', eventDetailQuerySchema), async (c) => {
|
|
2161
|
-
const auth = await requireAuth(c);
|
|
2162
|
-
if (!auth)
|
|
2163
|
-
return c.json({ error: 'UNAUTHENTICATED' }, 401);
|
|
2164
2051
|
const { id: eventId } = c.req.valid('param');
|
|
2165
2052
|
const { partitionId } = c.req.valid('query');
|
|
2166
2053
|
let eventQuery = db
|
|
@@ -2225,15 +2112,12 @@ export function createConsoleRoutes(options) {
|
|
|
2225
2112
|
},
|
|
2226
2113
|
},
|
|
2227
2114
|
}), async (c) => {
|
|
2228
|
-
const auth = await requireAuth(c);
|
|
2229
|
-
if (!auth)
|
|
2230
|
-
return c.json({ error: 'UNAUTHENTICATED' }, 401);
|
|
2231
2115
|
const res = await db.deleteFrom('sync_request_events').executeTakeFirst();
|
|
2232
2116
|
const deletedCount = Number(res?.numDeletedRows ?? 0);
|
|
2233
2117
|
const payloadDeletedCount = await deleteUnreferencedPayloadSnapshots();
|
|
2234
2118
|
logSyncEvent({
|
|
2235
2119
|
event: 'console.clear_events',
|
|
2236
|
-
consoleUserId:
|
|
2120
|
+
consoleUserId: c.var.consoleAuth.consoleUserId,
|
|
2237
2121
|
deletedCount,
|
|
2238
2122
|
payloadDeletedCount,
|
|
2239
2123
|
});
|
|
@@ -2263,14 +2147,11 @@ export function createConsoleRoutes(options) {
|
|
|
2263
2147
|
},
|
|
2264
2148
|
},
|
|
2265
2149
|
}), async (c) => {
|
|
2266
|
-
const auth = await requireAuth(c);
|
|
2267
|
-
if (!auth)
|
|
2268
|
-
return c.json({ error: 'UNAUTHENTICATED' }, 401);
|
|
2269
2150
|
const pruneResult = await runEventsPrune();
|
|
2270
2151
|
const deletedCount = pruneResult.totalDeleted;
|
|
2271
2152
|
logSyncEvent({
|
|
2272
2153
|
event: 'console.prune_events',
|
|
2273
|
-
consoleUserId:
|
|
2154
|
+
consoleUserId: c.var.consoleAuth.consoleUserId,
|
|
2274
2155
|
deletedCount,
|
|
2275
2156
|
requestEventsDeleted: pruneResult.requestEventsDeleted,
|
|
2276
2157
|
operationEventsDeleted: pruneResult.operationEventsDeleted,
|
|
@@ -2302,9 +2183,6 @@ export function createConsoleRoutes(options) {
|
|
|
2302
2183
|
},
|
|
2303
2184
|
},
|
|
2304
2185
|
}), zValidator('query', apiKeysQuerySchema), async (c) => {
|
|
2305
|
-
const auth = await requireAuth(c);
|
|
2306
|
-
if (!auth)
|
|
2307
|
-
return c.json({ error: 'UNAUTHENTICATED' }, 401);
|
|
2308
2186
|
const { limit, offset, type: keyType, status, expiresWithinDays, } = c.req.valid('query');
|
|
2309
2187
|
let query = db
|
|
2310
2188
|
.selectFrom('sync_api_keys')
|
|
@@ -2411,9 +2289,6 @@ export function createConsoleRoutes(options) {
|
|
|
2411
2289
|
},
|
|
2412
2290
|
},
|
|
2413
2291
|
}), zValidator('json', ConsoleApiKeyCreateRequestSchema), async (c) => {
|
|
2414
|
-
const auth = await requireAuth(c);
|
|
2415
|
-
if (!auth)
|
|
2416
|
-
return c.json({ error: 'UNAUTHENTICATED' }, 401);
|
|
2417
2292
|
const body = c.req.valid('json');
|
|
2418
2293
|
// Generate key components
|
|
2419
2294
|
const keyId = generateKeyId();
|
|
@@ -2446,7 +2321,7 @@ export function createConsoleRoutes(options) {
|
|
|
2446
2321
|
.execute();
|
|
2447
2322
|
logSyncEvent({
|
|
2448
2323
|
event: 'console.create_api_key',
|
|
2449
|
-
consoleUserId:
|
|
2324
|
+
consoleUserId: c.var.consoleAuth.consoleUserId,
|
|
2450
2325
|
keyId,
|
|
2451
2326
|
keyType: body.keyType,
|
|
2452
2327
|
});
|
|
@@ -2495,9 +2370,6 @@ export function createConsoleRoutes(options) {
|
|
|
2495
2370
|
},
|
|
2496
2371
|
},
|
|
2497
2372
|
}), zValidator('param', apiKeyIdParamSchema), async (c) => {
|
|
2498
|
-
const auth = await requireAuth(c);
|
|
2499
|
-
if (!auth)
|
|
2500
|
-
return c.json({ error: 'UNAUTHENTICATED' }, 401);
|
|
2501
2373
|
const { id: keyId } = c.req.valid('param');
|
|
2502
2374
|
const row = await db
|
|
2503
2375
|
.selectFrom('sync_api_keys')
|
|
@@ -2555,9 +2427,6 @@ export function createConsoleRoutes(options) {
|
|
|
2555
2427
|
},
|
|
2556
2428
|
},
|
|
2557
2429
|
}), zValidator('param', apiKeyIdParamSchema), async (c) => {
|
|
2558
|
-
const auth = await requireAuth(c);
|
|
2559
|
-
if (!auth)
|
|
2560
|
-
return c.json({ error: 'UNAUTHENTICATED' }, 401);
|
|
2561
2430
|
const { id: keyId } = c.req.valid('param');
|
|
2562
2431
|
const now = new Date().toISOString();
|
|
2563
2432
|
const res = await db
|
|
@@ -2569,7 +2438,7 @@ export function createConsoleRoutes(options) {
|
|
|
2569
2438
|
const revoked = Number(res?.numUpdatedRows ?? 0) > 0;
|
|
2570
2439
|
logSyncEvent({
|
|
2571
2440
|
event: 'console.revoke_api_key',
|
|
2572
|
-
consoleUserId:
|
|
2441
|
+
consoleUserId: c.var.consoleAuth.consoleUserId,
|
|
2573
2442
|
keyId,
|
|
2574
2443
|
revoked,
|
|
2575
2444
|
});
|
|
@@ -2604,9 +2473,6 @@ export function createConsoleRoutes(options) {
|
|
|
2604
2473
|
},
|
|
2605
2474
|
},
|
|
2606
2475
|
}), zValidator('json', ConsoleApiKeyBulkRevokeRequestSchema), async (c) => {
|
|
2607
|
-
const auth = await requireAuth(c);
|
|
2608
|
-
if (!auth)
|
|
2609
|
-
return c.json({ error: 'UNAUTHENTICATED' }, 401);
|
|
2610
2476
|
const body = c.req.valid('json');
|
|
2611
2477
|
const keyIds = [...new Set(body.keyIds.map((keyId) => keyId.trim()))]
|
|
2612
2478
|
.filter((keyId) => keyId.length > 0)
|
|
@@ -2657,7 +2523,7 @@ export function createConsoleRoutes(options) {
|
|
|
2657
2523
|
};
|
|
2658
2524
|
logSyncEvent({
|
|
2659
2525
|
event: 'console.bulk_revoke_api_keys',
|
|
2660
|
-
consoleUserId:
|
|
2526
|
+
consoleUserId: c.var.consoleAuth.consoleUserId,
|
|
2661
2527
|
requestedCount: response.requestedCount,
|
|
2662
2528
|
revokedCount: response.revokedCount,
|
|
2663
2529
|
alreadyRevokedCount: response.alreadyRevokedCount,
|
|
@@ -2694,9 +2560,6 @@ export function createConsoleRoutes(options) {
|
|
|
2694
2560
|
},
|
|
2695
2561
|
},
|
|
2696
2562
|
}), zValidator('param', apiKeyIdParamSchema), async (c) => {
|
|
2697
|
-
const auth = await requireAuth(c);
|
|
2698
|
-
if (!auth)
|
|
2699
|
-
return c.json({ error: 'UNAUTHENTICATED' }, 401);
|
|
2700
2563
|
const { id: keyId } = c.req.valid('param');
|
|
2701
2564
|
const now = new Date().toISOString();
|
|
2702
2565
|
const existingRow = await db
|
|
@@ -2739,7 +2602,7 @@ export function createConsoleRoutes(options) {
|
|
|
2739
2602
|
.execute();
|
|
2740
2603
|
logSyncEvent({
|
|
2741
2604
|
event: 'console.stage_rotate_api_key',
|
|
2742
|
-
consoleUserId:
|
|
2605
|
+
consoleUserId: c.var.consoleAuth.consoleUserId,
|
|
2743
2606
|
oldKeyId: keyId,
|
|
2744
2607
|
newKeyId,
|
|
2745
2608
|
});
|
|
@@ -2790,9 +2653,6 @@ export function createConsoleRoutes(options) {
|
|
|
2790
2653
|
},
|
|
2791
2654
|
},
|
|
2792
2655
|
}), zValidator('param', apiKeyIdParamSchema), async (c) => {
|
|
2793
|
-
const auth = await requireAuth(c);
|
|
2794
|
-
if (!auth)
|
|
2795
|
-
return c.json({ error: 'UNAUTHENTICATED' }, 401);
|
|
2796
2656
|
const { id: keyId } = c.req.valid('param');
|
|
2797
2657
|
const now = new Date().toISOString();
|
|
2798
2658
|
// Get existing key
|
|
@@ -2843,7 +2703,7 @@ export function createConsoleRoutes(options) {
|
|
|
2843
2703
|
.execute();
|
|
2844
2704
|
logSyncEvent({
|
|
2845
2705
|
event: 'console.rotate_api_key',
|
|
2846
|
-
consoleUserId:
|
|
2706
|
+
consoleUserId: c.var.consoleAuth.consoleUserId,
|
|
2847
2707
|
oldKeyId: keyId,
|
|
2848
2708
|
newKeyId,
|
|
2849
2709
|
});
|
|
@@ -2889,9 +2749,6 @@ export function createConsoleRoutes(options) {
|
|
|
2889
2749
|
},
|
|
2890
2750
|
},
|
|
2891
2751
|
}), zValidator('query', ConsoleBlobListQuerySchema), async (c) => {
|
|
2892
|
-
const auth = await requireAuth(c);
|
|
2893
|
-
if (!auth)
|
|
2894
|
-
return c.json({ error: 'UNAUTHENTICATED' }, 401);
|
|
2895
2752
|
if (!bucket) {
|
|
2896
2753
|
return c.json({ error: 'BLOB_STORAGE_NOT_CONFIGURED' }, 501);
|
|
2897
2754
|
}
|
|
@@ -2933,9 +2790,6 @@ export function createConsoleRoutes(options) {
|
|
|
2933
2790
|
},
|
|
2934
2791
|
},
|
|
2935
2792
|
}), async (c) => {
|
|
2936
|
-
const auth = await requireAuth(c);
|
|
2937
|
-
if (!auth)
|
|
2938
|
-
return c.json({ error: 'UNAUTHENTICATED' }, 401);
|
|
2939
2793
|
if (!bucket) {
|
|
2940
2794
|
return c.json({ error: 'BLOB_STORAGE_NOT_CONFIGURED' }, 501);
|
|
2941
2795
|
}
|
|
@@ -2974,9 +2828,6 @@ export function createConsoleRoutes(options) {
|
|
|
2974
2828
|
},
|
|
2975
2829
|
},
|
|
2976
2830
|
}), async (c) => {
|
|
2977
|
-
const auth = await requireAuth(c);
|
|
2978
|
-
if (!auth)
|
|
2979
|
-
return c.json({ error: 'UNAUTHENTICATED' }, 401);
|
|
2980
2831
|
if (!bucket) {
|
|
2981
2832
|
return c.json({ error: 'BLOB_STORAGE_NOT_CONFIGURED' }, 501);
|
|
2982
2833
|
}
|
|
@@ -3016,12 +2867,9 @@ export function createTokenAuthenticator(token) {
|
|
|
3016
2867
|
return async (c) => {
|
|
3017
2868
|
if (!expectedToken)
|
|
3018
2869
|
return null;
|
|
3019
|
-
const
|
|
3020
|
-
if (
|
|
3021
|
-
|
|
3022
|
-
if (bearerToken === expectedToken) {
|
|
3023
|
-
return { consoleUserId: 'token' };
|
|
3024
|
-
}
|
|
2870
|
+
const bearerToken = parseBearerToken(c.req.header('Authorization'));
|
|
2871
|
+
if (bearerToken === expectedToken) {
|
|
2872
|
+
return { consoleUserId: 'token' };
|
|
3025
2873
|
}
|
|
3026
2874
|
return null;
|
|
3027
2875
|
};
|