@ea-lab/reactive-json-docs 2.5.0 → 2.6.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ea-lab/reactive-json-docs",
3
- "version": "2.5.0",
3
+ "version": "2.6.0",
4
4
  "description": "Complete documentation for Reactive-JSON - Components, examples and LLM-parsable guides",
5
5
  "main": "public/rjbuild/docs/index.yaml",
6
6
  "files": [
@@ -26,8 +26,8 @@
26
26
  "private": false,
27
27
  "devDependencies": {
28
28
  "@craco/craco": "^7.1.0",
29
- "@ea-lab/reactive-json": "^1.2.0",
30
- "@ea-lab/reactive-json-chartjs": "^1.0.0",
29
+ "@ea-lab/reactive-json": "^2.5.1",
30
+ "@ea-lab/reactive-json-chartjs": "^1.1.1",
31
31
  "@npmcli/fs": "^4.0.0",
32
32
  "@reduxjs/toolkit": "^2.6.1",
33
33
  "@testing-library/jest-dom": "^6.6.3",
@@ -77,7 +77,7 @@
77
77
  ]
78
78
  },
79
79
  "dependencies": {
80
- "@ea-lab/reactive-json-bootstrap": "^0.0.2",
80
+ "@ea-lab/reactive-json-bootstrap": "^0.1.0",
81
81
  "mermaid": "^11.10.1",
82
82
  "remark-gfm": "^4.0.1"
83
83
  }
@@ -66,6 +66,7 @@ The response completely replaces the local Syncable Object.
66
66
  | `trigger` | string | - | Path to a boolean value. When set to `true`, triggers an immediate sync and resets to `false`. Works in any mode. In `onIdle` mode, it cancels the pending idle timer. |
67
67
  | `maxRetries` | number | `0` | Number of additional retry attempts after a failed sync. `0` means one attempt with no retry. |
68
68
  | `retryDelay` | number | `5000` | Milliseconds between retry attempts. |
69
+ | `mergeKey` | string | - | Path to a **stable identity** for the syncable (typically its `submission_url`). All `DataSync` instances resolving to the same value form a shared group: edits are mirrored live across them and persisted by a single owner. See [Shared Syncables](#shared-syncables-mergekey). |
69
70
 
70
71
  ## Synchronization Modes
71
72
 
@@ -200,6 +201,47 @@ For raw server or network errors (5xx without a structured body, or the browser
200
201
 
201
202
  This prevents feedback loops: when the component updates `status` to "syncing" or when the server response updates `status` to "success", these changes do not trigger a new sync cycle.
202
203
 
204
+ ## Shared Syncables (`mergeKey`)
205
+
206
+ When the **same resource** is mounted in several places at once — the same record shown in two views, or one editable item embedded in multiple components — each `DataSync` would normally watch its own copy and POST independently. That causes duplicate writes and lets the copies drift apart.
207
+
208
+ Set `mergeKey` to make those instances cooperate. It is a path resolving to a **stable identity** for the syncable (commonly its `submission_url`). Every `DataSync` that resolves to the same value forms a **group**:
209
+
210
+ - **One writer (the owner).** The first instance to join is the group's owner, re-elected automatically if it unmounts. Only the owner sends requests.
211
+ - **Live mirror.** When any member's `data` changes, that data is applied to every other member's store — with their own change-watcher suppressed, so they neither re-broadcast nor POST. All copies stay in sync on screen.
212
+ - **Single, coalesced write.** Persistence is delegated to the owner, which (re)schedules its one debounced sync and reads the **latest** shared data when it fires. Rapid edits across different members collapse into a single request carrying the final value — no concurrent writers, no stale-data write, no revert.
213
+ - **Server propagation.** On a successful sync, the owner broadcasts the (server-enriched) response `data` back to the group.
214
+
215
+ ```yaml
216
+ data:
217
+ cardA:
218
+ submission_url: "/api/items/123"
219
+ data: { title: "Hello" }
220
+ cardB:
221
+ submission_url: "/api/items/123" # SAME entity, second mount
222
+ data: { title: "Hello" }
223
+
224
+ renderView:
225
+ - type: TextField
226
+ dataLocation: ~~.cardA.data.title
227
+ - type: DataSync
228
+ path: ~~.cardA
229
+ mergeKey: ~~.cardA.submission_url
230
+
231
+ - type: TextField
232
+ dataLocation: ~~.cardB.data.title
233
+ - type: DataSync
234
+ path: ~~.cardB
235
+ mergeKey: ~~.cardB.submission_url
236
+ ```
237
+
238
+ Editing either field mirrors live to the other, and the whole group produces a single POST.
239
+
240
+ **Notes**
241
+ - The library stays agnostic about what makes two syncables "the same": you pick the identity by pointing `mergeKey` at whatever field is stable per resource (usually `submission_url`).
242
+ - Leaving `mergeKey` unset keeps the default behavior — one independent sync per instance.
243
+ - Known limitation: if the owner unmounts while a sync is still pending, that in-flight edit is not persisted (the new owner only writes on the next edit).
244
+
203
245
  ## Using with Templates
204
246
 
205
247
  `DataSync` supports `TemplateContext`, so it can be used inside templates to sync individual items in a list: