@sveltebase/sync 1.1.1 → 1.1.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/README.md CHANGED
@@ -130,6 +130,18 @@ Use it in your Svelte 5 components (using your preferred Dexie reactivity hook,
130
130
  {/each}
131
131
  ```
132
132
 
133
+ ### Synced Database Operations
134
+
135
+ Under the hood, `@sveltebase/sync` intercepts native Dexie table writes to capture and propagate mutations to the backend. The following methods automatically sync with the server:
136
+
137
+ * **`.add(row)`**: Triggers a `"create"` sync mutation.
138
+ * **`.put(row)` or `.put(id, changes)`**: Computes a diff of changed properties (for updates) or initiates a `"create"` mutation (for new rows) and sends it to the server.
139
+ * **`.update(id, changes)`**: Performs a local partial update and propagates the changes to the server as an `"update"` mutation.
140
+ * **`.delete(id)`**: Locally deletes the row and propagates a `"delete"` mutation to the server.
141
+
142
+ > [!NOTE]
143
+ > **Bulk methods** (such as `.bulkAdd()`, `.bulkPut()`, and `.bulkDelete()`) bypass backend syncing entirely. They write directly to IndexedDB, which is useful for performing offline seeding or local-only updates.
144
+
133
145
  ---
134
146
 
135
147
  ### Step 2: Define Sync Handlers (Server)
@@ -16,7 +16,7 @@ declare class SyncClientClass<TSchema extends Record<string, any> = Record<strin
16
16
  private pingInterval;
17
17
  private closedByClient;
18
18
  private activeChannels;
19
- private _status;
19
+ private _statusState;
20
20
  private pendingMutations;
21
21
  private mutationQueue;
22
22
  constructor(options: {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,KAAK,KAAK,EAAwB,MAAM,OAAO,CAAC;AAGhE,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IAC/C,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;CACrC,CAAC;AAaF,cAAM,eAAe,CACnB,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CACzD,SAAQ,KAAK;IACb,OAAO,CAAC,KAAK,CAA4C;IACzD,OAAO,CAAC,MAAM,CAAwB;IACtC,OAAO,CAAC,YAAY,CAA8B;IAClD,OAAO,CAAC,cAAc,CAA4C;IAClE,OAAO,CAAC,YAAY,CAA6C;IACjE,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,cAAc,CAAqB;IAG3C,OAAO,CAAC,OAAO,CAAqE;IAGpF,OAAO,CAAC,gBAAgB,CAAsC;IAE9D,OAAO,CAAC,aAAa,CAMb;gBAEI,OAAO,EAAE;QACnB,IAAI,EAAE,MAAM,CAAC;QACb,GAAG,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;QAC/C,MAAM,EAAE,MAAM,CAAC,MAAM,OAAO,GAAG,MAAM,EAAE,WAAW,CAAC,CAAC;KACrD;IAoBD,IAAW,MAAM,gDAEhB;IAED,OAAO,CAAC,cAAc;YAiJR,OAAO;IAuFd,SAAS;IAgBhB,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,aAAa;YAOP,kBAAkB;IAoBhC,OAAO,CAAC,kBAAkB;YAkBZ,UAAU;YAiBV,aAAa;YAqBb,mBAAmB;IAwEjC,OAAO,CAAC,kBAAkB;IAQ1B,OAAO,CAAC,eAAe;IAqChB,UAAU;CAelB;AAED,MAAM,MAAM,UAAU,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,eAAe,CAAC,OAAO,CAAC,GAAG;KAC5G,CAAC,IAAI,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;CACxC,GAAG;IACF,CAAC,SAAS,EAAE,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;CACjC,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,KACvB,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACzD,OAAO,EAAE;IACT,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IAC/C,MAAM,EAAE,MAAM,CAAC,MAAM,OAAO,GAAG,MAAM,EAAE,WAAW,CAAC,CAAC;CACrD,KAAK,UAAU,CAAC,OAAO,CAA0B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,KAAK,KAAK,EAAwB,MAAM,OAAO,CAAC;AAIhE,MAAM,MAAM,WAAW,GAAG;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IAC/C,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;CACrC,CAAC;AAaF,cAAM,eAAe,CACnB,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CACzD,SAAQ,KAAK;IACb,OAAO,CAAC,KAAK,CAA4C;IACzD,OAAO,CAAC,MAAM,CAAwB;IACtC,OAAO,CAAC,YAAY,CAA8B;IAClD,OAAO,CAAC,cAAc,CAA4C;IAClE,OAAO,CAAC,YAAY,CAA6C;IACjE,OAAO,CAAC,cAAc,CAAS;IAC/B,OAAO,CAAC,cAAc,CAAqB;IAG3C,OAAO,CAAC,YAAY,CAA0B;IAG9C,OAAO,CAAC,gBAAgB,CAAsC;IAE9D,OAAO,CAAC,aAAa,CAMb;gBAEI,OAAO,EAAE;QACnB,IAAI,EAAE,MAAM,CAAC;QACb,GAAG,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;QAC/C,MAAM,EAAE,MAAM,CAAC,MAAM,OAAO,GAAG,MAAM,EAAE,WAAW,CAAC,CAAC;KACrD;IAoBD,IAAW,MAAM,gDAEhB;IAED,OAAO,CAAC,cAAc;YAiJR,OAAO;IAuFd,SAAS;IAgBhB,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,aAAa;YAOP,kBAAkB;IAoBhC,OAAO,CAAC,kBAAkB;YAkBZ,UAAU;YAiBV,aAAa;YAqBb,mBAAmB;IAwEjC,OAAO,CAAC,kBAAkB;IAQ1B,OAAO,CAAC,eAAe;IAqChB,UAAU;CAelB;AAED,MAAM,MAAM,UAAU,CAAC,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,IAAI,eAAe,CAAC,OAAO,CAAC,GAAG;KAC5G,CAAC,IAAI,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;CACxC,GAAG;IACF,CAAC,SAAS,EAAE,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;CACjC,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,KACvB,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACzD,OAAO,EAAE;IACT,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;IAC/C,MAAM,EAAE,MAAM,CAAC,MAAM,OAAO,GAAG,MAAM,EAAE,WAAW,CAAC,CAAC;CACrD,KAAK,UAAU,CAAC,OAAO,CAA0B,CAAC"}
@@ -1,5 +1,6 @@
1
1
  import Dexie, {} from "dexie";
2
2
  import { parseSyncMessage } from "../protocol.js";
3
+ import { ConnectionStatus } from "./status.svelte.js";
3
4
  class SyncClientClass extends Dexie {
4
5
  wsUrl;
5
6
  socket;
@@ -8,8 +9,8 @@ class SyncClientClass extends Dexie {
8
9
  pingInterval;
9
10
  closedByClient = false;
10
11
  activeChannels = new Set();
11
- // Reactive connection status
12
- _status = $state("connecting");
12
+ // Reactive connection status delegated to status.svelte.ts
13
+ _statusState = new ConnectionStatus();
13
14
  // Mutations waiting for ack/reject from server
14
15
  pendingMutations = new Map();
15
16
  // Mutations queued to be sent when connection is established
@@ -31,7 +32,7 @@ class SyncClientClass extends Dexie {
31
32
  }
32
33
  }
33
34
  get status() {
34
- return this._status;
35
+ return this._statusState.value;
35
36
  }
36
37
  decorateTables() {
37
38
  for (const [tableName, config] of Object.entries(this.tableConfigs)) {
@@ -126,7 +127,7 @@ class SyncClientClass extends Dexie {
126
127
  async connect() {
127
128
  if (this.closedByClient)
128
129
  return;
129
- this._status = "connecting";
130
+ this._statusState.value = "connecting";
130
131
  const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
131
132
  const host = window.location.host;
132
133
  let resolvedUrl;
@@ -135,7 +136,7 @@ class SyncClientClass extends Dexie {
135
136
  }
136
137
  catch (err) {
137
138
  console.error("SyncClient: Failed to resolve wsUrl", err);
138
- this._status = "disconnected";
139
+ this._statusState.value = "disconnected";
139
140
  if (!this.closedByClient) {
140
141
  this.reconnectTimer = setTimeout(() => this.connect(), 2000);
141
142
  }
@@ -150,7 +151,7 @@ class SyncClientClass extends Dexie {
150
151
  if (this.socket !== socket)
151
152
  return;
152
153
  console.log("SyncClient: WebSocket connected");
153
- this._status = "connected";
154
+ this._statusState.value = "connected";
154
155
  this.activeChannels.clear();
155
156
  this.startHeartbeat();
156
157
  // Re-subscribe to all tables (delta-sync aware)
@@ -186,7 +187,7 @@ class SyncClientClass extends Dexie {
186
187
  socket.addEventListener("close", () => {
187
188
  if (this.socket === socket) {
188
189
  this.socket = undefined;
189
- this._status = "disconnected";
190
+ this._statusState.value = "disconnected";
190
191
  this.stopHeartbeat();
191
192
  if (!this.closedByClient) {
192
193
  this.reconnectTimer = setTimeout(() => this.connect(), 2000);
@@ -211,7 +212,7 @@ class SyncClientClass extends Dexie {
211
212
  }
212
213
  catch { }
213
214
  this.socket = undefined;
214
- this._status = "disconnected";
215
+ this._statusState.value = "disconnected";
215
216
  }
216
217
  this.connect();
217
218
  }
@@ -403,7 +404,7 @@ class SyncClientClass extends Dexie {
403
404
  }
404
405
  disconnect() {
405
406
  this.closedByClient = true;
406
- this._status = "disconnected";
407
+ this._statusState.value = "disconnected";
407
408
  this.stopHeartbeat();
408
409
  if (this.reconnectTimer) {
409
410
  clearTimeout(this.reconnectTimer);
@@ -0,0 +1,6 @@
1
+ export declare class ConnectionStatus {
2
+ private _value;
3
+ get value(): "connecting" | "connected" | "disconnected";
4
+ set value(newValue: "connecting" | "connected" | "disconnected");
5
+ }
6
+ //# sourceMappingURL=status.svelte.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.svelte.d.ts","sourceRoot":"","sources":["../../src/client/status.svelte.ts"],"names":[],"mappings":"AAAA,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAqE;IAEnF,IAAI,KAAK,IAIW,YAAY,GAAG,WAAW,GAAG,cAAc,CAF9D;IAED,IAAI,KAAK,CAAC,QAAQ,EAAE,YAAY,GAAG,WAAW,GAAG,cAAc,EAE9D;CACF"}
@@ -0,0 +1,9 @@
1
+ export class ConnectionStatus {
2
+ _value = $state("connecting");
3
+ get value() {
4
+ return this._value;
5
+ }
6
+ set value(newValue) {
7
+ this._value = newValue;
8
+ }
9
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sveltebase/sync",
3
- "version": "1.1.1",
3
+ "version": "1.1.2",
4
4
  "type": "module",
5
5
  "publishConfig": {
6
6
  "access": "public"