mirror of
https://github.com/Youzini-afk/ST-Bionic-Memory-Ecology.git
synced 2026-06-13 18:31:16 +08:00
173 lines
5.4 KiB
JavaScript
173 lines
5.4 KiB
JavaScript
// ST-BME v3 GraphStore adapter wrappers.
|
|
//
|
|
// These wrappers add v3 head/marker sidecar methods to existing stores without
|
|
// changing their legacy load/save behavior. Physical namespace cutover is handled
|
|
// by dedicated constructors/routes later.
|
|
|
|
import {
|
|
GRAPH_V3_COMMIT_MARKER_KEY,
|
|
GRAPH_V3_HEAD_KEY,
|
|
} from "../graph/graph-v3-namespace.js";
|
|
import {
|
|
normalizeCommitMarkerV3,
|
|
normalizeGraphHead,
|
|
} from "../graph/graph-head.js";
|
|
import {
|
|
readGraphChatStateNamespaces,
|
|
writeGraphChatStatePayload,
|
|
} from "../graph/graph-persistence.js";
|
|
import { assertGraphStoreContract } from "./graph-store-contract.js";
|
|
|
|
const GRAPH_STORE_V3_WRAPPED = Symbol.for("st-bme.graph-store-v3-wrapped");
|
|
|
|
function bindStoreMethod(store = null, method = "") {
|
|
const value = store?.[method];
|
|
return typeof value === "function" ? value.bind(store) : value;
|
|
}
|
|
|
|
export function isGraphStoreV3Wrapped(store = null) {
|
|
return Boolean(store?.[GRAPH_STORE_V3_WRAPPED]);
|
|
}
|
|
|
|
export function wrapDbLikeGraphStoreV3(store = null) {
|
|
assertGraphStoreContract(store);
|
|
if (isGraphStoreV3Wrapped(store)) return store;
|
|
|
|
const wrapper = Object.create(store);
|
|
Object.defineProperty(wrapper, GRAPH_STORE_V3_WRAPPED, {
|
|
value: true,
|
|
enumerable: false,
|
|
});
|
|
|
|
for (const key of Reflect.ownKeys(store)) {
|
|
if (key === GRAPH_STORE_V3_WRAPPED) continue;
|
|
const descriptor = Object.getOwnPropertyDescriptor(store, key);
|
|
if (descriptor) Object.defineProperty(wrapper, key, descriptor);
|
|
}
|
|
|
|
for (const method of [
|
|
"open",
|
|
"close",
|
|
"getMeta",
|
|
"setMeta",
|
|
"patchMeta",
|
|
"commitDelta",
|
|
"exportSnapshot",
|
|
"exportSnapshotProbe",
|
|
"importSnapshot",
|
|
"isEmpty",
|
|
"clearAll",
|
|
]) {
|
|
if (typeof store[method] === "function") {
|
|
wrapper[method] = bindStoreMethod(store, method);
|
|
}
|
|
}
|
|
|
|
wrapper.readHead = async ({ fallback = null } = {}) => {
|
|
const raw = await store.getMeta(GRAPH_V3_HEAD_KEY, null);
|
|
return raw == null ? fallback : normalizeGraphHead(raw, fallback || {});
|
|
};
|
|
|
|
wrapper.writeHead = async (head = null, { fallback = null } = {}) => {
|
|
const normalized = normalizeGraphHead(head, fallback || {});
|
|
await store.patchMeta({ [GRAPH_V3_HEAD_KEY]: normalized });
|
|
return normalized;
|
|
};
|
|
|
|
wrapper.readCommitMarker = async ({ fallback = null } = {}) => {
|
|
const raw = await store.getMeta(GRAPH_V3_COMMIT_MARKER_KEY, null);
|
|
return normalizeCommitMarkerV3(raw) || fallback;
|
|
};
|
|
|
|
wrapper.writeCommitMarker = async (marker = null) => {
|
|
const normalized = normalizeCommitMarkerV3(marker);
|
|
if (!normalized) {
|
|
const error = new Error("graph-store-v3-commit-marker-invalid");
|
|
error.code = "graph_store_v3_commit_marker_invalid";
|
|
throw error;
|
|
}
|
|
await store.patchMeta({ [GRAPH_V3_COMMIT_MARKER_KEY]: normalized });
|
|
return normalized;
|
|
};
|
|
|
|
wrapper.deleteAll = async (...args) => {
|
|
if (typeof store.clearAll !== "function") {
|
|
const error = new Error("graph-store-v3-delete-all-unavailable");
|
|
error.code = "graph_store_v3_delete_all_unavailable";
|
|
throw error;
|
|
}
|
|
return store.clearAll(...args);
|
|
};
|
|
|
|
return wrapper;
|
|
}
|
|
|
|
export function createLukerChatStateGraphStoreV3({
|
|
context = null,
|
|
chatStateTarget = null,
|
|
storeKind = "luker-chat-state",
|
|
storeMode = "luker-chat-state-v3",
|
|
} = {}) {
|
|
async function readNamespace(namespace = "", fallback = null) {
|
|
const payloads = await readGraphChatStateNamespaces(context, [namespace], {
|
|
target: chatStateTarget,
|
|
});
|
|
return payloads.get(namespace) ?? fallback;
|
|
}
|
|
|
|
async function writeNamespace(namespace = "", payload = null) {
|
|
const result = await writeGraphChatStatePayload(context, namespace, payload, {
|
|
target: chatStateTarget,
|
|
});
|
|
if (result?.ok !== true) {
|
|
const error = new Error(result?.reason || "luker-graph-store-v3-write-failed");
|
|
error.code = "luker_graph_store_v3_write_failed";
|
|
error.result = result;
|
|
throw error;
|
|
}
|
|
return payload;
|
|
}
|
|
|
|
return {
|
|
storeKind,
|
|
storeMode,
|
|
async open() {
|
|
return this;
|
|
},
|
|
async close() {},
|
|
async getMeta(key = "", fallbackValue = null) {
|
|
return readNamespace(String(key || ""), fallbackValue);
|
|
},
|
|
async patchMeta(record = {}) {
|
|
const entries = Object.entries(record && typeof record === "object" ? record : {});
|
|
for (const [key, value] of entries) {
|
|
await writeNamespace(key, value);
|
|
}
|
|
return record;
|
|
},
|
|
async readHead({ fallback = null } = {}) {
|
|
const raw = await readNamespace(GRAPH_V3_HEAD_KEY, null);
|
|
return raw == null ? fallback : normalizeGraphHead(raw, fallback || {});
|
|
},
|
|
async writeHead(head = null, { fallback = null } = {}) {
|
|
const normalized = normalizeGraphHead(head, fallback || {});
|
|
await writeNamespace(GRAPH_V3_HEAD_KEY, normalized);
|
|
return normalized;
|
|
},
|
|
async readCommitMarker({ fallback = null } = {}) {
|
|
const raw = await readNamespace(GRAPH_V3_COMMIT_MARKER_KEY, null);
|
|
return normalizeCommitMarkerV3(raw) || fallback;
|
|
},
|
|
async writeCommitMarker(marker = null) {
|
|
const normalized = normalizeCommitMarkerV3(marker);
|
|
if (!normalized) {
|
|
const error = new Error("luker-graph-store-v3-commit-marker-invalid");
|
|
error.code = "luker_graph_store_v3_commit_marker_invalid";
|
|
throw error;
|
|
}
|
|
await writeNamespace(GRAPH_V3_COMMIT_MARKER_KEY, normalized);
|
|
return normalized;
|
|
},
|
|
};
|
|
}
|