@object-ui/core 5.0.2 → 5.1.1
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/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,50 @@
|
|
|
1
1
|
# @object-ui/core
|
|
2
2
|
|
|
3
|
+
## 5.1.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- @object-ui/types@5.1.1
|
|
8
|
+
|
|
9
|
+
## 5.1.0
|
|
10
|
+
|
|
11
|
+
### Minor Changes
|
|
12
|
+
|
|
13
|
+
- 5b80cfd: feat: Optimistic Concurrency Control (OCC) on DataSource writes
|
|
14
|
+
|
|
15
|
+
`DataSource.update()` and `DataSource.delete()` now accept an optional fourth /
|
|
16
|
+
third argument `opts?: { ifMatch?: string }`. When supplied, adapters forward
|
|
17
|
+
the token to the backend; servers that implement OCC (e.g. ObjectStack
|
|
18
|
+
`>=4.2.0`) compare it against the record's current `updated_at` and reject
|
|
19
|
+
with `409 CONCURRENT_UPDATE` on mismatch, preventing silent overwrites in
|
|
20
|
+
multi-user editing scenarios.
|
|
21
|
+
|
|
22
|
+
**`@object-ui/data-objectstack`**
|
|
23
|
+
- Exports `ConcurrentUpdateError` (carries `currentVersion` and
|
|
24
|
+
`currentRecord`) and `isConcurrentUpdateError()` type guard.
|
|
25
|
+
- `update()` / `delete()` accept `opts.ifMatch` and forward it via the
|
|
26
|
+
`@objectstack/client` data API (header: `If-Match`). Requires
|
|
27
|
+
`@objectstack/client@>=4.1.2` for the header to reach the server;
|
|
28
|
+
older clients silently drop the option and fall back to today's
|
|
29
|
+
"last writer wins" behaviour.
|
|
30
|
+
- Adapter-level error handling maps a 409 with `code === 'CONCURRENT_UPDATE'`
|
|
31
|
+
into a typed `ConcurrentUpdateError` so callers can detect and recover
|
|
32
|
+
from conflicts without parsing the wire format.
|
|
33
|
+
|
|
34
|
+
**`@object-ui/core`**
|
|
35
|
+
- `ApiDataSource.update()` and `.delete()` accept `opts.ifMatch` and emit
|
|
36
|
+
the `If-Match` HTTP header.
|
|
37
|
+
|
|
38
|
+
UI consumers (Detail view, inline cell-edit) will be wired in a follow-up
|
|
39
|
+
patch to capture `updated_at` at load time, pass it as `ifMatch` on save,
|
|
40
|
+
and present a Reload / Overwrite / Cancel dialog on conflict.
|
|
41
|
+
|
|
42
|
+
### Patch Changes
|
|
43
|
+
|
|
44
|
+
- Updated dependencies [cf30cc2]
|
|
45
|
+
- Updated dependencies [5b80cfd]
|
|
46
|
+
- @object-ui/types@5.1.0
|
|
47
|
+
|
|
3
48
|
## 5.0.2
|
|
4
49
|
|
|
5
50
|
### Patch Changes
|
|
@@ -48,8 +48,12 @@ export declare class ApiDataSource<T = any> implements DataSource<T> {
|
|
|
48
48
|
find(_resource: string, params?: QueryParams): Promise<QueryResult<T>>;
|
|
49
49
|
findOne(_resource: string, id: string | number, params?: QueryParams): Promise<T | null>;
|
|
50
50
|
create(_resource: string, data: Partial<T>): Promise<T>;
|
|
51
|
-
update(_resource: string, id: string | number, data: Partial<T
|
|
52
|
-
|
|
51
|
+
update(_resource: string, id: string | number, data: Partial<T>, opts?: {
|
|
52
|
+
ifMatch?: string;
|
|
53
|
+
}): Promise<T>;
|
|
54
|
+
delete(_resource: string, id: string | number, opts?: {
|
|
55
|
+
ifMatch?: string;
|
|
56
|
+
}): Promise<boolean>;
|
|
53
57
|
getObjectSchema(_objectName: string): Promise<any>;
|
|
54
58
|
getView(_objectName: string, _viewId: string): Promise<any | null>;
|
|
55
59
|
getApp(_appId: string): Promise<any | null>;
|
|
@@ -214,20 +214,26 @@ export class ApiDataSource {
|
|
|
214
214
|
body: data,
|
|
215
215
|
});
|
|
216
216
|
}
|
|
217
|
-
async update(_resource, id, data) {
|
|
217
|
+
async update(_resource, id, data, opts) {
|
|
218
218
|
const config = this.writeConfig ?? this.readConfig;
|
|
219
219
|
return this.request(config, {
|
|
220
220
|
pathSuffix: String(id),
|
|
221
221
|
method: 'PATCH',
|
|
222
222
|
body: data,
|
|
223
|
+
...(opts?.ifMatch
|
|
224
|
+
? { headers: { 'If-Match': String(opts.ifMatch) } }
|
|
225
|
+
: {}),
|
|
223
226
|
});
|
|
224
227
|
}
|
|
225
|
-
async delete(_resource, id) {
|
|
228
|
+
async delete(_resource, id, opts) {
|
|
226
229
|
const config = this.writeConfig ?? this.readConfig;
|
|
227
230
|
try {
|
|
228
231
|
await this.request(config, {
|
|
229
232
|
pathSuffix: String(id),
|
|
230
233
|
method: 'DELETE',
|
|
234
|
+
...(opts?.ifMatch
|
|
235
|
+
? { headers: { 'If-Match': String(opts.ifMatch) } }
|
|
236
|
+
: {}),
|
|
231
237
|
});
|
|
232
238
|
return true;
|
|
233
239
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@object-ui/core",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.1.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"sideEffects": false,
|
|
6
6
|
"license": "MIT",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"@objectstack/spec": "^4.0.5",
|
|
29
29
|
"lodash": "^4.18.1",
|
|
30
30
|
"zod": "^4.4.3",
|
|
31
|
-
"@object-ui/types": "5.
|
|
31
|
+
"@object-ui/types": "5.1.1"
|
|
32
32
|
},
|
|
33
33
|
"devDependencies": {
|
|
34
34
|
"typescript": "^6.0.3",
|