manifest
Version:
Self-hosted Manifest LLM router with embedded server, SQLite database, and dashboard
156 lines • 7.37 kB
JavaScript
;
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __metadata = (this && this.__metadata) || function (k, v) {
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.NotificationRulesService = void 0;
const common_1 = require("@nestjs/common");
const typeorm_1 = require("typeorm");
const uuid_1 = require("uuid");
const sql_dialect_1 = require("../../common/utils/sql-dialect");
let NotificationRulesService = class NotificationRulesService {
ds;
dialect;
constructor(ds) {
this.ds = ds;
this.dialect = (0, sql_dialect_1.detectDialect)(ds.options.type);
}
sql(query) {
return (0, sql_dialect_1.portableSql)(query, this.dialect);
}
async listRules(userId, agentName) {
return this.ds.query(this.sql(`SELECT nr.*, COALESCE(nl.trigger_count, 0) AS trigger_count
FROM notification_rules nr
LEFT JOIN (
SELECT rule_id, COUNT(*) AS trigger_count
FROM notification_logs
WHERE rule_id IN (SELECT id FROM notification_rules WHERE user_id = $1 AND agent_name = $2)
GROUP BY rule_id
) nl ON nl.rule_id = nr.id
WHERE nr.user_id = $3 AND nr.agent_name = $4
ORDER BY nr.created_at DESC`), [userId, agentName, userId, agentName]);
}
async createRule(userId, dto) {
const agent = await this.resolveAgent(userId, dto.agent_name);
const id = (0, uuid_1.v4)();
const now = new Date().toISOString().replace('T', ' ').replace('Z', '').slice(0, 19);
await this.ds.query(this.sql(`INSERT INTO notification_rules
(id, tenant_id, agent_id, agent_name, user_id, metric_type, threshold, period, action, is_active, created_at, updated_at)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)`), [
id,
agent.tenant_id,
agent.id,
dto.agent_name,
userId,
dto.metric_type,
dto.threshold,
dto.period,
dto.action ?? 'notify',
this.dialect === 'sqlite' ? 1 : true,
now,
now,
]);
const rows = await this.ds.query(this.sql(`SELECT * FROM notification_rules WHERE id = $1`), [
id,
]);
return rows[0];
}
async updateRule(userId, ruleId, dto) {
await this.verifyOwnership(userId, ruleId);
const sets = [];
const params = [];
let paramIdx = 1;
if (dto.metric_type !== undefined) {
sets.push(`metric_type = $${paramIdx++}`);
params.push(dto.metric_type);
}
if (dto.threshold !== undefined) {
sets.push(`threshold = $${paramIdx++}`);
params.push(dto.threshold);
}
if (dto.period !== undefined) {
sets.push(`period = $${paramIdx++}`);
params.push(dto.period);
}
if (dto.action !== undefined) {
sets.push(`action = $${paramIdx++}`);
params.push(dto.action);
}
if (dto.is_active !== undefined) {
sets.push(`is_active = $${paramIdx++}`);
params.push(this.dialect === 'sqlite' ? (dto.is_active ? 1 : 0) : dto.is_active);
}
if (sets.length === 0)
return this.getRule(ruleId);
const now = new Date().toISOString().replace('T', ' ').replace('Z', '').slice(0, 19);
sets.push(`updated_at = $${paramIdx++}`);
params.push(now);
params.push(ruleId);
await this.ds.query(this.sql(`UPDATE notification_rules SET ${sets.join(', ')} WHERE id = $${paramIdx}`), params);
const rows = await this.ds.query(this.sql(`SELECT * FROM notification_rules WHERE id = $1`), [
ruleId,
]);
return rows[0];
}
async deleteRule(userId, ruleId) {
await this.verifyOwnership(userId, ruleId);
await this.ds.query(this.sql(`DELETE FROM notification_rules WHERE id = $1`), [ruleId]);
}
async getConsumption(tenantId, agentName, metric, periodStart, periodEnd) {
const expr = metric === 'tokens'
? 'COALESCE(SUM(input_tokens + output_tokens), 0)'
: 'COALESCE(SUM(cost_usd), 0)';
const rows = await this.ds.query(this.sql(`SELECT ${expr} as total FROM agent_messages
WHERE tenant_id = $1 AND agent_name = $2
AND timestamp >= $3 AND timestamp < $4`), [tenantId, agentName, periodStart, periodEnd]);
return Number(rows[0]?.total ?? 0);
}
async getAllActiveRules() {
return this.ds.query(this.sql(`SELECT * FROM notification_rules WHERE is_active = $1 AND action IN ($2, $3)`), [this.dialect === 'sqlite' ? 1 : true, 'notify', 'both']);
}
async getActiveRulesForUser(userId) {
return this.ds.query(this.sql(`SELECT * FROM notification_rules WHERE user_id = $1 AND is_active = $2 AND action IN ($3, $4)`), [userId, this.dialect === 'sqlite' ? 1 : true, 'notify', 'both']);
}
async getActiveBlockRules(tenantId, agentName) {
return this.ds.query(this.sql(`SELECT * FROM notification_rules
WHERE tenant_id = $1 AND agent_name = $2
AND is_active = $3 AND action IN ($4, $5)`), [tenantId, agentName, this.dialect === 'sqlite' ? 1 : true, 'block', 'both']);
}
async resolveAgent(userId, agentName) {
const rows = await this.ds.query(this.sql(`SELECT a.id, a.tenant_id FROM agents a
JOIN tenants t ON t.id = a.tenant_id
WHERE t.name = $1 AND a.name = $2`), [userId, agentName]);
if (!rows.length) {
throw new common_1.BadRequestException(`Agent "${agentName}" not found`);
}
return rows[0];
}
async verifyOwnership(userId, ruleId) {
const rows = await this.ds.query(this.sql(`SELECT id FROM notification_rules WHERE id = $1 AND user_id = $2`), [ruleId, userId]);
if (!rows.length) {
throw new common_1.NotFoundException('Notification rule not found');
}
}
async getRule(ruleId) {
const rows = await this.ds.query(this.sql(`SELECT * FROM notification_rules WHERE id = $1`), [
ruleId,
]);
return rows[0];
}
async getOwnedRule(userId, ruleId) {
const rows = await this.ds.query(this.sql(`SELECT * FROM notification_rules WHERE id = $1 AND user_id = $2`), [ruleId, userId]);
return rows[0];
}
};
exports.NotificationRulesService = NotificationRulesService;
exports.NotificationRulesService = NotificationRulesService = __decorate([
(0, common_1.Injectable)(),
__metadata("design:paramtypes", [typeorm_1.DataSource])
], NotificationRulesService);
//# sourceMappingURL=notification-rules.service.js.map