taglib-wasm
Version:
TagLib for TypeScript platforms: Deno, Node.js, Bun, Electron, browsers, and Cloudflare Workers
203 lines (202 loc) • 5.67 kB
JavaScript
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
import { detectRuntime } from "./detector.js";
import {
initializeWasmer,
isWasmerAvailable,
loadWasmerWasi
} from "./wasmer-sdk-loader.js";
class UnifiedLoaderError extends Error {
constructor(message, cause) {
super(message);
__publicField(this, "code", "UNIFIED_LOADER_ERROR");
this.name = "UnifiedLoaderError";
this.cause = cause;
}
}
class ModuleLoadError extends Error {
constructor(message, wasmType, cause) {
super(message);
this.wasmType = wasmType;
__publicField(this, "code", "MODULE_LOAD_ERROR");
this.name = "ModuleLoadError";
this.cause = cause;
}
}
async function loadUnifiedTagLibModule(options = {}) {
const startTime = performance.now();
const runtime = detectRuntime();
if (options.debug) {
console.log(`[UnifiedLoader] Detected runtime: ${runtime.environment}`);
}
const wasmType = await selectWasmType(runtime, options);
if (options.debug) {
console.log(
`[UnifiedLoader] Selected ${wasmType} for ${runtime.environment}`
);
}
const { module, actualWasmType } = await loadModule(
wasmType,
runtime,
options
);
const unifiedModule = await createUnifiedModule(
module,
runtime,
actualWasmType,
startTime
);
if (options.debug) {
const initTime = performance.now() - startTime;
console.log(`[UnifiedLoader] Initialized in ${initTime.toFixed(2)}ms`);
}
return unifiedModule;
}
async function selectWasmType(runtime, options) {
if (options.forceWasmType) {
return options.forceWasmType;
}
if (options.disableOptimizations) {
return "emscripten";
}
if (runtime.supportsFilesystem && await isWasmerAvailable()) {
return "wasi";
}
return "emscripten";
}
async function loadModule(wasmType, _runtime, options) {
if (wasmType === "wasi") {
return await loadWasiModuleWithFallback(options);
} else {
return {
module: await loadEmscriptenModule(options),
actualWasmType: "emscripten"
};
}
}
async function loadWasiModuleWithFallback(options) {
try {
await initializeWasmer(options.useInlineWasm);
const wasiModule = await loadWasmerWasi({
wasmPath: options.wasmUrl || "./dist/taglib-wasi.wasm",
useInlineWasm: options.useInlineWasm,
debug: options.debug
});
return { module: wasiModule, actualWasmType: "wasi" };
} catch (error) {
if (options.debug) {
console.warn(
`[UnifiedLoader] WASI loading failed, falling back to Emscripten:`,
error
);
}
return {
module: await loadEmscriptenModule(options),
actualWasmType: "emscripten"
};
}
}
async function loadEmscriptenModule(options) {
try {
let createModule;
try {
const module2 = await import("../../build/taglib-wrapper.js");
createModule = module2.default;
} catch {
try {
const module2 = await import("../../dist/taglib-wrapper.js");
createModule = module2.default;
} catch {
throw new ModuleLoadError(
"Could not load Emscripten module from build or dist",
"emscripten"
);
}
}
const moduleConfig = {};
if (options.wasmBinary) {
moduleConfig.wasmBinary = options.wasmBinary;
}
if (options.wasmUrl) {
moduleConfig.locateFile = (path) => {
return path.endsWith(".wasm") ? options.wasmUrl : path;
};
}
const module = await createModule(moduleConfig);
return module;
} catch (error) {
throw new ModuleLoadError(
`Failed to load Emscripten module: ${error}`,
"emscripten",
error
);
}
}
async function createUnifiedModule(module, runtime, wasmType, startTime) {
const isWasi = wasmType === "wasi";
const initTime = performance.now() - startTime;
if (isWasi) {
const wasiModule = module;
const adapter = await createWasiAdapter(wasiModule);
return Object.assign(adapter, {
runtime,
isWasi: true,
isEmscripten: false,
getPerformanceMetrics: () => ({
initTime,
wasmType: "wasi",
environment: runtime.environment,
memoryUsage: wasiModule.memory.buffer.byteLength
})
});
} else {
const emscriptenModule = module;
return {
...emscriptenModule,
runtime,
isWasi: false,
isEmscripten: true,
getPerformanceMetrics: () => ({
initTime,
wasmType: "emscripten",
environment: runtime.environment,
memoryUsage: emscriptenModule.HEAP8?.buffer.byteLength
})
};
}
}
async function createWasiAdapter(wasiModule) {
const { WasiToTagLibAdapter } = await import("./wasi-adapter.js");
return new WasiToTagLibAdapter(wasiModule);
}
function isWasiAvailable() {
const runtime = detectRuntime();
return runtime.wasmType === "wasi" && runtime.supportsFilesystem;
}
function getRecommendedConfig() {
const runtime = detectRuntime();
if (runtime.environment === "browser") {
return {
forceWasmType: "emscripten",
disableOptimizations: false
};
}
if (runtime.supportsFilesystem) {
return {
forceWasmType: "wasi",
useInlineWasm: false,
disableOptimizations: false
};
}
return {
disableOptimizations: false
};
}
export {
ModuleLoadError,
UnifiedLoaderError,
getRecommendedConfig,
isWasiAvailable,
loadUnifiedTagLibModule
};