@syncular/client 0.41.1 → 0.41.2

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/remote.js CHANGED
@@ -2,7 +2,7 @@
2
2
  * Database-less SSP2 producer (§6.10). It prepares and sends ordinary commits
3
3
  * through the existing push path without creating a local replica or outbox.
4
4
  */
5
- import { decodeMessage, decodeRemoteOperationResponse, decodeRemoteOperationRealtimeMessage, encodeMessage, encodeRemoteOperationRequest, encodeRemoteOperationRealtimeMessage, encodeSparseRow, PROTOCOL_WIRE_VERSION, } from '@syncular/core';
5
+ import { decodeMessage, decodeRemoteOperationResponse, decodeRemoteOperationRealtimeMessage, encodeMessage, encodeRemoteOperationRequest, encodeRemoteOperationRealtimeMessage, encodeSparseRow, normalizeRejectionDetails, PROTOCOL_WIRE_VERSION, } from '@syncular/core';
6
6
  import { encryptRowValues } from './encryption.js';
7
7
  import { ClientSyncError } from './errors.js';
8
8
  import { compileClientSchema, recordToRowValues, normalizeRecordKeys, coerceSqlRepresentation, } from './schema.js';
@@ -60,6 +60,17 @@ function operationResponse(bytes) {
60
60
  }
61
61
  return response;
62
62
  }
63
+ function operationError(response) {
64
+ if (response.details === undefined) {
65
+ return new ClientSyncError(response.code, response.message, response.retryable);
66
+ }
67
+ try {
68
+ return new ClientSyncError(response.code, response.message, response.retryable, { ...normalizeRejectionDetails(response.details) });
69
+ }
70
+ catch {
71
+ return new ClientSyncError('client.invalid_host_response', 'remote operation error details are malformed');
72
+ }
73
+ }
63
74
  export class SyncRemoteClient {
64
75
  #schema;
65
76
  #clientId;
@@ -257,9 +268,8 @@ export class SyncRemoteClient {
257
268
  operationId: descriptor.id,
258
269
  params: params ?? null,
259
270
  })));
260
- if (response.kind === 'error') {
261
- throw new ClientSyncError(response.code, response.message, response.retryable);
262
- }
271
+ if (response.kind === 'error')
272
+ throw operationError(response);
263
273
  if (response.kind !== 'query' || response.operationId !== descriptor.id) {
264
274
  throw new ClientSyncError('client.invalid_host_response', 'remote query returned a mismatched response');
265
275
  }
@@ -288,9 +298,8 @@ export class SyncRemoteClient {
288
298
  requestId,
289
299
  params: input ?? null,
290
300
  })));
291
- if (response.kind === 'error') {
292
- throw new ClientSyncError(response.code, response.message, response.retryable);
293
- }
301
+ if (response.kind === 'error')
302
+ throw operationError(response);
294
303
  if (response.kind !== 'command' ||
295
304
  response.operationId !== descriptor.id ||
296
305
  response.requestId !== requestId) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@syncular/client",
3
- "version": "0.41.1",
3
+ "version": "0.41.2",
4
4
  "description": "Syncular TypeScript client core — offline-first sync over SQLite (WASM/OPFS, Bun, Node)",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Benjamin Kniffler",
@@ -97,10 +97,10 @@
97
97
  },
98
98
  "dependencies": {
99
99
  "@sqlite.org/sqlite-wasm": "^3.53.0-build1",
100
- "@syncular/core": "0.41.1"
100
+ "@syncular/core": "0.41.2"
101
101
  },
102
102
  "devDependencies": {
103
- "@syncular/server": "0.41.1",
103
+ "@syncular/server": "0.41.2",
104
104
  "playwright": "1.63.0",
105
105
  "@electric-sql/pglite": "^0.5.4"
106
106
  }
package/src/remote.ts CHANGED
@@ -10,6 +10,7 @@ import {
10
10
  encodeRemoteOperationRequest,
11
11
  encodeRemoteOperationRealtimeMessage,
12
12
  encodeSparseRow,
13
+ normalizeRejectionDetails,
13
14
  PROTOCOL_WIRE_VERSION,
14
15
  type PushOperation,
15
16
  type PushOperationResult,
@@ -190,6 +191,31 @@ function operationResponse(bytes: Uint8Array): RemoteOperationResponse {
190
191
  return response;
191
192
  }
192
193
 
194
+ function operationError(
195
+ response: Extract<RemoteOperationResponse, { kind: 'error' }>,
196
+ ): ClientSyncError {
197
+ if (response.details === undefined) {
198
+ return new ClientSyncError(
199
+ response.code,
200
+ response.message,
201
+ response.retryable,
202
+ );
203
+ }
204
+ try {
205
+ return new ClientSyncError(
206
+ response.code,
207
+ response.message,
208
+ response.retryable,
209
+ { ...normalizeRejectionDetails(response.details) },
210
+ );
211
+ } catch {
212
+ return new ClientSyncError(
213
+ 'client.invalid_host_response',
214
+ 'remote operation error details are malformed',
215
+ );
216
+ }
217
+ }
218
+
193
219
  export class SyncRemoteClient {
194
220
  readonly #schema;
195
221
  readonly #clientId: string;
@@ -452,13 +478,7 @@ export class SyncRemoteClient {
452
478
  }),
453
479
  ),
454
480
  );
455
- if (response.kind === 'error') {
456
- throw new ClientSyncError(
457
- response.code,
458
- response.message,
459
- response.retryable,
460
- );
461
- }
481
+ if (response.kind === 'error') throw operationError(response);
462
482
  if (response.kind !== 'query' || response.operationId !== descriptor.id) {
463
483
  throw new ClientSyncError(
464
484
  'client.invalid_host_response',
@@ -504,13 +524,7 @@ export class SyncRemoteClient {
504
524
  }),
505
525
  ),
506
526
  );
507
- if (response.kind === 'error') {
508
- throw new ClientSyncError(
509
- response.code,
510
- response.message,
511
- response.retryable,
512
- );
513
- }
527
+ if (response.kind === 'error') throw operationError(response);
514
528
  if (
515
529
  response.kind !== 'command' ||
516
530
  response.operationId !== descriptor.id ||