memorio 5.1.3 → 5.1.4
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/AGENTS.md +1 -1
- package/CHANGELOG.md +9 -6
- package/README.md +18 -13
- package/examples/sqlite-batched-writes.ts +60 -60
- package/global.cjs +73 -33
- package/global.js +73 -33
- package/index.cjs +73 -33
- package/index.js +73 -33
- package/llms.txt +13 -0
- package/markdown/MEMORY.md +27 -0
- package/markdown/SQLITE.md +2 -2
- package/markdown/SYNC.md +1 -1
- package/modules/redux.cjs +29 -6
- package/modules/redux.cjs.map +1 -1
- package/modules/redux.js +29 -6
- package/modules/redux.js.map +1 -1
- package/package.json +1 -1
- package/types/state.d.ts +19 -5
- package/vsix/memorio.vsix +0 -0
package/index.cjs
CHANGED
|
@@ -3324,19 +3324,39 @@ if (globalThis[STATE_INSTANCE_KEY]) {
|
|
|
3324
3324
|
const initial = exports.store.get(key);
|
|
3325
3325
|
if (initial !== void 0 && initial !== null) {
|
|
3326
3326
|
let acc = exports.state;
|
|
3327
|
+
let seedOk = true;
|
|
3327
3328
|
for (let i = 0; i < segments.length - 1; i++) {
|
|
3328
3329
|
const seg = segments[i];
|
|
3329
|
-
|
|
3330
|
-
|
|
3330
|
+
const existing = acc[seg];
|
|
3331
|
+
if (existing === void 0 || existing === null) {
|
|
3332
|
+
acc[seg] = {};
|
|
3333
|
+
acc = acc[seg];
|
|
3334
|
+
} else if (typeof existing === "object") {
|
|
3335
|
+
acc = existing;
|
|
3336
|
+
} else {
|
|
3337
|
+
if (exports.DEV) {
|
|
3338
|
+
console.warn(
|
|
3339
|
+
`[memorio state] state.persist('${normalized}') aborted seeding: '${seg}' already holds a primitive value (${typeof existing}), cannot nest '${segments.slice(i + 1).join(".")}' under it.`
|
|
3340
|
+
);
|
|
3341
|
+
}
|
|
3342
|
+
seedOk = false;
|
|
3343
|
+
break;
|
|
3344
|
+
}
|
|
3345
|
+
}
|
|
3346
|
+
if (seedOk && acc) {
|
|
3347
|
+
acc[segments[segments.length - 1]] = deepRaw(initial);
|
|
3331
3348
|
}
|
|
3332
|
-
if (acc) acc[segments[segments.length - 1]] = deepRaw(initial);
|
|
3333
3349
|
}
|
|
3334
3350
|
const handler = /* @__PURE__ */ __name(() => {
|
|
3335
3351
|
let current = exports.state;
|
|
3336
3352
|
for (const seg of segments) {
|
|
3337
3353
|
current = current === void 0 || current === null ? void 0 : current[seg];
|
|
3338
3354
|
}
|
|
3339
|
-
|
|
3355
|
+
if (current === void 0) {
|
|
3356
|
+
exports.store.remove(key);
|
|
3357
|
+
} else {
|
|
3358
|
+
exports.store.set(key, deepRaw(current));
|
|
3359
|
+
}
|
|
3340
3360
|
}, "handler");
|
|
3341
3361
|
const off = dispatch.listen(normalized, handler);
|
|
3342
3362
|
return typeof off === "function" ? off : () => {
|
|
@@ -3756,8 +3776,7 @@ var observerFunction = /* @__PURE__ */ __name((s, cb = null, option = true) => {
|
|
|
3756
3776
|
}
|
|
3757
3777
|
if (s && cb) {
|
|
3758
3778
|
const resolvedPath = resolvePath(s);
|
|
3759
|
-
if (!resolvedPath)
|
|
3760
|
-
if (typeof s !== "string" && !(s && typeof s === "object")) {
|
|
3779
|
+
if (!resolvedPath) {
|
|
3761
3780
|
console.error(`Observer Error: name of state need to be a 'string' like 'state.test' or a direct state value`);
|
|
3762
3781
|
return;
|
|
3763
3782
|
}
|
|
@@ -3807,7 +3826,7 @@ Object.defineProperties(
|
|
|
3807
3826
|
* @returns void
|
|
3808
3827
|
*/
|
|
3809
3828
|
removeAll: {
|
|
3810
|
-
|
|
3829
|
+
value: /* @__PURE__ */ __name(() => {
|
|
3811
3830
|
const obs = globalThis.observer;
|
|
3812
3831
|
const list = obs?.list;
|
|
3813
3832
|
if (list) {
|
|
@@ -3816,7 +3835,7 @@ Object.defineProperties(
|
|
|
3816
3835
|
});
|
|
3817
3836
|
}
|
|
3818
3837
|
return true;
|
|
3819
|
-
}, "
|
|
3838
|
+
}, "value")
|
|
3820
3839
|
},
|
|
3821
3840
|
///
|
|
3822
3841
|
/**
|
|
@@ -3846,40 +3865,58 @@ var useObserver = /* @__PURE__ */ __name(((func, deps = []) => {
|
|
|
3846
3865
|
const unsubs = [];
|
|
3847
3866
|
const depList = Array.isArray(deps) && !deps.__path ? deps : [deps];
|
|
3848
3867
|
try {
|
|
3849
|
-
depList.
|
|
3850
|
-
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
|
|
3854
|
-
}
|
|
3855
|
-
t = dep.__path || (typeof dep.toString === "function" && dep.toString() !== "[object Object]" ? dep.toString() : "");
|
|
3868
|
+
if (depList.length === 0) {
|
|
3869
|
+
exports.internal.clearTrackedPaths();
|
|
3870
|
+
exports.internal.tracking = true;
|
|
3871
|
+
try {
|
|
3872
|
+
func();
|
|
3873
|
+
} catch (_) {
|
|
3856
3874
|
}
|
|
3857
|
-
|
|
3858
|
-
|
|
3859
|
-
const path = t.startsWith("store.") || t.startsWith("state.") ? t : "state." + t;
|
|
3875
|
+
exports.internal.tracking = false;
|
|
3876
|
+
exports.internal.trackedPaths.forEach((path) => {
|
|
3860
3877
|
if (!handlers.includes(path)) {
|
|
3878
|
+
message_default(`useObserver: [Auto-Discovery] -> "${path}"`);
|
|
3861
3879
|
handlers.push(path);
|
|
3862
3880
|
const off = dispatch.listen(path, () => func());
|
|
3863
3881
|
if (typeof off === "function") unsubs.push({ path, off });
|
|
3864
3882
|
}
|
|
3865
|
-
}
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
|
|
3883
|
+
});
|
|
3884
|
+
} else {
|
|
3885
|
+
depList.forEach((dep) => {
|
|
3886
|
+
let t = "";
|
|
3887
|
+
if (typeof dep === "function") {
|
|
3888
|
+
const result = exports.propertyName(dep);
|
|
3889
|
+
if (result) t = result;
|
|
3890
|
+
} else if (typeof dep === "object" && dep !== null) {
|
|
3891
|
+
t = dep.__path || (typeof dep.toString === "function" && dep.toString() !== "[object Object]" ? dep.toString() : "");
|
|
3871
3892
|
}
|
|
3872
|
-
|
|
3873
|
-
|
|
3893
|
+
if (t) {
|
|
3894
|
+
t = t.replace(/^(\(\)\s*=>\s*)/, "").replace(/^globalThis\./, "").replace(/^state\./, "");
|
|
3895
|
+
const path = t.startsWith("store.") || t.startsWith("state.") ? t : "state." + t;
|
|
3874
3896
|
if (!handlers.includes(path)) {
|
|
3875
|
-
message_default(`useObserver: [Auto-Discovery] -> "${path}"`);
|
|
3876
3897
|
handlers.push(path);
|
|
3877
3898
|
const off = dispatch.listen(path, () => func());
|
|
3878
3899
|
if (typeof off === "function") unsubs.push({ path, off });
|
|
3879
3900
|
}
|
|
3880
|
-
}
|
|
3881
|
-
|
|
3882
|
-
|
|
3901
|
+
} else {
|
|
3902
|
+
exports.internal.clearTrackedPaths();
|
|
3903
|
+
exports.internal.tracking = true;
|
|
3904
|
+
try {
|
|
3905
|
+
func();
|
|
3906
|
+
} catch (_) {
|
|
3907
|
+
}
|
|
3908
|
+
exports.internal.tracking = false;
|
|
3909
|
+
exports.internal.trackedPaths.forEach((path) => {
|
|
3910
|
+
if (!handlers.includes(path)) {
|
|
3911
|
+
message_default(`useObserver: [Auto-Discovery] -> "${path}"`);
|
|
3912
|
+
handlers.push(path);
|
|
3913
|
+
const off = dispatch.listen(path, () => func());
|
|
3914
|
+
if (typeof off === "function") unsubs.push({ path, off });
|
|
3915
|
+
}
|
|
3916
|
+
});
|
|
3917
|
+
}
|
|
3918
|
+
});
|
|
3919
|
+
}
|
|
3883
3920
|
if (handlers.length > 0) {
|
|
3884
3921
|
message_default(`useObserver: Monitoring ${handlers.length} paths.`);
|
|
3885
3922
|
} else {
|
|
@@ -4805,7 +4842,7 @@ init_internal();
|
|
|
4805
4842
|
|
|
4806
4843
|
// package.json
|
|
4807
4844
|
var package_default = {
|
|
4808
|
-
version: "5.1.
|
|
4845
|
+
version: "5.1.4"};
|
|
4809
4846
|
|
|
4810
4847
|
// core/global.ts
|
|
4811
4848
|
init_env();
|
|
@@ -5481,19 +5518,22 @@ var memory = {
|
|
|
5481
5518
|
async patch(key, patches) {
|
|
5482
5519
|
const entry = await this._getEntry(key);
|
|
5483
5520
|
if (!entry) return;
|
|
5521
|
+
const patchedValue = JSON.parse(JSON.stringify(entry.value ?? {}));
|
|
5484
5522
|
let patched = false;
|
|
5485
5523
|
for (const p of patches) {
|
|
5524
|
+
const relativePath = p.path.replace(/^[^.]+\./, "");
|
|
5486
5525
|
if (p.op === "set") {
|
|
5487
|
-
setNestedPath(
|
|
5526
|
+
setNestedPath(patchedValue, relativePath, p.value);
|
|
5488
5527
|
patched = true;
|
|
5489
5528
|
} else if (p.op === "delete") {
|
|
5490
|
-
deleteNestedPath(
|
|
5529
|
+
deleteNestedPath(patchedValue, relativePath);
|
|
5491
5530
|
patched = true;
|
|
5492
5531
|
}
|
|
5493
5532
|
}
|
|
5494
5533
|
if (!patched) return;
|
|
5495
5534
|
const updated = {
|
|
5496
5535
|
...entry,
|
|
5536
|
+
value: patchedValue,
|
|
5497
5537
|
updatedAt: now(),
|
|
5498
5538
|
lastConfirmedAt: now(),
|
|
5499
5539
|
version: (entry.version ? entry.version : 0) + 1,
|
package/index.js
CHANGED
|
@@ -3321,19 +3321,39 @@ if (globalThis[STATE_INSTANCE_KEY]) {
|
|
|
3321
3321
|
const initial = store.get(key);
|
|
3322
3322
|
if (initial !== void 0 && initial !== null) {
|
|
3323
3323
|
let acc = state2;
|
|
3324
|
+
let seedOk = true;
|
|
3324
3325
|
for (let i = 0; i < segments.length - 1; i++) {
|
|
3325
3326
|
const seg = segments[i];
|
|
3326
|
-
|
|
3327
|
-
|
|
3327
|
+
const existing = acc[seg];
|
|
3328
|
+
if (existing === void 0 || existing === null) {
|
|
3329
|
+
acc[seg] = {};
|
|
3330
|
+
acc = acc[seg];
|
|
3331
|
+
} else if (typeof existing === "object") {
|
|
3332
|
+
acc = existing;
|
|
3333
|
+
} else {
|
|
3334
|
+
if (DEV) {
|
|
3335
|
+
console.warn(
|
|
3336
|
+
`[memorio state] state.persist('${normalized}') aborted seeding: '${seg}' already holds a primitive value (${typeof existing}), cannot nest '${segments.slice(i + 1).join(".")}' under it.`
|
|
3337
|
+
);
|
|
3338
|
+
}
|
|
3339
|
+
seedOk = false;
|
|
3340
|
+
break;
|
|
3341
|
+
}
|
|
3342
|
+
}
|
|
3343
|
+
if (seedOk && acc) {
|
|
3344
|
+
acc[segments[segments.length - 1]] = deepRaw(initial);
|
|
3328
3345
|
}
|
|
3329
|
-
if (acc) acc[segments[segments.length - 1]] = deepRaw(initial);
|
|
3330
3346
|
}
|
|
3331
3347
|
const handler = /* @__PURE__ */ __name(() => {
|
|
3332
3348
|
let current = state2;
|
|
3333
3349
|
for (const seg of segments) {
|
|
3334
3350
|
current = current === void 0 || current === null ? void 0 : current[seg];
|
|
3335
3351
|
}
|
|
3336
|
-
|
|
3352
|
+
if (current === void 0) {
|
|
3353
|
+
store.remove(key);
|
|
3354
|
+
} else {
|
|
3355
|
+
store.set(key, deepRaw(current));
|
|
3356
|
+
}
|
|
3337
3357
|
}, "handler");
|
|
3338
3358
|
const off = dispatch.listen(normalized, handler);
|
|
3339
3359
|
return typeof off === "function" ? off : () => {
|
|
@@ -3753,8 +3773,7 @@ var observerFunction = /* @__PURE__ */ __name((s, cb = null, option = true) => {
|
|
|
3753
3773
|
}
|
|
3754
3774
|
if (s && cb) {
|
|
3755
3775
|
const resolvedPath = resolvePath(s);
|
|
3756
|
-
if (!resolvedPath)
|
|
3757
|
-
if (typeof s !== "string" && !(s && typeof s === "object")) {
|
|
3776
|
+
if (!resolvedPath) {
|
|
3758
3777
|
console.error(`Observer Error: name of state need to be a 'string' like 'state.test' or a direct state value`);
|
|
3759
3778
|
return;
|
|
3760
3779
|
}
|
|
@@ -3804,7 +3823,7 @@ Object.defineProperties(
|
|
|
3804
3823
|
* @returns void
|
|
3805
3824
|
*/
|
|
3806
3825
|
removeAll: {
|
|
3807
|
-
|
|
3826
|
+
value: /* @__PURE__ */ __name(() => {
|
|
3808
3827
|
const obs = globalThis.observer;
|
|
3809
3828
|
const list = obs?.list;
|
|
3810
3829
|
if (list) {
|
|
@@ -3813,7 +3832,7 @@ Object.defineProperties(
|
|
|
3813
3832
|
});
|
|
3814
3833
|
}
|
|
3815
3834
|
return true;
|
|
3816
|
-
}, "
|
|
3835
|
+
}, "value")
|
|
3817
3836
|
},
|
|
3818
3837
|
///
|
|
3819
3838
|
/**
|
|
@@ -3843,40 +3862,58 @@ var useObserver = /* @__PURE__ */ __name(((func, deps = []) => {
|
|
|
3843
3862
|
const unsubs = [];
|
|
3844
3863
|
const depList = Array.isArray(deps) && !deps.__path ? deps : [deps];
|
|
3845
3864
|
try {
|
|
3846
|
-
depList.
|
|
3847
|
-
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
|
|
3851
|
-
}
|
|
3852
|
-
t = dep.__path || (typeof dep.toString === "function" && dep.toString() !== "[object Object]" ? dep.toString() : "");
|
|
3865
|
+
if (depList.length === 0) {
|
|
3866
|
+
internal_default.clearTrackedPaths();
|
|
3867
|
+
internal_default.tracking = true;
|
|
3868
|
+
try {
|
|
3869
|
+
func();
|
|
3870
|
+
} catch (_) {
|
|
3853
3871
|
}
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
const path2 = t.startsWith("store.") || t.startsWith("state.") ? t : "state." + t;
|
|
3872
|
+
internal_default.tracking = false;
|
|
3873
|
+
internal_default.trackedPaths.forEach((path2) => {
|
|
3857
3874
|
if (!handlers.includes(path2)) {
|
|
3875
|
+
message_default(`useObserver: [Auto-Discovery] -> "${path2}"`);
|
|
3858
3876
|
handlers.push(path2);
|
|
3859
3877
|
const off = dispatch.listen(path2, () => func());
|
|
3860
3878
|
if (typeof off === "function") unsubs.push({ path: path2, off });
|
|
3861
3879
|
}
|
|
3862
|
-
}
|
|
3863
|
-
|
|
3864
|
-
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3880
|
+
});
|
|
3881
|
+
} else {
|
|
3882
|
+
depList.forEach((dep) => {
|
|
3883
|
+
let t = "";
|
|
3884
|
+
if (typeof dep === "function") {
|
|
3885
|
+
const result = propertyName(dep);
|
|
3886
|
+
if (result) t = result;
|
|
3887
|
+
} else if (typeof dep === "object" && dep !== null) {
|
|
3888
|
+
t = dep.__path || (typeof dep.toString === "function" && dep.toString() !== "[object Object]" ? dep.toString() : "");
|
|
3868
3889
|
}
|
|
3869
|
-
|
|
3870
|
-
|
|
3890
|
+
if (t) {
|
|
3891
|
+
t = t.replace(/^(\(\)\s*=>\s*)/, "").replace(/^globalThis\./, "").replace(/^state\./, "");
|
|
3892
|
+
const path2 = t.startsWith("store.") || t.startsWith("state.") ? t : "state." + t;
|
|
3871
3893
|
if (!handlers.includes(path2)) {
|
|
3872
|
-
message_default(`useObserver: [Auto-Discovery] -> "${path2}"`);
|
|
3873
3894
|
handlers.push(path2);
|
|
3874
3895
|
const off = dispatch.listen(path2, () => func());
|
|
3875
3896
|
if (typeof off === "function") unsubs.push({ path: path2, off });
|
|
3876
3897
|
}
|
|
3877
|
-
}
|
|
3878
|
-
|
|
3879
|
-
|
|
3898
|
+
} else {
|
|
3899
|
+
internal_default.clearTrackedPaths();
|
|
3900
|
+
internal_default.tracking = true;
|
|
3901
|
+
try {
|
|
3902
|
+
func();
|
|
3903
|
+
} catch (_) {
|
|
3904
|
+
}
|
|
3905
|
+
internal_default.tracking = false;
|
|
3906
|
+
internal_default.trackedPaths.forEach((path2) => {
|
|
3907
|
+
if (!handlers.includes(path2)) {
|
|
3908
|
+
message_default(`useObserver: [Auto-Discovery] -> "${path2}"`);
|
|
3909
|
+
handlers.push(path2);
|
|
3910
|
+
const off = dispatch.listen(path2, () => func());
|
|
3911
|
+
if (typeof off === "function") unsubs.push({ path: path2, off });
|
|
3912
|
+
}
|
|
3913
|
+
});
|
|
3914
|
+
}
|
|
3915
|
+
});
|
|
3916
|
+
}
|
|
3880
3917
|
if (handlers.length > 0) {
|
|
3881
3918
|
message_default(`useObserver: Monitoring ${handlers.length} paths.`);
|
|
3882
3919
|
} else {
|
|
@@ -4802,7 +4839,7 @@ init_internal();
|
|
|
4802
4839
|
|
|
4803
4840
|
// package.json
|
|
4804
4841
|
var package_default = {
|
|
4805
|
-
version: "5.1.
|
|
4842
|
+
version: "5.1.4"};
|
|
4806
4843
|
|
|
4807
4844
|
// core/global.ts
|
|
4808
4845
|
init_env();
|
|
@@ -5478,19 +5515,22 @@ var memory = {
|
|
|
5478
5515
|
async patch(key, patches) {
|
|
5479
5516
|
const entry = await this._getEntry(key);
|
|
5480
5517
|
if (!entry) return;
|
|
5518
|
+
const patchedValue = JSON.parse(JSON.stringify(entry.value ?? {}));
|
|
5481
5519
|
let patched = false;
|
|
5482
5520
|
for (const p of patches) {
|
|
5521
|
+
const relativePath = p.path.replace(/^[^.]+\./, "");
|
|
5483
5522
|
if (p.op === "set") {
|
|
5484
|
-
setNestedPath(
|
|
5523
|
+
setNestedPath(patchedValue, relativePath, p.value);
|
|
5485
5524
|
patched = true;
|
|
5486
5525
|
} else if (p.op === "delete") {
|
|
5487
|
-
deleteNestedPath(
|
|
5526
|
+
deleteNestedPath(patchedValue, relativePath);
|
|
5488
5527
|
patched = true;
|
|
5489
5528
|
}
|
|
5490
5529
|
}
|
|
5491
5530
|
if (!patched) return;
|
|
5492
5531
|
const updated = {
|
|
5493
5532
|
...entry,
|
|
5533
|
+
value: patchedValue,
|
|
5494
5534
|
updatedAt: now(),
|
|
5495
5535
|
lastConfirmedAt: now(),
|
|
5496
5536
|
version: (entry.version ? entry.version : 0) + 1,
|
package/llms.txt
CHANGED
|
@@ -91,6 +91,19 @@ These are materially different behaviors - confirm against the actual source whi
|
|
|
91
91
|
- Automatic path tracking via `__path` property
|
|
92
92
|
- Nested proxy support
|
|
93
93
|
- Auto-dispatches events on changes
|
|
94
|
+
- `state.persist(path)` mirrors state path to `store` and syncs writes (see "Getting Started" guide)
|
|
95
|
+
|
|
96
|
+
#### `state.persist(path)`
|
|
97
|
+
|
|
98
|
+
Creates a bidirectional mirror between `state` (live in-memory) and `store` (durable copy). Seeds the initial value from `store` if present, then every write to that path flows to `store` automatically.
|
|
99
|
+
|
|
100
|
+
```javascript
|
|
101
|
+
const stopPersisting = state.persist('state.user')
|
|
102
|
+
state.user = { name: 'Sara' }
|
|
103
|
+
// ... writes to state.user are mirrored to store
|
|
104
|
+
|
|
105
|
+
stopPersisting() // stops mirroring; store value is preserved
|
|
106
|
+
```
|
|
94
107
|
|
|
95
108
|
### `store` - localStorage Persistence
|
|
96
109
|
|
package/markdown/MEMORY.md
CHANGED
|
@@ -69,6 +69,33 @@ Permanently removes a memory.
|
|
|
69
69
|
await memorio.memory.forget('user.temp')
|
|
70
70
|
```
|
|
71
71
|
|
|
72
|
+
### `memorio.memory.patch(key, patches)`
|
|
73
|
+
|
|
74
|
+
Apply a field-level JSON Patch to an existing memory entry's value. Supports `set` and `delete` operations.
|
|
75
|
+
|
|
76
|
+
```ts
|
|
77
|
+
await memorio.memory.remember('user', {
|
|
78
|
+
name: 'Mario',
|
|
79
|
+
profile: { theme: 'light', lang: 'en' }
|
|
80
|
+
})
|
|
81
|
+
|
|
82
|
+
// Set a nested value
|
|
83
|
+
await memorio.memory.patch('user', [
|
|
84
|
+
{ op: 'set', path: 'user.profile.theme', value: 'dark' }
|
|
85
|
+
])
|
|
86
|
+
|
|
87
|
+
// Delete a field
|
|
88
|
+
await memorio.memory.patch('user', [
|
|
89
|
+
{ op: 'delete', path: 'user.profile.lang' }
|
|
90
|
+
])
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
| Field | Type | Description |
|
|
94
|
+
|-------|------|-------------|
|
|
95
|
+
| `op` | `'set' \| 'delete'` | The patch operation type |
|
|
96
|
+
| `path` | `string` | Dot-notation path relative to the entry value (e.g. `'user.profile.theme'`) |
|
|
97
|
+
| `value` | `any` | The value to set (only for `op: 'set'`) |
|
|
98
|
+
|
|
72
99
|
### `memorio.memory.context(opts?)`
|
|
73
100
|
|
|
74
101
|
Returns ranked, relevant memories. Uses recency × confidence × type/scope boost algorithm.
|
package/markdown/SQLITE.md
CHANGED
|
@@ -153,8 +153,8 @@ await sqlite.db.journal.checkpoint('app'); // manual checkpoint
|
|
|
153
153
|
|
|
154
154
|
| Method | Parameters | Returns | Description |
|
|
155
155
|
|--------|------------|---------|-------------|
|
|
156
|
-
| `sqlite.config(opts)` | `opts: { loader?, locateFile?, wasmUrl?, persistence?, namespace? }` | `sqlite` | Configure the engine. `loader` fully replaces the initializer (default = CDN `<script>`); `locateFile` customizes wasm resolution; `wasmUrl` sets the wasm base directory; `persistence` toggles
|
|
157
|
-
| `sqlite.db.create(name, opts)` | `name: string, opts?: { data?, persistence? }` | `Database` | Opens/creates a named in-memory db. With `persistence: true` (or global config),
|
|
156
|
+
| `sqlite.config(opts)` | `opts: { loader?, locateFile?, wasmUrl?, persistence?, namespace? }` | `sqlite` | Configure the engine. `loader` fully replaces the initializer (default = CDN `<script>`); `locateFile` customizes wasm resolution; `wasmUrl` sets the wasm base directory; `persistence` toggles journal + checkpoint persistence; `namespace` partitions persisted data. Chainable. |
|
|
157
|
+
| `sqlite.db.create(name, opts)` | `name: string, opts?: { data?, persistence? }` | `Database` | Opens/creates a named in-memory db. With `persistence: true` (or global config), the latest checkpoint is restored and pending journal entries are replayed for full crash recovery. |
|
|
158
158
|
| `sqlite.db.persist(name)` | `name: string` | `Promise<boolean>` | Force an immediate checkpoint (full snapshot + journal clear) of a persisted database to `store`. Alias of `flush`. |
|
|
159
159
|
| `sqlite.db.flush(name)` | `name: string` | `Promise<boolean>` | Force an immediate checkpoint (alias of `persist`). |
|
|
160
160
|
| `sqlite.db.download(name, filename?)` | `name: string, filename?: string` | `Promise<boolean>` | Dev-only: trigger a browser download of the db as a `.sqlite` file. |
|
package/markdown/SYNC.md
CHANGED
|
@@ -71,7 +71,7 @@ the durable journal/value store when you opt in:
|
|
|
71
71
|
snapshot the database to `store` (localStorage) and restore it on reopen.
|
|
72
72
|
- Writes are journaled incrementally (append-only, HLC-timestamped) and
|
|
73
73
|
checkpointed periodically (every 50 ops or 250 ms of idle). On reopen, the
|
|
74
|
-
last checkpoint is loaded and the journal is replayed
|
|
74
|
+
last checkpoint is loaded and the journal is replayed - no writes are lost.
|
|
75
75
|
- `sqlite.db.persist(name)` / `sqlite.db.flush(name)` forces an immediate
|
|
76
76
|
checkpoint; `sqlite.db.close(name)` checkpoints + closes;
|
|
77
77
|
`sqlite.db.download(name, file?)` triggers a browser `.sqlite` download
|
package/modules/redux.cjs
CHANGED
|
@@ -2029,19 +2029,39 @@ if (globalThis[STATE_INSTANCE_KEY]) {
|
|
|
2029
2029
|
const initial = store.get(key);
|
|
2030
2030
|
if (initial !== void 0 && initial !== null) {
|
|
2031
2031
|
let acc = state2;
|
|
2032
|
+
let seedOk = true;
|
|
2032
2033
|
for (let i = 0; i < segments.length - 1; i++) {
|
|
2033
2034
|
const seg = segments[i];
|
|
2034
|
-
|
|
2035
|
-
|
|
2035
|
+
const existing = acc[seg];
|
|
2036
|
+
if (existing === void 0 || existing === null) {
|
|
2037
|
+
acc[seg] = {};
|
|
2038
|
+
acc = acc[seg];
|
|
2039
|
+
} else if (typeof existing === "object") {
|
|
2040
|
+
acc = existing;
|
|
2041
|
+
} else {
|
|
2042
|
+
if (DEV) {
|
|
2043
|
+
console.warn(
|
|
2044
|
+
`[memorio state] state.persist('${normalized}') aborted seeding: '${seg}' already holds a primitive value (${typeof existing}), cannot nest '${segments.slice(i + 1).join(".")}' under it.`
|
|
2045
|
+
);
|
|
2046
|
+
}
|
|
2047
|
+
seedOk = false;
|
|
2048
|
+
break;
|
|
2049
|
+
}
|
|
2050
|
+
}
|
|
2051
|
+
if (seedOk && acc) {
|
|
2052
|
+
acc[segments[segments.length - 1]] = deepRaw(initial);
|
|
2036
2053
|
}
|
|
2037
|
-
if (acc) acc[segments[segments.length - 1]] = deepRaw(initial);
|
|
2038
2054
|
}
|
|
2039
2055
|
const handler = /* @__PURE__ */ __name(() => {
|
|
2040
2056
|
let current = state2;
|
|
2041
2057
|
for (const seg of segments) {
|
|
2042
2058
|
current = current === void 0 || current === null ? void 0 : current[seg];
|
|
2043
2059
|
}
|
|
2044
|
-
|
|
2060
|
+
if (current === void 0) {
|
|
2061
|
+
store.remove(key);
|
|
2062
|
+
} else {
|
|
2063
|
+
store.set(key, deepRaw(current));
|
|
2064
|
+
}
|
|
2045
2065
|
}, "handler");
|
|
2046
2066
|
const off = dispatch.listen(normalized, handler);
|
|
2047
2067
|
return typeof off === "function" ? off : () => {
|
|
@@ -3031,19 +3051,22 @@ var memory = {
|
|
|
3031
3051
|
async patch(key, patches) {
|
|
3032
3052
|
const entry = await this._getEntry(key);
|
|
3033
3053
|
if (!entry) return;
|
|
3054
|
+
const patchedValue = JSON.parse(JSON.stringify(entry.value ?? {}));
|
|
3034
3055
|
let patched = false;
|
|
3035
3056
|
for (const p of patches) {
|
|
3057
|
+
const relativePath = p.path.replace(/^[^.]+\./, "");
|
|
3036
3058
|
if (p.op === "set") {
|
|
3037
|
-
setNestedPath(
|
|
3059
|
+
setNestedPath(patchedValue, relativePath, p.value);
|
|
3038
3060
|
patched = true;
|
|
3039
3061
|
} else if (p.op === "delete") {
|
|
3040
|
-
deleteNestedPath(
|
|
3062
|
+
deleteNestedPath(patchedValue, relativePath);
|
|
3041
3063
|
patched = true;
|
|
3042
3064
|
}
|
|
3043
3065
|
}
|
|
3044
3066
|
if (!patched) return;
|
|
3045
3067
|
const updated = {
|
|
3046
3068
|
...entry,
|
|
3069
|
+
value: patchedValue,
|
|
3047
3070
|
updatedAt: now(),
|
|
3048
3071
|
lastConfirmedAt: now(),
|
|
3049
3072
|
version: (entry.version ? entry.version : 0) + 1,
|