@procedures/store 0.41.0 → 0.41.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 +9 -0
- package/README.md +3 -1
- package/dist/.tsbuildinfo +1 -1
- package/dist/storage/hybrid.d.ts +7 -3
- package/dist/storage/hybrid.d.ts.map +1 -1
- package/dist/storage/hybrid.js +24 -5
- package/dist/storage/hybrid.js.map +1 -1
- package/package.json +4 -4
- package/src/storage/hybrid.ts +24 -6
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package",
|
|
3
3
|
"name": "@procedures/store",
|
|
4
|
-
"version": "0.41.
|
|
4
|
+
"version": "0.41.1",
|
|
5
5
|
"description": "A program store for procedure-as-data: save the programs that procedure.define makes, load them back after a restart, in memory, a JSON file, IndexedDB or a remote collection storage.",
|
|
6
6
|
"keywords": [
|
|
7
7
|
"program-store",
|
|
@@ -78,12 +78,12 @@
|
|
|
78
78
|
},
|
|
79
79
|
"dependencies": {
|
|
80
80
|
"@mark1russell7/service": "^0.5.8",
|
|
81
|
-
"@procedures/client": "0.41.
|
|
82
|
-
"@procedures/collections": "0.41.
|
|
81
|
+
"@procedures/client": "0.41.1",
|
|
82
|
+
"@procedures/collections": "0.41.1",
|
|
83
83
|
"zod": "^4.6.5"
|
|
84
84
|
},
|
|
85
85
|
"devDependencies": {
|
|
86
|
-
"@procedures/fs": "0.41.
|
|
86
|
+
"@procedures/fs": "0.41.1",
|
|
87
87
|
"@mark1russell7/cue": "^1.0.0",
|
|
88
88
|
"@types/node": "^22.0.0",
|
|
89
89
|
"fake-indexeddb": "^6.2.5",
|
package/src/storage/hybrid.ts
CHANGED
|
@@ -2893,7 +2893,14 @@ export class HybridStorage<T> implements CollectionStorage<T> {
|
|
|
2893
2893
|
if (conflicts !== undefined && conflicts.length > 0 && !resolved.has(op)) {
|
|
2894
2894
|
resolved.add(op);
|
|
2895
2895
|
this.isOnline = true;
|
|
2896
|
-
await this.resolvePushConflicts(op, conflicts)
|
|
2896
|
+
if (await this.resolvePushConflicts(op, conflicts)) {
|
|
2897
|
+
// Each id is the echo of an earlier send: the operation leaves the queue as sent (roadmap O69)
|
|
2898
|
+
if (this.offlineOps[0] === op) {
|
|
2899
|
+
this.offlineOps.shift();
|
|
2900
|
+
sent++;
|
|
2901
|
+
this.storeDirty = true;
|
|
2902
|
+
}
|
|
2903
|
+
}
|
|
2897
2904
|
continue;
|
|
2898
2905
|
}
|
|
2899
2906
|
if (
|
|
@@ -3357,16 +3364,21 @@ export class HybridStorage<T> implements CollectionStorage<T> {
|
|
|
3357
3364
|
* This method applies the conflicts of a push that the remote refused (`VERSION_CONFLICT`). Each
|
|
3358
3365
|
* conflict goes to `conflictResolution`, as a conflict of a pull does:
|
|
3359
3366
|
*
|
|
3360
|
-
* - The remote item is the value of the operation itself
|
|
3361
|
-
* remote, and its answer was lost. The base becomes the current
|
|
3362
|
-
* the operation
|
|
3367
|
+
* - The remote item is the value of the operation itself, or a delete finds no remote item. An
|
|
3368
|
+
* earlier send of it reached the remote, and its answer was lost. The base becomes the current
|
|
3369
|
+
* version. When each id of the operation is such an echo, the operation leaves the queue with
|
|
3370
|
+
* no further send (roadmap O69). Else the policy decides for the other ids.
|
|
3363
3371
|
* - `remote`: the remote item replaces the local item, and the queued writes of the id go.
|
|
3364
3372
|
* - `merge`: the merged item replaces the local item, and a new queued write sends it.
|
|
3365
3373
|
* - `local`: the base becomes the current version, so the next send replaces the remote item.
|
|
3366
3374
|
* - `error`: the queue keeps the operation, and the push throws `ConflictError` with the ids.
|
|
3375
|
+
*
|
|
3376
|
+
* The method gives true when each id of the operation is an echo. An id without a conflict is
|
|
3377
|
+
* not an echo: the remote did not show its value.
|
|
3367
3378
|
*/
|
|
3368
|
-
private async resolvePushConflicts(op: QueuedOperation, conflicts: readonly VersionConflict[]): Promise<
|
|
3379
|
+
private async resolvePushConflicts(op: QueuedOperation, conflicts: readonly VersionConflict[]): Promise<boolean> {
|
|
3369
3380
|
const ids: string[] = [];
|
|
3381
|
+
const echoes = new Set<string>();
|
|
3370
3382
|
let queueChanged = false;
|
|
3371
3383
|
for (const conflict of conflicts) {
|
|
3372
3384
|
const { id } = conflict;
|
|
@@ -3376,9 +3388,11 @@ export class HybridStorage<T> implements CollectionStorage<T> {
|
|
|
3376
3388
|
const remoteItem = conflict.value as T;
|
|
3377
3389
|
const remoteVersion = conflict.version ?? this.versionOfItem(remoteItem);
|
|
3378
3390
|
// The echo of this operation, or a remote item without a version: the queued write wins
|
|
3379
|
-
|
|
3391
|
+
const echo = written !== null && sameJson(written.value, remoteItem);
|
|
3392
|
+
if (remoteVersion === undefined || echo) {
|
|
3380
3393
|
if (remoteVersion === undefined) this.bases.delete(id);
|
|
3381
3394
|
else this.bases.set(id, remoteVersion);
|
|
3395
|
+
if (echo) echoes.add(id);
|
|
3382
3396
|
continue;
|
|
3383
3397
|
}
|
|
3384
3398
|
const localItem = await this.readLocal(id);
|
|
@@ -3388,6 +3402,7 @@ export class HybridStorage<T> implements CollectionStorage<T> {
|
|
|
3388
3402
|
// The remote has no item: the echo of a delete, or a delete of another writer
|
|
3389
3403
|
if (written === null) {
|
|
3390
3404
|
this.bases.set(id, null);
|
|
3405
|
+
echoes.add(id);
|
|
3391
3406
|
continue;
|
|
3392
3407
|
}
|
|
3393
3408
|
if (await this.resolveRemoteDelete(id, ids)) queueChanged = true;
|
|
@@ -3398,6 +3413,9 @@ export class HybridStorage<T> implements CollectionStorage<T> {
|
|
|
3398
3413
|
await this.persistAll().catch(() => undefined);
|
|
3399
3414
|
}
|
|
3400
3415
|
if (ids.length > 0) throw new ConflictError(ids);
|
|
3416
|
+
// A clear and a delete of a batch write no value that a conflict shows: they are never echoes
|
|
3417
|
+
const written = idsOf(op);
|
|
3418
|
+
return !queueChanged && written.length > 0 && written.every((id) => echoes.has(id));
|
|
3401
3419
|
}
|
|
3402
3420
|
|
|
3403
3421
|
/**
|