openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
190 lines (189 loc) • 7.27 kB
JavaScript
import { a as getNodeSqliteKysely, i as executeSqliteQueryTakeFirstSync, r as executeSqliteQuerySync } from "./kysely-sync-COmh4HWh.js";
import { _t as coerceRequiredSqliteNumber, i as openOpenClawStateDatabase, s as runOpenClawStateWriteTransaction } from "./openclaw-state-db-BRTnL-D8.js";
//#region src/infra/sqlite-audit-record-store.ts
const LEGACY_AUDIT_SEQUENCE_BASE = Number.MIN_SAFE_INTEGER;
function getAuditRecordKysely(database) {
return getNodeSqliteKysely(database);
}
function parseAuditRecord(row) {
return {
key: row.event_key,
value: JSON.parse(row.payload_json),
createdAt: row.created_at,
sequence: row.sequence
};
}
function countAuditRecords(database, scope) {
const row = executeSqliteQueryTakeFirstSync(database, getAuditRecordKysely(database).selectFrom("diagnostic_events").select((eb) => eb.fn.countAll().as("count")).where("scope", "=", scope));
return typeof row?.count === "bigint" ? coerceRequiredSqliteNumber(row.count) : row?.count ?? 0;
}
function nextAuditSequence(params) {
const next = (executeSqliteQueryTakeFirstSync(params.database, getAuditRecordKysely(params.database).selectFrom("diagnostic_events").select((eb) => eb.fn.max("sequence").as("sequence")).where("scope", "=", params.scope).where("sequence", params.legacy ? "<" : ">=", 0))?.sequence ?? (params.legacy ? LEGACY_AUDIT_SEQUENCE_BASE : 0)) + 1;
if (!Number.isSafeInteger(next) || params.legacy && next >= 0) throw new Error(`Audit sequence exhausted for scope ${params.scope}`);
return next;
}
function pruneAuditRecords(params) {
const overflow = countAuditRecords(params.database, params.scope) - params.maxEntries;
if (overflow <= 0) return;
const protectedKey = params.protectedKey;
const baseCandidates = getAuditRecordKysely(params.database).selectFrom("diagnostic_events").select("event_key").where("scope", "=", params.scope);
const candidates = (protectedKey === void 0 ? baseCandidates : baseCandidates.where("event_key", "!=", protectedKey)).orderBy("sequence", "asc").limit(overflow);
executeSqliteQuerySync(params.database, getAuditRecordKysely(params.database).deleteFrom("diagnostic_events").where("scope", "=", params.scope).where("event_key", "in", candidates));
}
/** Opens one bounded audit-record scope in the shared state database. */
function createSqliteAuditRecordStore(options) {
const scope = options.scope;
const maxEntries = Math.max(1, Math.floor(options.maxEntries));
function prepareRecord(record) {
const payloadJson = JSON.stringify(record.value);
if (payloadJson === void 0) throw new Error(`Audit record ${scope}/${record.key} is not JSON-serializable`);
return {
event_key: record.key,
payload_json: payloadJson,
created_at: record.createdAt
};
}
function insertRecord(database, record) {
executeSqliteQuerySync(database, getAuditRecordKysely(database).insertInto("diagnostic_events").values({
scope,
event_key: record.event_key,
payload_json: record.payload_json,
created_at: record.created_at,
sequence: record.sequence
}).onConflict((conflict) => conflict.columns(["scope", "event_key"]).doNothing()));
}
function upsertPreparedRecord(database, record) {
executeSqliteQuerySync(database, getAuditRecordKysely(database).insertInto("diagnostic_events").values({
scope,
event_key: record.event_key,
payload_json: record.payload_json,
created_at: record.created_at,
sequence: nextAuditSequence({
database,
scope,
legacy: false
})
}).onConflict((conflict) => conflict.columns(["scope", "event_key"]).doUpdateSet({
payload_json: record.payload_json,
created_at: record.created_at
})));
pruneAuditRecords({
database,
scope,
maxEntries,
protectedKey: record.event_key
});
}
function deleteRecord(database, key) {
executeSqliteQuerySync(database, getAuditRecordKysely(database).deleteFrom("diagnostic_events").where("scope", "=", scope).where("event_key", "=", key));
}
return {
register(key, value, createdAt = Date.now()) {
const record = prepareRecord({
key,
value,
createdAt
});
runOpenClawStateWriteTransaction((database) => {
insertRecord(database.db, {
...record,
sequence: nextAuditSequence({
database: database.db,
scope,
legacy: false
})
});
pruneAuditRecords({
database: database.db,
scope,
maxEntries,
protectedKey: key
});
}, options);
},
upsert(key, value, createdAt = Date.now()) {
const record = prepareRecord({
key,
value,
createdAt
});
runOpenClawStateWriteTransaction((database) => {
upsertPreparedRecord(database.db, record);
}, options);
},
delete(key) {
runOpenClawStateWriteTransaction((database) => {
deleteRecord(database.db, key);
}, options);
},
compareAndSet(key, expectedValue, value, createdAt = Date.now()) {
const expectedPayloadJson = expectedValue === null ? null : JSON.stringify(expectedValue);
const record = value === null ? null : prepareRecord({
key,
value,
createdAt
});
let updated = false;
runOpenClawStateWriteTransaction((database) => {
if ((executeSqliteQueryTakeFirstSync(database.db, getAuditRecordKysely(database.db).selectFrom("diagnostic_events").select("payload_json").where("scope", "=", scope).where("event_key", "=", key))?.payload_json ?? null) !== expectedPayloadJson) return;
if (record) upsertPreparedRecord(database.db, record);
else deleteRecord(database.db, key);
updated = true;
}, options);
return updated;
},
registerLegacyMany(records) {
const prepared = records.map(prepareRecord);
if (prepared.length === 0) return;
runOpenClawStateWriteTransaction((database) => {
let sequence = nextAuditSequence({
database: database.db,
scope,
legacy: true
});
for (const record of prepared) {
insertRecord(database.db, {
...record,
sequence
});
sequence += 1;
}
pruneAuditRecords({
database: database.db,
scope,
maxEntries
});
}, options);
},
size() {
return countAuditRecords(openOpenClawStateDatabase(options).db, scope);
},
entries() {
const database = openOpenClawStateDatabase(options);
return executeSqliteQuerySync(database.db, getAuditRecordKysely(database.db).selectFrom("diagnostic_events").select([
"event_key",
"payload_json",
"created_at",
"sequence"
]).where("scope", "=", scope).orderBy("sequence", "asc")).rows.map((row) => {
const { sequence: _sequence, ...entry } = parseAuditRecord(row);
return entry;
});
},
latest(params) {
const limit = Math.max(0, Math.floor(params.limit));
if (limit === 0) return [];
const database = openOpenClawStateDatabase(options);
const baseQuery = getAuditRecordKysely(database.db).selectFrom("diagnostic_events").select([
"event_key",
"payload_json",
"created_at",
"sequence"
]).where("scope", "=", scope);
const query = params.beforeSequence === void 0 ? baseQuery : baseQuery.where("sequence", "<", params.beforeSequence);
return executeSqliteQuerySync(database.db, query.orderBy("sequence", "desc").limit(limit)).rows.map((row) => parseAuditRecord(row));
}
};
}
//#endregion
export { createSqliteAuditRecordStore as t };