@openade/pel
Version:
Punto di Elaborazione (Elaboration Point) - Server library for managing PEMs and communicating with ADE
131 lines • 5.22 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.AnomalyManager = exports.AnomalyType = void 0;
var AnomalyType;
(function (AnomalyType) {
AnomalyType["CONNECTION_ERROR"] = "ERR_CONN";
AnomalyType["PEM_BLOCKED"] = "ERR_BLOCK";
AnomalyType["INTEGRITY_ERROR"] = "ERR_INTEG";
AnomalyType["VALIDATION_ERROR"] = "ERR_VALID";
AnomalyType["MISSING_JOURNAL"] = "ERR_MISS_J";
AnomalyType["MISSING_DOCUMENTS"] = "ERR_MISS_DC";
})(AnomalyType || (exports.AnomalyType = AnomalyType = {}));
class AnomalyManager {
constructor(config) {
this.pendingAnomalies = new Map();
this.config = {
autoTransmit: true,
batchSize: 10,
...config,
};
}
async reportAnomaly(anomaly) {
const anomalyId = this.generateAnomalyId(anomaly);
console.warn('Anomaly reported:', {
id: anomalyId,
type: anomaly.type,
pemId: anomaly.pemId,
details: anomaly.details,
});
const path = `anomalies/${anomaly.pemId}/${anomaly.timestamp.replace(/[:.]/g, '-')}.json`;
await this.config.storage.store(path, new TextEncoder().encode(JSON.stringify(anomaly, null, 2)));
this.pendingAnomalies.set(anomalyId, anomaly);
if (this.config.autoTransmit && this.config.adeClient) {
await this.transmitPendingAnomalies();
}
}
async reportConnectionError(taxpayerFiscalCode, pemId, pemLocation, startedAt, operationsWithoutNetwork, networkRestoredAt) {
await this.reportAnomaly({
type: AnomalyType.CONNECTION_ERROR,
taxpayerFiscalCode,
pemId,
pemLocation,
details: `PEM-PEL connection failure. ${operationsWithoutNetwork} operations registered without network.`,
timestamp: new Date().toISOString(),
startedAt,
resolvedAt: networkRestoredAt,
metadata: {
operationsWithoutNetwork,
networkRestoredAt,
},
});
}
async reportPEMBlocked(taxpayerFiscalCode, pemId, pemLocation, blockedAt, operationsCount) {
await this.reportAnomaly({
type: AnomalyType.PEM_BLOCKED,
taxpayerFiscalCode,
pemId,
pemLocation,
details: `PEM blocked due to transmission threshold exceeded. ${operationsCount} operations not transmitted.`,
timestamp: blockedAt,
startedAt: blockedAt,
metadata: {
operationsWithoutNetwork: operationsCount,
},
});
}
async reportIntegrityError(taxpayerFiscalCode, pemId, pemLocation, expectedHash, actualHash, details) {
await this.reportAnomaly({
type: AnomalyType.INTEGRITY_ERROR,
taxpayerFiscalCode,
pemId,
pemLocation,
details: `Hash chain integrity error: ${details}`,
timestamp: new Date().toISOString(),
metadata: {
expectedHash,
actualHash,
},
});
}
async transmitPendingAnomalies() {
if (this.pendingAnomalies.size === 0) {
return;
}
if (!this.config.adeClient) {
console.warn('ADE client not configured, cannot transmit anomalies');
return;
}
const anomalies = Array.from(this.pendingAnomalies.values());
const batchSize = this.config.batchSize || 10;
console.log(`Transmitting ${anomalies.length} anomalies to ADE...`);
for (let i = 0; i < anomalies.length; i += batchSize) {
const batch = anomalies.slice(i, i + batchSize);
try {
const result = await this.config.adeClient.trasmissioneAnomalie(batch);
console.log(`✓ Transmitted batch ${Math.floor(i / batchSize) + 1} (${batch.length} anomalies) - ${result.success ? 'SUCCESS' : 'FAILED'}`);
for (const anomaly of batch) {
const id = this.generateAnomalyId(anomaly);
this.pendingAnomalies.delete(id);
}
}
catch (error) {
console.error(`Error transmitting anomaly batch:`, error);
}
}
console.log(`Anomaly transmission complete. ${this.pendingAnomalies.size} remaining in queue.`);
}
getPendingCount() {
return this.pendingAnomalies.size;
}
getPendingAnomalies() {
return Array.from(this.pendingAnomalies.values());
}
clearResolved() {
const before = this.pendingAnomalies.size;
for (const [id, anomaly] of this.pendingAnomalies.entries()) {
if (anomaly.resolvedAt) {
this.pendingAnomalies.delete(id);
}
}
const cleared = before - this.pendingAnomalies.size;
if (cleared > 0) {
console.log(`Cleared ${cleared} resolved anomalies`);
}
}
generateAnomalyId(anomaly) {
return `${anomaly.type}_${anomaly.pemId}_${anomaly.timestamp}`;
}
}
exports.AnomalyManager = AnomalyManager;
//# sourceMappingURL=anomaly.manager.js.map