@drakkar.software/starfish-client 2.0.0 → 2.2.0

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/index.js CHANGED
@@ -198,6 +198,12 @@ function createSchemaValidator(ajv, schema) {
198
198
  }
199
199
 
200
200
  // src/sync.ts
201
+ var AbortError = class extends Error {
202
+ constructor() {
203
+ super("SyncManager was aborted");
204
+ this.name = "AbortError";
205
+ }
206
+ };
201
207
  var SyncManager = class {
202
208
  client;
203
209
  pullPath;
@@ -212,6 +218,7 @@ var SyncManager = class {
212
218
  lastHash = null;
213
219
  lastCheckpoint = 0;
214
220
  localData = {};
221
+ aborted = false;
215
222
  constructor(options) {
216
223
  this.client = options.client;
217
224
  this.pullPath = options.pullPath;
@@ -224,22 +231,35 @@ var SyncManager = class {
224
231
  this.validate = options.validate;
225
232
  this.encryptor = options.encryptor ?? (options.encryptionSecret && options.encryptionSalt ? createEncryptor(options.encryptionSecret, options.encryptionSalt, options.encryptionInfo) : null);
226
233
  }
234
+ abort() {
235
+ this.aborted = true;
236
+ }
237
+ get isAborted() {
238
+ return this.aborted;
239
+ }
227
240
  getData() {
228
241
  return { ...this.localData };
229
242
  }
230
243
  getHash() {
231
244
  return this.lastHash;
232
245
  }
246
+ /** Set the last-known server hash. Used by persistence layers to restore state across restarts. */
247
+ setHash(hash) {
248
+ this.lastHash = hash;
249
+ }
233
250
  getCheckpoint() {
234
251
  return this.lastCheckpoint;
235
252
  }
236
253
  async pull() {
254
+ if (this.aborted) throw new AbortError();
237
255
  this.logger?.pullStart(this.loggerName);
238
256
  const start = performance.now();
239
257
  try {
240
258
  const result = await this.client.pull(this.pullPath, this.lastCheckpoint);
259
+ if (this.aborted) throw new AbortError();
241
260
  if (this.encryptor) {
242
261
  const decrypted = await this.encryptor.decrypt(result.data);
262
+ if (this.aborted) throw new AbortError();
243
263
  this.localData = decrypted;
244
264
  result.data = decrypted;
245
265
  } else if (this.lastCheckpoint > 0) {
@@ -258,6 +278,7 @@ var SyncManager = class {
258
278
  }
259
279
  }
260
280
  async push(data) {
281
+ if (this.aborted) throw new AbortError();
261
282
  if (this.validate) {
262
283
  const result = this.validate(data);
263
284
  if (result !== true) throw new ValidationError(result);
@@ -269,19 +290,23 @@ var SyncManager = class {
269
290
  while (attempt <= this.maxRetries) {
270
291
  try {
271
292
  const payload = this.encryptor ? await this.encryptor.encrypt(pendingData) : pendingData;
293
+ if (this.aborted) throw new AbortError();
272
294
  const sig = this.signData ? await this.signData(stableStringify(payload)) : void 0;
295
+ if (this.aborted) throw new AbortError();
273
296
  const result = await this.client.push(
274
297
  this.pushPath,
275
298
  payload,
276
299
  this.lastHash,
277
300
  sig
278
301
  );
302
+ if (this.aborted) throw new AbortError();
279
303
  this.lastHash = result.hash;
280
304
  this.lastCheckpoint = result.timestamp;
281
305
  this.localData = pendingData;
282
306
  this.logger?.pushSuccess(this.loggerName, Math.round(performance.now() - start));
283
307
  return result;
284
308
  } catch (err) {
309
+ if (err instanceof AbortError) throw err;
285
310
  if (!(err instanceof ConflictError) || attempt >= this.maxRetries) {
286
311
  this.logger?.pushError(this.loggerName, err instanceof Error ? err.message : String(err));
287
312
  throw err;
@@ -289,11 +314,14 @@ var SyncManager = class {
289
314
  this.logger?.conflict(this.loggerName, attempt + 1);
290
315
  try {
291
316
  const remote = await this.client.pull(this.pullPath);
317
+ if (this.aborted) throw new AbortError();
292
318
  const remoteData = this.encryptor ? await this.encryptor.decrypt(remote.data) : remote.data;
319
+ if (this.aborted) throw new AbortError();
293
320
  this.lastHash = remote.hash;
294
321
  this.lastCheckpoint = remote.timestamp;
295
322
  pendingData = this.onConflict(pendingData, remoteData);
296
323
  } catch (resolveErr) {
324
+ if (resolveErr instanceof AbortError) throw resolveErr;
297
325
  const msg = resolveErr instanceof Error ? resolveErr.message : String(resolveErr);
298
326
  this.logger?.pushError(this.loggerName, `Conflict resolution failed (attempt ${attempt + 1}): ${msg}`);
299
327
  throw resolveErr;
@@ -1308,6 +1336,7 @@ async function pullEntitlements(client, userId, opts) {
1308
1336
  }
1309
1337
  }
1310
1338
  export {
1339
+ AbortError,
1311
1340
  ConflictError,
1312
1341
  ENCRYPTED_KEY,
1313
1342
  SnapshotHistory,