@memrosetta/sync-client 0.1.5 → 0.1.6

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.d.ts CHANGED
@@ -6,8 +6,21 @@ declare class Outbox {
6
6
  private readonly db;
7
7
  constructor(db: Database.Database);
8
8
  addOp(op: SyncOp): void;
9
- getPending(): readonly SyncOp[];
10
- countPending(): number;
9
+ /**
10
+ * Return pending outbox ops in chronological order.
11
+ *
12
+ * When `userId` is supplied, only ops belonging to that user are
13
+ * returned. This is the v0.5.2 hardening that prevents a
14
+ * cross-user fragmentation: if an older client wrote ops under a
15
+ * legacy `user_id` and the current `SyncClient` is configured with
16
+ * a canonical user, the transport will no longer silently pick up
17
+ * the legacy ops and ship them to the hub. The legacy queue is
18
+ * cleared by `memrosetta migrate legacy-user-ids` before the first
19
+ * post-migration push so this filter is defense-in-depth, not the
20
+ * primary fix.
21
+ */
22
+ getPending(userId?: string): readonly SyncOp[];
23
+ countPending(userId?: string): number;
11
24
  markPushed(opIds: readonly string[]): void;
12
25
  }
13
26
 
package/dist/index.js CHANGED
@@ -52,12 +52,27 @@ var Outbox = class {
52
52
  VALUES (?, ?, ?, ?, ?, ?, ?)`
53
53
  ).run(op.opId, op.opType, op.deviceId, op.userId, payloadStr, op.createdAt, null);
54
54
  }
55
- getPending() {
56
- const rows = this.db.prepare("SELECT * FROM sync_outbox WHERE pushed_at IS NULL ORDER BY created_at ASC").all();
55
+ /**
56
+ * Return pending outbox ops in chronological order.
57
+ *
58
+ * When `userId` is supplied, only ops belonging to that user are
59
+ * returned. This is the v0.5.2 hardening that prevents a
60
+ * cross-user fragmentation: if an older client wrote ops under a
61
+ * legacy `user_id` and the current `SyncClient` is configured with
62
+ * a canonical user, the transport will no longer silently pick up
63
+ * the legacy ops and ship them to the hub. The legacy queue is
64
+ * cleared by `memrosetta migrate legacy-user-ids` before the first
65
+ * post-migration push so this filter is defense-in-depth, not the
66
+ * primary fix.
67
+ */
68
+ getPending(userId) {
69
+ const rows = userId && userId.length > 0 ? this.db.prepare(
70
+ "SELECT * FROM sync_outbox WHERE pushed_at IS NULL AND user_id = ? ORDER BY created_at ASC"
71
+ ).all(userId) : this.db.prepare("SELECT * FROM sync_outbox WHERE pushed_at IS NULL ORDER BY created_at ASC").all();
57
72
  return rows.map(rowToSyncOp);
58
73
  }
59
- countPending() {
60
- const row = this.db.prepare("SELECT COUNT(*) as count FROM sync_outbox WHERE pushed_at IS NULL").get();
74
+ countPending(userId) {
75
+ const row = userId && userId.length > 0 ? this.db.prepare("SELECT COUNT(*) as count FROM sync_outbox WHERE pushed_at IS NULL AND user_id = ?").get(userId) : this.db.prepare("SELECT COUNT(*) as count FROM sync_outbox WHERE pushed_at IS NULL").get();
61
76
  return row.count;
62
77
  }
63
78
  markPushed(opIds) {
@@ -274,7 +289,7 @@ var SyncClient = class {
274
289
  serverUrl: this.config.serverUrl,
275
290
  userId: this.config.userId,
276
291
  deviceId: this.config.deviceId,
277
- pendingOps: this.outbox.countPending(),
292
+ pendingOps: this.outbox.countPending(this.config.userId),
278
293
  lastPush: {
279
294
  attemptAt: this.getState("last_push_attempt_at"),
280
295
  successAt: this.getState("last_push_success_at")
@@ -289,7 +304,7 @@ var SyncClient = class {
289
304
  async push() {
290
305
  const now = (/* @__PURE__ */ new Date()).toISOString();
291
306
  this.setState("last_push_attempt_at", now);
292
- const pending = this.outbox.getPending();
307
+ const pending = this.outbox.getPending(this.config.userId);
293
308
  if (pending.length === 0) {
294
309
  this.setState("last_push_success_at", now);
295
310
  return { pushed: 0, results: [], highWatermark: 0 };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@memrosetta/sync-client",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "Local-first sync client for MemRosetta (outbox/inbox, push/pull)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",