init project

This commit is contained in:
root
2026-07-31 13:12:54 -04:00
parent 0da92d5e02
commit f3863f760c
7215 changed files with 1860260 additions and 1 deletions
Generated Vendored
+16
View File
@@ -0,0 +1,16 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../esbuild/bin/esbuild" "$@"
else
exec node "$basedir/../esbuild/bin/esbuild" "$@"
fi
Generated Vendored Executable
+17
View File
@@ -0,0 +1,17 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\esbuild\bin\esbuild" %*
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../esbuild/bin/esbuild" $args
} else {
& "$basedir/node$exe" "$basedir/../esbuild/bin/esbuild" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../esbuild/bin/esbuild" $args
} else {
& "node$exe" "$basedir/../esbuild/bin/esbuild" $args
}
$ret=$LASTEXITCODE
}
exit $ret
Generated Vendored
+16
View File
@@ -0,0 +1,16 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../nanoid/bin/nanoid.cjs" "$@"
else
exec node "$basedir/../nanoid/bin/nanoid.cjs" "$@"
fi
Generated Vendored Executable
+17
View File
@@ -0,0 +1,17 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\nanoid\bin\nanoid.cjs" %*
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../nanoid/bin/nanoid.cjs" $args
} else {
& "$basedir/node$exe" "$basedir/../nanoid/bin/nanoid.cjs" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../nanoid/bin/nanoid.cjs" $args
} else {
& "node$exe" "$basedir/../nanoid/bin/nanoid.cjs" $args
}
$ret=$LASTEXITCODE
}
exit $ret
+16
View File
@@ -0,0 +1,16 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../which/bin/node-which" "$@"
else
exec node "$basedir/../which/bin/node-which" "$@"
fi
Generated Vendored Executable
+17
View File
@@ -0,0 +1,17 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\which\bin\node-which" %*
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../which/bin/node-which" $args
} else {
& "$basedir/node$exe" "$basedir/../which/bin/node-which" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../which/bin/node-which" $args
} else {
& "node$exe" "$basedir/../which/bin/node-which" $args
}
$ret=$LASTEXITCODE
}
exit $ret
+16
View File
@@ -0,0 +1,16 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../pixelmatch/bin/pixelmatch" "$@"
else
exec node "$basedir/../pixelmatch/bin/pixelmatch" "$@"
fi
Generated Vendored Executable
+17
View File
@@ -0,0 +1,17 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\pixelmatch\bin\pixelmatch" %*
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../pixelmatch/bin/pixelmatch" $args
} else {
& "$basedir/node$exe" "$basedir/../pixelmatch/bin/pixelmatch" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../pixelmatch/bin/pixelmatch" $args
} else {
& "node$exe" "$basedir/../pixelmatch/bin/pixelmatch" $args
}
$ret=$LASTEXITCODE
}
exit $ret
+16
View File
@@ -0,0 +1,16 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../playwright/cli.js" "$@"
else
exec node "$basedir/../playwright/cli.js" "$@"
fi
+16
View File
@@ -0,0 +1,16 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../playwright-core/cli.js" "$@"
else
exec node "$basedir/../playwright-core/cli.js" "$@"
fi
Generated Vendored Executable
+17
View File
@@ -0,0 +1,17 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\playwright-core\cli.js" %*
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../playwright-core/cli.js" $args
} else {
& "$basedir/node$exe" "$basedir/../playwright-core/cli.js" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../playwright-core/cli.js" $args
} else {
& "node$exe" "$basedir/../playwright-core/cli.js" $args
}
$ret=$LASTEXITCODE
}
exit $ret
Generated Vendored Executable
+17
View File
@@ -0,0 +1,17 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\playwright\cli.js" %*
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../playwright/cli.js" $args
} else {
& "$basedir/node$exe" "$basedir/../playwright/cli.js" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../playwright/cli.js" $args
} else {
& "node$exe" "$basedir/../playwright/cli.js" $args
}
$ret=$LASTEXITCODE
}
exit $ret
+16
View File
@@ -0,0 +1,16 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../@grpc/proto-loader/build/bin/proto-loader-gen-types.js" "$@"
else
exec node "$basedir/../@grpc/proto-loader/build/bin/proto-loader-gen-types.js" "$@"
fi
+17
View File
@@ -0,0 +1,17 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\@grpc\proto-loader\build\bin\proto-loader-gen-types.js" %*
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../@grpc/proto-loader/build/bin/proto-loader-gen-types.js" $args
} else {
& "$basedir/node$exe" "$basedir/../@grpc/proto-loader/build/bin/proto-loader-gen-types.js" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../@grpc/proto-loader/build/bin/proto-loader-gen-types.js" $args
} else {
& "node$exe" "$basedir/../@grpc/proto-loader/build/bin/proto-loader-gen-types.js" $args
}
$ret=$LASTEXITCODE
}
exit $ret
Generated Vendored
+16
View File
@@ -0,0 +1,16 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../rolldown/bin/cli.mjs" "$@"
else
exec node "$basedir/../rolldown/bin/cli.mjs" "$@"
fi
Generated Vendored Executable
+17
View File
@@ -0,0 +1,17 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\rolldown\bin\cli.mjs" %*
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../rolldown/bin/cli.mjs" $args
} else {
& "$basedir/node$exe" "$basedir/../rolldown/bin/cli.mjs" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../rolldown/bin/cli.mjs" $args
} else {
& "node$exe" "$basedir/../rolldown/bin/cli.mjs" $args
}
$ret=$LASTEXITCODE
}
exit $ret
Generated Vendored
+16
View File
@@ -0,0 +1,16 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../typescript/bin/tsc" "$@"
else
exec node "$basedir/../typescript/bin/tsc" "$@"
fi
Generated Vendored Executable
+17
View File
@@ -0,0 +1,17 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\typescript\bin\tsc" %*
Generated Vendored
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../typescript/bin/tsc" $args
} else {
& "$basedir/node$exe" "$basedir/../typescript/bin/tsc" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../typescript/bin/tsc" $args
} else {
& "node$exe" "$basedir/../typescript/bin/tsc" $args
}
$ret=$LASTEXITCODE
}
exit $ret
Generated Vendored
+16
View File
@@ -0,0 +1,16 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../typescript/bin/tsserver" "$@"
else
exec node "$basedir/../typescript/bin/tsserver" "$@"
fi
Generated Vendored Executable
+17
View File
@@ -0,0 +1,17 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\typescript\bin\tsserver" %*
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../typescript/bin/tsserver" $args
} else {
& "$basedir/node$exe" "$basedir/../typescript/bin/tsserver" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../typescript/bin/tsserver" $args
} else {
& "node$exe" "$basedir/../typescript/bin/tsserver" $args
}
$ret=$LASTEXITCODE
}
exit $ret
Generated Vendored
+16
View File
@@ -0,0 +1,16 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../tsx/dist/cli.mjs" "$@"
else
exec node "$basedir/../tsx/dist/cli.mjs" "$@"
fi
Generated Vendored Executable
+17
View File
@@ -0,0 +1,17 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\tsx\dist\cli.mjs" %*
Generated Vendored
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../tsx/dist/cli.mjs" $args
} else {
& "$basedir/node$exe" "$basedir/../tsx/dist/cli.mjs" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../tsx/dist/cli.mjs" $args
} else {
& "node$exe" "$basedir/../tsx/dist/cli.mjs" $args
}
$ret=$LASTEXITCODE
}
exit $ret
Generated Vendored
+16
View File
@@ -0,0 +1,16 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../uuid/dist/bin/uuid" "$@"
else
exec node "$basedir/../uuid/dist/bin/uuid" "$@"
fi
Generated Vendored Executable
+17
View File
@@ -0,0 +1,17 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\uuid\dist\bin\uuid" %*
Generated Vendored
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../uuid/dist/bin/uuid" $args
} else {
& "$basedir/node$exe" "$basedir/../uuid/dist/bin/uuid" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../uuid/dist/bin/uuid" $args
} else {
& "node$exe" "$basedir/../uuid/dist/bin/uuid" $args
}
$ret=$LASTEXITCODE
}
exit $ret
Generated Vendored
+16
View File
@@ -0,0 +1,16 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../vite/bin/vite.js" "$@"
else
exec node "$basedir/../vite/bin/vite.js" "$@"
fi
Generated Vendored Executable
+17
View File
@@ -0,0 +1,17 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\vite\bin\vite.js" %*
Generated Vendored
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../vite/bin/vite.js" $args
} else {
& "$basedir/node$exe" "$basedir/../vite/bin/vite.js" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../vite/bin/vite.js" $args
} else {
& "node$exe" "$basedir/../vite/bin/vite.js" $args
}
$ret=$LASTEXITCODE
}
exit $ret
Generated Vendored
+16
View File
@@ -0,0 +1,16 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../vitest/vitest.mjs" "$@"
else
exec node "$basedir/../vitest/vitest.mjs" "$@"
fi
Generated Vendored Executable
+17
View File
@@ -0,0 +1,17 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\vitest\vitest.mjs" %*
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../vitest/vitest.mjs" $args
} else {
& "$basedir/node$exe" "$basedir/../vitest/vitest.mjs" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../vitest/vitest.mjs" $args
} else {
& "node$exe" "$basedir/../vitest/vitest.mjs" $args
}
$ret=$LASTEXITCODE
}
exit $ret
+16
View File
@@ -0,0 +1,16 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../which-command/cli.js" "$@"
else
exec node "$basedir/../which-command/cli.js" "$@"
fi
Generated Vendored Executable
+17
View File
@@ -0,0 +1,17 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\which-command\cli.js" %*
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../which-command/cli.js" $args
} else {
& "$basedir/node$exe" "$basedir/../which-command/cli.js" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../which-command/cli.js" $args
} else {
& "node$exe" "$basedir/../which-command/cli.js" $args
}
$ret=$LASTEXITCODE
}
exit $ret
+16
View File
@@ -0,0 +1,16 @@
#!/bin/sh
basedir=$(dirname "$(echo "$0" | sed -e 's,\\,/,g')")
case `uname` in
*CYGWIN*|*MINGW*|*MSYS*)
if command -v cygpath > /dev/null 2>&1; then
basedir=`cygpath -w "$basedir"`
fi
;;
esac
if [ -x "$basedir/node" ]; then
exec "$basedir/node" "$basedir/../why-is-node-running/cli.js" "$@"
else
exec node "$basedir/../why-is-node-running/cli.js" "$@"
fi
Generated Vendored Executable
+17
View File
@@ -0,0 +1,17 @@
@ECHO off
GOTO start
:find_dp0
SET dp0=%~dp0
EXIT /b
:start
SETLOCAL
CALL :find_dp0
IF EXIST "%dp0%\node.exe" (
SET "_prog=%dp0%\node.exe"
) ELSE (
SET "_prog=node"
SET PATHEXT=%PATHEXT:;.JS;=;%
)
endLocal & goto #_undefined_# 2>NUL || title %COMSPEC% & "%_prog%" "%dp0%\..\why-is-node-running\cli.js" %*
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/env pwsh
$basedir=Split-Path $MyInvocation.MyCommand.Definition -Parent
$exe=""
if ($PSVersionTable.PSVersion -lt "6.0" -or $IsWindows) {
# Fix case when both the Windows and Linux builds of Node
# are installed in the same directory
$exe=".exe"
}
$ret=0
if (Test-Path "$basedir/node$exe") {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "$basedir/node$exe" "$basedir/../why-is-node-running/cli.js" $args
} else {
& "$basedir/node$exe" "$basedir/../why-is-node-running/cli.js" $args
}
$ret=$LASTEXITCODE
} else {
# Support pipeline input
if ($MyInvocation.ExpectingInput) {
$input | & "node$exe" "$basedir/../why-is-node-running/cli.js" $args
} else {
& "node$exe" "$basedir/../why-is-node-running/cli.js" $args
}
$ret=$LASTEXITCODE
}
exit $ret
+3175
View File
File diff suppressed because it is too large Load Diff
@@ -0,0 +1 @@
{"version":"4.1.10","results":[[":src/lib/__tests__/sandbox.test.ts",{"duration":11.984899999999982,"failed":false}],[":src/lib/__tests__/processManager.test.ts",{"duration":805.6025999999999,"failed":false}],[":src/tools/docker/__tests__/dockerManager.test.ts",{"duration":13.444799999999987,"failed":false}],[":src/tools/laravel/__tests__/artisanAllowList.test.ts",{"duration":4.152300000000025,"failed":false}],[":src/tools/codeigniter/__tests__/sparkAllowList.test.ts",{"duration":4.632000000000005,"failed":false}],[":src/lib/__tests__/runCommand.test.ts",{"duration":806.9179000000001,"failed":false}],[":src/tools/laravel/__tests__/artisan.test.ts",{"duration":95.09100000000035,"failed":false}],[":src/tools/codeigniter/__tests__/spark.test.ts",{"duration":73.26659999999993,"failed":false}],[":src/lib/frameworks/__tests__/detect.test.ts",{"duration":84.05799999999999,"failed":false}],[":src/lib/__tests__/baselines.test.ts",{"duration":93.35469999999998,"failed":false}],[":src/tools/browser/__tests__/visualDiff.test.ts",{"duration":13.445299999999861,"failed":false}],[":src/tools/audit/__tests__/lighthouse.test.ts",{"duration":9.24369999999999,"failed":false}],[":src/tools/git/__tests__/gitTools.test.ts",{"duration":51.321699999999964,"failed":false}],[":src/lib/frameworks/__tests__/reactNext.test.ts",{"duration":14.86160000000001,"failed":false}],[":src/tools/codeigniter/__tests__/shieldAuth.test.ts",{"duration":42.760299999999916,"failed":false}],[":src/tools/laravel/__tests__/artisanAllowList.v12.test.ts",{"duration":4.987000000000023,"failed":false}],[":src/tools/docker/__tests__/generate.test.ts",{"duration":125.57389999999987,"failed":false}],[":src/lib/frameworks/__tests__/workspace.test.ts",{"duration":45.256399999999985,"failed":false}],[":src/tools/scaffold/__tests__/generateComponent.vue.test.ts",{"duration":81.99119999999994,"failed":false}],[":src/tools/backends/__tests__/generateResources.test.ts",{"duration":136.75019999999995,"failed":false}],[":src/lib/frameworks/__tests__/laravelSail.test.ts",{"duration":19.781600000000026,"failed":false}],[":src/tools/git/__tests__/gitDiffSummarize.test.ts",{"duration":7.5289000000000215,"failed":false}]]}
+31
View File
@@ -0,0 +1,31 @@
# Change Log
All notable changes to this project will be documented in this file
automatically by Versionist. DO NOT EDIT THIS FILE MANUALLY!
This project adheres to [Semantic Versioning](http://semver.org/).
# v1.0.2
## (2020-05-13)
* Update dependencies and replace yarn with npm [Paulo Castro]
# v1.0.1
## (2020-05-02)
* Fix npm publish via balena CI [Paulo Castro]
# v1.0.0
## (2020-04-29)
* Review README.md [Paulo Castro]
# v0.0.6
## (2020-04-29)
* Update CI config (add .resinci.yml and appveyor.yml, remove codecov) [Paulo Castro]
* Add LICENSE.md and CHANGELOG.md files (setup versionist) [Paulo Castro]
* Update package.json (npm package details - fork from zeit/dockerignore) [Paulo Castro]
## 0.0.5 - 2019-04-22
* Last zeit/dockerignore release before fork as balena-io-modules/dockerignore
+206
View File
@@ -0,0 +1,206 @@
* Copyright 2020 Balena Ltd. under the Apache 2.0 License included in this file.
* Copyright 2018 Zeit Inc. under the MIT License included in this file.
--------------------------------------------------------------------------
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
--------------------------------------------------------------------------
The MIT License (MIT)
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.
--------------------------------------------------------------------------
+261
View File
@@ -0,0 +1,261 @@
# dockerignore
`dockerignore` is a file filter library fully compatible with Docker's [.dockerignore
file](https://docs.docker.com/engine/reference/builder/#dockerignore-file), exposing the
same API as the popular [ignore](https://github.com/kaelzhang/node-ignore) package for the
`.gitignore` format.
`dockerignore` is also:
* Compatible with Linux, macOS and Windows.
* Compact with 0 external dependencies (production install).
* A pure Javascript port of Docker's Golang implementation of the `.dockerignore` format.
* Well tested with hundreds of test cases including comparison against the actual behavior
of `docker build` on Windows and Linux.
* Relied on in production environments by
[balena-cli](https://www.balena.io/docs/reference/balena-cli/),
[now-cli](https://github.com/zeit/now-cli/)
and other prominent projects built around Docker.
### What's different from `ignore`?
The `.dockerignore` spec has several differences from `.gitignore`:
- `*` in `.gitignore` matches everything, whereas in `.dockerignore` it only matches files in the
current directory (like glob). This difference is important when whitelisting after a `*` rule.
- `abc` in `.gitignore` matches all `abc` files and directories, however deeply nested, whereas
in `.dockerignore` it matches only at `./abc` and not in subdirectories like `./somedir/abc`.
- With `.gitignore`, when a parent directory is ignored, subdirectories cannot be re-added (using
`!`) since `git` simply avoids walking through the subtree as an optimization. With
`.dockerignore`, a subdirectory can be re-added even if a parent directory has been ignored.
- For a complete list of differences, check out the [.gitignore
spec](https://git-scm.com/docs/gitignore) and the [.dockerignore
spec](https://docs.docker.com/engine/reference/builder/#dockerignore-file).
### What's the same as `ignore`?
The entire API. `dockerignore` started as a fork of
[node-ignore](https://github.com/kaelzhang/node-ignore), and even reuses the same `index.d.ts` file
for TypeScript definitions. Under the hood, `node-ignore`'s matching logic was rewritten to closely
match Docker's implementation (modeled mainly around
[dockerignore.go](https://github.com/moby/moby/blob/v19.03.8/builder/dockerignore/dockerignore.go)
and [fileutils.go](https://github.com/moby/moby/blob/v19.03.8/pkg/fileutils/fileutils.go)).
### Compatibility
`dockerignore` works with Node.js version 8 and above, on Linux, macOS and Windows.
The code is compiled with [Babel](https://babeljs.io/docs/en/).
## Install
```bash
npm install --save @balena/dockerignore
```
## Usage
```js
const ignore = require('@balena/dockerignore')
const ig = ignore().add(['.abc/*', '!.abc/d/'])
```
Typescript type definitions are also included:
```typescript
import ignore from '@balena/dockerignore'
const ig = ignore().add(['.abc/*', '!.abc/d/'])
```
### Filter the given paths
```js
const paths = [
'.abc/a.js', // filtered out
'.abc/d/e.js' // included
]
ig.filter(paths) // ['.abc/d/e.js']
ig.ignores('.abc/a.js') // true
```
### As the filter function
```js
paths.filter(ig.createFilter()); // ['.abc/d/e.js']
```
### Windows paths are supported
```js
ig.filter(['.abc\\a.js', '.abc\\d\\e.js'])
// if the code above runs on windows, the result will be
// ['.abc\\d\\e.js']
```
## Backslashes _vs._ forward slashes
`dockerignore` behaves just like the Docker CLI ("docker build") in relation to the backslash (`\`)
and forward slash (`/`) characters:
OS | Location | Slash (`/`) | Backslash (`\`)
------------ | ----------------------- | ---------------| --------------------
Linux, macOS | `.dockerignore` | Path separator | Escape character
Linux, macOS | `filter()`, `ignores()` | Path separator | Part of file name
Windows | `.dockerignore` | Path separator | Path separator
Windows | `filter()`, `ignores()` | Path separator | Path separator
This means that forward slashes can be used in the `.dockerignore` file for cross-platform
compatibility. This is consistent with how Windows works generally: both forward slashes
and backslashes are accepted as path separators by the Command Prompt (cmd.exe) or
PowerShell, and by library functions like the Golang
[filepath.Clean](https://golang.org/pkg/path/filepath/#Clean) or the Node.js
[path.normalize](https://nodejs.org/docs/latest-v10.x/api/path.html#path_path_normalize_path).
The use of the backslash as an escape character (Linux and macOS only) is not documented in the
`.dockerignore` specification. "Reasonable" uses are probably to escape the few characters that
have a special meaning in the `.dockerignore` file, namely `"*#!\"` (excluding the double quotes),
as opposed to characters that have a special meaning in [regular
expressions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Regular_Expressions)
generally. The "escaping" behavior for any other characters (e.g. `'\\b'`) is undefined and subject
to implementation-specific interpretation that may change at any time.
## Absolute paths
Leading and trailing slashes (or backslashes on Windows) are removed from `.dockerignore` patterns,
so `'/a'`, `'a/'` and `'/a/'` are all equivalent to `'a'` in a `.dockerignore` file, and they all
anchor to the "leftmost" directory when matching against relative paths. For example, pattern `'a'`
is compared with `'x'` for a given path `'x/y/z'`. This follows Docker's Golang implementation for
compatibility. Conversely, a given absolute path will not match a non-wildcard pattern. More
examples:
```js
ignore().add('a').ignores('a') // true
ignore().add('/a').ignores('a') // true
ignore().add('/a/').ignores('a') // true
ignore().add('a').ignores('/a') // false
ignore().add('/a').ignores('/a') // false
ignore().add('/a/').ignores('/a') // false
```
Considering pattern slash removal, the cases above may be reduced to:
```js
ignore().add('a').ignores('a') // true
ignore().add('a').ignores('/a') // false
```
The 'false' outcome for these examples may appear to mismatch the behavior of "docker build", when
the source argument for the Dockerfile [ADD](https://docs.docker.com/engine/reference/builder/#add)
or [COPY](https://docs.docker.com/engine/reference/builder/#copy) instructions is an absolute path
(starting with a slash). The explanation is that docker converts absolute source paths to relative
paths (relative to the "build context") **prior to pattern matching:**
https://github.com/moby/moby/blob/v19.03.8/pkg/archive/archive.go#L806
https://github.com/moby/moby/blob/v19.03.8/pkg/archive/archive.go#L825
... while `dockerignore` mirrors the implementation of the pattern matcher itself. The advice is
for your application to do the same as the docker CLI: use relative paths for pattern matching.
This is also generally more portable across different environments: development machine, CI
pipelines, servers or end user devices.
## Comments
A pattern starting with `'#'` (hash) is ignored as a comment. The hash can be prefixed with
a slash or backslash in order to match a file name that also starts with a hash:
```js
ignore().add('#abc').ignores('#abc') // false
ignore().add('/#abc').ignores('#abc') // true
ignore().add('\\#abc').ignores('#abc') // true
```
This works because of the leading slash removal from patterns described in [Absolute
Paths](#absolute-paths).
## Exclusion patterns
Patterns starting with `'!'` (exclamation mark) define matching exclusions (exceptions) as
documented in the [.dockerignore
specification](https://docs.docker.com/engine/reference/builder/#dockerignore-file). For
compatibility with Docker's implementation, patterns starting with `'/!'` or `'!/'` (but not
`'/!/'`) will also be considered exclusion patterns, in addition to slash removal described in
[Absolute Paths](#absolute-paths). Backslash escaping as `'\\!'` may be used in order to match a
file or directory name that starts with the exclamation mark, but this is only possible on Linux
and macOS, not on Windows. Again, it only behaves this way for compatibility with Docker's
implementation.
## Options
Matching is case-insensitive by default, following the `ignore` API
([ignorecase](https://www.npmjs.com/package/ignore#optionsignorecase-since-400)).
Note however that Docker performs case-sensitive matching.
Use the `ignorecase: false` option to align with Docker's behavior:
```js
const ig = ignore({ ignorecase: false }) // for case-sensitive matching
```
## Methods
### .add(pattern)
### .add(patterns)
- **pattern** `String|Ignore` An ignore pattern string, or the `Ignore` instance
- **patterns** `Array.<pattern>` Array of ignore patterns.
Adds a rule or several rules to the current manager.
Returns `this`
`pattern` could either be a line of ignore pattern or a string of multiple ignore patterns, which means we could just `ignore().add()` the content of a ignore file:
```js
ignore()
.add(fs.readFileSync(filenameOfGitignore).toString())
.filter(filenames)
```
`pattern` could also be an `ignore` instance, so that we could easily inherit the rules of another `Ignore` instance.
### .ignores(pathname)
Returns `Boolean` whether `pathname` should be ignored.
```js
ig.ignores('.abc/a.js') // true
```
### .filter(paths)
Filters the given array of pathnames, and returns the filtered array.
- **paths** `Array.<path>` The array of `pathname`s to be filtered.
### .createFilter()
Creates a filter function which could filter an array of paths with `Array.prototype.filter`.
Returns `function(path)` the filter function.
## Contributing
Contributions are always welcome!
1. Fork this repository to your own GitHub account and then clone it to your local device.
2. Install the dependencies: `npm install`
3. Add a test case (if applicable) and ensure it currently fails
4. Add code to pass the test
5. Make a pull request (additional tests will run on CI to ensure that your test case agrees with an actual `docker build`)
## Acknowledgements
The initial work on this project was done by Pranay Prakash
([@pranaygp](https://twitter.com/pranaygp)) / [▲ZEIT](https://zeit.co), Kael Zhang
([@kaelzhang](https://github.com/kaelzhang)) and the [node-ignore
contributors](https://github.com/kaelzhang/node-ignore/graphs/contributors).
Paulo Castro ([@pdcastro](https://github.com/pdcastro)) / [balena.io](https://www.balena.io/)
forked the repository in year 2020 ([encouraged by
Zeit](https://github.com/zeit/dockerignore/pull/16#issuecomment-611790479)) and put in a
substantial effort on Windows support, cross-platform compatibility and testing, leading to release
1.0.0.
+363
View File
@@ -0,0 +1,363 @@
'use strict';
/**
* @license
* Copyright 2020 Balena Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* ------------------------------------------------------------------------
*
* Copyright 2018 Zeit, Inc.
* Licensed under the MIT License. See file LICENSE.md for a full copy.
*
* ------------------------------------------------------------------------
*/
/**
* This module implements the [dockerignore
* spec](https://docs.docker.com/engine/reference/builder/#dockerignore-file),
* closely following Docker's (Moby) Golang implementation:
* https://github.com/moby/moby/blob/v19.03.8/builder/dockerignore/dockerignore.go
* https://github.com/moby/moby/blob/v19.03.8/pkg/fileutils/fileutils.go
* https://github.com/moby/moby/blob/v19.03.8/pkg/archive/archive.go#L825
*
* Something the spec is not clear about, but we discovered by reading source code
* and testing against the "docker build" command, is the handling of backslashes and
* forward slashes as path separators and escape characters in the .dockerignore file
* across platforms including Windows, Linux and macOS:
*
* * On Linux and macOS, only forward slashes can be used as path separators in the
* .dockerignore file, and the backslash works as an escape character.
* * On Windows, both forward slashes and backslashes are allowed as path separators
* in the .dockerignore file, and the backslash is not used as an escape character.
*
* This is consistent with how Windows works generally: both forward slashes and
* backslashes are accepted as path separators by the cmd.exe Command Prompt or
* PowerShell, and by library functions like the Golang filepath.Clean or the
* Node.js path.normalize.
*
* Similarly, path strings provided to the IgnoreBase.ignores() and IgnoreBase.filter()
* methods can use either forward slashes or backslashes as path separators on Windows,
* but only forward slashes are accepted as path separators on Linux and macOS.
*/
const path = require('path');
const factory = options => new IgnoreBase(options); // https://github.com/kaelzhang/node-ignore/blob/5.1.4/index.js#L538-L539
// Fixes typescript module import
factory.default = factory;
module.exports = factory;
function make_array(subject) {
return Array.isArray(subject) ? subject : [subject];
}
const REGEX_TRAILING_SLASH = /(?<=.)\/$/;
const REGEX_TRAILING_BACKSLASH = /(?<=.)\\$/;
const REGEX_TRAILING_PATH_SEP = path.sep === '\\' ? REGEX_TRAILING_BACKSLASH : REGEX_TRAILING_SLASH;
const KEY_IGNORE = typeof Symbol !== 'undefined' ? Symbol.for('dockerignore') : 'dockerignore'; // An implementation of Go's filepath.Clean
// https://golang.org/pkg/path/filepath/#Clean
// https://github.com/golang/go/blob/master/src/path/filepath/path.go
// Note that, like Go, on Windows this function converts forward slashes
// to backslashes.
function cleanPath(file) {
return path.normalize(file).replace(REGEX_TRAILING_PATH_SEP, '');
} // Javascript port of Golang's filepath.ToSlash
// https://golang.org/pkg/path/filepath/#ToSlash
// https://github.com/golang/go/blob/master/src/path/filepath/path.go
// Convert any OS-specific path separator to '/'. Backslash is converted
// to forward slash on Windows, but not on Linux/macOS.
// Note that both forward slashes and backslashes are valid path separators on
// Windows. As a result, code such as `pattern.split(path.sep).join('/')` fails
// on Windows when forward slashes are used as path separators.
function toSlash(file) {
if (path.sep === '/') {
return file;
}
return file.replace(/\\/g, '/');
} // Javascript port of Golang's filepath.FromSlash
// https://github.com/golang/go/blob/master/src/path/filepath/path.go
function fromSlash(file) {
if (path.sep === '/') {
return file;
}
return file.replace(/\//g, path.sep);
}
class IgnoreBase {
constructor({
// https://github.com/kaelzhang/node-ignore/blob/5.1.4/index.js#L372
ignorecase = true
} = {}) {
this._rules = [];
this._ignorecase = ignorecase;
this[KEY_IGNORE] = true;
this._initCache();
}
_initCache() {
this._cache = {};
} // @param {Array.<string>|string|Ignore} pattern
add(pattern) {
this._added = false;
if (typeof pattern === 'string') {
pattern = pattern.split(/\r?\n/g);
}
make_array(pattern).forEach(this._addPattern, this); // Some rules have just added to the ignore,
// making the behavior changed.
if (this._added) {
this._initCache();
}
return this;
} // legacy
addPattern(pattern) {
return this.add(pattern);
}
_addPattern(pattern) {
// https://github.com/kaelzhang/node-ignore/issues/32
if (pattern && pattern[KEY_IGNORE]) {
this._rules = this._rules.concat(pattern._rules);
this._added = true;
return;
}
if (this._checkPattern(pattern)) {
const rule = this._createRule(pattern.trim());
if (rule !== null) {
this._added = true;
this._rules.push(rule);
}
}
}
_checkPattern(pattern) {
// https://github.com/moby/moby/blob/v19.03.8/builder/dockerignore/dockerignore.go#L34-L40
return pattern && typeof pattern === 'string' && pattern.indexOf('#') !== 0 && pattern.trim() !== "";
}
filter(paths) {
return make_array(paths).filter(path => this._filter(path));
}
createFilter() {
return path => this._filter(path);
}
ignores(path) {
return !this._filter(path);
} // https://github.com/moby/moby/blob/v19.03.8/builder/dockerignore/dockerignore.go#L41-L53
// https://github.com/moby/moby/blob/v19.03.8/pkg/fileutils/fileutils.go#L29-L55
_createRule(pattern) {
const origin = pattern;
let negative = false; // > An optional prefix "!" which negates the pattern;
// https://github.com/moby/moby/blob/v19.03.8/builder/dockerignore/dockerignore.go#L43-L46
if (pattern[0] === '!') {
negative = true;
pattern = pattern.substring(1).trim();
} // https://github.com/moby/moby/blob/v19.03.8/builder/dockerignore/dockerignore.go#L47-L53
if (pattern.length > 0) {
pattern = cleanPath(pattern);
pattern = toSlash(pattern);
if (pattern.length > 1 && pattern[0] === '/') {
pattern = pattern.slice(1);
}
} // https://github.com/moby/moby/blob/v19.03.8/builder/dockerignore/dockerignore.go#L54-L55
if (negative) {
pattern = '!' + pattern;
} // https://github.com/moby/moby/blob/v19.03.8/pkg/fileutils/fileutils.go#L30
pattern = pattern.trim();
if (pattern === "") {
return null;
} // https://github.com/moby/moby/blob/v19.03.8/pkg/fileutils/fileutils.go#L34
// convert forward slashes to backslashes on Windows
pattern = cleanPath(pattern); // https://github.com/moby/moby/blob/v19.03.8/pkg/fileutils/fileutils.go#L36-L42
if (pattern[0] === '!') {
if (pattern.length === 1) {
return null;
}
negative = true;
pattern = pattern.substring(1);
} else {
negative = false;
}
return {
origin,
pattern,
// https://github.com/moby/moby/blob/v19.03.8/pkg/fileutils/fileutils.go#L54
dirs: pattern.split(path.sep),
negative
};
} // @returns `Boolean` true if the `path` is NOT ignored
_filter(path) {
if (!path) {
return false;
}
if (path in this._cache) {
return this._cache[path];
}
return this._cache[path] = this._test(path);
} // @returns {Boolean} true if a file is NOT ignored
// https://github.com/moby/moby/blob/v19.03.8/pkg/fileutils/fileutils.go#L62
_test(file) {
file = fromSlash(file); // equivalent to golang filepath.Dir() https://golang.org/src/path/filepath/path.go
const parentPath = cleanPath(path.dirname(file));
const parentPathDirs = parentPath.split(path.sep);
let matched = false;
this._rules.forEach(rule => {
let match = this._match(file, rule); // https://github.com/moby/moby/blob/v19.03.8/pkg/fileutils/fileutils.go#L80
if (!match && parentPath !== ".") {
// Check to see if the pattern matches one of our parent dirs.
if (rule.dirs.includes('**')) {
// Ah shucks! We have to test every possible parent path that has
// a number of dirs _n_ where
// `rule.dirs.filter(doubleStar).length <= _n_ <= parentPathDirs.length`
// since the ** can imply any number of directories including 0
for (let i = rule.dirs.filter(x => x !== '**').length; i <= parentPathDirs.length; i++) {
match = match || this._match(parentPathDirs.slice(0, i).join(path.sep), rule);
}
} else if (rule.dirs.length <= parentPathDirs.length) {
// https://github.com/moby/moby/blob/v19.03.8/pkg/fileutils/fileutils.go#L83
match = this._match(parentPathDirs.slice(0, rule.dirs.length).join(path.sep), rule);
}
}
if (match) {
matched = !rule.negative;
}
});
return !matched;
} // @returns {Boolean} true if a file is matched by a rule
_match(file, rule) {
return this._compile(rule).regexp.test(file);
} // https://github.com/moby/moby/blob/v19.03.8/pkg/fileutils/fileutils.go#L139
_compile(rule) {
if (rule.regexp) {
return rule;
}
let regStr = '^'; // Go through the pattern and convert it to a regexp.
let escapedSlash = path.sep === '\\' ? '\\\\' : path.sep;
for (let i = 0; i < rule.pattern.length; i++) {
const ch = rule.pattern[i];
if (ch === '*') {
if (rule.pattern[i + 1] === '*') {
// is some flavor of "**"
i++; // Treat **/ as ** so eat the "/"
if (rule.pattern[i + 1] === path.sep) {
i++;
}
if (rule.pattern[i + 1] === undefined) {
// is "**EOF" - to align with .gitignore just accept all
regStr += ".*";
} else {
// is "**"
// Note that this allows for any # of /'s (even 0) because
// the .* will eat everything, even /'s
regStr += `(.*${escapedSlash})?`;
}
} else {
// is "*" so map it to anything but "/"
regStr += `[^${escapedSlash}]*`;
}
} else if (ch === '?') {
// "?" is any char except "/"
regStr += `[^${escapedSlash}]`;
} else if (ch === '.' || ch === '$') {
// Escape some regexp special chars that have no meaning
// in golang's filepath.Match
regStr += `\\${ch}`;
} else if (ch === '\\') {
// escape next char. Note that a trailing \ in the pattern
// will be left alone (but need to escape it)
if (path.sep === '\\') {
// On windows map "\" to "\\", meaning an escaped backslash,
// and then just continue because filepath.Match on
// Windows doesn't allow escaping at all
regStr += escapedSlash;
continue;
}
if (rule.pattern[i + 1] !== undefined) {
regStr += '\\' + rule.pattern[i + 1];
i++;
} else {
regStr += '\\';
}
} else {
regStr += ch;
}
}
regStr += "$";
rule.regexp = new RegExp(regStr, this._ignorecase ? 'i' : '');
return rule;
}
}
+45
View File
@@ -0,0 +1,45 @@
export interface Ignore {
/**
* Adds a rule rules to the current manager.
* @param {string | Ignore} pattern
* @returns IgnoreBase
*/
add(pattern: string | Ignore): Ignore
/**
* Adds several rules to the current manager.
* @param {string[]} patterns
* @returns IgnoreBase
*/
add(patterns: (string | Ignore)[]): Ignore
/**
* Filters the given array of pathnames, and returns the filtered array.
* NOTICE that each path here should be a relative path to the root of your repository.
* @param paths the array of paths to be filtered.
* @returns The filtered array of paths
*/
filter(paths: string[]): string[]
/**
* Creates a filter function which could filter
* an array of paths with Array.prototype.filter.
*/
createFilter(): (path: string) => boolean
/**
* Returns Boolean whether pathname should be ignored.
* @param {string} pathname a path to check
* @returns boolean
*/
ignores(pathname: string): boolean
}
interface Options {
ignorecase?: boolean
}
/**
* Creates new ignore manager.
*/
declare function ignore(options?: Options): Ignore
export default ignore
+49
View File
@@ -0,0 +1,49 @@
{
"name": "@balena/dockerignore",
"version": "1.0.2",
"description": "dockerignore is a file filter library compatible with Docker and the node-ignore API",
"main": "./ignore.js",
"files": [
"ignore.js",
"index.d.ts"
],
"scripts": {
"prepublishOnly": "npm run build",
"build": "babel -o ignore.js index.js",
"test": "npm run build && nyc ava ./test/ignore.js"
},
"repository": {
"type": "git",
"url": "git@github.com:balena-io-modules/dockerignore.git"
},
"keywords": [
"ignore",
".dockerignore",
"dockerignore",
"rules",
"manager",
"filter",
"regexp",
"regex",
"fnmatch",
"glob",
"asterisks",
"regular-expression"
],
"license": "Apache-2.0",
"bugs": {
"url": "https://github.com/balena-io-modules/dockerignore/issues"
},
"devDependencies": {
"async-sema": "^3.1.0",
"ava": "^0.25.0",
"@babel/cli": "^7.8.4",
"@babel/preset-env": "^7.9.6",
"chai": "^4.2.0",
"cuid": "^2.1.8",
"mkdirp": "^1.0.4",
"nyc": "^15.0.1",
"rimraf": "^3.0.2",
"tmp": "^0.2.1"
}
}
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021-present Toyobayashi
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.
+1
View File
@@ -0,0 +1 @@
See [https://github.com/toyobayashi/emnapi](https://github.com/toyobayashi/emnapi)
+366
View File
@@ -0,0 +1,366 @@
import type { Context } from '@emnapi/runtime';
import type { ReferenceOwnership } from '@emnapi/runtime';
import type { Worker as Worker_2 } from 'worker_threads';
/** @public */
export declare type BaseCreateOptions = {
filename?: string
nodeBinding?: NodeBinding
reuseWorker?: ThreadManagerOptionsMain['reuseWorker']
asyncWorkPoolSize?: number
waitThreadStart?: MainThreadBaseOptions['waitThreadStart']
onCreateWorker?: (info: CreateWorkerInfo) => any
print?: (str: string) => void
printErr?: (str: string) => void
postMessage?: (msg: any) => any
plugins?: (PluginFactory | EmnapiPlugin)[]
}
export declare interface BaseOptions {
wasi: WASIInstance;
version?: 'preview1';
wasm64?: boolean;
}
export declare interface ChildThreadOptions extends BaseOptions {
childThread: true;
postMessage?: (data: any) => void;
}
export declare interface CleanupThreadPayload {
tid: number;
}
export declare interface CommandInfo<T extends CommandType> {
type: T;
payload: CommandPayloadMap[T];
}
export declare interface CommandPayloadMap {
load: LoadPayload;
loaded: LoadedPayload;
start: StartPayload;
'cleanup-thread': CleanupThreadPayload;
'terminate-all-threads': TerminateAllThreadsPayload;
'spawn-thread': SpawnThreadPayload;
}
export declare type CommandType = keyof CommandPayloadMap;
export declare function createInstanceProxy(instance: WebAssembly.Instance, memory?: WebAssembly.Memory | (() => WebAssembly.Memory)): WebAssembly.Instance;
/** @public */
export declare function createNapiModule (
options: CreateOptions
): NapiModule
/** @public */
export declare type CreateOptions = BaseCreateOptions & ({
context: Context
childThread?: boolean
} | {
context?: Context
childThread: true
})
/** @public */
export declare interface CreateWorkerInfo {
type: 'thread' | 'async-work'
name: string
}
/** @public */
export declare interface EmnapiPlugin {
importObject?: (originalImports: WebAssembly.Imports) => (WebAssembly.Imports | void)
}
/** @public */
export declare interface InitOptions {
instance: WebAssembly.Instance
module: WebAssembly.Module
memory?: WebAssembly.Memory
table?: WebAssembly.Table
}
export declare type InputType = string | URL | Response | BufferSource | WebAssembly.Module;
export declare interface InstantiatedSource extends LoadedSource {
napiModule: NapiModule;
}
export declare function instantiateNapiModule(wasmInput: InputType | Promise<InputType>, options: InstantiateOptions): Promise<InstantiatedSource>;
export declare function instantiateNapiModuleSync(wasmInput: BufferSource | WebAssembly.Module, options: InstantiateOptions): InstantiatedSource;
export declare type InstantiateOptions = CreateOptions & LoadOptions;
export declare function isSharedArrayBuffer(value: any): value is SharedArrayBuffer;
export declare function isTrapError(e: Error): e is WebAssembly.RuntimeError;
export declare interface LoadedPayload {
}
export declare interface LoadedSource extends WebAssembly.WebAssemblyInstantiatedSource {
usedInstance: WebAssembly.Instance;
}
export declare function loadNapiModule(napiModule: NapiModule, wasmInput: InputType | Promise<InputType>, options?: LoadOptions): Promise<LoadedSource>;
export declare function loadNapiModuleSync(napiModule: NapiModule, wasmInput: BufferSource | WebAssembly.Module, options?: LoadOptions): LoadedSource;
export declare interface LoadOptions {
wasi?: WASIInstance;
overwriteImports?: (importObject: WebAssembly.Imports) => WebAssembly.Imports;
beforeInit?: (source: WebAssembly.WebAssemblyInstantiatedSource) => void;
getMemory?: (exports: WebAssembly.Exports) => WebAssembly.Memory;
getTable?: (exports: WebAssembly.Exports) => WebAssembly.Table;
}
export declare interface LoadPayload {
wasmModule: WebAssembly.Module;
wasmMemory: WebAssembly.Memory;
sab?: Int32Array;
}
export declare interface MainThreadBaseOptions extends BaseOptions {
waitThreadStart?: boolean | number;
}
export declare type MainThreadOptions = MainThreadOptionsWithThreadManager | MainThreadOptionsCreateThreadManager;
export declare interface MainThreadOptionsCreateThreadManager extends MainThreadBaseOptions, ThreadManagerOptionsMain {
}
export declare interface MainThreadOptionsWithThreadManager extends MainThreadBaseOptions {
threadManager?: ThreadManager | (() => ThreadManager);
}
export declare interface MessageEventData<T extends CommandType> {
__emnapi__: CommandInfo<T>;
}
export declare class MessageHandler extends ThreadMessageHandler {
napiModule: NapiModule | undefined;
constructor(options: MessageHandlerOptions);
instantiate(data: LoadPayload): InstantiatedSource | PromiseLike<InstantiatedSource>;
handle(e: WorkerMessageEvent): void;
}
export declare interface MessageHandlerOptions extends ThreadMessageHandlerOptions {
onLoad: (data: LoadPayload) => InstantiatedSource | PromiseLike<InstantiatedSource>;
}
/** @public */
export declare interface NapiModule {
imports: {
env: any
napi: any
emnapi: any
}
exports: any
loaded: boolean
filename: string
childThread: boolean
emnapi: {
/**
* Synchronize data between the wasm memory and an ArrayBuffer / view.
*
* Note: when a non-shared wasm memory has grown, a view over the
* detached old buffer is re-created over the current buffer through the
* intrinsic base-class constructor, so for view inputs the returned view
* may be a base-class instance (e.g. `Uint8Array` or `DataView`)
* instead of the subclass that was passed in.
*/
syncMemory<T extends ArrayBuffer | ArrayBufferView> (
js_to_wasm: boolean,
arrayBufferOrView: T,
offset?: number,
len?: number
): T extends ArrayBufferView ? ArrayBufferView : T
getMemoryAddress (arrayBufferOrView: ArrayBuffer | ArrayBufferView): PointerInfo
addSendListener (worker: any): boolean
}
init (options: InitOptions): any
initWorker (arg: number, func: [number, number]): void
postMessage?: (msg: any) => any
waitThreadStart: boolean | number
/* Excluded from this release type: PThread */}
/** @public */
export declare interface NodeBinding {
node: {
emitAsyncInit: Function
emitAsyncDestroy: Function
makeCallback: Function
}
napi: {
asyncInit: Function
asyncDestroy: Function
makeCallback: Function
}
}
/** @public */
export declare type PluginContext = any
/** @public */
export declare type PluginFactory = (ctx: PluginContext) => EmnapiPlugin
/** @public */
export declare interface PointerInfo {
address: number
ownership: ReferenceOwnership
runtimeAllocated: 0 | 1
}
export declare interface ReuseWorkerOptions {
size: number;
strict?: boolean;
}
export declare interface SpawnThreadPayload {
startArg: number;
errorOrTid: number;
}
export declare interface StartPayload {
tid: number;
arg: number;
sab?: Int32Array;
}
export declare interface StartResult {
exitCode: number;
instance: WebAssembly.Instance;
}
export declare interface TerminateAllThreadsPayload {
}
export declare class ThreadManager {
unusedWorkers: WorkerLike[];
pthreads: Record<number, WorkerLike>;
get nextWorkerID(): number;
wasmModule: WebAssembly.Module | null;
wasmMemory: WebAssembly.Memory | null;
private readonly messageEvents;
private readonly _childThread;
private readonly _onCreateWorker;
private readonly _reuseWorker;
private readonly _beforeLoad?;
readonly printErr: (message: string) => void;
threadSpawn?: ((startArg: number, errorOrTid?: number) => number);
constructor(options: ThreadManagerOptions);
init(): void;
initMainThread(): void;
private preparePool;
shouldPreloadWorkers(): boolean;
loadWasmModuleToAllWorkers(): Promise<WorkerLike[]>;
preloadWorkers(): Promise<WorkerLike[]>;
setup(wasmModule: WebAssembly.Module, wasmMemory: WebAssembly.Memory): void;
markId(worker: WorkerLike): number;
returnWorkerToPool(worker: WorkerLike): void;
loadWasmModuleToWorker(worker: WorkerLike, sab?: Int32Array): Promise<WorkerLike>;
allocateUnusedWorker(): WorkerLike;
getNewWorker(sab?: Int32Array): WorkerLike | undefined;
cleanThread(worker: WorkerLike, tid: number, force?: boolean): void;
terminateWorker(worker: WorkerLike): void;
terminateAllThreads(): void;
addMessageEventListener(worker: WorkerLike, onMessage: (e: WorkerMessageEvent) => void): () => void;
fireMessageEvent(worker: WorkerLike, e: WorkerMessageEvent): void;
}
export declare type ThreadManagerOptions = ThreadManagerOptionsMain | ThreadManagerOptionsChild;
export declare interface ThreadManagerOptionsBase {
printErr?: (message: string) => void;
threadSpawn?: (startArg: number, errorOrTid?: number) => number;
}
export declare interface ThreadManagerOptionsChild extends ThreadManagerOptionsBase {
childThread: true;
}
export declare interface ThreadManagerOptionsMain extends ThreadManagerOptionsBase {
beforeLoad?: (worker: WorkerLike) => any;
reuseWorker?: boolean | number | ReuseWorkerOptions;
onCreateWorker: WorkerFactory;
childThread?: false;
}
export declare class ThreadMessageHandler {
protected instance: WebAssembly.Instance | undefined;
private messagesBeforeLoad;
protected postMessage: (message: any) => void;
protected onLoad?: (data: LoadPayload) => WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
protected onError: (error: Error, type: WorkerMessageType) => void;
constructor(options?: ThreadMessageHandlerOptions);
instantiate(data: LoadPayload): WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
handle(e: WorkerMessageEvent<MessageEventData<WorkerMessageType>>): void;
private _load;
private _start;
protected _loaded(err: Error | null, source: WebAssembly.WebAssemblyInstantiatedSource | null, payload: LoadPayload): void;
protected handleAfterLoad<E extends WorkerMessageEvent>(e: E, f: (e: E) => void): void;
}
export declare interface ThreadMessageHandlerOptions {
onLoad?: (data: LoadPayload) => WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
onError?: (error: Error, type: WorkerMessageType) => void;
postMessage?: (message: any) => void;
}
export declare const version: string;
export declare interface WASIInstance {
readonly wasiImport?: Record<string, any>;
initialize(instance: object): void;
start(instance: object): number;
getImportObject?(): any;
}
export declare class WASIThreads {
PThread: ThreadManager | undefined;
private wasmMemory;
private wasmInstance;
private readonly threadSpawn;
readonly childThread: boolean;
private readonly postMessage;
readonly wasi: WASIInstance;
constructor(options: WASIThreadsOptions);
getImportObject(): {
wasi: WASIThreadsImports;
};
setup(wasmInstance: WebAssembly.Instance, wasmModule: WebAssembly.Module, wasmMemory?: WebAssembly.Memory): void;
preloadWorkers(): Promise<WorkerLike[]>;
initialize(instance: WebAssembly.Instance, module: WebAssembly.Module, memory?: WebAssembly.Memory): WebAssembly.Instance;
start(instance: WebAssembly.Instance, module: WebAssembly.Module, memory?: WebAssembly.Memory): StartResult;
terminateAllThreads(): void;
}
export declare interface WASIThreadsImports {
'thread-spawn': (startArg: number, errorOrTid?: number) => number;
}
export declare type WASIThreadsOptions = MainThreadOptions | ChildThreadOptions;
export declare type WorkerFactory = (ctx: {
type: string;
name: string;
}) => WorkerLike;
export declare type WorkerLike = (Worker | Worker_2) & {
whenLoaded?: Promise<WorkerLike>;
loaded?: boolean;
__emnapi_tid?: number;
};
export declare interface WorkerMessageEvent<T = any> {
data: T;
}
export declare type WorkerMessageType = 'load' | 'start';
export { }
+366
View File
@@ -0,0 +1,366 @@
import type { Context } from '@emnapi/runtime';
import type { ReferenceOwnership } from '@emnapi/runtime';
import type { Worker as Worker_2 } from 'worker_threads';
/** @public */
export declare type BaseCreateOptions = {
filename?: string
nodeBinding?: NodeBinding
reuseWorker?: ThreadManagerOptionsMain['reuseWorker']
asyncWorkPoolSize?: number
waitThreadStart?: MainThreadBaseOptions['waitThreadStart']
onCreateWorker?: (info: CreateWorkerInfo) => any
print?: (str: string) => void
printErr?: (str: string) => void
postMessage?: (msg: any) => any
plugins?: (PluginFactory | EmnapiPlugin)[]
}
export declare interface BaseOptions {
wasi: WASIInstance;
version?: 'preview1';
wasm64?: boolean;
}
export declare interface ChildThreadOptions extends BaseOptions {
childThread: true;
postMessage?: (data: any) => void;
}
export declare interface CleanupThreadPayload {
tid: number;
}
export declare interface CommandInfo<T extends CommandType> {
type: T;
payload: CommandPayloadMap[T];
}
export declare interface CommandPayloadMap {
load: LoadPayload;
loaded: LoadedPayload;
start: StartPayload;
'cleanup-thread': CleanupThreadPayload;
'terminate-all-threads': TerminateAllThreadsPayload;
'spawn-thread': SpawnThreadPayload;
}
export declare type CommandType = keyof CommandPayloadMap;
export declare function createInstanceProxy(instance: WebAssembly.Instance, memory?: WebAssembly.Memory | (() => WebAssembly.Memory)): WebAssembly.Instance;
/** @public */
export declare function createNapiModule (
options: CreateOptions
): NapiModule
/** @public */
export declare type CreateOptions = BaseCreateOptions & ({
context: Context
childThread?: boolean
} | {
context?: Context
childThread: true
})
/** @public */
export declare interface CreateWorkerInfo {
type: 'thread' | 'async-work'
name: string
}
/** @public */
export declare interface EmnapiPlugin {
importObject?: (originalImports: WebAssembly.Imports) => (WebAssembly.Imports | void)
}
/** @public */
export declare interface InitOptions {
instance: WebAssembly.Instance
module: WebAssembly.Module
memory?: WebAssembly.Memory
table?: WebAssembly.Table
}
export declare type InputType = string | URL | Response | BufferSource | WebAssembly.Module;
export declare interface InstantiatedSource extends LoadedSource {
napiModule: NapiModule;
}
export declare function instantiateNapiModule(wasmInput: InputType | Promise<InputType>, options: InstantiateOptions): Promise<InstantiatedSource>;
export declare function instantiateNapiModuleSync(wasmInput: BufferSource | WebAssembly.Module, options: InstantiateOptions): InstantiatedSource;
export declare type InstantiateOptions = CreateOptions & LoadOptions;
export declare function isSharedArrayBuffer(value: any): value is SharedArrayBuffer;
export declare function isTrapError(e: Error): e is WebAssembly.RuntimeError;
export declare interface LoadedPayload {
}
export declare interface LoadedSource extends WebAssembly.WebAssemblyInstantiatedSource {
usedInstance: WebAssembly.Instance;
}
export declare function loadNapiModule(napiModule: NapiModule, wasmInput: InputType | Promise<InputType>, options?: LoadOptions): Promise<LoadedSource>;
export declare function loadNapiModuleSync(napiModule: NapiModule, wasmInput: BufferSource | WebAssembly.Module, options?: LoadOptions): LoadedSource;
export declare interface LoadOptions {
wasi?: WASIInstance;
overwriteImports?: (importObject: WebAssembly.Imports) => WebAssembly.Imports;
beforeInit?: (source: WebAssembly.WebAssemblyInstantiatedSource) => void;
getMemory?: (exports: WebAssembly.Exports) => WebAssembly.Memory;
getTable?: (exports: WebAssembly.Exports) => WebAssembly.Table;
}
export declare interface LoadPayload {
wasmModule: WebAssembly.Module;
wasmMemory: WebAssembly.Memory;
sab?: Int32Array;
}
export declare interface MainThreadBaseOptions extends BaseOptions {
waitThreadStart?: boolean | number;
}
export declare type MainThreadOptions = MainThreadOptionsWithThreadManager | MainThreadOptionsCreateThreadManager;
export declare interface MainThreadOptionsCreateThreadManager extends MainThreadBaseOptions, ThreadManagerOptionsMain {
}
export declare interface MainThreadOptionsWithThreadManager extends MainThreadBaseOptions {
threadManager?: ThreadManager | (() => ThreadManager);
}
export declare interface MessageEventData<T extends CommandType> {
__emnapi__: CommandInfo<T>;
}
export declare class MessageHandler extends ThreadMessageHandler {
napiModule: NapiModule | undefined;
constructor(options: MessageHandlerOptions);
instantiate(data: LoadPayload): InstantiatedSource | PromiseLike<InstantiatedSource>;
handle(e: WorkerMessageEvent): void;
}
export declare interface MessageHandlerOptions extends ThreadMessageHandlerOptions {
onLoad: (data: LoadPayload) => InstantiatedSource | PromiseLike<InstantiatedSource>;
}
/** @public */
export declare interface NapiModule {
imports: {
env: any
napi: any
emnapi: any
}
exports: any
loaded: boolean
filename: string
childThread: boolean
emnapi: {
/**
* Synchronize data between the wasm memory and an ArrayBuffer / view.
*
* Note: when a non-shared wasm memory has grown, a view over the
* detached old buffer is re-created over the current buffer through the
* intrinsic base-class constructor, so for view inputs the returned view
* may be a base-class instance (e.g. `Uint8Array` or `DataView`)
* instead of the subclass that was passed in.
*/
syncMemory<T extends ArrayBuffer | ArrayBufferView> (
js_to_wasm: boolean,
arrayBufferOrView: T,
offset?: number,
len?: number
): T extends ArrayBufferView ? ArrayBufferView : T
getMemoryAddress (arrayBufferOrView: ArrayBuffer | ArrayBufferView): PointerInfo
addSendListener (worker: any): boolean
}
init (options: InitOptions): any
initWorker (arg: number, func: [number, number]): void
postMessage?: (msg: any) => any
waitThreadStart: boolean | number
/* Excluded from this release type: PThread */}
/** @public */
export declare interface NodeBinding {
node: {
emitAsyncInit: Function
emitAsyncDestroy: Function
makeCallback: Function
}
napi: {
asyncInit: Function
asyncDestroy: Function
makeCallback: Function
}
}
/** @public */
export declare type PluginContext = any
/** @public */
export declare type PluginFactory = (ctx: PluginContext) => EmnapiPlugin
/** @public */
export declare interface PointerInfo {
address: number
ownership: ReferenceOwnership
runtimeAllocated: 0 | 1
}
export declare interface ReuseWorkerOptions {
size: number;
strict?: boolean;
}
export declare interface SpawnThreadPayload {
startArg: number;
errorOrTid: number;
}
export declare interface StartPayload {
tid: number;
arg: number;
sab?: Int32Array;
}
export declare interface StartResult {
exitCode: number;
instance: WebAssembly.Instance;
}
export declare interface TerminateAllThreadsPayload {
}
export declare class ThreadManager {
unusedWorkers: WorkerLike[];
pthreads: Record<number, WorkerLike>;
get nextWorkerID(): number;
wasmModule: WebAssembly.Module | null;
wasmMemory: WebAssembly.Memory | null;
private readonly messageEvents;
private readonly _childThread;
private readonly _onCreateWorker;
private readonly _reuseWorker;
private readonly _beforeLoad?;
readonly printErr: (message: string) => void;
threadSpawn?: ((startArg: number, errorOrTid?: number) => number);
constructor(options: ThreadManagerOptions);
init(): void;
initMainThread(): void;
private preparePool;
shouldPreloadWorkers(): boolean;
loadWasmModuleToAllWorkers(): Promise<WorkerLike[]>;
preloadWorkers(): Promise<WorkerLike[]>;
setup(wasmModule: WebAssembly.Module, wasmMemory: WebAssembly.Memory): void;
markId(worker: WorkerLike): number;
returnWorkerToPool(worker: WorkerLike): void;
loadWasmModuleToWorker(worker: WorkerLike, sab?: Int32Array): Promise<WorkerLike>;
allocateUnusedWorker(): WorkerLike;
getNewWorker(sab?: Int32Array): WorkerLike | undefined;
cleanThread(worker: WorkerLike, tid: number, force?: boolean): void;
terminateWorker(worker: WorkerLike): void;
terminateAllThreads(): void;
addMessageEventListener(worker: WorkerLike, onMessage: (e: WorkerMessageEvent) => void): () => void;
fireMessageEvent(worker: WorkerLike, e: WorkerMessageEvent): void;
}
export declare type ThreadManagerOptions = ThreadManagerOptionsMain | ThreadManagerOptionsChild;
export declare interface ThreadManagerOptionsBase {
printErr?: (message: string) => void;
threadSpawn?: (startArg: number, errorOrTid?: number) => number;
}
export declare interface ThreadManagerOptionsChild extends ThreadManagerOptionsBase {
childThread: true;
}
export declare interface ThreadManagerOptionsMain extends ThreadManagerOptionsBase {
beforeLoad?: (worker: WorkerLike) => any;
reuseWorker?: boolean | number | ReuseWorkerOptions;
onCreateWorker: WorkerFactory;
childThread?: false;
}
export declare class ThreadMessageHandler {
protected instance: WebAssembly.Instance | undefined;
private messagesBeforeLoad;
protected postMessage: (message: any) => void;
protected onLoad?: (data: LoadPayload) => WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
protected onError: (error: Error, type: WorkerMessageType) => void;
constructor(options?: ThreadMessageHandlerOptions);
instantiate(data: LoadPayload): WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
handle(e: WorkerMessageEvent<MessageEventData<WorkerMessageType>>): void;
private _load;
private _start;
protected _loaded(err: Error | null, source: WebAssembly.WebAssemblyInstantiatedSource | null, payload: LoadPayload): void;
protected handleAfterLoad<E extends WorkerMessageEvent>(e: E, f: (e: E) => void): void;
}
export declare interface ThreadMessageHandlerOptions {
onLoad?: (data: LoadPayload) => WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
onError?: (error: Error, type: WorkerMessageType) => void;
postMessage?: (message: any) => void;
}
export declare const version: string;
export declare interface WASIInstance {
readonly wasiImport?: Record<string, any>;
initialize(instance: object): void;
start(instance: object): number;
getImportObject?(): any;
}
export declare class WASIThreads {
PThread: ThreadManager | undefined;
private wasmMemory;
private wasmInstance;
private readonly threadSpawn;
readonly childThread: boolean;
private readonly postMessage;
readonly wasi: WASIInstance;
constructor(options: WASIThreadsOptions);
getImportObject(): {
wasi: WASIThreadsImports;
};
setup(wasmInstance: WebAssembly.Instance, wasmModule: WebAssembly.Module, wasmMemory?: WebAssembly.Memory): void;
preloadWorkers(): Promise<WorkerLike[]>;
initialize(instance: WebAssembly.Instance, module: WebAssembly.Module, memory?: WebAssembly.Memory): WebAssembly.Instance;
start(instance: WebAssembly.Instance, module: WebAssembly.Module, memory?: WebAssembly.Memory): StartResult;
terminateAllThreads(): void;
}
export declare interface WASIThreadsImports {
'thread-spawn': (startArg: number, errorOrTid?: number) => number;
}
export declare type WASIThreadsOptions = MainThreadOptions | ChildThreadOptions;
export declare type WorkerFactory = (ctx: {
type: string;
name: string;
}) => WorkerLike;
export declare type WorkerLike = (Worker | Worker_2) & {
whenLoaded?: Promise<WorkerLike>;
loaded?: boolean;
__emnapi_tid?: number;
};
export declare interface WorkerMessageEvent<T = any> {
data: T;
}
export declare type WorkerMessageType = 'load' | 'start';
export { }
File diff suppressed because it is too large Load Diff
+7227
View File
File diff suppressed because it is too large Load Diff
+5
View File
@@ -0,0 +1,5 @@
import { PluginFactory } from '../emnapi-core'
export { PluginFactory, PluginContext, EmnapiPlugin } from '../emnapi-core'
declare const _default: PluginFactory
export default _default
+818
View File
@@ -0,0 +1,818 @@
//#region src/emnapi/async-work.js
function asyncWork (emnapiPluginCtx) {
const { emnapiCtx, emnapiNodeBinding, emnapiAsyncWorkPoolSize } = emnapiPluginCtx;
var mod = (function (exports, emnapi_shared, emscripten_runtime) {
//#region src/async-work.ts
/**
* @__deps $emnapiCtx
* @__deps $emnapiEnv
* @__deps $emnapiNodeBinding
* @__deps $emnapiAsyncWorkPoolSize
* @__postset
* ```
* emnapiAWST.init();
* ```
*/
var emnapiAWST = {
idGen: {},
values: [undefined],
queued: new Set(),
pending: [],
init: function () {
const idGen = {
nextId: 1,
list: [],
generate: function () {
let id;
if (idGen.list.length) {
id = idGen.list.shift();
}
else {
id = idGen.nextId;
idGen.nextId++;
}
return id;
},
reuse: function (id) {
idGen.list.push(id);
}
};
emnapiAWST.idGen = idGen;
emnapiAWST.values = [undefined];
emnapiAWST.queued = new Set();
emnapiAWST.pending = [];
},
create: function (env, resource, resourceName, execute, complete, data) {
let asyncId = 0;
let triggerAsyncId = 0;
if (emnapiNodeBinding) {
const asyncContext = emnapiNodeBinding.node.emitAsyncInit(resource, resourceName, -1);
asyncId = asyncContext.asyncId;
triggerAsyncId = asyncContext.triggerAsyncId;
}
const id = emnapiAWST.idGen.generate();
emnapiAWST.values[id] = {
env,
id,
resource,
asyncId,
triggerAsyncId,
status: 0,
execute,
complete,
data
};
return id;
},
callComplete: function (work, status) {
const complete = work.complete;
const env = work.env;
const data = work.data;
const callback = () => {
if (!complete)
return;
const envObject = emnapi_shared.emnapiEnv;
const scope = emnapiCtx.openScope(envObject);
try {
envObject.callbackIntoModule(true, () => {
(emnapiPluginCtx.wasmTable.get(complete))(env, status, data);
});
}
finally {
emnapiCtx.closeScope(envObject, scope);
}
};
if (emnapiNodeBinding) {
emnapiNodeBinding.node.makeCallback(work.resource, callback, [], {
asyncId: work.asyncId,
triggerAsyncId: work.triggerAsyncId
});
}
else {
callback();
}
},
queue: function (id) {
const work = emnapiAWST.values[id];
if (!work)
return;
if (work.status === 0) {
work.status = 1;
if (emnapiAWST.queued.size >= (Math.abs(emnapiAsyncWorkPoolSize) || 4)) {
emnapiAWST.pending.push(id);
return;
}
emnapiAWST.queued.add(id);
const env = work.env;
const data = work.data;
const execute = work.execute;
work.status = 2;
emnapiCtx.features.setImmediate(() => {
(emnapiPluginCtx.wasmTable.get(execute))(env, data);
emnapiAWST.queued.delete(id);
work.status = 3;
emnapiCtx.features.setImmediate(() => {
emnapiAWST.callComplete(work, 0 /* napi_status.napi_ok */);
});
if (emnapiAWST.pending.length > 0) {
const nextWorkId = emnapiAWST.pending.shift();
emnapiAWST.values[nextWorkId].status = 0;
emnapiAWST.queue(nextWorkId);
}
});
}
},
cancel: function (id) {
const index = emnapiAWST.pending.indexOf(id);
if (index !== -1) {
const work = emnapiAWST.values[id];
if (work && (work.status === 1)) {
work.status = 4;
emnapiAWST.pending.splice(index, 1);
emnapiCtx.features.setImmediate(() => {
emnapiAWST.callComplete(work, 11 /* napi_status.napi_cancelled */);
});
return 0 /* napi_status.napi_ok */;
}
else {
return 9 /* napi_status.napi_generic_failure */;
}
}
return 9 /* napi_status.napi_generic_failure */;
},
remove: function (id) {
const work = emnapiAWST.values[id];
if (!work)
return;
if (emnapiNodeBinding) {
emnapiNodeBinding.node.emitAsyncDestroy({
asyncId: work.asyncId,
triggerAsyncId: work.triggerAsyncId
});
}
emnapiAWST.values[id] = undefined;
emnapiAWST.idGen.reuse(id);
}
};
//#endregion src/async-work.ts
//#region src/macro.ts
//#endregion src/macro.ts
//#region src/core/async-work.ts
const {
// onCreateWorker, napiModule, singleThreadAsyncWork, _emnapi_async_work_pool_size,
// PThread, ENVIRONMENT_IS_NODE, ENVIRONMENT_IS_PTHREAD, wasmInstance, _free, wasmMemory, _malloc,
_emnapi_node_emit_async_init, _emnapi_node_emit_async_destroy, _emnapi_runtime_keepalive_pop, _emnapi_runtime_keepalive_push } = emnapiPluginCtx;
var emnapiAWMT = {
pool: [],
workerReady: null,
globalAddress: 0,
globalOffset: {
idle_threads: 0,
q: 1 * 4,
next: 1 * 4,
prev: 2 * 4,
mutex: 3 * 4,
cond: 4 * 4,
exit_message: 5 * 4,
end: 7 * 4
},
offset: {
/* napi_ref */ resource: 0,
/* double */ async_id: 8,
/* double */ trigger_async_id: 16,
/* napi_env */ env: 24,
/* int32_t */ status: 1 * 4 + 24, // 0 for pending, 1 for cancelled, 2 for completed
queue: 2 * 4 + 24,
queue_next: 2 * 4 + 24,
queue_prev: 3 * 4 + 24,
/* void* */ data: 4 * 4 + 24,
/* napi_async_execute_callback */ execute: 5 * 4 + 24,
/* napi_async_complete_callback */ complete: 6 * 4 + 24,
end: 7 * 4 + 24
},
/**
* When another thread grows the shared WebAssembly.Memory, this agent's
* cached `wasmMemory.buffer` may still have the old shorter length
* (V8 refreshes it lazily). If a pointer derived from shared memory lies
* beyond the cached length, `wasmMemory.grow(0)` forces the agent to
* observe the current memory size and refreshes the buffer.
*/
ensureBufferFor(end) {
let buffer = emscripten_runtime.wasmMemory.buffer;
if (end > buffer.byteLength) {
emscripten_runtime.wasmMemory.grow(0);
buffer = emscripten_runtime.wasmMemory.buffer;
}
return buffer;
},
init() {
emnapiAWMT.pool = [];
emnapiAWMT.workerReady = null;
if (typeof emscripten_runtime.PThread !== 'undefined') {
emscripten_runtime.PThread.unusedWorkers.forEach(emnapiAWMT.addListener);
Object.values(emscripten_runtime.PThread.pthreads).forEach(emnapiAWMT.addListener);
const __original_getNewWorker = emscripten_runtime.PThread.getNewWorker;
emscripten_runtime.PThread.getNewWorker = function () {
const r = __original_getNewWorker.apply(this, arguments);
emnapiAWMT.addListener(r);
return r;
};
}
},
addListener(worker) {
if (!worker)
return false;
if (worker._emnapiAWMTListener)
return true;
const handler = function (e) {
const data = emscripten_runtime.ENVIRONMENT_IS_NODE ? e : e.data;
const __emnapi__ = data.__emnapi__;
if (__emnapi__) {
const type = __emnapi__.type;
const payload = __emnapi__.payload;
if (type === 'async-work-complete') {
emnapiAWMT.callComplete(payload.work, 0 /* napi_status.napi_ok */);
}
}
};
const dispose = function () {
if (emscripten_runtime.ENVIRONMENT_IS_NODE) {
worker.off('message', handler);
}
else {
worker.removeEventListener('message', handler, false);
}
delete worker._emnapiAWMTListener;
};
worker._emnapiAWMTListener = { handler, dispose };
if (emscripten_runtime.ENVIRONMENT_IS_NODE) {
worker.on('message', handler);
}
else {
worker.addEventListener('message', handler, false);
}
return true;
},
initGlobal() {
if (!emnapiAWMT.globalAddress) {
emnapiAWMT.globalAddress = emscripten_runtime._malloc(emnapiAWMT.globalOffset.end);
emnapiAWMT.globalAddress >>>= 0;
const size = emnapiAWMT.globalOffset.end;
const addr = emnapiAWMT.globalAddress;
new Uint8Array(emnapiAWMT.ensureBufferFor(addr + size), addr, size).fill(0);
emnapiAWMT.queueInit(emnapiAWMT.globalAddress + emnapiAWMT.globalOffset.q);
emnapiAWMT.queueInit(emnapiAWMT.globalAddress + emnapiAWMT.globalOffset.exit_message);
}
},
terminateWorkers() {
emnapiAWMT.pool.forEach(w => {
w._emnapiAWMTListener?.dispose();
w._emnapiTSFNListener?.dispose();
w.terminate();
});
emnapiAWMT.pool.length = 0;
},
initWorkers(n) {
if (emscripten_runtime.ENVIRONMENT_IS_PTHREAD) {
return emnapiAWMT.workerReady || (emnapiAWMT.workerReady = Promise.resolve());
}
if (emnapiAWMT.workerReady)
return emnapiAWMT.workerReady;
if (!('emnapi_async_worker_create' in emscripten_runtime.wasmInstance.exports)) {
throw new TypeError('`emnapi_async_worker_create` is not exported, please try to add `--export=emnapi_async_worker_create` to linker flags');
}
const emnapi_async_worker_create = emscripten_runtime.wasmInstance.exports.emnapi_async_worker_create;
const args = [];
emnapiAWMT.initGlobal();
for (let i = 0; i < n; ++i) {
args.push(emnapi_async_worker_create(1, emnapiAWMT.globalAddress));
}
const promises = args.map(index => {
if (index === 0) {
return Promise.reject(new Error('Failed to create async worker'));
}
let worker;
if (index < 0) {
worker = emnapiAWMT.pool[-index - 1];
if (worker)
return worker.whenLoaded;
}
index >>>= 0;
const tidOffset = 20;
const view = new DataView(emnapiAWMT.ensureBufferFor(index + tidOffset + 4));
const tid = view.getInt32(index + tidOffset, true);
worker = emscripten_runtime.PThread.pthreads[tid];
return worker.whenLoaded;
});
emnapiAWMT.workerReady = Promise.all(promises);
return emnapiAWMT.workerReady;
},
getResource(work) {
emnapiAWMT.ensureBufferFor(work + emnapiAWMT.offset.resource + 4);
var HEAP_DATA_VIEW = new DataView(emnapiPluginCtx.wasmMemory.buffer), GET_HEAP_DATA_VIEW = () => HEAP_DATA_VIEW.buffer === emnapiPluginCtx.wasmMemory.buffer ? HEAP_DATA_VIEW : (HEAP_DATA_VIEW = new DataView(emnapiPluginCtx.wasmMemory.buffer));
return GET_HEAP_DATA_VIEW().getUint32(work + emnapiAWMT.offset.resource, true);
},
getExecute(work) {
emnapiAWMT.ensureBufferFor(work + emnapiAWMT.offset.execute + 4);
var HEAP_DATA_VIEW = new DataView(emnapiPluginCtx.wasmMemory.buffer), GET_HEAP_DATA_VIEW = () => HEAP_DATA_VIEW.buffer === emnapiPluginCtx.wasmMemory.buffer ? HEAP_DATA_VIEW : (HEAP_DATA_VIEW = new DataView(emnapiPluginCtx.wasmMemory.buffer));
return GET_HEAP_DATA_VIEW().getUint32(work + emnapiAWMT.offset.execute, true);
},
getComplete(work) {
emnapiAWMT.ensureBufferFor(work + emnapiAWMT.offset.complete + 4);
var HEAP_DATA_VIEW = new DataView(emnapiPluginCtx.wasmMemory.buffer), GET_HEAP_DATA_VIEW = () => HEAP_DATA_VIEW.buffer === emnapiPluginCtx.wasmMemory.buffer ? HEAP_DATA_VIEW : (HEAP_DATA_VIEW = new DataView(emnapiPluginCtx.wasmMemory.buffer));
return GET_HEAP_DATA_VIEW().getUint32(work + emnapiAWMT.offset.complete, true);
},
getEnv(work) {
emnapiAWMT.ensureBufferFor(work + emnapiAWMT.offset.env + 4);
var HEAP_DATA_VIEW = new DataView(emnapiPluginCtx.wasmMemory.buffer), GET_HEAP_DATA_VIEW = () => HEAP_DATA_VIEW.buffer === emnapiPluginCtx.wasmMemory.buffer ? HEAP_DATA_VIEW : (HEAP_DATA_VIEW = new DataView(emnapiPluginCtx.wasmMemory.buffer));
return GET_HEAP_DATA_VIEW().getUint32(work + emnapiAWMT.offset.env, true);
},
getData(work) {
emnapiAWMT.ensureBufferFor(work + emnapiAWMT.offset.data + 4);
var HEAP_DATA_VIEW = new DataView(emnapiPluginCtx.wasmMemory.buffer), GET_HEAP_DATA_VIEW = () => HEAP_DATA_VIEW.buffer === emnapiPluginCtx.wasmMemory.buffer ? HEAP_DATA_VIEW : (HEAP_DATA_VIEW = new DataView(emnapiPluginCtx.wasmMemory.buffer));
return GET_HEAP_DATA_VIEW().getUint32(work + emnapiAWMT.offset.data, true);
},
getMutex() {
const index = emnapiAWMT.globalAddress + emnapiAWMT.globalOffset.mutex;
const mutex = {
lock() {
const isBrowserMain = typeof window !== 'undefined' && typeof document !== 'undefined' && !emscripten_runtime.ENVIRONMENT_IS_NODE;
const i32a = new Int32Array(emnapiAWMT.ensureBufferFor(index + 4), index, 1);
if (isBrowserMain) {
while (true) {
const oldValue = Atomics.compareExchange(i32a, 0, 0, 10);
if (oldValue === 0) {
return;
}
}
}
else {
while (true) {
const oldValue = Atomics.compareExchange(i32a, 0, 0, 10);
if (oldValue === 0) {
return;
}
Atomics.wait(i32a, 0, 10);
}
}
},
unlock() {
const i32a = new Int32Array(emnapiAWMT.ensureBufferFor(index + 4), index, 1);
const oldValue = Atomics.compareExchange(i32a, 0, 10, 0);
if (oldValue !== 10) {
throw new Error('Tried to unlock while not holding the mutex');
}
Atomics.notify(i32a, 0, 1);
},
execute(fn) {
mutex.lock();
try {
return fn();
}
finally {
mutex.unlock();
}
}
};
return mutex;
},
getCond() {
const index = emnapiAWMT.globalAddress + emnapiAWMT.globalOffset.cond;
const mutex = emnapiAWMT.getMutex();
const cond = {
wait() {
const i32a = new Int32Array(emnapiAWMT.ensureBufferFor(index + 4), index, 1);
const value = Atomics.load(i32a, 0);
mutex.unlock();
Atomics.wait(i32a, 0, value);
mutex.lock();
},
signal() {
const i32a = new Int32Array(emnapiAWMT.ensureBufferFor(index + 4), index, 1);
Atomics.add(i32a, 0, 1);
Atomics.notify(i32a, 0, 1);
}
};
return cond;
},
queueInit(q) {
emnapiAWMT.ensureBufferFor(q + 4 + 4);
var HEAP_DATA_VIEW = new DataView(emnapiPluginCtx.wasmMemory.buffer), GET_HEAP_DATA_VIEW = () => HEAP_DATA_VIEW.buffer === emnapiPluginCtx.wasmMemory.buffer ? HEAP_DATA_VIEW : (HEAP_DATA_VIEW = new DataView(emnapiPluginCtx.wasmMemory.buffer));
GET_HEAP_DATA_VIEW().setUint32(q, q, true);
GET_HEAP_DATA_VIEW().setUint32(q + 4, q, true);
},
queueInsertTail(h, q) {
emnapiAWMT.ensureBufferFor(h + 4 + 4);
emnapiAWMT.ensureBufferFor(q + 4 + 4);
var HEAP_DATA_VIEW = new DataView(emnapiPluginCtx.wasmMemory.buffer), GET_HEAP_DATA_VIEW = () => HEAP_DATA_VIEW.buffer === emnapiPluginCtx.wasmMemory.buffer ? HEAP_DATA_VIEW : (HEAP_DATA_VIEW = new DataView(emnapiPluginCtx.wasmMemory.buffer));
GET_HEAP_DATA_VIEW().setUint32(q, h, true);
const tempValue = GET_HEAP_DATA_VIEW().getUint32(h + 4, true);
GET_HEAP_DATA_VIEW().setUint32(q + 4, tempValue, true);
const qprev = GET_HEAP_DATA_VIEW().getUint32(q + 4, true);
GET_HEAP_DATA_VIEW().setUint32(qprev, q, true);
GET_HEAP_DATA_VIEW().setUint32(h + 4, q, true);
},
queueRemove(q) {
emnapiAWMT.ensureBufferFor(q + 4 + 4);
var HEAP_DATA_VIEW = new DataView(emnapiPluginCtx.wasmMemory.buffer), GET_HEAP_DATA_VIEW = () => HEAP_DATA_VIEW.buffer === emnapiPluginCtx.wasmMemory.buffer ? HEAP_DATA_VIEW : (HEAP_DATA_VIEW = new DataView(emnapiPluginCtx.wasmMemory.buffer));
const qprev = GET_HEAP_DATA_VIEW().getUint32(q + 4, true);
const qnext = GET_HEAP_DATA_VIEW().getUint32(q, true);
GET_HEAP_DATA_VIEW().setUint32(qprev, qnext, true);
GET_HEAP_DATA_VIEW().setUint32(qnext + 4, qprev, true);
},
queueEmpty(q) {
emnapiAWMT.ensureBufferFor(q + 4);
var HEAP_DATA_VIEW = new DataView(emnapiPluginCtx.wasmMemory.buffer), GET_HEAP_DATA_VIEW = () => HEAP_DATA_VIEW.buffer === emnapiPluginCtx.wasmMemory.buffer ? HEAP_DATA_VIEW : (HEAP_DATA_VIEW = new DataView(emnapiPluginCtx.wasmMemory.buffer));
// eslint-disable-next-line eqeqeq
return q == GET_HEAP_DATA_VIEW().getUint32(q, true);
},
scheduleWork: function (work) {
if (!emnapiAWMT.workerReady?.ready) {
emnapiAWMT.initWorkers(emnapi_shared._emnapi_async_work_pool_size()).then(() => {
emnapiAWMT.workerReady.ready = true;
}).catch((err) => {
emnapiAWMT.workerReady = null;
throw err;
});
}
_emnapi_runtime_keepalive_push();
emnapiCtx.increaseWaitingRequestCounter();
const statusBuffer = new Int32Array(emnapiAWMT.ensureBufferFor(work + emnapiAWMT.offset.status + 4), work + emnapiAWMT.offset.status, 1);
Atomics.store(statusBuffer, 0, 0 /* AsyncWorkStatus.Pending */);
const mutex = emnapiAWMT.getMutex();
const cond = emnapiAWMT.getCond();
mutex.lock();
try {
emnapiAWMT.queueInsertTail(emnapiAWMT.globalAddress + emnapiAWMT.globalOffset.q, work + emnapiAWMT.offset.queue);
}
catch (err) {
_emnapi_runtime_keepalive_pop();
emnapiCtx.decreaseWaitingRequestCounter();
mutex.unlock();
throw err;
}
emnapiAWMT.ensureBufferFor(emnapiAWMT.globalAddress + emnapiAWMT.globalOffset.idle_threads + 4);
var HEAP_DATA_VIEW = new DataView(emnapiPluginCtx.wasmMemory.buffer), GET_HEAP_DATA_VIEW = () => HEAP_DATA_VIEW.buffer === emnapiPluginCtx.wasmMemory.buffer ? HEAP_DATA_VIEW : (HEAP_DATA_VIEW = new DataView(emnapiPluginCtx.wasmMemory.buffer));
if (GET_HEAP_DATA_VIEW().getUint32(emnapiAWMT.globalAddress + emnapiAWMT.globalOffset.idle_threads, true) > 0) {
cond.signal();
}
mutex.unlock();
},
cancelWork(work) {
let cancelled = false;
emnapiAWMT.getMutex().execute(() => {
emnapiAWMT.ensureBufferFor(work + emnapiAWMT.offset.status + 4);
var HEAP_DATA_VIEW = new DataView(emnapiPluginCtx.wasmMemory.buffer), GET_HEAP_DATA_VIEW = () => HEAP_DATA_VIEW.buffer === emnapiPluginCtx.wasmMemory.buffer ? HEAP_DATA_VIEW : (HEAP_DATA_VIEW = new DataView(emnapiPluginCtx.wasmMemory.buffer));
cancelled = !emnapiAWMT.queueEmpty(work + emnapiAWMT.offset.queue) && GET_HEAP_DATA_VIEW().getInt32(work + emnapiAWMT.offset.status, true) !== 2 /* AsyncWorkStatus.Completed */;
if (cancelled) {
emnapiAWMT.queueRemove(work + emnapiAWMT.offset.queue);
}
});
if (!cancelled) {
return 9 /* napi_status.napi_generic_failure */;
}
if (Atomics.compareExchange(new Int32Array(emnapiAWMT.ensureBufferFor(work + emnapiAWMT.offset.status + 4), work + emnapiAWMT.offset.status, 1), 0, 0 /* AsyncWorkStatus.Pending */, 1 /* AsyncWorkStatus.Cancelled */) !== 0 /* AsyncWorkStatus.Pending */) {
return 9 /* napi_status.napi_generic_failure */;
}
emnapiCtx.features.setImmediate(() => {
emnapiAWMT.callComplete(work, 11 /* napi_status.napi_cancelled */);
});
return 0 /* napi_status.napi_ok */;
},
callComplete: function (work, status) {
_emnapi_runtime_keepalive_pop();
emnapiCtx.decreaseWaitingRequestCounter();
const complete = emnapiAWMT.getComplete(work);
const env = emnapiAWMT.getEnv(work);
const data = emnapiAWMT.getData(work);
const envObject = emnapi_shared.emnapiEnv;
const scope = emnapiCtx.openScope(envObject);
const callback = () => {
if (!complete)
return;
envObject.callbackIntoModule(true, () => {
(emnapiPluginCtx.wasmTable.get(complete))(env, status, data);
});
};
try {
if (emnapiNodeBinding) {
const resource = emnapiAWMT.getResource(work);
const resource_value = emnapiCtx.getRef(resource).get();
const resourceObject = emnapiCtx.jsValueFromNapiValue(resource_value);
const view = new DataView(emnapiAWMT.ensureBufferFor(work + emnapiAWMT.offset.trigger_async_id + 8));
const asyncId = view.getFloat64(work + emnapiAWMT.offset.async_id, true);
const triggerAsyncId = view.getFloat64(work + emnapiAWMT.offset.trigger_async_id, true);
emnapiNodeBinding.node.makeCallback(resourceObject, callback, [], {
asyncId,
triggerAsyncId
});
}
else {
callback();
}
}
finally {
emnapiCtx.closeScope(envObject, scope);
}
}
};
emnapiAWST.init();
emnapiAWMT.init();
/** @__sig ippppppp */
var napi_create_async_work = emnapi_shared.singleThreadAsyncWork
? function (env, resource, resource_name, execute, complete, data, result) {
if (!env)
return 1 /* napi_status.napi_invalid_arg */;
// @ts-expect-error
const envObject = emnapi_shared.emnapiEnv;
envObject.checkGCAccess();
if (!execute)
return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
if (!result)
return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
let resourceObject;
if (resource) {
resourceObject = Object(emnapiCtx.jsValueFromNapiValue(resource));
}
else {
resourceObject = {};
}
if (!resource_name)
return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
const resourceName = String(emnapiCtx.jsValueFromNapiValue(resource_name));
const id = emnapiAWST.create(env, resourceObject, resourceName, execute, complete, data);
result >>>= 0;
var HEAP_DATA_VIEW = new DataView(emnapiPluginCtx.wasmMemory.buffer), GET_HEAP_DATA_VIEW = () => HEAP_DATA_VIEW.buffer === emnapiPluginCtx.wasmMemory.buffer ? HEAP_DATA_VIEW : (HEAP_DATA_VIEW = new DataView(emnapiPluginCtx.wasmMemory.buffer));
GET_HEAP_DATA_VIEW().setUint32(result, id, true);
return envObject.clearLastError();
}
: function (env, resource, resource_name, execute, complete, data, result) {
if (!env)
return 1 /* napi_status.napi_invalid_arg */;
// @ts-expect-error
const envObject = emnapi_shared.emnapiEnv;
envObject.checkGCAccess();
if (!execute)
return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
if (!result)
return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
let resourceObject;
if (resource) {
resourceObject = Object(emnapiCtx.jsValueFromNapiValue(resource));
}
else {
resourceObject = {};
}
if (!resource_name)
return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
const sizeofAW = emnapiAWMT.offset.end;
let aw = emscripten_runtime._malloc(sizeofAW);
if (!aw)
return envObject.setLastError(9 /* napi_status.napi_generic_failure */);
aw >>>= 0;
new Uint8Array(emnapiAWMT.ensureBufferFor(aw + sizeofAW)).subarray(aw, aw + sizeofAW).fill(0);
const s = emnapiCtx.napiValueFromJsValue(resourceObject);
const resourceRef = emnapiCtx.createReference(envObject, s, 1, 1 /* ReferenceOwnership.kUserland */);
const resource_ = resourceRef.id;
var HEAP_DATA_VIEW = new DataView(emnapiPluginCtx.wasmMemory.buffer), GET_HEAP_DATA_VIEW = () => HEAP_DATA_VIEW.buffer === emnapiPluginCtx.wasmMemory.buffer ? HEAP_DATA_VIEW : (HEAP_DATA_VIEW = new DataView(emnapiPluginCtx.wasmMemory.buffer));
GET_HEAP_DATA_VIEW().setUint32(aw, resource_, true);
_emnapi_node_emit_async_init(s, resource_name, -1, aw + emnapiAWMT.offset.async_id);
GET_HEAP_DATA_VIEW().setUint32(aw + emnapiAWMT.offset.env, env, true);
GET_HEAP_DATA_VIEW().setUint32(aw + emnapiAWMT.offset.execute, execute, true);
GET_HEAP_DATA_VIEW().setUint32(aw + emnapiAWMT.offset.complete, complete, true);
GET_HEAP_DATA_VIEW().setUint32(aw + emnapiAWMT.offset.data, data, true);
emnapiAWMT.queueInit(aw + emnapiAWMT.offset.queue);
result >>>= 0;
GET_HEAP_DATA_VIEW().setUint32(result, aw, true);
return envObject.clearLastError();
};
/** @__sig ipp */
var napi_delete_async_work = emnapi_shared.singleThreadAsyncWork
? function (env, work) {
if (!env)
return 1 /* napi_status.napi_invalid_arg */;
// @ts-expect-error
const envObject = emnapi_shared.emnapiEnv;
envObject.checkGCAccess();
if (!work)
return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
work >>>= 0;
emnapiAWST.remove(work);
return envObject.clearLastError();
}
: function (env, work) {
if (!env)
return 1 /* napi_status.napi_invalid_arg */;
// @ts-expect-error
const envObject = emnapi_shared.emnapiEnv;
envObject.checkGCAccess();
if (!work)
return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
work >>>= 0;
const resource = emnapiAWMT.getResource(work);
emnapiCtx.getRef(resource).dispose();
if (emnapiNodeBinding) {
const view = new DataView(emnapiAWMT.ensureBufferFor(work + emnapiAWMT.offset.trigger_async_id + 8));
const asyncId = view.getFloat64(work + emnapiAWMT.offset.async_id, true);
const triggerAsyncId = view.getFloat64(work + emnapiAWMT.offset.trigger_async_id, true);
_emnapi_node_emit_async_destroy(asyncId, triggerAsyncId);
}
emscripten_runtime._free(work);
return envObject.clearLastError();
};
/** @__sig ipp */
var napi_queue_async_work = emnapi_shared.singleThreadAsyncWork
? function (env, work) {
if (!env)
return 1 /* napi_status.napi_invalid_arg */;
const envObject = emnapi_shared.emnapiEnv;
if (!work)
return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
work >>>= 0;
emnapiAWST.queue(work);
return envObject.clearLastError();
}
: function (env, work) {
if (!env)
return 1 /* napi_status.napi_invalid_arg */;
const envObject = emnapi_shared.emnapiEnv;
if (!work)
return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
work >>>= 0;
emnapiAWMT.scheduleWork(work);
return envObject.clearLastError();
};
/** @__sig ipp */
var napi_cancel_async_work = emnapi_shared.singleThreadAsyncWork
? function (env, work) {
if (!env)
return 1 /* napi_status.napi_invalid_arg */;
const envObject = emnapi_shared.emnapiEnv;
if (!work)
return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
work >>>= 0;
const status = emnapiAWST.cancel(work);
if (status === 0 /* napi_status.napi_ok */)
return envObject.clearLastError();
return envObject.setLastError(status);
}
: function (env, work) {
if (!env)
return 1 /* napi_status.napi_invalid_arg */;
const envObject = emnapi_shared.emnapiEnv;
if (!work)
return envObject.setLastError(1 /* napi_status.napi_invalid_arg */);
work >>>= 0;
const status = emnapiAWMT.cancelWork(work);
if (status === 0 /* napi_status.napi_ok */)
return envObject.clearLastError();
return envObject.setLastError(status);
};
/** @__sig pp */
function _emnapi_async_worker(globalAddress) {
globalAddress >>>= 0;
emnapiAWMT.globalAddress = globalAddress;
const mutex = emnapiAWMT.getMutex();
const cond = emnapiAWMT.getCond();
mutex.lock();
const exitMessageAddr = globalAddress + emnapiAWMT.globalOffset.exit_message;
const idleThreadsAddr = globalAddress + emnapiAWMT.globalOffset.idle_threads;
const workerQueueAddr = globalAddress + emnapiAWMT.globalOffset.q;
var HEAP_DATA_VIEW = new DataView(emnapiPluginCtx.wasmMemory.buffer), GET_HEAP_DATA_VIEW = () => HEAP_DATA_VIEW.buffer === emnapiPluginCtx.wasmMemory.buffer ? HEAP_DATA_VIEW : (HEAP_DATA_VIEW = new DataView(emnapiPluginCtx.wasmMemory.buffer));
for (;;) {
emnapiAWMT.ensureBufferFor(workerQueueAddr + 4);
while (emnapiAWMT.queueEmpty(workerQueueAddr)) {
Atomics.add(new Int32Array(emnapiAWMT.ensureBufferFor(idleThreadsAddr + 4), idleThreadsAddr, 1), 0, 1);
cond.wait();
Atomics.sub(new Int32Array(emnapiAWMT.ensureBufferFor(idleThreadsAddr + 4), idleThreadsAddr, 1), 0, 1);
}
const q = GET_HEAP_DATA_VIEW().getUint32(workerQueueAddr, true);
if (q === exitMessageAddr) {
cond.signal();
mutex.unlock();
break;
}
const work = q - emnapiAWMT.offset.queue;
emnapiAWMT.queueRemove(q);
emnapiAWMT.queueInit(q);
mutex.unlock();
const statusBuffer = new Int32Array(emnapiAWMT.ensureBufferFor(work + emnapiAWMT.offset.status + 4), work + emnapiAWMT.offset.status, 1);
if (Atomics.load(statusBuffer, 0) === 1 /* AsyncWorkStatus.Cancelled */) {
emscripten_runtime.abort('unreachable');
}
const execute = emnapiAWMT.getExecute(work);
const env = emnapiAWMT.getEnv(work);
const data = emnapiAWMT.getData(work);
(emnapiPluginCtx.wasmTable.get(execute))(env, data);
Atomics.store(statusBuffer, 0, 2 /* AsyncWorkStatus.Completed */);
const postMessage = emnapi_shared.napiModule.postMessage;
postMessage({
__emnapi__: {
type: 'async-work-complete',
payload: { work }
}
});
mutex.lock();
}
return 0;
}
/** @__sig ipp */
function _emnapi_spawn_worker(f, globalAddress) {
if (typeof emnapi_shared.onCreateWorker !== 'function') {
throw new TypeError('`options.onCreateWorker` is not a function');
}
const promises = [];
const args = [];
if (!('emnapi_async_worker_create' in emscripten_runtime.wasmInstance.exports)) {
throw new TypeError('`emnapi_async_worker_create` is not exported, please try to add `--export=emnapi_async_worker_create` to linker flags');
}
args.push(emscripten_runtime.wasmInstance.exports.emnapi_async_worker_create(0, 0));
const handleError = (e) => {
if ('message' in e && (e.message.indexOf('RuntimeError') !== -1 || e.message.indexOf('unreachable') !== -1)) {
emnapiAWMT.terminateWorkers();
}
};
let ret;
try {
const worker = emnapi_shared.onCreateWorker({ type: 'async-work', name: 'emnapi-async-worker' });
const p = emscripten_runtime.PThread.loadWasmModuleToWorker(worker);
if (emscripten_runtime.ENVIRONMENT_IS_NODE) {
worker.on('error', handleError);
}
else {
worker.addEventListener('error', handleError, false);
}
emnapiAWMT.addListener(worker);
if (typeof emnapiPluginCtx.emnapiTSFN !== 'undefined') {
emnapiPluginCtx.emnapiTSFN.addListener(worker);
}
promises.push(p.then(() => {
if (typeof worker.unref === 'function') {
worker.unref();
}
}));
ret = emnapiAWMT.pool.push(worker) - 1;
const arg = args[0];
worker.threadBlockBase = arg;
worker.postMessage({
__emnapi__: {
type: 'async-worker-init',
payload: { arg, func: [f, globalAddress] }
}
});
}
catch (err) {
const arg = args[0];
emscripten_runtime._free(arg);
throw err;
}
return ret;
}
function initWorker(startArg, func) {
if (emnapi_shared.napiModule.childThread) {
if (typeof emscripten_runtime.wasmInstance.exports.emnapi_async_worker_init !== 'function') {
throw new TypeError('`emnapi_async_worker_init` is not exported, please try to add `--export=emnapi_async_worker_init` to linker flags');
}
emscripten_runtime.wasmInstance.exports.emnapi_async_worker_init(startArg);
(emnapiPluginCtx.wasmTable.get(func[0]))(func[1]);
}
else {
throw new Error('startThread is only available in child threads');
}
}
emnapi_shared.napiModule.initWorker = initWorker;
//#endregion src/core/async-work.ts
exports._emnapi_async_worker = _emnapi_async_worker;
exports._emnapi_spawn_worker = _emnapi_spawn_worker;
exports.napi_cancel_async_work = napi_cancel_async_work;
exports.napi_create_async_work = napi_create_async_work;
exports.napi_delete_async_work = napi_delete_async_work;
exports.napi_queue_async_work = napi_queue_async_work;
return exports;
})({}, emnapiPluginCtx, emnapiPluginCtx);
return {
importObject: (original) => {
Object.keys(mod).forEach(key => {
if (key.startsWith('napi_') || key.startsWith('node_api_')) {
original.napi[key] = mod[key];
} else {
original.env[key] = mod[key];
}
});
}
};
}
//#endregion src/emnapi/async-work.js
export { asyncWork as default };
+4
View File
@@ -0,0 +1,4 @@
export { PluginFactory, PluginContext, EmnapiPlugin } from '../emnapi-core'
export { default as v8 } from './v8'
export { default as asyncWork } from './async-work'
export { default as tsfn } from './threadsafe-function'
+3
View File
@@ -0,0 +1,3 @@
export { default as v8 } from './v8.js'
export { default as asyncWork } from './async-work.js'
export { default as tsfn } from './threadsafe-function.js'
+5
View File
@@ -0,0 +1,5 @@
import { PluginFactory } from '../emnapi-core'
export { PluginFactory, PluginContext, EmnapiPlugin } from '../emnapi-core'
declare const _default: PluginFactory
export default _default
File diff suppressed because it is too large Load Diff
+5
View File
@@ -0,0 +1,5 @@
import { PluginFactory } from '../emnapi-core'
export { PluginFactory, PluginContext, EmnapiPlugin } from '../emnapi-core'
declare const _default: PluginFactory
export default _default
+1446
View File
File diff suppressed because it is too large Load Diff
+39
View File
@@ -0,0 +1,39 @@
{
"name": "@emnapi/core",
"version": "2.0.0-alpha.3",
"description": "emnapi core",
"type": "module",
"main": "./dist/emnapi-core.js",
"module": "./dist/emnapi-core.js",
"types": "./dist/emnapi-core.d.ts",
"sideEffects": false,
"exports": {
".": "./dist/emnapi-core.js",
"./plugins": "./dist/plugins/index.js",
"./plugins/index": "./dist/plugins/index.js",
"./plugins/v8": "./dist/plugins/v8.js",
"./plugins/async-work": "./dist/plugins/async-work.js",
"./plugins/threadsafe-function": "./dist/plugins/threadsafe-function.js",
"./package.json": "./package.json"
},
"dependencies": {
"@emnapi/wasi-threads": "2.0.1",
"tslib": "^2.4.0"
},
"scripts": {
"build": "node ./script/build.js && rollup -c"
},
"repository": {
"type": "git",
"url": "git+https://github.com/toyobayashi/emnapi.git"
},
"author": "toyobayashi",
"license": "MIT",
"bugs": {
"url": "https://github.com/toyobayashi/emnapi/issues"
},
"homepage": "https://github.com/toyobayashi/emnapi#readme",
"publishConfig": {
"access": "public"
}
}
+60
View File
@@ -0,0 +1,60 @@
import { defineConfig } from '@emnapi/shared'
import pkg from './package.json' with { type: 'json' }
import { join, dirname } from 'path'
import fs from 'fs'
const plugins = [
['v8', 'v8', 'emnapiCorePluginsV8'],
['asyncWork', 'async-work', 'emnapiCorePluginsAsyncWork'],
['tsfn', 'threadsafe-function', 'emnapiCorePluginsThreadSafeFunction']
]
export default [
...defineConfig({
outputName: 'emnapiCore',
outputFile: 'emnapi-core',
defines: {
__VERSION__: JSON.stringify(pkg.version)
},
external: ['@emnapi/wasi-threads'],
plugins: [
{
name: 'rollup-plugin-create-plugin-entry',
writeBundle (outputOptions) {
const distDir = dirname(outputOptions.file)
fs.mkdirSync(join(distDir, 'plugins'), { recursive: true })
const entryFile = join(distDir, 'plugins', 'index.js')
const dtsEntryFile = join(distDir, 'plugins', 'index.d.ts')
let content = ''
for (const [name, file] of plugins) {
content += `export { default as ${name} } from './${file}.js'\n`
}
let dtsContent = "export { PluginFactory, PluginContext, EmnapiPlugin } from '../emnapi-core'\n"
for (const [name, file] of plugins) {
dtsContent += `export { default as ${name} } from './${file}'\n`
}
fs.writeFileSync(entryFile, content, 'utf8')
fs.writeFileSync(dtsEntryFile, dtsContent, 'utf8')
}
}
]
}),
...defineConfig({
outputFile: 'emnapi-core.full',
defines: {
__VERSION__: JSON.stringify(pkg.version)
},
}),
...plugins.flatMap(([_, name, outputName]) => defineConfig({
outputName,
outputFile: `plugins/${name}`,
dtsEntry: `dist/types/emnapi/${name}.d.ts`,
staticDtsContent: (code) => code.replace(/\.\/index/g, '../emnapi-core'),
input: join(import.meta.dirname, `src/emnapi/${name}.js`),
compilerOptions: {
declaration: false,
declarationMap: false,
declarationDir: undefined
}
}))
]
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021-present Toyobayashi
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.
+1
View File
@@ -0,0 +1 @@
See [https://github.com/toyobayashi/emnapi](https://github.com/toyobayashi/emnapi)
+828
View File
@@ -0,0 +1,828 @@
/// <reference lib="esnext.disposable" />
export declare type Ptr = number | bigint
export declare interface IBuffer extends Uint8Array {
toString (encoding?: string, start?: number, end?: number): string
}
export declare interface BufferCtor {
readonly prototype: IBuffer
/** @deprecated */
new (...args: any[]): IBuffer
from: {
(buffer: ArrayBufferLike): IBuffer
(buffer: ArrayBufferLike, byteOffset: number, length: number): IBuffer
}
alloc: (size: number) => IBuffer
isBuffer: (obj: unknown) => obj is IBuffer
}
export declare const enum Constant {
HOLE,
EMPTY,
UNDEFINED,
NULL,
FALSE,
TRUE,
GLOBAL,
EMPTY_STRING,
}
export declare const enum Version {
NODE_API_SUPPORTED_VERSION_MIN = 1,
NODE_API_DEFAULT_MODULE_API_VERSION = 8,
NODE_API_SUPPORTED_VERSION_MAX = 10,
NODE_MODULE_VERSION = 127,
NAPI_VERSION_EXPERIMENTAL = 2147483647 // INT_MAX
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export declare type Pointer<T> = number | bigint
// eslint-disable-next-line @typescript-eslint/no-unused-vars
export declare type PointerPointer<T> = number
export declare type FunctionPointer<T extends (...args: any[]) => any> = Pointer<T>
export declare type Const<T> = T
export declare type void_p = Pointer<void>
export declare type void_pp = Pointer<void_p>
export declare type bool = number
export declare type char = number
export declare type char_p = Pointer<char>
export declare type unsigned_char = number
export declare type const_char = Const<char>
export declare type const_char_p = Pointer<const_char>
export declare type char16_t = number
export declare type const_char16_t = number
export declare type char16_t_p = Pointer<char16_t>
export declare type const_char16_t_p = Pointer<const_char16_t>
export declare type short = number
export declare type unsigned_short = number
export declare type int = number
export declare type unsigned_int = number
export declare type long = number
export declare type unsigned_long = number
export declare type long_long = bigint
export declare type unsigned_long_long = bigint
export declare type float = number
export declare type double = number
export declare type long_double = number
export declare type size_t = number
export declare type int8_t = number
export declare type uint8_t = number
export declare type int16_t = number
export declare type uint16_t = number
export declare type int32_t = number
export declare type uint32_t = number
export declare type int64_t = bigint
export declare type uint64_t = bigint
export declare type napi_env = Pointer<unknown>
export declare type napi_value = Pointer<unknown>
export declare type napi_ref = Pointer<unknown>
export declare type napi_deferred = Pointer<unknown>
export declare type napi_handle_scope = Pointer<unknown>
export declare type napi_escapable_handle_scope = Pointer<unknown>
export declare type napi_addon_register_func = FunctionPointer<(env: napi_env, exports: napi_value) => napi_value>
export declare type napi_callback_info = Pointer<unknown>
export declare type napi_callback = FunctionPointer<(env: napi_env, info: napi_callback_info) => napi_value>
export declare interface napi_extended_error_info {
error_message: const_char_p
engine_reserved: void_p
engine_error_code: uint32_t
error_code: napi_status
}
export declare interface napi_property_descriptor {
// One of utf8name or name should be NULL.
utf8name: const_char_p
name: napi_value
method: napi_callback
getter: napi_callback
setter: napi_callback
value: napi_value
/* napi_property_attributes */
attributes: number
data: void_p
}
export declare type napi_finalize = FunctionPointer<(
env: napi_env,
finalize_data: void_p,
finalize_hint: void_p
) => void>
export declare interface node_module {
nm_version: int32_t
nm_flags: uint32_t
nm_filename: Pointer<const_char>
nm_register_func: napi_addon_register_func
nm_modname: Pointer<const_char>
nm_priv: Pointer<void>
reserved: PointerPointer<void>
}
export declare interface napi_node_version {
major: uint32_t
minor: uint32_t
patch: uint32_t
release: const_char_p
}
export declare interface emnapi_emscripten_version {
major: uint32_t
minor: uint32_t
patch: uint32_t
}
export declare const enum napi_status {
napi_ok,
napi_invalid_arg,
napi_object_expected,
napi_string_expected,
napi_name_expected,
napi_function_expected,
napi_number_expected,
napi_boolean_expected,
napi_array_expected,
napi_generic_failure,
napi_pending_exception,
napi_cancelled,
napi_escape_called_twice,
napi_handle_scope_mismatch,
napi_callback_scope_mismatch,
napi_queue_full,
napi_closing,
napi_bigint_expected,
napi_date_expected,
napi_arraybuffer_expected,
napi_detachable_arraybuffer_expected,
napi_would_deadlock, // unused
napi_no_external_buffers_allowed,
napi_cannot_run_js
}
export declare const enum napi_property_attributes {
napi_default = 0,
napi_writable = 1 << 0,
napi_enumerable = 1 << 1,
napi_configurable = 1 << 2,
// Used with napi_define_class to distinguish static properties
// from instance properties. Ignored by napi_define_properties.
napi_static = 1 << 10,
/// #ifdef NAPI_EXPERIMENTAL
// Default for class methods.
napi_default_method = napi_writable | napi_configurable,
// Default for object properties, like in JS obj[prop].
napi_default_jsproperty = napi_writable | napi_enumerable | napi_configurable
/// #endif // NAPI_EXPERIMENTAL
}
export declare const enum napi_valuetype {
napi_undefined,
napi_null,
napi_boolean,
napi_number,
napi_string,
napi_symbol,
napi_object,
napi_function,
napi_external,
napi_bigint
}
export declare const enum napi_typedarray_type {
napi_int8_array,
napi_uint8_array,
napi_uint8_clamped_array,
napi_int16_array,
napi_uint16_array,
napi_int32_array,
napi_uint32_array,
napi_float32_array,
napi_float64_array,
napi_bigint64_array,
napi_biguint64_array,
napi_float16_array,
}
export declare const enum napi_key_collection_mode {
napi_key_include_prototypes,
napi_key_own_only
}
export declare const enum napi_key_filter {
napi_key_all_properties = 0,
napi_key_writable = 1,
napi_key_enumerable = 1 << 1,
napi_key_configurable = 1 << 2,
napi_key_skip_strings = 1 << 3,
napi_key_skip_symbols = 1 << 4
}
export declare const enum napi_key_conversion {
napi_key_keep_numbers,
napi_key_numbers_to_strings
}
export declare const enum emnapi_memory_view_type {
emnapi_int8_array,
emnapi_uint8_array,
emnapi_uint8_clamped_array,
emnapi_int16_array,
emnapi_uint16_array,
emnapi_int32_array,
emnapi_uint32_array,
emnapi_float32_array,
emnapi_float64_array,
emnapi_bigint64_array,
emnapi_biguint64_array,
emnapi_float16_array,
emnapi_data_view = -1,
emnapi_buffer = -2
}
export declare const enum napi_threadsafe_function_call_mode {
napi_tsfn_nonblocking,
napi_tsfn_blocking
}
export declare const enum napi_threadsafe_function_release_mode {
napi_tsfn_release,
napi_tsfn_abort
}
export declare class ArrayStore<T extends {
id: number | bigint;
}> extends BaseArrayStore<T> {
protected _allocator: IdAllocator;
constructor(initialCapacity?: number);
insert(value: T): void;
alloc<P extends any[]>(factory: (...args: P) => T, ...args: P): T;
dealloc(id: number | bigint): void;
}
export declare class BaseArrayStore<T> extends Disposable_2 implements ObjectAllocator<T> {
protected _values: [undefined, ...(T | undefined)[]];
constructor(initialCapacity?: number);
assign(id: number | bigint, value: T): T;
deref<R extends T = T>(id: number | bigint): R | undefined;
alloc<P extends any[]>(factory: (...args: P) => T, ...args: P): T;
dealloc(id: number | bigint): void;
dispose(): void;
}
export declare type CleanupHookCallbackFunction = number | ((arg: number) => void);
export declare class Context {
private _isStopping;
private _canCallIntoJs;
private _suppressDestroy;
private envStore;
refStore: Map<number, Reference>;
private readonly refCounter?;
private readonly cleanupQueue;
readonly features: Features;
readonly isolate: Isolate;
constructor(options?: ContextOptions);
getIsolate(): Isolate;
suppressDestroy(): void;
getRuntimeVersions(): {
version: string;
NODE_API_SUPPORTED_VERSION_MAX: Version;
NAPI_VERSION_EXPERIMENTAL: Version;
NODE_API_DEFAULT_MODULE_API_VERSION: Version;
NODE_MODULE_VERSION: Version;
};
createNotSupportWeakRefError(api: string, message: string): NotSupportWeakRefError;
createNotSupportBufferError(api: string, message: string): NotSupportBufferError;
createReference(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership): Reference;
createReferenceWithData(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, data: void_p): Reference;
createReferenceWithFinalizer(envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, finalize_callback?: napi_finalize, finalize_data?: void_p, finalize_hint?: void_p): Reference;
createResolver<T>(): Resolver<T>;
adjustAmountOfExternalAllocatedMemory(changeInBytes: number | bigint): bigint;
createEnv(filename: string, moduleApiVersion: number, bridge: EnvNativeBridge, nodeBinding?: any): Env;
createFunction(envObject: Env, napiCallback: (env: napi_env, info: napi_callback_info) => void_p, data: number | bigint, name: string, dynamicExecution: boolean): Function;
createTrackedFinalizer(envObject: Env, finalize_callback: napi_finalize, finalize_data: void_p, finalize_hint: void_p): TrackedFinalizer;
getCurrentScope(): HandleScope;
openScope(envObject: Env): HandleScope;
closeScope(envObject: Env, scope?: HandleScope): void;
getEnv(env: napi_env): Env | undefined;
getRef(ref: napi_ref): Reference | undefined;
getHandleScope(scope: napi_handle_scope): HandleScope | undefined;
getCallbackInfo(info: napi_callback_info): ICallbackInfo;
napiValueFromJsValue(value: unknown): number | bigint;
jsValueFromNapiValue<T = any>(napiValue: number | bigint): T | undefined;
createExternal(data: number | bigint): External_2;
getExternalValue(external: External_2): number | bigint;
isExternal(value: unknown): boolean;
addCleanupHook(envObject: Env, fn: CleanupHookCallbackFunction, arg: number): void;
removeCleanupHook(envObject: Env, fn: CleanupHookCallbackFunction, arg: number): void;
runCleanup(): void;
increaseWaitingRequestCounter(): void;
decreaseWaitingRequestCounter(): void;
setCanCallIntoJs(value: boolean): void;
setStopping(value: boolean): void;
canCallIntoJs(): boolean;
getDylinkMetadata(binary: WebAssembly.Module | Uint8Array): DylinkMetadata;
destroy(): void;
}
export declare interface ContextOptions extends IsolateOptions {
}
export declare class CountIdAllocator extends Disposable_2 implements IdAllocator {
next: number;
constructor(initialNext?: number);
aquire(): number;
release(_: number): void;
dispose(): void;
}
export declare class CountIdReuseAllocator extends CountIdAllocator implements IdAllocator {
private _freeList;
aquire(): number;
release(id: number): void;
dispose(): void;
}
export declare function createContext(options?: ContextOptions): Context;
export declare function deletePrivate(obj: any, key: Private): boolean;
declare abstract class Disposable_2 implements globalThis.Disposable {
abstract dispose(): void;
[Symbol.dispose](): void;
}
export { Disposable_2 as Disposable }
export declare interface DylinkMetadata {
neededDynlibs: string[];
tlsExports: Set<string>;
weakImports: Set<string>;
runtimePaths: string[];
memorySize: number;
memoryAlign: number;
tableSize: number;
tableAlign: number;
}
export declare class EmnapiError extends Error {
constructor(message?: string);
}
export declare abstract class Env extends Disposable_2 {
id: number | bigint;
openHandleScopes: number;
instanceData: TrackedFinalizer | null;
lastException: Persistent<any>;
refs: number;
reflist: RefTracker;
finalizing_reflist: RefTracker;
pendingFinalizers: RefTracker[];
moduleApiVersion: number;
filename: string;
nodeBinding?: any;
inGcFinalizer: boolean;
bridge: EnvNativeBridge;
readonly ctx: Context;
private store;
constructor(ctx: Context, store: ArrayStore<Env>, bridge: EnvNativeBridge);
canCallIntoJs(): boolean;
terminatedOrTerminating(): boolean;
ref(): void;
unref(): void;
clearLastError(): napi_status;
setLastError(error_code: napi_status, engine_error_code?: uint32_t, engine_reserved?: number): napi_status;
callIntoModule<T>(fn: (env: Env) => T, handleException?: (envObject: Env, value: any) => void): T;
abstract callFinalizer(cb: napi_finalize, data: void_p, hint: void_p): void;
invokeFinalizerFromGC(finalizer: RefTracker): void;
checkGCAccess(): void;
enqueueFinalizer(finalizer: RefTracker): void;
dequeueFinalizer(finalizer: RefTracker): void;
deleteMe(): void;
dispose(): void;
private readonly _bindingMap;
initObjectBinding<S extends object>(value: S): IReferenceBinding;
getObjectBinding<S extends object>(value: S): IReferenceBinding;
setInstanceData(data: number, finalize_cb: number, finalize_hint: number): void;
getInstanceData(): number | bigint;
}
export declare interface EnvNativeBridge {
address: number;
deleteEnv: (ptr: number) => void;
setLastError: (env: napi_env, error_code: napi_status, engine_error_code: uint32_t, engine_reserved: number) => void;
makeDynCall_vppp: (cb: Ptr) => (a: Ptr, b: Ptr, c: Ptr) => void;
makeDynCall_vp: (cb: Ptr) => (a: Ptr) => void;
abort: (msg?: string) => never;
wasm64?: boolean;
}
declare interface External_2 extends Record<any, any> {
}
declare const External_2: {
new (value: number | bigint): External_2;
prototype: null;
};
export { External_2 as External }
export declare interface Features {
makeDynamicFunction: ((...args: any[]) => Function) | undefined;
getGlobalThis: () => typeof globalThis;
setFunctionName: ((fn: Function, name: string) => void) | undefined;
Reflect: typeof Reflect | undefined;
finalizer: boolean;
weakSymbol: boolean;
BigInt: typeof BigInt | undefined;
MessageChannel: typeof MessageChannel | undefined;
Buffer: BufferCtor | undefined;
setImmediate: (callback: () => void) => any;
withResolvers: <T>(this: PromiseConstructor) => Resolver<T>;
}
export declare class Finalizer {
envObject: Env;
private _finalizeCallback;
private _finalizeData;
private _finalizeHint;
private _makeDynCall_vppp;
constructor(envObject: Env, _finalizeCallback?: napi_finalize, _finalizeData?: void_p, _finalizeHint?: void_p);
copy(): Finalizer;
move(target: Finalizer): void;
callback(): napi_finalize;
data(): void_p;
hint(): void_p;
resetEnv(): void;
resetFinalizer(): void;
callFinalizer(): void;
dispose(): void;
}
export declare class FunctionTemplate extends Template {
callback: (info: napi_callback_info, v8FunctionCallback: Ptr) => Ptr;
v8FunctionCallback: Ptr;
data: any;
className: string | undefined;
signature: Signature | undefined;
private _instanceTemplate;
private _prototypeTemplate;
private _cached;
constructor(ctx: Isolate, callback: (info: napi_callback_info, v8FunctionCallback: Ptr) => Ptr, v8FunctionCallback: Ptr, data: any, signature?: Signature);
setClassName(name: string): void;
instanceTemplate(): ObjectTemplate;
prototypeTemplate(): ObjectTemplate;
getFunction(): (...args: any[]) => any;
}
export declare function getDefaultContext(): Context;
export declare function getDylinkMetadata(binary: WebAssembly.Module | Uint8Array): DylinkMetadata;
export declare function getExternalValue(external: External_2): number | bigint;
export declare function getInternalField(instance: object, index: number): any;
export declare function getPrivate(obj: any, key: Private): any;
export declare class HandleScope extends Disposable_2 {
handleStore: HandleStore;
id: number | bigint;
parent: HandleScope | null;
child: HandleScope | null;
start: number;
end: number;
private _escapeCalled;
callbackInfo: ICallbackInfo;
static create(parentScope: HandleScope | null, handleStore: HandleStore, start?: number, end?: number): HandleScope;
constructor(parentScope: HandleScope | null, handleStore: HandleStore, start?: number, end?: number);
reuse(parentScope: HandleScope): void;
add<V>(value: V): number;
addExternal(data: number | bigint): number;
dispose(): void;
escape(handle: number): number;
escapeCalled(): boolean;
}
export declare class HandleStore extends BaseArrayStore<any> {
static MIN_ID: 8;
private _allocator;
private _features;
readonly refValues: Map<number, PersistentValueType<any>>;
private _erase;
private _deref;
constructor(features: Features);
isOutOfScope(id: number): boolean;
deepDeref<R = any>(id: number | bigint): R | undefined;
push<S>(value: S): number;
erase(start: number, end: number, weak: boolean): void;
swap(a: number, b: number): void;
}
export declare function hasPrivate(obj: any, key: Private): boolean;
export declare interface ICallbackInfo {
thiz: any;
holder: any;
data: void_p;
args: ArrayLike<any>;
fn: Function;
}
export declare interface IdAllocator extends Disposable_2 {
aquire(): number;
release(id: number): void;
}
export declare interface IReferenceBinding {
wrapped: number;
tag: Uint32Array | null;
}
export declare function isExternal(object: unknown): object is External_2;
export declare class Isolate {
private _lastException;
private _globalThis;
private _scopeStore;
private _handleStore;
private _externalMemory;
globalHandleStore: PersistentStore;
readonly features: Features;
constructor(options?: IsolateOptions);
napiValueFromJsValue(value: unknown): number | bigint;
jsValueFromNapiValue<T = any>(napiValue: number | bigint): T | undefined;
deleteRefSlotValue(id: number | bigint): void;
getRefSlotValue(id: number | bigint): PersistentValueType<any>;
setRefSlotValue(id: number | bigint, ref: PersistentValueType<any>): void;
createReference<T>(...args: [T] | []): Persistent<T>;
insertRef<T>(persistent: Persistent<T>): void;
getRef<T = any>(ref: napi_ref): Persistent<T> | undefined;
removeRef(ref: napi_ref, force?: boolean): void;
getTryCatch(address: number | bigint): TryCatch | undefined;
pushTryCatch(address: number | bigint): TryCatch;
popTryCatch(address: number | bigint): void;
setLastException(err: any): void;
throwException(err: any): any;
hasPendingException(): boolean;
getAndClearLastException(): any;
adjustAmountOfExternalAllocatedMemory(changeInBytes: number | bigint): bigint;
createSignature(template: FunctionTemplate): Signature;
createObjectTemplate(constructor: any): ObjectTemplate;
setInternalField(obj: any, index: number, value: any): void;
getInternalField(obj: any, index: number): any;
getInternalFieldCount(obj: any): number;
createFunctionTemplate(callback: (info: napi_callback_info, v8FunctionCallback: Ptr) => Ptr, v8FunctionCallback: Ptr, data: any, signature?: Signature): FunctionTemplate;
isScopeEmpty(): boolean;
getCurrentScope(): HandleScope;
openScope(): HandleScope;
closeScope(_scope?: HandleScope): void;
getHandleScope(scope: napi_handle_scope): HandleScope | undefined;
getCallbackInfo(info: napi_callback_info): ICallbackInfo;
createExternal(data: number | bigint): External_2;
getExternalValue(external: External_2): number | bigint;
isExternal(value: unknown): boolean;
createResolver<T>(): Resolver<T>;
createPrivate(name: string): Private;
getOrCreateGlobalPrivate(name: string): Private;
setPrivate(obj: any, key: Private, value: any): void;
getPrivate(obj: any, key: Private): any;
hasPrivate(obj: any, key: Private): boolean;
deletePrivate(obj: any, key: Private): boolean;
}
export declare interface IsolateOptions {
features?: Partial<Features>;
onExternalMemoryChange?: (current: bigint, old: bigint, delta: bigint) => any;
}
export declare function isReferenceType(v: any): v is object;
export declare const NAPI_VERSION_EXPERIMENTAL = Version.NAPI_VERSION_EXPERIMENTAL;
export declare const NODE_API_DEFAULT_MODULE_API_VERSION = Version.NODE_API_DEFAULT_MODULE_API_VERSION;
export declare const NODE_API_SUPPORTED_VERSION_MAX = Version.NODE_API_SUPPORTED_VERSION_MAX;
export declare const NODE_API_SUPPORTED_VERSION_MIN = Version.NODE_API_SUPPORTED_VERSION_MIN;
export declare class NodeEnv extends Env {
destructing: boolean;
finalizationScheduled: boolean;
constructor(ctx: Context, store: ArrayStore<Env>, bridge: EnvNativeBridge);
deleteMe(): void;
canCallIntoJs(): boolean;
triggerFatalException(err: any): void;
callbackIntoModule<T>(enforceUncaughtExceptionPolicy: boolean, fn: (env: Env) => T): T;
callFinalizer(cb: napi_finalize, data: void_p, hint: void_p): void;
callFinalizerInternal(forceUncaught: int, cb: napi_finalize, data: void_p, hint: void_p): void;
enqueueFinalizer(finalizer: RefTracker): void;
drainFinalizerQueue(): void;
}
export declare class NotSupportBufferError extends EmnapiError {
constructor(api: string, message: string);
}
export declare class NotSupportWeakRefError extends EmnapiError {
constructor(api: string, message: string);
}
export declare interface ObjectAllocator<T> extends Disposable_2 {
deref<R extends T = T>(id: number | bigint): R | undefined;
alloc<P extends any[]>(factory: (...args: P) => T, ...args: P): T;
dealloc(id: number | bigint): void;
}
export declare class ObjectTemplate extends Template {
Ctor: any;
internalFieldCount: number;
private _accessors;
constructor(ctx: Isolate, Ctor?: any);
setAccessor(name: string | symbol, getterWrap: (property: Ptr, info: Ptr, getter: Ptr) => Ptr, setterWrap: (property: Ptr, value: Ptr, info: Ptr, setter: Ptr) => Ptr, getter: Ptr, setter: Ptr, data: any, attribute: number, getterSideEffectType: number, setterSideEffectType: number): void;
setInternalFieldCount(value: number): void;
applyToInstance(instance: any): void;
newInstance(_context: any): any;
}
export declare class Persistent<T> extends Disposable_2 {
private _param;
private _callback;
private _isolate;
id: number;
private static readonly _registry;
constructor(isolate: Isolate, ...args: [T] | []);
dispose(): void;
copy(): Persistent<T>;
move(to: Persistent<T>): void;
slot(): number;
getSlot(): PersistentValueType<T>;
setSlot(ref: PersistentValueType<T>): void;
deleteSlot(): void;
setWeak<P>(param: P, callback: (param: P) => void): void;
clearWeak(): void;
reset(): void;
resetTo(value: T): void;
isEmpty(): boolean;
deref(): T | undefined;
}
export declare class PersistentStore extends ArrayStore<Persistent<any>> {
private _recyleList;
constructor(initialCapacity?: number);
markUnused(id: number | bigint): void;
recycle(): void;
}
export declare type PersistentValueType<T> = StrongRef<T> | WeakRef<T extends object ? T : never> | undefined;
export declare class Private {
private _name;
constructor(name: string);
name(): string;
static forApi(name: string): Private;
}
export declare class Reference extends RefTracker {
private static weakCallback;
id: number;
envObject: Env | undefined;
private ctx;
private canBeWeak;
private _refcount;
private _ownership;
static create(ctx: Context, envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, _unused1?: void_p, _unused2?: void_p, _unused3?: void_p): Reference;
constructor(ctx: Context, envObject: Env, handle_id: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership);
getPersistent(): Persistent<any>;
ref(): number;
unref(): number;
deref(): any;
get(): napi_value;
resetFinalizer(): void;
data(): void_p;
refcount(): number;
ownership(): ReferenceOwnership;
protected callUserFinalizer(): void;
protected invokeFinalizerFromGC(): void;
private _setWeak;
setWeakWithData<T>(data: T, callback: (data: T) => void): void;
clearWeak(): void;
finalize(): void;
dispose(): void;
}
export declare enum ReferenceOwnership {
kRuntime = 0,
kUserland = 1
}
export declare class ReferenceWithData extends Reference {
private _data;
static create(ctx: Context, envObject: Env, value: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, data: void_p): ReferenceWithData;
constructor(ctx: Context, envObject: Env, value: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, data: void_p);
data(): void_p;
}
export declare class ReferenceWithFinalizer extends Reference {
private _finalizer;
static create(ctx: Context, envObject: Env, value: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, finalize_callback: napi_finalize, finalize_data: void_p, finalize_hint: void_p): ReferenceWithFinalizer;
constructor(ctx: Context, envObject: Env, value: napi_value, initialRefcount: uint32_t, ownership: ReferenceOwnership, finalize_callback: napi_finalize, finalize_data: void_p, finalize_hint: void_p);
resetFinalizer(): void;
data(): void_p;
protected callUserFinalizer(): void;
protected invokeFinalizerFromGC(): void;
dispose(): void;
}
export declare class RefTracker extends Disposable_2 {
dispose(): void;
finalize(): void;
protected _next: RefTracker | null;
protected _prev: RefTracker | null;
link(list: RefTracker): void;
unlink(): void;
static finalizeAll(list: RefTracker): void;
}
export declare interface Resolver<T> {
promise: Promise<T>;
resolve: (value: T | PromiseLike<T>) => void;
reject: (reason?: any) => void;
}
export declare interface ReusableStoreValue extends Disposable_2 {
reuse(...args: any[]): void;
}
export declare class ScopeStore extends BaseArrayStore<HandleScope> {
private readonly _rootScope;
currentScope: HandleScope;
constructor();
openScope(handleStore: HandleStore): HandleScope;
closeScope(): void;
isEmpty(): boolean;
}
export declare function setInternalField(instance: object, index: number, value: any): void;
export declare function setPrivate(obj: any, key: Private, value: any): void;
export declare class Signature {
receiver: FunctionTemplate | undefined;
constructor(receiver: FunctionTemplate | undefined);
}
export declare class StrongRef<T> extends Disposable_2 {
private _value;
constructor(value: T);
deref(): T;
dispose(): void;
}
export declare class Template {
protected ctx: Isolate;
protected _properties: Map<string | symbol, [any, number]>;
constructor(ctx: Isolate);
set(name: string | symbol, value: any, attr: number): void;
protected _addPropertiesToInstance(instance: any): void;
}
export declare class TrackedFinalizer extends RefTracker {
private _finalizer;
static create(envObject: Env, finalize_callback: napi_finalize, finalize_data: void_p, finalize_hint: void_p): TrackedFinalizer;
private constructor();
data(): void_p;
dispose(): void;
finalize(): void;
}
export declare class TryCatch {
static top: TryCatch | null;
private static _map;
id: number | bigint;
private _exception;
private _caught;
private _next;
constructor(id: number | bigint);
static deref(id: number | bigint): TryCatch | undefined;
static pop(): void;
isEmpty(): boolean;
hasCaught(): boolean;
exception(): any;
rethrow(ctx: Isolate): any;
setError(err: any): void;
reset(): void;
extractException(): any;
}
export declare const version: string;
export { }
+2225
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
+63
View File
@@ -0,0 +1,63 @@
'use strict'
// Mutable CommonJS facade over the ESM build. The v1 package shipped a real
// CJS entry whose exports object was mutable; generated WASI loaders and
// @napi-rs/wasm-runtime's runtime.cjs rely on sharing that one mutable
// exports object (e.g. test harnesses intercept `createContext` around a
// fresh loader require). The v2 package is ESM-only, and `require()` of an
// ES module returns a frozen namespace, so restore the contract here. Each
// export is re-assigned individually (instead of spreading the namespace
// into `module.exports`) so cjs-module-lexer can statically detect the named
// exports -- `import()` of this CJS entry must still expose them as module
// namespace properties. Module-level state (the default-context memoization)
// lives inside the ESM module itself, so both entries observe the same
// runtime state.
const __emnapiRuntime = require('./dist/emnapi.js')
module.exports.ArrayStore = __emnapiRuntime.ArrayStore
module.exports.BaseArrayStore = __emnapiRuntime.BaseArrayStore
module.exports.Context = __emnapiRuntime.Context
module.exports.CountIdAllocator = __emnapiRuntime.CountIdAllocator
module.exports.CountIdReuseAllocator = __emnapiRuntime.CountIdReuseAllocator
module.exports.Disposable = __emnapiRuntime.Disposable
module.exports.EmnapiError = __emnapiRuntime.EmnapiError
module.exports.Env = __emnapiRuntime.Env
module.exports.External = __emnapiRuntime.External
module.exports.Finalizer = __emnapiRuntime.Finalizer
module.exports.FunctionTemplate = __emnapiRuntime.FunctionTemplate
module.exports.HandleScope = __emnapiRuntime.HandleScope
module.exports.HandleStore = __emnapiRuntime.HandleStore
module.exports.Isolate = __emnapiRuntime.Isolate
module.exports.NAPI_VERSION_EXPERIMENTAL = __emnapiRuntime.NAPI_VERSION_EXPERIMENTAL
module.exports.NODE_API_DEFAULT_MODULE_API_VERSION = __emnapiRuntime.NODE_API_DEFAULT_MODULE_API_VERSION
module.exports.NODE_API_SUPPORTED_VERSION_MAX = __emnapiRuntime.NODE_API_SUPPORTED_VERSION_MAX
module.exports.NODE_API_SUPPORTED_VERSION_MIN = __emnapiRuntime.NODE_API_SUPPORTED_VERSION_MIN
module.exports.NodeEnv = __emnapiRuntime.NodeEnv
module.exports.NotSupportBufferError = __emnapiRuntime.NotSupportBufferError
module.exports.NotSupportWeakRefError = __emnapiRuntime.NotSupportWeakRefError
module.exports.ObjectTemplate = __emnapiRuntime.ObjectTemplate
module.exports.Persistent = __emnapiRuntime.Persistent
module.exports.PersistentStore = __emnapiRuntime.PersistentStore
module.exports.Private = __emnapiRuntime.Private
module.exports.RefTracker = __emnapiRuntime.RefTracker
module.exports.Reference = __emnapiRuntime.Reference
module.exports.ReferenceOwnership = __emnapiRuntime.ReferenceOwnership
module.exports.ReferenceWithData = __emnapiRuntime.ReferenceWithData
module.exports.ReferenceWithFinalizer = __emnapiRuntime.ReferenceWithFinalizer
module.exports.ScopeStore = __emnapiRuntime.ScopeStore
module.exports.Signature = __emnapiRuntime.Signature
module.exports.StrongRef = __emnapiRuntime.StrongRef
module.exports.Template = __emnapiRuntime.Template
module.exports.TrackedFinalizer = __emnapiRuntime.TrackedFinalizer
module.exports.TryCatch = __emnapiRuntime.TryCatch
module.exports.createContext = __emnapiRuntime.createContext
module.exports.deletePrivate = __emnapiRuntime.deletePrivate
module.exports.getDefaultContext = __emnapiRuntime.getDefaultContext
module.exports.getDylinkMetadata = __emnapiRuntime.getDylinkMetadata
module.exports.getExternalValue = __emnapiRuntime.getExternalValue
module.exports.getInternalField = __emnapiRuntime.getInternalField
module.exports.getPrivate = __emnapiRuntime.getPrivate
module.exports.hasPrivate = __emnapiRuntime.hasPrivate
module.exports.isExternal = __emnapiRuntime.isExternal
module.exports.isReferenceType = __emnapiRuntime.isReferenceType
module.exports.setInternalField = __emnapiRuntime.setInternalField
module.exports.setPrivate = __emnapiRuntime.setPrivate
module.exports.version = __emnapiRuntime.version
+39
View File
@@ -0,0 +1,39 @@
{
"name": "@emnapi/runtime",
"version": "2.0.0-alpha.3",
"description": "emnapi runtime",
"type": "module",
"main": "./dist/emnapi.js",
"module": "./dist/emnapi.js",
"types": "./dist/emnapi.d.ts",
"sideEffects": false,
"exports": {
".": {
"types": "./dist/emnapi.d.ts",
"import": "./dist/emnapi.js",
"require": "./index.cjs",
"default": "./dist/emnapi.js"
},
"./package.json": "./package.json"
},
"dependencies": {
"tslib": "^2.4.0"
},
"scripts": {
"build": "rollup -c",
"test": "node ./test/index.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/toyobayashi/emnapi.git"
},
"author": "toyobayashi",
"license": "MIT",
"bugs": {
"url": "https://github.com/toyobayashi/emnapi/issues"
},
"homepage": "https://github.com/toyobayashi/emnapi#readme",
"publishConfig": {
"access": "public"
}
}
+25
View File
@@ -0,0 +1,25 @@
import { defineConfig } from '@emnapi/shared'
import fs from 'fs'
import path from 'path'
import { EOL } from 'os'
import pkg from './package.json' with { type: 'json' }
export default defineConfig({
outputName: 'emnapi',
outputFile: 'emnapi',
sourcemap: true,
defines: {
__VERSION__: JSON.stringify(pkg.version)
},
apiExtractorCallback: (result) => {
if (result.succeeded) {
let dts = ''
dts += '/// <reference lib="esnext.disposable" />' + EOL + EOL
dts += fs.readFileSync(path.join(import.meta.dirname, 'src/typings/common.d.ts'), 'utf8').replace(/declare/g, 'export declare')
dts += fs.readFileSync(path.join(import.meta.dirname, 'src/typings/ctype.d.ts'), 'utf8').replace(/declare/g, 'export declare')
dts += fs.readFileSync(path.join(import.meta.dirname, 'src/typings/napi.d.ts'), 'utf8').replace(/declare/g, 'export declare')
dts += fs.readFileSync(result.extractorConfig.publicTrimmedFilePath, 'utf8')
fs.writeFileSync(result.extractorConfig.publicTrimmedFilePath, dts, 'utf8')
}
}
})
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021-present Toyobayashi
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.
+203
View File
@@ -0,0 +1,203 @@
# @emnapi/wasi-threads
This package makes [wasi-threads proposal](https://github.com/WebAssembly/wasi-threads) based WASI modules work in Node.js and browser.
## Quick Start
`index.html`
```html
<script src="./node_modules/@tybys/wasm-util/dist/wasm-util.js"></script>
<script src="./node_modules/@emnapi/wasi-threads/dist/wasi-threads.js"></script>
<script src="./index.js"></script>
```
If your application will block browser main thread (for example `pthread_join`), please run it in worker instead.
```html
<script>
// pthread_join (Atomics.wait) cannot be called in browser main thread
new Worker('./index.js')
</script>
```
`index.js`
```js
const ENVIRONMENT_IS_NODE =
typeof process === 'object' && process !== null &&
typeof process.versions === 'object' && process.versions !== null &&
typeof process.versions.node === 'string';
(function (main) {
if (ENVIRONMENT_IS_NODE) {
main(require)
} else {
if (typeof importScripts === 'function') {
importScripts('./node_modules/@tybys/wasm-util/dist/wasm-util.js')
importScripts('./node_modules/@emnapi/wasi-threads/dist/wasi-threads.js')
}
const nodeWasi = { WASI: globalThis.wasmUtil.WASI }
const nodeWorkerThreads = {
Worker: globalThis.Worker
}
const _require = function (request) {
if (request === 'node:wasi' || request === 'wasi') return nodeWasi
if (request === 'node:worker_threads' || request === 'worker_threads') return nodeWorkerThreads
if (request === '@emnapi/wasi-threads') return globalThis.wasiThreads
throw new Error('Can not find module: ' + request)
}
main(_require)
}
})(async function (require) {
const { WASI } = require('wasi')
const { Worker } = require('worker_threads')
const { WASIThreads } = require('@emnapi/wasi-threads')
const wasi = new WASI({
version: 'preview1'
})
const wasiThreads = new WASIThreads({
wasi,
/**
* avoid Atomics.wait() deadlock during thread creation in browser
* see https://emscripten.org/docs/tools_reference/settings_reference.html#pthread-pool-size
*/
reuseWorker: ENVIRONMENT_IS_NODE
? false
: {
size: 4 /** greater than actual needs (2) */,
strict: true
},
/**
* Synchronous thread creation
* pthread_create will not return until thread worker actually starts
*/
waitThreadStart: typeof window === 'undefined' ? 1000 : false,
onCreateWorker: () => {
return new Worker('./worker.js', {
execArgv: ['--experimental-wasi-unstable-preview1']
})
}
})
const memory = new WebAssembly.Memory({
initial: 16777216 / 65536,
maximum: 2147483648 / 65536,
shared: true
})
let input
const file = 'path/to/your/wasi-module.wasm'
try {
input = require('fs').readFileSync(require('path').join(__dirname, file))
} catch (err) {
const response = await fetch(file)
input = await response.arrayBuffer()
}
let { module, instance } = await WebAssembly.instantiate(input, {
env: { memory },
wasi_snapshot_preview1: wasi.wasiImport,
...wasiThreads.getImportObject()
})
wasiThreads.setup(instance, module, memory)
await wasiThreads.preloadWorkers()
if (typeof instance.exports._start === 'function') {
return wasi.start(instance)
} else {
wasi.initialize(instance)
// instance.exports.exported_wasm_function()
}
})
```
`worker.js`
```js
(function (main) {
const ENVIRONMENT_IS_NODE =
typeof process === 'object' && process !== null &&
typeof process.versions === 'object' && process.versions !== null &&
typeof process.versions.node === 'string'
if (ENVIRONMENT_IS_NODE) {
const _require = function (request) {
return require(request)
}
const _init = function () {
const nodeWorkerThreads = require('worker_threads')
const parentPort = nodeWorkerThreads.parentPort
parentPort.on('message', (data) => {
globalThis.onmessage({ data })
})
Object.assign(globalThis, {
self: globalThis,
require,
Worker: nodeWorkerThreads.Worker,
importScripts: function (f) {
(0, eval)(require('fs').readFileSync(f, 'utf8') + '//# sourceURL=' + f)
},
postMessage: function (msg) {
parentPort.postMessage(msg)
}
})
}
main(_require, _init)
} else {
importScripts('./node_modules/@tybys/wasm-util/dist/wasm-util.js')
importScripts('./node_modules/@emnapi/wasi-threads/dist/wasi-threads.js')
const nodeWasi = { WASI: globalThis.wasmUtil.WASI }
const _require = function (request) {
if (request === '@emnapi/wasi-threads') return globalThis.wasiThreads
if (request === 'node:wasi' || request === 'wasi') return nodeWasi
throw new Error('Can not find module: ' + request)
}
const _init = function () {}
main(_require, _init)
}
})(function main (require, init) {
init()
const { WASI } = require('wasi')
const { ThreadMessageHandler, WASIThreads } = require('@emnapi/wasi-threads')
const handler = new ThreadMessageHandler({
async onLoad ({ wasmModule, wasmMemory }) {
const wasi = new WASI({
version: 'preview1'
})
const wasiThreads = new WASIThreads({
wasi,
childThread: true
})
const originalInstance = await WebAssembly.instantiate(wasmModule, {
env: {
memory: wasmMemory,
},
wasi_snapshot_preview1: wasi.wasiImport,
...wasiThreads.getImportObject()
})
// must call `initialize` instead of `start` in child thread
const instance = wasiThreads.initialize(originalInstance, wasmModule, wasmMemory)
return { module: wasmModule, instance }
}
})
globalThis.onmessage = function (e) {
handler.handle(e)
// handle other messages
}
})
```
+211
View File
@@ -0,0 +1,211 @@
import type { Worker as Worker_2 } from 'worker_threads';
export declare interface BaseOptions {
wasi: WASIInstance;
version?: 'preview1';
wasm64?: boolean;
}
export declare interface ChildThreadOptions extends BaseOptions {
childThread: true;
postMessage?: (data: any) => void;
}
export declare interface CleanupThreadPayload {
tid: number;
}
export declare interface CommandInfo<T extends CommandType> {
type: T;
payload: CommandPayloadMap[T];
}
export declare interface CommandPayloadMap {
load: LoadPayload;
loaded: LoadedPayload;
start: StartPayload;
'cleanup-thread': CleanupThreadPayload;
'terminate-all-threads': TerminateAllThreadsPayload;
'spawn-thread': SpawnThreadPayload;
}
export declare type CommandType = keyof CommandPayloadMap;
export declare function createInstanceProxy(instance: WebAssembly.Instance, memory?: WebAssembly.Memory | (() => WebAssembly.Memory)): WebAssembly.Instance;
export declare function isSharedArrayBuffer(value: any): value is SharedArrayBuffer;
export declare function isTrapError(e: Error): e is WebAssembly.RuntimeError;
export declare interface LoadedPayload {
}
export declare interface LoadPayload {
wasmModule: WebAssembly.Module;
wasmMemory: WebAssembly.Memory;
sab?: Int32Array;
}
export declare interface MainThreadBaseOptions extends BaseOptions {
waitThreadStart?: boolean | number;
}
export declare type MainThreadOptions = MainThreadOptionsWithThreadManager | MainThreadOptionsCreateThreadManager;
export declare interface MainThreadOptionsCreateThreadManager extends MainThreadBaseOptions, ThreadManagerOptionsMain {
}
export declare interface MainThreadOptionsWithThreadManager extends MainThreadBaseOptions {
threadManager?: ThreadManager | (() => ThreadManager);
}
export declare interface MessageEventData<T extends CommandType> {
__emnapi__: CommandInfo<T>;
}
export declare interface ReuseWorkerOptions {
size: number;
strict?: boolean;
}
export declare interface SpawnThreadPayload {
startArg: number;
errorOrTid: number;
}
export declare interface StartPayload {
tid: number;
arg: number;
sab?: Int32Array;
}
export declare interface StartResult {
exitCode: number;
instance: WebAssembly.Instance;
}
export declare interface TerminateAllThreadsPayload {
}
export declare class ThreadManager {
unusedWorkers: WorkerLike[];
pthreads: Record<number, WorkerLike>;
get nextWorkerID(): number;
wasmModule: WebAssembly.Module | null;
wasmMemory: WebAssembly.Memory | null;
private readonly messageEvents;
private readonly _childThread;
private readonly _onCreateWorker;
private readonly _reuseWorker;
private readonly _beforeLoad?;
readonly printErr: (message: string) => void;
threadSpawn?: ((startArg: number, errorOrTid?: number) => number);
constructor(options: ThreadManagerOptions);
init(): void;
initMainThread(): void;
private preparePool;
shouldPreloadWorkers(): boolean;
loadWasmModuleToAllWorkers(): Promise<WorkerLike[]>;
preloadWorkers(): Promise<WorkerLike[]>;
setup(wasmModule: WebAssembly.Module, wasmMemory: WebAssembly.Memory): void;
markId(worker: WorkerLike): number;
returnWorkerToPool(worker: WorkerLike): void;
loadWasmModuleToWorker(worker: WorkerLike, sab?: Int32Array): Promise<WorkerLike>;
allocateUnusedWorker(): WorkerLike;
getNewWorker(sab?: Int32Array): WorkerLike | undefined;
cleanThread(worker: WorkerLike, tid: number, force?: boolean): void;
terminateWorker(worker: WorkerLike): void;
terminateAllThreads(): void;
addMessageEventListener(worker: WorkerLike, onMessage: (e: WorkerMessageEvent) => void): () => void;
fireMessageEvent(worker: WorkerLike, e: WorkerMessageEvent): void;
}
export declare type ThreadManagerOptions = ThreadManagerOptionsMain | ThreadManagerOptionsChild;
export declare interface ThreadManagerOptionsBase {
printErr?: (message: string) => void;
threadSpawn?: (startArg: number, errorOrTid?: number) => number;
}
export declare interface ThreadManagerOptionsChild extends ThreadManagerOptionsBase {
childThread: true;
}
export declare interface ThreadManagerOptionsMain extends ThreadManagerOptionsBase {
beforeLoad?: (worker: WorkerLike) => any;
reuseWorker?: boolean | number | ReuseWorkerOptions;
onCreateWorker: WorkerFactory;
childThread?: false;
}
export declare class ThreadMessageHandler {
protected instance: WebAssembly.Instance | undefined;
private messagesBeforeLoad;
protected postMessage: (message: any) => void;
protected onLoad?: (data: LoadPayload) => WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
protected onError: (error: Error, type: WorkerMessageType) => void;
constructor(options?: ThreadMessageHandlerOptions);
instantiate(data: LoadPayload): WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
handle(e: WorkerMessageEvent<MessageEventData<WorkerMessageType>>): void;
private _load;
private _start;
protected _loaded(err: Error | null, source: WebAssembly.WebAssemblyInstantiatedSource | null, payload: LoadPayload): void;
protected handleAfterLoad<E extends WorkerMessageEvent>(e: E, f: (e: E) => void): void;
}
export declare interface ThreadMessageHandlerOptions {
onLoad?: (data: LoadPayload) => WebAssembly.WebAssemblyInstantiatedSource | PromiseLike<WebAssembly.WebAssemblyInstantiatedSource>;
onError?: (error: Error, type: WorkerMessageType) => void;
postMessage?: (message: any) => void;
}
export declare interface WASIInstance {
readonly wasiImport?: Record<string, any>;
initialize(instance: object): void;
start(instance: object): number;
getImportObject?(): any;
}
export declare class WASIThreads {
PThread: ThreadManager | undefined;
private wasmMemory;
private wasmInstance;
private readonly threadSpawn;
readonly childThread: boolean;
private readonly postMessage;
readonly wasi: WASIInstance;
constructor(options: WASIThreadsOptions);
getImportObject(): {
wasi: WASIThreadsImports;
};
setup(wasmInstance: WebAssembly.Instance, wasmModule: WebAssembly.Module, wasmMemory?: WebAssembly.Memory): void;
preloadWorkers(): Promise<WorkerLike[]>;
initialize(instance: WebAssembly.Instance, module: WebAssembly.Module, memory?: WebAssembly.Memory): WebAssembly.Instance;
start(instance: WebAssembly.Instance, module: WebAssembly.Module, memory?: WebAssembly.Memory): StartResult;
terminateAllThreads(): void;
}
export declare interface WASIThreadsImports {
'thread-spawn': (startArg: number, errorOrTid?: number) => number;
}
export declare type WASIThreadsOptions = MainThreadOptions | ChildThreadOptions;
export declare type WorkerFactory = (ctx: {
type: string;
name: string;
}) => WorkerLike;
export declare type WorkerLike = (Worker | Worker_2) & {
whenLoaded?: Promise<WorkerLike>;
loaded?: boolean;
__emnapi_tid?: number;
};
export declare interface WorkerMessageEvent<T = any> {
data: T;
}
export declare type WorkerMessageType = 'load' | 'start';
export { }
+918
View File
@@ -0,0 +1,918 @@
//#region src/util.ts
const _WebAssembly = typeof WebAssembly !== 'undefined'
? WebAssembly
: typeof WXWebAssembly !== 'undefined'
? WXWebAssembly
: undefined;
const ENVIRONMENT_IS_NODE = typeof process === 'object' && process !== null &&
typeof process.versions === 'object' && process.versions !== null &&
typeof process.versions.node === 'string';
function getPostMessage(options) {
return typeof options?.postMessage === 'function'
? options.postMessage
: typeof postMessage === 'function'
? postMessage
: undefined;
}
function serizeErrorToBuffer(sab, code, error) {
const i32array = new Int32Array(sab);
Atomics.store(i32array, 0, code);
if (code > 1 && error) {
const name = error.name;
const message = error.message;
const stack = error.stack;
const nameBuffer = new TextEncoder().encode(name);
const messageBuffer = new TextEncoder().encode(message);
const stackBuffer = new TextEncoder().encode(stack);
Atomics.store(i32array, 1, nameBuffer.length);
Atomics.store(i32array, 2, messageBuffer.length);
Atomics.store(i32array, 3, stackBuffer.length);
const buffer = new Uint8Array(sab);
buffer.set(nameBuffer, 16);
buffer.set(messageBuffer, 16 + nameBuffer.length);
buffer.set(stackBuffer, 16 + nameBuffer.length + messageBuffer.length);
}
}
function deserizeErrorFromBuffer(sab) {
const i32array = new Int32Array(sab);
const status = Atomics.load(i32array, 0);
if (status <= 1) {
return null;
}
const nameLength = Atomics.load(i32array, 1);
const messageLength = Atomics.load(i32array, 2);
const stackLength = Atomics.load(i32array, 3);
const buffer = new Uint8Array(sab);
const nameBuffer = buffer.slice(16, 16 + nameLength);
const messageBuffer = buffer.slice(16 + nameLength, 16 + nameLength + messageLength);
const stackBuffer = buffer.slice(16 + nameLength + messageLength, 16 + nameLength + messageLength + stackLength);
const name = new TextDecoder().decode(nameBuffer);
const message = new TextDecoder().decode(messageBuffer);
const stack = new TextDecoder().decode(stackBuffer);
const ErrorConstructor = globalThis[name] ?? (name === 'RuntimeError' ? (_WebAssembly.RuntimeError ?? Error) : Error);
const error = new ErrorConstructor(message);
Object.defineProperty(error, 'stack', {
value: stack,
writable: true,
enumerable: false,
configurable: true
});
return error;
}
function isSharedArrayBuffer(value) {
return ((typeof SharedArrayBuffer === 'function' && value instanceof SharedArrayBuffer) ||
(Object.prototype.toString.call(value) === '[object SharedArrayBuffer]'));
}
function isTrapError(e) {
try {
return e instanceof _WebAssembly.RuntimeError;
}
catch (_) {
return false;
}
}
//#endregion src/util.ts
//#region src/command.ts
function createMessage(type, payload) {
return {
__emnapi__: {
type,
payload
}
};
}
//#endregion src/command.ts
//#region src/thread-manager.ts
const WASI_THREADS_MAX_TID = 0x1FFFFFFF;
function checkSharedWasmMemory(wasmMemory) {
if (wasmMemory) {
if (!isSharedArrayBuffer(wasmMemory.buffer)) {
throw new Error('Multithread features require shared wasm memory. ' +
'Try to compile with `-matomics -mbulk-memory` and use `--import-memory --shared-memory` during linking, ' +
'then create WebAssembly.Memory with `shared: true` option');
}
}
else {
if (typeof SharedArrayBuffer === 'undefined') {
throw new Error('Current environment does not support SharedArrayBuffer, threads are not available!');
}
}
}
function getReuseWorker(value) {
if (typeof value === 'boolean') {
return value ? { size: 0, strict: false } : false;
}
if (typeof value === 'number') {
if (!(value >= 0)) {
throw new RangeError('reuseWorker: size must be a non-negative integer');
}
return { size: value, strict: false };
}
if (!value) {
return false;
}
const size = Number(value.size) || 0;
const strict = Boolean(value.strict);
if (!(size > 0) && strict) {
throw new RangeError('reuseWorker: size must be set to positive integer if strict is set to true');
}
return { size, strict };
}
let nextWorkerID = 0;
class ThreadManager {
get nextWorkerID() { return nextWorkerID; }
constructor(options) {
this.unusedWorkers = [];
this.pthreads = Object.create(null);
this.wasmModule = null;
this.wasmMemory = null;
this.messageEvents = new WeakMap();
if (!options) {
throw new TypeError('ThreadManager(): options is not provided');
}
if ('childThread' in options) {
this._childThread = Boolean(options.childThread);
}
else {
this._childThread = false;
}
if (this._childThread) {
this._onCreateWorker = undefined;
this._reuseWorker = false;
this._beforeLoad = undefined;
}
else {
this._onCreateWorker = options.onCreateWorker;
this._reuseWorker = getReuseWorker(options.reuseWorker);
this._beforeLoad = options.beforeLoad;
}
this.printErr = options.printErr ?? console.error.bind(console);
this.threadSpawn = options.threadSpawn;
}
init() {
if (!this._childThread) {
this.initMainThread();
}
}
initMainThread() {
this.preparePool();
}
preparePool() {
if (this._reuseWorker) {
if (this._reuseWorker.size) {
let pthreadPoolSize = this._reuseWorker.size;
while (pthreadPoolSize--) {
const worker = this.allocateUnusedWorker();
if (ENVIRONMENT_IS_NODE) {
worker.once('message', () => { });
worker.unref();
}
}
}
}
}
shouldPreloadWorkers() {
return !this._childThread && this._reuseWorker && this._reuseWorker.size > 0;
}
loadWasmModuleToAllWorkers() {
const promises = Array(this.unusedWorkers.length);
for (let i = 0; i < this.unusedWorkers.length; ++i) {
const worker = this.unusedWorkers[i];
if (ENVIRONMENT_IS_NODE)
worker.ref();
promises[i] = this.loadWasmModuleToWorker(worker).then((w) => {
if (ENVIRONMENT_IS_NODE)
worker.unref();
return w;
}, (e) => {
if (ENVIRONMENT_IS_NODE)
worker.unref();
throw e;
});
}
return Promise.all(promises).catch((err) => {
this.terminateAllThreads();
throw err;
});
}
preloadWorkers() {
if (this.shouldPreloadWorkers()) {
return this.loadWasmModuleToAllWorkers();
}
return Promise.resolve([]);
}
setup(wasmModule, wasmMemory) {
this.wasmModule = wasmModule;
this.wasmMemory = wasmMemory;
}
markId(worker) {
if (worker.__emnapi_tid)
return worker.__emnapi_tid;
const tid = nextWorkerID + 43;
nextWorkerID = (nextWorkerID + 1) % (WASI_THREADS_MAX_TID - 42);
this.pthreads[tid] = worker;
worker.__emnapi_tid = tid;
return tid;
}
returnWorkerToPool(worker) {
var tid = worker.__emnapi_tid;
if (tid !== undefined) {
delete this.pthreads[tid];
}
this.unusedWorkers.push(worker);
delete worker.__emnapi_tid;
if (ENVIRONMENT_IS_NODE) {
worker.unref();
}
}
loadWasmModuleToWorker(worker, sab) {
if (worker.whenLoaded)
return worker.whenLoaded;
const err = this.printErr;
const beforeLoad = this._beforeLoad;
const _this = this;
worker.whenLoaded = new Promise((resolve, reject) => {
const handleError = function (e) {
let message = 'worker sent an error!';
if (worker.__emnapi_tid !== undefined) {
message = 'worker (tid = ' + worker.__emnapi_tid + ') sent an error!';
}
if ('message' in e) {
err(message + ' ' + e.message);
if (e.message.indexOf('RuntimeError') !== -1 || e.message.indexOf('unreachable') !== -1) {
try {
_this.terminateAllThreads();
}
catch (_) { }
}
}
else {
err(message);
}
reject(e);
throw e;
};
const handleMessage = (data) => {
if (data.__emnapi__) {
const type = data.__emnapi__.type;
const payload = data.__emnapi__.payload;
if (type === 'loaded') {
worker.loaded = true;
if (ENVIRONMENT_IS_NODE && !worker.__emnapi_tid) {
worker.unref();
}
resolve(worker);
}
else if (type === 'cleanup-thread') {
if (payload.tid in this.pthreads) {
this.cleanThread(worker, payload.tid);
}
}
else if (type === 'spawn-thread') {
this.threadSpawn(payload.startArg, payload.errorOrTid);
}
else if (type === 'terminate-all-threads') {
this.terminateAllThreads();
}
}
};
worker.onmessage = (e) => {
handleMessage(e.data);
this.fireMessageEvent(worker, e);
};
worker.onerror = handleError;
if (ENVIRONMENT_IS_NODE) {
worker.on('message', function (data) {
worker.onmessage?.({
data
});
});
worker.on('error', function (e) {
worker.onerror?.(e);
});
worker.on('detachedExit', function () { });
}
if (typeof beforeLoad === 'function') {
beforeLoad(worker);
}
try {
worker.postMessage(createMessage('load', {
wasmModule: this.wasmModule,
wasmMemory: this.wasmMemory,
sab
}));
}
catch (err) {
checkSharedWasmMemory(this.wasmMemory);
throw err;
}
});
return worker.whenLoaded;
}
allocateUnusedWorker() {
const _onCreateWorker = this._onCreateWorker;
if (typeof _onCreateWorker !== 'function') {
throw new TypeError('`options.onCreateWorker` is not provided');
}
const worker = _onCreateWorker({ type: 'thread', name: 'emnapi-pthread' });
this.unusedWorkers.push(worker);
return worker;
}
getNewWorker(sab) {
if (this._reuseWorker) {
if (this.unusedWorkers.length === 0) {
if (this._reuseWorker.strict) {
if (!ENVIRONMENT_IS_NODE) {
const err = this.printErr;
err('Tried to spawn a new thread, but the thread pool is exhausted.\n' +
'This might result in a deadlock unless some threads eventually exit or the code explicitly breaks out to the event loop.');
return;
}
}
const worker = this.allocateUnusedWorker();
this.loadWasmModuleToWorker(worker, sab);
}
return this.unusedWorkers.pop();
}
const worker = this.allocateUnusedWorker();
this.loadWasmModuleToWorker(worker, sab);
return this.unusedWorkers.pop();
}
cleanThread(worker, tid, force) {
if (!force && this._reuseWorker) {
this.returnWorkerToPool(worker);
}
else {
delete this.pthreads[tid];
this.terminateWorker(worker);
delete worker.__emnapi_tid;
}
}
terminateWorker(worker) {
const tid = worker.__emnapi_tid;
worker.terminate();
this.messageEvents.get(worker)?.clear();
this.messageEvents.delete(worker);
worker.onmessage = (e) => {
if (e.data.__emnapi__) {
const err = this.printErr;
err('received "' + e.data.__emnapi__.type + '" command from terminated worker: ' + tid);
}
};
}
terminateAllThreads() {
const runningWorkers = Object.values(this.pthreads);
for (let i = 0; i < runningWorkers.length; ++i) {
this.terminateWorker(runningWorkers[i]);
}
for (let i = 0; i < this.unusedWorkers.length; ++i) {
this.terminateWorker(this.unusedWorkers[i]);
}
this.unusedWorkers = [];
this.pthreads = Object.create(null);
this.preparePool();
}
addMessageEventListener(worker, onMessage) {
let listeners = this.messageEvents.get(worker);
if (!listeners) {
listeners = new Set();
this.messageEvents.set(worker, listeners);
}
listeners.add(onMessage);
return () => {
listeners?.delete(onMessage);
};
}
fireMessageEvent(worker, e) {
const listeners = this.messageEvents.get(worker);
if (!listeners)
return;
const err = this.printErr;
listeners.forEach((listener) => {
try {
listener(e);
}
catch (e) {
err(e.stack);
}
});
}
}
//#endregion src/thread-manager.ts
//#region src/proxy.ts
const kIsProxy = Symbol('kIsProxy');
function createInstanceProxy(instance, memory) {
if (instance[kIsProxy])
return instance;
const originalExports = instance.exports;
const createHandler = function (target) {
const handlers = [
'apply',
'construct',
'defineProperty',
'deleteProperty',
'get',
'getOwnPropertyDescriptor',
'getPrototypeOf',
'has',
'isExtensible',
'ownKeys',
'preventExtensions',
'set',
'setPrototypeOf'
];
const handler = {};
for (let i = 0; i < handlers.length; i++) {
const name = handlers[i];
handler[name] = function () {
const args = Array.prototype.slice.call(arguments, 1);
args.unshift(target);
return Reflect[name].apply(Reflect, args);
};
}
return handler;
};
const handler = createHandler(originalExports);
const _initialize = () => { };
const _start = () => 0;
handler.get = function (_target, p, receiver) {
if (p === 'memory') {
return (typeof memory === 'function' ? memory() : memory) ?? Reflect.get(originalExports, p, receiver);
}
if (p === '_initialize') {
return p in originalExports ? _initialize : undefined;
}
if (p === '_start') {
return p in originalExports ? _start : undefined;
}
return Reflect.get(originalExports, p, receiver);
};
handler.has = function (_target, p) {
if (p === 'memory')
return true;
return Reflect.has(originalExports, p);
};
const exportsProxy = new Proxy(Object.create(null), handler);
return new Proxy(instance, {
get(target, p, receiver) {
if (p === 'exports') {
return exportsProxy;
}
if (p === kIsProxy) {
return true;
}
return Reflect.get(target, p, receiver);
}
});
}
//#endregion src/proxy.ts
//#region src/wasi-threads.ts
const patchedWasiInstances = new WeakMap();
const THREAD_SPAWN_RESULT_SIZE = Int32Array.BYTES_PER_ELEMENT * 2;
const sharedArrayBufferByteLength = typeof SharedArrayBuffer === 'function'
? Object.getOwnPropertyDescriptor(SharedArrayBuffer.prototype, 'byteLength').get
: undefined;
function isConclusivelySharedArrayBuffer(buffer) {
if (sharedArrayBufferByteLength === undefined)
return false;
try {
sharedArrayBufferByteLength.call(buffer);
return true;
}
catch (_) {
return false;
}
}
function getThreadSpawnResultView(memory, address, wasm64) {
const offset = typeof address === 'bigint' ? Number(address) : address >>> 0;
let buffer = memory.buffer;
if (offset + THREAD_SPAWN_RESULT_SIZE > buffer.byteLength &&
isConclusivelySharedArrayBuffer(buffer)) {
if (wasm64) {
memory.grow(BigInt(0));
}
else {
memory.grow(0);
}
buffer = memory.buffer;
}
return new Int32Array(buffer, offset, 2);
}
class WASIThreads {
constructor(options) {
if (!options) {
throw new TypeError('WASIThreads(): options is not provided');
}
if (!options.wasi) {
throw new TypeError('WASIThreads(): options.wasi is not provided');
}
patchedWasiInstances.set(this, new WeakSet());
const wasi = options.wasi;
patchWasiInstance(this, wasi);
this.wasi = wasi;
if ('childThread' in options) {
this.childThread = Boolean(options.childThread);
}
else {
this.childThread = false;
}
this.PThread = undefined;
if ('threadManager' in options) {
if (typeof options.threadManager === 'function') {
this.PThread = options.threadManager();
}
else {
this.PThread = options.threadManager;
}
}
else {
if (!this.childThread) {
this.PThread = new ThreadManager(options);
this.PThread.init();
}
}
let waitThreadStart = false;
if ('waitThreadStart' in options) {
waitThreadStart = typeof options.waitThreadStart === 'number' ? options.waitThreadStart : Boolean(options.waitThreadStart);
}
const postMessage = getPostMessage(options);
if (this.childThread && typeof postMessage !== 'function') {
throw new TypeError('options.postMessage is not a function');
}
this.postMessage = postMessage;
const wasm64 = Boolean(options.wasm64);
const threadSpawn = (startArg, errorOrTid) => {
const EAGAIN = 6;
const isNewABI = errorOrTid !== undefined;
try {
checkSharedWasmMemory(this.wasmMemory);
}
catch (err) {
this.PThread?.printErr(err.stack);
if (isNewABI) {
const struct = getThreadSpawnResultView(this.wasmMemory, errorOrTid, wasm64);
Atomics.store(struct, 0, 1);
Atomics.store(struct, 1, EAGAIN);
Atomics.notify(struct, 1);
return 1;
}
else {
return -EAGAIN;
}
}
if (!isNewABI) {
const malloc = this.wasmInstance.exports.malloc;
errorOrTid = wasm64 ? Number(malloc(BigInt(8))) : (malloc(8) >>> 0);
if (!errorOrTid) {
return -48;
}
}
const _free = this.wasmInstance.exports.free;
const free = wasm64 ? (ptr) => { _free(BigInt(ptr)); } : _free;
const struct = getThreadSpawnResultView(this.wasmMemory, errorOrTid, wasm64);
Atomics.store(struct, 0, 0);
Atomics.store(struct, 1, 0);
if (this.childThread) {
postMessage(createMessage('spawn-thread', {
startArg,
errorOrTid: errorOrTid
}));
Atomics.wait(struct, 1, 0);
const isError = Atomics.load(struct, 0);
const result = Atomics.load(struct, 1);
if (isNewABI) {
return isError;
}
free(errorOrTid);
return isError ? -result : result;
}
const shouldWait = waitThreadStart || (waitThreadStart === 0);
let sab;
if (shouldWait) {
sab = new Int32Array(new SharedArrayBuffer(16 + 8192));
Atomics.store(sab, 0, 0);
}
let worker;
let tid;
const PThread = this.PThread;
try {
worker = PThread.getNewWorker(sab);
if (!worker) {
throw new Error('failed to get new worker');
}
tid = PThread.markId(worker);
if (ENVIRONMENT_IS_NODE) {
worker.unref();
}
worker.postMessage(createMessage('start', {
tid,
arg: startArg,
sab
}));
if (shouldWait) {
if (typeof waitThreadStart === 'number') {
const waitResult = Atomics.wait(sab, 0, 0, waitThreadStart);
if (waitResult === 'timed-out') {
throw new Error('Spawning thread timed out. Please check if the worker is created successfully and if message is handled properly in the worker.');
}
}
else {
Atomics.wait(sab, 0, 0);
}
const r = Atomics.load(sab, 0);
if (r > 1) {
throw deserizeErrorFromBuffer(sab.buffer);
}
}
}
catch (e) {
if (worker !== undefined && tid !== undefined) {
try {
PThread.cleanThread(worker, tid, true);
}
catch (_) { }
}
Atomics.store(struct, 0, 1);
Atomics.store(struct, 1, EAGAIN);
Atomics.notify(struct, 1);
PThread?.printErr(e.stack);
if (isNewABI) {
return 1;
}
free(errorOrTid);
return -EAGAIN;
}
Atomics.store(struct, 0, 0);
Atomics.store(struct, 1, tid);
Atomics.notify(struct, 1);
if (!shouldWait) {
worker.whenLoaded.catch((err) => {
delete worker.whenLoaded;
PThread.cleanThread(worker, tid, true);
throw err;
});
}
if (isNewABI) {
return 0;
}
free(errorOrTid);
return tid;
};
this.threadSpawn = threadSpawn;
if (this.PThread) {
this.PThread.threadSpawn = threadSpawn;
}
}
getImportObject() {
return {
wasi: {
'thread-spawn': this.threadSpawn
}
};
}
setup(wasmInstance, wasmModule, wasmMemory) {
wasmMemory ??= wasmInstance.exports.memory;
this.wasmInstance = wasmInstance;
this.wasmMemory = wasmMemory;
if (this.PThread) {
this.PThread.setup(wasmModule, wasmMemory);
}
}
preloadWorkers() {
if (this.PThread) {
return this.PThread.preloadWorkers();
}
return Promise.resolve([]);
}
initialize(instance, module, memory) {
const exports = instance.exports;
memory ??= exports.memory;
if (this.childThread) {
instance = createInstanceProxy(instance, memory);
}
this.setup(instance, module, memory);
const wasi = this.wasi;
if (('_start' in exports) && (typeof exports._start === 'function')) {
if (this.childThread) {
wasi.start(instance);
try {
const kStarted = getWasiSymbol(wasi, 'kStarted');
wasi[kStarted] = false;
}
catch (_) { }
}
else {
setupInstance(wasi, instance);
}
}
else {
wasi.initialize(instance);
}
return instance;
}
start(instance, module, memory) {
const exports = instance.exports;
memory ??= exports.memory;
if (this.childThread) {
instance = createInstanceProxy(instance, memory);
}
this.setup(instance, module, memory);
const exitCode = this.wasi.start(instance);
return { exitCode, instance };
}
terminateAllThreads() {
if (!this.childThread) {
this.PThread?.terminateAllThreads();
}
else {
this.postMessage(createMessage('terminate-all-threads', {}));
}
}
}
function patchWasiInstance(wasiThreads, wasi) {
const patched = patchedWasiInstances.get(wasiThreads);
if (patched.has(wasi)) {
return;
}
const _this = wasiThreads;
const wasiImport = wasi.wasiImport;
if (wasiImport) {
const proc_exit = wasiImport.proc_exit;
wasiImport.proc_exit = function (code) {
_this.terminateAllThreads();
return proc_exit.call(this, code);
};
}
if (!_this.childThread) {
const start = wasi.start;
if (typeof start === 'function') {
wasi.start = function (instance) {
try {
return start.call(this, instance);
}
catch (err) {
if (isTrapError(err)) {
_this.terminateAllThreads();
}
throw err;
}
};
}
}
patched.add(wasi);
}
function getWasiSymbol(wasi, description) {
const symbols = Object.getOwnPropertySymbols(wasi);
const selectDescription = (description) => (s) => {
if (s.description) {
return s.description === description;
}
return s.toString() === `Symbol(${description})`;
};
if (Array.isArray(description)) {
return description.map(d => symbols.filter(selectDescription(d))[0]);
}
return symbols.filter(selectDescription(description))[0];
}
function setupInstance(wasi, instance) {
const [kInstance, kSetMemory] = getWasiSymbol(wasi, ['kInstance', 'kSetMemory']);
wasi[kInstance] = instance;
wasi[kSetMemory](instance.exports.memory);
}
//#endregion src/wasi-threads.ts
//#region src/worker.ts
class ThreadMessageHandler {
constructor(options) {
const postMsg = getPostMessage(options);
if (typeof postMsg !== 'function') {
throw new TypeError('options.postMessage is not a function');
}
this.postMessage = postMsg;
this.onLoad = options?.onLoad;
this.onError = typeof options?.onError === 'function' ? options.onError : (_type, err) => { throw err; };
this.instance = undefined;
this.messagesBeforeLoad = [];
}
instantiate(data) {
if (typeof this.onLoad === 'function') {
return this.onLoad(data);
}
throw new Error('ThreadMessageHandler.prototype.instantiate is not implemented');
}
handle(e) {
if (e?.data?.__emnapi__) {
const type = e.data.__emnapi__.type;
const payload = e.data.__emnapi__.payload;
try {
if (type === 'load') {
this._load(payload);
}
else if (type === 'start') {
this.handleAfterLoad(e, () => {
this._start(payload);
});
}
}
catch (err) {
this.onError(err, type);
}
}
}
_load(payload) {
if (this.instance !== undefined)
return;
let source;
try {
source = this.instantiate(payload);
}
catch (err) {
this._loaded(err, null, payload);
return;
}
const then = source && 'then' in source ? source.then : undefined;
if (typeof then === 'function') {
then.call(source, (source) => { this._loaded(null, source, payload); }, (err) => { this._loaded(err, null, payload); });
}
else {
this._loaded(null, source, payload);
}
}
_start(payload) {
const wasi_thread_start = this.instance.exports.wasi_thread_start;
if (typeof wasi_thread_start !== 'function') {
const err = new TypeError('wasi_thread_start is not exported');
notifyPthreadCreateResult(payload.sab, 2, err);
throw err;
}
const postMessage = this.postMessage;
const tid = payload.tid;
const startArg = payload.arg;
notifyPthreadCreateResult(payload.sab, 1);
try {
wasi_thread_start(tid, startArg);
}
catch (err) {
if (err !== 'unwind') {
throw err;
}
else {
return;
}
}
postMessage(createMessage('cleanup-thread', { tid }));
}
_loaded(err, source, payload) {
if (err) {
notifyPthreadCreateResult(payload.sab, 2, err);
throw err;
}
if (source == null) {
const err = new TypeError('onLoad should return an object');
notifyPthreadCreateResult(payload.sab, 2, err);
throw err;
}
const instance = source.instance;
if (!instance) {
const err = new TypeError('onLoad should return an object which includes "instance"');
notifyPthreadCreateResult(payload.sab, 2, err);
throw err;
}
this.instance = instance;
const postMessage = this.postMessage;
postMessage(createMessage('loaded', {}));
const messages = this.messagesBeforeLoad;
this.messagesBeforeLoad = [];
for (let i = 0; i < messages.length; i++) {
const data = messages[i];
this.handle({ data });
}
}
handleAfterLoad(e, f) {
if (this.instance !== undefined) {
f.call(this, e);
}
else {
this.messagesBeforeLoad.push(e.data);
}
}
}
function notifyPthreadCreateResult(sab, result, error) {
if (sab) {
serizeErrorToBuffer(sab.buffer, result, error);
Atomics.notify(sab, 0);
}
}
//#endregion src/worker.ts
export { ThreadManager, ThreadMessageHandler, WASIThreads, createInstanceProxy, isSharedArrayBuffer, isTrapError };
+35
View File
@@ -0,0 +1,35 @@
{
"name": "@emnapi/wasi-threads",
"version": "2.0.1",
"description": "WASI threads proposal implementation in JavaScript",
"type": "module",
"main": "./dist/wasi-threads.js",
"module": "./dist/wasi-threads.js",
"types": "./dist/wasi-threads.d.ts",
"sideEffects": false,
"exports": {
".": "./dist/wasi-threads.js",
"./package.json": "./package.json"
},
"dependencies": {
"tslib": "^2.4.0"
},
"scripts": {
"build": "rollup -c",
"build:test": "node ./test/build.js",
"test": "node ./test/index.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/toyobayashi/emnapi.git"
},
"author": "toyobayashi",
"license": "MIT",
"bugs": {
"url": "https://github.com/toyobayashi/emnapi/issues"
},
"homepage": "https://github.com/toyobayashi/emnapi#readme",
"publishConfig": {
"access": "public"
}
}
+6
View File
@@ -0,0 +1,6 @@
import { defineConfig } from '@emnapi/shared'
export default defineConfig({
outputName: 'wasiThreads',
outputFile: 'wasi-threads'
})
+3
View File
@@ -0,0 +1,3 @@
# esbuild
This is the Windows 64-bit binary for esbuild, a JavaScript bundler and minifier. See https://github.com/evanw/esbuild for details.
Generated Vendored Executable
BIN
View File
Binary file not shown.
+20
View File
@@ -0,0 +1,20 @@
{
"name": "@esbuild/win32-x64",
"version": "0.28.1",
"description": "The Windows 64-bit binary for esbuild, a JavaScript bundler.",
"repository": {
"type": "git",
"url": "git+https://github.com/evanw/esbuild.git"
},
"license": "MIT",
"preferUnplugged": true,
"engines": {
"node": ">=18"
},
"os": [
"win32"
],
"cpu": [
"x64"
]
}
+201
View File
@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright {yyyy} {name of copyright owner}
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
+84
View File
@@ -0,0 +1,84 @@
# Pure JavaScript gRPC Client
## Installation
Node 12 is recommended. The exact set of compatible Node versions can be found in the `engines` field of the `package.json` file.
```sh
npm install @grpc/grpc-js
```
## Documentation
Documentation specifically for the `@grpc/grpc-js` package is currently not available. However, [documentation is available for the `grpc` package](https://grpc.github.io/grpc/node/grpc.html), and the two packages contain mostly the same interface. There are a few notable differences, however, and these differences are noted in the "Migrating from grpc" section below.
## Features
- Clients
- Automatic reconnection
- Servers
- Streaming
- Metadata
- Partial compression support: clients can compress and decompress messages, and servers can decompress request messages
- Pick first and round robin load balancing policies
- Client Interceptors
- Connection Keepalives
- HTTP Connect support (proxies)
If you need a feature from the `grpc` package that is not provided by the `@grpc/grpc-js`, please file a feature request with that information.
This library does not directly handle `.proto` files. To use `.proto` files with this library we recommend using the `@grpc/proto-loader` package.
## Migrating from [`grpc`](https://www.npmjs.com/package/grpc)
`@grpc/grpc-js` is almost a drop-in replacement for `grpc`, but you may need to make a few code changes to use it:
- If you are currently loading `.proto` files using `grpc.load`, that function is not available in this library. You should instead load your `.proto` files using `@grpc/proto-loader` and load the resulting package definition objects into `@grpc/grpc-js` using `grpc.loadPackageDefinition`.
- If you are currently loading packages generated by `grpc-tools`, you should instead generate your files using the `generate_package_definition` option in `grpc-tools`, then load the object exported by the generated file into `@grpc/grpc-js` using `grpc.loadPackageDefinition`.
- If you have a server and you are using `Server#bind` to bind ports, you will need to use `Server#bindAsync` instead.
- If you are using any channel options supported in `grpc` but not supported in `@grpc/grpc-js`, you may need to adjust your code to handle the different behavior. Refer to [the list of supported options](#supported-channel-options) below.
- Refer to the [detailed package comparison](https://github.com/grpc/grpc-node/blob/master/PACKAGE-COMPARISON.md) for more details on the differences between `grpc` and `@grpc/grpc-js`.
## Supported Channel Options
Many channel arguments supported in `grpc` are not supported in `@grpc/grpc-js`. The channel arguments supported by `@grpc/grpc-js` are:
- `grpc.ssl_target_name_override`
- `grpc.primary_user_agent`
- `grpc.secondary_user_agent`
- `grpc.default_authority`
- `grpc.keepalive_time_ms`
- `grpc.keepalive_timeout_ms`
- `grpc.keepalive_permit_without_calls`
- `grpc.service_config`
- `grpc.max_concurrent_streams`
- `grpc.initial_reconnect_backoff_ms`
- `grpc.max_reconnect_backoff_ms`
- `grpc.use_local_subchannel_pool`
- `grpc.max_send_message_length`
- `grpc.max_receive_message_length`
- `grpc.enable_http_proxy`
- `grpc.default_compression_algorithm`
- `grpc.enable_channelz`
- `grpc.dns_min_time_between_resolutions_ms`
- `grpc.enable_retries`
- `grpc.max_connection_age_ms`
- `grpc.max_connection_age_grace_ms`
- `grpc.max_connection_idle_ms`
- `grpc.per_rpc_retry_buffer_size`
- `grpc.retry_buffer_size`
- `grpc.service_config_disable_resolution`
- `grpc.client_idle_timeout_ms`
- `grpc-node.max_session_memory`
- `grpc-node.tls_enable_trace`
- `grpc-node.retry_max_attempts_limit`
- `grpc-node.flow_control_window`
- `channelOverride`
- `channelFactoryOverride`
## Some Notes on API Guarantees
The public API of this library follows semantic versioning, with some caveats:
- Some methods are prefixed with an underscore. These methods are internal and should not be considered part of the public API.
- The class `Call` is only exposed due to limitations of TypeScript. It should not be considered part of the public API.
- In general, any API that is exposed by this library but is not exposed by the `grpc` library is likely an error and should not be considered part of the public API.
- The `grpc.experimental` namespace contains APIs that have not stabilized. Any API in that namespace may break in any minor version update.
+11
View File
@@ -0,0 +1,11 @@
import { ServiceDefinition } from './make-client';
import { Server, UntypedServiceImplementation } from './server';
interface GetServiceDefinition {
(): ServiceDefinition;
}
interface GetHandlers {
(): UntypedServiceImplementation;
}
export declare function registerAdminService(getServiceDefinition: GetServiceDefinition, getHandlers: GetHandlers): void;
export declare function addAdminServicesToServer(server: Server): void;
export {};
+30
View File
@@ -0,0 +1,30 @@
"use strict";
/*
* Copyright 2021 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.registerAdminService = registerAdminService;
exports.addAdminServicesToServer = addAdminServicesToServer;
const registeredAdminServices = [];
function registerAdminService(getServiceDefinition, getHandlers) {
registeredAdminServices.push({ getServiceDefinition, getHandlers });
}
function addAdminServicesToServer(server) {
for (const { getServiceDefinition, getHandlers } of registeredAdminServices) {
server.addService(getServiceDefinition(), getHandlers());
}
}
//# sourceMappingURL=admin.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"admin.js","sourceRoot":"","sources":["../../src/admin.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;AAkBH,oDAKC;AAED,4DAIC;AAhBD,MAAM,uBAAuB,GAGvB,EAAE,CAAC;AAET,SAAgB,oBAAoB,CAClC,oBAA0C,EAC1C,WAAwB;IAExB,uBAAuB,CAAC,IAAI,CAAC,EAAE,oBAAoB,EAAE,WAAW,EAAE,CAAC,CAAC;AACtE,CAAC;AAED,SAAgB,wBAAwB,CAAC,MAAc;IACrD,KAAK,MAAM,EAAE,oBAAoB,EAAE,WAAW,EAAE,IAAI,uBAAuB,EAAE,CAAC;QAC5E,MAAM,CAAC,UAAU,CAAC,oBAAoB,EAAE,EAAE,WAAW,EAAE,CAAC,CAAC;IAC3D,CAAC;AACH,CAAC"}
+5
View File
@@ -0,0 +1,5 @@
import { PeerCertificate } from "tls";
export interface AuthContext {
transportSecurityType?: string;
sslPeerCertificate?: PeerCertificate;
}
+19
View File
@@ -0,0 +1,19 @@
"use strict";
/*
* Copyright 2025 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=auth-context.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"auth-context.js","sourceRoot":"","sources":["../../src/auth-context.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG"}
+94
View File
@@ -0,0 +1,94 @@
export interface BackoffOptions {
initialDelay?: number;
multiplier?: number;
jitter?: number;
maxDelay?: number;
}
export declare class BackoffTimeout {
private callback;
/**
* The delay time at the start, and after each reset.
*/
private readonly initialDelay;
/**
* The exponential backoff multiplier.
*/
private readonly multiplier;
/**
* The maximum delay time
*/
private readonly maxDelay;
/**
* The maximum fraction by which the delay time can randomly vary after
* applying the multiplier.
*/
private readonly jitter;
/**
* The delay time for the next time the timer runs.
*/
private nextDelay;
/**
* The handle of the underlying timer. If running is false, this value refers
* to an object representing a timer that has ended, but it can still be
* interacted with without error.
*/
private timerId;
/**
* Indicates whether the timer is currently running.
*/
private running;
/**
* Indicates whether the timer should keep the Node process running if no
* other async operation is doing so.
*/
private hasRef;
/**
* The time that the currently running timer was started. Only valid if
* running is true.
*/
private startTime;
/**
* The approximate time that the currently running timer will end. Only valid
* if running is true.
*/
private endTime;
private id;
private static nextId;
constructor(callback: () => void, options?: BackoffOptions);
private static getNextId;
private trace;
private runTimer;
/**
* Call the callback after the current amount of delay time
*/
runOnce(): void;
/**
* Stop the timer. The callback will not be called until `runOnce` is called
* again.
*/
stop(): void;
/**
* Reset the delay time to its initial value. If the timer is still running,
* retroactively apply that reset to the current timer.
*/
reset(): void;
/**
* Check whether the timer is currently running.
*/
isRunning(): boolean;
/**
* Set that while the timer is running, it should keep the Node process
* running.
*/
ref(): void;
/**
* Set that while the timer is running, it should not keep the Node process
* running.
*/
unref(): void;
/**
* Get the approximate timestamp of when the timer will fire. Only valid if
* this.isRunning() is true.
*/
getEndTime(): Date;
}
+191
View File
@@ -0,0 +1,191 @@
"use strict";
/*
* Copyright 2019 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.BackoffTimeout = void 0;
const constants_1 = require("./constants");
const logging = require("./logging");
const TRACER_NAME = 'backoff';
const INITIAL_BACKOFF_MS = 1000;
const BACKOFF_MULTIPLIER = 1.6;
const MAX_BACKOFF_MS = 120000;
const BACKOFF_JITTER = 0.2;
/**
* Get a number uniformly at random in the range [min, max)
* @param min
* @param max
*/
function uniformRandom(min, max) {
return Math.random() * (max - min) + min;
}
class BackoffTimeout {
constructor(callback, options) {
this.callback = callback;
/**
* The delay time at the start, and after each reset.
*/
this.initialDelay = INITIAL_BACKOFF_MS;
/**
* The exponential backoff multiplier.
*/
this.multiplier = BACKOFF_MULTIPLIER;
/**
* The maximum delay time
*/
this.maxDelay = MAX_BACKOFF_MS;
/**
* The maximum fraction by which the delay time can randomly vary after
* applying the multiplier.
*/
this.jitter = BACKOFF_JITTER;
/**
* Indicates whether the timer is currently running.
*/
this.running = false;
/**
* Indicates whether the timer should keep the Node process running if no
* other async operation is doing so.
*/
this.hasRef = true;
/**
* The time that the currently running timer was started. Only valid if
* running is true.
*/
this.startTime = new Date();
/**
* The approximate time that the currently running timer will end. Only valid
* if running is true.
*/
this.endTime = new Date();
this.id = BackoffTimeout.getNextId();
if (options) {
if (options.initialDelay) {
this.initialDelay = options.initialDelay;
}
if (options.multiplier) {
this.multiplier = options.multiplier;
}
if (options.jitter) {
this.jitter = options.jitter;
}
if (options.maxDelay) {
this.maxDelay = options.maxDelay;
}
}
this.trace('constructed initialDelay=' + this.initialDelay + ' multiplier=' + this.multiplier + ' jitter=' + this.jitter + ' maxDelay=' + this.maxDelay);
this.nextDelay = this.initialDelay;
this.timerId = setTimeout(() => { }, 0);
clearTimeout(this.timerId);
}
static getNextId() {
return this.nextId++;
}
trace(text) {
logging.trace(constants_1.LogVerbosity.DEBUG, TRACER_NAME, '{' + this.id + '} ' + text);
}
runTimer(delay) {
var _a, _b;
this.trace('runTimer(delay=' + delay + ')');
this.endTime = this.startTime;
this.endTime.setMilliseconds(this.endTime.getMilliseconds() + delay);
clearTimeout(this.timerId);
this.timerId = setTimeout(() => {
this.trace('timer fired');
this.running = false;
this.callback();
}, delay);
if (!this.hasRef) {
(_b = (_a = this.timerId).unref) === null || _b === void 0 ? void 0 : _b.call(_a);
}
}
/**
* Call the callback after the current amount of delay time
*/
runOnce() {
this.trace('runOnce()');
this.running = true;
this.startTime = new Date();
this.runTimer(this.nextDelay);
const nextBackoff = Math.min(this.nextDelay * this.multiplier, this.maxDelay);
const jitterMagnitude = nextBackoff * this.jitter;
this.nextDelay =
nextBackoff + uniformRandom(-jitterMagnitude, jitterMagnitude);
}
/**
* Stop the timer. The callback will not be called until `runOnce` is called
* again.
*/
stop() {
this.trace('stop()');
clearTimeout(this.timerId);
this.running = false;
}
/**
* Reset the delay time to its initial value. If the timer is still running,
* retroactively apply that reset to the current timer.
*/
reset() {
this.trace('reset() running=' + this.running);
this.nextDelay = this.initialDelay;
if (this.running) {
const now = new Date();
const newEndTime = this.startTime;
newEndTime.setMilliseconds(newEndTime.getMilliseconds() + this.nextDelay);
clearTimeout(this.timerId);
if (now < newEndTime) {
this.runTimer(newEndTime.getTime() - now.getTime());
}
else {
this.running = false;
}
}
}
/**
* Check whether the timer is currently running.
*/
isRunning() {
return this.running;
}
/**
* Set that while the timer is running, it should keep the Node process
* running.
*/
ref() {
var _a, _b;
this.hasRef = true;
(_b = (_a = this.timerId).ref) === null || _b === void 0 ? void 0 : _b.call(_a);
}
/**
* Set that while the timer is running, it should not keep the Node process
* running.
*/
unref() {
var _a, _b;
this.hasRef = false;
(_b = (_a = this.timerId).unref) === null || _b === void 0 ? void 0 : _b.call(_a);
}
/**
* Get the approximate timestamp of when the timer will fire. Only valid if
* this.isRunning() is true.
*/
getEndTime() {
return this.endTime;
}
}
exports.BackoffTimeout = BackoffTimeout;
BackoffTimeout.nextId = 0;
//# sourceMappingURL=backoff-timeout.js.map
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"backoff-timeout.js","sourceRoot":"","sources":["../../src/backoff-timeout.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;;AAEH,2CAA2C;AAC3C,qCAAqC;AAErC,MAAM,WAAW,GAAG,SAAS,CAAC;AAE9B,MAAM,kBAAkB,GAAG,IAAI,CAAC;AAChC,MAAM,kBAAkB,GAAG,GAAG,CAAC;AAC/B,MAAM,cAAc,GAAG,MAAM,CAAC;AAC9B,MAAM,cAAc,GAAG,GAAG,CAAC;AAE3B;;;;GAIG;AACH,SAAS,aAAa,CAAC,GAAW,EAAE,GAAW;IAC7C,OAAO,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;AAC3C,CAAC;AASD,MAAa,cAAc;IAoDzB,YAAoB,QAAoB,EAAE,OAAwB;QAA9C,aAAQ,GAAR,QAAQ,CAAY;QAnDxC;;WAEG;QACc,iBAAY,GAAW,kBAAkB,CAAC;QAC3D;;WAEG;QACc,eAAU,GAAW,kBAAkB,CAAC;QACzD;;WAEG;QACc,aAAQ,GAAW,cAAc,CAAC;QACnD;;;WAGG;QACc,WAAM,GAAW,cAAc,CAAC;QAWjD;;WAEG;QACK,YAAO,GAAG,KAAK,CAAC;QACxB;;;WAGG;QACK,WAAM,GAAG,IAAI,CAAC;QACtB;;;WAGG;QACK,cAAS,GAAS,IAAI,IAAI,EAAE,CAAC;QACrC;;;WAGG;QACK,YAAO,GAAS,IAAI,IAAI,EAAE,CAAC;QAOjC,IAAI,CAAC,EAAE,GAAG,cAAc,CAAC,SAAS,EAAE,CAAC;QACrC,IAAI,OAAO,EAAE,CAAC;YACZ,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;gBACzB,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC;YAC3C,CAAC;YACD,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;gBACvB,IAAI,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;YACvC,CAAC;YACD,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;gBACnB,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;YAC/B,CAAC;YACD,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;gBACrB,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;YACnC,CAAC;QACH,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,2BAA2B,GAAG,IAAI,CAAC,YAAY,GAAG,cAAc,GAAG,IAAI,CAAC,UAAU,GAAG,UAAU,GAAG,IAAI,CAAC,MAAM,GAAG,YAAY,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC;QACzJ,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,YAAY,CAAC;QACnC,IAAI,CAAC,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE,GAAE,CAAC,EAAE,CAAC,CAAC,CAAC;QACvC,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC7B,CAAC;IAEO,MAAM,CAAC,SAAS;QACtB,OAAO,IAAI,CAAC,MAAM,EAAE,CAAC;IACvB,CAAC;IAEO,KAAK,CAAC,IAAY;QACxB,OAAO,CAAC,KAAK,CAAC,wBAAY,CAAC,KAAK,EAAE,WAAW,EAAE,GAAG,GAAG,IAAI,CAAC,EAAE,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC;IAC9E,CAAC;IAEO,QAAQ,CAAC,KAAa;;QAC5B,IAAI,CAAC,KAAK,CAAC,iBAAiB,GAAG,KAAK,GAAG,GAAG,CAAC,CAAC;QAC5C,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC;QAC9B,IAAI,CAAC,OAAO,CAAC,eAAe,CAC1B,IAAI,CAAC,OAAO,CAAC,eAAe,EAAE,GAAG,KAAK,CACvC,CAAC;QACF,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC3B,IAAI,CAAC,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;YAC7B,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;YAC1B,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;YACrB,IAAI,CAAC,QAAQ,EAAE,CAAC;QAClB,CAAC,EAAE,KAAK,CAAC,CAAC;QACV,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,MAAA,MAAA,IAAI,CAAC,OAAO,EAAC,KAAK,kDAAI,CAAC;QACzB,CAAC;IACH,CAAC;IAED;;OAEG;IACH,OAAO;QACL,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;QACxB,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;QACpB,IAAI,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC;QAC5B,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QAC9B,MAAM,WAAW,GAAG,IAAI,CAAC,GAAG,CAC1B,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,UAAU,EAChC,IAAI,CAAC,QAAQ,CACd,CAAC;QACF,MAAM,eAAe,GAAG,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC;QAClD,IAAI,CAAC,SAAS;YACZ,WAAW,GAAG,aAAa,CAAC,CAAC,eAAe,EAAE,eAAe,CAAC,CAAC;IACnE,CAAC;IAED;;;OAGG;IACH,IAAI;QACF,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACrB,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QAC3B,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;IACvB,CAAC;IAED;;;OAGG;IACH,KAAK;QACH,IAAI,CAAC,KAAK,CAAC,kBAAkB,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC;QAC9C,IAAI,CAAC,SAAS,GAAG,IAAI,CAAC,YAAY,CAAC;QACnC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,MAAM,UAAU,GAAG,IAAI,CAAC,SAAS,CAAC;YAClC,UAAU,CAAC,eAAe,CAAC,UAAU,CAAC,eAAe,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC;YAC1E,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC3B,IAAI,GAAG,GAAG,UAAU,EAAE,CAAC;gBACrB,IAAI,CAAC,QAAQ,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;YACtD,CAAC;iBAAM,CAAC;gBACN,IAAI,CAAC,OAAO,GAAG,KAAK,CAAC;YACvB,CAAC;QACH,CAAC;IACH,CAAC;IAED;;OAEG;IACH,SAAS;QACP,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAED;;;OAGG;IACH,GAAG;;QACD,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC;QACnB,MAAA,MAAA,IAAI,CAAC,OAAO,EAAC,GAAG,kDAAI,CAAC;IACvB,CAAC;IAED;;;OAGG;IACH,KAAK;;QACH,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC;QACpB,MAAA,MAAA,IAAI,CAAC,OAAO,EAAC,KAAK,kDAAI,CAAC;IACzB,CAAC;IAED;;;OAGG;IACH,UAAU;QACR,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;;AAjLH,wCAkLC;AAhIgB,qBAAM,GAAG,CAAC,AAAJ,CAAK"}

Some files were not shown because too many files have changed in this diff Show More