Source: session/CanonicalSessionBridge.js

'use strict';

const { WhatsAppSessionCompatibilityError } = require('./SessionErrors');

const CANONICAL_SESSION_CODEC_KIND = 'wwebjs-canonical-session-v1';
const CANONICAL_SESSION_CODEC_VERSION = 1;
const CANONICAL_SESSION_SCHEMA_VERSION = 17;
const CANONICAL_PRIVATE_MODULE_ABI = 'wwebjs-private-modules-v1';
const CANONICAL_FINGERPRINT_VERSION =
    'underchat-whatsapp-device-fingerprint-v2';
const DEFAULT_MAX_CANONICAL_BYTES = 64 * 1024 * 1024;
const DEFAULT_MAX_CANONICAL_RECORDS = 200000;
const MAX_SIGNAL_SESSION_BYTES = 8 * 1024 * 1024;
const MAX_SENDER_KEY_BYTES = 2 * 1024 * 1024;
const MAX_ROUTING_INFO_BYTES = 65535;
const PQ_PRE_KEY_ID_UPPER_BOUND = 0xffffff;
const PQ_PUBLIC_KEY_BYTES = 1568;
const PQ_PRIVATE_KEY_BYTES = 3168;
const PQ_SIGNATURE_BYTES = 64;
const PQ_CODEC_VERSION = 1;
const PQ_ALGORITHM = 'ML-KEM-1024';
const CANONICAL_PQ_KEY_MODE_GENERATE_AFTER_RECONNECT =
    'generate_after_reconnect';
const CANONICAL_SESSION_STORE_ABI = Object.freeze({
    schemaVersion: CANONICAL_SESSION_SCHEMA_VERSION,
    codecKind: CANONICAL_SESSION_CODEC_KIND,
    codecVersion: CANONICAL_SESSION_CODEC_VERSION,
    moduleAbi: CANONICAL_PRIVATE_MODULE_ABI,
    fingerprintVersion: CANONICAL_FINGERPRINT_VERSION,
    signalScopes: Object.freeze(['default', 'status', 'pq']),
    signalDomainTypes: Object.freeze([0, 1, 128, 129]),
    lifecycleCapabilities: Object.freeze([
        'active-canonical-replay-v1',
        'two-phase-activation-v1',
        'fenced-browser-termination-v1',
        'canonical-pq-ml-kem-1024-v1',
        'pq-upload-rollback-fence-v1',
        'profile-anchor-canonical-checkpoint-v1',
    ]),
});
const BASE64_PATTERN = /^[A-Za-z0-9+/]*={0,2}$/;
const HEX_32_PATTERN = /^[a-f0-9]{64}$/;
const SIGNAL_SCOPES = new Set(['default', 'status', 'pq']);
const WHATSAPP_MEOW_PQ_SAFE_STORAGE_MODES = new Set([
    'legacy_tables',
    'rollout_without_tables',
]);
const PQ_SERVER_COUNT_MODES = new Set(['unknown', 'observed', 'reset']);
const CANONICAL_SIGNAL_ID_PATTERN = /^\d+(?:_(?:1|128|129))?:\d+$/;
const UUID_PATTERN =
    /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu;
const POSITIVE_REVISION_PATTERN = /^[1-9]\d*$/u;
const PQ_SERVER_ROLLBACK_PROTOCOL = 'delete_pq_prekeys_server_ack_v1';

const isObjectRecord = (value) =>
    Boolean(value) && typeof value === 'object' && !Array.isArray(value);

const hasValidPqServerRollbackProof = (capabilities) =>
    isObjectRecord(capabilities) &&
    capabilities.pq_server_rollback_acknowledged === true &&
    capabilities.pq_server_rollback_protocol === PQ_SERVER_ROLLBACK_PROTOCOL &&
    UUID_PATTERN.test(
        String(capabilities.pq_server_rollback_handoff_id || ''),
    ) &&
    UUID_PATTERN.test(
        String(capabilities.pq_server_rollback_lifecycle_operation_id || ''),
    ) &&
    POSITIVE_REVISION_PATTERN.test(
        String(capabilities.pq_server_rollback_source_revision_id || ''),
    ) &&
    UUID_PATTERN.test(String(capabilities.pq_server_rollback_owner_id || '')) &&
    POSITIVE_REVISION_PATTERN.test(
        String(capabilities.pq_server_rollback_fencing_token || ''),
    ) &&
    Number.isSafeInteger(capabilities.pq_server_rollback_generation) &&
    capabilities.pq_server_rollback_generation > 0 &&
    UUID_PATTERN.test(String(capabilities.pq_server_rollback_epoch || '')) &&
    Number.isSafeInteger(capabilities.pq_server_rollback_acknowledged_at_ms) &&
    capabilities.pq_server_rollback_acknowledged_at_ms > 0 &&
    capabilities.pq_server_rollback_response_validated === true &&
    capabilities.pq_upload_lifecycle_fenced === true &&
    capabilities.pq_upload_lifecycle_fence_version === 1 &&
    typeof capabilities.pq_runtime_upload_enabled === 'boolean' &&
    typeof capabilities.pq_runtime_messaging_enabled === 'boolean';

const decodeBase64Length = (value) => {
    if (
        typeof value !== 'string' ||
        value.length % 4 === 1 ||
        !BASE64_PATTERN.test(value)
    ) {
        return -1;
    }
    try {
        return Buffer.from(value, 'base64').length;
    } catch {
        return -1;
    }
};

const assertBase64 = (value, code, expectedLength) => {
    const length = decodeBase64Length(value);
    if (
        length < 0 ||
        (expectedLength !== undefined && length !== expectedLength)
    ) {
        throw new WhatsAppSessionCompatibilityError(code);
    }
    return length;
};

const assertSafeInteger = (value, code, maximum = Number.MAX_SAFE_INTEGER) => {
    if (!Number.isSafeInteger(value) || value < 0 || value > maximum) {
        throw new WhatsAppSessionCompatibilityError(code);
    }
};

const assertAddress = (row, code) => {
    if (
        !isObjectRecord(row) ||
        typeof row.their_id !== 'string' ||
        !CANONICAL_SIGNAL_ID_PATTERN.test(row.their_id) ||
        (row.scope !== undefined && !SIGNAL_SCOPES.has(row.scope))
    ) {
        throw new WhatsAppSessionCompatibilityError(code);
    }
};

/**
 * WhatsMeow currently uses go.mau.fi/libsignal's classical X3DH wire and
 * storage model. It cannot retain WWeb's ML-KEM prekeys or consume a pending
 * PQXDH session. A handoff is therefore portable only when the source gives
 * an explicit, internally consistent proof that post-quantum state is inactive
 * and no PQ-scoped Signal session exists.
 *
 * This check deliberately fails closed for projections written by older
 * bridges that did not publish the PQ capability fields. Silently treating an
 * unknown state as classical could strand messages encrypted to a server-side
 * Kyber prekey after the Chromium source has already been stopped.
 */
function assertCanonicalTargetProviderCompatibility(
    projection,
    targetProvider,
) {
    if (targetProvider !== 'whatsmeow') return projection;

    const capabilities = projection?.capabilities;
    const signalSessions =
        projection?.tables?.whatsapp_signal_sessions ??
        projection?.tables?.signal_sessions;
    const pqPreKeys =
        projection?.tables?.whatsapp_pq_pre_keys ??
        projection?.tables?.pq_pre_keys;
    const pqPreKeyState =
        projection?.tables?.whatsapp_pq_pre_key_state ??
        projection?.tables?.pq_pre_key_state;
    const stateKnown =
        isObjectRecord(capabilities) &&
        typeof capabilities.pq_migrated === 'boolean' &&
        typeof capabilities.pq_upload_enabled === 'boolean' &&
        typeof capabilities.pq_messaging_enabled === 'boolean' &&
        WHATSAPP_MEOW_PQ_SAFE_STORAGE_MODES.has(capabilities.pq_storage_mode) &&
        Number.isSafeInteger(capabilities.pq_pre_key_count) &&
        capabilities.pq_pre_key_count >= 0 &&
        Number.isSafeInteger(capabilities.pq_last_resort_key_count) &&
        capabilities.pq_last_resort_key_count >= 0 &&
        hasValidPqServerRollbackProof(capabilities) &&
        Array.isArray(signalSessions) &&
        Array.isArray(pqPreKeys) &&
        Array.isArray(pqPreKeyState) &&
        pqPreKeyState.length <= 1;

    if (!stateKnown) {
        throw new WhatsAppSessionCompatibilityError(
            'wwebjs_whatsmeow_pqxdh_state_unknown',
            { target_provider: targetProvider },
        );
    }

    const pqSignalSessionCount = signalSessions.filter(
        (row) => row?.scope === 'pq',
    ).length;
    const canonicalPqState = pqPreKeyState[0];
    const serverRollbackAcknowledged =
        hasValidPqServerRollbackProof(capabilities);
    if (
        capabilities.pq_migrated ||
        (!serverRollbackAcknowledged && capabilities.pq_upload_enabled) ||
        (!serverRollbackAcknowledged && capabilities.pq_messaging_enabled) ||
        capabilities.pq_pre_key_count !== 0 ||
        capabilities.pq_last_resort_key_count !== 0 ||
        pqSignalSessionCount !== 0 ||
        pqPreKeys.length !== 0 ||
        canonicalPqState?.migrated === true
    ) {
        throw new WhatsAppSessionCompatibilityError(
            'wwebjs_whatsmeow_pqxdh_state_unportable',
            {
                target_provider: targetProvider,
                pq_migrated: capabilities.pq_migrated,
                pq_upload_enabled: capabilities.pq_upload_enabled,
                pq_messaging_enabled: capabilities.pq_messaging_enabled,
                pq_storage_mode: capabilities.pq_storage_mode,
                pq_pre_key_count: capabilities.pq_pre_key_count,
                pq_last_resort_key_count: capabilities.pq_last_resort_key_count,
                pq_signal_session_count: pqSignalSessionCount,
                pq_server_rollback_acknowledged: serverRollbackAcknowledged,
            },
        );
    }
    return projection;
}

/**
 * Validate the provider-neutral envelope before it crosses a trust boundary.
 * This deliberately validates shape and sizes without parsing or logging any
 * cryptographic value.
 */
function normalizeCanonicalProjection(
    projection,
    {
        requireComplete = true,
        maxBytes = DEFAULT_MAX_CANONICAL_BYTES,
        maxRecords = DEFAULT_MAX_CANONICAL_RECORDS,
    } = {},
) {
    if (
        !isObjectRecord(projection) ||
        projection.kind !== CANONICAL_SESSION_CODEC_KIND ||
        projection.codec_version !== CANONICAL_SESSION_CODEC_VERSION ||
        projection.module_abi !== CANONICAL_PRIVATE_MODULE_ABI ||
        typeof projection.web_version !== 'string' ||
        projection.web_version.length === 0 ||
        projection.fingerprint_version !== CANONICAL_FINGERPRINT_VERSION ||
        typeof projection.complete !== 'boolean' ||
        !Array.isArray(projection.blockers) ||
        !projection.blockers.every(
            (entry) =>
                typeof entry === 'string' && /^[a-z0-9_.-]{1,100}$/.test(entry),
        ) ||
        !isObjectRecord(projection.device) ||
        !isObjectRecord(projection.tables)
    ) {
        throw new WhatsAppSessionCompatibilityError(
            'wwebjs_canonical_projection_invalid',
        );
    }
    if (requireComplete && projection.complete !== true) {
        throw new WhatsAppSessionCompatibilityError(
            'wwebjs_canonical_projection_incomplete',
            { blockers: projection.blockers },
        );
    }

    const device = projection.device;
    if (
        typeof device.jid !== 'string' ||
        !device.jid ||
        (device.lid !== null && typeof device.lid !== 'string') ||
        typeof device.adv_secret_available !== 'boolean' ||
        !HEX_32_PATTERN.test(device.device_fingerprint)
    ) {
        throw new WhatsAppSessionCompatibilityError(
            'wwebjs_canonical_device_invalid',
        );
    }
    assertSafeInteger(
        device.registration_id,
        'wwebjs_canonical_registration_id_invalid',
        0xffffffff,
    );
    assertSafeInteger(
        device.signed_pre_key_id,
        'wwebjs_canonical_signed_pre_key_id_invalid',
        0xffffff,
    );
    assertSafeInteger(
        device.next_pre_key_id,
        'wwebjs_canonical_next_pre_key_id_invalid',
        0x1000000,
    );

    let byteCount = 0;
    const addBase64 = (value, code, length) => {
        const decodedLength = assertBase64(value, code, length);
        byteCount += decodedLength;
        if (byteCount > maxBytes) {
            throw new WhatsAppSessionCompatibilityError(
                'wwebjs_canonical_projection_limit_exceeded',
            );
        }
        return decodedLength;
    };
    addBase64(device.noise_key, 'wwebjs_canonical_noise_key_invalid', 32);
    addBase64(device.identity_key, 'wwebjs_canonical_identity_key_invalid', 32);
    addBase64(
        device.signed_pre_key,
        'wwebjs_canonical_signed_pre_key_invalid',
        32,
    );
    addBase64(
        device.signed_pre_key_sig,
        'wwebjs_canonical_signed_pre_key_signature_invalid',
        64,
    );
    if (device.adv_secret_available) {
        addBase64(device.adv_key, 'wwebjs_canonical_adv_key_invalid', 32);
    } else if (device.adv_key !== null) {
        throw new WhatsAppSessionCompatibilityError(
            'wwebjs_canonical_adv_capability_invalid',
        );
    }
    addBase64(device.adv_details, 'wwebjs_canonical_adv_details_invalid');
    addBase64(
        device.adv_account_sig,
        'wwebjs_canonical_adv_account_signature_invalid',
        64,
    );
    addBase64(
        device.adv_account_sig_key,
        'wwebjs_canonical_adv_account_signature_key_invalid',
        32,
    );
    addBase64(
        device.adv_device_sig,
        'wwebjs_canonical_adv_device_signature_invalid',
        64,
    );

    if (projection.transport_state != null) {
        const transportState = projection.transport_state;
        if (
            !isObjectRecord(transportState) ||
            transportState.kind !== 'whatsapp-transport-v1' ||
            transportState.codec_version !== 1
        ) {
            throw new WhatsAppSessionCompatibilityError(
                'wwebjs_canonical_transport_state_invalid',
            );
        }
        const routingInfoLength = addBase64(
            transportState.routing_info,
            'wwebjs_canonical_routing_info_invalid',
        );
        if (
            routingInfoLength < 1 ||
            routingInfoLength > MAX_ROUTING_INFO_BYTES
        ) {
            throw new WhatsAppSessionCompatibilityError(
                'wwebjs_canonical_routing_info_invalid',
            );
        }
    }

    if (projection.provider_state !== null) {
        const providerState = projection.provider_state;
        if (
            !isObjectRecord(providerState) ||
            providerState.kind !== 'wwebjs-noise-bootstrap-v1' ||
            providerState.codec_version !== 1 ||
            providerState.device_fingerprint !== device.device_fingerprint ||
            (providerState.certificate_chain !== null &&
                typeof providerState.certificate_chain !== 'string')
        ) {
            throw new WhatsAppSessionCompatibilityError(
                'wwebjs_canonical_provider_state_invalid',
            );
        }
        addBase64(
            providerState.noise_public_key,
            'wwebjs_canonical_provider_state_invalid',
            32,
        );
        addBase64(
            providerState.recovery_token,
            'wwebjs_canonical_provider_state_invalid',
            24,
        );
        if (providerState.certificate_chain !== null) {
            addBase64(
                providerState.certificate_chain,
                'wwebjs_canonical_provider_state_invalid',
            );
        }
    }

    const tableNames = [
        'identity_keys',
        'pre_keys',
        'pq_pre_keys',
        'pq_pre_key_state',
        'signal_sessions',
        'sender_keys',
        'app_state_sync_keys',
        'app_state_versions',
        'app_state_mutation_macs',
    ];
    let recordCount = 0;
    for (const tableName of tableNames) {
        const rows = projection.tables[tableName];
        if (!Array.isArray(rows)) {
            throw new WhatsAppSessionCompatibilityError(
                'wwebjs_canonical_projection_table_invalid',
                { table: tableName },
            );
        }
        recordCount += rows.length;
        if (recordCount > maxRecords) {
            throw new WhatsAppSessionCompatibilityError(
                'wwebjs_canonical_projection_limit_exceeded',
            );
        }
    }

    const unique = (rows, key, code) => {
        const keys = new Set();
        for (const row of rows) {
            const value = key(row);
            if (keys.has(value)) {
                throw new WhatsAppSessionCompatibilityError(code);
            }
            keys.add(value);
        }
    };

    for (const row of projection.tables.identity_keys) {
        assertAddress(row, 'wwebjs_canonical_identity_row_invalid');
        addBase64(row.identity, 'wwebjs_canonical_identity_row_invalid', 32);
    }
    unique(
        projection.tables.identity_keys,
        (row) => row.their_id,
        'wwebjs_canonical_identity_duplicate',
    );

    for (const row of projection.tables.pre_keys) {
        if (!isObjectRecord(row) || typeof row.uploaded !== 'boolean') {
            throw new WhatsAppSessionCompatibilityError(
                'wwebjs_canonical_pre_key_row_invalid',
            );
        }
        assertSafeInteger(
            row.key_id,
            'wwebjs_canonical_pre_key_row_invalid',
            0xffffff,
        );
        addBase64(row.key, 'wwebjs_canonical_pre_key_row_invalid', 32);
    }
    unique(
        projection.tables.pre_keys,
        (row) => String(row.key_id),
        'wwebjs_canonical_pre_key_duplicate',
    );

    let pqOneTimeKeyCount = 0;
    let pqLastResortKeyCount = 0;
    for (const row of projection.tables.pq_pre_keys) {
        if (
            !isObjectRecord(row) ||
            !['one_time', 'last_resort'].includes(row.key_kind) ||
            typeof row.sent_to_server !== 'boolean'
        ) {
            throw new WhatsAppSessionCompatibilityError(
                'wwebjs_canonical_pq_pre_key_row_invalid',
            );
        }
        assertSafeInteger(
            row.key_id,
            'wwebjs_canonical_pq_pre_key_row_invalid',
            PQ_PRE_KEY_ID_UPPER_BOUND - 1,
        );
        assertSafeInteger(
            row.timestamp_ms,
            'wwebjs_canonical_pq_pre_key_row_invalid',
        );
        addBase64(
            row.public_key,
            'wwebjs_canonical_pq_pre_key_row_invalid',
            PQ_PUBLIC_KEY_BYTES,
        );
        addBase64(
            row.private_key,
            'wwebjs_canonical_pq_pre_key_row_invalid',
            PQ_PRIVATE_KEY_BYTES,
        );
        addBase64(
            row.signature,
            'wwebjs_canonical_pq_pre_key_row_invalid',
            PQ_SIGNATURE_BYTES,
        );
        if (row.key_kind === 'last_resort') pqLastResortKeyCount += 1;
        else pqOneTimeKeyCount += 1;
    }
    unique(
        projection.tables.pq_pre_keys,
        (row) => String(row.key_id),
        'wwebjs_canonical_pq_pre_key_duplicate',
    );
    if (pqLastResortKeyCount > 1) {
        throw new WhatsAppSessionCompatibilityError(
            'wwebjs_canonical_pq_last_resort_key_duplicate',
        );
    }

    if (projection.tables.pq_pre_key_state.length > 1) {
        throw new WhatsAppSessionCompatibilityError(
            'wwebjs_canonical_pq_pre_key_state_duplicate',
        );
    }
    const pqState = projection.tables.pq_pre_key_state[0];
    let pqServerCountMode = 'reset';
    if (pqState) {
        if (
            !isObjectRecord(pqState) ||
            pqState.codec_version !== PQ_CODEC_VERSION ||
            pqState.algorithm !== PQ_ALGORITHM ||
            typeof pqState.migrated !== 'boolean'
        ) {
            throw new WhatsAppSessionCompatibilityError(
                'wwebjs_canonical_pq_pre_key_state_invalid',
            );
        }
        assertSafeInteger(
            pqState.next_pre_key_id,
            'wwebjs_canonical_pq_pre_key_state_invalid',
            PQ_PRE_KEY_ID_UPPER_BOUND - 1,
        );
        const hasServerCount = pqState.last_server_count !== null;
        const hasServerCountTimestamp =
            pqState.last_server_count_timestamp_ms !== null;
        if (hasServerCount !== hasServerCountTimestamp) {
            throw new WhatsAppSessionCompatibilityError(
                'wwebjs_canonical_pq_pre_key_state_invalid',
            );
        }
        if (hasServerCount) {
            assertSafeInteger(
                pqState.last_server_count,
                'wwebjs_canonical_pq_pre_key_state_invalid',
            );
            assertSafeInteger(
                pqState.last_server_count_timestamp_ms,
                'wwebjs_canonical_pq_pre_key_state_invalid',
            );
        }
        pqServerCountMode =
            projection.capabilities?.pq_server_count_mode ??
            (hasServerCount ? 'observed' : 'reset');
        if (
            !PQ_SERVER_COUNT_MODES.has(pqServerCountMode) ||
            (pqServerCountMode === 'observed' && !hasServerCount) ||
            (pqServerCountMode === 'reset' && hasServerCount)
        ) {
            throw new WhatsAppSessionCompatibilityError(
                'wwebjs_canonical_pq_server_count_mode_invalid',
            );
        }
    } else if (projection.tables.pq_pre_keys.length > 0) {
        throw new WhatsAppSessionCompatibilityError(
            'wwebjs_canonical_pq_pre_key_state_missing',
        );
    }

    if (
        pqState &&
        ((pqState.migrated &&
            (pqLastResortKeyCount !== 1 ||
                !projection.tables.pq_pre_keys.find(
                    (row) => row.key_kind === 'last_resort',
                )?.sent_to_server)) ||
            (!pqState.migrated &&
                projection.tables.pq_pre_keys.some(
                    (row) => row.sent_to_server,
                )) ||
            (!pqState.migrated &&
                pqOneTimeKeyCount > 0 &&
                pqLastResortKeyCount !== 1))
    ) {
        throw new WhatsAppSessionCompatibilityError(
            'wwebjs_canonical_pq_migration_state_diverged',
        );
    }

    const pqCapabilities = projection.capabilities;
    if (
        !isObjectRecord(pqCapabilities) ||
        typeof pqCapabilities.pq_migrated !== 'boolean' ||
        typeof pqCapabilities.pq_upload_enabled !== 'boolean' ||
        typeof pqCapabilities.pq_messaging_enabled !== 'boolean' ||
        !WHATSAPP_MEOW_PQ_SAFE_STORAGE_MODES.has(
            pqCapabilities.pq_storage_mode,
        ) ||
        !Number.isSafeInteger(pqCapabilities.pq_pre_key_count) ||
        pqCapabilities.pq_pre_key_count < 0 ||
        !Number.isSafeInteger(pqCapabilities.pq_last_resort_key_count) ||
        pqCapabilities.pq_last_resort_key_count < 0 ||
        pqCapabilities.pq_pre_key_count !== pqOneTimeKeyCount ||
        pqCapabilities.pq_last_resort_key_count !== pqLastResortKeyCount ||
        pqCapabilities.pq_migrated !== Boolean(pqState?.migrated) ||
        (pqCapabilities.pq_storage_mode === 'legacy_tables') !==
            Boolean(pqState) ||
        (pqCapabilities.pq_storage_mode === 'rollout_without_tables' &&
            (pqState || projection.tables.pq_pre_keys.length > 0)) ||
        (!pqState &&
            pqCapabilities.pq_server_count_mode !== undefined &&
            pqCapabilities.pq_server_count_mode !== 'reset') ||
        (pqState &&
            (pqCapabilities.pq_server_count_mode ?? pqServerCountMode) !==
                pqServerCountMode)
    ) {
        throw new WhatsAppSessionCompatibilityError(
            'wwebjs_canonical_pq_capability_invalid',
        );
    }
    const pqRollbackProofPresent = Object.keys(pqCapabilities).some((key) =>
        key.startsWith('pq_server_rollback_'),
    );
    if (
        pqRollbackProofPresent &&
        (!hasValidPqServerRollbackProof(pqCapabilities) ||
            pqCapabilities.pq_migrated !== false ||
            pqCapabilities.pq_pre_key_count !== 0 ||
            pqCapabilities.pq_last_resort_key_count !== 0 ||
            projection.tables.pq_pre_keys.length !== 0 ||
            projection.tables.signal_sessions.some(
                (row) => row?.scope !== 'default',
            ) ||
            JSON.stringify(pqCapabilities.canonical_signal_session_scopes) !==
                JSON.stringify(['default']) ||
            pqCapabilities.canonical_signal_session_resync_required !== true ||
            JSON.stringify(
                pqCapabilities.canonical_signal_session_resync_scopes,
            ) !== JSON.stringify(['status', 'pq']))
    ) {
        throw new WhatsAppSessionCompatibilityError(
            'wwebjs_canonical_pq_server_rollback_proof_invalid',
        );
    }

    for (const row of projection.tables.signal_sessions) {
        assertAddress(row, 'wwebjs_canonical_signal_session_row_invalid');
        if (!SIGNAL_SCOPES.has(row.scope)) {
            throw new WhatsAppSessionCompatibilityError(
                'wwebjs_canonical_signal_session_row_invalid',
            );
        }
        const sessionBytes = addBase64(
            row.session,
            'wwebjs_canonical_signal_session_row_invalid',
        );
        if (sessionBytes === 0 || sessionBytes > MAX_SIGNAL_SESSION_BYTES) {
            throw new WhatsAppSessionCompatibilityError(
                'wwebjs_canonical_signal_session_limit_exceeded',
            );
        }
    }
    unique(
        projection.tables.signal_sessions,
        (row) => `${row.their_id}\0${row.scope}`,
        'wwebjs_canonical_signal_session_duplicate',
    );

    for (const row of projection.tables.sender_keys) {
        if (
            !isObjectRecord(row) ||
            typeof row.chat_id !== 'string' ||
            !row.chat_id ||
            typeof row.sender_id !== 'string' ||
            !CANONICAL_SIGNAL_ID_PATTERN.test(row.sender_id)
        ) {
            throw new WhatsAppSessionCompatibilityError(
                'wwebjs_canonical_sender_key_row_invalid',
            );
        }
        const senderKeyBytes = addBase64(
            row.sender_key,
            'wwebjs_canonical_sender_key_row_invalid',
        );
        if (senderKeyBytes === 0 || senderKeyBytes > MAX_SENDER_KEY_BYTES) {
            throw new WhatsAppSessionCompatibilityError(
                'wwebjs_canonical_sender_key_limit_exceeded',
            );
        }
    }
    unique(
        projection.tables.sender_keys,
        (row) => `${row.chat_id}\0${row.sender_id}`,
        'wwebjs_canonical_sender_key_duplicate',
    );

    for (const row of projection.tables.app_state_sync_keys) {
        if (!isObjectRecord(row)) {
            throw new WhatsAppSessionCompatibilityError(
                'wwebjs_canonical_app_state_key_row_invalid',
            );
        }
        assertSafeInteger(
            row.timestamp,
            'wwebjs_canonical_app_state_key_row_invalid',
        );
        if (decodeBase64Length(row.key_id) < 2) {
            throw new WhatsAppSessionCompatibilityError(
                'wwebjs_canonical_app_state_key_epoch_invalid',
            );
        }
        addBase64(row.key_id, 'wwebjs_canonical_app_state_key_row_invalid');
        addBase64(
            row.key_data,
            'wwebjs_canonical_app_state_key_row_invalid',
            32,
        );
        addBase64(
            row.fingerprint,
            'wwebjs_canonical_app_state_key_row_invalid',
        );
    }
    unique(
        projection.tables.app_state_sync_keys,
        (row) => row.key_id,
        'wwebjs_canonical_app_state_key_duplicate',
    );

    for (const row of projection.tables.app_state_versions) {
        if (!isObjectRecord(row) || typeof row.name !== 'string' || !row.name) {
            throw new WhatsAppSessionCompatibilityError(
                'wwebjs_canonical_app_state_version_row_invalid',
            );
        }
        assertSafeInteger(
            row.version,
            'wwebjs_canonical_app_state_version_row_invalid',
        );
        addBase64(
            row.hash,
            'wwebjs_canonical_app_state_version_row_invalid',
            128,
        );
    }
    unique(
        projection.tables.app_state_versions,
        (row) => row.name,
        'wwebjs_canonical_app_state_version_duplicate',
    );

    for (const row of projection.tables.app_state_mutation_macs) {
        if (!isObjectRecord(row) || typeof row.name !== 'string' || !row.name) {
            throw new WhatsAppSessionCompatibilityError(
                'wwebjs_canonical_app_state_mac_row_invalid',
            );
        }
        assertSafeInteger(
            row.version,
            'wwebjs_canonical_app_state_mac_row_invalid',
        );
        addBase64(
            row.index_mac,
            'wwebjs_canonical_app_state_mac_row_invalid',
            32,
        );
        addBase64(
            row.value_mac,
            'wwebjs_canonical_app_state_mac_row_invalid',
            32,
        );
    }
    unique(
        projection.tables.app_state_mutation_macs,
        (row) => `${row.name}\0${row.index_mac}\0${row.version}`,
        'wwebjs_canonical_app_state_mac_duplicate',
    );

    if (
        projection.record_count !== recordCount ||
        projection.size_bytes !== byteCount
    ) {
        throw new WhatsAppSessionCompatibilityError(
            'wwebjs_canonical_projection_accounting_invalid',
        );
    }
    return projection;
}

const cloneBytes = (value, code, expectedLength) => {
    if (!Buffer.isBuffer(value) && !(value instanceof Uint8Array)) {
        throw new WhatsAppSessionCompatibilityError(code);
    }
    const bytes = Buffer.from(value);
    if (
        bytes.length === 0 ||
        (expectedLength !== undefined && bytes.length !== expectedLength)
    ) {
        throw new WhatsAppSessionCompatibilityError(code);
    }
    return bytes;
};

const normalizeNonImportableSignalSessions = (rows) => {
    if (!Array.isArray(rows)) {
        throw new WhatsAppSessionCompatibilityError(
            'wwebjs_canonical_store_projection_invalid',
        );
    }
    const seen = new Set();
    return rows
        .filter((row) => row?.session === null)
        .map((row) => {
            assertAddress(row, 'wwebjs_canonical_signal_session_row_invalid');
            if (!SIGNAL_SCOPES.has(row.scope)) {
                throw new WhatsAppSessionCompatibilityError(
                    'wwebjs_canonical_signal_session_row_invalid',
                );
            }
            const key = `${row.their_id}\0${row.scope}`;
            if (seen.has(key)) {
                throw new WhatsAppSessionCompatibilityError(
                    'wwebjs_canonical_signal_session_duplicate',
                );
            }
            seen.add(key);
            return {
                their_id: row.their_id,
                scope: row.scope,
                session: null,
            };
        });
};

/**
 * Convert the page-realm envelope to the public/store ABI. The browser uses
 * base64 because Puppeteer must cross a structured-clone boundary; callers and
 * PostgreSQL always receive byte arrays instead.
 */
function canonicalBrowserProjectionToStore(
    projection,
    { requireComplete = true } = {},
) {
    const normalized = normalizeCanonicalProjection(projection, {
        requireComplete,
    });
    const decode = (value) => Buffer.from(value, 'base64');
    const providerState = normalized.provider_state
        ? {
              kind: normalized.provider_state.kind,
              codec_version: normalized.provider_state.codec_version,
              device_fingerprint: Buffer.from(
                  normalized.provider_state.device_fingerprint,
                  'hex',
              ),
              noise_public_key: decode(
                  normalized.provider_state.noise_public_key,
              ),
              recovery_token: decode(normalized.provider_state.recovery_token),
              certificate_chain:
                  normalized.provider_state.certificate_chain === null
                      ? null
                      : decode(normalized.provider_state.certificate_chain),
          }
        : null;
    const transportState = normalized.transport_state
        ? {
              kind: normalized.transport_state.kind,
              codec_version: normalized.transport_state.codec_version,
              routing_info: decode(normalized.transport_state.routing_info),
          }
        : null;
    return {
        schema_version: CANONICAL_SESSION_SCHEMA_VERSION,
        codec_kind: CANONICAL_SESSION_CODEC_KIND,
        codec_version: CANONICAL_SESSION_CODEC_VERSION,
        module_abi: CANONICAL_PRIVATE_MODULE_ABI,
        web_version: normalized.web_version,
        fingerprint_version: CANONICAL_FINGERPRINT_VERSION,
        complete: normalized.complete,
        blockers: [...normalized.blockers],
        capabilities: {
            ...normalized.capabilities,
            pq_server_count_mode:
                normalized.capabilities.pq_server_count_mode ??
                (normalized.tables.pq_pre_key_state[0] &&
                normalized.tables.pq_pre_key_state[0].last_server_count !== null
                    ? 'observed'
                    : 'reset'),
        },
        device: {
            jid: normalized.device.jid,
            lid: normalized.device.lid,
            facebook_uuid: normalized.device.facebook_uuid || null,
            registration_id: normalized.device.registration_id,
            noise_key: decode(normalized.device.noise_key),
            identity_key: decode(normalized.device.identity_key),
            signed_pre_key: decode(normalized.device.signed_pre_key),
            signed_pre_key_id: normalized.device.signed_pre_key_id,
            signed_pre_key_sig: decode(normalized.device.signed_pre_key_sig),
            adv_secret_available: normalized.device.adv_secret_available,
            adv_key:
                normalized.device.adv_key === null
                    ? null
                    : decode(normalized.device.adv_key),
            adv_details: decode(normalized.device.adv_details),
            adv_account_sig: decode(normalized.device.adv_account_sig),
            adv_account_sig_key: decode(normalized.device.adv_account_sig_key),
            adv_device_sig: decode(normalized.device.adv_device_sig),
            platform: normalized.device.platform || 'web',
            business_name: normalized.device.business_name || '',
            push_name: normalized.device.push_name || '',
            lid_migration_ts: normalized.device.lid_migration_ts || 0,
            next_pre_key_id: normalized.device.next_pre_key_id,
            device_fingerprint: Buffer.from(
                normalized.device.device_fingerprint,
                'hex',
            ),
            fingerprint_version: CANONICAL_FINGERPRINT_VERSION,
        },
        provider_state: providerState,
        transport_state: transportState,
        tables: {
            whatsapp_identity_keys: normalized.tables.identity_keys.map(
                (row) => ({
                    their_id: row.their_id,
                    identity: decode(row.identity),
                }),
            ),
            whatsapp_pre_keys: normalized.tables.pre_keys.map((row) => ({
                key_id: row.key_id,
                key: decode(row.key),
                uploaded: row.uploaded,
            })),
            whatsapp_pq_pre_keys: normalized.tables.pq_pre_keys.map((row) => ({
                key_id: row.key_id,
                key_kind: row.key_kind,
                public_key: decode(row.public_key),
                private_key: decode(row.private_key),
                signature: decode(row.signature),
                timestamp_ms: row.timestamp_ms,
                sent_to_server: row.sent_to_server,
            })),
            whatsapp_pq_pre_key_state: normalized.tables.pq_pre_key_state.map(
                (row) => ({
                    codec_version: row.codec_version,
                    algorithm: row.algorithm,
                    next_pre_key_id: row.next_pre_key_id,
                    migrated: row.migrated,
                    last_server_count: row.last_server_count,
                    last_server_count_timestamp_ms:
                        row.last_server_count_timestamp_ms,
                }),
            ),
            whatsapp_signal_sessions: normalized.tables.signal_sessions.map(
                (row) => ({
                    their_id: row.their_id,
                    scope: row.scope,
                    session: decode(row.session),
                }),
            ),
            whatsapp_sender_keys: normalized.tables.sender_keys.map((row) => ({
                chat_id: row.chat_id,
                sender_id: row.sender_id,
                sender_key: decode(row.sender_key),
            })),
            whatsapp_app_state_sync_keys:
                normalized.tables.app_state_sync_keys.map((row) => ({
                    key_id: decode(row.key_id),
                    key_data: decode(row.key_data),
                    timestamp: row.timestamp,
                    fingerprint: decode(row.fingerprint),
                })),
            whatsapp_app_state_version:
                normalized.tables.app_state_versions.map((row) => ({
                    name: row.name,
                    version: row.version,
                    hash: decode(row.hash),
                })),
            whatsapp_app_state_mutation_macs:
                normalized.tables.app_state_mutation_macs.map((row) => ({
                    name: row.name,
                    version: row.version,
                    index_mac: decode(row.index_mac),
                    value_mac: decode(row.value_mac),
                })),
        },
        record_count: normalized.record_count,
        size_bytes: normalized.size_bytes,
    };
}

/** Convert the public/store ABI back to the page-realm envelope. */
function canonicalStoreProjectionToBrowser(projection, { webVersion } = {}) {
    if (
        !isObjectRecord(projection) ||
        projection.schema_version !== CANONICAL_SESSION_SCHEMA_VERSION ||
        projection.codec_kind !== CANONICAL_SESSION_CODEC_KIND ||
        projection.codec_version !== CANONICAL_SESSION_CODEC_VERSION ||
        projection.fingerprint_version !== CANONICAL_FINGERPRINT_VERSION ||
        !isObjectRecord(projection.device) ||
        !isObjectRecord(projection.tables)
    ) {
        throw new WhatsAppSessionCompatibilityError(
            'wwebjs_canonical_store_projection_invalid',
        );
    }
    const device = projection.device;
    if (
        device.fingerprint_version !== CANONICAL_FINGERPRINT_VERSION ||
        typeof device.adv_secret_available !== 'boolean'
    ) {
        throw new WhatsAppSessionCompatibilityError(
            'wwebjs_canonical_store_device_invalid',
        );
    }
    const encode = (value, code, expectedLength) =>
        cloneBytes(value, code, expectedLength).toString('base64');
    const tables = projection.tables;
    const requiredTables = [
        'whatsapp_identity_keys',
        'whatsapp_pre_keys',
        'whatsapp_pq_pre_keys',
        'whatsapp_pq_pre_key_state',
        'whatsapp_signal_sessions',
        'whatsapp_sender_keys',
        'whatsapp_app_state_sync_keys',
        'whatsapp_app_state_version',
        'whatsapp_app_state_mutation_macs',
    ];
    if (requiredTables.some((name) => !Array.isArray(tables[name]))) {
        throw new WhatsAppSessionCompatibilityError(
            'wwebjs_canonical_store_projection_invalid',
        );
    }
    const nonImportableSignalSessions = normalizeNonImportableSignalSessions(
        tables.whatsapp_signal_sessions,
    );
    const signalSessionKeys = new Set();
    for (const row of tables.whatsapp_signal_sessions) {
        assertAddress(row, 'wwebjs_canonical_signal_session_row_invalid');
        if (!SIGNAL_SCOPES.has(row.scope)) {
            throw new WhatsAppSessionCompatibilityError(
                'wwebjs_canonical_signal_session_row_invalid',
            );
        }
        const key = `${row.their_id}\0${row.scope}`;
        if (signalSessionKeys.has(key)) {
            throw new WhatsAppSessionCompatibilityError(
                'wwebjs_canonical_signal_session_duplicate',
            );
        }
        signalSessionKeys.add(key);
    }
    const providerState = projection.provider_state;
    const transportState = projection.transport_state;
    const pqState = tables.whatsapp_pq_pre_key_state[0];
    const pqOneTimeKeyCount = tables.whatsapp_pq_pre_keys.filter(
        (row) => row?.key_kind === 'one_time',
    ).length;
    const pqLastResortKeyCount = tables.whatsapp_pq_pre_keys.filter(
        (row) => row?.key_kind === 'last_resort',
    ).length;
    const capabilities = {
        ...(isObjectRecord(projection.capabilities)
            ? projection.capabilities
            : {
                  adv_secret_available: device.adv_secret_available,
                  passkey_handoff_supported: device.adv_secret_available,
                  signal_scopes: ['default', 'status', 'pq'],
                  signal_domain_types: [0, 1, 128, 129],
                  app_state_import_mode: 'snapshot_resync',
                  canonical_signal_session_scopes: ['default', 'status', 'pq'],
                  canonical_signal_session_resync_required: false,
                  canonical_signal_session_resync_scopes: [],
              }),
    };
    capabilities.pq_migrated ??= Boolean(pqState?.migrated);
    capabilities.pq_upload_enabled ??= Boolean(pqState?.migrated);
    capabilities.pq_messaging_enabled ??= Boolean(pqState?.migrated);
    capabilities.pq_storage_mode ??= pqState
        ? 'legacy_tables'
        : 'rollout_without_tables';
    capabilities.pq_pre_key_count ??= pqOneTimeKeyCount;
    capabilities.pq_last_resort_key_count ??= pqLastResortKeyCount;
    capabilities.pq_server_count_mode ??=
        pqState?.last_server_count !== null &&
        pqState?.last_server_count !== undefined
            ? 'observed'
            : 'reset';
    const browser = {
        kind: CANONICAL_SESSION_CODEC_KIND,
        codec_version: CANONICAL_SESSION_CODEC_VERSION,
        module_abi: CANONICAL_PRIVATE_MODULE_ABI,
        web_version: webVersion || projection.web_version || 'unknown',
        fingerprint_version: CANONICAL_FINGERPRINT_VERSION,
        complete: projection.complete !== false,
        blockers: Array.isArray(projection.blockers)
            ? [...projection.blockers]
            : [],
        capabilities,
        device: {
            jid: device.jid,
            lid: device.lid ?? null,
            facebook_uuid: device.facebook_uuid ?? null,
            registration_id: Number(device.registration_id),
            noise_key: encode(
                device.noise_key,
                'wwebjs_canonical_noise_key_invalid',
                32,
            ),
            identity_key: encode(
                device.identity_key,
                'wwebjs_canonical_identity_key_invalid',
                32,
            ),
            signed_pre_key: encode(
                device.signed_pre_key,
                'wwebjs_canonical_signed_pre_key_invalid',
                32,
            ),
            signed_pre_key_id: Number(device.signed_pre_key_id),
            signed_pre_key_sig: encode(
                device.signed_pre_key_sig,
                'wwebjs_canonical_signed_pre_key_signature_invalid',
                64,
            ),
            adv_secret_available: device.adv_secret_available,
            adv_key: device.adv_secret_available
                ? encode(device.adv_key, 'wwebjs_canonical_adv_key_invalid', 32)
                : null,
            adv_details: encode(
                device.adv_details,
                'wwebjs_canonical_adv_details_invalid',
            ),
            adv_account_sig: encode(
                device.adv_account_sig,
                'wwebjs_canonical_adv_account_signature_invalid',
                64,
            ),
            adv_account_sig_key: encode(
                device.adv_account_sig_key,
                'wwebjs_canonical_adv_account_signature_key_invalid',
                32,
            ),
            adv_device_sig: encode(
                device.adv_device_sig,
                'wwebjs_canonical_adv_device_signature_invalid',
                64,
            ),
            platform: device.platform || 'web',
            business_name: device.business_name || '',
            push_name: device.push_name || '',
            lid_migration_ts: Number(device.lid_migration_ts || 0),
            next_pre_key_id: Number(device.next_pre_key_id),
            device_fingerprint: cloneBytes(
                device.device_fingerprint,
                'wwebjs_canonical_device_fingerprint_invalid',
                32,
            ).toString('hex'),
        },
        provider_state:
            providerState == null
                ? null
                : {
                      kind: providerState.kind,
                      codec_version: providerState.codec_version,
                      device_fingerprint: cloneBytes(
                          providerState.device_fingerprint,
                          'wwebjs_canonical_provider_state_invalid',
                          32,
                      ).toString('hex'),
                      noise_public_key: encode(
                          providerState.noise_public_key,
                          'wwebjs_canonical_provider_state_invalid',
                          32,
                      ),
                      recovery_token: encode(
                          providerState.recovery_token,
                          'wwebjs_canonical_provider_state_invalid',
                          24,
                      ),
                      certificate_chain:
                          providerState.certificate_chain == null
                              ? null
                              : encode(
                                    providerState.certificate_chain,
                                    'wwebjs_canonical_provider_state_invalid',
                                ),
                  },
        transport_state:
            transportState == null
                ? null
                : {
                      kind: transportState.kind,
                      codec_version: transportState.codec_version,
                      routing_info: encode(
                          transportState.routing_info,
                          'wwebjs_canonical_routing_info_invalid',
                      ),
                  },
        tables: {
            identity_keys: tables.whatsapp_identity_keys.map((row) => ({
                their_id: row.their_id,
                identity: encode(
                    row.identity,
                    'wwebjs_canonical_identity_row_invalid',
                    32,
                ),
            })),
            pre_keys: tables.whatsapp_pre_keys.map((row) => ({
                key_id: Number(row.key_id),
                key: encode(
                    row.key,
                    'wwebjs_canonical_pre_key_row_invalid',
                    32,
                ),
                uploaded: row.uploaded,
            })),
            pq_pre_keys: tables.whatsapp_pq_pre_keys.map((row) => ({
                key_id: Number(row.key_id),
                key_kind: row.key_kind,
                public_key: encode(
                    row.public_key,
                    'wwebjs_canonical_pq_pre_key_row_invalid',
                    PQ_PUBLIC_KEY_BYTES,
                ),
                private_key: encode(
                    row.private_key,
                    'wwebjs_canonical_pq_pre_key_row_invalid',
                    PQ_PRIVATE_KEY_BYTES,
                ),
                signature: encode(
                    row.signature,
                    'wwebjs_canonical_pq_pre_key_row_invalid',
                    PQ_SIGNATURE_BYTES,
                ),
                timestamp_ms: Number(row.timestamp_ms),
                sent_to_server: row.sent_to_server,
            })),
            pq_pre_key_state: tables.whatsapp_pq_pre_key_state.map((row) => ({
                codec_version: Number(row.codec_version),
                algorithm: row.algorithm,
                next_pre_key_id: Number(row.next_pre_key_id),
                migrated: row.migrated,
                last_server_count:
                    row.last_server_count === null
                        ? null
                        : Number(row.last_server_count),
                last_server_count_timestamp_ms:
                    row.last_server_count_timestamp_ms === null
                        ? null
                        : Number(row.last_server_count_timestamp_ms),
            })),
            // A NULL canonical session is meaningful to the native stores but
            // has no valid WWebJS IndexedDB representation. Keep it in the
            // PostgreSQL/store ABI and deliberately omit it from the browser
            // import envelope. PostgresSessionStore preserves these rows on
            // subsequent WWeb-only checkpoints.
            signal_sessions: tables.whatsapp_signal_sessions
                .filter((row) => row.session !== null)
                .map((row) => ({
                    their_id: row.their_id,
                    scope: row.scope,
                    session: encode(
                        row.session,
                        'wwebjs_canonical_signal_session_row_invalid',
                    ),
                })),
            sender_keys: tables.whatsapp_sender_keys.map((row) => ({
                chat_id: row.chat_id,
                sender_id: row.sender_id,
                sender_key: encode(
                    row.sender_key,
                    'wwebjs_canonical_sender_key_row_invalid',
                ),
            })),
            app_state_sync_keys: tables.whatsapp_app_state_sync_keys.map(
                (row) => ({
                    key_id: encode(
                        row.key_id,
                        'wwebjs_canonical_app_state_key_row_invalid',
                    ),
                    key_data: encode(
                        row.key_data,
                        'wwebjs_canonical_app_state_key_row_invalid',
                        32,
                    ),
                    timestamp: Number(row.timestamp),
                    fingerprint: encode(
                        row.fingerprint,
                        'wwebjs_canonical_app_state_key_row_invalid',
                    ),
                }),
            ),
            app_state_versions: tables.whatsapp_app_state_version.map(
                (row) => ({
                    name: row.name,
                    version: Number(row.version),
                    hash: encode(
                        row.hash,
                        'wwebjs_canonical_app_state_version_row_invalid',
                        128,
                    ),
                }),
            ),
            app_state_mutation_macs:
                tables.whatsapp_app_state_mutation_macs.map((row) => ({
                    name: row.name,
                    version: Number(row.version),
                    index_mac: encode(
                        row.index_mac,
                        'wwebjs_canonical_app_state_mac_row_invalid',
                        32,
                    ),
                    value_mac: encode(
                        row.value_mac,
                        'wwebjs_canonical_app_state_mac_row_invalid',
                        32,
                    ),
                })),
        },
    };
    browser.record_count = Object.values(browser.tables).reduce(
        (total, rows) => total + rows.length,
        0,
    );
    const encodedValues = [
        browser.device.noise_key,
        browser.device.identity_key,
        browser.device.signed_pre_key,
        browser.device.signed_pre_key_sig,
        browser.device.adv_details,
        browser.device.adv_account_sig,
        browser.device.adv_account_sig_key,
        browser.device.adv_device_sig,
        ...(browser.device.adv_key ? [browser.device.adv_key] : []),
        ...(browser.provider_state
            ? [
                  browser.provider_state.noise_public_key,
                  browser.provider_state.recovery_token,
                  ...(browser.provider_state.certificate_chain
                      ? [browser.provider_state.certificate_chain]
                      : []),
              ]
            : []),
        ...(browser.transport_state
            ? [browser.transport_state.routing_info]
            : []),
        ...browser.tables.identity_keys.map((row) => row.identity),
        ...browser.tables.pre_keys.map((row) => row.key),
        ...browser.tables.pq_pre_keys.flatMap((row) => [
            row.public_key,
            row.private_key,
            row.signature,
        ]),
        ...browser.tables.signal_sessions.map((row) => row.session),
        ...browser.tables.sender_keys.map((row) => row.sender_key),
        ...browser.tables.app_state_sync_keys.flatMap((row) => [
            row.key_id,
            row.key_data,
            row.fingerprint,
        ]),
        ...browser.tables.app_state_versions.map((row) => row.hash),
        ...browser.tables.app_state_mutation_macs.flatMap((row) => [
            row.index_mac,
            row.value_mac,
        ]),
    ];
    browser.size_bytes = encodedValues.reduce(
        (total, value) => total + Buffer.from(value, 'base64').length,
        0,
    );
    const normalized = normalizeCanonicalProjection(browser);
    Object.defineProperty(normalized, 'non_importable_signal_session_count', {
        configurable: true,
        enumerable: false,
        value: nonImportableSignalSessions.length,
    });
    return normalized;
}

/* This function is serialized by Puppeteer and executes in the page realm. */
async function exportCanonicalSessionProjection(options) {
    const blockers = new Set();
    const diagnostics = {};
    let recordCount = 0;
    let sizeBytes = 0;
    const pqRollback = options?.pqServerRollback;
    const pqRollbackRequested = pqRollback !== undefined;
    const pqRollbackValid =
        pqRollbackRequested &&
        Boolean(pqRollback) &&
        pqRollback.protocol === 'delete_pq_prekeys_server_ack_v1' &&
        pqRollback.server_acknowledged === true &&
        pqRollback.local_cleanup_complete === true &&
        /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu.test(
            String(pqRollback.handoff_id || ''),
        ) &&
        /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu.test(
            String(pqRollback.lifecycle_operation_id || ''),
        ) &&
        /^[1-9]\d*$/u.test(String(pqRollback.source_revision_id || '')) &&
        /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu.test(
            String(pqRollback.owner_id || ''),
        ) &&
        /^[1-9]\d*$/u.test(String(pqRollback.fencing_token || '')) &&
        Number.isSafeInteger(pqRollback.generation) &&
        pqRollback.generation > 0 &&
        /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu.test(
            String(pqRollback.epoch || ''),
        ) &&
        Number.isSafeInteger(pqRollback.acknowledged_at_ms) &&
        pqRollback.acknowledged_at_ms > 0 &&
        pqRollback.response_validated === true &&
        pqRollback.upload_lifecycle_fenced === true &&
        pqRollback.upload_lifecycle_fence_version === 1 &&
        typeof pqRollback.runtime_upload_enabled === 'boolean' &&
        typeof pqRollback.runtime_messaging_enabled === 'boolean';
    if (pqRollbackRequested && !pqRollbackValid) {
        blockers.add('post_quantum.server_rollback_proof_invalid');
    }

    const requireModule = (name) => {
        try {
            const moduleValue = window.require?.(name);
            if (!moduleValue) throw new Error('missing');
            return moduleValue.default || moduleValue;
        } catch {
            blockers.add(`module.${name}.unavailable`.toLowerCase());
            return undefined;
        }
    };
    const toBytes = (value) => {
        if (value instanceof ArrayBuffer) return new Uint8Array(value);
        if (ArrayBuffer.isView(value)) {
            return new Uint8Array(
                value.buffer,
                value.byteOffset,
                value.byteLength,
            );
        }
        return undefined;
    };
    const toBase64 = (value, expectedLength) => {
        const bytes = toBytes(value);
        if (
            !bytes ||
            (expectedLength !== undefined &&
                bytes.byteLength !== expectedLength)
        ) {
            return undefined;
        }
        let binary = '';
        for (let offset = 0; offset < bytes.length; offset += 0x8000) {
            binary += String.fromCharCode(
                ...bytes.subarray(offset, offset + 0x8000),
            );
        }
        sizeBytes += bytes.byteLength;
        if (sizeBytes > options.maxBytes) {
            throw new Error('wwebjs_canonical_projection_limit_exceeded');
        }
        return btoa(binary);
    };
    const fromBase64 = (value) => {
        if (typeof value !== 'string') return undefined;
        try {
            const binary = atob(value);
            return Uint8Array.from(binary, (entry) => entry.charCodeAt(0));
        } catch {
            return undefined;
        }
    };
    const addRows = (rows) => {
        recordCount += rows.length;
        if (recordCount > options.maxRecords) {
            throw new Error('wwebjs_canonical_projection_limit_exceeded');
        }
        return rows;
    };
    const all = async (table, blocker) => {
        if (!table || typeof table.all !== 'function') {
            blockers.add(blocker);
            return [];
        }
        try {
            const rows = await table.all();
            if (!Array.isArray(rows)) throw new Error('invalid');
            return rows;
        } catch {
            blockers.add(blocker);
            return [];
        }
    };
    const widString = (value) => {
        if (typeof value === 'string') return value;
        if (!value || typeof value !== 'object') return undefined;
        for (const field of ['_serialized', 'serialized', 'id']) {
            if (typeof value[field] === 'string') return value[field];
        }
        try {
            const jid = value.toJid?.();
            if (typeof jid === 'string') return jid;
        } catch {
            // Try the legacy string representation below.
        }
        try {
            const legacy = value.toString?.({ legacy: true });
            if (typeof legacy === 'string' && legacy !== '[object Object]') {
                return legacy;
            }
        } catch {
            // The caller treats an unrenderable WID as an incomplete export.
        }
        return undefined;
    };
    const parseSignalAddress = (value) => {
        if (typeof value !== 'string' || !value.endsWith('.0')) return null;
        let address = value.slice(0, -2);
        let scope = 'default';
        if (address.endsWith('_status')) {
            address = address.slice(0, -'_status'.length);
            scope = 'status';
        } else if (address.endsWith('_pq')) {
            address = address.slice(0, -'_pq'.length);
            scope = 'pq';
        }
        const separator = address.lastIndexOf('@');
        if (separator <= 0) return null;
        const head = address.slice(0, separator);
        const server = address.slice(separator + 1);
        const match = /^(\d+)(?::(\d+))?$/.exec(head);
        if (!match) return null;
        const domainType =
            server === 'lid'
                ? 1
                : server === 'hosted'
                  ? 128
                  : server === 'hosted.lid'
                    ? 129
                    : server === 'c.us' || server === 's.whatsapp.net'
                      ? 0
                      : undefined;
        if (domainType === undefined) return null;
        const signalUser =
            domainType === 0 ? match[1] : `${match[1]}_${domainType}`;
        return {
            their_id: `${signalUser}:${Number(match[2] || 0)}`,
            scope,
        };
    };
    const encodeProto = (encoder, spec, value) => {
        try {
            const encoded = encoder.encodeProtobuf(spec, value);
            return encoded.readByteArrayView();
        } catch {
            return undefined;
        }
    };
    const encodeVarint = (input) => {
        let value = Number(input);
        const output = [];
        do {
            let byte = value % 128;
            value = Math.floor(value / 128);
            if (value > 0) byte |= 0x80;
            output.push(byte);
        } while (value > 0);
        return output;
    };
    const encodeFingerprint = (fingerprint) => {
        if (!fingerprint || typeof fingerprint !== 'object') return undefined;
        const rawId = Number(fingerprint.rawId);
        const currentIndex = Number(fingerprint.currentIndex);
        const indexes = fingerprint.deviceIndexes;
        if (
            !Number.isSafeInteger(rawId) ||
            rawId < 0 ||
            !Number.isSafeInteger(currentIndex) ||
            currentIndex < 0 ||
            !Array.isArray(indexes) ||
            !indexes.every((entry) => Number.isSafeInteger(entry) && entry >= 0)
        ) {
            return undefined;
        }
        const packed = indexes.flatMap(encodeVarint);
        return Uint8Array.from([
            8,
            ...encodeVarint(rawId),
            16,
            ...encodeVarint(currentIndex),
            ...(packed.length > 0
                ? [26, ...encodeVarint(packed.length), ...packed]
                : []),
        ]);
    };
    const domainDigest = async (domainValue, fields) => {
        const domain = new TextEncoder().encode(domainValue);
        const normalized = fields.map((field) => {
            const bytes = toBytes(field);
            return bytes ? new Uint8Array(bytes) : undefined;
        });
        if (normalized.some((field) => !field || field.byteLength === 0)) {
            return undefined;
        }
        const total = normalized.reduce(
            (sum, field) => sum + 4 + field.byteLength,
            domain.byteLength,
        );
        const payload = new Uint8Array(total);
        payload.set(domain);
        const view = new DataView(payload.buffer);
        let offset = domain.byteLength;
        for (const field of normalized) {
            view.setUint32(offset, field.byteLength, false);
            offset += 4;
            payload.set(field, offset);
            offset += field.byteLength;
        }
        try {
            const digest = new Uint8Array(
                await crypto.subtle.digest('SHA-256', payload),
            );
            return [...digest]
                .map((byte) => byte.toString(16).padStart(2, '0'))
                .join('');
        } finally {
            payload.fill(0);
            for (const field of normalized) field.fill(0);
        }
    };
    const fingerprintDigest = (fields) =>
        domainDigest('underchat-whatsapp-device-fingerprint-v2', fields);

    const signalApi = requireModule('WAWebSignalStoreApi');
    const signalStorage = requireModule('WAWebSignalStorage');
    const kyberStore = requireModule('WAWebKyberPreKeyStore');
    const pqGating = requireModule('WAWebPQGatingUtils');
    const signalConst = requireModule('WAWebSignalConst');
    const signalCommon = requireModule('WAWebSignalCommonUtils');
    const signalConvert = requireModule('WAWebSignalConvertApi');
    const sessionsApi = requireModule('WASignalSessions');
    const groupSessionsApi = requireModule('WASignalGroupSession');
    const localStorageProto = requireModule('WASignalLocalStorageProtocol.pb');
    const protobufEncoder = requireModule('encodeProtobuf');
    const noiseStoreModule = requireModule('WAWebUserPrefsInfoStore');
    const multiDevice = requireModule('WAWebUserPrefsMultiDevice');
    const syncdDb = requireModule('WAWebSyncdDb');
    const collectionSchema = requireModule('WAWebSchemaCollectionVersion');
    const syncActionsSchema = requireModule('WAWebSchemaSyncActions');
    const connectionModule = requireModule('WAWebConnModel');
    const meUserPrefs = requireModule('WAWebUserPrefsMeUser');
    const userPrefsGeneral = requireModule('WAWebUserPrefsGeneral');
    const mobilePlatforms = requireModule('WAWebMobilePlatforms');
    const lidMigration = requireModule('WAWebLid1X1MigrationGating');

    const signalStore = signalApi?.waSignalStore;
    const noiseStore = noiseStoreModule?.waNoiseInfo;
    if (
        !signalStore ||
        typeof signalStore.getRegistrationInfo !== 'function' ||
        typeof signalStore.getSignedPreKey !== 'function' ||
        typeof signalStore.getADVSignedIdentity !== 'function' ||
        typeof signalStorage?.initialize !== 'function' ||
        typeof kyberStore?.isPQMigrated !== 'function' ||
        typeof kyberStore?.setPQMigrated !== 'function' ||
        typeof kyberStore?.loadKyberKeysForDigest !== 'function' ||
        typeof pqGating?.isPqKeysUploadEnabled !== 'function' ||
        typeof pqGating?.isPq1on1MessageEnabled !== 'function' ||
        typeof sessionsApi?.serializeSession !== 'function' ||
        typeof groupSessionsApi?.serializeSession !== 'function' ||
        !localStorageProto?.RecordStructureSpec ||
        !localStorageProto?.SenderKeyRecordStructureSpec ||
        typeof protobufEncoder?.encodeProtobuf !== 'function' ||
        typeof noiseStore?.get !== 'function' ||
        typeof multiDevice?.getRoutingInfo !== 'function' ||
        typeof userPrefsGeneral?.getLastMobilePlatform !== 'function' ||
        typeof userPrefsGeneral?.getPushname !== 'function' ||
        typeof lidMigration?.Lid1X1MigrationUtils?.isLidMigrated !== 'function'
    ) {
        blockers.add('module_abi.incompatible');
    }

    try {
        await signalStorage?.initialize?.();
    } catch {
        blockers.add('signal_storage.initialize_failed');
    }
    const safeRead = async (read, blocker) => {
        if (typeof read !== 'function') {
            blockers.add(blocker);
            return undefined;
        }
        try {
            return await read();
        } catch {
            blockers.add(blocker);
            return undefined;
        }
    };
    const [registration, signedPreKey, advIdentity, noiseInfo, routingInfo] =
        await Promise.all([
            safeRead(
                () => signalStore.getRegistrationInfo(),
                'device.registration_info_read_failed',
            ),
            safeRead(
                () => signalStore.getSignedPreKey(),
                'device.signed_pre_key_read_failed',
            ),
            safeRead(
                () => signalStore.getADVSignedIdentity(),
                'device.adv_identity_read_failed',
            ),
            safeRead(() => noiseStore.get(), 'device.noise_info_read_failed'),
            safeRead(
                () => multiDevice.getRoutingInfo(),
                'transport.routing_info_read_failed',
            ),
        ]);

    const requiredBytes = (value, length, blocker) => {
        const bytes = toBytes(value);
        if (!bytes || bytes.byteLength !== length) {
            blockers.add(blocker);
            return undefined;
        }
        return new Uint8Array(bytes);
    };
    const identityPublic = requiredBytes(
        registration?.identityKeyPair?.pubKey,
        32,
        'device.identity_public_missing',
    );
    const identityPrivate = requiredBytes(
        registration?.identityKeyPair?.privKey,
        32,
        'device.identity_private_missing',
    );
    const noisePrivate = requiredBytes(
        noiseInfo?.staticKeyPair?.privKey,
        32,
        'device.noise_private_missing',
    );
    const noisePublic = requiredBytes(
        noiseInfo?.staticKeyPair?.pubKey,
        32,
        'device.noise_public_missing',
    );
    const noiseRecoveryToken = requiredBytes(
        noiseInfo?.recoveryToken,
        24,
        'device.noise_recovery_token_missing',
    );
    const noiseCertificateChain = noiseInfo?.certificateChainBuffer
        ? toBytes(noiseInfo.certificateChainBuffer)
        : undefined;
    const routingInfoBytes = toBytes(routingInfo?.edgeRouting ?? routingInfo);
    if (
        !routingInfoBytes ||
        routingInfoBytes.byteLength < 1 ||
        routingInfoBytes.byteLength > 65535
    ) {
        blockers.add('transport.routing_info_missing');
    }
    const signedPrivate = requiredBytes(
        signedPreKey?.keyPair?.privKey,
        32,
        'device.signed_pre_key_missing',
    );
    const signedSignature = requiredBytes(
        signedPreKey?.signature,
        64,
        'device.signed_pre_key_signature_missing',
    );
    const advDetails = toBytes(advIdentity?.details);
    const advAccountSignature = requiredBytes(
        advIdentity?.accountSignature,
        64,
        'device.adv_account_signature_missing',
    );
    const advAccountSignatureKey = requiredBytes(
        advIdentity?.accountSignatureKey,
        32,
        'device.adv_account_signature_key_missing',
    );
    const advDeviceSignature = requiredBytes(
        advIdentity?.deviceSignature,
        64,
        'device.adv_device_signature_missing',
    );
    if (!advDetails || advDetails.byteLength === 0) {
        blockers.add('device.adv_details_missing');
    }

    let advSecret = fromBase64(options.capturedAdvSecret);
    if (!advSecret || advSecret.byteLength !== 32) {
        try {
            const current = await multiDevice?.getADVSecretKey?.();
            advSecret = fromBase64(current);
        } catch {
            advSecret = undefined;
        }
    }
    const advSecretAvailable = advSecret?.byteLength === 32;

    const conn = connectionModule?.Conn;
    const supportedPrimaryPlatforms = new Set(
        Object.values(mobilePlatforms?.PLATFORMS || {}).filter(
            (value) => typeof value === 'string',
        ),
    );
    const storedPrimaryPlatform = await safeRead(
        () => userPrefsGeneral?.getLastMobilePlatform?.(),
        'device.platform_read_failed',
    );
    const primaryPlatform = [conn?.platform, storedPrimaryPlatform].find(
        (value) =>
            typeof value === 'string' && supportedPrimaryPlatforms.has(value),
    );
    if (!primaryPlatform) blockers.add('device.platform_missing');
    const pushName = await safeRead(
        () => userPrefsGeneral?.getPushname?.(),
        'device.push_name_read_failed',
    );
    const lidMigrated =
        (await safeRead(
            () => lidMigration?.Lid1X1MigrationUtils?.isLidMigrated?.(),
            'device.lid_migration_state_read_failed',
        )) === true;
    // The canonical device JID identifies the linked companion, not merely
    // the WhatsApp account. Current Web builds expose the complete WID (with
    // its `:device` component) through the device getters. Older private ABIs
    // only exposed the user getters, so retain those as a compatibility
    // fallback without letting them erase a device ID that is available.
    const jid =
        widString(meUserPrefs?.getMaybeMeDevicePn?.()) ||
        widString(meUserPrefs?.getMaybeMePnUser?.()) ||
        widString(conn?.wid || conn?.me || conn?.meUser);
    const lid =
        widString(meUserPrefs?.getMaybeMeDeviceLid?.()) ||
        widString(meUserPrefs?.getMaybeMeLidUser?.()) ||
        widString(conn?.lid || conn?.meLid || conn?.lidWid) ||
        null;
    if (!jid) blockers.add('device.jid_missing');
    if (lid && !lidMigrated) blockers.add('device.lid_migration_state_missing');
    if (
        !Number.isSafeInteger(registration?.registrationId) ||
        registration.registrationId < 0 ||
        registration.registrationId > 0xffffffff
    ) {
        blockers.add('device.registration_id_missing');
    }
    if (
        !Number.isSafeInteger(signedPreKey?.keyId) ||
        signedPreKey.keyId < 0 ||
        signedPreKey.keyId > 0xffffff
    ) {
        blockers.add('device.signed_pre_key_id_missing');
    }

    const fingerprint = await fingerprintDigest([
        identityPublic,
        advDetails,
        advAccountSignatureKey,
        advAccountSignature,
        advDeviceSignature,
    ]);
    if (!fingerprint) blockers.add('device.fingerprint_missing');

    let firstUnuploaded = 1;
    let nextPreKeyId = 1;
    try {
        [firstUnuploaded, nextPreKeyId] = await Promise.all([
            signalStore.getMeta(signalConst.META_KEYS.FIRST_UNUPLOAD_PK_ID),
            signalStore.getMeta(signalConst.META_KEYS.NEXT_PK_ID),
        ]);
        firstUnuploaded = Number(firstUnuploaded || 1);
        nextPreKeyId = Number(nextPreKeyId || firstUnuploaded || 1);
    } catch {
        blockers.add('device.pre_key_counters_unavailable');
    }

    let pqMigrated = false;
    let pqUploadEnabled = false;
    let pqMessagingEnabled = false;
    let pqStorageMode = 'unknown';
    let pqServerCountMode = 'reset';
    let pqPreKeyCount = 0;
    let pqLastResortKeyCount = 0;
    const pqPreKeyRows = [];
    const pqPreKeyStateRows = [];
    const pqPrivateKeyCopies = [];
    try {
        [pqMigrated, pqUploadEnabled, pqMessagingEnabled] = await Promise.all([
            kyberStore.isPQMigrated().then(Boolean),
            Promise.resolve(Boolean(pqGating.isPqKeysUploadEnabled())),
            Promise.resolve(Boolean(pqGating.isPq1on1MessageEnabled())),
        ]);
        const pqTables = [];
        let missingPqTables = 0;
        for (const getterName of [
            'getKyberPreKeyTable',
            'getKyberLastResortKeyTable',
        ]) {
            try {
                const table = signalStorage?.[getterName]?.();
                if (!table || typeof table.all !== 'function') {
                    throw new Error('invalid_table');
                }
                pqTables.push(table);
            } catch (error) {
                if (error?.name !== 'NoSuchTableError') throw error;
                missingPqTables += 1;
            }
        }
        if (missingPqTables === 0) {
            const [preKeys, lastResortKeys] = await Promise.all(
                pqTables.map((table) => table.all()),
            );
            if (!Array.isArray(preKeys) || !Array.isArray(lastResortKeys)) {
                throw new Error('invalid_rows');
            }
            pqStorageMode = 'legacy_tables';
            // WhatsApp Web does not expose Baileys' last observed server count.
            // `unknown` tells the PostgreSQL store to retain the existing pair
            // atomically instead of turning a loss of observability into NULL.
            pqServerCountMode = 'unknown';
            const nextPqPreKeyId = Number(
                await kyberStore.getNextKyberPreKeyId?.(),
            );
            if (
                !Number.isSafeInteger(nextPqPreKeyId) ||
                nextPqPreKeyId < 0 ||
                nextPqPreKeyId >= 0xffffff
            ) {
                blockers.add('post_quantum.allocator_incompatible');
            } else {
                pqPreKeyStateRows.push({
                    codec_version: 1,
                    algorithm: 'ML-KEM-1024',
                    next_pre_key_id: nextPqPreKeyId,
                    migrated: pqMigrated,
                    last_server_count: null,
                    last_server_count_timestamp_ms: null,
                });
            }
            if (lastResortKeys.length > 1) {
                blockers.add('post_quantum.last_resort_key_ambiguous');
            }
            const seenPqKeyIds = new Set();
            for (const [keyKind, rows] of [
                ['one_time', preKeys],
                ['last_resort', lastResortKeys],
            ]) {
                for (const row of rows) {
                    const keyId = Number(row?.keyId);
                    const publicKey = toBytes(row?.keyPair?.pubKey);
                    const privateKey = toBytes(row?.keyPair?.privKey);
                    const signature = toBytes(row?.signature);
                    const timestampMs = Number(row?.timestamp);
                    const sentToServer =
                        keyKind === 'one_time' ? row?.sentToServer : pqMigrated;
                    if (
                        !Number.isSafeInteger(keyId) ||
                        keyId < 0 ||
                        keyId >= 0xffffff ||
                        seenPqKeyIds.has(keyId) ||
                        !publicKey ||
                        publicKey.byteLength !== 1568 ||
                        !privateKey ||
                        privateKey.byteLength !== 3168 ||
                        !signature ||
                        signature.byteLength !== 64 ||
                        !Number.isSafeInteger(timestampMs) ||
                        timestampMs < 0 ||
                        typeof sentToServer !== 'boolean'
                    ) {
                        blockers.add('post_quantum.row_incompatible');
                        continue;
                    }
                    seenPqKeyIds.add(keyId);
                    const privateKeyCopy = new Uint8Array(privateKey);
                    pqPrivateKeyCopies.push(privateKeyCopy);
                    pqPreKeyRows.push({
                        key_id: keyId,
                        key_kind: keyKind,
                        public_key: toBase64(publicKey, 1568),
                        private_key: toBase64(privateKeyCopy, 3168),
                        signature: toBase64(signature, 64),
                        timestamp_ms: timestampMs,
                        sent_to_server: sentToServer,
                    });
                }
            }
            pqPreKeyRows.sort((left, right) => left.key_id - right.key_id);
            pqPreKeyCount = pqPreKeyRows.filter(
                (row) => row.key_kind === 'one_time',
            ).length;
            pqLastResortKeyCount = pqPreKeyRows.filter(
                (row) => row.key_kind === 'last_resort',
            ).length;
            if (pqMigrated && pqLastResortKeyCount === 0) {
                blockers.add('post_quantum.migrated_state_incomplete');
            }
            if (
                (!pqMigrated &&
                    pqPreKeyRows.some((row) => row.sent_to_server)) ||
                (!pqMigrated && pqPreKeyCount > 0 && pqLastResortKeyCount !== 1)
            ) {
                blockers.add('post_quantum.migration_state_diverged');
            }
        } else if (missingPqTables === 2) {
            // Feature flags do not prove that a managed store is empty. A
            // rollout can be disabled while dormant/rollback key material is
            // still present, and silently exporting that as an empty legacy
            // projection would destroy the companion's PQ state.
            let digestState;
            try {
                digestState = await kyberStore.loadKyberKeysForDigest();
            } catch (error) {
                if (
                    error?.name === 'NoSuchTableError' &&
                    !pqMigrated &&
                    !pqUploadEnabled &&
                    !pqMessagingEnabled
                ) {
                    // The audited legacy implementation builds its digest by
                    // reopening these exact physical tables. If both getters
                    // and that digest path report NoSuchTable while every PQ
                    // rollout flag is inactive, there is no alternate managed
                    // store and physical absence is the empty-state proof.
                    digestState = {
                        kyberPreKeys: [],
                        kyberLastResortKeys: [],
                    };
                } else {
                    throw error;
                }
            }
            if (
                !Array.isArray(digestState?.kyberPreKeys) ||
                !Array.isArray(digestState?.kyberLastResortKeys)
            ) {
                throw new Error('invalid_managed_store');
            }
            pqPreKeyCount = digestState.kyberPreKeys.length;
            pqLastResortKeyCount = digestState.kyberLastResortKeys.length;
            if (
                !pqMigrated &&
                pqPreKeyCount === 0 &&
                pqLastResortKeyCount === 0 &&
                ((!pqUploadEnabled && !pqMessagingEnabled) || pqRollbackValid)
            ) {
                pqStorageMode = 'rollout_without_tables';
            } else {
                pqStorageMode = 'managed_store';
                blockers.add('post_quantum.private_material_unavailable');
                if (pqMigrated && pqLastResortKeyCount === 0) {
                    blockers.add('post_quantum.migrated_state_incomplete');
                }
                if (pqUploadEnabled && !pqMigrated) {
                    blockers.add('post_quantum.regeneration_pending');
                }
            }
        } else {
            blockers.add('post_quantum.storage_incompatible');
        }
    } catch {
        blockers.add('post_quantum.capability_read_failed');
    }

    const identityRows = [];
    for (const row of await all(
        signalStorage?.getIdentityTable?.(),
        'identity_keys.read_failed',
    )) {
        const address = parseSignalAddress(row?.identifier);
        const signalIdentity = signalCommon?.strToBuffer?.(row?.identityKey);
        let bytes = toBytes(signalIdentity);
        if (bytes?.byteLength === 33 && bytes[0] === 5) {
            bytes = bytes.subarray(1);
        }
        if (
            !address ||
            address.scope !== 'default' ||
            !bytes ||
            bytes.byteLength !== 32
        ) {
            blockers.add('identity_keys.row_incompatible');
            continue;
        }
        identityRows.push({
            their_id: address.their_id,
            identity: toBase64(bytes, 32),
        });
    }

    const preKeyRows = [];
    for (const row of await all(
        signalStorage?.getPreKeyTable?.(),
        'pre_keys.read_failed',
    )) {
        const keyId = Number(row?.keyId);
        const privateKey = toBytes(row?.keyPair?.privKey);
        if (
            !Number.isSafeInteger(keyId) ||
            keyId < 0 ||
            keyId > 0xffffff ||
            !privateKey ||
            privateKey.byteLength !== 32
        ) {
            blockers.add('pre_keys.row_incompatible');
            continue;
        }
        preKeyRows.push({
            key_id: keyId,
            key: toBase64(privateKey, 32),
            uploaded: keyId < firstUnuploaded,
        });
    }

    const signalSessionRows = [];
    const signalAddresses = new Set();
    for (const row of await all(
        signalStorage?.getSessionTable?.(),
        'signal_sessions.read_failed',
    )) {
        const address = parseSignalAddress(row?.address);
        let serialized;
        try {
            const session = await signalConvert.maybeConvertSession(
                row.session,
            );
            serialized = encodeProto(
                protobufEncoder,
                localStorageProto.RecordStructureSpec,
                sessionsApi.serializeSession(session),
            );
        } catch {
            // The row is rejected by the shared compatibility path below.
        }
        const key = address
            ? `${address.their_id}\0${address.scope}`
            : undefined;
        if (
            !address ||
            !serialized ||
            serialized.byteLength === 0 ||
            serialized.byteLength > 8 * 1024 * 1024 ||
            signalAddresses.has(key)
        ) {
            blockers.add('signal_sessions.row_incompatible');
            continue;
        }
        signalAddresses.add(key);
        signalSessionRows.push({
            ...address,
            session: toBase64(serialized),
        });
    }

    const senderKeyRows = [];
    const senderAddresses = new Set();
    for (const row of await all(
        signalStorage?.getSenderKeyTable?.(),
        'sender_keys.read_failed',
    )) {
        const separator =
            typeof row?.senderKeyName === 'string'
                ? row.senderKeyName.indexOf('::')
                : -1;
        const chatId =
            separator > 0 ? row.senderKeyName.slice(0, separator) : undefined;
        const address =
            separator > 0
                ? parseSignalAddress(row.senderKeyName.slice(separator + 2))
                : undefined;
        let serialized;
        try {
            const senderKey = signalConvert.maybeConvertSenderKey(
                row.senderKey,
            );
            serialized = encodeProto(
                protobufEncoder,
                localStorageProto.SenderKeyRecordStructureSpec,
                groupSessionsApi.serializeSession(senderKey),
            );
        } catch {
            // The row is rejected by the shared compatibility path below.
        }
        const key =
            chatId && address && address.scope === 'default'
                ? `${chatId}\0${address.their_id}`
                : undefined;
        if (
            !key ||
            !serialized ||
            serialized.byteLength === 0 ||
            serialized.byteLength > 2 * 1024 * 1024 ||
            senderAddresses.has(key)
        ) {
            blockers.add('sender_keys.row_incompatible');
            continue;
        }
        senderAddresses.add(key);
        senderKeyRows.push({
            chat_id: chatId,
            sender_id: address.their_id,
            sender_key: toBase64(serialized),
        });
    }

    const appStateSyncKeyRows = [];
    let syncKeys;
    try {
        syncKeys = await syncdDb?.getAllSyncKeys?.();
        if (!Array.isArray(syncKeys)) throw new Error('invalid');
    } catch {
        blockers.add('app_state_sync_keys.read_failed');
        syncKeys = [];
    }
    for (const row of syncKeys) {
        const keyId = toBytes(row?.keyId);
        const keyData = toBytes(row?.keyData);
        const encodedFingerprint = encodeFingerprint(row?.fingerprint);
        if (
            !keyId ||
            keyId.byteLength === 0 ||
            !keyData ||
            keyData.byteLength !== 32 ||
            !encodedFingerprint ||
            !Number.isSafeInteger(row?.timestamp) ||
            row.timestamp < 0
        ) {
            blockers.add('app_state_sync_keys.row_incompatible');
            continue;
        }
        const derivedKeyEpoch =
            keyId[keyId.byteLength - 2] * 256 + keyId[keyId.byteLength - 1];
        if (row.keyEpoch !== derivedKeyEpoch) {
            blockers.add('app_state_sync_keys.key_epoch_incompatible');
        }
        appStateSyncKeyRows.push({
            key_id: toBase64(keyId),
            key_data: toBase64(keyData, 32),
            timestamp: row.timestamp,
            fingerprint: toBase64(encodedFingerprint),
        });
    }

    const appStateVersionRows = [];
    const appStateVersionSourceRows = await all(
        collectionSchema?.getCollectionVersionTable?.(),
        'app_state_versions.read_failed',
    );
    const appStateVersionIncompatibleSamples = [];
    let appStateVersionIncompatibleCount = 0;
    for (const row of appStateVersionSourceRows) {
        const hash = toBytes(row?.ltHash);
        if (
            typeof row?.collection !== 'string' ||
            !row.collection ||
            !Number.isSafeInteger(row.version) ||
            row.version < 0 ||
            !hash ||
            hash.byteLength !== 128
        ) {
            blockers.add('app_state_versions.row_incompatible');
            appStateVersionIncompatibleCount += 1;
            if (appStateVersionIncompatibleSamples.length < 3) {
                const describeValue = (value) => ({
                    type: typeof value,
                    constructor:
                        typeof value === 'object' && value !== null
                            ? String(
                                  value.constructor?.name || 'unknown',
                              ).slice(0, 80)
                            : null,
                });
                appStateVersionIncompatibleSamples.push({
                    columns:
                        typeof row === 'object' && row !== null
                            ? Object.keys(row)
                                  .filter((key) =>
                                      /^[A-Za-z0-9_$]{1,80}$/u.test(key),
                                  )
                                  .sort()
                                  .slice(0, 32)
                            : [],
                    column_types:
                        typeof row === 'object' && row !== null
                            ? Object.keys(row)
                                  .filter((key) =>
                                      /^[A-Za-z0-9_$]{1,80}$/u.test(key),
                                  )
                                  .sort()
                                  .slice(0, 32)
                                  .map((key) => ({
                                      name: key,
                                      ...describeValue(row[key]),
                                  }))
                            : [],
                    collection: describeValue(row?.collection),
                    version: describeValue(row?.version),
                    bytes: {
                        ...describeValue(row?.ltHash),
                        length: Number.isSafeInteger(hash?.byteLength)
                            ? hash.byteLength
                            : null,
                    },
                    state: {
                        ...describeValue(row?.state),
                        code:
                            typeof row?.state === 'string' &&
                            /^[A-Za-z0-9_.:-]{1,80}$/u.test(row.state)
                                ? row.state
                                : null,
                        columns:
                            typeof row?.state === 'object' && row.state !== null
                                ? Object.keys(row.state)
                                      .filter((key) =>
                                          /^[A-Za-z0-9_$]{1,80}$/u.test(key),
                                      )
                                      .sort()
                                      .slice(0, 32)
                                : [],
                        version: describeValue(row?.state?.version),
                        lt_hash: {
                            ...describeValue(row?.state?.ltHash),
                            length: Number.isSafeInteger(
                                toBytes(row?.state?.ltHash)?.byteLength,
                            )
                                ? toBytes(row.state.ltHash).byteLength
                                : null,
                        },
                        hash: {
                            ...describeValue(row?.state?.hash),
                            length: Number.isSafeInteger(
                                toBytes(row?.state?.hash)?.byteLength,
                            )
                                ? toBytes(row.state.hash).byteLength
                                : null,
                        },
                        finite_failure_started:
                            Number.isFinite(row?.finiteFailureStartTime) &&
                            row.finiteFailureStartTime > 0,
                    },
                });
            }
            continue;
        }
        appStateVersionRows.push({
            name: row.collection,
            version: row.version,
            hash: toBase64(hash, 128),
        });
    }
    if (appStateVersionIncompatibleCount > 0) {
        diagnostics.app_state_versions = {
            row_count: appStateVersionSourceRows.length,
            incompatible_count: appStateVersionIncompatibleCount,
            samples: appStateVersionIncompatibleSamples,
        };
    }

    const appStateMutationMacRows = [];
    const mutationMacKeys = new Set();
    for (const row of await all(
        syncActionsSchema?.getSyncActionsTable?.(),
        'app_state_mutation_macs.read_failed',
    )) {
        const indexMac = toBytes(row?.indexMac);
        const valueMac = toBytes(row?.valueMac);
        if (
            typeof row?.collection !== 'string' ||
            !row.collection ||
            !Number.isSafeInteger(row.version) ||
            row.version < 0 ||
            !indexMac ||
            indexMac.byteLength !== 32 ||
            !valueMac ||
            valueMac.byteLength !== 32
        ) {
            blockers.add('app_state_mutation_macs.row_incompatible');
            continue;
        }
        const indexMacEncoded = toBase64(indexMac, 32);
        const key = `${row.collection}\0${indexMacEncoded}\0${row.version}`;
        if (mutationMacKeys.has(key)) continue;
        mutationMacKeys.add(key);
        appStateMutationMacRows.push({
            name: row.collection,
            version: row.version,
            index_mac: indexMacEncoded,
            value_mac: toBase64(valueMac, 32),
        });
    }

    if (
        pqRollbackValid &&
        (pqMigrated || pqPreKeyCount !== 0 || pqLastResortKeyCount !== 0)
    ) {
        blockers.add('post_quantum.server_rollback_state_not_empty');
    }
    const handoffSignalSessionRows = pqRollbackValid
        ? signalSessionRows.filter((row) => row.scope === 'default')
        : signalSessionRows;
    const tables = {
        identity_keys: addRows(identityRows),
        pre_keys: addRows(preKeyRows),
        pq_pre_keys: addRows(pqPreKeyRows),
        pq_pre_key_state: addRows(pqPreKeyStateRows),
        signal_sessions: addRows(handoffSignalSessionRows),
        sender_keys: addRows(senderKeyRows),
        app_state_sync_keys: addRows(appStateSyncKeyRows),
        app_state_versions: addRows(appStateVersionRows),
        app_state_mutation_macs: addRows(appStateMutationMacRows),
    };
    const device = {
        jid: jid || '',
        lid,
        facebook_uuid: null,
        registration_id: registration?.registrationId,
        noise_key: noisePrivate ? toBase64(noisePrivate, 32) : '',
        identity_key: identityPrivate ? toBase64(identityPrivate, 32) : '',
        signed_pre_key: signedPrivate ? toBase64(signedPrivate, 32) : '',
        signed_pre_key_id: signedPreKey?.keyId,
        signed_pre_key_sig: signedSignature
            ? toBase64(signedSignature, 64)
            : '',
        adv_secret_available: advSecretAvailable,
        adv_key: advSecretAvailable ? toBase64(advSecret, 32) : null,
        adv_details: advDetails ? toBase64(advDetails) : '',
        adv_account_sig: advAccountSignature
            ? toBase64(advAccountSignature, 64)
            : '',
        adv_account_sig_key: advAccountSignatureKey
            ? toBase64(advAccountSignatureKey, 32)
            : '',
        adv_device_sig: advDeviceSignature
            ? toBase64(advDeviceSignature, 64)
            : '',
        platform: primaryPlatform || '',
        business_name: '',
        push_name: typeof pushName === 'string' ? pushName : '',
        // WhatsApp Web only exposes a boolean migration-completion proof. The
        // shared store deliberately reconstructs that proof from durable
        // device state instead of trusting provider metadata, so persist a
        // stable positive marker when the private ABI confirms completion.
        // A constant keeps repeated checkpoints byte-stable.
        lid_migration_ts: lidMigrated ? 1 : 0,
        next_pre_key_id: nextPreKeyId,
        device_fingerprint: fingerprint || '',
    };
    const providerState =
        noisePublic && noiseRecoveryToken && fingerprint
            ? {
                  kind: 'wwebjs-noise-bootstrap-v1',
                  codec_version: 1,
                  device_fingerprint: fingerprint,
                  noise_public_key: toBase64(noisePublic, 32),
                  recovery_token: toBase64(noiseRecoveryToken, 24),
                  certificate_chain: noiseCertificateChain
                      ? toBase64(noiseCertificateChain)
                      : null,
              }
            : null;
    const transportState = routingInfoBytes
        ? {
              kind: 'whatsapp-transport-v1',
              codec_version: 1,
              routing_info: toBase64(routingInfoBytes),
          }
        : null;
    for (const secret of [
        identityPrivate,
        noisePrivate,
        noiseRecoveryToken,
        signedPrivate,
        advSecret,
        ...pqPrivateKeyCopies,
    ]) {
        secret?.fill?.(0);
    }
    return {
        kind: 'wwebjs-canonical-session-v1',
        codec_version: 1,
        module_abi: 'wwebjs-private-modules-v1',
        web_version: window.Debug?.VERSION || 'unknown',
        fingerprint_version: 'underchat-whatsapp-device-fingerprint-v2',
        complete: blockers.size === 0,
        blockers: [...blockers].sort(),
        ...(Object.keys(diagnostics).length > 0 ? { diagnostics } : {}),
        capabilities: {
            adv_secret_available: advSecretAvailable,
            passkey_handoff_supported: advSecretAvailable,
            signal_scopes: ['default', 'status', 'pq'],
            signal_domain_types: [0, 1, 128, 129],
            app_state_import_mode: 'snapshot_resync',
            canonical_signal_session_scopes: pqRollbackValid
                ? ['default']
                : ['default', 'status', 'pq'],
            canonical_signal_session_resync_required: pqRollbackValid,
            canonical_signal_session_resync_scopes: pqRollbackValid
                ? ['status', 'pq']
                : [],
            pq_migrated: pqMigrated,
            pq_upload_enabled: pqUploadEnabled,
            pq_messaging_enabled: pqMessagingEnabled,
            pq_storage_mode: pqStorageMode,
            pq_server_count_mode: pqServerCountMode,
            pq_pre_key_count: pqPreKeyCount,
            pq_last_resort_key_count: pqLastResortKeyCount,
            ...(pqRollbackValid
                ? {
                      pq_server_rollback_acknowledged: true,
                      pq_server_rollback_protocol:
                          'delete_pq_prekeys_server_ack_v1',
                      pq_server_rollback_handoff_id: pqRollback.handoff_id,
                      pq_server_rollback_lifecycle_operation_id:
                          pqRollback.lifecycle_operation_id,
                      pq_server_rollback_source_revision_id: String(
                          pqRollback.source_revision_id,
                      ),
                      pq_server_rollback_owner_id: pqRollback.owner_id,
                      pq_server_rollback_fencing_token: String(
                          pqRollback.fencing_token,
                      ),
                      pq_server_rollback_generation: pqRollback.generation,
                      pq_server_rollback_epoch: pqRollback.epoch,
                      pq_server_rollback_acknowledged_at_ms:
                          pqRollback.acknowledged_at_ms,
                      pq_server_rollback_response_validated: true,
                      pq_upload_lifecycle_fenced: true,
                      pq_upload_lifecycle_fence_version: 1,
                      pq_runtime_upload_enabled:
                          pqRollback.runtime_upload_enabled,
                      pq_runtime_messaging_enabled:
                          pqRollback.runtime_messaging_enabled,
                  }
                : {}),
            lid_migrated: lidMigrated,
        },
        device,
        provider_state: providerState,
        transport_state: transportState,
        tables,
        record_count: recordCount,
        size_bytes: sizeBytes,
    };
}

/* This function is serialized by Puppeteer and executes in the page realm. */
async function importCanonicalSessionProjection(projection, options) {
    // A canonical cross-provider import can legitimately spend more than the
    // Puppeteer protocol default inside IndexedDB-backed private APIs (notably
    // while a fresh WWeb profile creates its signal-store tables).  Do not keep
    // that work attached to one long Runtime.callFunctionOn request: it hides
    // the import stage and makes Chromium abort the otherwise recoverable
    // hydration at Puppeteer's transport deadline.
    //
    // The task modes intentionally live in this serialized function instead
    // of a Node closure.  `page.evaluate()` serializes this function into the
    // WhatsApp document, where the named-function binding lets the short
    // `start` invocation launch the regular import asynchronously and return
    // immediately.  Node then polls only a safe, aggregate task state.  No
    // credential material is exposed through the task status object.
    const backgroundTaskKey = '__WWebCanonicalImportTaskV1';
    const backgroundTaskMode = options?.backgroundTaskMode;
    const backgroundTaskId =
        typeof options?.backgroundTaskId === 'string' &&
        /^[a-f0-9-]{16,128}$/iu.test(options.backgroundTaskId)
            ? options.backgroundTaskId
            : undefined;
    const safeTaskErrorCode = (error) => {
        const candidate = String(error?.code || error?.message || '');
        const controlled = /wwebjs_canonical_[a-z0-9_]+/iu.exec(candidate)?.[0];
        return controlled
            ? controlled.toLowerCase()
            : 'wwebjs_canonical_import_task_failed';
    };
    const taskSnapshot = (task) => ({
        task_id: task.id,
        status: task.status,
        stage: task.stage,
        duration_ms: Math.max(0, Date.now() - task.started_at_ms),
        ...(Number.isSafeInteger(task.progress_completed) &&
        Number.isSafeInteger(task.progress_total) &&
        task.progress_completed >= 0 &&
        task.progress_completed <= task.progress_total
            ? {
                  progress_completed: task.progress_completed,
                  progress_total: task.progress_total,
              }
            : {}),
        ...(task.error_code ? { error_code: task.error_code } : {}),
    });
    const activeTask = () => {
        const candidate = window[backgroundTaskKey];
        return candidate?.id === backgroundTaskId ? candidate : undefined;
    };

    if (backgroundTaskMode === 'start') {
        if (!backgroundTaskId) {
            throw new Error('wwebjs_canonical_import_task_id_invalid');
        }
        const existing = window[backgroundTaskKey];
        if (existing?.status === 'running') {
            throw new Error('wwebjs_canonical_import_task_already_running');
        }
        const task = {
            id: backgroundTaskId,
            status: 'running',
            stage: 'projection_validation',
            started_at_ms: Date.now(),
            updated_at_ms: Date.now(),
            cancelled: false,
        };
        // Keep an eventual result in this invocation's closure rather than a
        // serializable global property. The next short `consume` evaluation
        // can call these closures, while `observe` can never expose it.
        let completionResult;
        task.consumeResult = () => {
            const result = completionResult;
            completionResult = undefined;
            return result;
        };
        task.clearResult = () => {
            completionResult = undefined;
        };
        window[backgroundTaskKey] = task;
        // Keep only opaque task state in the global registry. The projection
        // is captured by this promise chain until the import settles and is
        // never added to a serializable status object.
        void new Promise((resolve) => setTimeout(resolve, 0))
            .then(() =>
                importCanonicalSessionProjection(projection, {
                    ...options,
                    backgroundTaskMode: 'run',
                    backgroundTaskId,
                }),
            )
            .then(
                (result) => {
                    if (task.cancelled) return;
                    task.status = 'completed';
                    task.stage = 'completed';
                    completionResult = result;
                    task.updated_at_ms = Date.now();
                },
                (error) => {
                    if (task.cancelled) return;
                    task.status = 'failed';
                    task.error_code = safeTaskErrorCode(error);
                    task.updated_at_ms = Date.now();
                },
            );
        return taskSnapshot(task);
    }

    if (backgroundTaskMode === 'observe') {
        if (!backgroundTaskId) {
            throw new Error('wwebjs_canonical_import_task_id_invalid');
        }
        const task = activeTask();
        if (!task) {
            throw new Error('wwebjs_canonical_import_task_missing');
        }
        return taskSnapshot(task);
    }

    if (backgroundTaskMode === 'consume') {
        if (!backgroundTaskId) {
            throw new Error('wwebjs_canonical_import_task_id_invalid');
        }
        const task = activeTask();
        if (!task) {
            throw new Error('wwebjs_canonical_import_task_missing');
        }
        if (task.status === 'running') {
            throw new Error('wwebjs_canonical_import_task_still_running');
        }
        if (task.status !== 'completed') {
            throw new Error(
                task.error_code || 'wwebjs_canonical_import_task_failed',
            );
        }
        const result = task.consumeResult?.();
        task.clearResult?.();
        task.consumeResult = undefined;
        task.clearResult = undefined;
        delete window[backgroundTaskKey];
        if (!result || typeof result !== 'object') {
            throw new Error('wwebjs_canonical_import_task_result_missing');
        }
        return result;
    }

    if (backgroundTaskMode === 'cancel') {
        if (!backgroundTaskId) {
            throw new Error('wwebjs_canonical_import_task_id_invalid');
        }
        const task = activeTask();
        if (!task) return false;
        task.cancelled = true;
        task.status = 'cancelled';
        task.stage = 'cancelled';
        task.error_code = 'wwebjs_canonical_import_task_cancelled';
        task.clearResult?.();
        task.consumeResult = undefined;
        task.clearResult = undefined;
        task.updated_at_ms = Date.now();
        delete window[backgroundTaskKey];
        return true;
    }

    if (backgroundTaskMode !== undefined && backgroundTaskMode !== 'run') {
        throw new Error('wwebjs_canonical_import_task_mode_invalid');
    }

    const task =
        backgroundTaskMode === 'run' && backgroundTaskId
            ? activeTask()
            : undefined;
    if (backgroundTaskMode === 'run' && !task) {
        throw new Error('wwebjs_canonical_import_task_missing');
    }
    const taskDeadlineAtMs = options?.backgroundTaskDeadlineAtMs;
    if (
        backgroundTaskMode === 'run' &&
        (!Number.isSafeInteger(taskDeadlineAtMs) ||
            taskDeadlineAtMs <= task.started_at_ms)
    ) {
        throw new Error('wwebjs_canonical_import_task_timeout_invalid');
    }
    const setImportStage = (stage) => {
        if (task?.cancelled) {
            throw new Error('wwebjs_canonical_import_task_cancelled');
        }
        if (task && Date.now() >= taskDeadlineAtMs) {
            throw new Error('wwebjs_canonical_import_task_timeout');
        }
        if (task) {
            if (task.stage !== stage) {
                task.progress_completed = undefined;
                task.progress_total = undefined;
            }
            task.stage = stage;
            task.updated_at_ms = Date.now();
        }
        return stage;
    };
    const setImportProgress = (completed, total) => {
        if (
            !Number.isSafeInteger(completed) ||
            !Number.isSafeInteger(total) ||
            completed < 0 ||
            completed > total
        ) {
            throw new Error('wwebjs_canonical_import_progress_invalid');
        }
        if (task) {
            task.progress_completed = completed;
            task.progress_total = total;
            task.updated_at_ms = Date.now();
        }
    };
    const fail = (code) => {
        throw new Error(code);
    };
    // Keep this helper inside the Puppeteer-serialized function. A module-level
    // closure is unavailable in the WhatsApp page realm and would turn an
    // otherwise valid public sender-key state into an opaque import failure.
    const normalizeCanonicalSenderKeyRecord = (record) => {
        if (!record || !Array.isArray(record.senderKeyStates)) return record;

        let normalized = false;
        const senderKeyStates = record.senderKeyStates.map((state) => {
            const signingKey = state?.senderSigningKey;
            const privateKey = signingKey?.private;
            if (
                !(privateKey instanceof Uint8Array) ||
                privateKey.byteLength !== 0
            ) {
                return state;
            }

            const senderSigningKey = { ...signingKey };
            delete senderSigningKey.private;
            normalized = true;
            return { ...state, senderSigningKey };
        });

        return normalized ? { ...record, senderKeyStates } : record;
    };
    setImportStage('projection_validation');
    let currentImportStage;
    const importStep = async (stage, operation) => {
        currentImportStage = setImportStage(stage);
        try {
            const result = await operation();
            // An individual IndexedDB/private-module promise can take longer
            // than expected. Recheck the task fence after it settles so a
            // late final operation cannot be reported as a successful import.
            setImportStage(stage);
            return result;
        } catch (error) {
            if (/^wwebjs_canonical_/u.test(String(error?.message || ''))) {
                throw error;
            }
            fail(`wwebjs_canonical_import_${stage}_failed`);
        }
    };
    const signalComponentNames = [
        'identity_keys',
        'pre_keys',
        'pq_pre_keys',
        'signal_sessions',
        'sender_keys',
    ];
    const requestedSignalComponents = options?.preserveExistingSignalComponents;
    const requestedSignalComponentKeys =
        requestedSignalComponents &&
        typeof requestedSignalComponents === 'object' &&
        !Array.isArray(requestedSignalComponents)
            ? Object.keys(requestedSignalComponents)
            : [];
    const requestedSignalComponentsValid =
        requestedSignalComponents === undefined ||
        (requestedSignalComponents &&
            typeof requestedSignalComponents === 'object' &&
            !Array.isArray(requestedSignalComponents) &&
            Object.getPrototypeOf(requestedSignalComponents) ===
                Object.prototype &&
            requestedSignalComponentKeys.length ===
                signalComponentNames.length &&
            signalComponentNames.every(
                (name) =>
                    Object.hasOwn(requestedSignalComponents, name) &&
                    typeof requestedSignalComponents[name] === 'boolean',
            ) &&
            requestedSignalComponentKeys.every((name) =>
                signalComponentNames.includes(name),
            ));
    if (
        !projection ||
        projection.kind !== 'wwebjs-canonical-session-v1' ||
        projection.codec_version !== 1 ||
        projection.module_abi !== 'wwebjs-private-modules-v1' ||
        projection.fingerprint_version !==
            'underchat-whatsapp-device-fingerprint-v2' ||
        options?.moduleAbi !== 'wwebjs-private-modules-v1' ||
        projection.complete !== true ||
        !projection.device ||
        !projection.tables ||
        !Array.isArray(projection.tables.pq_pre_keys) ||
        !Array.isArray(projection.tables.pq_pre_key_state) ||
        (options?.preserveExistingAppState !== undefined &&
            typeof options.preserveExistingAppState !== 'boolean') ||
        (options?.preserveExistingSignalTables !== undefined &&
            typeof options.preserveExistingSignalTables !== 'boolean') ||
        (options?.preserveExistingSignalTables === true &&
            options?.preserveExistingAppState !== true) ||
        !requestedSignalComponentsValid ||
        (requestedSignalComponents !== undefined &&
            (options?.preserveExistingAppState !== true ||
                options?.preserveExistingSignalTables === true))
    ) {
        fail('wwebjs_canonical_projection_incompatible');
    }
    const preserveExistingAppState = options?.preserveExistingAppState === true;
    const preserveExistingSignalTables =
        options?.preserveExistingSignalTables === true;
    const preserveExistingSignalComponents = Object.freeze(
        Object.fromEntries(
            signalComponentNames.map((name) => [
                name,
                preserveExistingSignalTables ||
                    requestedSignalComponents?.[name] === true,
            ]),
        ),
    );
    const preservedSignalComponents = signalComponentNames.filter(
        (name) => preserveExistingSignalComponents[name],
    );
    const replacedSignalComponents = signalComponentNames.filter(
        (name) => !preserveExistingSignalComponents[name],
    );
    const pqPairValidationProof = options?.pqPairValidationProof;
    if (
        pqPairValidationProof !== undefined &&
        (!pqPairValidationProof ||
            pqPairValidationProof.version !== 1 ||
            pqPairValidationProof.algorithm !== 'ML-KEM-1024' ||
            !Number.isSafeInteger(pqPairValidationProof.key_count) ||
            pqPairValidationProof.key_count < 1 ||
            !/^[a-f0-9]{64}$/u.test(
                String(pqPairValidationProof.commitment || ''),
            ))
    ) {
        fail('wwebjs_canonical_pq_validation_proof_invalid');
    }

    const requireModule = (name) => {
        try {
            const moduleValue = window.require?.(name);
            if (!moduleValue) fail('wwebjs_canonical_module_abi_incompatible');
            return moduleValue.default || moduleValue;
        } catch (error) {
            if (error?.message === 'wwebjs_canonical_module_abi_incompatible') {
                throw error;
            }
            fail('wwebjs_canonical_module_abi_incompatible');
        }
    };
    const fromBase64 = (value, expectedLength) => {
        if (
            typeof value !== 'string' ||
            value.length % 4 === 1 ||
            !/^[A-Za-z0-9+/]*={0,2}$/.test(value)
        ) {
            fail('wwebjs_canonical_projection_incompatible');
        }
        let bytes;
        try {
            const binary = atob(value);
            bytes = Uint8Array.from(binary, (entry) => entry.charCodeAt(0));
        } catch {
            fail('wwebjs_canonical_projection_incompatible');
        }
        if (
            expectedLength !== undefined &&
            bytes.byteLength !== expectedLength
        ) {
            fail('wwebjs_canonical_projection_incompatible');
        }
        return bytes;
    };
    const asArrayBuffer = (bytes) =>
        bytes.buffer.slice(
            bytes.byteOffset,
            bytes.byteOffset + bytes.byteLength,
        );
    const toBase64 = (bytes) => {
        let binary = '';
        for (let offset = 0; offset < bytes.length; offset += 0x8000) {
            binary += String.fromCharCode(
                ...bytes.subarray(offset, offset + 0x8000),
            );
        }
        return btoa(binary);
    };
    const constantTimeHexEqual = (left, right) => {
        if (
            typeof left !== 'string' ||
            typeof right !== 'string' ||
            left.length !== right.length
        ) {
            return false;
        }
        let difference = 0;
        for (let index = 0; index < left.length; index += 1) {
            difference |= left.charCodeAt(index) ^ right.charCodeAt(index);
        }
        return difference === 0;
    };
    const domainDigest = async (domainValue, fields) => {
        const domain = new TextEncoder().encode(domainValue);
        const total = fields.reduce(
            (sum, field) => sum + 4 + field.byteLength,
            domain.byteLength,
        );
        const payload = new Uint8Array(total);
        payload.set(domain);
        const view = new DataView(payload.buffer);
        let offset = domain.byteLength;
        for (const field of fields) {
            view.setUint32(offset, field.byteLength, false);
            offset += 4;
            payload.set(field, offset);
            offset += field.byteLength;
        }
        try {
            const digest = new Uint8Array(
                await crypto.subtle.digest('SHA-256', payload),
            );
            return [...digest]
                .map((byte) => byte.toString(16).padStart(2, '0'))
                .join('');
        } finally {
            payload.fill(0);
        }
    };
    const fingerprintDigest = (fields) =>
        domainDigest('underchat-whatsapp-device-fingerprint-v2', fields);
    const signedIdentityDigest = (fields) =>
        domainDigest('underchat-wwebjs-signed-identity-tuple-v1', fields);
    const bytesDigest = async (bytes) => {
        const digest = new Uint8Array(
            await crypto.subtle.digest('SHA-256', bytes),
        );
        return [...digest]
            .map((byte) => byte.toString(16).padStart(2, '0'))
            .join('');
    };
    const parseCanonicalSignalAddress = (value, scope = 'default') => {
        const match = /^(\d+)(?:_(1|128|129))?:(\d+)$/.exec(value);
        if (!match || !['default', 'status', 'pq'].includes(scope)) {
            fail('wwebjs_canonical_signal_address_incompatible');
        }
        const device = Number(match[3]);
        if (!Number.isSafeInteger(device) || device < 0 || device > 65535) {
            fail('wwebjs_canonical_signal_address_incompatible');
        }
        const server =
            match[2] === '1'
                ? 'lid'
                : match[2] === '128'
                  ? 'hosted'
                  : match[2] === '129'
                    ? 'hosted.lid'
                    : 'c.us';
        const devicePart = device === 0 ? '' : `:${device}`;
        const scopePart =
            scope === 'status' ? '_status' : scope === 'pq' ? '_pq' : '';
        return `${match[1]}${devicePart}@${server}${scopePart}.0`;
    };
    const parseFingerprint = (bytes) => {
        let offset = 0;
        const readVarint = () => {
            let value = 0;
            let multiplier = 1;
            for (let count = 0; count < 5; count += 1) {
                if (offset >= bytes.length) {
                    fail('wwebjs_canonical_app_state_fingerprint_invalid');
                }
                const byte = bytes[offset++];
                value += (byte & 0x7f) * multiplier;
                if ((byte & 0x80) === 0) return value;
                multiplier *= 128;
            }
            fail('wwebjs_canonical_app_state_fingerprint_invalid');
        };
        const fingerprint = {
            rawId: 0,
            currentIndex: 0,
            deviceIndexes: [],
        };
        while (offset < bytes.length) {
            const tag = readVarint();
            const field = tag >>> 3;
            const wireType = tag & 7;
            if ((field === 1 || field === 2) && wireType === 0) {
                const value = readVarint();
                if (field === 1) fingerprint.rawId = value;
                else fingerprint.currentIndex = value;
            } else if (field === 3 && wireType === 0) {
                fingerprint.deviceIndexes.push(readVarint());
            } else if (field === 3 && wireType === 2) {
                const length = readVarint();
                const end = offset + length;
                if (end > bytes.length) {
                    fail('wwebjs_canonical_app_state_fingerprint_invalid');
                }
                while (offset < end) {
                    fingerprint.deviceIndexes.push(readVarint());
                }
                if (offset !== end) {
                    fail('wwebjs_canonical_app_state_fingerprint_invalid');
                }
            } else if (wireType === 0) {
                readVarint();
            } else if (wireType === 2) {
                const length = readVarint();
                offset += length;
                if (offset > bytes.length) {
                    fail('wwebjs_canonical_app_state_fingerprint_invalid');
                }
            } else {
                fail('wwebjs_canonical_app_state_fingerprint_invalid');
            }
        }
        return fingerprint;
    };

    const byteLengthIs = (value, length) => {
        if (value instanceof ArrayBuffer) return value.byteLength === length;
        return ArrayBuffer.isView(value) && value.byteLength === length;
    };
    const signalApi = requireModule('WAWebSignalStoreApi');
    const signalStorage = requireModule('WAWebSignalStorage');
    const kyberStore = requireModule('WAWebKyberPreKeyStore');
    const pqGating = requireModule('WAWebPQGatingUtils');
    const signalConst = requireModule('WAWebSignalConst');
    const signalCommon = requireModule('WAWebSignalCommonUtils');
    const sessionsApi = requireModule('WASignalSessions');
    const groupSessionsApi = requireModule('WASignalGroupSession');
    const localStorageProto = requireModule('WASignalLocalStorageProtocol.pb');
    const protobufDecoder = requireModule('decodeProtobuf');
    const curve = requireModule('WAWebCryptoCurve25519');
    const signalSignatures = requireModule('WASignalSignatures');
    const kem =
        projection.tables.pq_pre_keys.length > 0 && !pqPairValidationProof
            ? requireModule('WAKemModule')
            : undefined;
    const noiseStoreModule = requireModule('WAWebUserPrefsInfoStore');
    const multiDevice = requireModule('WAWebUserPrefsMultiDevice');
    const syncdDb = requireModule('WAWebSyncdDb');
    const syncKeysSchema = requireModule('WAWebSchemaSyncKeys');
    const collectionSchema = requireModule('WAWebSchemaCollectionVersion');
    const syncActionsSchema = requireModule('WAWebSchemaSyncActions');
    const pendingMutationsSchema = requireModule('WAWebSchemaPendingMutations');
    const missingKeysSchema = requireModule('WAWebSchemaMissingKeys');
    const widFactory = requireModule('WAWebWidFactory');
    const meUserPrefs = requireModule('WAWebUserPrefsMeUser');
    const userPrefsGeneral = requireModule('WAWebUserPrefsGeneral');
    const mobilePlatforms = requireModule('WAWebMobilePlatforms');
    const lidMigration = requireModule('WAWebLid1X1MigrationGating');
    const userPrefsTypes = requireModule('WAWebUserPrefsTypes');

    const signalStore = signalApi?.waSignalStore;
    const noiseStore = noiseStoreModule?.waNoiseInfo;
    if (
        !signalStore ||
        typeof signalStorage?.initialize !== 'function' ||
        typeof signalStore.setRegistrationInfo !== 'function' ||
        typeof signalStore.getRegistrationInfo !== 'function' ||
        typeof signalStore.putSignedPreKeys !== 'function' ||
        typeof signalStore.getSignedPreKey !== 'function' ||
        typeof signalStore.putADVSignedIdentity !== 'function' ||
        typeof signalStore.getADVSignedIdentity !== 'function' ||
        typeof signalStore.putPreKeys !== 'function' ||
        typeof signalStore.bulkPutIdentity !== 'function' ||
        typeof signalStore.bulkPutSession !== 'function' ||
        typeof signalStore.bulkPutSenderKey !== 'function' ||
        typeof signalStore.putMeta !== 'function' ||
        !(signalStore.idToSignedPreKey instanceof Map) ||
        typeof signalStore.idToSignedPreKey.clear !== 'function' ||
        typeof kyberStore?.isPQMigrated !== 'function' ||
        typeof kyberStore?.setPQMigrated !== 'function' ||
        typeof pqGating?.isPqKeysUploadEnabled !== 'function' ||
        typeof pqGating?.isPq1on1MessageEnabled !== 'function' ||
        typeof noiseStore?.set !== 'function' ||
        typeof noiseStore?.get !== 'function' ||
        typeof curve?.keyPair !== 'function' ||
        typeof signalSignatures?.verifyMsgSignalVariant !== 'function' ||
        typeof protobufDecoder?.decodeProtobuf !== 'function' ||
        typeof sessionsApi?.parseSessionFromRecord !== 'function' ||
        typeof groupSessionsApi?.parseSessionFromRecord !== 'function' ||
        !localStorageProto?.RecordStructureSpec ||
        !localStorageProto?.SenderKeyRecordStructureSpec ||
        typeof syncdDb?.createSyncKey !== 'function' ||
        typeof meUserPrefs?.setMe !== 'function' ||
        typeof meUserPrefs?.setMeLid !== 'function' ||
        typeof userPrefsGeneral?.setLastMobilePlatform !== 'function' ||
        userPrefsGeneral.setLastMobilePlatform.length !== 1 ||
        typeof userPrefsGeneral?.getLastMobilePlatform !== 'function' ||
        userPrefsGeneral.getLastMobilePlatform.length !== 0 ||
        typeof userPrefsGeneral?.setPushname !== 'function' ||
        userPrefsGeneral.setPushname.length !== 1 ||
        typeof userPrefsGeneral?.getPushname !== 'function' ||
        userPrefsGeneral.getPushname.length !== 0 ||
        typeof lidMigration?.Lid1X1MigrationUtils?.setIsLidMigrated !==
            'function' ||
        typeof lidMigration?.Lid1X1MigrationUtils?.isLidMigrated !==
            'function' ||
        userPrefsTypes?.LidMigrationSource?.HISTORY === undefined ||
        typeof multiDevice?.isRegistered !== 'function' ||
        typeof multiDevice?.setADVSecretKey !== 'function' ||
        typeof multiDevice?.getADVSecretKey !== 'function' ||
        typeof multiDevice?.setRoutingInfo !== 'function' ||
        typeof multiDevice?.getRoutingInfo !== 'function'
    ) {
        fail('wwebjs_canonical_module_abi_incompatible');
    }
    const resolveSignalTables = () => [
        signalStorage.getBaseKeyTable?.(),
        signalStorage.getIdentityTable?.(),
        signalStorage.getMetaTable?.(),
        signalStorage.getPreKeyTable?.(),
        signalStorage.getSessionTable?.(),
        signalStorage.getSignedPreKeyTable?.(),
        signalStorage.getSenderKeyTable?.(),
    ];
    const writableSignalTables = (tables) =>
        Array.isArray(tables) &&
        tables.length === 7 &&
        tables.every((table) => table && typeof table.clear === 'function');
    let signalTables;
    let bootstrapRegistration;
    currentImportStage = setImportStage('signal_storage_bootstrap_probe');
    try {
        signalTables = resolveSignalTables();
    } catch {
        signalTables = undefined;
    }
    let projectedIdentityKeyShapeValid;
    try {
        const projectedIdentityKey = fromBase64(
            projection.device.identity_key,
            32,
        );
        projectedIdentityKeyShapeValid = projectedIdentityKey.byteLength === 32;
        projectedIdentityKey.fill(0);
    } catch {
        projectedIdentityKeyShapeValid = false;
    }
    const reusableProfileProjectionProof =
        preserveExistingAppState &&
        writableSignalTables(signalTables) &&
        signalTables.every((table) => typeof table.all === 'function') &&
        Number.isSafeInteger(projection.device.registration_id) &&
        projection.device.registration_id > 0 &&
        projection.device.registration_id <= 0xffffffff &&
        projectedIdentityKeyShapeValid &&
        /^[a-f0-9]{64}$/u.test(
            String(projection.device.device_fingerprint || ''),
        );
    if (!reusableProfileProjectionProof) {
        try {
            bootstrapRegistration = await signalStore.getRegistrationInfo();
        } catch {
            bootstrapRegistration = undefined;
        }
    }
    const bootstrapSignalStorageReady =
        reusableProfileProjectionProof ||
        (writableSignalTables(signalTables) &&
            signalTables.every((table) => typeof table.all === 'function') &&
            Number.isSafeInteger(bootstrapRegistration?.registrationId) &&
            bootstrapRegistration.registrationId > 0 &&
            byteLengthIs(bootstrapRegistration?.identityKeyPair?.pubKey, 32) &&
            byteLengthIs(bootstrapRegistration?.identityKeyPair?.privKey, 32));
    const signalStorageInitializationMode = bootstrapSignalStorageReady
        ? 'preinitialized_bootstrap_proof'
        : 'official_initialize';
    if (!bootstrapSignalStorageReady) {
        await importStep('signal_storage_initialize', () =>
            signalStorage.initialize(),
        );
        signalTables = await importStep('signal_table_resolution', async () =>
            resolveSignalTables(),
        );
    }
    const copyBytes = (value, expectedLength) => {
        const view =
            value instanceof ArrayBuffer
                ? new Uint8Array(value)
                : ArrayBuffer.isView(value)
                  ? new Uint8Array(
                        value.buffer,
                        value.byteOffset,
                        value.byteLength,
                    )
                  : undefined;
        if (!view || view.byteLength !== expectedLength) return undefined;
        return new Uint8Array(view);
    };
    const wipeBytes = (value) => {
        const view =
            value instanceof ArrayBuffer
                ? new Uint8Array(value)
                : ArrayBuffer.isView(value)
                  ? new Uint8Array(
                        value.buffer,
                        value.byteOffset,
                        value.byteLength,
                    )
                  : undefined;
        view?.fill(0);
    };
    const bytesEqual = (left, right) => {
        const leftBytes =
            left instanceof ArrayBuffer
                ? new Uint8Array(left)
                : ArrayBuffer.isView(left)
                  ? new Uint8Array(
                        left.buffer,
                        left.byteOffset,
                        left.byteLength,
                    )
                  : undefined;
        const rightBytes =
            right instanceof ArrayBuffer
                ? new Uint8Array(right)
                : ArrayBuffer.isView(right)
                  ? new Uint8Array(
                        right.buffer,
                        right.byteOffset,
                        right.byteLength,
                    )
                  : undefined;
        if (
            !leftBytes ||
            !rightBytes ||
            leftBytes.length !== rightBytes.length
        ) {
            return false;
        }
        let difference = 0;
        for (let index = 0; index < leftBytes.length; index += 1) {
            difference |= leftBytes[index] ^ rightBytes[index];
        }
        return difference === 0;
    };
    const safeCounter = (value) => Number.isSafeInteger(value) && value >= 0;
    const validateMessageKeys = (keys) => {
        if (!Array.isArray(keys) || keys.length > 2000) return false;
        return keys.every(
            (key) =>
                key &&
                safeCounter(key.index) &&
                byteLengthIs(key.cipherKey, 32) &&
                byteLengthIs(key.macKey, 32) &&
                byteLengthIs(key.iv, 16),
        );
    };
    const validateSignalSessionState = (state) => {
        if (
            !state ||
            state.sessionVersion !== 3 ||
            !byteLengthIs(state.localIdentityPublic, 33) ||
            !byteLengthIs(state.remoteIdentityPublic, 33) ||
            !byteLengthIs(state.rootKey, 32) ||
            !byteLengthIs(state.aliceBaseKey, 33) ||
            !safeCounter(state.previousCounter) ||
            !safeCounter(state.remoteRegistrationId) ||
            !safeCounter(state.localRegistrationId) ||
            !state.senderChain ||
            !byteLengthIs(state.senderChain.senderRatchetKey, 33) ||
            !byteLengthIs(state.senderChain.senderRatchetKeyPrivate, 32) ||
            !state.senderChain.chainKey ||
            !safeCounter(state.senderChain.chainKey.index) ||
            !byteLengthIs(state.senderChain.chainKey.key, 32) ||
            !validateMessageKeys(state.senderChain.messageKeys) ||
            !Array.isArray(state.receiverChains) ||
            state.receiverChains.length > 5
        ) {
            return false;
        }
        return state.receiverChains.every(
            (chain) =>
                chain &&
                byteLengthIs(chain.senderRatchetKey, 33) &&
                chain.chainKey &&
                safeCounter(chain.chainKey.index) &&
                byteLengthIs(chain.chainKey.key, 32) &&
                validateMessageKeys(chain.messageKeys),
        );
    };
    const validateSignalRecord = (record) =>
        record &&
        validateSignalSessionState(record.currentSession) &&
        Array.isArray(record.previousSessions) &&
        record.previousSessions.length <= 40 &&
        record.previousSessions.every(validateSignalSessionState);
    const validateSenderKeyRecord = (record) =>
        record &&
        Array.isArray(record.senderKeyStates) &&
        record.senderKeyStates.length > 0 &&
        record.senderKeyStates.length <= 5 &&
        record.senderKeyStates.every(
            (state) =>
                state &&
                safeCounter(state.senderKeyId) &&
                state.senderChainKey &&
                safeCounter(state.senderChainKey.iteration) &&
                byteLengthIs(state.senderChainKey.seed, 32) &&
                state.senderSigningKey &&
                byteLengthIs(state.senderSigningKey.public, 33) &&
                (state.senderSigningKey.private === undefined ||
                    byteLengthIs(state.senderSigningKey.private, 32)) &&
                Array.isArray(state.senderMessageKeys) &&
                state.senderMessageKeys.length <= 2000 &&
                state.senderMessageKeys.every(
                    (key) =>
                        key &&
                        safeCounter(key.iteration) &&
                        byteLengthIs(key.seed, 32),
                ),
        );

    const sensitive = [];
    const secretBytes = (value, length) => {
        const bytes = fromBase64(value, length);
        sensitive.push(bytes);
        return bytes;
    };
    const derivePair = async (privateBytes) => {
        const privateCopy = new Uint8Array(privateBytes);
        sensitive.push(privateCopy);
        const pair = await curve.keyPair(asArrayBuffer(privateCopy));
        const publicBytes = new Uint8Array(pair.pubKey);
        const normalizedPrivate = new Uint8Array(pair.privKey);
        if (
            publicBytes.byteLength !== 32 ||
            normalizedPrivate.byteLength !== 32
        ) {
            fail('wwebjs_canonical_key_derivation_failed');
        }
        sensitive.push(normalizedPrivate);
        return {
            pubKey: asArrayBuffer(publicBytes),
            privKey: asArrayBuffer(normalizedPrivate),
            publicBytes,
        };
    };

    try {
        currentImportStage = setImportStage('device_validation');
        const device = projection.device;
        const identityPrivate = secretBytes(device.identity_key, 32);
        const noisePrivate = secretBytes(device.noise_key, 32);
        const signedPrivate = secretBytes(device.signed_pre_key, 32);
        const signedSignature = fromBase64(device.signed_pre_key_sig, 64);
        const advDetails = fromBase64(device.adv_details);
        const advAccountSignature = fromBase64(device.adv_account_sig, 64);
        const advAccountSignatureKey = fromBase64(
            device.adv_account_sig_key,
            32,
        );
        const advDeviceSignature = fromBase64(device.adv_device_sig, 64);
        const advSecret = device.adv_secret_available
            ? secretBytes(device.adv_key, 32)
            : undefined;
        let routingInfo;
        if (projection.transport_state != null) {
            if (
                projection.transport_state.kind !== 'whatsapp-transport-v1' ||
                projection.transport_state.codec_version !== 1
            ) {
                fail('wwebjs_canonical_transport_state_invalid');
            }
            routingInfo = secretBytes(projection.transport_state.routing_info);
            if (routingInfo.byteLength < 1 || routingInfo.byteLength > 65535) {
                fail('wwebjs_canonical_routing_info_invalid');
            }
        } else if (options?.requireRoutingInfo === true) {
            fail('wwebjs_canonical_routing_info_unavailable');
        }
        if (advDetails.byteLength === 0) {
            fail('wwebjs_canonical_projection_incompatible');
        }

        const [identityPair, noisePair, signedPair] = await importStep(
            'device_key_derivation',
            () =>
                Promise.all([
                    derivePair(identityPrivate),
                    derivePair(noisePrivate),
                    derivePair(signedPrivate),
                ]),
        );
        const noiseBootstrap =
            projection.provider_state || options?.noiseBootstrap;
        const regenerateNoiseMetadata =
            !noiseBootstrap && options?.allowNoiseMetadataBootstrap === true;
        if (
            !regenerateNoiseMetadata &&
            (!noiseBootstrap ||
                noiseBootstrap.kind !== 'wwebjs-noise-bootstrap-v1' ||
                noiseBootstrap.codec_version !== 1 ||
                noiseBootstrap.device_fingerprint !== device.device_fingerprint)
        ) {
            fail('wwebjs_canonical_noise_metadata_unavailable');
        }
        const expectedNoisePublic = regenerateNoiseMetadata
            ? new Uint8Array(noisePair.publicBytes)
            : fromBase64(noiseBootstrap.noise_public_key, 32);
        let noisePublicDifference = 0;
        for (let index = 0; index < 32; index += 1) {
            noisePublicDifference |=
                expectedNoisePublic[index] ^ noisePair.publicBytes[index];
        }
        if (noisePublicDifference !== 0) {
            fail('wwebjs_canonical_noise_metadata_mismatch');
        }
        let noiseRecoveryToken;
        let noiseCertificateChain;
        if (regenerateNoiseMetadata) {
            noiseRecoveryToken = new Uint8Array(24);
            crypto.getRandomValues(noiseRecoveryToken);
            sensitive.push(noiseRecoveryToken);
        } else {
            noiseRecoveryToken = secretBytes(noiseBootstrap.recovery_token, 24);
            noiseCertificateChain =
                noiseBootstrap.certificate_chain === null
                    ? undefined
                    : fromBase64(noiseBootstrap.certificate_chain);
        }
        const serializedIdentityPublic = new Uint8Array(33);
        serializedIdentityPublic[0] = 5;
        serializedIdentityPublic.set(identityPair.publicBytes, 1);
        const serializedSignedPublic = new Uint8Array(33);
        serializedSignedPublic[0] = 5;
        serializedSignedPublic.set(signedPair.publicBytes, 1);
        const signedPreKeyValid = await importStep(
            'signed_pre_key_validation',
            async () =>
                signalSignatures.verifyMsgSignalVariant(
                    serializedIdentityPublic,
                    serializedSignedPublic,
                    signedSignature,
                ),
        );
        if (!signedPreKeyValid) {
            fail('wwebjs_canonical_signed_pre_key_invalid');
        }
        const fingerprint = await fingerprintDigest([
            identityPair.publicBytes,
            advDetails,
            advAccountSignatureKey,
            advAccountSignature,
            advDeviceSignature,
        ]);
        const [
            noisePublicHash,
            identityPublicHash,
            signedIdentityHash,
            routingInfoHash,
        ] = await Promise.all([
            bytesDigest(noisePair.publicBytes),
            bytesDigest(identityPair.publicBytes),
            signedIdentityDigest([
                advDetails,
                advAccountSignatureKey,
                advAccountSignature,
                advDeviceSignature,
            ]),
            routingInfo ? bytesDigest(routingInfo) : Promise.resolve(null),
        ]);
        if (
            !constantTimeHexEqual(
                fingerprint,
                String(device.device_fingerprint || '').toLowerCase(),
            )
        ) {
            fail('wwebjs_canonical_device_fingerprint_mismatch');
        }

        let me;
        let meLid;
        const supportedPrimaryPlatforms = new Set(
            Object.values(mobilePlatforms?.PLATFORMS || {}).filter(
                (value) => typeof value === 'string',
            ),
        );
        if (
            typeof device.platform !== 'string' ||
            !supportedPrimaryPlatforms.has(device.platform)
        ) {
            fail('wwebjs_canonical_primary_platform_invalid');
        }
        if (!device.lid || projection.capabilities?.lid_migrated !== true) {
            fail('wwebjs_canonical_lid_migration_state_unavailable');
        }
        try {
            me = widFactory.createWid(device.jid);
            meLid = device.lid ? widFactory.createWid(device.lid) : undefined;
        } catch {
            fail('wwebjs_canonical_device_jid_incompatible');
        }
        if (!me) fail('wwebjs_canonical_device_jid_incompatible');

        currentImportStage = setImportStage('identity_validation');
        const identities = projection.tables.identity_keys.map((row) => {
            const identifier = parseCanonicalSignalAddress(row.their_id);
            const rawIdentity = fromBase64(row.identity, 32);
            const serialized = new Uint8Array(33);
            serialized[0] = 5;
            serialized.set(rawIdentity, 1);
            return {
                identifier,
                identityKey: signalCommon.bufferToStr(
                    asArrayBuffer(serialized),
                ),
            };
        });
        const preKeys = [];
        // Reusable-profile equivalence is calculated from an offline native
        // export and the exact target projection before the page import begins.
        // When the classic pre-key component matches, re-deriving thousands of
        // identical public keys is both redundant and the dominant migration
        // cost. We still decode every private row and validate all boundaries,
        // but retain no key pair and perform no native write for that component.
        if (preserveExistingSignalComponents.pre_keys) {
            currentImportStage = setImportStage('preserved_pre_key_validation');
            for (const row of projection.tables.pre_keys) {
                secretBytes(row.key, 32);
                preKeys.push({
                    keyId: row.key_id,
                    uploaded: row.uploaded,
                });
            }
        } else {
            // The private curve module is not concurrency-safe at unbounded
            // cardinality. Derive a bounded batch at a time so a normal 800-key
            // replenishment cannot overload its internal worker/transaction.
            for (
                let start = 0;
                start < projection.tables.pre_keys.length;
                start += 32
            ) {
                const batch = projection.tables.pre_keys.slice(
                    start,
                    start + 32,
                );
                const derived = await importStep('pre_key_derivation', () =>
                    Promise.all(
                        batch.map(async (row) => {
                            const privateKey = secretBytes(row.key, 32);
                            return {
                                keyId: row.key_id,
                                keyPair: await derivePair(privateKey),
                                uploaded: row.uploaded,
                            };
                        }),
                    ),
                );
                preKeys.push(...derived);
            }
        }
        preKeys.sort((left, right) => left.keyId - right.keyId);
        let firstUnuploaded = device.next_pre_key_id;
        const firstPending = preKeys.find((row) => !row.uploaded);
        if (firstPending) firstUnuploaded = firstPending.keyId;
        if (
            preKeys.some(
                (row) => row.uploaded !== row.keyId < firstUnuploaded,
            ) ||
            preKeys.some((row) => row.keyId >= device.next_pre_key_id)
        ) {
            fail('wwebjs_canonical_pre_key_boundary_invalid');
        }

        currentImportStage = setImportStage('pq_pre_key_validation');
        if (projection.tables.pq_pre_key_state.length > 1) {
            fail('wwebjs_canonical_pq_pre_key_state_duplicate');
        }
        const pqState = projection.tables.pq_pre_key_state[0];
        if (!pqState && projection.tables.pq_pre_keys.length > 0) {
            fail('wwebjs_canonical_pq_pre_key_state_missing');
        }
        const pqHasServerCount =
            Boolean(pqState) && pqState.last_server_count !== null;
        const pqServerCountMode =
            projection.capabilities?.pq_server_count_mode ??
            (pqState && pqHasServerCount ? 'observed' : 'reset');
        if (
            pqState &&
            (pqState.codec_version !== 1 ||
                pqState.algorithm !== 'ML-KEM-1024' ||
                !safeCounter(pqState.next_pre_key_id) ||
                pqState.next_pre_key_id >= 0xffffff ||
                typeof pqState.migrated !== 'boolean' ||
                (pqState.last_server_count === null) !==
                    (pqState.last_server_count_timestamp_ms === null) ||
                (pqState.last_server_count !== null &&
                    (!safeCounter(pqState.last_server_count) ||
                        !safeCounter(pqState.last_server_count_timestamp_ms))))
        ) {
            fail('wwebjs_canonical_pq_pre_key_state_invalid');
        }
        if (
            !['unknown', 'observed', 'reset'].includes(pqServerCountMode) ||
            (pqState &&
                ((pqServerCountMode === 'observed' && !pqHasServerCount) ||
                    (pqServerCountMode === 'reset' && pqHasServerCount))) ||
            (!pqState && pqServerCountMode !== 'reset')
        ) {
            fail('wwebjs_canonical_pq_server_count_mode_invalid');
        }
        if (
            projection.tables.pq_pre_keys.length > 0 &&
            !pqPairValidationProof &&
            (typeof kem?.encapsulate !== 'function' ||
                typeof kem?.decapsulate !== 'function')
        ) {
            fail('wwebjs_canonical_pq_materialization_abi_incompatible');
        }
        const pqPreKeys = [];
        let pqLastResortKey;
        const pqKeyIds = new Set();
        const pqKeyMaterials = [];
        let pqLastResortMaterialSeen = false;
        for (const row of projection.tables.pq_pre_keys) {
            if (
                !row ||
                !['one_time', 'last_resort'].includes(row.key_kind) ||
                !safeCounter(row.key_id) ||
                row.key_id >= 0xffffff ||
                pqKeyIds.has(row.key_id) ||
                !safeCounter(row.timestamp_ms) ||
                typeof row.sent_to_server !== 'boolean'
            ) {
                fail('wwebjs_canonical_pq_pre_key_row_invalid');
            }
            if (row.key_kind === 'last_resort') {
                if (pqLastResortMaterialSeen) {
                    fail('wwebjs_canonical_pq_last_resort_key_duplicate');
                }
                pqLastResortMaterialSeen = true;
            }
            pqKeyIds.add(row.key_id);
            const publicKey = fromBase64(row.public_key, 1568);
            const privateKey = secretBytes(row.private_key, 3168);
            const signature = fromBase64(row.signature, 64);
            pqKeyMaterials.push({ row, publicKey, privateKey, signature });
        }
        for (const material of pqKeyMaterials) {
            const signatureValid = await importStep(
                'pq_pre_key_signature_validation',
                () =>
                    signalSignatures.verifyMsgSignalVariant(
                        serializedIdentityPublic,
                        material.publicKey,
                        material.signature,
                    ),
            );
            if (!signatureValid) {
                fail('wwebjs_canonical_pq_pre_key_signature_invalid');
            }
        }
        setImportProgress(0, pqKeyMaterials.length);
        if (pqPairValidationProof) {
            const commitmentFields = pqKeyMaterials.flatMap(
                ({ row, publicKey, privateKey, signature }) => [
                    new TextEncoder().encode(
                        JSON.stringify([
                            row.key_id,
                            row.key_kind,
                            row.timestamp_ms,
                            row.sent_to_server,
                        ]),
                    ),
                    publicKey,
                    privateKey,
                    signature,
                ],
            );
            const commitment = await importStep(
                'pq_pre_key_pair_validation_proof',
                () =>
                    domainDigest(
                        'underchat-wwebjs-pq-pair-validation-v1',
                        commitmentFields,
                    ),
            );
            if (
                pqPairValidationProof.key_count !== pqKeyMaterials.length ||
                !constantTimeHexEqual(
                    commitment,
                    pqPairValidationProof.commitment,
                )
            ) {
                fail('wwebjs_canonical_pq_validation_proof_invalid');
            }
            setImportProgress(pqKeyMaterials.length, pqKeyMaterials.length);
        } else {
            // Retain a compatibility fallback for direct library consumers
            // that do not use BrowserSessionBridge's Node-side proof. The
            // WWeb private KEM implementation can serialize these nominally
            // asynchronous calls, so staged provider handoffs never use this
            // renderer path.
            const pqPairValidationBatchSize = 4;
            for (
                let start = 0;
                start < pqKeyMaterials.length;
                start += pqPairValidationBatchSize
            ) {
                const batch = pqKeyMaterials.slice(
                    start,
                    start + pqPairValidationBatchSize,
                );
                const settled = await importStep(
                    'pq_pre_key_pair_validation',
                    () =>
                        Promise.allSettled(
                            batch.map(async (material) => {
                                let encapsulated;
                                let decapsulated;
                                try {
                                    encapsulated = await kem.encapsulate(
                                        material.publicKey,
                                    );
                                    if (
                                        !byteLengthIs(
                                            encapsulated?.ciphertext,
                                            1568,
                                        ) ||
                                        !byteLengthIs(
                                            encapsulated?.sharedSecret,
                                            32,
                                        )
                                    ) {
                                        fail(
                                            'wwebjs_canonical_pq_pre_key_pair_invalid',
                                        );
                                    }
                                    decapsulated = await kem.decapsulate(
                                        encapsulated.ciphertext,
                                        material.privateKey,
                                    );
                                    if (
                                        !byteLengthIs(decapsulated, 32) ||
                                        !bytesEqual(
                                            decapsulated,
                                            encapsulated.sharedSecret,
                                        )
                                    ) {
                                        fail(
                                            'wwebjs_canonical_pq_pre_key_pair_invalid',
                                        );
                                    }
                                    return material;
                                } finally {
                                    wipeBytes(encapsulated?.sharedSecret);
                                    wipeBytes(decapsulated);
                                }
                            }),
                        ),
                );
                const rejected = settled.find(
                    (result) => result.status === 'rejected',
                );
                if (rejected) throw rejected.reason;
                setImportProgress(
                    Math.min(start + batch.length, pqKeyMaterials.length),
                    pqKeyMaterials.length,
                );
            }
        }
        // Only copy private material into the objects destined for the native
        // store after every pair has passed. A rejection in a late batch must
        // leave no successful earlier-batch copy outside the sensitive wipe
        // list while the import exits before its first destructive write.
        for (const {
            row,
            publicKey,
            privateKey,
            signature,
        } of pqKeyMaterials) {
            const key = {
                keyId: row.key_id,
                keyPair: {
                    pubKey: asArrayBuffer(publicKey),
                    privKey: asArrayBuffer(privateKey),
                },
                signature: asArrayBuffer(signature),
                timestamp: row.timestamp_ms,
                sentToServer: row.sent_to_server,
            };
            if (row.key_kind === 'last_resort') {
                pqLastResortKey = key;
            } else {
                pqPreKeys.push(key);
            }
        }
        pqPreKeys.sort((left, right) => left.keyId - right.keyId);
        if (
            pqState &&
            ((pqState.migrated &&
                (!pqLastResortKey || !pqLastResortKey.sentToServer)) ||
                (!pqState.migrated &&
                    (pqLastResortKey?.sentToServer ||
                        pqPreKeys.some((key) => key.sentToServer))) ||
                (!pqState.migrated && pqPreKeys.length > 0 && !pqLastResortKey))
        ) {
            fail('wwebjs_canonical_pq_migration_state_diverged');
        }
        const pqCapabilities = projection.capabilities;
        if (
            !pqCapabilities ||
            pqCapabilities.pq_migrated !== Boolean(pqState?.migrated) ||
            pqCapabilities.pq_storage_mode !==
                (pqState ? 'legacy_tables' : 'rollout_without_tables') ||
            (pqCapabilities.pq_server_count_mode ?? pqServerCountMode) !==
                pqServerCountMode ||
            pqCapabilities.pq_pre_key_count !== pqPreKeys.length ||
            pqCapabilities.pq_last_resort_key_count !==
                (pqLastResortKey ? 1 : 0)
        ) {
            fail('wwebjs_canonical_pq_capability_invalid');
        }

        currentImportStage = setImportStage('signal_session_validation');
        const knownSignalScopes = ['default', 'status', 'pq'];
        const sourceSignalScopes =
            projection.capabilities?.canonical_signal_session_scopes;
        const signalSessionResyncRequired =
            projection.capabilities
                ?.canonical_signal_session_resync_required === true;
        if (
            sourceSignalScopes !== undefined &&
            (!Array.isArray(sourceSignalScopes) ||
                sourceSignalScopes.length === 0 ||
                sourceSignalScopes.some(
                    (scope, index) =>
                        !knownSignalScopes.includes(scope) ||
                        sourceSignalScopes.indexOf(scope) !== index,
                ))
        ) {
            fail('wwebjs_canonical_signal_scope_capability_invalid');
        }
        const importableSignalScopes = new Set(
            sourceSignalScopes || knownSignalScopes,
        );
        const declaredResyncScopes =
            projection.capabilities?.canonical_signal_session_resync_scopes;
        if (
            declaredResyncScopes !== undefined &&
            (!Array.isArray(declaredResyncScopes) ||
                declaredResyncScopes.some(
                    (scope, index) =>
                        !knownSignalScopes.includes(scope) ||
                        declaredResyncScopes.indexOf(scope) !== index,
                ))
        ) {
            fail('wwebjs_canonical_signal_scope_capability_invalid');
        }
        const signalSessionResyncScopes = signalSessionResyncRequired
            ? new Set(
                  declaredResyncScopes ||
                      knownSignalScopes.filter(
                          (scope) => !importableSignalScopes.has(scope),
                      ),
              )
            : new Set();
        if (
            signalSessionResyncRequired &&
            [...signalSessionResyncScopes].some((scope) =>
                importableSignalScopes.has(scope),
            )
        ) {
            fail('wwebjs_canonical_signal_scope_capability_invalid');
        }
        const importedSignalRows = signalSessionResyncRequired
            ? projection.tables.signal_sessions.filter((row) =>
                  importableSignalScopes.has(row.scope),
              )
            : projection.tables.signal_sessions;
        const discardedSignalSessionCount =
            projection.tables.signal_sessions.length -
            importedSignalRows.length;
        const sessions = importedSignalRows.map((row) => {
            const address = parseCanonicalSignalAddress(
                row.their_id,
                row.scope,
            );
            try {
                const decoded = protobufDecoder.decodeProtobuf(
                    localStorageProto.RecordStructureSpec,
                    fromBase64(row.session),
                );
                if (!validateSignalRecord(decoded)) {
                    fail('wwebjs_canonical_signal_session_limits_invalid');
                }
                return {
                    address,
                    session: sessionsApi.parseSessionFromRecord(decoded),
                };
            } catch {
                fail('wwebjs_canonical_signal_session_incompatible');
            }
        });
        currentImportStage = setImportStage('sender_key_validation');
        const senderKeys = projection.tables.sender_keys.map((row) => {
            const senderAddress = parseCanonicalSignalAddress(row.sender_id);
            let decoded;
            try {
                decoded = protobufDecoder.decodeProtobuf(
                    localStorageProto.SenderKeyRecordStructureSpec,
                    fromBase64(row.sender_key),
                );
            } catch {
                fail('wwebjs_canonical_sender_key_incompatible');
            }

            const normalized = normalizeCanonicalSenderKeyRecord(decoded);
            if (!validateSenderKeyRecord(normalized)) {
                fail('wwebjs_canonical_sender_key_limits_invalid');
            }

            let senderKey;
            try {
                senderKey = groupSessionsApi.parseSessionFromRecord(normalized);
            } catch {
                fail('wwebjs_canonical_sender_key_runtime_parse_incompatible');
            }

            return {
                senderKeyName: `${row.chat_id}::${senderAddress}`,
                senderId: senderAddress,
                senderKey,
            };
        });
        currentImportStage = setImportStage('app_state_validation');
        const syncKeys = projection.tables.app_state_sync_keys.map((row) => {
            const keyId = fromBase64(row.key_id);
            if (keyId.byteLength < 2) {
                fail('wwebjs_canonical_app_state_key_epoch_invalid');
            }
            return {
                // WAWebSchemaSyncKeys.convertFromSyncKeyToRow reads
                // keyId.buffer before rebuilding the Uint8Array row key. The
                // read API returns an ArrayBuffer, but feeding that same shape
                // back into createSyncKey loses the key because ArrayBuffer
                // itself has no `.buffer` property.
                keyId: new Uint8Array(keyId),
                keyData: asArrayBuffer(secretBytes(row.key_data, 32)),
                timestamp: row.timestamp,
                fingerprint: parseFingerprint(fromBase64(row.fingerprint)),
                keyEpoch:
                    keyId[keyId.byteLength - 2] * 256 +
                    keyId[keyId.byteLength - 1],
            };
        });
        // All decoding and cryptographic validation above is side-effect free.
        // Only now may the empty candidate profile be hydrated.
        if (!writableSignalTables(signalTables)) {
            fail('wwebjs_canonical_module_abi_incompatible');
        }
        // Current WhatsApp Web builds can expose the two legacy Kyber table
        // getters even when the rollout deliberately omitted those tables.
        // In that state both getters throw NoSuchTableError and the supported
        // API is WAWebKyberPreKeyStore. Treating the getters as mandatory made
        // every canonical handoff fail before the first write. Conversely, a
        // migrated/enabled PQ runtime without its backing tables is unsafe and
        // must fail closed instead of silently discarding post-quantum state.
        const legacyKyberTables = [];
        let missingLegacyKyberTables = 0;
        for (const getterName of [
            'getKyberPreKeyTable',
            'getKyberLastResortKeyTable',
        ]) {
            const getter = signalStorage?.[getterName];
            if (typeof getter !== 'function') {
                fail('wwebjs_canonical_pq_storage_abi_incompatible');
            }
            try {
                const table = getter.call(signalStorage);
                if (!table || typeof table.clear !== 'function') {
                    fail('wwebjs_canonical_pq_storage_abi_incompatible');
                }
                legacyKyberTables.push(table);
            } catch (error) {
                if (error?.name !== 'NoSuchTableError') {
                    if (
                        /^wwebjs_canonical_/u.test(String(error?.message || ''))
                    ) {
                        throw error;
                    }
                    fail('wwebjs_canonical_pq_storage_unavailable');
                }
                missingLegacyKyberTables += 1;
            }
        }
        if (missingLegacyKyberTables !== 0 && missingLegacyKyberTables !== 2) {
            fail('wwebjs_canonical_pq_storage_inconsistent');
        }
        const pqUploadEnabled = Boolean(pqGating.isPqKeysUploadEnabled());
        const pqMessagingEnabled = Boolean(pqGating.isPq1on1MessageEnabled());
        // On rollout builds without either physical Kyber table,
        // isPQMigrated() waits for an internal store deadline even though the
        // source projection and runtime upload gate independently prove that
        // no PQ material exists or can be published. Avoid that redundant
        // native read only for this exact empty-rollout shape. Any table,
        // source PQ state, non-zero count, enabled upload gate or capability
        // disagreement still executes the official probe and therefore keeps
        // the fail-closed path for migrated companions.
        const declaredEmptyPqRollout =
            !pqState &&
            pqPreKeys.length === 0 &&
            !pqLastResortKey &&
            pqCapabilities?.pq_migrated === false &&
            pqCapabilities?.pq_storage_mode === 'rollout_without_tables' &&
            pqCapabilities?.pq_pre_key_count === 0 &&
            pqCapabilities?.pq_last_resort_key_count === 0 &&
            pqServerCountMode === 'reset' &&
            missingLegacyKyberTables === 2 &&
            pqUploadEnabled === false;
        const pqFlags = await importStep(
            'pq_capability_resolution',
            async () => ({
                migrated: declaredEmptyPqRollout
                    ? false
                    : Boolean(await kyberStore.isPQMigrated()),
                uploadEnabled: pqUploadEnabled,
                messagingEnabled: pqMessagingEnabled,
            }),
        );
        if (
            (pqState?.migrated || pqFlags.uploadEnabled) &&
            pqFlags.messagingEnabled !== true
        ) {
            // Once a companion has published (or can automatically publish) a
            // PQ bundle, the server may send PQXDH messages immediately. The
            // official upload task is registered independently of our manual
            // bootstrap call, so reject this rollout combination before any
            // write instead of relying only on ensurePostQuantumReady().
            fail('wwebjs_canonical_pq_messaging_runtime_disabled');
        }
        if (
            pqState &&
            (missingLegacyKyberTables !== 0 ||
                typeof kyberStore.saveKyberPreKeys !== 'function' ||
                typeof kyberStore.saveKyberLastResortKey !== 'function' ||
                typeof kyberStore.loadKyberPreKey !== 'function' ||
                typeof kyberStore.loadLatestKyberLastResortKey !== 'function' ||
                (typeof kyberStore.getUnsentKyberPreKeys !== 'function' &&
                    typeof window.__WWebSessionBridge
                        ?.readUnsentKyberPreKeys !== 'function') ||
                typeof kyberStore.loadKyberKeysForDigest !== 'function' ||
                typeof kyberStore.getNextKyberPreKeyId !== 'function' ||
                signalConst?.META_KEYS?.NEXT_KYBER_PK_ID == null)
        ) {
            fail('wwebjs_canonical_pq_materialization_abi_incompatible');
        }
        const signalTablesToClear = [
            // Device/base metadata and signed credentials are always resealed;
            // preservation applies only to independently checksummed bulk data.
            signalTables[0],
            signalTables[2],
            signalTables[5],
            ...(!preserveExistingSignalComponents.identity_keys
                ? [signalTables[1]]
                : []),
            ...(!preserveExistingSignalComponents.pre_keys
                ? [signalTables[3]]
                : []),
            ...(!preserveExistingSignalComponents.signal_sessions
                ? [signalTables[4]]
                : []),
            ...(!preserveExistingSignalComponents.sender_keys
                ? [signalTables[6]]
                : []),
        ];
        await importStep(
            preservedSignalComponents.length > 0
                ? 'clear_signal_credential_tables'
                : 'clear_signal_tables',
            () =>
                Promise.all(signalTablesToClear.map((table) => table.clear())),
        );
        // getSignedPreKey() is backed by a closure-level Map that survives an
        // IndexedDB table clear and even clearCredential(). Without explicitly
        // invalidating this pinned private-ABI cache, a reconnect-time read can
        // read back the SPK generated by the unpaired bootstrap instead of the
        // row just persisted below.
        signalStore.idToSignedPreKey.clear();
        if (
            legacyKyberTables.length > 0 &&
            !preserveExistingSignalComponents.pq_pre_keys
        ) {
            await importStep('clear_pq_tables', () =>
                Promise.all(legacyKyberTables.map((table) => table.clear())),
            );
        }
        await importStep('reset_pq_migration', () =>
            kyberStore.setPQMigrated(false),
        );
        signalStore.registrationInfo = undefined;

        await importStep('registration', () =>
            signalStore.setRegistrationInfo({
                registrationId: device.registration_id,
                identityKeyPair: {
                    pubKey: identityPair.pubKey,
                    privKey: identityPair.privKey,
                },
            }),
        );
        await importStep('signed_pre_key', () =>
            signalStore.putSignedPreKeys([
                {
                    keyId: device.signed_pre_key_id,
                    keyPair: {
                        pubKey: signedPair.pubKey,
                        privKey: signedPair.privKey,
                    },
                    signature: asArrayBuffer(signedSignature),
                },
            ]),
        );
        await importStep('signal_meta', () =>
            signalStore.putMeta([
                {
                    key: signalConst.META_KEYS.LAST_SPK_ID,
                    value: device.signed_pre_key_id,
                },
                {
                    key: signalConst.META_KEYS.FIRST_UNUPLOAD_PK_ID,
                    value: firstUnuploaded,
                },
                {
                    key: signalConst.META_KEYS.NEXT_PK_ID,
                    value: device.next_pre_key_id,
                },
                {
                    key: signalConst.META_KEYS.SERVER_HAS_KEY,
                    value: preKeys.some((row) => row.uploaded),
                },
                ...(pqState
                    ? [
                          {
                              key: signalConst.META_KEYS.NEXT_KYBER_PK_ID,
                              value: pqState.next_pre_key_id,
                          },
                      ]
                    : []),
            ]),
        );
        await importStep('adv_identity', () =>
            signalStore.putADVSignedIdentity({
                details: asArrayBuffer(advDetails),
                accountSignature: asArrayBuffer(advAccountSignature),
                accountSignatureKey: asArrayBuffer(advAccountSignatureKey),
                deviceSignature: asArrayBuffer(advDeviceSignature),
            }),
        );
        if (typeof multiDevice?.setADVSecretKey !== 'function') {
            fail('wwebjs_canonical_module_abi_incompatible');
        }
        await importStep('adv_secret', () =>
            multiDevice.setADVSecretKey(
                advSecret ? toBase64(advSecret) : undefined,
            ),
        );
        await importStep('noise_identity', () =>
            noiseStore.set({
                recoveryToken: asArrayBuffer(noiseRecoveryToken),
                staticKeyPair: {
                    pubKey: noisePair.pubKey,
                    privKey: noisePair.privKey,
                },
                certificateChainBuffer: noiseCertificateChain
                    ? asArrayBuffer(noiseCertificateChain)
                    : undefined,
            }),
        );
        if (routingInfo) {
            await importStep('routing_info', () =>
                multiDevice.setRoutingInfo({
                    domain: 'fb',
                    edgeRouting: new Uint8Array(routingInfo),
                }),
            );
        }
        // Establish the registered tuple before the slower bulk imports. The
        // unpaired bootstrap otherwise remains free to rotate credentials
        // locally while hundreds of prekeys are being derived/written.
        await importStep('me_preferences', () => meUserPrefs.setMe(me));
        if (meLid) {
            await importStep('me_lid_preferences', () =>
                meUserPrefs.setMeLid(meLid),
            );
        }
        await importStep('lid_migration_state', async () => {
            await lidMigration.Lid1X1MigrationUtils.setIsLidMigrated(
                true,
                userPrefsTypes.LidMigrationSource.HISTORY,
            );
            if (lidMigration.Lid1X1MigrationUtils.isLidMigrated() !== true) {
                fail('wwebjs_canonical_lid_migration_state_write_failed');
            }
        });
        await importStep('primary_platform', async () => {
            await userPrefsGeneral.setLastMobilePlatform(device.platform);
            if (
                (await userPrefsGeneral.getLastMobilePlatform()) !==
                device.platform
            ) {
                fail('wwebjs_canonical_primary_platform_write_failed');
            }
        });
        if (
            typeof device.push_name === 'string' &&
            device.push_name.length > 0
        ) {
            await importStep('push_name', async () => {
                userPrefsGeneral.setPushname(device.push_name);
                if (userPrefsGeneral.getPushname() !== device.push_name) {
                    fail('wwebjs_canonical_push_name_write_failed');
                }
            });
        }
        if (preKeys.length > 0 && !preserveExistingSignalComponents.pre_keys) {
            await importStep('pre_keys', () =>
                signalStore.putPreKeys(
                    preKeys.map((row) => ({
                        keyId: row.keyId,
                        keyPair: {
                            pubKey: row.keyPair.pubKey,
                            privKey: row.keyPair.privKey,
                        },
                    })),
                ),
            );
        }
        if (
            pqPreKeys.length > 0 &&
            !preserveExistingSignalComponents.pq_pre_keys
        ) {
            await importStep('pq_pre_keys', () =>
                kyberStore.saveKyberPreKeys(pqPreKeys),
            );
        }
        if (pqLastResortKey && !preserveExistingSignalComponents.pq_pre_keys) {
            const lastResortKey = {
                keyId: pqLastResortKey.keyId,
                keyPair: pqLastResortKey.keyPair,
                signature: pqLastResortKey.signature,
                timestamp: pqLastResortKey.timestamp,
            };
            await importStep('pq_last_resort_key', () =>
                kyberStore.saveKyberLastResortKey(lastResortKey),
            );
        }
        if (pqState) {
            await importStep('pq_migration_state', () =>
                kyberStore.setPQMigrated(pqState.migrated),
            );
            const [
                persistedPqPreKeys,
                persistedPqLastResortKey,
                unsentPqPreKeys,
                pqDigest,
                persistedNextPqPreKeyId,
                persistedPqMigrated,
            ] = await importStep('pq_material_readback', () =>
                Promise.all([
                    Promise.all(
                        pqPreKeys.map((key) =>
                            kyberStore.loadKyberPreKey(key.keyId),
                        ),
                    ),
                    kyberStore.loadLatestKyberLastResortKey(),
                    typeof kyberStore.getUnsentKyberPreKeys === 'function'
                        ? kyberStore.getUnsentKyberPreKeys()
                        : window.__WWebSessionBridge.readUnsentKyberPreKeys(),
                    kyberStore.loadKyberKeysForDigest(),
                    kyberStore.getNextKyberPreKeyId(),
                    kyberStore.isPQMigrated(),
                ]),
            );
            const pqStoredRowMatches = (expected, actual) =>
                actual?.keyId === expected.keyId &&
                actual?.timestamp === expected.timestamp &&
                actual?.sentToServer === expected.sentToServer &&
                bytesEqual(actual?.keyPair?.pubKey, expected.keyPair.pubKey) &&
                bytesEqual(
                    actual?.keyPair?.privKey,
                    expected.keyPair.privKey,
                ) &&
                bytesEqual(actual?.signature, expected.signature);
            const persistedOneTimeValid =
                Array.isArray(persistedPqPreKeys) &&
                persistedPqPreKeys.length === pqPreKeys.length &&
                persistedPqPreKeys.every((row, index) =>
                    pqStoredRowMatches(pqPreKeys[index], row),
                );
            const persistedLastResortValid = pqLastResortKey
                ? persistedPqLastResortKey?.keyId === pqLastResortKey.keyId &&
                  persistedPqLastResortKey?.timestamp ===
                      pqLastResortKey.timestamp &&
                  bytesEqual(
                      persistedPqLastResortKey?.keyPair?.pubKey,
                      pqLastResortKey.keyPair.pubKey,
                  ) &&
                  bytesEqual(
                      persistedPqLastResortKey?.keyPair?.privKey,
                      pqLastResortKey.keyPair.privKey,
                  ) &&
                  bytesEqual(
                      persistedPqLastResortKey?.signature,
                      pqLastResortKey.signature,
                  )
                : persistedPqLastResortKey == null;
            const expectedUnsentIds = pqPreKeys
                .filter((key) => !key.sentToServer)
                .map((key) => key.keyId)
                .sort((left, right) => left - right);
            const actualUnsentIds = Array.isArray(unsentPqPreKeys)
                ? unsentPqPreKeys
                      .map((key) => key?.keyId)
                      .sort((left, right) => left - right)
                : [];
            const digestPreKeys = pqDigest?.kyberPreKeys;
            const digestLastResortKeys = pqDigest?.kyberLastResortKeys;
            const digestValid =
                Array.isArray(digestPreKeys) &&
                digestPreKeys.length === pqPreKeys.length &&
                digestPreKeys.every(
                    (row, index) =>
                        row?.keyId === pqPreKeys[index].keyId &&
                        bytesEqual(
                            row?.publicKey,
                            pqPreKeys[index].keyPair.pubKey,
                        ),
                ) &&
                Array.isArray(digestLastResortKeys) &&
                digestLastResortKeys.length === (pqLastResortKey ? 1 : 0) &&
                (!pqLastResortKey ||
                    (digestLastResortKeys[0]?.keyId === pqLastResortKey.keyId &&
                        bytesEqual(
                            digestLastResortKeys[0]?.publicKey,
                            pqLastResortKey.keyPair.pubKey,
                        ) &&
                        bytesEqual(
                            digestLastResortKeys[0]?.signature,
                            pqLastResortKey.signature,
                        )));
            if (
                !persistedOneTimeValid ||
                !persistedLastResortValid ||
                !Array.isArray(unsentPqPreKeys) ||
                expectedUnsentIds.length !== actualUnsentIds.length ||
                expectedUnsentIds.some(
                    (keyId, index) => keyId !== actualUnsentIds[index],
                ) ||
                !digestValid ||
                persistedNextPqPreKeyId !== pqState.next_pre_key_id ||
                Boolean(persistedPqMigrated) !== pqState.migrated
            ) {
                fail('wwebjs_canonical_pq_material_readback_invalid');
            }
        }
        if (
            identities.length > 0 &&
            !preserveExistingSignalComponents.identity_keys
        ) {
            await importStep('identities', () =>
                signalStore.bulkPutIdentity(identities),
            );
        }
        if (
            sessions.length > 0 &&
            !preserveExistingSignalComponents.signal_sessions
        ) {
            await importStep('signal_sessions', () =>
                signalStore.bulkPutSession(sessions),
            );
        }
        if (
            senderKeys.length > 0 &&
            !preserveExistingSignalComponents.sender_keys
        ) {
            await importStep('sender_keys', () =>
                signalStore.bulkPutSenderKey(senderKeys),
            );
        }

        if (!preserveExistingAppState) {
            const appStateTables = await importStep(
                'app_state_table_resolution',
                async () => [
                    syncKeysSchema.getSyncKeysTable?.(),
                    collectionSchema.getCollectionVersionTable?.(),
                    syncActionsSchema.getSyncActionsTable?.(),
                    pendingMutationsSchema.getPendingMutationsTable?.(),
                    missingKeysSchema.getMissingKeysTable?.(),
                ],
            );
            if (
                appStateTables.some(
                    (table) => !table || typeof table.clear !== 'function',
                )
            ) {
                fail('wwebjs_canonical_module_abi_incompatible');
            }
            await importStep('clear_app_state_tables', () =>
                Promise.all(appStateTables.map((table) => table.clear())),
            );
        }

        // sync-keys.keyData is encrypted by WhatsApp Web's final database
        // message-encryption key. A fresh cross-provider profile deliberately
        // does not have that key while the browser is offline, so attempting a
        // write here fails with DbMsgEncKeyNotLoaded. Keep the validated rows
        // in the Node-side handoff projection. RemoteAuth installs them only
        // after the imported socket has authenticated and then drives the
        // official full app-state sync before any checkpoint or promotion.

        // Seal the critical tuple after all bulk work. This is intentionally
        // a second write followed by an official-API readback: if an unpaired
        // bootstrap writer rotated registration/SPK while the import was in
        // progress, the candidate fails here while it is still offline.
        const criticalSignedPreKeyTable =
            signalStorage.getSignedPreKeyTable?.();
        if (
            !criticalSignedPreKeyTable ||
            typeof criticalSignedPreKeyTable.clear !== 'function'
        ) {
            fail('wwebjs_canonical_module_abi_incompatible');
        }
        await importStep('critical_seal_signed_pre_key_clear', () =>
            criticalSignedPreKeyTable.clear(),
        );
        signalStore.idToSignedPreKey.clear();
        signalStore.registrationInfo = undefined;
        await importStep('critical_seal_registration', () =>
            signalStore.setRegistrationInfo({
                registrationId: device.registration_id,
                identityKeyPair: {
                    pubKey: identityPair.pubKey,
                    privKey: identityPair.privKey,
                },
            }),
        );
        await importStep('critical_seal_signed_pre_key', () =>
            signalStore.putSignedPreKeys([
                {
                    keyId: device.signed_pre_key_id,
                    keyPair: {
                        pubKey: signedPair.pubKey,
                        privKey: signedPair.privKey,
                    },
                    signature: asArrayBuffer(signedSignature),
                },
            ]),
        );
        await importStep('critical_seal_adv_identity', () =>
            signalStore.putADVSignedIdentity({
                details: asArrayBuffer(advDetails),
                accountSignature: asArrayBuffer(advAccountSignature),
                accountSignatureKey: asArrayBuffer(advAccountSignatureKey),
                deviceSignature: asArrayBuffer(advDeviceSignature),
            }),
        );
        await importStep('critical_seal_adv_secret', () =>
            multiDevice.setADVSecretKey(
                advSecret ? toBase64(advSecret) : undefined,
            ),
        );
        await importStep('critical_seal_noise_identity', () =>
            noiseStore.set({
                recoveryToken: asArrayBuffer(noiseRecoveryToken),
                staticKeyPair: {
                    pubKey: noisePair.pubKey,
                    privKey: noisePair.privKey,
                },
                certificateChainBuffer: noiseCertificateChain
                    ? asArrayBuffer(noiseCertificateChain)
                    : undefined,
            }),
        );
        if (routingInfo) {
            await importStep('critical_seal_routing_info', () =>
                multiDevice.setRoutingInfo({
                    domain: 'fb',
                    edgeRouting: new Uint8Array(routingInfo),
                }),
            );
        }
        await importStep('critical_seal_me_preferences', () =>
            meUserPrefs.setMe(me),
        );
        if (meLid) {
            await importStep('critical_seal_me_lid_preferences', () =>
                meUserPrefs.setMeLid(meLid),
            );
        }
        const [
            sealedRegistration,
            sealedSignedPreKey,
            sealedAdvIdentity,
            sealedAdvSecret,
            sealedNoiseInfo,
            sealedRoutingInfo,
        ] = await importStep('critical_seal_readback', () =>
            Promise.all([
                signalStore.getRegistrationInfo(),
                signalStore.getSignedPreKey(),
                signalStore.getADVSignedIdentity(),
                multiDevice.getADVSecretKey(),
                noiseStore.get(),
                multiDevice.getRoutingInfo(),
            ]),
        );
        const sealedIdentityPublic = new Uint8Array(33);
        sealedIdentityPublic[0] = 5;
        const sealedIdentityPublicBytes =
            sealedRegistration?.identityKeyPair?.pubKey;
        if (byteLengthIs(sealedIdentityPublicBytes, 32)) {
            sealedIdentityPublic.set(
                new Uint8Array(
                    sealedIdentityPublicBytes.buffer ||
                        sealedIdentityPublicBytes,
                    sealedIdentityPublicBytes.byteOffset || 0,
                    sealedIdentityPublicBytes.byteLength,
                ),
                1,
            );
        }
        const sealedSignedPublic = new Uint8Array(33);
        sealedSignedPublic[0] = 5;
        const sealedSignedPublicBytes = sealedSignedPreKey?.keyPair?.pubKey;
        if (byteLengthIs(sealedSignedPublicBytes, 32)) {
            sealedSignedPublic.set(
                new Uint8Array(
                    sealedSignedPublicBytes.buffer || sealedSignedPublicBytes,
                    sealedSignedPublicBytes.byteOffset || 0,
                    sealedSignedPublicBytes.byteLength,
                ),
                1,
            );
        }
        // IndexedDB-backed signal storage currently reads signatures as an
        // ArrayBuffer while verifyMsgSignalVariant expects a Uint8Array. The
        // initial validation already receives a Uint8Array; normalize the
        // official-store readback to the same ABI before verifying it.
        const sealedSignedSignature = copyBytes(
            sealedSignedPreKey?.signature,
            64,
        );
        const sealedSignatureValid =
            sealedSignedSignature !== undefined &&
            (await importStep('critical_seal_signature_validation', () =>
                signalSignatures.verifyMsgSignalVariant(
                    sealedIdentityPublic,
                    sealedSignedPublic,
                    sealedSignedSignature,
                ),
            ));
        let sealedAdvSecretBytes;
        if (typeof sealedAdvSecret === 'string' && sealedAdvSecret.length > 0) {
            try {
                const binary = atob(sealedAdvSecret);
                sealedAdvSecretBytes = Uint8Array.from(binary, (entry) =>
                    entry.charCodeAt(0),
                );
            } catch {
                sealedAdvSecretBytes = undefined;
            }
        }
        const sealedAdvSecretValid = advSecret
            ? bytesEqual(sealedAdvSecretBytes, advSecret)
            : sealedAdvSecret == null || sealedAdvSecret === '';
        const criticalSealChecks = [
            [
                'registration_id',
                sealedRegistration?.registrationId === device.registration_id,
            ],
            [
                'identity_public',
                bytesEqual(
                    sealedRegistration?.identityKeyPair?.pubKey,
                    identityPair.pubKey,
                ),
            ],
            [
                'identity_private',
                bytesEqual(
                    sealedRegistration?.identityKeyPair?.privKey,
                    identityPair.privKey,
                ),
            ],
            [
                'signed_pre_key_id',
                sealedSignedPreKey?.keyId === device.signed_pre_key_id,
            ],
            [
                'signed_pre_key_public',
                bytesEqual(
                    sealedSignedPreKey?.keyPair?.pubKey,
                    signedPair.pubKey,
                ),
            ],
            [
                'signed_pre_key_private',
                bytesEqual(
                    sealedSignedPreKey?.keyPair?.privKey,
                    signedPair.privKey,
                ),
            ],
            [
                'signed_pre_key_signature_bytes',
                bytesEqual(sealedSignedPreKey?.signature, signedSignature),
            ],
            ['signed_pre_key_signature_math', sealedSignatureValid === true],
            ['adv_details', bytesEqual(sealedAdvIdentity?.details, advDetails)],
            [
                'adv_account_signature',
                bytesEqual(
                    sealedAdvIdentity?.accountSignature,
                    advAccountSignature,
                ),
            ],
            [
                'adv_account_signature_key',
                bytesEqual(
                    sealedAdvIdentity?.accountSignatureKey,
                    advAccountSignatureKey,
                ),
            ],
            [
                'adv_device_signature',
                bytesEqual(
                    sealedAdvIdentity?.deviceSignature,
                    advDeviceSignature,
                ),
            ],
            ['adv_secret', sealedAdvSecretValid],
            [
                'noise_public',
                bytesEqual(
                    sealedNoiseInfo?.staticKeyPair?.pubKey,
                    noisePair.pubKey,
                ),
            ],
            [
                'noise_private',
                bytesEqual(
                    sealedNoiseInfo?.staticKeyPair?.privKey,
                    noisePair.privKey,
                ),
            ],
            [
                'noise_recovery',
                bytesEqual(sealedNoiseInfo?.recoveryToken, noiseRecoveryToken),
            ],
            [
                'routing_info',
                routingInfo
                    ? sealedRoutingInfo?.domain === 'fb' &&
                      bytesEqual(sealedRoutingInfo?.edgeRouting, routingInfo)
                    : sealedRoutingInfo == null,
            ],
            ['registered_flag', multiDevice.isRegistered() === true],
        ];
        const failedCriticalSealChecks = criticalSealChecks
            .filter(([, valid]) => !valid)
            .map(([category]) => category);
        if (failedCriticalSealChecks.length > 0) {
            fail(
                `wwebjs_canonical_critical_seal_invalid:${failedCriticalSealChecks.join(
                    ',',
                )}`,
            );
        }
        window.__WWebSessionBridge?.markClean?.();
        setImportStage('completion');
        return {
            imported_records: projection.record_count,
            imported_signal_sessions: sessions.length,
            imported_sender_keys: senderKeys.length,
            imported_app_state_sync_keys: 0,
            pending_app_state_sync_keys: preserveExistingAppState
                ? 0
                : syncKeys.length,
            adv_secret_available: Boolean(advSecret),
            app_state_import_mode: preserveExistingAppState
                ? 'preserved_native_profile'
                : 'deferred_authenticated_full_sync',
            noise_metadata_mode: regenerateNoiseMetadata
                ? 'canonical_noise_metadata_bootstrap_canary'
                : 'preserved',
            signal_storage_initialization_mode: signalStorageInitializationMode,
            signal_table_import_mode:
                preservedSignalComponents.length === signalComponentNames.length
                    ? 'preserved_equivalent_bulk_tables'
                    : preservedSignalComponents.length > 0
                      ? 'selective_component_replace'
                      : 'full_replace',
            preserved_signal_components: preservedSignalComponents,
            replaced_signal_components: replacedSignalComponents,
            pq_key_mode: pqState
                ? 'preserved'
                : pqFlags.uploadEnabled
                  ? CANONICAL_PQ_KEY_MODE_GENERATE_AFTER_RECONNECT
                  : 'disabled',
            imported_pq_pre_key_count: pqPreKeys.length,
            imported_pq_last_resort_key_count: pqLastResortKey ? 1 : 0,
            imported_pq_migrated: Boolean(pqState?.migrated),
            pq_storage_mode:
                legacyKyberTables.length === 2
                    ? 'legacy_tables'
                    : pqFlags.migrated ||
                        pqFlags.uploadEnabled ||
                        pqFlags.messagingEnabled
                      ? 'managed_store'
                      : 'rollout_without_tables',
            imported_signal_session_scopes: [
                ...new Set(importedSignalRows.map((row) => row.scope)),
            ].sort(),
            discarded_signal_session_count: discardedSignalSessionCount,
            signal_session_resync_required: signalSessionResyncRequired,
            signal_session_resync_scopes: [...signalSessionResyncScopes].sort(),
            status_session_mode: signalSessionResyncScopes.has('status')
                ? 'lazy_official_session_establishment'
                : 'preserved',
            routing_info_imported: Boolean(routingInfo),
            generated_provider_state: regenerateNoiseMetadata
                ? {
                      kind: 'wwebjs-noise-bootstrap-v1',
                      codec_version: 1,
                      device_fingerprint: device.device_fingerprint,
                      noise_public_key: toBase64(noisePair.publicBytes),
                      recovery_token: toBase64(noiseRecoveryToken),
                      certificate_chain: null,
                  }
                : undefined,
            expected_registration_state: {
                registration_id: device.registration_id,
                noise_public_hash: noisePublicHash,
                identity_public_hash: identityPublicHash,
                signed_identity_hash: signedIdentityHash,
                companion_fingerprint: fingerprint,
                signed_pre_key_id: device.signed_pre_key_id,
                routing_info_hash: routingInfoHash,
                noise_keypair_math_valid: true,
                identity_keypair_math_valid: true,
                signed_pre_key_keypair_math_valid: true,
                signed_pre_key_signature_valid: true,
            },
            reconnect_required: true,
            reload_required: false,
        };
    } catch (error) {
        if (/^wwebjs_canonical_/u.test(String(error?.message || ''))) {
            throw error;
        }
        fail(`wwebjs_canonical_import_${currentImportStage}_failed`);
    } finally {
        for (const bytes of sensitive) bytes.fill(0);
    }
}

module.exports = {
    CANONICAL_FINGERPRINT_VERSION,
    CANONICAL_PQ_KEY_MODE_GENERATE_AFTER_RECONNECT,
    CANONICAL_PRIVATE_MODULE_ABI,
    CANONICAL_SESSION_CODEC_KIND,
    CANONICAL_SESSION_CODEC_VERSION,
    CANONICAL_SESSION_SCHEMA_VERSION,
    CANONICAL_SESSION_STORE_ABI,
    DEFAULT_MAX_CANONICAL_BYTES,
    DEFAULT_MAX_CANONICAL_RECORDS,
    canonicalBrowserProjectionToStore,
    canonicalStoreProjectionToBrowser,
    assertCanonicalTargetProviderCompatibility,
    exportCanonicalSessionProjection,
    importCanonicalSessionProjection,
    normalizeCanonicalProjection,
};