"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.VDXF_KEYS = exports.PARENT_KEYS = exports.MULTIMAPREMOVE_KEY = exports.DATA_DESCRIPTOR_KEY = void 0;
exports.makeSubDD = makeSubDD;
exports.encodeVdxfValue = encodeVdxfValue;
exports.decodeVdxfValue = decodeVdxfValue;
exports.getCanonicalVdxfDefinitionCount = getCanonicalVdxfDefinitionCount;
exports.buildAgentContentMultimap = buildAgentContentMultimap;
exports.decodeContentMultimap = decodeContentMultimap;
exports.buildCanonicalAgentUpdate = buildCanonicalAgentUpdate;
exports.verifyPublishedIdentity = verifyPublishedIdentity;
exports.buildUpdateIdentityPayload = buildUpdateIdentityPayload;
exports.buildUpdateIdentityCommand = buildUpdateIdentityCommand;
exports.buildJobCompletionAdditions = buildJobCompletionAdditions;
exports.mergeContentMultimap = mergeContentMultimap;
exports.buildContentMultimapRemove = buildContentMultimapRemove;
exports.removeAndRewriteVdxfFields = removeAndRewriteVdxfFields;
// --- Constants ---
exports.DATA_DESCRIPTOR_KEY = 'i4GC1YGEVD21afWudGoFJVdnfjJ5XWnCQv';
exports.MULTIMAPREMOVE_KEY = 'i5Zkx5Z7tEfh42xtKfwbJ5LgEWE9rEgpFY'; // vrsc::identity.multimapremove
/**
 * @deprecated Parent group keys removed in 25-key flat format (2026-03-28).
 * Kept ONLY for backwards-compatible reading of old on-chain data.
 * Do NOT use for new writes — use flat VDXF_KEYS directly.
 */
exports.PARENT_KEYS = {
    agent: 'i8XMutgp1MRNoFoHQuzZ4ReowJd9NvCgDP', // agentplatform::agent
    service: 'i8pfR86vr8qbTPHbhmNQFJo8MYSWKv2TZD', // agentplatform::svc
    review: 'iMTQf3r1icnRfKLNtr5eByLKXZfsSzUt5f', // agentplatform::review
    session: 'iGxK7ke8RptD2mkhmUgjMASFysopezAT4n', // agentplatform::session
    platform: 'iMc951yUdCup5rFgZb8nwDFhkdd8Fktg2a', // agentplatform::platform
    bounty: 'i5L3iHEG4sFm4Lp5HSN1NLLxKQUfFaoU8S', // agentplatform::bounty
    workspace: 'iEibMMaoeMGjoSLSY61wSPB8Qy5rXnXjAk', // agentplatform::workspace
    job: 'iC6GEa5mq15EBatbHiwVtd53QHb8HiEDnT', // agentplatform::job
};
/**
 * 25 flat VDXF keys — each is its own top-level contentmultimap entry.
 * No parent group wrapping. Values wrapped via makeSubDD().
 */
exports.VDXF_KEYS = {
    // 15 agent keys
    agent: {
        displayName: 'iKkdwxhdupLgf7v2qn4JGBQHntsBb17kjW', // agentplatform::agent.displayname
        type: 'iNxeLSDFARVQezfEt4i8CBZjTSRpFTPAyP', // agentplatform::agent.type
        description: 'iQr3yKEn2DXaG4GQGVAVYivC3jwcvScfzk', // agentplatform::agent.description
        status: 'iLy373iaKafmRCY43ahty4m8aLQx32y8Fh', // agentplatform::agent.status
        payAddress: 'iRxxUvbDXJT5wVpnx7oc9nkYALCoDh6aTD', // agentplatform::agent.payaddress
        services: 'i8Wk7fcbsBWtcf965Z3WvDUjahF1aTH1tu', // agentplatform::agent.services
        models: 'iQJUQmdFSmM49cvLJfKLZnuRYsjXSmTTHY', // agentplatform::agent.models
        markup: 'iBLx3rga8DewiN6gyQyC5avFin8fnnojnS', // agentplatform::agent.markup
        networkCapabilities: 'iF7174LxgcAnu3qZ7iJzSyJYthDJXBzQNw', // agentplatform::agent.network.capabilities
        networkEndpoints: 'i5VzGsiFmJYuRr7b8aUyHzAS8vd9DC4puS', // agentplatform::agent.network.endpoints
        networkProtocols: 'iSAVTXMb9TyWWuDDnWopFhgZpjm21WPigv', // agentplatform::agent.network.protocols
        profileTags: 'iKM57qfzmgM1sxBgR3XBQa2XCRURZ2YVo2', // agentplatform::agent.profile.tags
        profileWebsite: 'i7HY93tqfqCkpyKYiNtcDbioAgF8gRL9TQ', // agentplatform::agent.profile.website
        profileAvatar: 'iALo91Z75iXZxMvymvQMRwo7GAeHv5veKc', // agentplatform::agent.profile.avatar
        profileCategory: 'iD3quozCGbzJyZ29uvRCeecr12np2dMsvN', // agentplatform::agent.profile.category
        disputePolicy: 'iFxerhcrMr2e5eWyvHiXuWHXj2dnhEZF8p', // agentplatform::agent.disputepolicy (was svc.dispute)
    },
    // 1 service schema key (on agentplatform@ only — agents don't write these)
    service: {
        schema: 'i4D2ifpAG7BYnfJZGVT1Tph7BMkp9qZPyS', // agentplatform::svc.schema
    },
    // 1 review key
    review: {
        record: 'iLbUN8TFvMZR9uaZYY1qBmL99bJE2uYdad', // agentplatform::review.record
    },
    // 2 bounty keys (schema only)
    bounty: {
        record: 'i6PC1B9vgVf8bLtHcdsNunLtr6ibtnL7ZC', // agentplatform::bounty.record
        application: 'iE8Z7gZmAs4NU8AqEJzV9MWHUCoUBQqfum', // agentplatform::bounty.application
    },
    // 1 platform key (on agentplatform@ only)
    platform: {
        config: 'iMs3n1aCWQh5rmkXCNLRi8WqbzZrq3F7Ye', // agentplatform::platform.config
    },
    // 1 session key
    session: {
        params: 'iHjLTt9P8Jb1uCYSpVpwXFbwzbPYWW4n8p', // agentplatform::session.params
    },
    // 2 workspace keys
    workspace: {
        attestation: 'i8xp9AgvueoAHyYXbxNACMgRQfEXF82V5D', // agentplatform::workspace.attestation
        capability: 'iMxAXRfTWUkKBmLGEZtEJbKj58kDi1GjZ9', // agentplatform::workspace.capability
    },
    // 1 job key
    job: {
        record: 'iPsXc7vcBzAxyjFYfPAs9PUtMLh1EJPHSn', // agentplatform::job.record
    },
};
// Legacy agent keys removed in 25-key migration (for backwards-compat decoding)
const LEGACY_AGENT_KEYS = {
    'iEEqjQsh5YDrwMyxyTrHFrMHTqrsPziCqu': 'owner', // agent.owner — REMOVED
    'iJ15GBkMfyMxvEf7wivLKbXRjpqS119QrM': 'network', // agent.network — REMOVED (split into 3)
    'iAFyowB5a3W5BLEv6tE7EPHAmGhaYcGJCt': 'profile', // agent.profile — REMOVED (split into 4)
};
// --- Reverse lookups ---
const REVERSE_LOOKUPS = {};
for (const [group, keys] of Object.entries(exports.VDXF_KEYS)) {
    REVERSE_LOOKUPS[group] = Object.fromEntries(Object.entries(keys).map(([k, v]) => [v, k]));
}
// Build legacy agent reverse lookup (current keys + removed keys)
const LEGACY_AGENT_REVERSE = {
    ...REVERSE_LOOKUPS['agent'],
    ...LEGACY_AGENT_KEYS,
};
// Global flat reverse: i-address → field name (across all groups)
const ALL_KEYS_FLAT = {};
for (const [, keys] of Object.entries(exports.VDXF_KEYS)) {
    for (const [field, iAddr] of Object.entries(keys)) {
        ALL_KEYS_FLAT[iAddr] = field;
    }
}
function getReverseLookup(type) {
    return REVERSE_LOOKUPS[type] || {};
}
// --- DataDescriptor helpers ---
/**
 * Build a sub-DataDescriptor (text/plain, flags=96).
 * Label is the field i-address, value is stored as objectdata.message.
 */
function makeSubDD(label, value) {
    return {
        [exports.DATA_DESCRIPTOR_KEY]: {
            version: 1,
            flags: 96,
            mimetype: 'text/plain',
            objectdata: { message: value },
            label,
        },
    };
}
/**
 * Parse a sub-DD to extract label + value.
 */
function parseSubDD(entry) {
    if (typeof entry !== 'object' || entry === null)
        return null;
    const dd = entry[exports.DATA_DESCRIPTOR_KEY];
    if (!dd)
        return null;
    const label = dd.label || '';
    if (dd.objectdata === null)
        return null; // deleted entry
    if (typeof dd.objectdata === 'object' && dd.objectdata !== null && 'message' in dd.objectdata) {
        return { label, value: dd.objectdata.message };
    }
    if (typeof dd.objectdata === 'string') {
        try {
            return { label, value: JSON.parse(Buffer.from(dd.objectdata, 'hex').toString('utf-8')) };
        }
        catch {
            return { label, value: dd.objectdata };
        }
    }
    return { label, value: dd.objectdata };
}
/**
 * Parse an outer DD (legacy nested pattern — objectdata is an array of sub-DDs).
 * Returns a map of resolved field names -> values.
 */
function parseOuterDD(entry, reverseLookup) {
    if (typeof entry !== 'object' || entry === null)
        return null;
    const dd = entry[exports.DATA_DESCRIPTOR_KEY];
    if (!dd)
        return null;
    if (!Array.isArray(dd.objectdata))
        return null;
    const record = {};
    for (const subEntry of dd.objectdata) {
        const sub = parseSubDD(subEntry);
        if (!sub || !sub.label)
            continue;
        const fieldName = reverseLookup[sub.label] || sub.label;
        record[fieldName] = sub.value;
    }
    return record;
}
// --- Legacy helpers (kept for backwards compat during transition) ---
function encodeVdxfValue(value) {
    return Buffer.from(JSON.stringify(value), 'utf8').toString('hex');
}
function decodeVdxfValue(hex) {
    try {
        return JSON.parse(Buffer.from(hex, 'hex').toString('utf8'));
    }
    catch (e) {
        console.warn(`[VDXF] decodeVdxfValue: JSON parse failed, returning raw string. Error: ${e.message}`);
        return Buffer.from(hex, 'hex').toString('utf8');
    }
}
function getCanonicalVdxfDefinitionCount() {
    return Object.values(exports.VDXF_KEYS).reduce((n, group) => n + Object.keys(group).length, 0);
}
// --- Service serialization helper (DRY) ---
function serializeServiceArray(services) {
    return services.map(svc => {
        const obj = { name: svc.name, status: svc.status || 'active' };
        if (svc.description)
            obj.description = svc.description;
        if (svc.category)
            obj.category = svc.category;
        const pricing = [];
        if (svc.price != null && svc.currency) {
            pricing.push({ currency: svc.currency, amount: String(svc.price) });
        }
        if (svc.acceptedCurrencies?.length) {
            for (const ac of svc.acceptedCurrencies) {
                pricing.push({ currency: ac.currency, amount: String(ac.price) });
            }
        }
        if (pricing.length)
            obj.pricing = pricing;
        if (svc.turnaround)
            obj.turnaround = svc.turnaround;
        if (svc.paymentTerms)
            obj.paymentTerms = svc.paymentTerms;
        if (svc.privateMode != null)
            obj.privateMode = svc.privateMode;
        if (svc.sovguard != null)
            obj.sovguard = svc.sovguard;
        if (svc.resolutionWindow != null)
            obj.resolutionWindow = svc.resolutionWindow;
        if (svc.refundPolicy)
            obj.refundPolicy = svc.refundPolicy;
        if (svc.costBreakdown)
            obj.costBreakdown = svc.costBreakdown;
        return obj;
    });
}
// --- Build flat contentmultimap (25-key format) ---
/**
 * Build a flat contentmultimap for an agent profile + services.
 * Each field is its own top-level key wrapped in makeSubDD().
 *
 * Network fields → 3 separate keys (capabilities, endpoints, protocols).
 * Profile fields → 4 separate keys (tags, website, avatar, category).
 * No parent key wrapping.
 */
function buildAgentContentMultimap(profile, services = [], disputePolicy) {
    const cmm = {};
    const K = exports.VDXF_KEYS.agent;
    if (profile) {
        // Core agent fields
        cmm[K.displayName] = [makeSubDD(K.displayName, profile.name)];
        cmm[K.type] = [makeSubDD(K.type, profile.type)];
        cmm[K.description] = [makeSubDD(K.description, profile.description)];
        cmm[K.status] = [makeSubDD(K.status, 'active')];
        if (profile.payAddress) {
            cmm[K.payAddress] = [makeSubDD(K.payAddress, profile.payAddress)];
        }
        // Services as JSON array
        if (services.length > 0) {
            cmm[K.services] = [makeSubDD(K.services, JSON.stringify(serializeServiceArray(services)))];
        }
        // Network fields → 3 individual flat keys
        if (profile.network) {
            if (profile.network.capabilities?.length) {
                cmm[K.networkCapabilities] = [makeSubDD(K.networkCapabilities, JSON.stringify(profile.network.capabilities))];
            }
            if (profile.network.endpoints?.length) {
                cmm[K.networkEndpoints] = [makeSubDD(K.networkEndpoints, JSON.stringify(profile.network.endpoints))];
            }
            if (profile.network.protocols?.length) {
                cmm[K.networkProtocols] = [makeSubDD(K.networkProtocols, JSON.stringify(profile.network.protocols))];
            }
        }
        // Profile fields → 4 individual flat keys
        if (profile.profile) {
            if (profile.profile.tags?.length) {
                cmm[K.profileTags] = [makeSubDD(K.profileTags, JSON.stringify(profile.profile.tags))];
            }
            if (profile.profile.website) {
                cmm[K.profileWebsite] = [makeSubDD(K.profileWebsite, profile.profile.website)];
            }
            if (profile.profile.avatar) {
                cmm[K.profileAvatar] = [makeSubDD(K.profileAvatar, profile.profile.avatar)];
            }
            if (profile.profile.category) {
                cmm[K.profileCategory] = [makeSubDD(K.profileCategory, profile.profile.category)];
            }
        }
        // LLM models → agent.models (JSON array)
        if (profile.models?.length) {
            cmm[K.models] = [makeSubDD(K.models, JSON.stringify(profile.models))];
        }
        // Pricing markup → agent.markup
        if (profile.markup != null && profile.markup >= 1 && profile.markup <= 50) {
            cmm[K.markup] = [makeSubDD(K.markup, String(profile.markup))];
        }
        // Session params → session.params (JSON object)
        if (profile.session && Object.keys(profile.session).length > 0) {
            cmm[exports.VDXF_KEYS.session.params] = [makeSubDD(exports.VDXF_KEYS.session.params, JSON.stringify(profile.session))];
        }
        // Platform config → platform.config (JSON object)
        if (profile.platformConfig && Object.keys(profile.platformConfig).length > 0) {
            cmm[exports.VDXF_KEYS.platform.config] = [makeSubDD(exports.VDXF_KEYS.platform.config, JSON.stringify(profile.platformConfig))];
        }
        // Workspace capability → workspace.capability (JSON object)
        if (profile.workspaceCapability) {
            cmm[exports.VDXF_KEYS.workspace.capability] = [makeSubDD(exports.VDXF_KEYS.workspace.capability, JSON.stringify(profile.workspaceCapability))];
        }
        // Dispute policy → agent.disputePolicy (JSON object)
        if (disputePolicy) {
            cmm[K.disputePolicy] = [makeSubDD(K.disputePolicy, JSON.stringify(disputePolicy))];
        }
    }
    else if (services.length > 0) {
        // Services-only (no profile)
        cmm[K.services] = [makeSubDD(K.services, JSON.stringify(serializeServiceArray(services)))];
    }
    return cmm;
}
// --- Decode contentmultimap (supports both flat + legacy formats) ---
/**
 * Detect whether a contentmultimap uses the legacy parent-keyed format.
 * Only triggers if the agent parent key is present (the main profile container).
 * Stray legacy keys (e.g. review parent from pre-migration) don't trigger legacy mode.
 */
function isLegacyFormat(cmm) {
    return !!cmm[exports.PARENT_KEYS.agent];
}
/**
 * Decode a flat-format contentmultimap entry: parse the sub-DD value.
 */
function parseFlatEntry(entries) {
    if (!entries?.length)
        return null;
    // Take the LAST entry (updateidentity appends, latest wins)
    const sub = parseSubDD(entries[entries.length - 1]);
    return sub?.value ?? null;
}
/**
 * Try to parse a string value as JSON, return original if not JSON.
 */
function tryParseJson(val) {
    if (typeof val !== 'string')
        return val;
    try {
        return JSON.parse(val);
    }
    catch {
        return val;
    }
}
/**
 * Decode services from a JSON array value.
 */
// ── On-chain value validation ──
// VDXF/contentmultimap data is published by arbitrary identities and is fully
// attacker-controllable. Validate every decoded value that flows into a
// financial or address sink so a malicious publisher cannot inject NaN /
// negative / Infinity / huge numbers (→ free usage, credit injection, meter
// corruption) or a bogus payout address.
const VDXF_MAX_SERVICES = 100;
const VDXF_MAX_PRICE = 1e9; // VRSC sanity ceiling
const VDXF_MAX_NUMBER = 1e12; // generic non-negative ceiling (limits/windows)
/** A finite number within [min, max], or undefined if the input is unusable. */
function safeNumber(v, min, max) {
    const n = typeof v === 'number' ? v : Number(v);
    if (!Number.isFinite(n) || n < min || n > max)
        return undefined;
    return n;
}
/** Validate a Verus R-address or i-address (base58check shape). */
function isVerusAddress(s) {
    return typeof s === 'string' && /^[Ri][1-9A-HJ-NP-Za-km-z]{25,40}$/.test(s);
}
function decodeServicesArray(raw) {
    const parsed = typeof raw === 'string'
        ? JSON.parse(raw) : raw;
    // Cap the array length to bound allocation/CPU from a hostile on-chain blob.
    const svcArr = Array.isArray(parsed) ? parsed.slice(0, VDXF_MAX_SERVICES) : [];
    const services = [];
    for (const svc of svcArr) {
        if (!svc.name)
            continue;
        let price;
        let currency;
        let acceptedCurrencies;
        if (svc.pricing && Array.isArray(svc.pricing)) {
            const pricingArr = svc.pricing.slice(0, 50);
            if (pricingArr.length > 0) {
                price = safeNumber(pricingArr[0].amount ?? pricingArr[0].price, 0, VDXF_MAX_PRICE);
                currency = pricingArr[0].currency;
            }
            if (pricingArr.length > 1) {
                acceptedCurrencies = pricingArr.slice(1)
                    .map(p => ({ currency: p.currency, price: safeNumber(p.amount ?? p.price, 0, VDXF_MAX_PRICE) }))
                    .filter((e) => e.price !== undefined);
            }
        }
        const svcInput = {
            name: svc.name,
            description: svc.description,
            category: svc.category,
            price,
            currency,
            turnaround: svc.turnaround,
            paymentTerms: svc.paymentTerms,
            privateMode: svc.privateMode != null ? svc.privateMode === true || svc.privateMode === 'true' : undefined,
            sovguard: svc.sovguard != null ? svc.sovguard === true || svc.sovguard === 'true' : undefined,
            status: svc.status,
        };
        if (acceptedCurrencies)
            svcInput.acceptedCurrencies = acceptedCurrencies;
        if (svc.resolutionWindow != null) {
            const rw = safeNumber(svc.resolutionWindow, 0, VDXF_MAX_NUMBER);
            if (rw !== undefined)
                svcInput.resolutionWindow = rw;
        }
        if (svc.refundPolicy) {
            svcInput.refundPolicy = typeof svc.refundPolicy === 'string'
                ? JSON.parse(svc.refundPolicy)
                : svc.refundPolicy;
        }
        if (svc.costBreakdown) {
            svcInput.costBreakdown = typeof svc.costBreakdown === 'string'
                ? JSON.parse(svc.costBreakdown)
                : svc.costBreakdown;
        }
        services.push(svcInput);
    }
    return services;
}
/**
 * Decode a contentmultimap back into AgentProfileInput + services.
 * Supports BOTH the new 25-key flat format and the legacy parent-keyed format.
 */
function decodeContentMultimap(cmm) {
    if (isLegacyFormat(cmm)) {
        return decodeLegacyContentMultimap(cmm);
    }
    return decodeFlatContentMultimap(cmm);
}
/**
 * Decode new 25-key flat format.
 */
function decodeFlatContentMultimap(cmm) {
    const profile = {};
    const services = [];
    const K = exports.VDXF_KEYS.agent;
    // Core agent fields
    const name = parseFlatEntry(cmm[K.displayName]);
    if (name)
        profile.name = name;
    const type = parseFlatEntry(cmm[K.type]);
    if (type)
        profile.type = type;
    const desc = parseFlatEntry(cmm[K.description]);
    if (desc)
        profile.description = desc;
    const payAddr = parseFlatEntry(cmm[K.payAddress]);
    // Only accept a well-formed R-/i-address — never a bogus on-chain payout target.
    if (isVerusAddress(payAddr))
        profile.payAddress = payAddr;
    // Services
    const svcRaw = parseFlatEntry(cmm[K.services]);
    if (svcRaw) {
        services.push(...decodeServicesArray(svcRaw));
    }
    // Network (3 individual keys → NetworkInput)
    const network = {};
    const caps = parseFlatEntry(cmm[K.networkCapabilities]);
    if (caps)
        network.capabilities = tryParseJson(caps);
    const eps = parseFlatEntry(cmm[K.networkEndpoints]);
    if (eps)
        network.endpoints = tryParseJson(eps);
    const protos = parseFlatEntry(cmm[K.networkProtocols]);
    if (protos)
        network.protocols = tryParseJson(protos);
    if (Object.keys(network).length > 0)
        profile.network = network;
    // Profile (4 individual keys → ProfileInput)
    const profileBlob = {};
    const tags = parseFlatEntry(cmm[K.profileTags]);
    if (tags)
        profileBlob.tags = tryParseJson(tags);
    const website = parseFlatEntry(cmm[K.profileWebsite]);
    if (website)
        profileBlob.website = website;
    const avatar = parseFlatEntry(cmm[K.profileAvatar]);
    if (avatar)
        profileBlob.avatar = avatar;
    const category = parseFlatEntry(cmm[K.profileCategory]);
    if (category)
        profileBlob.category = category;
    if (Object.keys(profileBlob).length > 0)
        profile.profile = profileBlob;
    // Models
    const models = parseFlatEntry(cmm[K.models]);
    if (models) {
        const parsed = tryParseJson(models);
        if (Array.isArray(parsed))
            profile.models = parsed;
    }
    // Markup
    const markup = parseFlatEntry(cmm[K.markup]);
    if (markup != null) {
        const m = safeNumber(markup, 1, 50); // mirror the build-side 1..50 clamp
        if (m !== undefined)
            profile.markup = m;
    }
    // Dispute policy
    const disputeRaw = parseFlatEntry(cmm[K.disputePolicy]);
    let disputePolicy;
    if (disputeRaw) {
        disputePolicy = tryParseJson(disputeRaw);
    }
    // Session params
    const sessionRaw = parseFlatEntry(cmm[exports.VDXF_KEYS.session.params]);
    if (sessionRaw) {
        const parsed = tryParseJson(sessionRaw);
        if (typeof parsed === 'object' && parsed !== null) {
            profile.session = parsed;
        }
    }
    // Platform config
    const platformRaw = parseFlatEntry(cmm[exports.VDXF_KEYS.platform.config]);
    if (platformRaw) {
        const parsed = tryParseJson(platformRaw);
        if (typeof parsed === 'object' && parsed !== null) {
            profile.platformConfig = parsed;
        }
    }
    // Workspace capability
    const wsRaw = parseFlatEntry(cmm[exports.VDXF_KEYS.workspace.capability]);
    if (wsRaw) {
        const parsed = tryParseJson(wsRaw);
        if (typeof parsed === 'object' && parsed !== null) {
            profile.workspaceCapability = parsed;
        }
    }
    return { profile: profile, services, disputePolicy };
}
/**
 * Decode legacy parent-keyed contentmultimap (pre-migration on-chain data).
 */
function decodeLegacyContentMultimap(cmm) {
    const profile = {};
    const session = {};
    const services = [];
    // --- Agent data (legacy parent key) ---
    const agentEntries = cmm[exports.PARENT_KEYS.agent];
    if (agentEntries?.length) {
        const agentData = parseOuterDD(agentEntries[agentEntries.length - 1], LEGACY_AGENT_REVERSE);
        if (agentData) {
            if (agentData.displayName)
                profile.name = agentData.displayName;
            if (agentData.type)
                profile.type = agentData.type;
            if (agentData.description)
                profile.description = agentData.description;
            // agent.owner mapped to payAddress for migration (validate the address)
            if (isVerusAddress(agentData.owner))
                profile.payAddress = agentData.owner;
            // Decode legacy consolidated network blob
            if (agentData.network) {
                const net = typeof agentData.network === 'string'
                    ? JSON.parse(agentData.network) : agentData.network;
                profile.network = net;
            }
            // Decode legacy consolidated profile blob
            if (agentData.profile) {
                const prof = typeof agentData.profile === 'string'
                    ? JSON.parse(agentData.profile) : agentData.profile;
                profile.profile = prof;
            }
            // Decode services JSON array
            if (agentData.services) {
                services.push(...decodeServicesArray(agentData.services));
            }
            // Models
            if (agentData.models) {
                const models = typeof agentData.models === 'string'
                    ? JSON.parse(agentData.models) : agentData.models;
                if (Array.isArray(models))
                    profile.models = models;
            }
            // Markup
            if (agentData.markup != null) {
                const m = safeNumber(agentData.markup, 1, 50);
                if (m !== undefined)
                    profile.markup = m;
            }
        }
    }
    // --- Session data (legacy parent key) ---
    const sessionEntries = cmm[exports.PARENT_KEYS.session];
    if (sessionEntries?.length) {
        const sessionData = parseOuterDD(sessionEntries[sessionEntries.length - 1], getReverseLookup('session'));
        if (sessionData) {
            if (sessionData.params) {
                const params = typeof sessionData.params === 'string'
                    ? JSON.parse(sessionData.params) : sessionData.params;
                Object.assign(session, params);
            }
            // Legacy individual session keys fallback (validate numerics)
            const dur = safeNumber(sessionData.duration, 0, VDXF_MAX_NUMBER);
            if (dur !== undefined)
                session.duration = dur;
            const tl = safeNumber(sessionData.tokenLimit, 0, VDXF_MAX_NUMBER);
            if (tl !== undefined)
                session.tokenLimit = tl;
            const il = safeNumber(sessionData.imageLimit, 0, VDXF_MAX_NUMBER);
            if (il !== undefined)
                session.imageLimit = il;
            const ml = safeNumber(sessionData.messageLimit, 0, VDXF_MAX_NUMBER);
            if (ml !== undefined)
                session.messageLimit = ml;
            const fs = safeNumber(sessionData.maxFileSize, 0, VDXF_MAX_NUMBER);
            if (fs !== undefined)
                session.maxFileSize = fs;
            if (sessionData.allowedFileTypes) {
                session.allowedFileTypes = typeof sessionData.allowedFileTypes === 'string'
                    ? JSON.parse(sessionData.allowedFileTypes) : sessionData.allowedFileTypes;
            }
        }
    }
    // --- Platform data (legacy parent key) ---
    const platformEntries = cmm[exports.PARENT_KEYS.platform];
    if (platformEntries?.length) {
        const platformData = parseOuterDD(platformEntries[platformEntries.length - 1], getReverseLookup('platform'));
        if (platformData?.config) {
            const cfg = typeof platformData.config === 'string'
                ? JSON.parse(platformData.config) : platformData.config;
            profile.platformConfig = cfg;
        }
    }
    // --- Workspace capability (legacy parent key) ---
    const workspaceEntries = cmm[exports.PARENT_KEYS.workspace];
    if (workspaceEntries?.length) {
        const wsData = parseOuterDD(workspaceEntries[workspaceEntries.length - 1], getReverseLookup('workspace'));
        if (wsData?.capability) {
            const cap = typeof wsData.capability === 'string'
                ? JSON.parse(wsData.capability) : wsData.capability;
            profile.workspaceCapability = cap;
        }
    }
    if (Object.keys(session).length > 0) {
        profile.session = session;
    }
    return { profile: profile, services, disputePolicy: undefined };
}
/**
 * Build a flat contentmultimap from field-name -> value pairs.
 * Each field is mapped to its VDXF_KEYS.agent i-address.
 */
function buildCanonicalAgentUpdate(params) {
    const { fullName, parent, primaryaddresses, minimumsignatures = 1, fields = {}, } = params;
    const clean = (fullName || '').replace(/@$/, '');
    const inferredName = clean ? clean.split('.')[0] : '';
    const inferredParent = clean.includes('.') ? clean.split('.').slice(1).join('.') : parent;
    if (!inferredName)
        throw new Error('Missing subID name');
    if (!inferredParent)
        throw new Error('Missing parent');
    if (!Array.isArray(primaryaddresses) || primaryaddresses.length === 0) {
        throw new Error('primaryaddresses required');
    }
    // Build flat contentmultimap from fields
    const contentmultimap = {};
    const K = exports.VDXF_KEYS.agent;
    for (const [field, value] of Object.entries(fields)) {
        if (value == null)
            continue;
        if (typeof value === 'string' && value.trim() === '')
            continue;
        if (Array.isArray(value) && value.length === 0)
            continue;
        const iAddr = K[field];
        if (!iAddr)
            continue;
        const strValue = typeof value === 'string' ? value : JSON.stringify(value);
        contentmultimap[iAddr] = [makeSubDD(iAddr, strValue)];
    }
    return {
        name: inferredName,
        parent: inferredParent,
        primaryaddresses,
        minimumsignatures,
        contentmultimap,
    };
}
function verifyPublishedIdentity(params) {
    const { identity, expectedPayload } = params;
    const errors = [];
    if (identity.name !== expectedPayload.name)
        errors.push('name mismatch');
    if (identity.parent !== expectedPayload.parent)
        errors.push('parent mismatch');
    const expectedCmm = (expectedPayload.contentmultimap || {});
    const onchain = identity.contentmultimap || {};
    for (const key of Object.keys(expectedCmm)) {
        if (!onchain[key] || onchain[key].length === 0) {
            errors.push(`missing key ${key}`);
        }
    }
    return { ok: errors.length === 0, errors };
}
function buildUpdateIdentityPayload(identityName, contentmultimap) {
    const clean = identityName.replace(/@$/, '');
    const parts = clean.split('.');
    const name = parts[0] || clean;
    const parent = parts.length > 1 ? parts.slice(1).join('.') : 'agentplatform';
    return {
        name,
        parent,
        contentmultimap,
    };
}
function buildUpdateIdentityCommand(payload, chain = 'verustest') {
    const args = ['verus'];
    if (chain === 'verustest')
        args.push('-chain=vrsctest');
    args.push('updateidentity', JSON.stringify(payload));
    return args;
}
// --- Job completion helpers ---
/**
 * Build flat contentmultimap additions for job completion (read-merge-write pattern).
 * Each record is its own top-level key.
 */
function buildJobCompletionAdditions(params) {
    const additions = {};
    additions[exports.VDXF_KEYS.job.record] = [makeSubDD(exports.VDXF_KEYS.job.record, JSON.stringify(params.jobRecord))];
    if (params.reviewRecord) {
        additions[exports.VDXF_KEYS.review.record] = [makeSubDD(exports.VDXF_KEYS.review.record, JSON.stringify(params.reviewRecord))];
    }
    if (params.workspaceAttestation) {
        additions[exports.VDXF_KEYS.workspace.attestation] = [makeSubDD(exports.VDXF_KEYS.workspace.attestation, JSON.stringify(params.workspaceAttestation))];
    }
    return additions;
}
/**
 * Merge two contentmultimaps. Values from `additions` are appended to `existing`.
 */
function mergeContentMultimap(existing, additions) {
    const merged = {};
    for (const [key, values] of Object.entries(existing)) {
        merged[key] = Array.isArray(values) ? [...values] : [values];
    }
    for (const [key, values] of Object.entries(additions)) {
        if (merged[key]) {
            merged[key] = [...merged[key], ...values];
        }
        else {
            merged[key] = [...values];
        }
    }
    return merged;
}
// --- VDXF Update (remove + rewrite) ---
/**
 * Build a contentmultimapremove payload for specific VDXF keys.
 * Uses action 3 (remove all values under a key) for each target.
 *
 * @param identityName - e.g. "myagent.agentplatform@"
 * @param vdxfKeyAddresses - i-addresses of VDXF keys to remove
 * @returns updateidentity-ready JSON object with removal instructions
 */
function buildContentMultimapRemove(identityName, vdxfKeyAddresses) {
    const clean = identityName.replace(/@$/, '');
    const parts = clean.split('.');
    const name = parts[0] || clean;
    const parent = parts.length > 1 ? parts.slice(1).join('.') : 'agentplatform';
    const removeEntries = vdxfKeyAddresses.map(iAddr => ({
        [exports.MULTIMAPREMOVE_KEY]: {
            version: 1,
            action: 3,
            entrykey: iAddr,
        },
    }));
    return {
        name,
        parent,
        contentmultimap: {
            [exports.MULTIMAPREMOVE_KEY]: removeEntries,
        },
    };
}
/**
 * Remove old VDXF values and write new ones in two separate transactions.
 * Waits for block confirmation between remove and write (required by Verus daemon).
 *
 * @throws If block confirmation times out (20 minutes) or transaction fails
 */
async function removeAndRewriteVdxfFields(params) {
    const { agent, identityName, fieldsToUpdate, chain, wif, onProgress } = params;
    const client = agent.client || agent._client;
    const log = (msg) => { if (onProgress)
        onProgress(msg); };
    // Resolve field names to i-addresses
    const fieldToIAddr = {};
    for (const [group, keys] of Object.entries(exports.VDXF_KEYS)) {
        for (const [field, iAddr] of Object.entries(keys)) {
            fieldToIAddr[field] = iAddr;
        }
    }
    const iAddressesToRemove = [];
    for (const fieldName of Object.keys(fieldsToUpdate)) {
        const iAddr = fieldToIAddr[fieldName];
        if (!iAddr)
            throw new Error(`Unknown VDXF field: ${fieldName}`);
        iAddressesToRemove.push(iAddr);
    }
    // ── PHASE 1: Remove old values ──
    log('Phase 1: Removing old VDXF values...');
    const rawIdentity = await client.getIdentityRaw();
    const identityData = rawIdentity.data || rawIdentity; // unwrap { data: { identity, prevOutput } }
    const rawUtxos = await client.getUtxos();
    const utxos = Array.isArray(rawUtxos) ? rawUtxos : (rawUtxos.utxos || []); // unwrap { utxos: [...] }
    const { buildIdentityUpdateTx } = await Promise.resolve().then(() => __importStar(require('../identity/update.js')));
    // Build remove payload — pass as vdxfAdditions under MULTIMAPREMOVE_KEY
    const removeEntries = iAddressesToRemove.map(iAddr => ({
        [exports.MULTIMAPREMOVE_KEY]: {
            version: 1,
            action: 3,
            entrykey: iAddr,
        },
    }));
    const removeTxHex = buildIdentityUpdateTx({
        wif,
        identityData,
        utxos,
        vdxfAdditions: {
            [exports.MULTIMAPREMOVE_KEY]: removeEntries,
        },
        network: chain,
    });
    const removeResult = await client.broadcast(removeTxHex);
    const removeTxid = removeResult.txid || removeResult;
    log(`Remove TX broadcast: ${removeTxid}`);
    // ── PHASE 2: Wait for block confirmation ──
    log('Phase 2: Waiting for block confirmation (can take 1-2 minutes)...');
    const chainInfoBefore = await client.getChainInfo();
    const removeHeight = chainInfoBefore.blockHeight;
    let currentHeight = removeHeight;
    let blocksWaited = 0;
    const MAX_WAIT_MS = 20 * 60 * 1000; // 20 minutes
    const POLL_INTERVAL_MS = 30 * 1000; // 30 seconds
    const startTime = Date.now();
    while (currentHeight <= removeHeight) {
        if (Date.now() - startTime > MAX_WAIT_MS) {
            throw new Error(`Block confirmation timed out after 20 minutes. Remove TX (${removeTxid}) may still be pending. ` +
                `Do NOT retry the remove — wait for it to confirm, then run the write step manually.`);
        }
        await new Promise(r => setTimeout(r, POLL_INTERVAL_MS));
        const info = await client.getChainInfo();
        currentHeight = info.blockHeight;
        blocksWaited++;
        if (blocksWaited % 2 === 0) {
            log(`Still waiting... (${Math.round((Date.now() - startTime) / 1000)}s, height: ${currentHeight}, need: >${removeHeight})`);
        }
    }
    log(`Block confirmed at height ${currentHeight} (waited ${blocksWaited * 30}s)`);
    // ── PHASE 3: Write new values ──
    log('Phase 3: Writing new VDXF values...');
    // Re-fetch identity data and UTXOs (remove tx consumed them)
    const freshRawIdentity = await client.getIdentityRaw();
    const freshIdentityData = freshRawIdentity.data || freshRawIdentity;
    const freshRawUtxos = await client.getUtxos();
    const freshUtxos = Array.isArray(freshRawUtxos) ? freshRawUtxos : (freshRawUtxos.utxos || []);
    // Build write payload — each field gets its own entry
    const writeAdditions = {};
    for (const [fieldName, newValue] of Object.entries(fieldsToUpdate)) {
        const iAddr = fieldToIAddr[fieldName];
        writeAdditions[iAddr] = [makeSubDD(iAddr, newValue)];
    }
    const writeTxHex = buildIdentityUpdateTx({
        wif,
        identityData: freshIdentityData,
        utxos: freshUtxos,
        vdxfAdditions: writeAdditions,
        network: chain,
    });
    const writeResult = await client.broadcast(writeTxHex);
    const writeTxid = writeResult.txid || writeResult;
    log(`Write TX broadcast: ${writeTxid}`);
    // Refresh agent on platform
    try {
        await client.refreshAgent?.(identityName);
    }
    catch { }
    log('VDXF update complete!');
    return { removeTxid, writeTxid, blocksWaited };
}
//# sourceMappingURL=vdxf.js.map