Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
2f8fbb2
v8 support
pavelsavara Jan 22, 2026
e67384d
only when without config resources
pavelsavara Jan 22, 2026
8f8cd70
Update src/native/corehost/browserhost/host/host.ts
pavelsavara Jan 22, 2026
9968254
Update src/native/corehost/browserhost/loader/bootstrap.ts
pavelsavara Jan 22, 2026
efcfc58
Update src/native/corehost/browserhost/loader/bootstrap.ts
pavelsavara Jan 22, 2026
284a4a1
Update src/native/corehost/browserhost/loader/bootstrap.ts
pavelsavara Jan 22, 2026
8c84094
Update src/native/corehost/browserhost/loader/bootstrap.ts
pavelsavara Jan 22, 2026
3641007
Update src/native/corehost/browserhost/loader/bootstrap.ts
pavelsavara Jan 22, 2026
ad20452
Update src/native/corehost/browserhost/loader/bootstrap.ts
pavelsavara Jan 22, 2026
17d16ea
Update src/native/corehost/browserhost/loader/bootstrap.ts
pavelsavara Jan 22, 2026
1918602
fix
pavelsavara Jan 22, 2026
48e206a
wip
pavelsavara Jan 22, 2026
e6022bd
Merge branch 'main' into v8
pavelsavara Jan 23, 2026
5c2073c
feedback
pavelsavara Jan 23, 2026
1564e47
feedback from https://github.com/dotnet/runtime/pull/123400
pavelsavara Jan 23, 2026
bf900f7
cleanup
pavelsavara Jan 23, 2026
f505813
fix
pavelsavara Jan 23, 2026
22cac87
fix
pavelsavara Jan 23, 2026
6391be5
wip
pavelsavara Jan 23, 2026
eaac6ec
use NODERAWFS
pavelsavara Jan 24, 2026
f89c7c2
fixes
pavelsavara Jan 26, 2026
3a7d56b
move instantiateWasm
pavelsavara Jan 26, 2026
74a70be
Merge branch 'main' into v8
pavelsavara Jan 26, 2026
ea7b0a5
browserAppBase
pavelsavara Jan 26, 2026
c491cd9
more
pavelsavara Jan 26, 2026
9471273
rename browserVirtualAppBase
pavelsavara Jan 26, 2026
e4278a7
fix
pavelsavara Jan 26, 2026
0e81b71
Merge branch 'main' into v8
pavelsavara Jan 28, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 5 additions & 20 deletions src/coreclr/hosts/corerun/corerun.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -365,20 +365,6 @@ static bool HOST_CONTRACT_CALLTYPE external_assembly_probe(
return false;
}

#ifdef TARGET_BROWSER
bool is_node()
{
return EM_ASM_INT({
if (typeof process !== 'undefined' &&
process.versions &&
process.versions.node) {
return 1;
}
return 0;
});
}
#endif // TARGET_BROWSER

static int run(const configuration& config)
{
platform_specific_actions actions;
Expand Down Expand Up @@ -620,12 +606,9 @@ static int run(const configuration& config)
}

#ifdef TARGET_BROWSER
if (!is_node())
{
// In browser we don't shutdown the runtime here as we want to keep it alive
return 0;
}
#endif // TARGET_BROWSER
// In browser we don't shutdown the runtime here as we want to keep it alive
return 0;
#else // TARGET_BROWSER

int latched_exit_code = 0;
result = coreclr_shutdown2_func(CurrentClrInstance, CurrentAppDomainId, &latched_exit_code);
Expand All @@ -641,6 +624,8 @@ static int run(const configuration& config)
::free((void*)s_core_libs_path);
::free((void*)s_core_root_path);
return exit_code;

#endif // TARGET_BROWSER
}

// Display the command line options
Expand Down
9 changes: 9 additions & 0 deletions src/coreclr/hosts/corerun/wasm/libCorerun.extpost.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,15 @@ var fetch = fetch || undefined; var dotnetNativeModuleLoaded = false; var dotnet
export function selfRun() {
const Module = {};
const corePreRun = () => {

// drop windows drive letter for NODEFS cwd to pretend we are in unix
NODERAWFS.cwd = () => {
const path = process.cwd();
return NODEFS.isWindows
? path.replace(/^[a-zA-Z]:/, "").replace(/\\/g, "/")
: path;
};

// copy all node/shell env variables to emscripten env
if (globalThis.process && globalThis.process.env) {
for (const [key, value] of Object.entries(process.env)) {
Expand Down
12 changes: 12 additions & 0 deletions src/coreclr/pal/src/debug/debug.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ SET_DEFAULT_DEBUG_CHANNEL(DEBUG); // some headers have code with asserts, so do
#endif
#endif // __APPLE__

#ifdef __EMSCRIPTEN__
#include <emscripten/heap.h>
#endif // __EMSCRIPTEN__

#if HAVE_MACH_EXCEPTIONS
#include "../exception/machexception.h"
#endif // HAVE_MACH_EXCEPTIONS
Expand Down Expand Up @@ -751,6 +755,13 @@ PAL_ProbeMemory(
DWORD cbBuffer,
BOOL fWriteAccess)
{
#if defined(__EMSCRIPTEN__)
if ((PBYTE)pBuffer + cbBuffer < (PVOID)emscripten_get_heap_size())
{
return TRUE;
}
return FALSE;
#else // __EMSCRIPTEN__
int fds[2];
int flags;

Expand Down Expand Up @@ -807,6 +818,7 @@ PAL_ProbeMemory(
close(fds[1]);

return result;
#endif // __EMSCRIPTEN__
}

} // extern "C"
6 changes: 3 additions & 3 deletions src/mono/browser/runtime/assets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import type { AssetEntryInternal } from "./types/internal";

import cwraps from "./cwraps";
import { wasm_load_icu_data } from "./icu";
import { Module, loaderHelpers, mono_assert, runtimeHelpers } from "./globals";
import { Module, browserVirtualAppBase, loaderHelpers, mono_assert, runtimeHelpers } from "./globals";
import { mono_log_info, mono_log_debug, parseSymbolMapFile } from "./logging";
import { mono_wasm_load_bytes_into_heap_persistent } from "./memory";
import { endMeasure, MeasuredBlock, startMeasure } from "./profiler";
Expand Down Expand Up @@ -52,15 +52,15 @@ export function instantiate_asset (asset: AssetEntry, url: string, bytes: Uint8A
fileName = fileName.substring(1);
if (parentDirectory) {
if (!parentDirectory.startsWith("/"))
parentDirectory = "/" + parentDirectory;
parentDirectory = browserVirtualAppBase + "/" + parentDirectory;

mono_log_debug(`Creating directory '${parentDirectory}'`);

Module.FS_createPath(
"/", parentDirectory, true, true // fixme: should canWrite be false?
);
} else {
parentDirectory = "/";
parentDirectory = browserVirtualAppBase;
}

mono_log_debug(() => `Creating file '${fileName}' in directory '${parentDirectory}'`);
Expand Down
1 change: 1 addition & 0 deletions src/mono/browser/runtime/globals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ export const ENVIRONMENT_IS_SIDECAR = ENVIRONMENT_IS_WEB_WORKER && typeof dotnet
export const ENVIRONMENT_IS_WORKER = ENVIRONMENT_IS_WEB_WORKER && !ENVIRONMENT_IS_SIDECAR; // we redefine what ENVIRONMENT_IS_WORKER, we replace it in emscripten internals, so that sidecar works
export const ENVIRONMENT_IS_WEB = typeof window == "object" || (ENVIRONMENT_IS_WEB_WORKER && !ENVIRONMENT_IS_NODE);
export const ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE;
export const browserVirtualAppBase = "/managed"; // keep in sync other places that define browserVirtualAppBase

// these are imported and re-exported from emscripten internals
export let ENVIRONMENT_IS_PTHREAD: boolean;
Expand Down
5 changes: 5 additions & 0 deletions src/mono/browser/runtime/loader/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { importLibraryInitializers, invokeLibraryInitializers } from "./libraryI
import { mono_exit } from "./exit";
import { makeURLAbsoluteWithApplicationBase } from "./polyfills";
import { appendUniqueQuery } from "./assets";
import { browserVirtualAppBase } from "./globals";

export function deep_merge_config (target: MonoConfigInternal, source: MonoConfigInternal): MonoConfigInternal {
// no need to merge the same object
Expand Down Expand Up @@ -190,6 +191,10 @@ export function normalizeConfig () {
config.debugLevel = -1;
}

if (config.virtualWorkingDirectory === undefined) {
config.virtualWorkingDirectory = browserVirtualAppBase;
}

if (!config.applicationEnvironment) {
config.applicationEnvironment = "Production";
}
Expand Down
1 change: 1 addition & 0 deletions src/mono/browser/runtime/loader/globals.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export const ENVIRONMENT_IS_SIDECAR = ENVIRONMENT_IS_WEB_WORKER && typeof dotnet
export const ENVIRONMENT_IS_WORKER = ENVIRONMENT_IS_WEB_WORKER && !ENVIRONMENT_IS_SIDECAR; // we redefine what ENVIRONMENT_IS_WORKER, we replace it in emscripten internals, so that sidecar works
export const ENVIRONMENT_IS_WEB = typeof window == "object" || (ENVIRONMENT_IS_WEB_WORKER && !ENVIRONMENT_IS_NODE);
export const ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE;
export const browserVirtualAppBase = "/managed"; // keep in sync other places that define browserVirtualAppBase

export let runtimeHelpers: RuntimeHelpers = {} as any;
export let loaderHelpers: LoaderHelpers = {} as any;
Expand Down
3 changes: 2 additions & 1 deletion src/mono/browser/test-main.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export const ENVIRONMENT_IS_SIDECAR = ENVIRONMENT_IS_WEB_WORKER && typeof dotnet
export const ENVIRONMENT_IS_WORKER = ENVIRONMENT_IS_WEB_WORKER && !ENVIRONMENT_IS_SIDECAR; // we redefine what ENVIRONMENT_IS_WORKER, we replace it in emscripten internals, so that sidecar works
export const ENVIRONMENT_IS_WEB = typeof window == "object" || (ENVIRONMENT_IS_WEB_WORKER && !ENVIRONMENT_IS_NODE);
export const ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE;
export const browserVirtualAppBase = "/managed"; // keep in sync other places that define browserVirtualAppBase
export const isFirefox = !!(ENVIRONMENT_IS_WEB && navigator.userAgent.includes("Firefox"));
export const isChromium = !!(ENVIRONMENT_IS_WEB && navigator.userAgentData && navigator.userAgentData.brands.some(b => b.brand === "Google Chrome" || b.brand === "Microsoft Edge" || b.brand === "Chromium"));

Expand Down Expand Up @@ -111,7 +112,7 @@ function initRunArgs(runArgs) {
// set defaults
runArgs.applicationArguments = runArgs.applicationArguments === undefined ? [] : runArgs.applicationArguments;
runArgs.profilers = runArgs.profilers === undefined ? [] : runArgs.profilers;
runArgs.workingDirectory = runArgs.workingDirectory === undefined ? '/' : runArgs.workingDirectory;
runArgs.workingDirectory = runArgs.workingDirectory === undefined ? browserVirtualAppBase : runArgs.workingDirectory;
runArgs.environmentVariables = runArgs.environmentVariables === undefined ? {} : runArgs.environmentVariables;
runArgs.runtimeArgs = runArgs.runtimeArgs === undefined ? [] : runArgs.runtimeArgs;
runArgs.enableGC = runArgs.enableGC === undefined ? true : runArgs.enableGC;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ Copyright (c) .NET Foundation. All rights reserved.
<Target Name="ComputeWasmVfs">
<ItemGroup>
<WasmFilesToIncludeInFileSystem Condition="'%(WasmFilesToIncludeInFileSystem.TargetPath)' == ''">
<TargetPath>/%(WasmFilesToIncludeInFileSystem.Identity)</TargetPath>
<TargetPath>%(WasmFilesToIncludeInFileSystem.Identity)</TargetPath>
</WasmFilesToIncludeInFileSystem>
</ItemGroup>

Expand Down
2 changes: 1 addition & 1 deletion src/mono/sample/mbr/browser/WasmDelta.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
<Target Name="PrepareDeltasForWasmApp" DependsOnTargets="Build;CompileDiff;ComputeDeltaFileOutputNames">
<ItemGroup>
<WasmFilesToIncludeInFileSystem Include="@(_DeltaFileForPublish)">
<TargetPath>\%(_DeltaFileForPublish.Filename)%(_DeltaFileForPublish.Extension)</TargetPath>
<TargetPath>%(_DeltaFileForPublish.Filename)%(_DeltaFileForPublish.Extension)</TargetPath>
</WasmFilesToIncludeInFileSystem>
</ItemGroup>
</Target>
Expand Down
2 changes: 1 addition & 1 deletion src/mono/sample/wasm/Directory.Build.targets
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@
</Target>

<Target Name="RunSampleWithV8" DependsOnTargets="BuildSampleInTree;_ComputeMainJSFileName">
<Exec WorkingDirectory="bin/publish/wwwroot" Command="v8 $(_WasmMainJSFileName) $(Args)" IgnoreExitCode="true" />
<Exec WorkingDirectory="bin/publish/wwwroot" Command="v8 --module $(_WasmMainJSFileName) $(Args)" IgnoreExitCode="true" />
</Target>
<Target Name="RunSampleWithNode" DependsOnTargets="BuildSampleInTree;_ComputeMainJSFileName">
<Exec WorkingDirectory="bin/publish/wwwroot" Command="node $(_WasmMainJSFileName) $(Args)" IgnoreExitCode="true" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ public BuildEnvironment()
$" {nameof(IsRunningOnCI)} is true but {nameof(IsWorkloadWithMultiThreadingForDefaultFramework)} is false.");
}

UseWebcil = EnvironmentVariables.UseWebcil && EnvironmentVariables.RuntimeFlavor != "CoreCLR"; // TODO-WASM: CoreCLR support for Webcil
UseWebcil = EnvironmentVariables.UseWebcil && EnvironmentVariables.RuntimeFlavor != "CoreCLR"; // TODO-WASM: CoreCLR support for Webcil https://github.com/dotnet/runtime/issues/120248

if (EnvironmentVariables.BuiltNuGetsPath is null || !Directory.Exists(EnvironmentVariables.BuiltNuGetsPath))
throw new Exception($"Cannot find 'BUILT_NUGETS_PATH={EnvironmentVariables.BuiltNuGetsPath}'");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,6 @@ public async Task LoadFilesToVfs(bool publish)

Assert.Contains(result.TestOutput, m => m.Contains("'/myfiles/Vfs1.txt' exists 'True' with content 'Vfs1.txt'"));
Assert.Contains(result.TestOutput, m => m.Contains("'/myfiles/Vfs2.txt' exists 'True' with content 'Vfs2.txt'"));
Assert.Contains(result.TestOutput, m => m.Contains("'/subdir/subsubdir/Vfs3.txt' exists 'True' with content 'Vfs3.txt'"));
Assert.Contains(result.TestOutput, m => m.Contains("'subdir/subsubdir/Vfs3.txt' exists 'True' with content 'Vfs3.txt'"));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ public static void Run()
// Check file presence in VFS based on application environment
PrintFileExistence("/myfiles/Vfs1.txt");
PrintFileExistence("/myfiles/Vfs2.txt");
PrintFileExistence("/subdir/subsubdir/Vfs3.txt");
PrintFileExistence("subdir/subsubdir/Vfs3.txt");
}

// Synchronize with FilesToIncludeInFileSystemTests
Expand Down
1 change: 1 addition & 0 deletions src/native/corehost/browserhost/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ target_link_options(browserhost PRIVATE
-sMODULARIZE=1
-sEXPORT_ES6=1
-sEXIT_RUNTIME=1
-sALLOW_TABLE_GROWTH=1
-sEXPORTED_RUNTIME_METHODS=BROWSER_HOST,${CMAKE_EMCC_EXPORTED_RUNTIME_METHODS}
-sEXPORTED_FUNCTIONS=${CMAKE_EMCC_EXPORTED_FUNCTIONS}
-sEXPORT_NAME=createDotnetRuntime
Expand Down
149 changes: 149 additions & 0 deletions src/native/corehost/browserhost/host/assets.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

import type { CharPtr, VfsAsset, VoidPtr, VoidPtrPtr } from "./types";
import { _ems_ } from "../../../libs/Common/JavaScript/ems-ambient";

import { dotnetAssert, dotnetLogger } from "./cross-module";
import { browserVirtualAppBase, ENVIRONMENT_IS_WEB } from "./per-module";

const hasInstantiateStreaming = typeof WebAssembly !== "undefined" && typeof WebAssembly.instantiateStreaming === "function";
const loadedAssemblies: Map<string, { ptr: number, length: number }> = new Map();
// eslint-disable-next-line @typescript-eslint/no-unused-vars
let wasmMemory: WebAssembly.Memory = undefined as any;
// eslint-disable-next-line @typescript-eslint/no-unused-vars
let wasmMainTable: WebAssembly.Table = undefined as any;

// eslint-disable-next-line @typescript-eslint/no-unused-vars
export function registerPdbBytes(bytes: Uint8Array, virtualPath: string) {
// WASM-TODO: https://github.com/dotnet/runtime/issues/122921
}

export function registerDllBytes(bytes: Uint8Array, virtualPath: string) {
const sp = _ems_.stackSave();
try {
const sizeOfPtr = 4;
const ptrPtr = _ems_.stackAlloc(sizeOfPtr);
if (_ems_._posix_memalign(ptrPtr as any, 16, bytes.length)) {
throw new Error("posix_memalign failed");
}

const ptr = _ems_.HEAPU32[ptrPtr as any >>> 2];
_ems_.HEAPU8.set(bytes, ptr >>> 0);
const name = virtualPath.substring(virtualPath.lastIndexOf("/") + 1);

_ems_.dotnetLogger.debug(`Registered assembly '${virtualPath}' (name: '${name}') at ${ptr.toString(16)} length ${bytes.length}`);
loadedAssemblies.set(virtualPath, { ptr, length: bytes.length });
loadedAssemblies.set(name, { ptr, length: bytes.length });
} finally {
_ems_.stackRestore(sp);
}
}

export function BrowserHost_ExternalAssemblyProbe(pathPtr: CharPtr, outDataStartPtr: VoidPtrPtr, outSize: VoidPtr) {
const path = _ems_.UTF8ToString(pathPtr);
const assembly = loadedAssemblies.get(path);
if (assembly) {
_ems_.HEAPU32[outDataStartPtr as any >>> 2] = assembly.ptr;
// int64_t target
_ems_.HEAPU32[outSize as any >>> 2] = assembly.length;
_ems_.HEAPU32[((outSize as any) + 4) >>> 2] = 0;
return true;
}
_ems_.dotnetLogger.debug(`Assembly not found: '${path}'`);
_ems_.HEAPU32[outDataStartPtr as any >>> 2] = 0;
_ems_.HEAPU32[outSize as any >>> 2] = 0;
_ems_.HEAPU32[((outSize as any) + 4) >>> 2] = 0;
return false;
}

export function loadIcuData(bytes: Uint8Array) {
const sp = _ems_.stackSave();
try {
const sizeOfPtr = 4;
const ptrPtr = _ems_.stackAlloc(sizeOfPtr);
if (_ems_._posix_memalign(ptrPtr as any, 16, bytes.length)) {
throw new Error("posix_memalign failed for ICU data");
}

const ptr = _ems_.HEAPU32[ptrPtr as any >>> 2];
_ems_.HEAPU8.set(bytes, ptr >>> 0);

const result = _ems_._wasm_load_icu_data(ptr as unknown as VoidPtr);
if (!result) {
throw new Error("Failed to initialize ICU data");
}
} finally {
_ems_.stackRestore(sp);
}
}

export function installVfsFile(bytes: Uint8Array, asset: VfsAsset) {
const virtualName: string = typeof (asset.virtualPath) === "string"
? asset.virtualPath
: asset.name;
const lastSlash = virtualName.lastIndexOf("/");
let parentDirectory = (lastSlash > 0)
? virtualName.substring(0, lastSlash)
: null;
let fileName = (lastSlash > 0)
? virtualName.substring(lastSlash + 1)
: virtualName;
if (fileName.startsWith("/")) {
fileName = fileName.substring(1);
}
if (parentDirectory) {
if (!parentDirectory.startsWith("/"))
parentDirectory = browserVirtualAppBase + "/" + parentDirectory;

_ems_.dotnetLogger.debug(`Creating directory '${parentDirectory}'`);

_ems_.FS.createPath(
"/", parentDirectory, true, true // fixme: should canWrite be false?
);
} else {
parentDirectory = browserVirtualAppBase;
}

_ems_.dotnetLogger.debug(`Creating file '${fileName}' in directory '${parentDirectory}'`);

_ems_.FS.createDataFile(
parentDirectory, fileName,
bytes, true /* canRead */, true /* canWrite */, true /* canOwn */
);
}

export async function instantiateWasm(wasmPromise: Promise<Response>, imports: WebAssembly.Imports, isStreaming: boolean, isMainModule: boolean): Promise<{ instance: WebAssembly.Instance; module: WebAssembly.Module; }> {
let instance: WebAssembly.Instance;
let module: WebAssembly.Module;
if (!hasInstantiateStreaming || !isStreaming) {
const res = await checkResponseOk(wasmPromise);
const data = await res.arrayBuffer();
module = await WebAssembly.compile(data);
instance = await WebAssembly.instantiate(module, imports);
} else {
const instantiated = await WebAssembly.instantiateStreaming(wasmPromise, imports);
await checkResponseOk(wasmPromise);
instance = instantiated.instance;
module = instantiated.module;
}
if (isMainModule) {
wasmMemory = instance.exports.memory as WebAssembly.Memory;
wasmMainTable = instance.exports.__indirect_function_table as WebAssembly.Table;
}
return { instance, module };
}

async function checkResponseOk(wasmPromise: Promise<Response> | undefined): Promise<Response> {
dotnetAssert.check(wasmPromise, "WASM binary promise was not initialized");
const res = await wasmPromise;
if (!res || res.ok === false) {
throw new Error(`Failed to load WebAssembly module. HTTP status: ${res?.status} ${res?.statusText}`);
}
const contentType = res.headers && res.headers.get ? res.headers.get("Content-Type") : undefined;
if (ENVIRONMENT_IS_WEB && contentType !== "application/wasm") {
dotnetLogger.warn("WebAssembly resource does not have the expected content type \"application/wasm\", so falling back to slower ArrayBuffer instantiation.");
}
return res;
}

4 changes: 4 additions & 0 deletions src/native/corehost/browserhost/host/cross-module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

export * from "../../../libs/Common/JavaScript/cross-module";
Loading
Loading