@quereus/sync-coordinator 0.8.2 → 0.9.1
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 +3 -3
- package/dist/src/common/index.d.ts +1 -0
- package/dist/src/common/index.d.ts.map +1 -1
- package/dist/src/common/index.js +1 -0
- package/dist/src/common/index.js.map +1 -1
- package/dist/src/common/serialization.d.ts +23 -0
- package/dist/src/common/serialization.d.ts.map +1 -0
- package/dist/src/common/serialization.js +86 -0
- package/dist/src/common/serialization.js.map +1 -0
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/metrics/coordinator-metrics.d.ts +1 -0
- package/dist/src/metrics/coordinator-metrics.d.ts.map +1 -1
- package/dist/src/metrics/coordinator-metrics.js +2 -0
- package/dist/src/metrics/coordinator-metrics.js.map +1 -1
- package/dist/src/server/routes.d.ts.map +1 -1
- package/dist/src/server/routes.js +7 -31
- package/dist/src/server/routes.js.map +1 -1
- package/dist/src/server/websocket.d.ts +1 -0
- package/dist/src/server/websocket.d.ts.map +1 -1
- package/dist/src/server/websocket.js +74 -51
- package/dist/src/server/websocket.js.map +1 -1
- package/dist/src/service/coordinator-service.d.ts +5 -5
- package/dist/src/service/coordinator-service.d.ts.map +1 -1
- package/dist/src/service/coordinator-service.js +34 -30
- package/dist/src/service/coordinator-service.js.map +1 -1
- package/dist/src/service/index.d.ts +2 -2
- package/dist/src/service/index.d.ts.map +1 -1
- package/dist/src/service/index.js +1 -1
- package/dist/src/service/index.js.map +1 -1
- package/dist/src/service/s3-batch-store.d.ts +1 -6
- package/dist/src/service/s3-batch-store.d.ts.map +1 -1
- package/dist/src/service/s3-batch-store.js +1 -9
- package/dist/src/service/s3-batch-store.js.map +1 -1
- package/dist/src/service/s3-config.d.ts +10 -0
- package/dist/src/service/s3-config.d.ts.map +1 -1
- package/dist/src/service/s3-config.js +7 -0
- package/dist/src/service/s3-config.js.map +1 -1
- package/dist/src/service/s3-snapshot-store.d.ts +1 -5
- package/dist/src/service/s3-snapshot-store.d.ts.map +1 -1
- package/dist/src/service/s3-snapshot-store.js +10 -12
- package/dist/src/service/s3-snapshot-store.js.map +1 -1
- package/dist/src/service/store-manager.d.ts +3 -0
- package/dist/src/service/store-manager.d.ts.map +1 -1
- package/dist/src/service/store-manager.js +10 -0
- package/dist/src/service/store-manager.js.map +1 -1
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -112,9 +112,9 @@ npx sync-coordinator --help
|
|
|
112
112
|
|----------|--------|-------------|
|
|
113
113
|
| `/sync/status` | GET | Health check and stats |
|
|
114
114
|
| `/sync/metrics` | GET | Prometheus metrics |
|
|
115
|
-
| `/sync/changes` | GET | Get changes since HLC |
|
|
116
|
-
| `/sync/changes` | POST | Apply changes |
|
|
117
|
-
| `/sync/snapshot` | GET | Stream full snapshot |
|
|
115
|
+
| `/sync/:databaseId/changes` | GET | Get changes since HLC |
|
|
116
|
+
| `/sync/:databaseId/changes` | POST | Apply changes |
|
|
117
|
+
| `/sync/:databaseId/snapshot` | GET | Stream full snapshot (NDJSON) |
|
|
118
118
|
| `/sync/ws` | WS | WebSocket for real-time sync |
|
|
119
119
|
|
|
120
120
|
## Prometheus Metrics
|
|
@@ -2,4 +2,5 @@
|
|
|
2
2
|
* Common utilities for sync-coordinator.
|
|
3
3
|
*/
|
|
4
4
|
export { createLogger, serverLog, httpLog, wsLog, serviceLog, authLog, configLog, } from './logger.js';
|
|
5
|
+
export { serializeChangeSet, deserializeChangeSet, serializeSnapshotChunk, } from './serialization.js';
|
|
5
6
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/common/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,YAAY,EACZ,SAAS,EACT,OAAO,EACP,KAAK,EACL,UAAU,EACV,OAAO,EACP,SAAS,GACV,MAAM,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/common/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,YAAY,EACZ,SAAS,EACT,OAAO,EACP,KAAK,EACL,UAAU,EACV,OAAO,EACP,SAAS,GACV,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,oBAAoB,CAAC"}
|
package/dist/src/common/index.js
CHANGED
|
@@ -2,4 +2,5 @@
|
|
|
2
2
|
* Common utilities for sync-coordinator.
|
|
3
3
|
*/
|
|
4
4
|
export { createLogger, serverLog, httpLog, wsLog, serviceLog, authLog, configLog, } from './logger.js';
|
|
5
|
+
export { serializeChangeSet, deserializeChangeSet, serializeSnapshotChunk, } from './serialization.js';
|
|
5
6
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/common/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,YAAY,EACZ,SAAS,EACT,OAAO,EACP,KAAK,EACL,UAAU,EACV,OAAO,EACP,SAAS,GACV,MAAM,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/common/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,YAAY,EACZ,SAAS,EACT,OAAO,EACP,KAAK,EACL,UAAU,EACV,OAAO,EACP,SAAS,GACV,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,kBAAkB,EAClB,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared serialization for JSON transport.
|
|
3
|
+
*
|
|
4
|
+
* Used by both the WebSocket handler and the HTTP routes
|
|
5
|
+
* for consistent wire format.
|
|
6
|
+
*/
|
|
7
|
+
import { type ChangeSet, type SnapshotChunk } from '@quereus/sync';
|
|
8
|
+
/**
|
|
9
|
+
* Serialize a ChangeSet for JSON transport.
|
|
10
|
+
* Converts binary fields (siteId, HLCs) to base64 strings.
|
|
11
|
+
*/
|
|
12
|
+
export declare function serializeChangeSet(cs: ChangeSet): object;
|
|
13
|
+
/**
|
|
14
|
+
* Serialize a SnapshotChunk for JSON transport.
|
|
15
|
+
* Converts binary fields (siteId, HLCs) to base64 strings.
|
|
16
|
+
*/
|
|
17
|
+
export declare function serializeSnapshotChunk(chunk: SnapshotChunk): object;
|
|
18
|
+
/**
|
|
19
|
+
* Deserialize a ChangeSet from JSON transport format.
|
|
20
|
+
* Converts base64 strings back to binary fields.
|
|
21
|
+
*/
|
|
22
|
+
export declare function deserializeChangeSet(cs: unknown): ChangeSet;
|
|
23
|
+
//# sourceMappingURL=serialization.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialization.d.ts","sourceRoot":"","sources":["../../../src/common/serialization.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAKN,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,MAAM,eAAe,CAAC;AAEvB;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,EAAE,EAAE,SAAS,GAAG,MAAM,CAcxD;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,CAkCnE;AAED;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,OAAO,GAAG,SAAS,CAe3D"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared serialization for JSON transport.
|
|
3
|
+
*
|
|
4
|
+
* Used by both the WebSocket handler and the HTTP routes
|
|
5
|
+
* for consistent wire format.
|
|
6
|
+
*/
|
|
7
|
+
import { siteIdFromBase64, siteIdToBase64, deserializeHLC, serializeHLC, } from '@quereus/sync';
|
|
8
|
+
/**
|
|
9
|
+
* Serialize a ChangeSet for JSON transport.
|
|
10
|
+
* Converts binary fields (siteId, HLCs) to base64 strings.
|
|
11
|
+
*/
|
|
12
|
+
export function serializeChangeSet(cs) {
|
|
13
|
+
return {
|
|
14
|
+
siteId: siteIdToBase64(cs.siteId),
|
|
15
|
+
transactionId: cs.transactionId,
|
|
16
|
+
hlc: Buffer.from(serializeHLC(cs.hlc)).toString('base64'),
|
|
17
|
+
changes: cs.changes.map(c => ({
|
|
18
|
+
...c,
|
|
19
|
+
hlc: Buffer.from(serializeHLC(c.hlc)).toString('base64'),
|
|
20
|
+
})),
|
|
21
|
+
schemaMigrations: cs.schemaMigrations.map(m => ({
|
|
22
|
+
...m,
|
|
23
|
+
hlc: Buffer.from(serializeHLC(m.hlc)).toString('base64'),
|
|
24
|
+
})),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Serialize a SnapshotChunk for JSON transport.
|
|
29
|
+
* Converts binary fields (siteId, HLCs) to base64 strings.
|
|
30
|
+
*/
|
|
31
|
+
export function serializeSnapshotChunk(chunk) {
|
|
32
|
+
switch (chunk.type) {
|
|
33
|
+
case 'header':
|
|
34
|
+
return {
|
|
35
|
+
type: chunk.type,
|
|
36
|
+
siteId: siteIdToBase64(chunk.siteId),
|
|
37
|
+
hlc: Buffer.from(serializeHLC(chunk.hlc)).toString('base64'),
|
|
38
|
+
tableCount: chunk.tableCount,
|
|
39
|
+
migrationCount: chunk.migrationCount,
|
|
40
|
+
snapshotId: chunk.snapshotId,
|
|
41
|
+
};
|
|
42
|
+
case 'column-versions':
|
|
43
|
+
return {
|
|
44
|
+
type: chunk.type,
|
|
45
|
+
schema: chunk.schema,
|
|
46
|
+
table: chunk.table,
|
|
47
|
+
entries: chunk.entries.map(([key, hlc, value]) => [
|
|
48
|
+
key,
|
|
49
|
+
Buffer.from(serializeHLC(hlc)).toString('base64'),
|
|
50
|
+
value,
|
|
51
|
+
]),
|
|
52
|
+
};
|
|
53
|
+
case 'schema-migration':
|
|
54
|
+
return {
|
|
55
|
+
type: chunk.type,
|
|
56
|
+
migration: {
|
|
57
|
+
...chunk.migration,
|
|
58
|
+
hlc: Buffer.from(serializeHLC(chunk.migration.hlc)).toString('base64'),
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
// table-start, table-end, footer have no binary fields
|
|
62
|
+
default:
|
|
63
|
+
return chunk;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Deserialize a ChangeSet from JSON transport format.
|
|
68
|
+
* Converts base64 strings back to binary fields.
|
|
69
|
+
*/
|
|
70
|
+
export function deserializeChangeSet(cs) {
|
|
71
|
+
const obj = cs;
|
|
72
|
+
return {
|
|
73
|
+
siteId: siteIdFromBase64(obj.siteId),
|
|
74
|
+
transactionId: obj.transactionId,
|
|
75
|
+
hlc: deserializeHLC(Buffer.from(obj.hlc, 'base64')),
|
|
76
|
+
changes: obj.changes.map(c => ({
|
|
77
|
+
...c,
|
|
78
|
+
hlc: deserializeHLC(Buffer.from(c.hlc, 'base64')),
|
|
79
|
+
})),
|
|
80
|
+
schemaMigrations: (obj.schemaMigrations || []).map(m => ({
|
|
81
|
+
...m,
|
|
82
|
+
hlc: deserializeHLC(Buffer.from(m.hlc, 'base64')),
|
|
83
|
+
})),
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=serialization.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serialization.js","sourceRoot":"","sources":["../../../src/common/serialization.ts"],"names":[],"mappings":"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"}
|
package/dist/src/index.d.ts
CHANGED
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
* ```
|
|
15
15
|
*/
|
|
16
16
|
export { type CoordinatorConfig, type PartialCoordinatorConfig, type CorsConfig, type AuthConfig, type SyncSettings, type LoggingConfig, DEFAULT_CONFIG, loadConfig, loadConfigFile, loadEnvConfig, } from './config/index.js';
|
|
17
|
-
export { type ClientIdentity, type ClientSession, type AuthContext, type SyncOperation, type RejectedChange, type ValidationResult, type CoordinatorHooks, CoordinatorService, type CoordinatorServiceOptions, StoreManager, type StoreEntry, type StoreManagerConfig, type StoreManagerHooks, type StoreContext, type S3StorageConfig, createS3Client, buildBatchKey, buildSnapshotKey, parseS3ConfigFromEnv, S3BatchStore, createS3BatchStore, type SyncBatch,
|
|
17
|
+
export { type ClientIdentity, type ClientSession, type AuthContext, type SyncOperation, type RejectedChange, type ValidationResult, type CoordinatorHooks, CoordinatorService, type CoordinatorServiceOptions, StoreManager, type StoreEntry, type StoreManagerConfig, type StoreManagerHooks, type StoreContext, type S3StorageConfig, type StoragePathResolver, createS3Client, buildBatchKey, buildSnapshotKey, defaultStoragePathResolver, parseS3ConfigFromEnv, S3BatchStore, createS3BatchStore, type SyncBatch, S3SnapshotStore, createS3SnapshotStore, type SnapshotMetadata, type SnapshotScheduleConfig, } from './service/index.js';
|
|
18
18
|
export { createCoordinatorServer, type CoordinatorServer, type CoordinatorServerOptions, registerRoutes, registerWebSocket, } from './server/index.js';
|
|
19
19
|
export { type CoordinatorMetrics, type CounterMetric, type GaugeMetric, type HistogramMetric, MetricsRegistry, globalRegistry, createCoordinatorMetrics, } from './metrics/index.js';
|
|
20
20
|
export { createLogger } from './common/index.js';
|
package/dist/src/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,wBAAwB,EAC7B,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,cAAc,EACd,UAAU,EACV,cAAc,EACd,aAAa,GACd,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,kBAAkB,EAClB,KAAK,yBAAyB,EAC9B,YAAY,EACZ,KAAK,UAAU,EACf,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,YAAY,EAEjB,KAAK,eAAe,EACpB,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,oBAAoB,EACpB,YAAY,EACZ,kBAAkB,EAClB,KAAK,SAAS,EACd,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,EACL,KAAK,iBAAiB,EACtB,KAAK,wBAAwB,EAC7B,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,aAAa,EAClB,cAAc,EACd,UAAU,EACV,cAAc,EACd,aAAa,GACd,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,KAAK,cAAc,EACnB,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,aAAa,EAClB,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,kBAAkB,EAClB,KAAK,yBAAyB,EAC9B,YAAY,EACZ,KAAK,UAAU,EACf,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,YAAY,EAEjB,KAAK,eAAe,EACpB,KAAK,mBAAmB,EACxB,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,0BAA0B,EAC1B,oBAAoB,EACpB,YAAY,EACZ,kBAAkB,EAClB,KAAK,SAAS,EACd,eAAe,EACf,qBAAqB,EACrB,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,GAC5B,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EACL,uBAAuB,EACvB,KAAK,iBAAiB,EACtB,KAAK,wBAAwB,EAC7B,cAAc,EACd,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,KAAK,kBAAkB,EACvB,KAAK,aAAa,EAClB,KAAK,WAAW,EAChB,KAAK,eAAe,EACpB,eAAe,EACf,cAAc,EACd,wBAAwB,GACzB,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
|
package/dist/src/index.js
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
// Configuration
|
|
17
17
|
export { DEFAULT_CONFIG, loadConfig, loadConfigFile, loadEnvConfig, } from './config/index.js';
|
|
18
18
|
// Service layer
|
|
19
|
-
export { CoordinatorService, StoreManager, createS3Client, buildBatchKey, buildSnapshotKey, parseS3ConfigFromEnv, S3BatchStore, createS3BatchStore, S3SnapshotStore, createS3SnapshotStore, } from './service/index.js';
|
|
19
|
+
export { CoordinatorService, StoreManager, createS3Client, buildBatchKey, buildSnapshotKey, defaultStoragePathResolver, parseS3ConfigFromEnv, S3BatchStore, createS3BatchStore, S3SnapshotStore, createS3SnapshotStore, } from './service/index.js';
|
|
20
20
|
// Server
|
|
21
21
|
export { createCoordinatorServer, registerRoutes, registerWebSocket, } from './server/index.js';
|
|
22
22
|
// Metrics
|
package/dist/src/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,gBAAgB;AAChB,OAAO,EAOL,cAAc,EACd,UAAU,EACV,cAAc,EACd,aAAa,GACd,MAAM,mBAAmB,CAAC;AAE3B,gBAAgB;AAChB,OAAO,EAQL,kBAAkB,EAElB,YAAY,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,gBAAgB;AAChB,OAAO,EAOL,cAAc,EACd,UAAU,EACV,cAAc,EACd,aAAa,GACd,MAAM,mBAAmB,CAAC;AAE3B,gBAAgB;AAChB,OAAO,EAQL,kBAAkB,EAElB,YAAY,EAQZ,cAAc,EACd,aAAa,EACb,gBAAgB,EAChB,0BAA0B,EAC1B,oBAAoB,EACpB,YAAY,EACZ,kBAAkB,EAElB,eAAe,EACf,qBAAqB,GAGtB,MAAM,oBAAoB,CAAC;AAE5B,SAAS;AACT,OAAO,EACL,uBAAuB,EAGvB,cAAc,EACd,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAE3B,UAAU;AACV,OAAO,EAKL,eAAe,EACf,cAAc,EACd,wBAAwB,GACzB,MAAM,oBAAoB,CAAC;AAE5B,mBAAmB;AACnB,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -14,6 +14,7 @@ export declare function createCoordinatorMetrics(registry?: MetricsRegistry): {
|
|
|
14
14
|
changesReceivedTotal: import("./types.js").CounterMetric;
|
|
15
15
|
changesRejectedTotal: import("./types.js").CounterMetric;
|
|
16
16
|
changesBroadcastTotal: import("./types.js").CounterMetric;
|
|
17
|
+
broadcastErrorsTotal: import("./types.js").CounterMetric;
|
|
17
18
|
snapshotRequestsTotal: import("./types.js").CounterMetric;
|
|
18
19
|
snapshotChunksTotal: import("./types.js").CounterMetric;
|
|
19
20
|
applyChangesDuration: import("./types.js").HistogramMetric;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"coordinator-metrics.d.ts","sourceRoot":"","sources":["../../../src/metrics/coordinator-metrics.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAkB,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AAGrE;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,GAAE,eAAgC
|
|
1
|
+
{"version":3,"file":"coordinator-metrics.d.ts","sourceRoot":"","sources":["../../../src/metrics/coordinator-metrics.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAkB,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AAGrE;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,GAAE,eAAgC;;;;;;;;;;;;;;;;;;EAwHlF;AAED,MAAM,MAAM,kBAAkB,GAAG,UAAU,CAAC,OAAO,wBAAwB,CAAC,CAAC"}
|
|
@@ -18,6 +18,7 @@ export function createCoordinatorMetrics(registry = globalRegistry) {
|
|
|
18
18
|
const changesReceivedTotal = registry.registerCounter('sync_changes_received_total', 'Total number of changes received from clients');
|
|
19
19
|
const changesRejectedTotal = registry.registerCounter('sync_changes_rejected_total', 'Total number of changes rejected during validation');
|
|
20
20
|
const changesBroadcastTotal = registry.registerCounter('sync_changes_broadcast_total', 'Total number of changes broadcast to clients');
|
|
21
|
+
const broadcastErrorsTotal = registry.registerCounter('sync_broadcast_errors_total', 'Total broadcast send failures');
|
|
21
22
|
// Snapshot metrics
|
|
22
23
|
const snapshotRequestsTotal = registry.registerCounter('sync_snapshot_requests_total', 'Total snapshot requests');
|
|
23
24
|
const snapshotChunksTotal = registry.registerCounter('sync_snapshot_chunks_total', 'Total snapshot chunks sent');
|
|
@@ -40,6 +41,7 @@ export function createCoordinatorMetrics(registry = globalRegistry) {
|
|
|
40
41
|
changesReceivedTotal,
|
|
41
42
|
changesRejectedTotal,
|
|
42
43
|
changesBroadcastTotal,
|
|
44
|
+
broadcastErrorsTotal,
|
|
43
45
|
// Snapshots
|
|
44
46
|
snapshotRequestsTotal,
|
|
45
47
|
snapshotChunksTotal,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"coordinator-metrics.js","sourceRoot":"","sources":["../../../src/metrics/coordinator-metrics.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,cAAc,EAAwB,MAAM,eAAe,CAAC;AACrE,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAElD;;GAEG;AACH,MAAM,UAAU,wBAAwB,CAAC,WAA4B,cAAc;IACjF,qBAAqB;IACrB,MAAM,mBAAmB,GAAG,QAAQ,CAAC,aAAa,CAChD,mCAAmC,EACnC,gDAAgD,CACjD,CAAC;IAEF,MAAM,kBAAkB,GAAG,QAAQ,CAAC,eAAe,CACjD,kCAAkC,EAClC,2CAA2C,CAC5C,CAAC;IAEF,uBAAuB;IACvB,MAAM,iBAAiB,GAAG,QAAQ,CAAC,eAAe,CAChD,0BAA0B,EAC1B,4CAA4C,CAC7C,CAAC;IAEF,MAAM,mBAAmB,GAAG,QAAQ,CAAC,iBAAiB,CACpD,oCAAoC,EACpC,kCAAkC,CACnC,CAAC;IAEF,yBAAyB;IACzB,MAAM,mBAAmB,GAAG,QAAQ,CAAC,eAAe,CAClD,4BAA4B,EAC5B,iCAAiC,CAClC,CAAC;IAEF,MAAM,oBAAoB,GAAG,QAAQ,CAAC,eAAe,CACnD,6BAA6B,EAC7B,+CAA+C,CAChD,CAAC;IAEF,MAAM,oBAAoB,GAAG,QAAQ,CAAC,eAAe,CACnD,6BAA6B,EAC7B,oDAAoD,CACrD,CAAC;IAEF,MAAM,qBAAqB,GAAG,QAAQ,CAAC,eAAe,CACpD,8BAA8B,EAC9B,8CAA8C,CAC/C,CAAC;IAEF,mBAAmB;IACnB,MAAM,qBAAqB,GAAG,QAAQ,CAAC,eAAe,CACpD,8BAA8B,EAC9B,yBAAyB,CAC1B,CAAC;IAEF,MAAM,mBAAmB,GAAG,QAAQ,CAAC,eAAe,CAClD,4BAA4B,EAC5B,4BAA4B,CAC7B,CAAC;IAEF,sBAAsB;IACtB,MAAM,oBAAoB,GAAG,QAAQ,CAAC,iBAAiB,CACrD,qCAAqC,EACrC,kCAAkC,CACnC,CAAC;IAEF,MAAM,kBAAkB,GAAG,QAAQ,CAAC,iBAAiB,CACnD,mCAAmC,EACnC,uCAAuC,CACxC,CAAC;IAEF,MAAM,eAAe,GAAG,QAAQ,CAAC,iBAAiB,CAChD,wBAAwB,EACxB,8BAA8B,EAC9B,oBAAoB,CACrB,CAAC;IAEF,eAAe;IACf,MAAM,iBAAiB,GAAG,QAAQ,CAAC,eAAe,CAChD,0BAA0B,EAC1B,+BAA+B,CAChC,CAAC;IAEF,MAAM,iBAAiB,GAAG,QAAQ,CAAC,eAAe,CAChD,0BAA0B,EAC1B,+BAA+B,CAChC,CAAC;IAEF,OAAO;QACL,aAAa;QACb,mBAAmB;QACnB,kBAAkB;QAElB,OAAO;QACP,iBAAiB;QACjB,mBAAmB;QAEnB,kBAAkB;QAClB,mBAAmB;QACnB,oBAAoB;QACpB,oBAAoB;QACpB,qBAAqB;
|
|
1
|
+
{"version":3,"file":"coordinator-metrics.js","sourceRoot":"","sources":["../../../src/metrics/coordinator-metrics.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,cAAc,EAAwB,MAAM,eAAe,CAAC;AACrE,OAAO,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAElD;;GAEG;AACH,MAAM,UAAU,wBAAwB,CAAC,WAA4B,cAAc;IACjF,qBAAqB;IACrB,MAAM,mBAAmB,GAAG,QAAQ,CAAC,aAAa,CAChD,mCAAmC,EACnC,gDAAgD,CACjD,CAAC;IAEF,MAAM,kBAAkB,GAAG,QAAQ,CAAC,eAAe,CACjD,kCAAkC,EAClC,2CAA2C,CAC5C,CAAC;IAEF,uBAAuB;IACvB,MAAM,iBAAiB,GAAG,QAAQ,CAAC,eAAe,CAChD,0BAA0B,EAC1B,4CAA4C,CAC7C,CAAC;IAEF,MAAM,mBAAmB,GAAG,QAAQ,CAAC,iBAAiB,CACpD,oCAAoC,EACpC,kCAAkC,CACnC,CAAC;IAEF,yBAAyB;IACzB,MAAM,mBAAmB,GAAG,QAAQ,CAAC,eAAe,CAClD,4BAA4B,EAC5B,iCAAiC,CAClC,CAAC;IAEF,MAAM,oBAAoB,GAAG,QAAQ,CAAC,eAAe,CACnD,6BAA6B,EAC7B,+CAA+C,CAChD,CAAC;IAEF,MAAM,oBAAoB,GAAG,QAAQ,CAAC,eAAe,CACnD,6BAA6B,EAC7B,oDAAoD,CACrD,CAAC;IAEF,MAAM,qBAAqB,GAAG,QAAQ,CAAC,eAAe,CACpD,8BAA8B,EAC9B,8CAA8C,CAC/C,CAAC;IAEF,MAAM,oBAAoB,GAAG,QAAQ,CAAC,eAAe,CACnD,6BAA6B,EAC7B,+BAA+B,CAChC,CAAC;IAEF,mBAAmB;IACnB,MAAM,qBAAqB,GAAG,QAAQ,CAAC,eAAe,CACpD,8BAA8B,EAC9B,yBAAyB,CAC1B,CAAC;IAEF,MAAM,mBAAmB,GAAG,QAAQ,CAAC,eAAe,CAClD,4BAA4B,EAC5B,4BAA4B,CAC7B,CAAC;IAEF,sBAAsB;IACtB,MAAM,oBAAoB,GAAG,QAAQ,CAAC,iBAAiB,CACrD,qCAAqC,EACrC,kCAAkC,CACnC,CAAC;IAEF,MAAM,kBAAkB,GAAG,QAAQ,CAAC,iBAAiB,CACnD,mCAAmC,EACnC,uCAAuC,CACxC,CAAC;IAEF,MAAM,eAAe,GAAG,QAAQ,CAAC,iBAAiB,CAChD,wBAAwB,EACxB,8BAA8B,EAC9B,oBAAoB,CACrB,CAAC;IAEF,eAAe;IACf,MAAM,iBAAiB,GAAG,QAAQ,CAAC,eAAe,CAChD,0BAA0B,EAC1B,+BAA+B,CAChC,CAAC;IAEF,MAAM,iBAAiB,GAAG,QAAQ,CAAC,eAAe,CAChD,0BAA0B,EAC1B,+BAA+B,CAChC,CAAC;IAEF,OAAO;QACL,aAAa;QACb,mBAAmB;QACnB,kBAAkB;QAElB,OAAO;QACP,iBAAiB;QACjB,mBAAmB;QAEnB,kBAAkB;QAClB,mBAAmB;QACnB,oBAAoB;QACpB,oBAAoB;QACpB,qBAAqB;QACrB,oBAAoB;QAEpB,YAAY;QACZ,qBAAqB;QACrB,mBAAmB;QAEnB,cAAc;QACd,oBAAoB;QACpB,kBAAkB;QAClB,eAAe;QAEf,OAAO;QACP,iBAAiB;QACjB,iBAAiB;QAEjB,qBAAqB;QACrB,QAAQ;KACT,CAAC;AACJ,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../../src/server/routes.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAgC,MAAM,SAAS,CAAC;AAE7E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;
|
|
1
|
+
{"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../../src/server/routes.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAgC,MAAM,SAAS,CAAC;AAE7E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAK5E;;GAEG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,eAAe,EACpB,OAAO,EAAE,kBAAkB,EAC3B,QAAQ,EAAE,MAAM,GACf,IAAI,CA0JN"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* HTTP routes for sync operations.
|
|
3
3
|
*/
|
|
4
|
-
import { siteIdFromBase64,
|
|
4
|
+
import { siteIdFromBase64, deserializeHLC } from '@quereus/sync';
|
|
5
5
|
import { httpLog } from '../common/logger.js';
|
|
6
|
+
import { serializeChangeSet, deserializeChangeSet, serializeSnapshotChunk } from '../common/serialization.js';
|
|
6
7
|
/**
|
|
7
8
|
* Register sync HTTP routes.
|
|
8
9
|
*/
|
|
@@ -84,20 +85,7 @@ export function registerRoutes(app, service, basePath) {
|
|
|
84
85
|
sinceHLC = deserializeHLC(hlcBytes);
|
|
85
86
|
}
|
|
86
87
|
const changes = await service.getChangesSince(databaseId, client, sinceHLC);
|
|
87
|
-
|
|
88
|
-
const serializedChanges = changes.map(cs => ({
|
|
89
|
-
...cs,
|
|
90
|
-
siteId: siteIdToBase64(cs.siteId),
|
|
91
|
-
hlc: Buffer.from(serializeHLC(cs.hlc)).toString('base64'),
|
|
92
|
-
changes: cs.changes.map(c => ({
|
|
93
|
-
...c,
|
|
94
|
-
hlc: Buffer.from(serializeHLC(c.hlc)).toString('base64'),
|
|
95
|
-
})),
|
|
96
|
-
schemaMigrations: cs.schemaMigrations.map(m => ({
|
|
97
|
-
...m,
|
|
98
|
-
hlc: Buffer.from(serializeHLC(m.hlc)).toString('base64'),
|
|
99
|
-
})),
|
|
100
|
-
}));
|
|
88
|
+
const serializedChanges = changes.map(cs => serializeChangeSet(cs));
|
|
101
89
|
return reply.send({ ok: true, data: { changes: serializedChanges } });
|
|
102
90
|
}
|
|
103
91
|
catch (err) {
|
|
@@ -120,20 +108,7 @@ export function registerRoutes(app, service, basePath) {
|
|
|
120
108
|
if (!body.changes || !Array.isArray(body.changes)) {
|
|
121
109
|
return errorResponse(reply, 'INVALID_BODY', 'Request body must contain changes array');
|
|
122
110
|
}
|
|
123
|
-
|
|
124
|
-
const changes = body.changes.map((cs) => ({
|
|
125
|
-
siteId: siteIdFromBase64(cs.siteId),
|
|
126
|
-
transactionId: cs.transactionId,
|
|
127
|
-
hlc: deserializeHLC(Buffer.from(cs.hlc, 'base64')),
|
|
128
|
-
changes: cs.changes.map(c => ({
|
|
129
|
-
...c,
|
|
130
|
-
hlc: deserializeHLC(Buffer.from(c.hlc, 'base64')),
|
|
131
|
-
})),
|
|
132
|
-
schemaMigrations: (cs.schemaMigrations || []).map(m => ({
|
|
133
|
-
...m,
|
|
134
|
-
hlc: deserializeHLC(Buffer.from(m.hlc, 'base64')),
|
|
135
|
-
})),
|
|
136
|
-
}));
|
|
111
|
+
const changes = body.changes.map(cs => deserializeChangeSet(cs));
|
|
137
112
|
const result = await service.applyChanges(databaseId, client, changes);
|
|
138
113
|
return reply.send({ ok: true, data: result });
|
|
139
114
|
}
|
|
@@ -157,7 +132,7 @@ export function registerRoutes(app, service, basePath) {
|
|
|
157
132
|
reply.raw.setHeader('Content-Type', 'application/x-ndjson');
|
|
158
133
|
reply.raw.setHeader('Transfer-Encoding', 'chunked');
|
|
159
134
|
for await (const chunk of service.getSnapshotStream(databaseId, client)) {
|
|
160
|
-
const serialized = JSON.stringify(chunk) + '\n';
|
|
135
|
+
const serialized = JSON.stringify(serializeSnapshotChunk(chunk)) + '\n';
|
|
161
136
|
reply.raw.write(serialized);
|
|
162
137
|
}
|
|
163
138
|
reply.raw.end();
|
|
@@ -165,7 +140,8 @@ export function registerRoutes(app, service, basePath) {
|
|
|
165
140
|
catch (err) {
|
|
166
141
|
const message = err instanceof Error ? err.message : 'Failed to get snapshot';
|
|
167
142
|
httpLog('GET /%s/snapshot error: %s', databaseId, message);
|
|
168
|
-
//
|
|
143
|
+
// Write an error chunk so NDJSON clients can detect the failure
|
|
144
|
+
reply.raw.write(JSON.stringify({ error: message }) + '\n');
|
|
169
145
|
reply.raw.end();
|
|
170
146
|
}
|
|
171
147
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../../src/server/routes.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,gBAAgB,EAAE,cAAc,
|
|
1
|
+
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../../src/server/routes.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"websocket.d.ts","sourceRoot":"","sources":["../../../src/server/websocket.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAkB,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"websocket.d.ts","sourceRoot":"","sources":["../../../src/server/websocket.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAkB,MAAM,SAAS,CAAC;AAE/D,OAAO,oBAAoB,CAAC;AAS5B,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAC;AAoD5E;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,eAAe,EACpB,OAAO,EAAE,kBAAkB,EAC3B,QAAQ,EAAE,MAAM,GACf,IAAI,CAsMN"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* WebSocket handler for real-time sync.
|
|
3
3
|
*/
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
4
|
+
import '@fastify/websocket';
|
|
5
|
+
import { siteIdFromBase64, siteIdToBase64, deserializeHLC, } from '@quereus/sync';
|
|
6
|
+
import { wsLog, serializeChangeSet, deserializeChangeSet, serializeSnapshotChunk } from '../common/index.js';
|
|
6
7
|
// ============================================================================
|
|
7
8
|
// WebSocket Handler
|
|
8
9
|
// ============================================================================
|
|
@@ -13,6 +14,7 @@ export function registerWebSocket(app, service, basePath) {
|
|
|
13
14
|
app.get(`${basePath}/ws`, { websocket: true }, (socket, request) => {
|
|
14
15
|
wsLog('New WebSocket connection from %s', request.ip);
|
|
15
16
|
let session = null;
|
|
17
|
+
let socketClosed = false;
|
|
16
18
|
const sendError = (code, message) => {
|
|
17
19
|
socket.send(JSON.stringify({ type: 'error', code, message }));
|
|
18
20
|
};
|
|
@@ -36,6 +38,9 @@ export function registerWebSocket(app, service, basePath) {
|
|
|
36
38
|
case 'get_snapshot':
|
|
37
39
|
await handleGetSnapshot();
|
|
38
40
|
break;
|
|
41
|
+
case 'resume_snapshot':
|
|
42
|
+
await handleResumeSnapshot(message);
|
|
43
|
+
break;
|
|
39
44
|
case 'ping':
|
|
40
45
|
sendMessage({ type: 'pong' });
|
|
41
46
|
break;
|
|
@@ -50,6 +55,7 @@ export function registerWebSocket(app, service, basePath) {
|
|
|
50
55
|
}
|
|
51
56
|
});
|
|
52
57
|
socket.on('close', () => {
|
|
58
|
+
socketClosed = true;
|
|
53
59
|
wsLog('WebSocket closed: %s', session?.connectionId?.slice(0, 8) || 'no-session');
|
|
54
60
|
if (session) {
|
|
55
61
|
service.unregisterSession(session.connectionId);
|
|
@@ -79,6 +85,14 @@ export function registerWebSocket(app, service, basePath) {
|
|
|
79
85
|
};
|
|
80
86
|
const identity = await service.authenticate(authContext);
|
|
81
87
|
session = await service.registerSession(msg.databaseId, socket, identity, authContext);
|
|
88
|
+
// If socket closed during registration, the close handler couldn't
|
|
89
|
+
// call unregisterSession because `session` wasn't assigned yet.
|
|
90
|
+
// Clean up now that we have the connectionId.
|
|
91
|
+
if (socketClosed) {
|
|
92
|
+
service.unregisterSession(session.connectionId);
|
|
93
|
+
session = null;
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
82
96
|
const serverSiteId = await service.getSiteId(msg.databaseId, identity);
|
|
83
97
|
sendMessage({
|
|
84
98
|
type: 'handshake_ack',
|
|
@@ -89,6 +103,12 @@ export function registerWebSocket(app, service, basePath) {
|
|
|
89
103
|
wsLog('Handshake complete: %s (db: %s)', session.connectionId.slice(0, 8), msg.databaseId);
|
|
90
104
|
}
|
|
91
105
|
catch (err) {
|
|
106
|
+
// If registerSession succeeded but a subsequent step threw,
|
|
107
|
+
// clean up the registered session to release the store reference.
|
|
108
|
+
if (session) {
|
|
109
|
+
service.unregisterSession(session.connectionId);
|
|
110
|
+
session = null;
|
|
111
|
+
}
|
|
92
112
|
const errMsg = err instanceof Error ? err.message : 'Authentication failed';
|
|
93
113
|
sendError('AUTH_FAILED', errMsg);
|
|
94
114
|
socket.close(4001, 'Authentication failed');
|
|
@@ -99,70 +119,73 @@ export function registerWebSocket(app, service, basePath) {
|
|
|
99
119
|
sendError('NOT_AUTHENTICATED', 'Must handshake first');
|
|
100
120
|
return;
|
|
101
121
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
122
|
+
try {
|
|
123
|
+
let sinceHLC;
|
|
124
|
+
if (msg.sinceHLC) {
|
|
125
|
+
sinceHLC = deserializeHLC(Buffer.from(msg.sinceHLC, 'base64'));
|
|
126
|
+
}
|
|
127
|
+
const changes = await service.getChangesSince(session.databaseId, session.identity, sinceHLC);
|
|
128
|
+
// Serialize for JSON transport
|
|
129
|
+
const serializedChanges = changes.map(cs => serializeChangeSet(cs));
|
|
130
|
+
sendMessage({ type: 'changes', changeSets: serializedChanges });
|
|
131
|
+
}
|
|
132
|
+
catch (err) {
|
|
133
|
+
const msg2 = err instanceof Error ? err.message : 'Failed to get changes';
|
|
134
|
+
wsLog('get_changes error: %s', msg2);
|
|
135
|
+
sendError('GET_CHANGES_ERROR', msg2);
|
|
105
136
|
}
|
|
106
|
-
const changes = await service.getChangesSince(session.databaseId, session.identity, sinceHLC);
|
|
107
|
-
// Serialize for JSON transport
|
|
108
|
-
const serializedChanges = changes.map(cs => serializeChangeSet(cs));
|
|
109
|
-
sendMessage({ type: 'changes', changeSets: serializedChanges });
|
|
110
137
|
}
|
|
111
138
|
async function handleApplyChanges(msg) {
|
|
112
139
|
if (!session) {
|
|
113
140
|
sendError('NOT_AUTHENTICATED', 'Must handshake first');
|
|
114
141
|
return;
|
|
115
142
|
}
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
143
|
+
try {
|
|
144
|
+
// Deserialize from JSON transport
|
|
145
|
+
const changes = msg.changes.map(cs => deserializeChangeSet(cs));
|
|
146
|
+
const result = await service.applyChanges(session.databaseId, session.identity, changes);
|
|
147
|
+
sendMessage({ type: 'apply_result', ...result });
|
|
148
|
+
}
|
|
149
|
+
catch (err) {
|
|
150
|
+
const msg2 = err instanceof Error ? err.message : 'Failed to apply changes';
|
|
151
|
+
wsLog('apply_changes error: %s', msg2);
|
|
152
|
+
sendError('APPLY_CHANGES_ERROR', msg2);
|
|
153
|
+
}
|
|
120
154
|
}
|
|
121
155
|
async function handleGetSnapshot() {
|
|
122
156
|
if (!session) {
|
|
123
157
|
sendError('NOT_AUTHENTICATED', 'Must handshake first');
|
|
124
158
|
return;
|
|
125
159
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
160
|
+
try {
|
|
161
|
+
for await (const chunk of service.getSnapshotStream(session.databaseId, session.identity)) {
|
|
162
|
+
sendMessage({ type: 'snapshot_chunk', chunk: serializeSnapshotChunk(chunk) });
|
|
163
|
+
}
|
|
164
|
+
sendMessage({ type: 'snapshot_complete' });
|
|
165
|
+
}
|
|
166
|
+
catch (err) {
|
|
167
|
+
const msg = err instanceof Error ? err.message : 'Snapshot streaming failed';
|
|
168
|
+
wsLog('get_snapshot error: %s', msg);
|
|
169
|
+
sendError('SNAPSHOT_ERROR', msg);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
async function handleResumeSnapshot(msg) {
|
|
173
|
+
if (!session) {
|
|
174
|
+
sendError('NOT_AUTHENTICATED', 'Must handshake first');
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
try {
|
|
178
|
+
for await (const chunk of service.resumeSnapshotStream(session.databaseId, session.identity, msg.checkpoint)) {
|
|
179
|
+
sendMessage({ type: 'snapshot_chunk', chunk: serializeSnapshotChunk(chunk) });
|
|
180
|
+
}
|
|
181
|
+
sendMessage({ type: 'snapshot_complete' });
|
|
182
|
+
}
|
|
183
|
+
catch (err) {
|
|
184
|
+
const msg2 = err instanceof Error ? err.message : 'Snapshot resume failed';
|
|
185
|
+
wsLog('resume_snapshot error: %s', msg2);
|
|
186
|
+
sendError('SNAPSHOT_ERROR', msg2);
|
|
129
187
|
}
|
|
130
|
-
sendMessage({ type: 'snapshot_complete' });
|
|
131
188
|
}
|
|
132
189
|
});
|
|
133
190
|
}
|
|
134
|
-
// ============================================================================
|
|
135
|
-
// Serialization Helpers
|
|
136
|
-
// ============================================================================
|
|
137
|
-
function serializeChangeSet(cs) {
|
|
138
|
-
return {
|
|
139
|
-
siteId: siteIdToBase64(cs.siteId),
|
|
140
|
-
transactionId: cs.transactionId,
|
|
141
|
-
hlc: Buffer.from(serializeHLC(cs.hlc)).toString('base64'),
|
|
142
|
-
changes: cs.changes.map(c => ({
|
|
143
|
-
...c,
|
|
144
|
-
hlc: Buffer.from(serializeHLC(c.hlc)).toString('base64'),
|
|
145
|
-
})),
|
|
146
|
-
schemaMigrations: cs.schemaMigrations.map(m => ({
|
|
147
|
-
...m,
|
|
148
|
-
hlc: Buffer.from(serializeHLC(m.hlc)).toString('base64'),
|
|
149
|
-
})),
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
function deserializeChangeSet(cs) {
|
|
153
|
-
const obj = cs;
|
|
154
|
-
return {
|
|
155
|
-
siteId: siteIdFromBase64(obj.siteId),
|
|
156
|
-
transactionId: obj.transactionId,
|
|
157
|
-
hlc: deserializeHLC(Buffer.from(obj.hlc, 'base64')),
|
|
158
|
-
changes: obj.changes.map(c => ({
|
|
159
|
-
...c,
|
|
160
|
-
hlc: deserializeHLC(Buffer.from(c.hlc, 'base64')),
|
|
161
|
-
})),
|
|
162
|
-
schemaMigrations: (obj.schemaMigrations || []).map(m => ({
|
|
163
|
-
...m,
|
|
164
|
-
hlc: deserializeHLC(Buffer.from(m.hlc, 'base64')),
|
|
165
|
-
})),
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
191
|
//# sourceMappingURL=websocket.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"websocket.js","sourceRoot":"","sources":["../../../src/server/websocket.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,cAAc,
|
|
1
|
+
{"version":3,"file":"websocket.js","sourceRoot":"","sources":["../../../src/server/websocket.ts"],"names":[],"mappings":"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"}
|