





















11// OpenClaw state database manages shared persisted state and migrations.
2-import { randomUUID } from "node:crypto";
32import { existsSync, mkdirSync } from "node:fs";
43import path from "node:path";
54import type { DatabaseSync } from "node:sqlite";
@@ -50,56 +49,14 @@ export type OpenClawStateDatabaseOptions = {
5049path?: string;
5150};
525153-/** Status stored for a state migration run. */
54-export type OpenClawMigrationRunStatus = "completed" | "warning" | "failed";
55-/** Status stored for a state backup run. */
56-export type OpenClawBackupRunStatus = "completed" | "failed";
57-5852export type OpenClawStateDatabaseSchemaMigration = {
5953kind: "agent-databases-composite-primary-key";
6054path: string;
6155};
625663-/** Input for recording one state migration run summary. */
64-export type RecordOpenClawStateMigrationRunOptions = OpenClawStateDatabaseOptions & {
65-id?: string;
66-startedAt: number;
67-finishedAt?: number;
68-status: OpenClawMigrationRunStatus;
69-report: Record<string, unknown>;
70-};
71-72-/** Input for recording one migrated source file/table pair. */
73-export type RecordOpenClawStateMigrationSourceOptions = OpenClawStateDatabaseOptions & {
74-runId: string;
75-migrationKind: string;
76-sourceKey: string;
77-sourcePath: string;
78-targetTable: string;
79-status: OpenClawMigrationRunStatus;
80-importedAt: number;
81-removedSource: boolean;
82-sourceSha256?: string;
83-sourceSizeBytes?: number;
84-sourceRecordCount?: number;
85-report: Record<string, unknown>;
86-};
87-88-/** Input for recording one state backup archive. */
89-export type RecordOpenClawStateBackupRunOptions = OpenClawStateDatabaseOptions & {
90-id?: string;
91-createdAt: number;
92-archivePath: string;
93-status: OpenClawBackupRunStatus;
94-manifest: Record<string, unknown>;
95-};
96-9757const cachedDatabases = new Map<string, OpenClawStateDatabase>();
985899-type OpenClawStateMetadataDatabase = Pick<
100-OpenClawStateKyselyDatabase,
101-"backup_runs" | "migration_runs" | "migration_sources" | "schema_meta"
102->;
59+type OpenClawStateMetadataDatabase = Pick<OpenClawStateKyselyDatabase, "schema_meta">;
1036010461function readSqliteUserVersion(db: DatabaseSync): number {
10562const row = db.prepare("PRAGMA user_version").get() as { user_version?: unknown } | undefined;
@@ -964,89 +921,6 @@ export function runOpenClawStateWriteTransaction<T>(
964921return result;
965922}
966923967-/** Record a state migration run and return its stable run id. */
968-export function recordOpenClawStateMigrationRun(
969-options: RecordOpenClawStateMigrationRunOptions,
970-): string {
971-const id = options.id ?? randomUUID();
972-runOpenClawStateWriteTransaction((database) => {
973-const db = getNodeSqliteKysely<OpenClawStateMetadataDatabase>(database.db);
974-executeSqliteQuerySync(
975-database.db,
976-db.insertInto("migration_runs").values({
977- id,
978-started_at: options.startedAt,
979-finished_at: options.finishedAt ?? null,
980-status: options.status,
981-report_json: JSON.stringify(options.report),
982-}),
983-);
984-}, options);
985-return id;
986-}
987-988-/** Upsert the per-source audit row for a state migration. */
989-export function recordOpenClawStateMigrationSource(
990-options: RecordOpenClawStateMigrationSourceOptions,
991-): void {
992-runOpenClawStateWriteTransaction((database) => {
993-const db = getNodeSqliteKysely<OpenClawStateMetadataDatabase>(database.db);
994-executeSqliteQuerySync(
995-database.db,
996-db
997-.insertInto("migration_sources")
998-.values({
999-source_key: options.sourceKey,
1000-migration_kind: options.migrationKind,
1001-source_path: options.sourcePath,
1002-target_table: options.targetTable,
1003-source_sha256: options.sourceSha256 ?? null,
1004-source_size_bytes: options.sourceSizeBytes ?? null,
1005-source_record_count: options.sourceRecordCount ?? null,
1006-last_run_id: options.runId,
1007-status: options.status,
1008-imported_at: options.importedAt,
1009-removed_source: options.removedSource ? 1 : 0,
1010-report_json: JSON.stringify(options.report),
1011-})
1012-.onConflict((conflict) =>
1013-conflict.column("source_key").doUpdateSet({
1014-migration_kind: (eb) => eb.ref("excluded.migration_kind"),
1015-source_path: (eb) => eb.ref("excluded.source_path"),
1016-target_table: (eb) => eb.ref("excluded.target_table"),
1017-source_sha256: (eb) => eb.ref("excluded.source_sha256"),
1018-source_size_bytes: (eb) => eb.ref("excluded.source_size_bytes"),
1019-source_record_count: (eb) => eb.ref("excluded.source_record_count"),
1020-last_run_id: (eb) => eb.ref("excluded.last_run_id"),
1021-status: (eb) => eb.ref("excluded.status"),
1022-imported_at: (eb) => eb.ref("excluded.imported_at"),
1023-removed_source: (eb) => eb.ref("excluded.removed_source"),
1024-report_json: (eb) => eb.ref("excluded.report_json"),
1025-}),
1026-),
1027-);
1028-}, options);
1029-}
1030-1031-/** Record a state backup archive and return its stable backup id. */
1032-export function recordOpenClawStateBackupRun(options: RecordOpenClawStateBackupRunOptions): string {
1033-const id = options.id ?? randomUUID();
1034-runOpenClawStateWriteTransaction((database) => {
1035-const db = getNodeSqliteKysely<OpenClawStateMetadataDatabase>(database.db);
1036-executeSqliteQuerySync(
1037-database.db,
1038-db.insertInto("backup_runs").values({
1039- id,
1040-created_at: options.createdAt,
1041-archive_path: options.archivePath,
1042-status: options.status,
1043-manifest_json: JSON.stringify(options.manifest),
1044-}),
1045-);
1046-}, options);
1047-return id;
1048-}
1049-1050924/** Close all cached shared state database handles. */
1051925export function closeOpenClawStateDatabase(): void {
1052926for (const database of cachedDatabases.values()) {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。