Repository: dotnet/runtime
File: src/native/corehost/browserhost/host/index.ts (TypeScript)

Code before:
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

import type { InternalExchange, BrowserHostExports, RuntimeAPI, BrowserHostExportsTable } from "./types";
import { InternalExchangeIndex } from "./types";
import { } from "./cross-linked"; // ensure ambient symbols are declared

import GitHash from "consts:gitHash";

import { runMain, runMainAndExit, registerDllBytes, installVfsFile, loadIcuData, initializeCoreCLR } from "./host";

export function dotnetInitializeModule(internals: InternalExchange): void {
    if (!Array.isArray(internals)) throw new Error("Expected internals to be an array");
    const runtimeApiLocal: Partial<RuntimeAPI> = {
        runMain,
        runMainAndExit,
    };
    const runtimeApi = internals[InternalExchangeIndex.RuntimeAPI];
    if (typeof runtimeApi !== "object") throw new Error("Expected internals to have RuntimeAPI");
    Object.assign(runtimeApi, runtimeApiLocal);
    if (runtimeApi.runtimeBuildInfo.gitHash && runtimeApi.runtimeBuildInfo.gitHash !== GitHash) {
        throw new Error(`Mismatched git hashes between loader and runtime. Loader: ${runtimeApi.runtimeBuildInfo.gitHash}, BrowserHost: ${GitHash}`);
    }

    internals[InternalExchangeIndex.BrowserHostExportsTable] = browserHostExportsToTable({
        registerDllBytes,
        installVfsFile,
        loadIcuData,
        initializeCoreCLR,
    });
    dotnetUpdateInternals(internals, dotnetUpdateInternalsSubscriber);
    function browserHostExportsToTable(map: BrowserHostExports): BrowserHostExportsTable {
        // keep in sync with browserHostExportsFromTable()
        return [
            map.registerDllBytes,
            map.installVfsFile,
            map.loadIcuData,
            map.initializeCoreCLR,
        ];
    }
}

export { BrowserHost_ExternalAssemblyProbe } from "./host";


Review comment (bug):
The gitHash consistency check should be performed before modifying the runtimeApi object with Object.assign. Move lines 21-23 to before line 20 to ensure that if the gitHash check fails, the runtimeApi hasn't been modified yet. This follows the same pattern as other modules where validation happens before mutation.
```suggestion
    if (runtimeApi.runtimeBuildInfo.gitHash && runtimeApi.runtimeBuildInfo.gitHash !== GitHash) {
        throw new Error(`Mismatched git hashes between loader and runtime. Loader: ${runtimeApi.runtimeBuildInfo.gitHash}, BrowserHost: ${GitHash}`);
    }
    Object.assign(runtimeApi, runtimeApiLocal);

    internals[InternalExchangeIndex.BrowserHostExportsTable] = browserHostExportsTable = browserHostExportsToTable({
```

Code after:
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

import type { InternalExchange, BrowserHostExports, RuntimeAPI, BrowserHostExportsTable } from "./types";
import { InternalExchangeIndex } from "./types";
import { } from "./cross-linked"; // ensure ambient symbols are declared

import GitHash from "consts:gitHash";

import { runMain, runMainAndExit, registerDllBytes, installVfsFile, loadIcuData, initializeCoreCLR } from "./host";

export function dotnetInitializeModule(internals: InternalExchange): void {
    if (!Array.isArray(internals)) throw new Error("Expected internals to be an array");
    const runtimeApiLocal: Partial<RuntimeAPI> = {
        runMain,
        runMainAndExit,
    };
    const runtimeApi = internals[InternalExchangeIndex.RuntimeAPI];
    if (typeof runtimeApi !== "object") throw new Error("Expected internals to have RuntimeAPI");
    if (runtimeApi.runtimeBuildInfo.gitHash && runtimeApi.runtimeBuildInfo.gitHash !== GitHash) {
        throw new Error(`Mismatched git hashes between loader and runtime. Loader: ${runtimeApi.runtimeBuildInfo.gitHash}, BrowserHost: ${GitHash}`);
    }
    Object.assign(runtimeApi, runtimeApiLocal);

    internals[InternalExchangeIndex.BrowserHostExportsTable] = browserHostExportsToTable({
        registerDllBytes,
        installVfsFile,
        loadIcuData,
        initializeCoreCLR,
    });
    dotnetUpdateInternals(internals, dotnetUpdateInternalsSubscriber);
    function browserHostExportsToTable(map: BrowserHostExports): BrowserHostExportsTable {
        // keep in sync with browserHostExportsFromTable()
        return [
            map.registerDllBytes,
            map.installVfsFile,
            map.loadIcuData,
            map.initializeCoreCLR,
        ];
    }
}

export { BrowserHost_ExternalAssemblyProbe } from "./host";