@syncular/server-hono 0.0.6-95 → 0.0.6-96
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/routes.d.ts.map +1 -1
- package/dist/console/routes.js +176 -37
- package/dist/console/routes.js.map +1 -1
- package/dist/console/types.d.ts +33 -0
- package/dist/console/types.d.ts.map +1 -1
- package/dist/create-server.d.ts.map +1 -1
- package/dist/create-server.js +1 -0
- package/dist/create-server.js.map +1 -1
- package/dist/routes.d.ts +16 -0
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +77 -55
- package/dist/routes.js.map +1 -1
- package/package.json +6 -6
- package/src/__tests__/console-routes.test.ts +92 -9
- package/src/__tests__/create-server.test.ts +147 -4
- package/src/console/routes.ts +233 -45
- package/src/console/types.ts +34 -0
- package/src/create-server.ts +1 -0
- package/src/routes.ts +107 -55
package/src/routes.ts
CHANGED
|
@@ -121,6 +121,22 @@ export interface SyncRoutesConfigWithRateLimit {
|
|
|
121
121
|
* Default: 200
|
|
122
122
|
*/
|
|
123
123
|
maxOperationsPerPush?: number;
|
|
124
|
+
/**
|
|
125
|
+
* Request/response payload snapshots recorded for console inspection.
|
|
126
|
+
*/
|
|
127
|
+
requestPayloadSnapshots?: {
|
|
128
|
+
/**
|
|
129
|
+
* Enable payload snapshot storage in `sync_request_payloads`.
|
|
130
|
+
* Default: true when console event recording is enabled.
|
|
131
|
+
*/
|
|
132
|
+
enabled?: boolean;
|
|
133
|
+
/**
|
|
134
|
+
* Max serialized payload size in bytes per request/response snapshot.
|
|
135
|
+
* Larger payloads are truncated with metadata.
|
|
136
|
+
* Default: 128 KiB.
|
|
137
|
+
*/
|
|
138
|
+
maxBytes?: number;
|
|
139
|
+
};
|
|
124
140
|
/**
|
|
125
141
|
* Rate limiting configuration.
|
|
126
142
|
* Set to false to disable all rate limiting.
|
|
@@ -212,7 +228,7 @@ const snapshotChunkParamsSchema = z.object({
|
|
|
212
228
|
chunkId: z.string().min(1),
|
|
213
229
|
});
|
|
214
230
|
|
|
215
|
-
const
|
|
231
|
+
const DEFAULT_REQUEST_PAYLOAD_SNAPSHOT_MAX_BYTES = 128 * 1024;
|
|
216
232
|
|
|
217
233
|
type TraceContext = {
|
|
218
234
|
traceId: string | null;
|
|
@@ -259,6 +275,19 @@ function parseSentryTraceHeader(
|
|
|
259
275
|
return { traceId, spanId };
|
|
260
276
|
}
|
|
261
277
|
|
|
278
|
+
function readPositiveInteger(
|
|
279
|
+
value: number | undefined,
|
|
280
|
+
fallback: number
|
|
281
|
+
): number {
|
|
282
|
+
if (typeof value !== 'number' || !Number.isFinite(value)) {
|
|
283
|
+
return fallback;
|
|
284
|
+
}
|
|
285
|
+
if (value <= 0) {
|
|
286
|
+
return fallback;
|
|
287
|
+
}
|
|
288
|
+
return Math.floor(value);
|
|
289
|
+
}
|
|
290
|
+
|
|
262
291
|
function readTraceContext(c: Context): TraceContext {
|
|
263
292
|
const traceparent = parseW3cTraceparent(c.req.header('traceparent'));
|
|
264
293
|
if (traceparent) return traceparent;
|
|
@@ -406,16 +435,16 @@ function countPullRows(response: PullResult['response']): number {
|
|
|
406
435
|
}, 0);
|
|
407
436
|
}
|
|
408
437
|
|
|
409
|
-
function encodePayloadSnapshot(value: unknown): string {
|
|
438
|
+
function encodePayloadSnapshot(value: unknown, maxBytes: number): string {
|
|
410
439
|
try {
|
|
411
440
|
const serialized = JSON.stringify(value);
|
|
412
|
-
if (serialized.length <=
|
|
441
|
+
if (serialized.length <= maxBytes) {
|
|
413
442
|
return serialized;
|
|
414
443
|
}
|
|
415
444
|
return JSON.stringify({
|
|
416
445
|
truncated: true,
|
|
417
446
|
originalSizeBytes: serialized.length,
|
|
418
|
-
preview: serialized.slice(0,
|
|
447
|
+
preview: serialized.slice(0, maxBytes),
|
|
419
448
|
});
|
|
420
449
|
} catch {
|
|
421
450
|
return JSON.stringify({
|
|
@@ -470,6 +499,13 @@ export function createSyncRoutes<
|
|
|
470
499
|
const consoleLiveEmitter = options.consoleLiveEmitter;
|
|
471
500
|
const shouldEmitConsoleLiveEvents = consoleLiveEmitter !== undefined;
|
|
472
501
|
const shouldRecordRequestEvents = shouldEmitConsoleLiveEvents;
|
|
502
|
+
const shouldCaptureRequestPayloadSnapshots =
|
|
503
|
+
shouldRecordRequestEvents &&
|
|
504
|
+
config.requestPayloadSnapshots?.enabled !== false;
|
|
505
|
+
const requestPayloadSnapshotMaxBytes = readPositiveInteger(
|
|
506
|
+
config.requestPayloadSnapshots?.maxBytes,
|
|
507
|
+
DEFAULT_REQUEST_PAYLOAD_SNAPSHOT_MAX_BYTES
|
|
508
|
+
);
|
|
473
509
|
const consoleSchemaReadyBase = shouldRecordRequestEvents
|
|
474
510
|
? (options.consoleSchemaReady ??
|
|
475
511
|
options.dialect.ensureConsoleSchema?.(options.db) ??
|
|
@@ -592,8 +628,14 @@ export function createSyncRoutes<
|
|
|
592
628
|
payload_ref, partition_id, request_payload, response_payload, created_at
|
|
593
629
|
) VALUES (
|
|
594
630
|
${nextPayloadRef}, ${event.partitionId},
|
|
595
|
-
${encodePayloadSnapshot(
|
|
596
|
-
|
|
631
|
+
${encodePayloadSnapshot(
|
|
632
|
+
event.payloadSnapshot.request,
|
|
633
|
+
requestPayloadSnapshotMaxBytes
|
|
634
|
+
)},
|
|
635
|
+
${encodePayloadSnapshot(
|
|
636
|
+
event.payloadSnapshot.response,
|
|
637
|
+
requestPayloadSnapshotMaxBytes
|
|
638
|
+
)},
|
|
597
639
|
${nowIso}
|
|
598
640
|
)
|
|
599
641
|
ON CONFLICT (payload_ref) DO UPDATE SET
|
|
@@ -854,15 +896,17 @@ export function createSyncRoutes<
|
|
|
854
896
|
commitSeq: pushed.response.commitSeq,
|
|
855
897
|
operationCount: pushOps.length,
|
|
856
898
|
tables: pushed.affectedTables,
|
|
857
|
-
payloadSnapshot:
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
899
|
+
payloadSnapshot: shouldCaptureRequestPayloadSnapshots
|
|
900
|
+
? {
|
|
901
|
+
request: {
|
|
902
|
+
clientId,
|
|
903
|
+
clientCommitId: pushBody.clientCommitId,
|
|
904
|
+
schemaVersion: pushBody.schemaVersion,
|
|
905
|
+
operations: pushBody.operations,
|
|
906
|
+
},
|
|
907
|
+
response: pushed.response,
|
|
908
|
+
}
|
|
909
|
+
: null,
|
|
866
910
|
}));
|
|
867
911
|
emitConsoleLiveEvent(consoleLiveEmitter, 'push', () => ({
|
|
868
912
|
partitionId,
|
|
@@ -1073,7 +1117,7 @@ export function createSyncRoutes<
|
|
|
1073
1117
|
const scopesSummary = shouldRecordRequestEvents
|
|
1074
1118
|
? summarizeScopeValues(pullResult.effectiveScopes)
|
|
1075
1119
|
: null;
|
|
1076
|
-
const payloadSnapshot =
|
|
1120
|
+
const payloadSnapshot = shouldCaptureRequestPayloadSnapshots
|
|
1077
1121
|
? {
|
|
1078
1122
|
request: {
|
|
1079
1123
|
clientId,
|
|
@@ -1586,14 +1630,16 @@ export function createSyncRoutes<
|
|
|
1586
1630
|
durationMs: invalidDurationMs,
|
|
1587
1631
|
errorCode: 'INVALID_PUSH_PAYLOAD',
|
|
1588
1632
|
errorMessage: 'Invalid push payload',
|
|
1589
|
-
payloadSnapshot:
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1633
|
+
payloadSnapshot: shouldCaptureRequestPayloadSnapshots
|
|
1634
|
+
? {
|
|
1635
|
+
request: msg,
|
|
1636
|
+
response: {
|
|
1637
|
+
ok: false,
|
|
1638
|
+
status: 'rejected',
|
|
1639
|
+
reason: 'invalid_push_payload',
|
|
1640
|
+
},
|
|
1641
|
+
}
|
|
1642
|
+
: null,
|
|
1597
1643
|
}));
|
|
1598
1644
|
emitConsoleLiveEvent(consoleLiveEmitter, 'push', () => ({
|
|
1599
1645
|
partitionId,
|
|
@@ -1644,19 +1690,21 @@ export function createSyncRoutes<
|
|
|
1644
1690
|
errorCode: 'MAX_OPERATIONS_EXCEEDED',
|
|
1645
1691
|
errorMessage: `Maximum ${maxOperationsPerPush} operations per push`,
|
|
1646
1692
|
operationCount: pushOps.length,
|
|
1647
|
-
payloadSnapshot:
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1693
|
+
payloadSnapshot: shouldCaptureRequestPayloadSnapshots
|
|
1694
|
+
? {
|
|
1695
|
+
request: {
|
|
1696
|
+
clientId,
|
|
1697
|
+
clientCommitId: parsed.data.clientCommitId,
|
|
1698
|
+
schemaVersion: parsed.data.schemaVersion,
|
|
1699
|
+
operations: parsed.data.operations,
|
|
1700
|
+
},
|
|
1701
|
+
response: {
|
|
1702
|
+
ok: false,
|
|
1703
|
+
status: 'rejected',
|
|
1704
|
+
reason: 'max_operations_exceeded',
|
|
1705
|
+
},
|
|
1706
|
+
}
|
|
1707
|
+
: null,
|
|
1660
1708
|
}));
|
|
1661
1709
|
emitConsoleLiveEvent(consoleLiveEmitter, 'push', () => ({
|
|
1662
1710
|
partitionId,
|
|
@@ -1718,15 +1766,17 @@ export function createSyncRoutes<
|
|
|
1718
1766
|
commitSeq: pushed.response.commitSeq,
|
|
1719
1767
|
operationCount: pushOps.length,
|
|
1720
1768
|
tables: pushed.affectedTables,
|
|
1721
|
-
payloadSnapshot:
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1769
|
+
payloadSnapshot: shouldCaptureRequestPayloadSnapshots
|
|
1770
|
+
? {
|
|
1771
|
+
request: {
|
|
1772
|
+
clientId,
|
|
1773
|
+
clientCommitId: parsed.data.clientCommitId,
|
|
1774
|
+
schemaVersion: parsed.data.schemaVersion,
|
|
1775
|
+
operations: parsed.data.operations,
|
|
1776
|
+
},
|
|
1777
|
+
response: pushed.response,
|
|
1778
|
+
}
|
|
1779
|
+
: null,
|
|
1730
1780
|
}));
|
|
1731
1781
|
emitConsoleLiveEvent(consoleLiveEmitter, 'push', () => ({
|
|
1732
1782
|
partitionId,
|
|
@@ -1848,15 +1898,17 @@ export function createSyncRoutes<
|
|
|
1848
1898
|
durationMs: failedDurationMs,
|
|
1849
1899
|
errorCode: 'INTERNAL_SERVER_ERROR',
|
|
1850
1900
|
errorMessage: message,
|
|
1851
|
-
payloadSnapshot:
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1901
|
+
payloadSnapshot: shouldCaptureRequestPayloadSnapshots
|
|
1902
|
+
? {
|
|
1903
|
+
request: msg,
|
|
1904
|
+
response: {
|
|
1905
|
+
ok: false,
|
|
1906
|
+
status: 'rejected',
|
|
1907
|
+
reason: 'internal_server_error',
|
|
1908
|
+
message,
|
|
1909
|
+
},
|
|
1910
|
+
}
|
|
1911
|
+
: null,
|
|
1860
1912
|
}));
|
|
1861
1913
|
emitConsoleLiveEvent(consoleLiveEmitter, 'push', () => ({
|
|
1862
1914
|
partitionId,
|