forked from forks/ffprobe-wasm-npm
Add project files
This commit is contained in:
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
.DS_Store
|
||||
.vscode/
|
||||
node_modules/
|
||||
dist/
|
||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "ffprobe-wasm-app"]
|
||||
path = ffprobe-wasm-app
|
||||
url = https://github.com/alfg/ffprobe-wasm
|
||||
22
LICENSE
Normal file
22
LICENSE
Normal file
@@ -0,0 +1,22 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2022 Tomás Fox
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
|
||||
42
README.md
Normal file
42
README.md
Normal file
@@ -0,0 +1,42 @@
|
||||
ffprobe-wasm
|
||||
==========
|
||||
|
||||
Gather information from multimedia streams. Works on the browser and Node.js.
|
||||
|
||||
Uses the code at [alfg/ffprobe-wasm](https://github.com/alfg/ffprobe-wasm), but in a packaged format, so it can be reused in other projects.
|
||||
|
||||
_Note_: This project doesn't build or use FFProbe. Instead it uses FFmpeg's libavformat and libavcodec to output similar results.
|
||||
|
||||
## Installation
|
||||
|
||||
```sh
|
||||
npm install ffprobe-wasm
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
Node.js
|
||||
|
||||
```ts
|
||||
import { FFprobeWorker } from 'ffprobe-wasm/node.mjs';
|
||||
|
||||
const worker = new FFprobeWorker();
|
||||
|
||||
const fileInfo = await worker.getFileInfo('file.mp4');
|
||||
console.log(fileInfo);
|
||||
```
|
||||
|
||||
Browser
|
||||
|
||||
```ts
|
||||
import { FFprobeWorker } from 'ffprobe-wasm/browser.mjs';
|
||||
|
||||
const worker = new FFprobeWorker();
|
||||
|
||||
// input is the reference to a <input type="file" /> element
|
||||
input.addEventListener('change', (event) => {
|
||||
const file = event.target.files[0]
|
||||
const fileInfo = await worker.getFileInfo(file);
|
||||
console.log(fileInfo);
|
||||
});
|
||||
```
|
||||
22
build.sh
Executable file
22
build.sh
Executable file
@@ -0,0 +1,22 @@
|
||||
#/bin/sh
|
||||
|
||||
# Exit on error
|
||||
set -e
|
||||
|
||||
# Clean
|
||||
rm -rf dist
|
||||
rm -rf ffprobe-wasm-app/dist
|
||||
|
||||
# Build wasm
|
||||
cd ffprobe-wasm-app
|
||||
# sed -i -e 's/ffprobe-wasm\.js/ffprobe-wasm.mjs/g;s/-o dist\/ffprobe-wasm\.mjs \\/-o dist\/ffprobe-wasm.mjs -s EXPORT_NAME=ffprobe \\/' Makefile
|
||||
docker-compose run ffprobe-wasm make
|
||||
cd ..
|
||||
cp -R ffprobe-wasm-app/dist dist
|
||||
cp src/*.d.* dist
|
||||
|
||||
# Build browser/node workers
|
||||
npm run build
|
||||
|
||||
# Copy package.json
|
||||
cp package.json dist
|
||||
1
ffprobe-wasm-app
Submodule
1
ffprobe-wasm-app
Submodule
Submodule ffprobe-wasm-app added at ff36b01373
50
package-lock.json
generated
Normal file
50
package-lock.json
generated
Normal file
@@ -0,0 +1,50 @@
|
||||
{
|
||||
"name": "ffprobe-wasm",
|
||||
"version": "0.1.0",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "ffprobe-wasm",
|
||||
"version": "0.1.0",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/node": "^17.0.21",
|
||||
"typescript": "^4.5.5"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "17.0.21",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz",
|
||||
"integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "4.5.5",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz",
|
||||
"integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4.2.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/node": {
|
||||
"version": "17.0.21",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz",
|
||||
"integrity": "sha512-DBZCJbhII3r90XbQxI8Y9IjjiiOGlZ0Hr32omXIZvwwZ7p4DMMXGrKXVyPfuoBOri9XNtL0UK69jYIBIsRX3QQ==",
|
||||
"dev": true
|
||||
},
|
||||
"typescript": {
|
||||
"version": "4.5.5",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.5.tgz",
|
||||
"integrity": "sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
}
|
||||
27
package.json
Normal file
27
package.json
Normal file
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"name": "ffprobe-wasm",
|
||||
"version": "0.1.0",
|
||||
"description": "ffprobe-like for browser and node, powered by WebAssembly",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/tfoxy/ffprobe-wasm"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/tfoxy/ffprobe-wasm/issues"
|
||||
},
|
||||
"keywords": [
|
||||
"ffprobe",
|
||||
"WebAssembly",
|
||||
"ffmpeg",
|
||||
"video"
|
||||
],
|
||||
"author": "Tomás Fox <tomas.c.fox@gmail.com>",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"build": "tsc"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^17.0.21",
|
||||
"typescript": "^4.5.5"
|
||||
}
|
||||
}
|
||||
49
src/browser.mts
Normal file
49
src/browser.mts
Normal file
@@ -0,0 +1,49 @@
|
||||
import type { Chapter, ChapterTag, FileInfo, Frame, FramesInfo, Stream } from "./ffprobe-wasm.mjs";
|
||||
import type {
|
||||
IncomingMessage,
|
||||
IncomingData,
|
||||
OutgoingMessage,
|
||||
} from "./worker.mjs";
|
||||
|
||||
export class FFprobeWorker {
|
||||
readonly #worker: Worker;
|
||||
|
||||
constructor() {
|
||||
this.#worker = new Worker("./worker-browser.mjs");
|
||||
}
|
||||
|
||||
async getFileInfo(file: File): Promise<FileInfo> {
|
||||
return this.#postMessage({ type: "getFileInfo", payload: [file.name, { files: [file] }] });
|
||||
}
|
||||
|
||||
async getFrames(file: File, offset: number): Promise<FramesInfo> {
|
||||
return this.#postMessage({ type: "getFrames", payload: [file.name, { files: [file] }, offset] });
|
||||
}
|
||||
|
||||
terminate(): void {
|
||||
this.#worker.terminate();
|
||||
}
|
||||
|
||||
#postMessage(data: IncomingData): Promise<any> {
|
||||
const channel = new MessageChannel();
|
||||
const message: IncomingMessage = {
|
||||
...data,
|
||||
port: channel.port2
|
||||
};
|
||||
|
||||
this.#worker.postMessage(message, [channel.port2]);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
channel.port1.onmessage = (event: MessageEvent<OutgoingMessage>) => {
|
||||
const { data } = event;
|
||||
if (data.status === "success") {
|
||||
resolve(data.payload);
|
||||
} else {
|
||||
reject(new Error(data.message));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export type { Chapter, ChapterTag, FileInfo, Frame, FramesInfo, Stream };
|
||||
145
src/ffprobe-wasm-shared.d.ts
vendored
Normal file
145
src/ffprobe-wasm-shared.d.ts
vendored
Normal file
@@ -0,0 +1,145 @@
|
||||
export interface FFprobe {
|
||||
get_file_info(path: string): Raw<FileInfo>;
|
||||
get_frames(path: string, offset: number): Raw<FramesInfo>;
|
||||
FS: FS;
|
||||
avutil_version(): string;
|
||||
avcodec_version(): string;
|
||||
avformat_version(): string;
|
||||
onRuntimeInitialized(): void;
|
||||
}
|
||||
|
||||
export type FSMountOptions = WorkerFSMountOptions | NodeFSMountOptions;
|
||||
|
||||
export interface WorkerFSMountOptions {
|
||||
files?: File[];
|
||||
blobs?: Blob[];
|
||||
packages?: any[];
|
||||
}
|
||||
|
||||
export interface NodeFSMountOptions {
|
||||
root: string;
|
||||
}
|
||||
|
||||
export interface FSFilesystemMountOptions {
|
||||
type: FSFilesystem;
|
||||
opts: FSFilesystemMountOptions;
|
||||
mountpoint: string;
|
||||
mounts: any[];
|
||||
}
|
||||
|
||||
export interface FSFilesystem {
|
||||
mount(opts: FSFilesystemMountOptions): FSNode;
|
||||
}
|
||||
|
||||
export interface FSNode {
|
||||
contents: Record<string, FSNode>;
|
||||
id: number;
|
||||
mode: number;
|
||||
name: string;
|
||||
parent: FSNode;
|
||||
timestamp: number;
|
||||
isDevice(): boolean;
|
||||
isFolder(): boolean;
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
export interface FSFilesystems {
|
||||
MEMFS: FSFilesystem;
|
||||
WORKERFS: FSFilesystem;
|
||||
NODEFS: FSFilesystem;
|
||||
}
|
||||
|
||||
export interface FS {
|
||||
analyzePath(path: string, dontResolveLastLink?: boolean): AnalyzePathReturn;
|
||||
mkdir(path: string, mode?: number): number;
|
||||
mount(type: FSFilesystem, opts: FSMountOptions, mountpoint: string): FSNode;
|
||||
unmount(mountpoint: string): void;
|
||||
filesystems: FSFilesystems;
|
||||
}
|
||||
|
||||
export interface AnalyzePathReturn {
|
||||
isRoot: boolean;
|
||||
exists: boolean;
|
||||
error: number;
|
||||
name: string | null;
|
||||
path: string | null;
|
||||
object: any | null;
|
||||
parentExists: boolean;
|
||||
parentPath: string | null;
|
||||
parentObject: any | null;
|
||||
}
|
||||
|
||||
export interface FileInfo {
|
||||
bit_rate: number
|
||||
chapters: Chapter[]
|
||||
duration: number
|
||||
flags: number
|
||||
name: string
|
||||
nb_chapters: number
|
||||
nb_streams: number
|
||||
streams: Stream[]
|
||||
url: string
|
||||
}
|
||||
|
||||
export interface Collection<T> {
|
||||
count: { value: number }
|
||||
ptr: number;
|
||||
ptrType: any;
|
||||
get(index: number): T;
|
||||
size(): number;
|
||||
}
|
||||
|
||||
export type Raw<T> = {
|
||||
[K in keyof T]: T[K] extends Array<infer U> ? Collection<Raw<U>> : T[K]
|
||||
}
|
||||
|
||||
export interface Chapter {
|
||||
end: number
|
||||
id: number
|
||||
start: number
|
||||
tags: ChapterTag[]
|
||||
/**
|
||||
* @example "1/1000"
|
||||
*/
|
||||
time_base: string
|
||||
}
|
||||
|
||||
export interface ChapterTag {
|
||||
key: string
|
||||
value: string
|
||||
}
|
||||
|
||||
export interface Stream {
|
||||
bit_rate: number
|
||||
channels: number
|
||||
codec_name: string
|
||||
codec_type: number
|
||||
duration: number
|
||||
format: string
|
||||
frame_size: number
|
||||
height: number
|
||||
id: number
|
||||
level: number
|
||||
profile: string
|
||||
sample_rate: number
|
||||
start_time: number
|
||||
width: number
|
||||
}
|
||||
|
||||
export interface FramesInfo {
|
||||
avg_frame_rate: number
|
||||
duration: number
|
||||
frames: Frame[]
|
||||
gop_size: number
|
||||
nb_frames: number
|
||||
time_base: number
|
||||
}
|
||||
|
||||
export interface Frame {
|
||||
dts: number
|
||||
frame_number: number
|
||||
pict_type: number
|
||||
pkt_size: number
|
||||
pos: number
|
||||
pts: number
|
||||
}
|
||||
9
src/ffprobe-wasm.d.mts
Normal file
9
src/ffprobe-wasm.d.mts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { FFprobe } from "./ffprobe-wasm-shared";
|
||||
|
||||
export * from "./ffprobe-wasm-shared";
|
||||
|
||||
export default function loadFFprobe(ffprobe?: FFprobeInit): Promise<FFprobe>;
|
||||
|
||||
export interface FFprobeInit {
|
||||
locateFile?(path: string, scriptDirectory: string): string;
|
||||
}
|
||||
7
src/ffprobe-wasm.d.ts
vendored
Normal file
7
src/ffprobe-wasm.d.ts
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
import { FFprobe } from "./ffprobe-wasm-shared";
|
||||
|
||||
export * from "./ffprobe-wasm-shared";
|
||||
|
||||
declare const ffprobe: FFprobe;
|
||||
|
||||
export default ffprobe;
|
||||
52
src/node.mts
Normal file
52
src/node.mts
Normal file
@@ -0,0 +1,52 @@
|
||||
import { basename, dirname } from "path";
|
||||
import { fileURLToPath } from 'url';
|
||||
import { MessageChannel, Worker } from "worker_threads";
|
||||
import type { Chapter, ChapterTag, FileInfo, Frame, FramesInfo, Stream } from "./ffprobe-wasm.mjs";
|
||||
import type {
|
||||
IncomingMessage,
|
||||
IncomingData,
|
||||
OutgoingMessage,
|
||||
} from "./worker.mjs";
|
||||
|
||||
export class FFprobeWorker {
|
||||
readonly #worker: Worker;
|
||||
|
||||
constructor() {
|
||||
const __dirname = dirname(fileURLToPath(import.meta.url));
|
||||
this.#worker = new Worker(`${__dirname}/worker-node.mjs`);
|
||||
}
|
||||
|
||||
async getFileInfo(filePath: string): Promise<FileInfo> {
|
||||
return this.#postMessage({ type: "getFileInfo", payload: [basename(filePath), { root: dirname(filePath) }] });
|
||||
}
|
||||
|
||||
async getFrames(filePath: string, offset: number): Promise<FramesInfo> {
|
||||
return this.#postMessage({ type: "getFrames", payload: [basename(filePath), { root: dirname(filePath) }, offset] });
|
||||
}
|
||||
|
||||
terminate(): void {
|
||||
this.#worker.terminate();
|
||||
}
|
||||
|
||||
#postMessage(data: IncomingData): Promise<any> {
|
||||
const channel = new MessageChannel();
|
||||
const message: IncomingMessage = {
|
||||
...data,
|
||||
port: channel.port2
|
||||
};
|
||||
|
||||
this.#worker.postMessage(message, [channel.port2]);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
channel.port1.on("message", (data: OutgoingMessage) => {
|
||||
if (data.status === "success") {
|
||||
resolve(data.payload);
|
||||
} else {
|
||||
reject(new Error(data.message));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export type { Chapter, ChapterTag, FileInfo, Frame, FramesInfo, Stream };
|
||||
11
src/worker-browser.mts
Normal file
11
src/worker-browser.mts
Normal file
@@ -0,0 +1,11 @@
|
||||
import loadFFprobe from "./ffprobe-wasm.mjs";
|
||||
import { createListener, IncomingMessage } from "./worker.mjs";
|
||||
|
||||
const listener = createListener(
|
||||
loadFFprobe({
|
||||
locateFile: (path) => `${location.origin}/node_modules/ffprobe-wasm/${path}`
|
||||
}),
|
||||
"WORKERFS",
|
||||
);
|
||||
|
||||
self.onmessage = (event: MessageEvent<IncomingMessage>) => listener(event.data);
|
||||
19
src/worker-node.mts
Normal file
19
src/worker-node.mts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { createRequire } from "module";
|
||||
import { parentPort } from "worker_threads";
|
||||
import type { FFprobe } from "./ffprobe-wasm.js";
|
||||
import { createListener } from "./worker.mjs";
|
||||
|
||||
if (!parentPort) {
|
||||
throw new Error("parentPort must be defined. Are you sure you are in a worker context?");
|
||||
}
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
|
||||
const listener = createListener(new Promise((resolve) => {
|
||||
const ffprobe: FFprobe = require('./ffprobe-wasm.js')
|
||||
ffprobe.onRuntimeInitialized = () => {
|
||||
resolve(ffprobe);
|
||||
}
|
||||
}), "NODEFS");
|
||||
|
||||
parentPort.on("message", listener);
|
||||
133
src/worker.mts
Normal file
133
src/worker.mts
Normal file
@@ -0,0 +1,133 @@
|
||||
import type { MessagePort as NodeMessagePort } from "worker_threads";
|
||||
import type { Chapter, ChapterTag, FFprobe, FileInfo, FramesInfo, FSFilesystems, FSMountOptions, Stream } from "./ffprobe-wasm-shared";
|
||||
|
||||
export type IncomingMessage = { port: MessagePort | NodeMessagePort } & IncomingData;
|
||||
|
||||
export type IncomingData =
|
||||
| {
|
||||
type: "getFileInfo";
|
||||
payload: [fileName: string, mountOptions: FSMountOptions];
|
||||
}
|
||||
| {
|
||||
type: "getFrames";
|
||||
payload: [fileName: string, mountOptions: FSMountOptions, offset: number];
|
||||
};
|
||||
|
||||
export type OutgoingMessage =
|
||||
| ({ status: "success" } & OutgoingData)
|
||||
| { status: "error"; message: string };
|
||||
|
||||
export type OutgoingData =
|
||||
| {
|
||||
type: "getFileInfo";
|
||||
payload: FileInfo;
|
||||
}
|
||||
| {
|
||||
type: "getFrames";
|
||||
payload: FramesInfo;
|
||||
};
|
||||
|
||||
export function createListener(
|
||||
ffprobePromise: Promise<FFprobe>,
|
||||
fsType: keyof FSFilesystems,
|
||||
) {
|
||||
return onmessage;
|
||||
|
||||
async function onmessage(data: IncomingMessage) {
|
||||
try {
|
||||
switch (data.type) {
|
||||
case "getFileInfo":
|
||||
data.port.postMessage({
|
||||
status: "success",
|
||||
payload: await getFileInfo(...data.payload),
|
||||
type: data.type,
|
||||
});
|
||||
break;
|
||||
case "getFrames":
|
||||
data.port.postMessage({
|
||||
status: "success",
|
||||
payload: await getFrames(...data.payload),
|
||||
type: data.type,
|
||||
});
|
||||
break;
|
||||
default:
|
||||
const _: never = data;
|
||||
throw new Error(`Unknown event: ${JSON.stringify(_)}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
data.port.postMessage({
|
||||
status: "error",
|
||||
message: error instanceof Error ? error.message : "Unknown error",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async function getFileInfo(fileName: string, mountOptions: FSMountOptions): Promise<FileInfo> {
|
||||
const { FS, get_file_info } = await ffprobePromise;
|
||||
try {
|
||||
if (!FS.analyzePath("/work").exists) {
|
||||
FS.mkdir("/work");
|
||||
}
|
||||
FS.mount(FS.filesystems[fsType], mountOptions, "/work");
|
||||
|
||||
// Call the wasm module.
|
||||
const rawInfo = get_file_info(`/work/${fileName}`);
|
||||
|
||||
// Remap streams into collection.
|
||||
const streams: Stream[] = [];
|
||||
for (let i = 0; i < rawInfo.streams.size(); i++) {
|
||||
streams.push(rawInfo.streams.get(i));
|
||||
}
|
||||
|
||||
// Remap chapters into collection.
|
||||
const chapters: Chapter[] = [];
|
||||
for (let i = 0; i < rawInfo.chapters.size(); i++) {
|
||||
const rawChapter = rawInfo.chapters.get(i);
|
||||
|
||||
const tags: ChapterTag[] = [];
|
||||
for (let j = 0; j < rawChapter.tags.size(); j++) {
|
||||
tags.push(rawChapter.tags.get(j));
|
||||
}
|
||||
|
||||
chapters.push({ ...rawChapter, tags });
|
||||
}
|
||||
|
||||
return {
|
||||
...rawInfo,
|
||||
streams,
|
||||
chapters,
|
||||
};
|
||||
} finally {
|
||||
// Cleanup mount.
|
||||
FS.unmount("/work");
|
||||
}
|
||||
}
|
||||
|
||||
async function getFrames(fileName: string, mountOptions: FSMountOptions, offset: number): Promise<FramesInfo> {
|
||||
const { FS, get_frames } = await ffprobePromise;
|
||||
try {
|
||||
if (!FS.analyzePath("/work").exists) {
|
||||
FS.mkdir("/work");
|
||||
}
|
||||
FS.mount(FS.filesystems.WORKERFS, mountOptions, "/work");
|
||||
|
||||
// Call the wasm module.
|
||||
const framesInfo = get_frames(`/work/${fileName}`, offset);
|
||||
|
||||
// Remap frames into collection.
|
||||
const frames = [];
|
||||
for (let i = 0; i < framesInfo.frames.size(); i++) {
|
||||
frames.push(framesInfo.frames.get(i));
|
||||
}
|
||||
|
||||
return {
|
||||
...framesInfo,
|
||||
frames,
|
||||
};
|
||||
} finally {
|
||||
// Cleanup mount.
|
||||
FS.unmount("/work");
|
||||
}
|
||||
}
|
||||
}
|
||||
17
tsconfig.json
Normal file
17
tsconfig.json
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2021",
|
||||
"lib": ["DOM", "ES2021"],
|
||||
"module": "ES2020",
|
||||
"moduleResolution": "Node",
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"allowJs": false,
|
||||
"strict": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"outDir": "./dist",
|
||||
"declaration": true
|
||||
},
|
||||
"include": ["./src"]
|
||||
}
|
||||
Reference in New Issue
Block a user