@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.
Files changed (56) hide show
  1. package/README.md +23 -0
  2. package/dist/api-key-auth.js +1 -1
  3. package/dist/blobs.d.ts.map +1 -1
  4. package/dist/blobs.js +31 -8
  5. package/dist/blobs.js.map +1 -1
  6. package/dist/console/index.d.ts +1 -1
  7. package/dist/console/index.d.ts.map +1 -1
  8. package/dist/console/index.js +1 -1
  9. package/dist/console/index.js.map +1 -1
  10. package/dist/console/routes.d.ts +1 -2
  11. package/dist/console/routes.d.ts.map +1 -1
  12. package/dist/console/routes.js +65 -2
  13. package/dist/console/routes.js.map +1 -1
  14. package/dist/console/schemas.d.ts +138 -496
  15. package/dist/console/schemas.d.ts.map +1 -1
  16. package/dist/console/schemas.js +3 -9
  17. package/dist/console/schemas.js.map +1 -1
  18. package/dist/create-server.d.ts +3 -1
  19. package/dist/create-server.d.ts.map +1 -1
  20. package/dist/create-server.js +4 -3
  21. package/dist/create-server.js.map +1 -1
  22. package/dist/index.d.ts +3 -3
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +9 -9
  25. package/dist/index.js.map +1 -1
  26. package/dist/proxy/connection-manager.d.ts +1 -1
  27. package/dist/proxy/connection-manager.d.ts.map +1 -1
  28. package/dist/proxy/connection-manager.js +1 -1
  29. package/dist/proxy/connection-manager.js.map +1 -1
  30. package/dist/proxy/index.js +2 -2
  31. package/dist/proxy/routes.d.ts +2 -2
  32. package/dist/proxy/routes.d.ts.map +1 -1
  33. package/dist/proxy/routes.js +3 -3
  34. package/dist/proxy/routes.js.map +1 -1
  35. package/dist/routes.d.ts +2 -2
  36. package/dist/routes.d.ts.map +1 -1
  37. package/dist/routes.js +447 -260
  38. package/dist/routes.js.map +1 -1
  39. package/dist/ws.d.ts +40 -3
  40. package/dist/ws.d.ts.map +1 -1
  41. package/dist/ws.js +51 -6
  42. package/dist/ws.js.map +1 -1
  43. package/package.json +32 -9
  44. package/src/__tests__/pull-chunk-storage.test.ts +415 -27
  45. package/src/__tests__/realtime-bridge.test.ts +3 -1
  46. package/src/__tests__/sync-rate-limit-routing.test.ts +181 -0
  47. package/src/blobs.ts +31 -8
  48. package/src/console/index.ts +1 -0
  49. package/src/console/routes.ts +78 -25
  50. package/src/console/schemas.ts +0 -31
  51. package/src/create-server.ts +6 -0
  52. package/src/index.ts +12 -3
  53. package/src/proxy/connection-manager.ts +2 -2
  54. package/src/proxy/routes.ts +3 -3
  55. package/src/routes.ts +570 -327
  56. 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 ok = safeSend(
103
- ws,
104
- JSON.stringify({
105
- event: 'sync',
106
- data: { cursor, timestamp: Date.now() },
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
- conn.sendSync(cursor);
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