@syncular/server-hono 0.0.1 → 0.0.2-126
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/README.md +23 -0
- package/dist/api-key-auth.js +1 -1
- package/dist/blobs.d.ts.map +1 -1
- package/dist/blobs.js +31 -8
- package/dist/blobs.js.map +1 -1
- package/dist/console/index.d.ts +1 -1
- package/dist/console/index.d.ts.map +1 -1
- package/dist/console/index.js +1 -1
- package/dist/console/index.js.map +1 -1
- package/dist/console/routes.d.ts +1 -2
- package/dist/console/routes.d.ts.map +1 -1
- package/dist/console/routes.js +65 -2
- package/dist/console/routes.js.map +1 -1
- package/dist/console/schemas.d.ts +138 -496
- package/dist/console/schemas.d.ts.map +1 -1
- package/dist/console/schemas.js +3 -9
- package/dist/console/schemas.js.map +1 -1
- package/dist/create-server.d.ts +3 -1
- package/dist/create-server.d.ts.map +1 -1
- package/dist/create-server.js +4 -3
- package/dist/create-server.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -9
- package/dist/index.js.map +1 -1
- package/dist/proxy/connection-manager.d.ts +1 -1
- package/dist/proxy/connection-manager.d.ts.map +1 -1
- package/dist/proxy/connection-manager.js +1 -1
- package/dist/proxy/connection-manager.js.map +1 -1
- package/dist/proxy/index.js +2 -2
- package/dist/proxy/routes.d.ts +2 -2
- package/dist/proxy/routes.d.ts.map +1 -1
- package/dist/proxy/routes.js +3 -3
- package/dist/proxy/routes.js.map +1 -1
- package/dist/routes.d.ts +2 -2
- package/dist/routes.d.ts.map +1 -1
- package/dist/routes.js +447 -260
- package/dist/routes.js.map +1 -1
- package/dist/ws.d.ts +40 -3
- package/dist/ws.d.ts.map +1 -1
- package/dist/ws.js +51 -6
- package/dist/ws.js.map +1 -1
- package/package.json +32 -9
- package/src/__tests__/pull-chunk-storage.test.ts +415 -27
- package/src/__tests__/realtime-bridge.test.ts +3 -1
- package/src/__tests__/sync-rate-limit-routing.test.ts +181 -0
- package/src/blobs.ts +31 -8
- package/src/console/index.ts +1 -0
- package/src/console/routes.ts +78 -25
- package/src/console/schemas.ts +0 -31
- package/src/create-server.ts +6 -0
- package/src/index.ts +12 -3
- package/src/proxy/connection-manager.ts +2 -2
- package/src/proxy/routes.ts +3 -3
- package/src/routes.ts +570 -327
- package/src/ws.ts +76 -13
package/src/ws.ts
CHANGED
|
@@ -17,12 +17,23 @@ export interface PresenceEntry {
|
|
|
17
17
|
metadata?: Record<string, unknown>;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Push response data sent back to the client over WS
|
|
22
|
+
*/
|
|
23
|
+
export interface WsPushResponseData {
|
|
24
|
+
requestId: string;
|
|
25
|
+
ok: boolean;
|
|
26
|
+
status: string;
|
|
27
|
+
commitSeq?: number;
|
|
28
|
+
results: Array<{ opIndex: number; status: string; [k: string]: unknown }>;
|
|
29
|
+
}
|
|
30
|
+
|
|
20
31
|
/**
|
|
21
32
|
* WebSocket event data for sync notifications
|
|
22
33
|
*/
|
|
23
34
|
export interface SyncWebSocketEvent {
|
|
24
35
|
/** Event type */
|
|
25
|
-
event: 'sync' | 'heartbeat' | 'error' | 'presence';
|
|
36
|
+
event: 'sync' | 'heartbeat' | 'error' | 'presence' | 'push-response';
|
|
26
37
|
/** Data payload */
|
|
27
38
|
data: {
|
|
28
39
|
/** New cursor position (for sync events) */
|
|
@@ -38,6 +49,12 @@ export interface SyncWebSocketEvent {
|
|
|
38
49
|
metadata?: Record<string, unknown>;
|
|
39
50
|
entries?: PresenceEntry[];
|
|
40
51
|
};
|
|
52
|
+
/** Push response data (for push-response events) */
|
|
53
|
+
requestId?: string;
|
|
54
|
+
ok?: boolean;
|
|
55
|
+
status?: string;
|
|
56
|
+
commitSeq?: number;
|
|
57
|
+
results?: Array<{ opIndex: number; status: string; [k: string]: unknown }>;
|
|
41
58
|
/** Timestamp */
|
|
42
59
|
timestamp: number;
|
|
43
60
|
};
|
|
@@ -47,8 +64,8 @@ export interface SyncWebSocketEvent {
|
|
|
47
64
|
* WebSocket connection controller for managing active connections
|
|
48
65
|
*/
|
|
49
66
|
export interface WebSocketConnection {
|
|
50
|
-
/** Send a sync notification */
|
|
51
|
-
sendSync(cursor: number): void;
|
|
67
|
+
/** Send a sync notification, optionally with inline change data */
|
|
68
|
+
sendSync(cursor: number, changes?: unknown[]): void;
|
|
52
69
|
/** Send a heartbeat */
|
|
53
70
|
sendHeartbeat(): void;
|
|
54
71
|
/** Send a presence event */
|
|
@@ -60,6 +77,8 @@ export interface WebSocketConnection {
|
|
|
60
77
|
metadata?: Record<string, unknown>;
|
|
61
78
|
entries?: PresenceEntry[];
|
|
62
79
|
}): void;
|
|
80
|
+
/** Send a push response back to the client */
|
|
81
|
+
sendPushResponse(data: WsPushResponseData): void;
|
|
63
82
|
/** Send an error and close */
|
|
64
83
|
sendError(message: string): void;
|
|
65
84
|
/** Close the connection */
|
|
@@ -97,15 +116,16 @@ export function createWebSocketConnection(
|
|
|
97
116
|
actorId: args.actorId,
|
|
98
117
|
clientId: args.clientId,
|
|
99
118
|
transportPath: args.transportPath,
|
|
100
|
-
sendSync(cursor: number) {
|
|
119
|
+
sendSync(cursor: number, changes?: unknown[]) {
|
|
101
120
|
if (!connection.isOpen) return;
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
121
|
+
const payload: Record<string, unknown> = {
|
|
122
|
+
cursor,
|
|
123
|
+
timestamp: Date.now(),
|
|
124
|
+
};
|
|
125
|
+
if (changes && changes.length > 0) {
|
|
126
|
+
payload.changes = changes;
|
|
127
|
+
}
|
|
128
|
+
const ok = safeSend(ws, JSON.stringify({ event: 'sync', data: payload }));
|
|
109
129
|
if (!ok) closed = true;
|
|
110
130
|
},
|
|
111
131
|
sendHeartbeat() {
|
|
@@ -134,6 +154,17 @@ export function createWebSocketConnection(
|
|
|
134
154
|
);
|
|
135
155
|
if (!ok) closed = true;
|
|
136
156
|
},
|
|
157
|
+
sendPushResponse(data: WsPushResponseData) {
|
|
158
|
+
if (!connection.isOpen) return;
|
|
159
|
+
const ok = safeSend(
|
|
160
|
+
ws,
|
|
161
|
+
JSON.stringify({
|
|
162
|
+
event: 'push-response',
|
|
163
|
+
data: { ...data, timestamp: Date.now() },
|
|
164
|
+
})
|
|
165
|
+
);
|
|
166
|
+
if (!ok) closed = true;
|
|
167
|
+
},
|
|
137
168
|
sendError(message: string) {
|
|
138
169
|
if (connection.isOpen) {
|
|
139
170
|
safeSend(
|
|
@@ -575,10 +606,16 @@ export class WebSocketConnectionManager {
|
|
|
575
606
|
* Notify clients that new data is available for the given scopes.
|
|
576
607
|
* Dedupes connections that match multiple scopes.
|
|
577
608
|
*/
|
|
609
|
+
/**
|
|
610
|
+
* Maximum serialized size (bytes) for inline WS change delivery.
|
|
611
|
+
* Larger payloads fall back to cursor-only notification.
|
|
612
|
+
*/
|
|
613
|
+
private static readonly WS_INLINE_MAX_BYTES = 64 * 1024;
|
|
614
|
+
|
|
578
615
|
notifyScopeKeys(
|
|
579
616
|
scopeKeys: string[],
|
|
580
617
|
cursor: number,
|
|
581
|
-
opts?: { excludeClientIds?: string[] }
|
|
618
|
+
opts?: { excludeClientIds?: string[]; changes?: unknown[] }
|
|
582
619
|
): void {
|
|
583
620
|
const exclude = new Set(opts?.excludeClientIds ?? []);
|
|
584
621
|
const targets = new Set<WebSocketConnection>();
|
|
@@ -589,10 +626,36 @@ export class WebSocketConnectionManager {
|
|
|
589
626
|
for (const conn of conns) targets.add(conn);
|
|
590
627
|
}
|
|
591
628
|
|
|
629
|
+
// Size guard: only deliver inline changes if under threshold
|
|
630
|
+
let inlineChanges: unknown[] | undefined;
|
|
631
|
+
if (opts?.changes && opts.changes.length > 0) {
|
|
632
|
+
const serialized = JSON.stringify(opts.changes);
|
|
633
|
+
if (serialized.length <= WebSocketConnectionManager.WS_INLINE_MAX_BYTES) {
|
|
634
|
+
inlineChanges = opts.changes;
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
|
|
592
638
|
for (const conn of targets) {
|
|
593
639
|
if (!conn.isOpen) continue;
|
|
594
640
|
if (exclude.has(conn.clientId)) continue;
|
|
595
|
-
|
|
641
|
+
if (inlineChanges) {
|
|
642
|
+
conn.sendSync(cursor, inlineChanges);
|
|
643
|
+
} else {
|
|
644
|
+
conn.sendSync(cursor);
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
/**
|
|
650
|
+
* Notify all connected clients of a new cursor position.
|
|
651
|
+
* Used for external data changes that affect all clients regardless of scope.
|
|
652
|
+
*/
|
|
653
|
+
notifyAllClients(cursor: number): void {
|
|
654
|
+
for (const conns of this.connectionsByClientId.values()) {
|
|
655
|
+
for (const conn of conns) {
|
|
656
|
+
if (!conn.isOpen) continue;
|
|
657
|
+
conn.sendSync(cursor);
|
|
658
|
+
}
|
|
596
659
|
}
|
|
597
660
|
}
|
|
598
661
|
|