@hashgraphonline/conversational-agent
Version:
Hashgraph Online conversational AI agent implementing HCS-10 communication, HCS-2 registries, and content inscription on Hedera. https://hol.org
158 lines (157 loc) • 4.79 kB
JavaScript
import { EntityFormat } from "./index27.js";
import { Logger, HederaMirrorNode } from "@hashgraphonline/standards-sdk";
class FormatConverterRegistry {
constructor() {
this.converters = /* @__PURE__ */ new Map();
this.entityTypeCache = /* @__PURE__ */ new Map();
this.logger = new Logger({ module: "FormatConverterRegistry" });
this.defaultCacheTTL = 5 * 60 * 1e3;
}
/**
* Register a format converter
*/
register(converter) {
const key = `${converter.sourceFormat}→${converter.targetFormat}`;
this.converters.set(key, converter);
}
/**
* Find a converter for the given source and target formats
*/
findConverter(source, target) {
const key = `${source}→${target}`;
return this.converters.get(key) || null;
}
/**
* Convert an entity to the target format
*/
async convertEntity(entity, target, context) {
const sourceFormat = await this.detectFormatWithFallback(entity, context);
if (sourceFormat === target) {
return entity;
}
const converter = this.findConverter(sourceFormat, target);
if (!converter) {
throw new Error(`No converter found for ${sourceFormat} → ${target}`);
}
if (!converter.canConvert(entity, context)) {
throw new Error(`Converter cannot handle entity: ${entity}`);
}
const result = await converter.convert(entity, context);
return result;
}
/**
* Detect the format of an entity string with API-based verification and fallback
*/
async detectFormatWithFallback(entity, context) {
if (entity.startsWith("hcs://")) {
return EntityFormat.HRL;
}
if (/^0\.0\.\d+$/.test(entity)) {
const cached = this.getCachedFormat(entity);
if (cached) {
return cached;
}
try {
const detected = await this.detectFormat(entity, context || {});
if (detected !== EntityFormat.ANY) {
this.setCachedFormat(entity, detected);
return detected;
}
} catch (error) {
this.logger.warn(
`Entity detection failed for ${entity}, using fallback: ${error.message}`
);
}
return EntityFormat.ANY;
}
return EntityFormat.ANY;
}
/**
* Public helper: detect entity format (ACCOUNT_ID, TOKEN_ID, TOPIC_ID, HRL, or ANY)
*/
async detectEntityFormat(entity, context) {
return this.detectFormatWithFallback(entity, context);
}
/**
* Detect entity format via Hedera Mirror Node API calls
*/
async detectFormat(entity, context) {
const networkType = context.networkType || "testnet";
const mirrorNode = new HederaMirrorNode(networkType, this.logger);
mirrorNode.configureRetry({
maxRetries: 3,
maxDelayMs: 1e3
});
const checks = await Promise.allSettled([
mirrorNode.getAccountBalance(entity).then((result) => result !== null ? EntityFormat.ACCOUNT_ID : null).catch(() => null),
mirrorNode.getTokenInfo(entity).then((result) => result !== null ? EntityFormat.TOKEN_ID : null).catch(() => null),
mirrorNode.getTopicInfo(entity).then((result) => result !== null ? EntityFormat.TOPIC_ID : null).catch(() => null),
mirrorNode.getContract(entity).then((result) => result !== null ? EntityFormat.CONTRACT_ID : null).catch(() => null)
]);
const successful = checks.find(
(result) => result.status === "fulfilled" && result.value !== null
);
return successful && successful.status === "fulfilled" ? successful.value : EntityFormat.ANY;
}
/**
* Get cached entity format if valid
*/
getCachedFormat(entity) {
const entry = this.entityTypeCache.get(entity);
if (!entry || this.isCacheExpired(entry)) {
this.entityTypeCache.delete(entity);
return null;
}
return entry.format;
}
/**
* Set cached entity format
*/
setCachedFormat(entity, format) {
this.entityTypeCache.set(entity, {
format,
timestamp: Date.now(),
ttl: this.defaultCacheTTL
});
}
/**
* Check if cache entry is expired
*/
isCacheExpired(entry) {
return Date.now() - entry.timestamp > entry.ttl;
}
/**
* Get all registered converters
*/
getRegisteredConverters() {
return Array.from(this.converters.keys()).map((key) => {
const [source, target] = key.split("→");
return {
source,
target
};
});
}
/**
* Check if a converter exists for the given formats
*/
hasConverter(source, target) {
return this.findConverter(source, target) !== null;
}
/**
* Clear all registered converters
*/
clear() {
this.converters.clear();
}
/**
* Clear entity type cache
*/
clearCache() {
this.entityTypeCache.clear();
}
}
export {
FormatConverterRegistry
};
//# sourceMappingURL=index26.js.map