mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-28 00:52:57 +00:00
fix: preserve sqlite compatibility shims
This commit is contained in:
@@ -574,11 +574,12 @@ Completed consolidation/deletion highlights:
|
||||
- Channel session runtime types now expose `{agentId, sessionKey}` for
|
||||
updated-at reads, inbound metadata, and last-route updates. The old
|
||||
`saveSessionStore(storePath, store)` compatibility type is gone.
|
||||
- Plugin runtime, extension API, root library, and `config/sessions` barrel
|
||||
surfaces no longer export `resolveStorePath`; plugin code uses SQLite-backed
|
||||
session row helpers. The old `resolveLegacySessionStorePath` helper is gone;
|
||||
legacy `sessions.json` path construction is now local to migration and test
|
||||
fixtures.
|
||||
- Plugin runtime, extension API, and `config/sessions` barrel surfaces now steer
|
||||
plugin code to SQLite-backed session row helpers. Root library compatibility
|
||||
exports (`loadSessionStore`, `saveSessionStore`, `resolveStorePath`) remain as
|
||||
deprecated shims for existing consumers. The old
|
||||
`resolveLegacySessionStorePath` helper is gone; legacy `sessions.json` path
|
||||
construction is now local to migration and test fixtures.
|
||||
- `src/config/sessions/session-entries.sqlite.ts` now stores canonical session
|
||||
entries in the per-agent database and has row-level read/upsert/delete patch
|
||||
support. Runtime upsert/patch/delete no longer scans for case variants or
|
||||
@@ -1768,6 +1769,8 @@ runtime contract:
|
||||
`patchSessionEntry`, `deleteSessionEntry`, and `listSessionEntries`.
|
||||
- Whole-store rewrite helpers, file writers, queue tests, alias pruning, and
|
||||
legacy-key deletion parameters are gone from runtime.
|
||||
- Deprecated root-package compatibility exports still adapt canonical
|
||||
`sessions.json` paths onto the SQLite row APIs.
|
||||
- `sessions.json` parsing remains only in doctor migration/import code and
|
||||
doctor tests.
|
||||
- Runtime lifecycle fallback reads SQLite transcript headers, not JSONL first
|
||||
|
||||
@@ -30,14 +30,17 @@ export let getSessionEntry: LibraryExports["getSessionEntry"];
|
||||
export let handlePortError: LibraryExports["handlePortError"];
|
||||
export let listSessionEntries: LibraryExports["listSessionEntries"];
|
||||
export let loadConfig: LibraryExports["loadConfig"];
|
||||
export let loadSessionStore: LibraryExports["loadSessionStore"];
|
||||
export let monitorWebChannel: LibraryExports["monitorWebChannel"];
|
||||
export let normalizeE164: LibraryExports["normalizeE164"];
|
||||
export let patchSessionEntry: LibraryExports["patchSessionEntry"];
|
||||
export let PortInUseError: LibraryExports["PortInUseError"];
|
||||
export let promptYesNo: LibraryExports["promptYesNo"];
|
||||
export let resolveSessionKey: LibraryExports["resolveSessionKey"];
|
||||
export let resolveStorePath: LibraryExports["resolveStorePath"];
|
||||
export let runCommandWithTimeout: LibraryExports["runCommandWithTimeout"];
|
||||
export let runExec: LibraryExports["runExec"];
|
||||
export let saveSessionStore: LibraryExports["saveSessionStore"];
|
||||
export let upsertSessionEntry: LibraryExports["upsertSessionEntry"];
|
||||
export let waitForever: LibraryExports["waitForever"];
|
||||
|
||||
@@ -72,14 +75,17 @@ if (!isMain) {
|
||||
handlePortError,
|
||||
listSessionEntries,
|
||||
loadConfig,
|
||||
loadSessionStore,
|
||||
monitorWebChannel,
|
||||
normalizeE164,
|
||||
patchSessionEntry,
|
||||
PortInUseError,
|
||||
promptYesNo,
|
||||
resolveSessionKey,
|
||||
resolveStorePath,
|
||||
runCommandWithTimeout,
|
||||
runExec,
|
||||
saveSessionStore,
|
||||
upsertSessionEntry,
|
||||
waitForever,
|
||||
} = await import("./library.js"));
|
||||
|
||||
@@ -706,12 +706,20 @@ export async function createBackupArchive(
|
||||
});
|
||||
await publishTempArchive({ tempArchivePath, outputPath });
|
||||
if (manifest && result.assets.some((asset) => asset.kind === "state")) {
|
||||
recordOpenClawStateBackupRun({
|
||||
createdAt: nowMs,
|
||||
archivePath: outputPath,
|
||||
status: "completed",
|
||||
manifest: manifest as unknown as Record<string, unknown>,
|
||||
});
|
||||
try {
|
||||
recordOpenClawStateBackupRun({
|
||||
createdAt: nowMs,
|
||||
archivePath: outputPath,
|
||||
status: "completed",
|
||||
manifest: manifest as unknown as Record<string, unknown>,
|
||||
});
|
||||
} catch (error) {
|
||||
opts.log?.(
|
||||
`Backup created, but recording backup history failed: ${
|
||||
error instanceof Error ? error.message : String(error)
|
||||
}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
await fs.rm(tempArchivePath, { force: true }).catch(() => undefined);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { readFileSync } from "node:fs";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import * as library from "./library.js";
|
||||
|
||||
const libraryPath = new URL("./library.ts", import.meta.url);
|
||||
const lazyRuntimeSpecifiers = [
|
||||
@@ -38,3 +39,11 @@ describe("library module imports", () => {
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe("root library compatibility exports", () => {
|
||||
it("keeps deprecated session-store shims available", () => {
|
||||
expect(library.loadSessionStore).toEqual(expect.any(Function));
|
||||
expect(library.saveSessionStore).toEqual(expect.any(Function));
|
||||
expect(library.resolveStorePath).toEqual(expect.any(Function));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -18,6 +18,11 @@ import {
|
||||
handlePortError,
|
||||
PortInUseError,
|
||||
} from "./infra/ports.js";
|
||||
import {
|
||||
loadSessionStore,
|
||||
resolveStorePath,
|
||||
saveSessionStore,
|
||||
} from "./plugin-sdk/session-store-runtime.js";
|
||||
import type { monitorWebChannel as monitorWebChannelRuntime } from "./plugins/runtime/runtime-web-channel-plugin.js";
|
||||
import type {
|
||||
runCommandWithTimeout as runCommandWithTimeoutRuntime,
|
||||
@@ -84,6 +89,7 @@ export {
|
||||
describePortOwner,
|
||||
ensurePortAvailable,
|
||||
handlePortError,
|
||||
loadSessionStore,
|
||||
loadConfig,
|
||||
getSessionEntry,
|
||||
listSessionEntries,
|
||||
@@ -91,6 +97,8 @@ export {
|
||||
patchSessionEntry,
|
||||
PortInUseError,
|
||||
resolveSessionKey,
|
||||
resolveStorePath,
|
||||
saveSessionStore,
|
||||
upsertSessionEntry,
|
||||
waitForever,
|
||||
};
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
loadSessionStore,
|
||||
readSessionUpdatedAt,
|
||||
resolveAndPersistSessionFile,
|
||||
resolveSessionTranscriptPathInDir,
|
||||
saveSessionStore,
|
||||
updateSessionStore,
|
||||
upsertSessionEntry,
|
||||
@@ -21,6 +22,15 @@ describe("session-store-runtime compatibility", () => {
|
||||
return { ...process.env, OPENCLAW_STATE_DIR: stateDir };
|
||||
}
|
||||
|
||||
it("rejects reserved checkpoint session IDs for transcript paths", () => {
|
||||
expect(() =>
|
||||
resolveSessionTranscriptPathInDir(
|
||||
"sess.checkpoint.11111111-1111-4111-8111-111111111111",
|
||||
"/tmp/sessions",
|
||||
),
|
||||
).toThrow(/Invalid session ID/);
|
||||
});
|
||||
|
||||
it("rejects custom store paths instead of falling back to the default agent", async () => {
|
||||
await withOpenClawTestState(
|
||||
{
|
||||
|
||||
@@ -5,6 +5,7 @@ import type { MsgContext } from "../auto-reply/templating.js";
|
||||
import { resolveStateDir } from "../config/paths.js";
|
||||
import { loadSqliteSessionEntries } from "../config/sessions/session-entries.sqlite.js";
|
||||
import { normalizeSessionEntries } from "../config/sessions/session-entry-normalize.js";
|
||||
import { validateSessionId } from "../config/sessions/session-id.js";
|
||||
import { resolveAndPersistSessionTranscriptScope } from "../config/sessions/session-scope.js";
|
||||
import { resolveSessionRowEntry } from "../config/sessions/store-entry.js";
|
||||
import {
|
||||
@@ -73,8 +74,6 @@ type SaveSessionStoreOptions = {
|
||||
|
||||
type CompatSessionEntry = SessionEntry & { sessionFile?: string };
|
||||
|
||||
const SAFE_SESSION_ID_RE = /^[a-z0-9][a-z0-9._-]{0,127}$/i;
|
||||
|
||||
function optionsWithEnv(agentId: string, env?: NodeJS.ProcessEnv): SessionRowOptions {
|
||||
return env ? { agentId, env } : { agentId };
|
||||
}
|
||||
@@ -177,10 +176,7 @@ export function resolveSessionTranscriptPathInDir(
|
||||
sessionsDir: string,
|
||||
topicId?: string | number,
|
||||
): string {
|
||||
const trimmed = sessionId.trim();
|
||||
if (!SAFE_SESSION_ID_RE.test(trimmed)) {
|
||||
throw new Error(`Invalid session ID: ${sessionId}`);
|
||||
}
|
||||
const trimmed = validateSessionId(sessionId);
|
||||
const safeTopicId =
|
||||
typeof topicId === "string"
|
||||
? encodeURIComponent(topicId)
|
||||
|
||||
Reference in New Issue
Block a user