@delali/sirannon-db 0.1.4 → 0.1.5

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.
@@ -0,0 +1,111 @@
1
+ import { SirannonError } from './chunk-O7BHI3CF.mjs';
2
+
3
+ // src/replication/errors.ts
4
+ var ReplicationError = class extends SirannonError {
5
+ constructor(message, code = "REPLICATION_ERROR", details) {
6
+ super(message, code);
7
+ this.details = details;
8
+ this.name = "ReplicationError";
9
+ }
10
+ };
11
+ var ConflictError = class extends ReplicationError {
12
+ constructor(message, table, rowId) {
13
+ super(message, "CONFLICT_ERROR");
14
+ this.table = table;
15
+ this.rowId = rowId;
16
+ this.name = "ConflictError";
17
+ }
18
+ };
19
+ var TransportError = class extends ReplicationError {
20
+ constructor(message) {
21
+ super(message, "TRANSPORT_ERROR");
22
+ this.name = "TransportError";
23
+ }
24
+ };
25
+ var BatchValidationError = class extends ReplicationError {
26
+ constructor(message) {
27
+ super(message, "BATCH_VALIDATION_ERROR");
28
+ this.name = "BatchValidationError";
29
+ }
30
+ };
31
+ var WriteConcernError = class extends ReplicationError {
32
+ constructor(message) {
33
+ super(message, "WRITE_CONCERN_ERROR");
34
+ this.name = "WriteConcernError";
35
+ }
36
+ };
37
+ var ReadConcernError = class extends ReplicationError {
38
+ constructor(message, details) {
39
+ super(message, "READ_CONCERN_ERROR", details);
40
+ this.name = "ReadConcernError";
41
+ }
42
+ };
43
+ var TopologyError = class extends ReplicationError {
44
+ constructor(message) {
45
+ super(message, "TOPOLOGY_ERROR");
46
+ this.name = "TopologyError";
47
+ }
48
+ };
49
+ var CoordinatorError = class extends ReplicationError {
50
+ constructor(message, details) {
51
+ super(message, "COORDINATOR_UNAVAILABLE", details);
52
+ this.name = "CoordinatorError";
53
+ }
54
+ };
55
+ var AuthorityError = class extends ReplicationError {
56
+ constructor(message, code = "AUTHORITY_LOST", details) {
57
+ super(message, code, details);
58
+ this.name = "AuthorityError";
59
+ }
60
+ };
61
+ var StalePrimaryError = class extends AuthorityError {
62
+ constructor(message, details) {
63
+ super(message, "STALE_PRIMARY", details);
64
+ this.name = "StalePrimaryError";
65
+ }
66
+ };
67
+ var FailoverError = class extends ReplicationError {
68
+ constructor(message, code = "NO_SAFE_PRIMARY", details) {
69
+ super(message, code, details);
70
+ this.name = "FailoverError";
71
+ }
72
+ };
73
+ var NoSafePrimaryError = class extends FailoverError {
74
+ constructor(message, details) {
75
+ super(message, "NO_SAFE_PRIMARY", details);
76
+ this.name = "NoSafePrimaryError";
77
+ }
78
+ };
79
+ var NodeNotInSyncError = class extends ReplicationError {
80
+ constructor(message, details) {
81
+ super(message, "NODE_NOT_IN_SYNC", details);
82
+ this.name = "NodeNotInSyncError";
83
+ }
84
+ };
85
+ var NodeDrainingError = class extends ReplicationError {
86
+ constructor(message, details) {
87
+ super(message, "NODE_DRAINING", details);
88
+ this.name = "NodeDrainingError";
89
+ }
90
+ };
91
+ var ProtocolVersionMismatchError = class extends ReplicationError {
92
+ constructor(message, details) {
93
+ super(message, "PROTOCOL_VERSION_MISMATCH", details);
94
+ this.name = "ProtocolVersionMismatchError";
95
+ }
96
+ };
97
+ var UnsafeRecoveryRequiredError = class extends FailoverError {
98
+ constructor(message, details) {
99
+ super(message, "UNSAFE_RECOVERY_REQUIRED", details);
100
+ this.name = "UnsafeRecoveryRequiredError";
101
+ }
102
+ };
103
+ var SyncError = class extends ReplicationError {
104
+ constructor(message, requestId) {
105
+ super(message, "SYNC_ERROR");
106
+ this.requestId = requestId;
107
+ this.name = "SyncError";
108
+ }
109
+ };
110
+
111
+ export { AuthorityError, BatchValidationError, ConflictError, CoordinatorError, FailoverError, NoSafePrimaryError, NodeDrainingError, NodeNotInSyncError, ProtocolVersionMismatchError, ReadConcernError, ReplicationError, StalePrimaryError, SyncError, TopologyError, TransportError, UnsafeRecoveryRequiredError, WriteConcernError };
@@ -1,5 +1,18 @@
1
1
  /** Query parameter types: named (object) or positional (array). */
2
2
  type Params = Record<string, unknown> | unknown[];
3
+ type WriteConcernLevel = 'local' | 'majority' | 'all';
4
+ interface WriteConcern {
5
+ level: WriteConcernLevel;
6
+ timeoutMs?: number;
7
+ }
8
+ type ReadConcernLevel = 'local' | 'majority' | 'linearizable';
9
+ interface ReadConcern {
10
+ level: ReadConcernLevel;
11
+ }
12
+ interface QueryOptions {
13
+ writeConcern?: WriteConcern;
14
+ readConcern?: ReadConcern;
15
+ }
3
16
  /** CDC operation type. */
4
17
  type ChangeOperation = 'insert' | 'update' | 'delete';
5
18
  /** Event emitted when a watched table row changes. */
@@ -17,6 +30,8 @@ interface ClientOptions {
17
30
  transport?: 'websocket' | 'http';
18
31
  /** Custom headers for HTTP requests. */
19
32
  headers?: Record<string, string>;
33
+ /** WebSocket subprotocols sent during the browser-compatible handshake. */
34
+ webSocketProtocols?: string | string[];
20
35
  /** Reconnect on WebSocket disconnect. Default: true. */
21
36
  autoReconnect?: boolean;
22
37
  /** Reconnect interval in ms. Default: 1000. */
@@ -42,7 +57,7 @@ interface TransactionResponse {
42
57
  * Each transport instance is bound to a specific database.
43
58
  */
44
59
  interface Transport {
45
- query(sql: string, params?: Params): Promise<QueryResponse>;
60
+ query(sql: string, params?: Params, readConcern?: ReadConcern): Promise<QueryResponse>;
46
61
  execute(sql: string, params?: Params): Promise<ExecuteResponse>;
47
62
  transaction(statements: Array<{
48
63
  sql: string;
@@ -89,7 +104,7 @@ declare class RemoteDatabase {
89
104
  * )
90
105
  * ```
91
106
  */
92
- query<T = Record<string, unknown>>(sql: string, params?: Params): Promise<T[]>;
107
+ query<T = Record<string, unknown>>(sql: string, params?: Params, options?: QueryOptions): Promise<T[]>;
93
108
  /**
94
109
  * Execute a mutation (INSERT, UPDATE, DELETE) and return
95
110
  * the number of affected rows and last insert row ID.
@@ -129,45 +144,97 @@ declare class RemoteDatabase {
129
144
  close(): void;
130
145
  }
131
146
 
132
- /**
133
- * Client for a remote sirannon-db server. Creates {@link RemoteDatabase}
134
- * instances that communicate with the server over HTTP or WebSocket.
135
- *
136
- * ```ts
137
- * const client = new SirannonClient('http://localhost:9876', {
138
- * transport: 'websocket',
139
- * })
140
- *
141
- * const db = client.database('main')
142
- * const rows = await db.query('SELECT * FROM users')
143
- *
144
- * client.close()
145
- * ```
146
- */
147
+ interface TopologyAwareClientOptions extends ClientOptions {
148
+ endpoints?: string[];
149
+ primary?: string;
150
+ replicas?: string[];
151
+ readPreference?: 'primary' | 'replica' | 'nearest';
152
+ discovery?: 'static' | 'coordinator';
153
+ readConcern?: ReadConcernLevel;
154
+ }
147
155
  declare class SirannonClient {
148
156
  private readonly baseUrl;
149
157
  private readonly wsBaseUrl;
150
158
  private readonly transport;
151
159
  private readonly headers;
160
+ private readonly webSocketProtocols;
152
161
  private readonly autoReconnect;
153
162
  private readonly reconnectInterval;
154
163
  private readonly databases;
155
164
  private closed;
165
+ private readonly topologyEnabled;
166
+ private readonly primaryUrl;
167
+ private readonly replicaUrls;
168
+ private readonly readPreference;
169
+ private readonly discovery;
170
+ private readonly readConcern;
171
+ private readonly starterEndpoints;
172
+ private readonly clusterRouting;
173
+ private readonly topologyTransports;
174
+ private latencies;
175
+ private latencyMeasuredAt;
176
+ private latencyMeasuring;
177
+ private readonly LATENCY_TTL_MS;
178
+ private removedReplicas;
156
179
  constructor(url: string, options?: ClientOptions);
157
- /**
158
- * Get a {@link RemoteDatabase} proxy for the given database ID.
159
- * Returns a cached instance if one already exists for this ID.
160
- *
161
- * The underlying transport connection is established lazily on
162
- * the first operation (query, execute, or subscribe).
163
- */
180
+ constructor(options: TopologyAwareClientOptions);
164
181
  database(id: string): RemoteDatabase;
165
- /**
166
- * Close all database connections and release resources.
167
- * After calling `close()`, new calls to `database()` will throw.
168
- */
169
182
  close(): void;
170
183
  private createTransport;
184
+ private createTransportForUrl;
185
+ _createTransportForEndpoint(url: string, databaseId: string): Transport;
186
+ _getReadEndpoint(databaseId?: string, readConcern?: ReadConcernLevel): Promise<string>;
187
+ _getWriteEndpoint(databaseId?: string): Promise<string>;
188
+ _getReadConcern(): ReadConcernLevel | undefined;
189
+ _usesCoordinatorDiscovery(): boolean;
190
+ _removeReplica(url: string): void;
191
+ private ensureLatencyMeasured;
192
+ private measureLatencies;
193
+ _refreshClusterRouting(databaseId: string): Promise<void>;
194
+ private ensureClusterRouting;
195
+ private clusterDiscoveryCandidates;
196
+ _unregisterTopologyTransport(databaseId: string, transport: TopologyAwareTransport): void;
197
+ private notifyClusterRoutingChanged;
198
+ }
199
+
200
+ declare class TopologyAwareTransport implements Transport {
201
+ private readonly databaseId;
202
+ private readonly client;
203
+ private closed;
204
+ private readTransport;
205
+ private writeTransport;
206
+ private subscriptionTransport;
207
+ private readTransportRequest;
208
+ private writeTransportRequest;
209
+ private subscriptionTransportRequest;
210
+ private subscriptionOperation;
211
+ private activeSubscriptions;
212
+ private nextSubscriptionId;
213
+ private currentReadUrl;
214
+ private currentWriteUrl;
215
+ private currentSubscriptionUrl;
216
+ constructor(databaseId: string, client: SirannonClient);
217
+ query(sql: string, params?: Params): Promise<QueryResponse>;
218
+ execute(sql: string, params?: Params): Promise<ExecuteResponse>;
219
+ transaction(statements: Array<{
220
+ sql: string;
221
+ params?: Params;
222
+ }>): Promise<TransactionResponse>;
223
+ subscribe(table: string, filter: Record<string, unknown> | undefined, callback: (event: ChangeEvent) => void): Promise<RemoteSubscription>;
224
+ _handleClusterRoutingChanged(): Promise<void>;
225
+ close(): void;
226
+ private subscribeOnCurrentEndpoint;
227
+ private createSubscriptionHandle;
228
+ private migrateSubscriptionsToCurrentEndpoint;
229
+ private getReadTransport;
230
+ private resolveReadTransport;
231
+ private getWriteTransport;
232
+ private resolveWriteTransport;
233
+ private getSubscriptionTransport;
234
+ private resolveSubscriptionTransport;
235
+ private closeSubscriptionTransport;
236
+ private withSubscriptionOperation;
237
+ private assertOpen;
171
238
  }
172
239
 
173
240
  /**
@@ -196,7 +263,7 @@ declare class HttpTransport implements Transport {
196
263
  private readonly headers;
197
264
  private closed;
198
265
  constructor(baseUrl: string, headers?: Record<string, string>);
199
- query(sql: string, params?: Params): Promise<QueryResponse>;
266
+ query(sql: string, params?: Params, readConcern?: ReadConcern): Promise<QueryResponse>;
200
267
  execute(sql: string, params?: Params): Promise<ExecuteResponse>;
201
268
  transaction(statements: Array<{
202
269
  sql: string;
@@ -207,24 +274,13 @@ declare class HttpTransport implements Transport {
207
274
  private post;
208
275
  }
209
276
 
210
- /**
211
- * WebSocket transport for sirannon-db. Connects to
212
- * `ws(s)://host:port/db/{id}` and supports query, execute,
213
- * and real-time CDC subscriptions over a single persistent connection.
214
- *
215
- * Connections are established lazily on first use and will
216
- * auto-reconnect (with subscription restoration) when
217
- * `autoReconnect` is enabled.
218
- *
219
- * Transactions are not supported over WebSocket; use
220
- * {@link HttpTransport} for batch transactions.
221
- */
222
277
  declare class WebSocketTransport implements Transport {
223
278
  private ws;
224
279
  private readonly url;
225
280
  private readonly autoReconnect;
226
281
  private readonly reconnectInterval;
227
282
  private readonly requestTimeout;
283
+ private readonly protocols;
228
284
  private pendingRequests;
229
285
  private activeSubscriptions;
230
286
  private idCounter;
@@ -235,6 +291,7 @@ declare class WebSocketTransport implements Transport {
235
291
  autoReconnect?: boolean;
236
292
  reconnectInterval?: number;
237
293
  requestTimeout?: number;
294
+ protocols?: string | string[];
238
295
  });
239
296
  query(sql: string, params?: Params): Promise<QueryResponse>;
240
297
  execute(sql: string, params?: Params): Promise<ExecuteResponse>;
@@ -256,4 +313,4 @@ declare class WebSocketTransport implements Transport {
256
313
  private cancelReconnect;
257
314
  }
258
315
 
259
- export { HttpTransport, RemoteDatabase, RemoteError, type RemoteSubscription, type RemoteSubscriptionBuilder, RemoteSubscriptionBuilderImpl, SirannonClient, type Transport, WebSocketTransport };
316
+ export { HttpTransport, RemoteDatabase, RemoteError, type RemoteSubscription, type RemoteSubscriptionBuilder, RemoteSubscriptionBuilderImpl, SirannonClient, type TopologyAwareClientOptions, type Transport, WebSocketTransport };