cry-synced-db-client 0.1.166 → 0.1.167
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.js +92 -3
- package/dist/src/db/SyncedDb.d.ts +22 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4963,7 +4963,8 @@ var _SyncedDb = class _SyncedDb {
|
|
|
4963
4963
|
const merged = _SyncedDb.applyDiffLocally(
|
|
4964
4964
|
currentMem != null ? currentMem : existing,
|
|
4965
4965
|
diff,
|
|
4966
|
-
id
|
|
4966
|
+
id,
|
|
4967
|
+
collection
|
|
4967
4968
|
);
|
|
4968
4969
|
this.pendingChanges.schedule(collection, id, merged, 0, "save");
|
|
4969
4970
|
if (!isWriteOnly && !(existing == null ? void 0 : existing._deleted) && !(existing == null ? void 0 : existing._archived)) {
|
|
@@ -6122,7 +6123,7 @@ var _SyncedDb = class _SyncedDb {
|
|
|
6122
6123
|
* Returns a new object (the cloned-and-mutated `base`); never mutates
|
|
6123
6124
|
* the input `base` reference.
|
|
6124
6125
|
*/
|
|
6125
|
-
static applyDiffLocally(base, diff, fallbackId) {
|
|
6126
|
+
static applyDiffLocally(base, diff, fallbackId, collection) {
|
|
6126
6127
|
const seed = base ? _SyncedDb.safeDeepClone(base) : { _id: fallbackId };
|
|
6127
6128
|
if (seed._id == null) seed._id = fallbackId;
|
|
6128
6129
|
for (const path of Object.keys(diff)) {
|
|
@@ -6136,10 +6137,98 @@ var _SyncedDb = class _SyncedDb {
|
|
|
6136
6137
|
continue;
|
|
6137
6138
|
}
|
|
6138
6139
|
const ok = setByPath(seed, path, value);
|
|
6139
|
-
if (!ok)
|
|
6140
|
+
if (!ok) {
|
|
6141
|
+
_SyncedDb.materializeBracketPath(seed, path, value, collection, fallbackId);
|
|
6142
|
+
}
|
|
6140
6143
|
}
|
|
6141
6144
|
return seed;
|
|
6142
6145
|
}
|
|
6146
|
+
/**
|
|
6147
|
+
* Fallback for `setByPath` failures inside `applyDiffLocally`. Materializes
|
|
6148
|
+
* the parent array when it's missing from `seed`. Two patterns covered, per
|
|
6149
|
+
* production-spec (mozirje 2026-05-10 — literal bracket-keyed sibling
|
|
6150
|
+
* properties polluting Dexie/in-mem):
|
|
6151
|
+
*
|
|
6152
|
+
* 1. `polje[<id>] = <obj>` → seed.polje = [<obj>]
|
|
6153
|
+
* 2. `polje[<id>].<field> = <v>` → seed.polje = [{_id: <id>, <field>: <v>}]
|
|
6154
|
+
*
|
|
6155
|
+
* Everything else (nested-via-dots before bracket, multi-bracket paths
|
|
6156
|
+
* like `_redundanca.terapije[<id>].postavke[<id2>]`, deeper sub-fields)
|
|
6157
|
+
* is dropped silently — materializing those locally would risk corrupting
|
|
6158
|
+
* unrelated invariants on the nested objects. Dirty-change still carries
|
|
6159
|
+
* the path, so server applies it; next sync brings the canonical state
|
|
6160
|
+
* back to local.
|
|
6161
|
+
*
|
|
6162
|
+
* Replaces the pre-fix blind `seed[path] = value` fallback that stamped
|
|
6163
|
+
* literal bracket-keyed top-level properties (e.g. `"postavke[<id>]": [<el>]`)
|
|
6164
|
+
* onto Dexie rows and in-mem state, persisting forever through subsequent
|
|
6165
|
+
* `safeDeepClone`-based save cycles.
|
|
6166
|
+
*/
|
|
6167
|
+
static materializeBracketPath(seed, path, value, collection, id) {
|
|
6168
|
+
const tokens = tokenizePath(path);
|
|
6169
|
+
const firstToken = tokens[0];
|
|
6170
|
+
const dropSilently = typeof firstToken === "string" && firstToken.startsWith("_");
|
|
6171
|
+
const drop = (reason) => {
|
|
6172
|
+
if (dropSilently) return;
|
|
6173
|
+
console.error(
|
|
6174
|
+
`SyncedDb.applyDiffLocally: dropping bracket-path diff entry (${reason})`,
|
|
6175
|
+
{ collection, _id: String(id), path, value }
|
|
6176
|
+
);
|
|
6177
|
+
};
|
|
6178
|
+
if (tokens.length < 2 || tokens.length > 3) {
|
|
6179
|
+
drop(`unsupported token count ${tokens.length}`);
|
|
6180
|
+
return;
|
|
6181
|
+
}
|
|
6182
|
+
if (firstToken === void 0 || firstToken.startsWith("[")) {
|
|
6183
|
+
drop("first segment is not a plain field");
|
|
6184
|
+
return;
|
|
6185
|
+
}
|
|
6186
|
+
const secondToken = tokens[1];
|
|
6187
|
+
if (!secondToken.startsWith("[") || !secondToken.endsWith("]")) {
|
|
6188
|
+
drop("second segment is not a bracket-by-id");
|
|
6189
|
+
return;
|
|
6190
|
+
}
|
|
6191
|
+
if (tokens.length === 3 && tokens[2].startsWith("[")) {
|
|
6192
|
+
drop("nested bracket path");
|
|
6193
|
+
return;
|
|
6194
|
+
}
|
|
6195
|
+
const bracketId = secondToken.slice(1, -1);
|
|
6196
|
+
if (bracketId.length === 0) {
|
|
6197
|
+
drop("empty bracket id");
|
|
6198
|
+
return;
|
|
6199
|
+
}
|
|
6200
|
+
const existing = seed[firstToken];
|
|
6201
|
+
if (existing != null && !Array.isArray(existing)) {
|
|
6202
|
+
drop(`existing "${firstToken}" is not an array`);
|
|
6203
|
+
return;
|
|
6204
|
+
}
|
|
6205
|
+
if (tokens.length === 2) {
|
|
6206
|
+
let element = value;
|
|
6207
|
+
if (Array.isArray(value) && value.length === 1 && value[0] != null && typeof value[0] === "object") {
|
|
6208
|
+
element = value[0];
|
|
6209
|
+
}
|
|
6210
|
+
if (element == null || typeof element !== "object" || Array.isArray(element)) {
|
|
6211
|
+
drop("value is not a single element or wire-form wrapper");
|
|
6212
|
+
return;
|
|
6213
|
+
}
|
|
6214
|
+
if (element._id == null) {
|
|
6215
|
+
element._id = bracketId;
|
|
6216
|
+
}
|
|
6217
|
+
if (existing == null) {
|
|
6218
|
+
seed[firstToken] = [element];
|
|
6219
|
+
} else {
|
|
6220
|
+
existing.push(element);
|
|
6221
|
+
}
|
|
6222
|
+
return;
|
|
6223
|
+
}
|
|
6224
|
+
const fieldName = tokens[2];
|
|
6225
|
+
const newElement = { _id: bracketId, [fieldName]: value };
|
|
6226
|
+
if (existing == null) {
|
|
6227
|
+
seed[firstToken] = [newElement];
|
|
6228
|
+
} else {
|
|
6229
|
+
existing.push(newElement);
|
|
6230
|
+
}
|
|
6231
|
+
}
|
|
6143
6232
|
/**
|
|
6144
6233
|
* Deep clone for `applyDiffLocally`. Recurses into plain objects and
|
|
6145
6234
|
* arrays; preserves `Date` (cloned to avoid shared reference) and
|
|
@@ -435,6 +435,28 @@ export declare class SyncedDb implements I_SyncedDb {
|
|
|
435
435
|
* the input `base` reference.
|
|
436
436
|
*/
|
|
437
437
|
private static applyDiffLocally;
|
|
438
|
+
/**
|
|
439
|
+
* Fallback for `setByPath` failures inside `applyDiffLocally`. Materializes
|
|
440
|
+
* the parent array when it's missing from `seed`. Two patterns covered, per
|
|
441
|
+
* production-spec (mozirje 2026-05-10 — literal bracket-keyed sibling
|
|
442
|
+
* properties polluting Dexie/in-mem):
|
|
443
|
+
*
|
|
444
|
+
* 1. `polje[<id>] = <obj>` → seed.polje = [<obj>]
|
|
445
|
+
* 2. `polje[<id>].<field> = <v>` → seed.polje = [{_id: <id>, <field>: <v>}]
|
|
446
|
+
*
|
|
447
|
+
* Everything else (nested-via-dots before bracket, multi-bracket paths
|
|
448
|
+
* like `_redundanca.terapije[<id>].postavke[<id2>]`, deeper sub-fields)
|
|
449
|
+
* is dropped silently — materializing those locally would risk corrupting
|
|
450
|
+
* unrelated invariants on the nested objects. Dirty-change still carries
|
|
451
|
+
* the path, so server applies it; next sync brings the canonical state
|
|
452
|
+
* back to local.
|
|
453
|
+
*
|
|
454
|
+
* Replaces the pre-fix blind `seed[path] = value` fallback that stamped
|
|
455
|
+
* literal bracket-keyed top-level properties (e.g. `"postavke[<id>]": [<el>]`)
|
|
456
|
+
* onto Dexie rows and in-mem state, persisting forever through subsequent
|
|
457
|
+
* `safeDeepClone`-based save cycles.
|
|
458
|
+
*/
|
|
459
|
+
private static materializeBracketPath;
|
|
438
460
|
/**
|
|
439
461
|
* Deep clone for `applyDiffLocally`. Recurses into plain objects and
|
|
440
462
|
* arrays; preserves `Date` (cloned to avoid shared reference) and
|