``` ├── .github/ ├── workflows/ ├── release.yml ├── .gitignore ├── .gitmodules ├── LICENSE ├── LICENSE.nodejs ├── LICENSE.v8 ├── README.md ├── assets/ ├── banner.png ├── boxy.svg ├── hakostress.gif ├── bridge/ ├── CMakeLists.txt ├── build.h ├── cmake/ ├── GetGitVersion.cmake ├── ParseWasiVersion.cmake ├── version.h.in ├── wasi_version.h.in ├── hako.c ├── hako.h ├── embedders/ ├── ts/ ├── .gitignore ├── README.md ├── biome.json ├── build.ts ├── package-lock.json ├── package.json ├── patches/ ├── uwasi+1.4.0.patch ├── src/ ├── etc/ ├── errors.ts ├── ffi.ts ``` ## /.github/workflows/release.yml ```yml path="/.github/workflows/release.yml" name: Publish to NPM on: push: tags: - 'v*' jobs: publish: runs-on: ubuntu-latest permissions: contents: read id-token: write deployments: write steps: - name: checkout repository uses: actions/checkout@v4 with: submodules: recursive - uses: actions/setup-node@v4 with: node-version: '22.14.0' registry-url: 'https://registry.npmjs.org' - name: setup bun uses: oven-sh/setup-bun@v2 with: bun-version: '1.2.9' - name: Setup cmake uses: jwlawson/actions-setup-cmake@802fa1a2c4e212495c05bf94dba2704a92a472be with: cmake-version: '4.0.x' - name: envsetup run: chmod +x tools/envsetup.sh && tools/envsetup.sh - name: patch run: chmod +x tools/patch.sh && tools/patch.sh # the TypeScript embedder is up first - name: install dependencies (TS) working-directory: embedders/ts run: | # npm has a bug, nothing we can do. rm -rf package-lock.json npm i # just until uwasi deploys a new version npm run patch:deps - name: generate builds (TS) working-directory: embedders/ts run: npm run generate:builds - name: generate version (TS) working-directory: embedders/ts run: npm run generate:version - name: lint (TS) working-directory: embedders/ts run: | source ${{ github.workspace }}/tools/third-party/env.sh npm run lint - name: test (TS) working-directory: embedders/ts run: npm run test - name: build (TS) working-directory: embedders/ts run: npm run build # we will publish in a bit, let's build and publish REPL - name: install dependencies (REPL) working-directory: examples/repl run: bun install - name: generate build (REPL) working-directory: examples/repl run: bun run build - name: publish REPL to cloudflare pages uses: cloudflare/pages-action@v1 with: apiToken: ${{ secrets.PAGE_PUBLISH_TOKEN }} accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} projectName: hakorepl directory: dist gitHubToken: ${{ secrets.GITHUB_TOKEN }} branch: production workingDirectory: examples/repl wranglerVersion: '3' - name: Publish package to NPM working-directory: embedders/ts run: npm publish --provenance --access public --tag latest env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} ``` ## /.gitignore ```gitignore path="/.gitignore" .DS_Store bridge/build bridge/.cache bridge/version.h bridge/wasi_version.h dist node_modules *.wasm .vscode bun.lock hako.sln *.g.ts obj bin tools/third-party ``` ## /.gitmodules ```gitmodules path="/.gitmodules" [submodule "primjs"] path = primjs url = https://github.com/lynx-family/primjs ``` ## /LICENSE ``` path="/LICENSE" 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. ``` ## /LICENSE.nodejs ```nodejs path="/LICENSE.nodejs" The MIT License (MIT) Copyright (c) 2017 [Node.js API collaborators](https://github.com/nodejs/node-addon-api#collaborators) 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. ``` ## /LICENSE.v8 ```v8 path="/LICENSE.v8" Copyright 2006-2011, the V8 project authors. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of Google Inc. nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ``` ## /README.md

Hako logo

Hako (ha-ko) or 箱 means “box” in Japanese.

[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0.txt) Hako is a embeddable, lightweight, secure, high-performance JavaScript engine. It is a fork of PrimJS; Hako has full support for ES2019 and later ESNext features, and offers superior performance and a better development experience when compared to QuickJS.
## What makes it secure? Hako compiles down to WebAssembly, a memory-safe, sandboxed execution environment. This means even though Hako is written in C/C++, programs it is embedded in have an extra layer of security from memory corruption attacks. Hako also has a built-in sandboxing mechanism in the form of VMContext which allows you to restrict the capabilities of JavaScript code. A number of APIs are exposed to limit the amount of memory and 'gas' a script can consume before it is terminated, and development follows an opinionated 'fail-fast' design for bailing out of potentially unstable code that could consume or block I/O. Combining all of these, you can run hundreds of VMs in parallel on a single machine. ![](./assets//hakostress.gif) ## What makes it embeddable? Hako does not use Emscripten to compile down to WebAssembly; so long as your language of choice has a WebAssembly runtime, you can embed Hako in it by implementing the necessary imports. You can see an example of embedding Hako in Go [here](https://gist.github.com/andrewmd5/197efb527ef40131c34ca12fd6d0a61e). It is also incredibly tiny. The release build is ~800KB. ## What makes it fast? Hako is a fork of [PrimJS](https://github.com/lynx-family/primjs), which in sythentic benchmarks shows performance gains of 28% over QuickJS. Compiling to WebAssembly has no noticeable impact on performance as the amazing JIT compilers of JavaScriptCore/Bun, V8/NodeJS, and Wasmtime allow code to run at near-native speeds. You can enable profiling in Hako to see how your code is performing. Here's a simple string concatenation benchmark comparing Hako to QuickJS and QuickJS-NG: ```javascript const t1 = Date.now() let str = ''; for (let i = 0; i < 1000_000; i++) { str += 'a'; } const t2 = Date.now() console.log(t2 - t1); // Results: // quickjs-ng: 6854ms // quickjs: 112ms // hako: 92ms ``` As you can see, Hako outperforms both QuickJS and QuickJS-NG in this common operation, with QuickJS-NG being particularly slow at string concatenation.​​​​​​​​​​​​​​​​ ## Notice This project is still in early access - documentation is a work in progress, and the API/ABI should not be considered stable. If you wish to contribute, please do so by opening an issue or a pull request for further discussion. Your feedback is greatly appreciated. You can find the intitial reference implementation of Hako in TypeScript [here](./embedders/ts/README.md). For further reading and to get a sense of the roadmap see the initial releasse blog post [here](https://andrews.substack.com/p/hako). ## /assets/banner.png Binary file available at https://raw.githubusercontent.com/andrewmd5/hako/refs/heads/main/assets/banner.png ## /assets/boxy.svg ```svg path="/assets/boxy.svg" ``` ## /assets/hakostress.gif Binary file available at https://raw.githubusercontent.com/andrewmd5/hako/refs/heads/main/assets/hakostress.gif ## /bridge/CMakeLists.txt cmake_minimum_required(VERSION 4.0.0) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(HAVE_FLAG_SEARCH_PATHS_FIRST 0) # Get WASI SDK path from environment - require it to be set if(DEFINED ENV{WASI_SDK_PATH}) set(WASI_SDK_PATH $ENV{WASI_SDK_PATH}) else() message(FATAL_ERROR "WASI SDK not found. Please set WASI_SDK_PATH environment variable.") endif() if(DEFINED ENV{PRIMJS_DIR}) set(PRIMJS_DIR $ENV{PRIMJS_DIR}) else() message(FATAL_ERROR "PrimJS dir not found. Please set PRIMJS_DIR environment variable.") endif() message(STATUS "Using WASI SDK from: ${WASI_SDK_PATH}") message(STATUS "Using PrimJS from: ${PRIMJS_DIR}") # Set WASI tools set(CMAKE_C_COMPILER "${WASI_SDK_PATH}/bin/clang") set(CMAKE_CXX_COMPILER "${WASI_SDK_PATH}/bin/clang++") set(CMAKE_AR "${WASI_SDK_PATH}/bin/llvm-ar") set(CMAKE_RANLIB "${WASI_SDK_PATH}/bin/llvm-ranlib") set(CMAKE_STRIP "${WASI_SDK_PATH}/bin/llvm-strip") # Set WASI sysroot and target set(CMAKE_SYSROOT "${WASI_SDK_PATH}/share/wasi-sysroot") set(CMAKE_C_COMPILER_TARGET "wasm32-wasi-threads") set(CMAKE_CXX_COMPILER_TARGET "wasm32-wasi-threads") set(CMAKE_TRY_COMPILE_TARGET_TYPE "STATIC_LIBRARY") set(CMAKE_C_COMPILER_WORKS "1") set(CMAKE_CXX_COMPILER_WORKS "1") project("hako") set(CMAKE_C_LINK_FLAGS "") set(CMAKE_CXX_LINK_FLAGS "") list(APPEND CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake") # Include the ParseWasiVersion module include(ParseWasiVersion) # Parse the WASI SDK VERSION file parse_wasi_version(${WASI_SDK_PATH}) # Create a wasi_version.h file with the parsed values configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/wasi_version.h.in ${CMAKE_CURRENT_SOURCE_DIR}/wasi_version.h ) include(GetGitVersion) get_git_version(GIT_VERSION) set(HAKO_VERSION ${GIT_VERSION}) configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/cmake/version.h.in ${CMAKE_CURRENT_SOURCE_DIR}/version.h ) # Basic settings enable_language(C CXX ASM) set(CMAKE_CXX_STANDARD 17) # Build type if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE "Release") endif() message(STATUS "Building in ${CMAKE_BUILD_TYPE} mode") message(STATUS "Source directory: ${CMAKE_CURRENT_SOURCE_DIR}") if(CMAKE_BUILD_TYPE STREQUAL "Debug") # Debug mode - add debug info, disable optimizations set(OPTIMIZATION_FLAGS "-g -O0") else() # Release mode - use full optimization set(OPTIMIZATION_FLAGS "-O3") set(WASM_OPT_FLAG "--wasm-opt") endif() # Configuration options option(ENABLE_QUICKJS_DEBUGGER "Enable quickjs debugger" OFF) option(ENABLE_HAKO_PROFILER "Enable the Hako profiler" OFF) option(ENABLE_LEPUSNG "Enable LepusNG" ON) option(ENABLE_PRIMJS_SNAPSHOT "Enable primjs snapshot" OFF) option(ENABLE_COMPATIBLE_MM "Enable compatible memory" OFF) option(DISABLE_NANBOX "Disable nanbox" OFF) option(ENABLE_CODECACHE "Enable code cache" OFF) option(CACHE_PROFILE "Enable cache profile" OFF) option(ENABLE_MEM "Enable memory detection" OFF) option(ENABLE_ATOMICS "Enable Atomics" ON) option(FORCE_GC "Enable force gc" OFF) option(ENABLE_ASAN "Enable address sanitizer" OFF) option(ENABLE_BIGNUM "Enable bignum" OFF) option(WASM_INITIAL_MEMORY "Initial memory size in bytes" "25165824") # 24MB default option(WASM_MAX_MEMORY "Maximum memory size in bytes" "268435456") # 256MB default option(WASM_STACK_SIZE "Stack size in bytes" "8388608") # 8MB default option(WASM_OUTPUT_NAME "Output name for the WASM file" "hako.wasm") if(CMAKE_BUILD_TYPE STREQUAL "Debug") set(ENABLE_MEM ON) endif() # Required WASI emulation options add_compile_options( -Wno-cast-function-type-mismatch -D_WASI_EMULATED_MMAN -D_WASI_EMULATED_SIGNAL -D_WASI_EMULATED_PROCESS_CLOCKS ) # Simplify for WASI if(NOT DEFINED LYNX_SIMPLIFY) add_definitions(-DLYNX_SIMPLIFY -DENABLE_BUILTIN_SERIALIZE) endif() # Compiler flags set(CMAKE_COMMON_FLAGS "${OPTIMIZATION_FLAGS} -fPIC -ffunction-sections -fdata-sections \ -fno-short-enums -fno-strict-aliasing -Wall -Wextra -Wno-unused-parameter \ -Wno-unused-function -faddrsig -Wno-c99-designator -Wno-unknown-warning-option \ -Wno-sign-compare -Wno-unused-but-set-variable -pthread -matomics -msimd128 -mmultivalue -mmutable-globals -mtail-call -msign-ext -mbulk-memory -mnontrapping-fptoint -mextended-const") if(ENABLE_ASAN) add_definitions(-DHAKO_SANITIZE_LEAK) set(CMAKE_COMMON_FLAGS "${CMAKE_COMMON_FLAGS} -fno-omit-frame-pointer") else() set(CMAKE_COMMON_FLAGS "${CMAKE_COMMON_FLAGS} -fomit-frame-pointer -fno-sanitize=safe-stack") endif() set(CMAKE_C_FLAGS "${CMAKE_COMMON_FLAGS} ${CMAKE_C_FLAGS}") set(CMAKE_CXX_FLAGS "${CMAKE_COMMON_FLAGS} ${CMAKE_CXX_FLAGS} -std=c++17") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--gc-sections -Wl,--build-id=sha1 -O2") # Common definitions add_definitions(-DEMSCRIPTEN) add_definitions(-D__WASI_SDK__) add_definitions(-DOS_WASI=1) if(${ENABLE_LEPUSNG} AND ${ENABLE_BIGNUM}) message(FATAL_ERROR "ENABLE_LEPUSNG and ENABLE_BIGNUM cannot be both enabled.") endif() if(${ENABLE_BIGNUM}) add_definitions(-DCONFIG_BIGNUM) endif() if(${ENABLE_ATOMICS}) add_definitions(-DENABLE_ATOMICS -DCONFIG_ATOMICS) endif() if(${ENABLE_HAKO_PROFILER}) add_definitions(-DENABLE_HAKO_PROFILER) endif() # Feature definitions if(${ENABLE_MEM}) add_definitions(-DDEBUG_MEMORY) add_definitions(-DDUMP_QJS_VALUE) add_definitions(-DDUMP_LEAKS) endif() if(${FORCE_GC}) add_definitions(-DFORCE_GC_AT_MALLOC) endif() if(${ENABLE_LEPUSNG}) add_definitions(-DENABLE_LEPUSNG) endif() if(${DISABLE_NANBOX}) add_definitions(-DDISABLE_NANBOX=1) else() add_definitions(-DDISABLE_NANBOX=0) endif() # primjs snapshot version if(${ENABLE_PRIMJS_SNAPSHOT}) add_definitions(-DENABLE_PRIMJS_SNAPSHOT) if(${ENABLE_COMPATIBLE_MM}) add_definitions(-DENABLE_COMPATIBLE_MM) endif() if(${ENABLE_QUICKJS_DEBUGGER}) set(primjs_embedded_sources ${PRIMJS_DIR}/src/interpreter/primjs/wasi/embedded-inspector.S) else() set(primjs_embedded_sources ${PRIMJS_DIR}/src/interpreter/primjs/wasi/embedded.S) endif() endif() # List all QuickJS sources set(quickjs_sources ${PRIMJS_DIR}/src/basic/log/logging.cc ${PRIMJS_DIR}/src/gc/allocator.cc ${PRIMJS_DIR}/src/gc/collector.cc ${PRIMJS_DIR}/src/gc/global-handles.cc ${PRIMJS_DIR}/src/gc/qjsvaluevalue-space.cc ${PRIMJS_DIR}/src/gc/sweeper.cc ${PRIMJS_DIR}/src/gc/thread_pool.cc ${PRIMJS_DIR}/src/gc/collector.cc ${PRIMJS_DIR}/src/interpreter/quickjs/source/cutils.cc ${PRIMJS_DIR}/src/interpreter/quickjs/source/libregexp.cc ${PRIMJS_DIR}/src/interpreter/quickjs/source/libunicode.cc ${PRIMJS_DIR}/src/interpreter/quickjs/source/primjs_monitor.cc ${PRIMJS_DIR}/src/interpreter/quickjs/source/quickjs_gc.cc ${PRIMJS_DIR}/src/interpreter/quickjs/source/quickjs_queue.cc ${PRIMJS_DIR}/src/interpreter/quickjs/source/quickjs_version.cc ${PRIMJS_DIR}/src/interpreter/quickjs/source/quickjs-libc.cc ${PRIMJS_DIR}/src/interpreter/quickjs/source/quickjs.cc) # Add BigNum support if enabled if(ENABLE_BIGNUM) set(quickjs_sources ${quickjs_sources} ${PRIMJS_DIR}/src/interpreter/quickjs/source/libbf.cc) endif() # Add debugger sources if enabled if(${ENABLE_QUICKJS_DEBUGGER}) add_definitions(-DENABLE_QUICKJS_DEBUGGER) set(quickjs_debugger_sources ${PRIMJS_DIR}/src/inspector/cpuprofiler/cpu_profiler.cc ${PRIMJS_DIR}/src/inspector/cpuprofiler/profile_generator.cc ${PRIMJS_DIR}/src/inspector/cpuprofiler/profile_tree.cc ${PRIMJS_DIR}/src/inspector/cpuprofiler/profiler_sampling.cc ${PRIMJS_DIR}/src/inspector/cpuprofiler/tracing_cpu_profiler.cc ${PRIMJS_DIR}/src/inspector/debugger/debugger_breakpoint.cc ${PRIMJS_DIR}/src/inspector/debugger/debugger_callframe.cc ${PRIMJS_DIR}/src/inspector/debugger/debugger_properties.cc ${PRIMJS_DIR}/src/inspector/debugger/debugger_queue.cc ${PRIMJS_DIR}/src/inspector/debugger/debugger.cc ${PRIMJS_DIR}/src/inspector/heapprofiler/edge.cc ${PRIMJS_DIR}/src/inspector/heapprofiler/entry.cc ${PRIMJS_DIR}/src/inspector/heapprofiler/gen.cc ${PRIMJS_DIR}/src/inspector/heapprofiler/heapexplorer.cc ${PRIMJS_DIR}/src/inspector/heapprofiler/heapprofiler.cc ${PRIMJS_DIR}/src/inspector/heapprofiler/serialize.cc ${PRIMJS_DIR}/src/inspector/heapprofiler/snapshot.cc ${PRIMJS_DIR}/src/inspector/runtime/runtime.cc ${PRIMJS_DIR}/src/inspector/protocols.cc ${PRIMJS_DIR}/src/inspector/string_tools.cc) # Add debugger sources to QuickJS sources set(quickjs_sources ${quickjs_sources} ${quickjs_debugger_sources}) endif() # Add embedded sources if defined if(DEFINED primjs_embedded_sources) set(quickjs_sources ${quickjs_sources} ${primjs_embedded_sources}) endif() # Include directories include_directories( ${PRIMJS_DIR}/src ${PRIMJS_DIR}/src/interpreter ${PRIMJS_DIR}/src/interpreter/quickjs/include ${PRIMJS_DIR}/src/interpreter/quickjs/source ${PRIMJS_DIR}/src/napi ${PRIMJS_DIR}/src/napi/common ${PRIMJS_DIR}/src/napi/env ${PRIMJS_DIR}/src/napi/internal ${PRIMJS_DIR}/src/napi/quickjs ${PRIMJS_DIR}/src/napi/v8) # Build the QuickJS static library add_library(quickjs STATIC ${quickjs_sources}) set_target_properties(quickjs PROPERTIES ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_NAME "quick") # Add WASI-specific link options to the QuickJS library target_link_options(quickjs PRIVATE "-Wl,--allow-undefined -Wl,wasi-emulated-signal -Wl,wasi-emulated-process-clocks -Wl,--shared-memory") # Build the hako WASM module set(hako_source ${CMAKE_CURRENT_SOURCE_DIR}/hako.c) add_executable(hako_reactor ${hako_source}) set_target_properties(hako_reactor PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR} OUTPUT_NAME ${WASM_OUTPUT_NAME} ) target_link_libraries(hako_reactor PRIVATE quickjs) target_include_directories(hako_reactor PRIVATE ${PRIMJS_DIR}/src ${PRIMJS_DIR}/src/interpreter ${PRIMJS_DIR}/src/interpreter/quickjs/include ${PRIMJS_DIR}/src/interpreter/quickjs/source ${PRIMJS_DIR}/src/napi ${PRIMJS_DIR}/src/napi/common ${PRIMJS_DIR}/src/napi/env ${PRIMJS_DIR}/src/napi/internal ${PRIMJS_DIR}/src/napi/quickjs ${PRIMJS_DIR}/src/napi/v8 ) # WASM-specific link options target_link_options(hako_reactor PRIVATE -mexec-model=reactor -Wl,--import-memory,--export-memory -Wl,--no-entry -Wl,--export=malloc -Wl,--export=free -Wl,--export=__heap_base -Wl,--export=__data_end -Wl,--allow-undefined -Wl,-z,stack-size=${WASM_STACK_SIZE} -Wl,--initial-memory=${WASM_INITIAL_MEMORY} -Wl,--max-memory=${WASM_MAX_MEMORY} ${WASM_OPT_FLAG} ) message(STATUS "Configuration summary:") message(STATUS " WASI SDK path: ${WASI_SDK_PATH}") message(STATUS " PrimJS directory: ${PRIMJS_DIR}") message(STATUS " Output WASM: ${WASM_OUTPUT_NAME}") message(STATUS " Initial memory: ${WASM_INITIAL_MEMORY} bytes") message(STATUS " Maximum memory: ${WASM_MAX_MEMORY} bytes") message(STATUS " Stack size: ${WASM_STACK_SIZE} bytes") message(STATUS " Bignum support: ${ENABLE_BIGNUM}") message(STATUS " LepusNG support: ${ENABLE_LEPUSNG}") message(STATUS " Debugger support: ${ENABLE_QUICKJS_DEBUGGER}") if(DEFINED WASI_VERSION_PARSED) message(STATUS " WASI SDK version: ${WASI_VERSION}") if(DEFINED WASI_WASI_LIBC) message(STATUS " WASI-libc version: ${WASI_WASI_LIBC}") endif() if(DEFINED WASI_LLVM) message(STATUS " LLVM version: ${WASI_LLVM}") endif() if(DEFINED WASI_LLVM_VERSION) message(STATUS " LLVM detailed version: ${WASI_LLVM_VERSION}") endif() if(DEFINED WASI_CONFIG) message(STATUS " WASI config: ${WASI_CONFIG}") endif() endif() ## /bridge/build.h ```h path="/bridge/build.h" #ifndef BUILD_H #define BUILD_H #ifdef __cplusplus extern "C" { #endif /** * @brief Build flags indicating which features are enabled in the runtime */ typedef enum HAKO_BuildFlag { HAKO_BuildFlag_Debug = 1 << 0, /* Debug build */ HAKO_BuildFlag_Sanitizer = 1 << 1, /* Address sanitizer enabled */ HAKO_BuildFlag_Bignum = 1 << 2, /* BigNum support enabled */ HAKO_BuildFlag_LepusNG = 1 << 3, /* LepusNG enabled */ HAKO_BuildFlag_Debugger = 1 << 4, /* QuickJS debugger enabled */ HAKO_BuildFlag_Snapshot = 1 << 5, /* PrimJS snapshot enabled */ HAKO_BuildFlag_CompatibleMM = 1 << 6, /* Compatible memory management */ HAKO_BuildFlag_Nanbox = 1 << 7, /* NaN boxing enabled */ HAKO_BuildFlag_CodeCache = 1 << 8, /* Code cache enabled */ HAKO_BuildFlag_CacheProfile = 1 << 9, /* Cache profiling enabled */ HAKO_BuildFlag_MemDetection = 1 << 10, /* Memory leak detection enabled */ HAKO_BuildFlag_Atomics = 1 << 11, /* Atomics support enabled */ HAKO_BuildFlag_ForceGC = 1 << 12, /* Force GC at allocation enabled */ HAKO_BuildFlag_LynxSimplify = 1 << 13, /* Lynx simplification enabled */ HAKO_BuildFlag_BuiltinSerialize = 1 << 14, /* Builtin serialization enabled */ HAKO_BuildFlag_HakoProfiler = 1 << 15, /* Hako profiler enabled */ } HAKO_BuildFlag; /* Build flags as individual compile-time constants */ #if defined(DEBUG) || defined(_DEBUG) #define HAKO_HAS_DEBUG 1 #else #define HAKO_HAS_DEBUG 0 #endif #ifdef __SANITIZE_ADDRESS__ #define HAKO_HAS_SANITIZER 1 #else #define HAKO_HAS_SANITIZER 0 #endif #ifdef CONFIG_BIGNUM #define HAKO_HAS_BIGNUM 1 #else #define HAKO_HAS_BIGNUM 0 #endif #ifdef ENABLE_LEPUSNG #define HAKO_HAS_LEPUSNG 1 #else #define HAKO_HAS_LEPUSNG 0 #endif #ifdef ENABLE_QUICKJS_DEBUGGER #define HAKO_HAS_DEBUGGER 1 #else #define HAKO_HAS_DEBUGGER 0 #endif #ifdef ENABLE_PRIMJS_SNAPSHOT #define HAKO_HAS_SNAPSHOT 1 #else #define HAKO_HAS_SNAPSHOT 0 #endif #ifdef ENABLE_COMPATIBLE_MM #define HAKO_HAS_COMPATIBLE_MM 1 #else #define HAKO_HAS_COMPATIBLE_MM 0 #endif #if defined(DISABLE_NANBOX) && DISABLE_NANBOX == 0 #define HAKO_HAS_NANBOX 1 #else #define HAKO_HAS_NANBOX 0 #endif #ifdef ENABLE_CODECACHE #define HAKO_HAS_CODECACHE 1 #else #define HAKO_HAS_CODECACHE 0 #endif #ifdef CACHE_PROFILE #define HAKO_HAS_CACHE_PROFILE 1 #else #define HAKO_HAS_CACHE_PROFILE 0 #endif #ifdef DEBUG_MEMORY #define HAKO_HAS_MEM_DETECTION 1 #else #define HAKO_HAS_MEM_DETECTION 0 #endif #if defined(CONFIG_ATOMICS) || defined(ENABLE_ATOMICS) #define HAKO_HAS_ATOMICS 1 #else #define HAKO_HAS_ATOMICS 0 #endif #ifdef FORCE_GC_AT_MALLOC #define HAKO_HAS_FORCE_GC 1 #else #define HAKO_HAS_FORCE_GC 0 #endif #ifdef LYNX_SIMPLIFY #define HAKO_HAS_LYNX_SIMPLIFY 1 #else #define HAKO_HAS_LYNX_SIMPLIFY 0 #endif #ifdef ENABLE_BUILTIN_SERIALIZE #define HAKO_HAS_BUILTIN_SERIALIZE 1 #else #define HAKO_HAS_BUILTIN_SERIALIZE 0 #endif #ifdef ENABLE_HAKO_PROFILER #define HAKO_HAS_HAKO_PROFILER 1 #else #define HAKO_HAS_HAKO_PROFILER 0 #endif /* Define the build flags value as a true compile-time constant */ #define HAKO_BUILD_FLAGS_VALUE \ ((HAKO_HAS_DEBUG ? HAKO_BuildFlag_Debug : 0) | \ (HAKO_HAS_SANITIZER ? HAKO_BuildFlag_Sanitizer : 0) | \ (HAKO_HAS_BIGNUM ? HAKO_BuildFlag_Bignum : 0) | \ (HAKO_HAS_LEPUSNG ? HAKO_BuildFlag_LepusNG : 0) | \ (HAKO_HAS_DEBUGGER ? HAKO_BuildFlag_Debugger : 0) | \ (HAKO_HAS_SNAPSHOT ? HAKO_BuildFlag_Snapshot : 0) | \ (HAKO_HAS_COMPATIBLE_MM ? HAKO_BuildFlag_CompatibleMM : 0) | \ (HAKO_HAS_NANBOX ? HAKO_BuildFlag_Nanbox : 0) | \ (HAKO_HAS_CODECACHE ? HAKO_BuildFlag_CodeCache : 0) | \ (HAKO_HAS_CACHE_PROFILE ? HAKO_BuildFlag_CacheProfile : 0) | \ (HAKO_HAS_MEM_DETECTION ? HAKO_BuildFlag_MemDetection : 0) | \ (HAKO_HAS_ATOMICS ? HAKO_BuildFlag_Atomics : 0) | \ (HAKO_HAS_FORCE_GC ? HAKO_BuildFlag_ForceGC : 0) | \ (HAKO_HAS_LYNX_SIMPLIFY ? HAKO_BuildFlag_LynxSimplify : 0) | \ (HAKO_HAS_BUILTIN_SERIALIZE ? HAKO_BuildFlag_BuiltinSerialize : 0) | \ (HAKO_HAS_HAKO_PROFILER ? HAKO_BuildFlag_HakoProfiler : 0)) /* Helper macro to check if a build flag is enabled at compile time */ #define HAKO_IS_ENABLED(flag) ((HAKO_BUILD_FLAGS_VALUE & (flag)) != 0) /** * @brief Structure containing build information */ typedef struct HakoBuildInfo { const char *version; /* Git version */ HAKO_BuildFlag flags; /* Feature flags bitmap */ const char *build_date; /* Build date */ const char *wasi_sdk_version; const char *wasi_libc; /* WASI-libc commit hash */ const char *llvm; /* LLVM commit hash */ const char *llvm_version; /* LLVM version */ const char *config; /* Configuration hash */ } HakoBuildInfo; #ifdef __cplusplus } #endif #endif /* BUILD_H */ ``` ## /bridge/cmake/GetGitVersion.cmake ```cmake path="/bridge/cmake/GetGitVersion.cmake" # GetGitVersion.cmake # Returns a version string from Git tags # # This function inspects the git tags for the project and returns a string # into a CMake variable # # get_git_version() # # - Example # # include(GetGitVersion) # get_git_version(GIT_VERSION) find_package(Git) if(__get_git_version) return() endif() set(__get_git_version INCLUDED) function(get_git_version var) if(GIT_EXECUTABLE) # First try the exact tag - this works better in CI environments execute_process( COMMAND ${GIT_EXECUTABLE} describe --exact-match --tags WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} RESULT_VARIABLE status_exact OUTPUT_VARIABLE GIT_VERSION_EXACT ERROR_VARIABLE error_exact OUTPUT_STRIP_TRAILING_WHITESPACE ) if(NOT ${status_exact}) # We found an exact tag match set(GIT_VERSION ${GIT_VERSION_EXACT}) message(STATUS "Git exact tag match: ${GIT_VERSION}") else() # Try with the pattern matching approach execute_process( COMMAND ${GIT_EXECUTABLE} describe --match "v[0-9]*.[0-9]*.[0-9]*" --abbrev=8 WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} RESULT_VARIABLE status OUTPUT_VARIABLE GIT_VERSION ERROR_VARIABLE error_output OUTPUT_STRIP_TRAILING_WHITESPACE ) if(${status}) message(STATUS "Git version detection failed with: ${error_output}") # Fallback to tag listing to see what's available execute_process( COMMAND ${GIT_EXECUTABLE} tag -l WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} OUTPUT_VARIABLE available_tags ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE ) message(STATUS "Available tags: ${available_tags}") set(GIT_VERSION "0.0.0") else() string(REGEX REPLACE "-[0-9]+-g" "-" GIT_VERSION ${GIT_VERSION}) endif() endif() else() set(GIT_VERSION "0.0.0") endif() if(GIT_VERSION MATCHES "^v") string(SUBSTRING ${GIT_VERSION} 1 -1 GIT_VERSION) endif() message(STATUS "Git Version: ${GIT_VERSION}") set(${var} ${GIT_VERSION} PARENT_SCOPE) endfunction() ``` ## /bridge/cmake/ParseWasiVersion.cmake ```cmake path="/bridge/cmake/ParseWasiVersion.cmake" # ParseWasiVersion.cmake # Function to parse the WASI SDK VERSION file into CMake variables # # This function reads the VERSION file from the WASI SDK directory and parses # its contents into CMake variables that can be used in the build system # and in generated source files. if(__parse_wasi_version) return() endif() set(__parse_wasi_version INCLUDED) function(parse_wasi_version WASI_SDK_PATH) set(VERSION_FILE "${WASI_SDK_PATH}/VERSION") # Check if VERSION file exists if(NOT EXISTS "${VERSION_FILE}") message(WARNING "WASI SDK VERSION file not found at ${VERSION_FILE}") # Set default values set(WASI_VERSION "unknown" PARENT_SCOPE) set(WASI_WASI_LIBC "unknown" PARENT_SCOPE) set(WASI_LLVM "unknown" PARENT_SCOPE) set(WASI_LLVM_VERSION "unknown" PARENT_SCOPE) set(WASI_CONFIG "unknown" PARENT_SCOPE) return() endif() # Read the VERSION file content file(READ "${VERSION_FILE}" VERSION_CONTENT) # Extract the WASI SDK version (first line) if(VERSION_CONTENT MATCHES "^([^\n]*)") set(WASI_VERSION "${CMAKE_MATCH_1}" PARENT_SCOPE) message(STATUS "WASI SDK version: ${CMAKE_MATCH_1}") else() set(WASI_VERSION "unknown" PARENT_SCOPE) endif() # Extract WASI-libc commit hash if(VERSION_CONTENT MATCHES "wasi-libc:[ \t]*([^\n]*)") set(WASI_WASI_LIBC "${CMAKE_MATCH_1}" PARENT_SCOPE) message(STATUS "WASI-libc commit: ${CMAKE_MATCH_1}") else() set(WASI_WASI_LIBC "unknown" PARENT_SCOPE) endif() # Extract LLVM commit hash if(VERSION_CONTENT MATCHES "llvm:[ \t]*([^\n]*)") set(WASI_LLVM "${CMAKE_MATCH_1}" PARENT_SCOPE) message(STATUS "LLVM commit: ${CMAKE_MATCH_1}") else() set(WASI_LLVM "unknown" PARENT_SCOPE) endif() # Extract LLVM version if(VERSION_CONTENT MATCHES "llvm-version:[ \t]*([^\n]*)") set(WASI_LLVM_VERSION "${CMAKE_MATCH_1}" PARENT_SCOPE) message(STATUS "LLVM version: ${CMAKE_MATCH_1}") else() set(WASI_LLVM_VERSION "unknown" PARENT_SCOPE) endif() # Extract configuration hash if(VERSION_CONTENT MATCHES "config:[ \t]*([^\n]*)") set(WASI_CONFIG "${CMAKE_MATCH_1}" PARENT_SCOPE) message(STATUS "Config hash: ${CMAKE_MATCH_1}") else() set(WASI_CONFIG "unknown" PARENT_SCOPE) endif() endfunction() ``` ## /bridge/cmake/version.h.in ```in path="/bridge/cmake/version.h.in" #ifndef HAKO_VERSION_H_ #define HAKO_VERSION_H_ #define HAKO_VERSION "@HAKO_VERSION@" #endif /* HAKO_VERSION_H_ */ ``` ## /bridge/cmake/wasi_version.h.in ```in path="/bridge/cmake/wasi_version.h.in" /** * @file wasi_version.h * @brief WASI SDK version information parsed from VERSION file * @note This file is auto-generated. Do not edit directly. */ #ifndef WASI_VERSION_H #define WASI_VERSION_H #ifdef __cplusplus extern "C" { #endif /** * WASI SDK version information */ #define WASI_VERSION "@WASI_VERSION@" /** * WASI-libc commit hash */ #define WASI_WASI_LIBC "@WASI_WASI_LIBC@" /** * LLVM commit hash */ #define WASI_LLVM "@WASI_LLVM@" /** * LLVM version */ #define WASI_LLVM_VERSION "@WASI_LLVM_VERSION@" /** * Configuration hash */ #define WASI_CONFIG "@WASI_CONFIG@" #ifdef __cplusplus } #endif #endif /* WASI_VERSION_H */ ``` ## /bridge/hako.c ```c path="/bridge/hako.c" #include #include #include #include #ifdef HAKO_SANITIZE_LEAK #include #endif #include "cutils.h" #include "hako.h" #include "quickjs-libc.h" #include "version.h" #include "wasi_version.h" #define PKG "quickjs-wasi: " #define LOG_LEN 500 #define NUM_THREADS 10 #include /** * Define attribute for exporting functions to WebAssembly */ #if defined(__WASI__) || defined(__wasi__) #define WASM_EXPORT(func) __attribute__((export_name(#func))) func #else #define WASM_EXPORT(func) func #endif typedef struct hako_RuntimeData { bool debug_log; } hako_RuntimeData; __attribute__((import_module("hako"), import_name("call_function"))) extern LEPUSValue * host_call_function(LEPUSContext *ctx, LEPUSValueConst *this_ptr, int argc, LEPUSValueConst *argv, uint32_t magic_func_id); __attribute__((import_module("hako"), import_name("interrupt_handler"))) extern int host_interrupt_handler(LEPUSRuntime *rt, LEPUSContext *ctx, void *opaque); __attribute__((import_module("hako"), import_name("load_module_source"))) extern char * host_load_module_source(LEPUSRuntime *rt, LEPUSContext *ctx, CString *module_name); __attribute__((import_module("hako"), import_name("normalize_module"))) extern char * host_normalize_module(LEPUSRuntime *rt, LEPUSContext *ctx, CString *module_base_name, CString *module_name); __attribute__((import_module("hako"), import_name("profile_function_start"))) extern void host_profile_function_start(LEPUSContext *ctx, CString *event, JSVoid *opaque); __attribute__((import_module("hako"), import_name("profile_function_end"))) extern void host_profile_function_end(LEPUSContext *ctx, CString *event, JSVoid *opaque); static const char *HAKO_BAD_FREE_MSG = "+---------------------------------------------------------+\n" "| FATAL ERROR #1 |\n" "+---------------------------------------------------------+\n" "| Attempted to free constant JavaScript primitive: |\n" "| Address: %p |\n" "| |\n" "| Cannot free undefined/null/true/false as these are |\n" "| static values. Doing so would cause undefined behavior |\n" "| and probable memory corruption. |\n" "| |\n" "| Fix: Check value ownership before attempting to free. |\n" "+---------------------------------------------------------+\n"; static HakoBuildInfo build_info = {.version = HAKO_VERSION, .flags = HAKO_BUILD_FLAGS_VALUE, .build_date = __DATE__ " " __TIME__, .wasi_sdk_version = WASI_VERSION, .wasi_libc = WASI_WASI_LIBC, .llvm = WASI_LLVM, .llvm_version = WASI_LLVM_VERSION, .config = WASI_CONFIG}; hako_RuntimeData *hako_get_runtime_data(LEPUSRuntime *rt) { hako_RuntimeData *data = malloc(sizeof(hako_RuntimeData)); data->debug_log = false; return data; } hako_RuntimeData *hako_get_context_rt_data(LEPUSContext *ctx) { return hako_get_runtime_data(LEPUS_GetRuntime(ctx)); } void hako_log(char *msg) { fputs(PKG, stderr); fputs(msg, stderr); fputs("\n", stderr); } void hako_dump(LEPUSContext *ctx, LEPUSValueConst value) { CString *str = LEPUS_ToCString(ctx, value); if (!str) { return; } fputs(str, stderr); LEPUS_FreeCString(ctx, str); putchar('\n'); } #define MAX_EVENT_BUFFER_SIZE 1024 static char event_buffer[MAX_EVENT_BUFFER_SIZE]; static int hako_atom_to_str(LEPUSContext *ctx, JSAtom atom, const char **out_str, const char *default_value) { // Use provided default_value if available, otherwise use "" const char *anonymous_str = default_value ? default_value : ""; if (atom == 0 /*JS_ATOM_NULL*/) { *out_str = anonymous_str; return 0; // Static string, no need to free } const char *atom_str = LEPUS_AtomToCString(ctx, atom); if (atom_str[0]) { *out_str = atom_str; return 1; // Dynamic string, needs to be freed } *out_str = anonymous_str; return 0; // Static string, no need to free } static void hako_profile_function_start(LEPUSContext *ctx, JSAtom func, JSAtom filename, void *opaque) { __wasi_errno_t err; __wasi_timestamp_t current_time; // Get the current time using WASI err = __wasi_clock_time_get(__WASI_CLOCKID_MONOTONIC, 0, ¤t_time); const char *func_str; int need_free_func = hako_atom_to_str(ctx, func, &func_str, NULL); const char *filename_str; int need_free_filename = hako_atom_to_str(ctx, filename, &filename_str, "file://hako.c"); // Use the shared buffer for formatting the event int written = snprintf(event_buffer, MAX_EVENT_BUFFER_SIZE, "{\"name\": \"%s\",\"cat\": \"js\",\"ph\": \"B\",\"ts\": %llu,\"pid\": 1,\"tid\": 1,\"args\": {\"file\": \"%s\"}}", func_str, current_time / 1000, filename_str); host_profile_function_start(ctx, event_buffer, opaque); // Clean up dynamic strings if (need_free_func) { LEPUS_FreeCString(ctx, func_str); } if (need_free_filename) { LEPUS_FreeCString(ctx, filename_str); } } static void hako_profile_function_end(LEPUSContext *ctx, JSAtom func, JSAtom filename, void *opaque) { __wasi_errno_t err; __wasi_timestamp_t current_time; // Get the current time using WASI err = __wasi_clock_time_get(__WASI_CLOCKID_MONOTONIC, 0, ¤t_time); const char *func_str; int need_free_func = hako_atom_to_str(ctx, func, &func_str, NULL); const char *filename_str; int need_free_filename = hako_atom_to_str(ctx, filename, &filename_str, "file://hako.c"); // Use the shared buffer for formatting the event int written = snprintf(event_buffer, MAX_EVENT_BUFFER_SIZE, "{\"name\": \"%s\",\"cat\": \"js\",\"ph\": \"E\",\"ts\": %llu,\"pid\": 1,\"tid\": 1,\"args\": {\"file\": \"%s\"}}", func_str, current_time / 1000, filename_str); host_profile_function_end(ctx, event_buffer, opaque); // Clean up dynamic strings if (need_free_func) { LEPUS_FreeCString(ctx, func_str); } if (need_free_filename) { LEPUS_FreeCString(ctx, filename_str); } } static struct LEPUSModuleDef *hako_compile_module(LEPUSContext *ctx, CString *module_name, BorrowedHeapChar *module_body) { // Use explicit flags for module compilation int eval_flags = LEPUS_EVAL_TYPE_MODULE | LEPUS_EVAL_FLAG_COMPILE_ONLY | LEPUS_EVAL_FLAG_STRICT; LEPUSValue func_val = LEPUS_Eval(ctx, module_body, strlen(module_body), module_name, eval_flags); if (LEPUS_IsException(func_val)) { return NULL; } // Ensure the result is a module if (!LEPUS_VALUE_IS_MODULE(func_val)) { LEPUS_ThrowTypeError(ctx, "Module '%s' code compiled to non-module object", module_name); LEPUS_FreeValue(ctx, func_val); return NULL; } struct LEPUSModuleDef *module = LEPUS_VALUE_GET_PTR(func_val); LEPUS_FreeValue(ctx, func_val); return module; } static LEPUSModuleDef *hako_load_module(LEPUSContext *ctx, CString *module_name, void *_unused) { LEPUSRuntime *rt = LEPUS_GetRuntime(ctx); char *module_source = host_load_module_source(rt, ctx, module_name); if (module_source == NULL) { LEPUS_ThrowTypeError( ctx, "Module not found: '%s'. Please check that the module name is correct " "and the module is available in your environment.", module_name); return NULL; } LEPUSModuleDef *module = hako_compile_module(ctx, module_name, module_source); free(module_source); return module; } static char *hako_normalize_module(LEPUSContext *ctx, CString *module_base_name, CString *module_name, void *_unused) { LEPUSRuntime *rt = LEPUS_GetRuntime(ctx); char *normalized_module_name = host_normalize_module(rt, ctx, module_base_name, module_name); char *js_module_name = lepus_strdup(ctx, normalized_module_name, 1); free(normalized_module_name); return js_module_name; } static LEPUSValue *jsvalue_to_heap(LEPUSValueConst value) { LEPUSValue *result = malloc(sizeof(LEPUSValue)); if (result) { *result = value; } return result; } LEPUSValue *WASM_EXPORT(HAKO_Throw)(LEPUSContext *ctx, LEPUSValueConst *error) { LEPUSValue copy = LEPUS_DupValue(ctx, *error); return jsvalue_to_heap(LEPUS_Throw(ctx, copy)); } LEPUSValue *WASM_EXPORT(HAKO_NewError)(LEPUSContext *ctx) { return jsvalue_to_heap(LEPUS_NewError(ctx)); } /** * Limits. */ /** * Memory limit. Set to -1 to disable. */ void WASM_EXPORT(HAKO_RuntimeSetMemoryLimit)(LEPUSRuntime *rt, size_t limit) { LEPUS_SetMemoryLimit(rt, limit); } /** * Memory diagnostics */ LEPUSValue *WASM_EXPORT(HAKO_RuntimeComputeMemoryUsage)(LEPUSRuntime *rt, LEPUSContext *ctx) { #if LYNX_SIMPLIFY LEPUSMemoryUsage s; LEPUS_ComputeMemoryUsage(rt, &s); LEPUSValue result = LEPUS_NewObject(ctx); LEPUS_SetPropertyStr(ctx, result, "malloc_limit", LEPUS_NewInt64(ctx, s.malloc_limit)); LEPUS_SetPropertyStr(ctx, result, "memory_used_size", LEPUS_NewInt64(ctx, s.memory_used_size)); LEPUS_SetPropertyStr(ctx, result, "malloc_count", LEPUS_NewInt64(ctx, s.malloc_count)); LEPUS_SetPropertyStr(ctx, result, "memory_used_count", LEPUS_NewInt64(ctx, s.memory_used_count)); LEPUS_SetPropertyStr(ctx, result, "atom_count", LEPUS_NewInt64(ctx, s.atom_count)); LEPUS_SetPropertyStr(ctx, result, "atom_size", LEPUS_NewInt64(ctx, s.atom_size)); LEPUS_SetPropertyStr(ctx, result, "str_count", LEPUS_NewInt64(ctx, s.str_count)); LEPUS_SetPropertyStr(ctx, result, "str_size", LEPUS_NewInt64(ctx, s.str_size)); LEPUS_SetPropertyStr(ctx, result, "obj_count", LEPUS_NewInt64(ctx, s.obj_count)); LEPUS_SetPropertyStr(ctx, result, "obj_size", LEPUS_NewInt64(ctx, s.obj_size)); LEPUS_SetPropertyStr(ctx, result, "prop_count", LEPUS_NewInt64(ctx, s.prop_count)); LEPUS_SetPropertyStr(ctx, result, "prop_size", LEPUS_NewInt64(ctx, s.prop_size)); LEPUS_SetPropertyStr(ctx, result, "shape_count", LEPUS_NewInt64(ctx, s.shape_count)); LEPUS_SetPropertyStr(ctx, result, "shape_size", LEPUS_NewInt64(ctx, s.shape_size)); LEPUS_SetPropertyStr(ctx, result, "lepus_func_count", LEPUS_NewInt64(ctx, s.lepus_func_count)); LEPUS_SetPropertyStr(ctx, result, "lepus_func_size", LEPUS_NewInt64(ctx, s.lepus_func_size)); LEPUS_SetPropertyStr(ctx, result, "lepus_func_code_size", LEPUS_NewInt64(ctx, s.lepus_func_code_size)); LEPUS_SetPropertyStr(ctx, result, "lepus_func_pc2line_count", LEPUS_NewInt64(ctx, s.lepus_func_pc2line_count)); LEPUS_SetPropertyStr(ctx, result, "lepus_func_pc2line_size", LEPUS_NewInt64(ctx, s.lepus_func_pc2line_size)); LEPUS_SetPropertyStr(ctx, result, "c_func_count", LEPUS_NewInt64(ctx, s.c_func_count)); LEPUS_SetPropertyStr(ctx, result, "array_count", LEPUS_NewInt64(ctx, s.array_count)); LEPUS_SetPropertyStr(ctx, result, "fast_array_count", LEPUS_NewInt64(ctx, s.fast_array_count)); LEPUS_SetPropertyStr(ctx, result, "fast_array_elements", LEPUS_NewInt64(ctx, s.fast_array_elements)); LEPUS_SetPropertyStr(ctx, result, "binary_object_count", LEPUS_NewInt64(ctx, s.binary_object_count)); LEPUS_SetPropertyStr(ctx, result, "binary_object_size", LEPUS_NewInt64(ctx, s.binary_object_size)); return jsvalue_to_heap(result); #else LEPUSValue result = LEPUS_NewObject(ctx); return jsvalue_to_heap(result); #endif } OwnedHeapChar *WASM_EXPORT(HAKO_RuntimeDumpMemoryUsage)(LEPUSRuntime *rt) { #if LYNX_SIMPLIFY char *result = malloc(sizeof(char) * 1024); FILE *memfile = fmemopen(result, 1024, "w"); LEPUSMemoryUsage s; LEPUS_ComputeMemoryUsage(rt, &s); LEPUS_DumpMemoryUsage(memfile, &s, rt); fclose(memfile); return result; #else char *result = malloc(sizeof(char) * 1024); snprintf(result, 1024, "Memory usage unavailable - LYNX_SIMPLIFY not defined"); return result; #endif } int WASM_EXPORT(HAKO_RecoverableLeakCheck)() { #ifdef HAKO_SANITIZE_LEAK return __lsan_do_recoverable_leak_check(); #else return 0; #endif } LEPUS_BOOL WASM_EXPORT(HAKO_BuildIsSanitizeLeak)() { #ifdef HAKO_SANITIZE_LEAK return 1; #else return 0; #endif } void WASM_EXPORT(HAKO_RuntimeJSThrow)(LEPUSContext *ctx, CString *message) { LEPUS_ThrowReferenceError(ctx, "%s", message); } void WASM_EXPORT(HAKO_ContextSetMaxStackSize)(LEPUSContext *ctx, size_t stack_size) { LEPUS_SetMaxStackSize(ctx, stack_size); } /** * Constant pointers. Because we always use LEPUSValue* from the host Javascript * environment, we need helper functions to return pointers to these constants. */ LEPUSValueConst HAKO_Undefined = LEPUS_UNDEFINED; LEPUSValueConst *WASM_EXPORT(HAKO_GetUndefined)() { return &HAKO_Undefined; } LEPUSValueConst HAKO_Null = LEPUS_NULL; LEPUSValueConst *WASM_EXPORT(HAKO_GetNull)() { return &HAKO_Null; } LEPUSValueConst HAKO_False = LEPUS_FALSE; LEPUSValueConst *WASM_EXPORT(HAKO_GetFalse)() { return &HAKO_False; } LEPUSValueConst HAKO_True = LEPUS_TRUE; LEPUSValueConst *WASM_EXPORT(HAKO_GetTrue)() { return &HAKO_True; } /** * Standard FFI functions */ void WASM_EXPORT(HAKO_EnableProfileCalls)(LEPUSRuntime *rt, uint32_t sampling, JSVoid *opaque) { #ifdef ENABLE_HAKO_PROFILER JS_EnableProfileCalls(rt, hako_profile_function_start, hako_profile_function_end, sampling, opaque); #endif } LEPUSRuntime *WASM_EXPORT(HAKO_NewRuntime)() { LEPUSRuntime *rt = LEPUS_NewRuntimeWithMode(0); if (rt == NULL) { return NULL; } #ifdef ENABLE_COMPATIBLE_MM #ifdef ENABLE_LEPUSNG LEPUS_SetRuntimeInfo(rt, "Lynx_LepusNG"); #else LEPUS_SetRuntimeInfo(rt, "Lynx_JS"); #endif #else #ifdef ENABLE_LEPUSNG LEPUS_SetRuntimeInfo(rt, "Lynx_LepusNG_RC"); #else LEPUS_SetRuntimeInfo(rt, "Lynx_JS_RC"); #endif #endif return rt; } void WASM_EXPORT(HAKO_FreeRuntime)(LEPUSRuntime *rt) { LEPUS_FreeRuntime(rt); } void WASM_EXPORT(HAKO_SetStripInfo)(LEPUSRuntime *rt, int flags) { LEPUS_SetStripInfo(rt, flags); } int WASM_EXPORT(HAKO_GetStripInfo)(LEPUSRuntime *rt) { return LEPUS_GetStripInfo(rt); } LEPUSContext *WASM_EXPORT(HAKO_NewContext)(LEPUSRuntime *rt, HAKO_Intrinsic intrinsics) { if (intrinsics == 0) { return LEPUS_NewContext(rt); } LEPUSContext *ctx = LEPUS_NewContextRaw(rt); if (ctx == NULL) { return NULL; } if (intrinsics & HAKO_Intrinsic_BaseObjects) { LEPUS_AddIntrinsicBaseObjects(ctx); } if (intrinsics & HAKO_Intrinsic_Date) { LEPUS_AddIntrinsicDate(ctx); } if (intrinsics & HAKO_Intrinsic_Eval) { LEPUS_AddIntrinsicEval(ctx); } if (intrinsics & HAKO_Intrinsic_StringNormalize) { LEPUS_AddIntrinsicStringNormalize(ctx); } if (intrinsics & HAKO_Intrinsic_RegExp) { LEPUS_AddIntrinsicRegExp(ctx); } if (intrinsics & HAKO_Intrinsic_RegExpCompiler) { LEPUS_AddIntrinsicRegExpCompiler(ctx); } if (intrinsics & HAKO_Intrinsic_JSON) { LEPUS_AddIntrinsicJSON(ctx); } if (intrinsics & HAKO_Intrinsic_Proxy) { LEPUS_AddIntrinsicProxy(ctx); } if (intrinsics & HAKO_Intrinsic_MapSet) { LEPUS_AddIntrinsicMapSet(ctx); } if (intrinsics & HAKO_Intrinsic_TypedArrays) { LEPUS_AddIntrinsicTypedArrays(ctx); } if (intrinsics & HAKO_Intrinsic_Promise) { LEPUS_AddIntrinsicPromise(ctx); } return ctx; } void WASM_EXPORT(HAKO_SetContextData)(LEPUSContext *ctx, JSVoid *data) { LEPUS_SetContextOpaque(ctx, data); } JSVoid *WASM_EXPORT(HAKO_GetContextData)(LEPUSContext *ctx) { return LEPUS_GetContextOpaque(ctx); } void WASM_EXPORT(HAKO_SetNoStrictMode)(LEPUSContext *ctx) { LEPUS_SetNoStrictMode(ctx); } void WASM_EXPORT(HAKO_SetVirtualStackSize)(LEPUSContext *ctx, uint32_t size) { LEPUS_SetVirtualStackSize(ctx, size); } void WASM_EXPORT(HAKO_FreeContext)(LEPUSContext *ctx) { LEPUS_FreeContext(ctx); } void WASM_EXPORT(HAKO_FreeValuePointer)(LEPUSContext *ctx, LEPUSValue *value) { if (value == &HAKO_Undefined || value == &HAKO_Null || value == &HAKO_True || value == &HAKO_False) { fprintf(stderr, HAKO_BAD_FREE_MSG, (void *)value); __builtin_trap(); } LEPUS_FreeValue(ctx, *value); free(value); } void WASM_EXPORT(HAKO_FreeValuePointerRuntime)(LEPUSRuntime *rt, LEPUSValue *value) { if (value == &HAKO_Undefined || value == &HAKO_Null || value == &HAKO_True || value == &HAKO_False) { fprintf(stderr, HAKO_BAD_FREE_MSG, (void *)value); __builtin_trap(); } LEPUS_FreeValueRT(rt, *value); free(value); } void WASM_EXPORT(HAKO_FreeVoidPointer)(LEPUSContext *ctx, JSVoid *ptr) { lepus_free(ctx, ptr); } void WASM_EXPORT(HAKO_FreeCString)(LEPUSContext *ctx, JSBorrowedChar *str) { LEPUS_FreeCString(ctx, str); } LEPUSValue *WASM_EXPORT(HAKO_DupValuePointer)(LEPUSContext *ctx, LEPUSValueConst *val) { return jsvalue_to_heap(LEPUS_DupValue(ctx, *val)); } LEPUSValue *WASM_EXPORT(HAKO_NewObject)(LEPUSContext *ctx) { return jsvalue_to_heap(LEPUS_NewObject(ctx)); } LEPUSValue *WASM_EXPORT(HAKO_NewObjectProto)(LEPUSContext *ctx, LEPUSValueConst *proto) { return jsvalue_to_heap(LEPUS_NewObjectProto(ctx, *proto)); } LEPUSValue *WASM_EXPORT(HAKO_NewArray)(LEPUSContext *ctx) { return jsvalue_to_heap(LEPUS_NewArray(ctx)); } void hako_free_buffer(LEPUSRuntime *unused_rt, void *unused_opaque, void *ptr) { free(ptr); } LEPUSValue *WASM_EXPORT(HAKO_NewArrayBuffer)(LEPUSContext *ctx, JSVoid *buffer, size_t length) { return jsvalue_to_heap(LEPUS_NewArrayBuffer(ctx, (uint8_t *)buffer, length, hako_free_buffer, NULL, false)); } LEPUSValue *WASM_EXPORT(HAKO_NewFloat64)(LEPUSContext *ctx, double num) { return jsvalue_to_heap(LEPUS_NewFloat64(ctx, num)); } double WASM_EXPORT(HAKO_GetFloat64)(LEPUSContext *ctx, LEPUSValueConst *value) { double result = NAN; LEPUS_ToFloat64(ctx, &result, *value); return result; } LEPUSValue *WASM_EXPORT(HAKO_NewString)(LEPUSContext *ctx, BorrowedHeapChar *string) { return jsvalue_to_heap(LEPUS_NewString(ctx, string)); } JSBorrowedChar *WASM_EXPORT(HAKO_ToCString)(LEPUSContext *ctx, LEPUSValueConst *value) { return LEPUS_ToCString(ctx, *value); } JSVoid *WASM_EXPORT(HAKO_CopyArrayBuffer)(LEPUSContext *ctx, LEPUSValueConst *data, size_t *out_length) { size_t length; uint8_t *buffer = LEPUS_GetArrayBuffer(ctx, &length, *data); if (!buffer) return 0; uint8_t *result = malloc(length); if (!result) return result; memcpy(result, buffer, length); if (out_length) *out_length = length; return result; } LEPUSValue hako_get_symbol_key(LEPUSContext *ctx, LEPUSValueConst *value) { LEPUSValue global = LEPUS_GetGlobalObject(ctx); LEPUSValue Symbol = LEPUS_GetPropertyStr(ctx, global, "Symbol"); LEPUS_FreeValue(ctx, global); LEPUSValue Symbol_keyFor = LEPUS_GetPropertyStr(ctx, Symbol, "keyFor"); LEPUSValue key = LEPUS_Call(ctx, Symbol_keyFor, Symbol, 1, value); LEPUS_FreeValue(ctx, Symbol_keyFor); LEPUS_FreeValue(ctx, Symbol); return key; } LEPUSValue hako_resolve_func_data(LEPUSContext *ctx, LEPUSValueConst this_val, int argc, LEPUSValueConst *argv, int magic, LEPUSValue *func_data) { return LEPUS_DupValue(ctx, func_data[0]); } LEPUSValue *WASM_EXPORT(HAKO_Eval)(LEPUSContext *ctx, BorrowedHeapChar *js_code, size_t js_code_length, BorrowedHeapChar *filename, EvalDetectModule detectModule, EvalFlags evalFlags) { // Only detect module if detection is enabled and module type isn't already // specified if (detectModule && (evalFlags & LEPUS_EVAL_TYPE_MODULE) == 0) { bool isModule = LEPUS_DetectModule(js_code, js_code_length); if (isModule) { evalFlags |= LEPUS_EVAL_TYPE_MODULE; } } LEPUSModuleDef *module = NULL; LEPUSValue eval_result; bool is_module = (evalFlags & LEPUS_EVAL_TYPE_MODULE) != 0; // Compile and evaluate module code specially if (is_module && (evalFlags & LEPUS_EVAL_FLAG_COMPILE_ONLY) == 0) { LEPUSValue func_obj = LEPUS_Eval(ctx, js_code, js_code_length, filename, evalFlags | LEPUS_EVAL_FLAG_COMPILE_ONLY); if (LEPUS_IsException(func_obj)) { return jsvalue_to_heap(func_obj); } if (!LEPUS_VALUE_IS_MODULE(func_obj)) { LEPUS_FreeValue(ctx, func_obj); return jsvalue_to_heap(LEPUS_ThrowTypeError( ctx, "Module code compiled to non-module object")); } module = LEPUS_VALUE_GET_PTR(func_obj); if (module == NULL) { LEPUS_FreeValue(ctx, func_obj); return jsvalue_to_heap( LEPUS_ThrowTypeError(ctx, "Module compiled to null")); } eval_result = LEPUS_EvalFunction(ctx, func_obj, LEPUS_UNDEFINED); } else { // Regular evaluation for non-module code or compile-only eval_result = LEPUS_Eval(ctx, js_code, js_code_length, filename, evalFlags); } // If we got an exception or not a promise, return it directly if (LEPUS_IsException(eval_result) || !LEPUS_IsPromise(eval_result)) { // For non-promise modules, return the module namespace if (is_module && !LEPUS_IsPromise(eval_result) && !LEPUS_IsException(eval_result)) { LEPUSValue module_namespace = LEPUS_GetModuleNamespace(ctx, module); LEPUS_FreeValue(ctx, eval_result); return jsvalue_to_heap(module_namespace); } // For everything else, return the eval result directly return jsvalue_to_heap(eval_result); } // At this point, we know we're dealing with a promise LEPUSPromiseStateEnum state = LEPUS_PromiseState(ctx, eval_result); // Handle promise based on its state if (state == LEPUS_PROMISE_FULFILLED || state == -1) { // For fulfilled promises with modules, return the namespace if (is_module) { LEPUSValue module_namespace = LEPUS_GetModuleNamespace(ctx, module); LEPUS_FreeValue(ctx, eval_result); return jsvalue_to_heap(module_namespace); } else { // For non-modules, get the promise result LEPUSValue result = LEPUS_PromiseResult(ctx, eval_result); LEPUS_FreeValue(ctx, eval_result); return jsvalue_to_heap(result); } } else if (state == LEPUS_PROMISE_REJECTED) { // For rejected promises, throw the rejection reason LEPUSValue reason = LEPUS_PromiseResult(ctx, eval_result); LEPUS_Throw(ctx, reason); LEPUS_FreeValue(ctx, reason); LEPUS_FreeValue(ctx, eval_result); return jsvalue_to_heap(LEPUS_EXCEPTION); } else if (state == LEPUS_PROMISE_PENDING) { // For pending promises, handle differently based on whether it's a module if (is_module) { LEPUSValue module_namespace = LEPUS_GetModuleNamespace(ctx, module); if (LEPUS_IsException(module_namespace)) { LEPUS_FreeValue(ctx, eval_result); return jsvalue_to_heap(module_namespace); } LEPUSValue then_resolve_module_namespace = LEPUS_NewCFunctionData( ctx, &hako_resolve_func_data, 0, 0, 1, &module_namespace); LEPUS_FreeValue(ctx, module_namespace); if (LEPUS_IsException(then_resolve_module_namespace)) { LEPUS_FreeValue(ctx, eval_result); return jsvalue_to_heap(then_resolve_module_namespace); } LEPUSAtom then_atom = LEPUS_NewAtom(ctx, "then"); LEPUSValueConst then_args[1] = {then_resolve_module_namespace}; LEPUSValue new_promise = LEPUS_Invoke(ctx, eval_result, then_atom, 1, then_args); LEPUS_FreeAtom(ctx, then_atom); LEPUS_FreeValue(ctx, then_resolve_module_namespace); LEPUS_FreeValue(ctx, eval_result); return jsvalue_to_heap(new_promise); } else { // For non-modules, return the promise directly return jsvalue_to_heap(eval_result); } } else { // Unknown promise state, return as is return jsvalue_to_heap(eval_result); } } LEPUSValue *WASM_EXPORT(HAKO_NewSymbol)(LEPUSContext *ctx, BorrowedHeapChar *description, int isGlobal) { LEPUSValue global = LEPUS_GetGlobalObject(ctx); LEPUSValue Symbol = LEPUS_GetPropertyStr(ctx, global, "Symbol"); LEPUS_FreeValue(ctx, global); LEPUSValue descriptionValue = LEPUS_NewString(ctx, description); LEPUSValue symbol; if (isGlobal != 0) { LEPUSValue Symbol_for = LEPUS_GetPropertyStr(ctx, Symbol, "for"); symbol = LEPUS_Call(ctx, Symbol_for, Symbol, 1, &descriptionValue); LEPUS_FreeValue(ctx, descriptionValue); LEPUS_FreeValue(ctx, Symbol_for); LEPUS_FreeValue(ctx, Symbol); return jsvalue_to_heap(symbol); } symbol = LEPUS_Call(ctx, Symbol, LEPUS_UNDEFINED, 1, &descriptionValue); LEPUS_FreeValue(ctx, descriptionValue); LEPUS_FreeValue(ctx, Symbol); return jsvalue_to_heap(symbol); } JSBorrowedChar * WASM_EXPORT(HAKO_GetSymbolDescriptionOrKey)(LEPUSContext *ctx, LEPUSValueConst *value) { JSBorrowedChar *result; LEPUSValue key = hako_get_symbol_key(ctx, value); if (!LEPUS_IsUndefined(key)) { result = LEPUS_ToCString(ctx, key); LEPUS_FreeValue(ctx, key); return result; } LEPUSValue description = LEPUS_GetPropertyStr(ctx, *value, "description"); result = LEPUS_ToCString(ctx, description); LEPUS_FreeValue(ctx, description); return result; } LEPUS_BOOL WASM_EXPORT(HAKO_IsGlobalSymbol)(LEPUSContext *ctx, LEPUSValueConst *value) { LEPUSValue key = hako_get_symbol_key(ctx, value); int undefined = LEPUS_IsUndefined(key); LEPUS_FreeValue(ctx, key); if (undefined) { return 0; } else { return 1; } } LEPUS_BOOL WASM_EXPORT(HAKO_IsJobPending)(LEPUSRuntime *rt) { return LEPUS_IsJobPending(rt); } LEPUSValue *WASM_EXPORT(HAKO_ExecutePendingJob)(LEPUSRuntime *rt, int maxJobsToExecute, LEPUSContext **lastJobContext) { LEPUSContext *pctx; int status = 1; int executed = 0; while (executed != maxJobsToExecute && status == 1) { status = LEPUS_ExecutePendingJob(rt, &pctx); if (status == -1) { *lastJobContext = pctx; return jsvalue_to_heap(LEPUS_GetException(pctx)); } else if (status == 1) { *lastJobContext = pctx; executed++; } } return jsvalue_to_heap(LEPUS_NewFloat64(pctx, executed)); } LEPUSValue *WASM_EXPORT(HAKO_GetProp)(LEPUSContext *ctx, LEPUSValueConst *this_val, LEPUSValueConst *prop_name) { LEPUSAtom prop_atom = LEPUS_ValueToAtom(ctx, *prop_name); LEPUSValue prop_val = LEPUS_GetProperty(ctx, *this_val, prop_atom); LEPUS_FreeAtom(ctx, prop_atom); if (LEPUS_IsException(prop_val)) { return NULL; } return jsvalue_to_heap(prop_val); } LEPUSValue *WASM_EXPORT(HAKO_GetPropNumber)(LEPUSContext *ctx, LEPUSValueConst *this_val, int prop_name) { LEPUSValue prop_val = LEPUS_GetPropertyUint32(ctx, *this_val, (uint32_t)prop_name); if (LEPUS_IsException(prop_val)) { return NULL; } return jsvalue_to_heap(prop_val); } LEPUS_BOOL WASM_EXPORT(HAKO_SetProp)(LEPUSContext *ctx, LEPUSValueConst *this_val, LEPUSValueConst *prop_name, LEPUSValueConst *prop_value) { LEPUSAtom prop_atom = LEPUS_ValueToAtom(ctx, *prop_name); LEPUSValue extra_prop_value = LEPUS_DupValue(ctx, *prop_value); int result = LEPUS_SetProperty(ctx, *this_val, prop_atom, extra_prop_value); LEPUS_FreeAtom(ctx, prop_atom); return result; } LEPUS_BOOL WASM_EXPORT(HAKO_DefineProp)( LEPUSContext *ctx, LEPUSValueConst *this_val, LEPUSValueConst *prop_name, LEPUSValueConst *prop_value, LEPUSValueConst *get, LEPUSValueConst *set, LEPUS_BOOL configurable, LEPUS_BOOL enumerable, LEPUS_BOOL has_value) { LEPUSAtom prop_atom = LEPUS_ValueToAtom(ctx, *prop_name); int flags = 0; if (configurable) { flags = flags | LEPUS_PROP_CONFIGURABLE; if (has_value) { flags = flags | LEPUS_PROP_HAS_CONFIGURABLE; } } if (enumerable) { flags = flags | LEPUS_PROP_ENUMERABLE; if (has_value) { flags = flags | LEPUS_PROP_HAS_ENUMERABLE; } } if (!LEPUS_IsUndefined(*get)) { flags = flags | LEPUS_PROP_HAS_GET; } if (!LEPUS_IsUndefined(*set)) { flags = flags | LEPUS_PROP_HAS_SET; } if (has_value) { flags = flags | LEPUS_PROP_HAS_VALUE; } int result = LEPUS_DefineProperty(ctx, *this_val, prop_atom, *prop_value, *get, *set, flags); LEPUS_FreeAtom(ctx, prop_atom); return result; } static inline bool __JS_AtomIsTaggedInt(LEPUSAtom v) { return (v & LEPUS_ATOM_TAG_INT) != 0; } static inline uint32_t __JS_AtomToUInt32(LEPUSAtom atom) { return atom & ~LEPUS_ATOM_TAG_INT; } LEPUSValue *WASM_EXPORT(HAKO_GetOwnPropertyNames)(LEPUSContext *ctx, LEPUSValue ***out_ptrs, uint32_t *out_len, LEPUSValueConst *obj, int flags) { if (out_ptrs == NULL || out_len == NULL) { return jsvalue_to_heap(LEPUS_ThrowTypeError(ctx, "Invalid arguments")); } if (LEPUS_IsObject(*obj) == false) { return jsvalue_to_heap(LEPUS_ThrowTypeError(ctx, "not an object")); } LEPUSPropertyEnum *tab = NULL; uint32_t total_props = 0; uint32_t out_props = 0; bool hako_standard_compliant_number = (flags & HAKO_STANDARD_COMPLIANT_NUMBER) != 0; bool hako_include_string = (flags & LEPUS_GPN_STRING_MASK) != 0; bool hako_include_number = hako_standard_compliant_number ? 0 : (flags & HAKO_GPN_NUMBER_MASK) != 0; if (hako_include_number) { flags = flags | LEPUS_GPN_STRING_MASK; } int status = 0; status = LEPUS_GetOwnPropertyNames(ctx, &tab, &total_props, *obj, flags); if (status < 0) { if (tab != NULL) { lepus_free(ctx, tab); } return jsvalue_to_heap(LEPUS_GetException(ctx)); } *out_ptrs = malloc(sizeof(LEPUSValue) * *out_len); for (int i = 0; i < total_props; i++) { LEPUSAtom atom = tab[i].atom; if (__JS_AtomIsTaggedInt(atom)) { if (hako_include_number) { uint32_t v = __JS_AtomToUInt32(atom); (*out_ptrs)[out_props++] = jsvalue_to_heap(LEPUS_NewInt32(ctx, v)); } else if (hako_include_string && hako_standard_compliant_number) { (*out_ptrs)[out_props++] = jsvalue_to_heap(LEPUS_AtomToValue(ctx, tab[i].atom)); } LEPUS_FreeAtom(ctx, atom); continue; } LEPUSValue atom_value = LEPUS_AtomToValue(ctx, atom); LEPUS_FreeAtom(ctx, atom); if (LEPUS_IsString(atom_value)) { if (hako_include_string) { (*out_ptrs)[out_props++] = jsvalue_to_heap(atom_value); } else { LEPUS_FreeValue(ctx, atom_value); } } else { (*out_ptrs)[out_props++] = jsvalue_to_heap(atom_value); } } lepus_free(ctx, tab); *out_len = out_props; return NULL; } LEPUSValue *WASM_EXPORT(HAKO_Call)(LEPUSContext *ctx, LEPUSValueConst *func_obj, LEPUSValueConst *this_obj, int argc, LEPUSValueConst **argv_ptrs) { LEPUSValueConst argv[argc]; int i; for (i = 0; i < argc; i++) { argv[i] = *(argv_ptrs[i]); } return jsvalue_to_heap(LEPUS_Call(ctx, *func_obj, *this_obj, argc, argv)); } LEPUSValue *WASM_EXPORT(HAKO_GetLastError)(LEPUSContext *ctx, LEPUSValue *maybe_exception) { // If maybe_exception is provided if (maybe_exception != NULL) { // Only if it's an exception, return the result of GetException if (LEPUS_IsException(*maybe_exception)) { return jsvalue_to_heap(LEPUS_GetException(ctx)); } // If it's provided but not an exception, just return NULL return NULL; } // If maybe_exception is NULL, check if there's an exception in context LEPUSValue exception = LEPUS_GetException(ctx); if (!LEPUS_IsNull(exception)) { return jsvalue_to_heap(exception); } return NULL; } /** * Enhanced dump function with JSON serialization and property enumeration */ JSBorrowedChar *WASM_EXPORT(HAKO_Dump)(LEPUSContext *ctx, LEPUSValueConst *obj) { LEPUSValue error_obj = LEPUS_UNDEFINED; LEPUSValue json_value = LEPUS_UNDEFINED; JSBorrowedChar *result = NULL; // Special handling for Error objects if (LEPUS_IsError(ctx, *obj)) { // Create a plain object to hold error properties error_obj = LEPUS_NewObject(ctx); LEPUSValue current_error = LEPUS_DupValue(ctx, *obj); LEPUSValue current_obj = error_obj; LEPUSValue next_obj; int depth = 0; while (depth < 3) { // Get message property LEPUSValue message = LEPUS_GetPropertyStr(ctx, current_error, "message"); if (!LEPUS_IsException(message) && !LEPUS_IsUndefined(message)) { // Set directly - LEPUS_SetPropertyStr will handle reference counting LEPUS_SetPropertyStr(ctx, current_obj, "message", message); // Don't free message here - SetPropertyStr either increases the ref // count or takes ownership } else { // Only free if we didn't set the property LEPUS_FreeValue(ctx, message); } // Get name property LEPUSValue name = LEPUS_GetPropertyStr(ctx, current_error, "name"); if (!LEPUS_IsException(name) && !LEPUS_IsUndefined(name)) { LEPUS_SetPropertyStr(ctx, current_obj, "name", name); // Don't free name here } else { LEPUS_FreeValue(ctx, name); } // Get stack property LEPUSValue stack = LEPUS_GetPropertyStr(ctx, current_error, "stack"); if (!LEPUS_IsException(stack) && !LEPUS_IsUndefined(stack)) { LEPUS_SetPropertyStr(ctx, current_obj, "stack", stack); // Don't free stack here } else { LEPUS_FreeValue(ctx, stack); } // Check for cause LEPUSValue cause = LEPUS_GetPropertyStr(ctx, current_error, "cause"); if (!LEPUS_IsException(cause) && !LEPUS_IsUndefined(cause) && !LEPUS_IsNull(cause) && LEPUS_IsError(ctx, cause) && depth < 2) // Check depth before going deeper { // Create a new object for the cause next_obj = LEPUS_NewObject(ctx); // Link current object to the cause LEPUS_SetPropertyStr(ctx, current_obj, "cause", next_obj); // Move to next iteration current_obj = next_obj; LEPUS_FreeValue(ctx, current_error); current_error = cause; // Take ownership, don't free depth++; } else { // Handle non-error cause or max depth reached if (!LEPUS_IsException(cause) && !LEPUS_IsUndefined(cause) && !LEPUS_IsNull(cause)) { LEPUS_SetPropertyStr(ctx, current_obj, "cause", cause); // Don't free cause here } else { LEPUS_FreeValue(ctx, cause); } LEPUS_FreeValue(ctx, current_error); break; } } // Use LEPUS_ToJSON to create JSON string json_value = LEPUS_ToJSON(ctx, error_obj, 2); // Indent with 2 spaces LEPUS_FreeValue(ctx, error_obj); if (!LEPUS_IsException(json_value)) { // Convert to C string result = LEPUS_ToCString(ctx, json_value); LEPUS_FreeValue(ctx, json_value); return result; } else { LEPUS_FreeValue(ctx, json_value); } } else { // For non-error objects, try LEPUS_ToJSON directly json_value = LEPUS_ToJSON(ctx, *obj, 2); // Indent with 2 spaces if (!LEPUS_IsException(json_value)) { // Convert to C string result = LEPUS_ToCString(ctx, json_value); LEPUS_FreeValue(ctx, json_value); return result; } else { LEPUS_FreeValue(ctx, json_value); } } // If JSON serialization fails, use a static buffer static char error_buffer[128]; snprintf(error_buffer, sizeof(error_buffer), "{\"error\":\"Failed to serialize object\"}"); return error_buffer; } LEPUSValue * WASM_EXPORT(HAKO_GetModuleNamespace)(LEPUSContext *ctx, LEPUSValueConst *module_func_obj) { if (!LEPUS_VALUE_IS_MODULE(*module_func_obj)) { return jsvalue_to_heap(LEPUS_ThrowTypeError(ctx, "Not a module")); } struct LEPUSModuleDef *module = LEPUS_VALUE_GET_PTR(*module_func_obj); return jsvalue_to_heap(LEPUS_GetModuleNamespace(ctx, module)); } OwnedHeapChar *WASM_EXPORT(HAKO_Typeof)(LEPUSContext *ctx, LEPUSValueConst *value) { CString *result = "unknown"; if (LEPUS_IsUndefined(*value)) { result = "undefined"; } else if (LEPUS_IsNull(*value)) { result = "null"; } else if (LEPUS_IsNumber(*value)) { result = "number"; } #ifdef CONFIG_BIGNUM else if (LEPUS_IsBigInt(*value)) { result = "bigint"; } else if (LEPUS_IsBigFloat(*value)) { result = "bigfloat"; } #endif else if (LEPUS_IsFunction(ctx, *value)) { result = "function"; } else if (LEPUS_IsBool(*value)) { result = "boolean"; } else if (LEPUS_IsNull(*value)) { result = "object"; } else if (LEPUS_IsUninitialized(*value)) { result = "undefined"; } else if (LEPUS_IsString(*value)) { result = "string"; } else if (LEPUS_IsSymbol(*value)) { result = "symbol"; } else if (LEPUS_IsObject(*value)) { result = "object"; } char *out = strdup(result); return out; } LEPUSAtom HAKO_AtomLength = 0; int WASM_EXPORT(HAKO_GetLength)(LEPUSContext *ctx, uint32_t *out_len, LEPUSValueConst *value) { LEPUSValue len_val; int result; if (!LEPUS_IsObject(*value)) { return -1; } if (HAKO_AtomLength == 0) { HAKO_AtomLength = LEPUS_NewAtom(ctx, "length"); } len_val = LEPUS_GetProperty(ctx, *value, HAKO_AtomLength); if (LEPUS_IsException(len_val)) { return -1; } result = LEPUS_ToUint32(ctx, out_len, len_val); LEPUS_FreeValue(ctx, len_val); return result; } LEPUS_BOOL WASM_EXPORT(HAKO_IsEqual)(LEPUSContext *ctx, LEPUSValueConst *a, LEPUSValueConst *b, IsEqualOp op) { switch (op) { case HAKO_EqualOp_SameValue: return LEPUS_SameValue(ctx, *a, *b); case HAKO_EqualOp_SameValueZero: return LEPUS_SameValueZero(ctx, *a, *b); default: case HAKO_EqualOp_StrictEq: return LEPUS_StrictEq(ctx, *a, *b); } } LEPUSValue *WASM_EXPORT(HAKO_GetGlobalObject)(LEPUSContext *ctx) { return jsvalue_to_heap(LEPUS_GetGlobalObject(ctx)); } LEPUSValue * WASM_EXPORT(HAKO_NewPromiseCapability)(LEPUSContext *ctx, LEPUSValue **resolve_funcs_out) { LEPUSValue resolve_funcs[2]; LEPUSValue promise = LEPUS_NewPromiseCapability(ctx, resolve_funcs); resolve_funcs_out[0] = jsvalue_to_heap(resolve_funcs[0]); resolve_funcs_out[1] = jsvalue_to_heap(resolve_funcs[1]); return jsvalue_to_heap(promise); } LEPUS_BOOL WASM_EXPORT(HAKO_IsPromise)(LEPUSContext *ctx, LEPUSValueConst *promise) { return LEPUS_IsPromise(*promise); } LEPUSPromiseStateEnum WASM_EXPORT(HAKO_PromiseState)(LEPUSContext *ctx, LEPUSValueConst *promise) { return LEPUS_PromiseState(ctx, *promise); } LEPUSValue *WASM_EXPORT(HAKO_PromiseResult)(LEPUSContext *ctx, LEPUSValueConst *promise) { return jsvalue_to_heap(LEPUS_PromiseResult(ctx, *promise)); } LEPUS_BOOL WASM_EXPORT(HAKO_BuildIsDebug)() { #ifdef HAKO_DEBUG_MODE return 1; #else return 0; #endif } CString *WASM_EXPORT(HAKO_GetVersion)() { return HAKO_VERSION; } uint64_t WASM_EXPORT(HAKO_GetPrimjsVersion)() { return LEPUS_GetPrimjsVersion(); } // Module loading helpers // C -> Host Callbacks LEPUSValue *hako_host_call_function(LEPUSContext *ctx, LEPUSValueConst *this_ptr, int argc, LEPUSValueConst *argv, uint32_t magic_func_id) { return host_call_function(ctx, this_ptr, argc, argv, magic_func_id); } // Function: PrimJS -> C LEPUSValue hako_call_function(LEPUSContext *ctx, LEPUSValueConst this_val, int argc, LEPUSValueConst *argv, int magic) { LEPUSValue *result_ptr = hako_host_call_function(ctx, &this_val, argc, argv, magic); if (result_ptr == NULL) { return LEPUS_UNDEFINED; } LEPUSValue result = *result_ptr; if (result_ptr == &HAKO_Undefined || result_ptr == &HAKO_Null || result_ptr == &HAKO_True || result_ptr == &HAKO_False) { return result; } free(result_ptr); return result; } LEPUSValue *WASM_EXPORT(HAKO_NewFunction)(LEPUSContext *ctx, uint32_t func_id, CString *name) { LEPUSValue func_obj = LEPUS_NewCFunctionMagic(ctx, hako_call_function, name, 0, LEPUS_CFUNC_constructor_or_func_magic, func_id); return jsvalue_to_heap(func_obj); } LEPUSValueConst * WASM_EXPORT(HAKO_ArgvGetJSValueConstPointer)(LEPUSValueConst *argv, int index) { return &argv[index]; } void WASM_EXPORT(HAKO_RuntimeEnableInterruptHandler)(LEPUSRuntime *rt, JSVoid *opaque) { LEPUS_SetInterruptHandler(rt, host_interrupt_handler, opaque); } void WASM_EXPORT(HAKO_RuntimeDisableInterruptHandler)(LEPUSRuntime *rt) { LEPUS_SetInterruptHandler(rt, NULL, NULL); } void WASM_EXPORT(HAKO_RuntimeEnableModuleLoader)(LEPUSRuntime *rt, LEPUS_BOOL use_custom_normalize) { LEPUSModuleNormalizeFunc *module_normalize = NULL; if (use_custom_normalize) { module_normalize = hako_normalize_module; } LEPUS_SetModuleLoaderFunc(rt, module_normalize, hako_load_module, NULL); } void WASM_EXPORT(HAKO_RuntimeDisableModuleLoader)(LEPUSRuntime *rt) { LEPUS_SetModuleLoaderFunc(rt, NULL, NULL, NULL); } LEPUSValue *WASM_EXPORT(HAKO_bjson_encode)(LEPUSContext *ctx, LEPUSValueConst *val) { size_t length; uint8_t *buffer = LEPUS_WriteObject(ctx, &length, *val, 0); if (!buffer) return jsvalue_to_heap(LEPUS_EXCEPTION); LEPUSValue array = LEPUS_NewArrayBufferCopy(ctx, buffer, length); lepus_free(ctx, buffer); return jsvalue_to_heap(array); } LEPUSValue *WASM_EXPORT(HAKO_bjson_decode)(LEPUSContext *ctx, LEPUSValueConst *data) { size_t length; uint8_t *buffer = LEPUS_GetArrayBuffer(ctx, &length, *data); if (!buffer) return jsvalue_to_heap(LEPUS_EXCEPTION); LEPUSValue value = LEPUS_ReadObject(ctx, buffer, length, 0); return jsvalue_to_heap(value); } LEPUS_BOOL WASM_EXPORT(HAKO_IsArray)(LEPUSContext *ctx, LEPUSValueConst *val) { return LEPUS_IsArray(ctx, *val); } LEPUS_BOOL WASM_EXPORT(HAKO_IsTypedArray)(LEPUSContext *ctx, LEPUSValueConst *val) { return LEPUS_IsTypedArray(ctx, *val); } // there is a super weird bug here where if any string literal contains the // class name (e.g. "Uint8Array") it will be corrupted in memory. HAKO_TypedArrayType WASM_EXPORT(HAKO_GetTypedArrayType)(LEPUSContext *ctx, LEPUSValueConst *val) { LEPUSTypedArrayType type = LEPUS_GetTypedArrayType(ctx, *val); switch (type) { case LEPUS_TYPED_UINT8_ARRAY: return HAKO_TYPED_UINT8_ARRAY; case LEPUS_TYPED_UINT8C_ARRAY: return HAKO_TYPED_UINT8C_ARRAY; case LEPUS_TYPED_INT8_ARRAY: return HAKO_TYPED_INT8_ARRAY; case LEPUS_TYPED_UINT16_ARRAY: return HAKO_TYPED_UINT16_ARRAY; case LEPUS_TYPED_INT16_ARRAY: return HAKO_TYPED_INT16_ARRAY; case LEPUS_TYPED_UINT32_ARRAY: return HAKO_TYPED_UINT32_ARRAY; case LEPUS_TYPED_INT32_ARRAY: return HAKO_TYPED_INT32_ARRAY; case LEPUS_TYPED_FLOAT32_ARRAY: return HAKO_TYPED_FLOAT32_ARRAY; case LEPUS_TYPED_FLOAT64_ARRAY: return HAKO_TYPED_FLOAT64_ARRAY; default: return HAKO_TYPED_UNKNOWN; } } JSVoid *WASM_EXPORT(HAKO_CopyTypedArrayBuffer)(LEPUSContext *ctx, LEPUSValueConst *val, size_t *out_length) { if (LEPUS_GetTypedArrayType(ctx, *val) != LEPUS_TYPED_UINT8_ARRAY) { LEPUS_ThrowTypeError(ctx, "Not a Uint8Array"); return NULL; } size_t byte_offset, byte_length, bytes_per_element; LEPUSValue buffer = LEPUS_GetTypedArrayBuffer( ctx, *val, &byte_offset, &byte_length, &bytes_per_element); if (LEPUS_IsException(buffer)) return NULL; // Now that we have the buffer, get the actual bytes size_t buffer_length; uint8_t *buffer_data = LEPUS_GetArrayBuffer(ctx, &buffer_length, buffer); if (!buffer_data) { LEPUS_FreeValue(ctx, buffer); // Free the buffer value we got return NULL; } // Allocate memory for the result uint8_t *result = malloc(byte_length); if (!result) { LEPUS_FreeValue(ctx, buffer); return NULL; } // Copy the relevant portion of the buffer memcpy(result, buffer_data + byte_offset, byte_length); // Set the output length if requested if (out_length) *out_length = byte_length; // Free the buffer value we obtained LEPUS_FreeValue(ctx, buffer); return result; } LEPUS_BOOL WASM_EXPORT(HAKO_IsArrayBuffer)(LEPUSValueConst *val) { return LEPUS_IsArrayBuffer(*val); } LEPUSValue *WASM_EXPORT(HAKO_ToJson)(LEPUSContext *ctx, LEPUSValueConst *val, int indent) { if (LEPUS_IsUndefined(*val)) { return jsvalue_to_heap(LEPUS_NewString(ctx, "undefined")); } if (LEPUS_IsNull(*val)) { return jsvalue_to_heap(LEPUS_NewString(ctx, "null")); } LEPUSValue result = LEPUS_ToJSON(ctx, *val, indent); if (LEPUS_IsException(result)) { return jsvalue_to_heap(result); } return jsvalue_to_heap(result); } LEPUS_BOOL WASM_EXPORT(HAKO_IsError)(LEPUSContext *ctx, LEPUSValueConst *val) { return LEPUS_IsError(ctx, *val); } LEPUS_BOOL WASM_EXPORT(HAKO_IsException)(LEPUSValueConst *val) { return LEPUS_IsException(*val); } LEPUSValue *WASM_EXPORT(HAKO_GetException)(LEPUSContext *ctx) { return jsvalue_to_heap(LEPUS_GetException(ctx)); } void WASM_EXPORT(SetGCThreshold)(LEPUSRuntime *rt, int64_t threshold) { LEPUS_SetGCThreshold(rt, threshold); } LEPUSValue *WASM_EXPORT(HAKO_NewBigInt)(LEPUSContext *ctx, int32_t low, int32_t high) { #ifdef CONFIG_BIGNUM int64_t combined = ((int64_t)high << 32) | ((uint32_t)low); return jsvalue_to_heap(LEPUS_NewBigInt64(ctx, combined)); #else return jsvalue_to_heap(LEPUS_ThrowTypeError(ctx, "BigInt not supported")); #endif } LEPUSValue *WASM_EXPORT(HAKO_NewBigUInt)(LEPUSContext *ctx, uint32_t low, uint32_t high) { #ifdef CONFIG_BIGNUM uint64_t combined = ((uint64_t)high << 32) | low; return jsvalue_to_heap(LEPUS_NewBigUint64(ctx, combined)); #else return jsvalue_to_heap(LEPUS_ThrowTypeError(ctx, "BigInt not supported")); #endif } LEPUS_BOOL WASM_EXPORT(HAKO_IsGCMode)(LEPUSContext *ctx) { return LEPUS_IsGCMode(ctx); } LEPUSValue *WASM_EXPORT(HAKO_NewDate)(LEPUSContext *ctx, double time) { return jsvalue_to_heap(LEPUS_NewDate(ctx, time)); } LEPUSClassID WASM_EXPORT(HAKO_GetClassID)(LEPUSContext *ctx, LEPUSValueConst *val) { return LEPUS_GetClassID(ctx, *val); } LEPUS_BOOL WASM_EXPORT(HAKO_IsInstanceOf)(LEPUSContext *ctx, LEPUSValueConst *val, LEPUSValueConst *obj) { return LEPUS_IsInstanceOf(ctx, *val, *obj); } HakoBuildInfo *WASM_EXPORT(HAKO_BuildInfo)() { // Return pointer to the existing static structure return &build_info; } void *thread_entry_point(void *ctx) { int id = (int)ctx; printf(" in thread %d\n", id); return 0; } ``` ## /bridge/hako.h ```h path="/bridge/hako.h" #ifndef HAKO_H #define HAKO_H #ifdef __cplusplus extern "C" { #endif #include #include #include #include "quickjs.h" #include "build.h" #define BorrowedHeapChar const char #define OwnedHeapChar char #define JSBorrowedChar const char #define JSVoid void #define CString const char #define EvalFlags int #define EvalDetectModule int #define HAKO_GPN_NUMBER_MASK (1 << 6) #define HAKO_STANDARD_COMPLIANT_NUMBER (1 << 7) #define LEPUS_ATOM_TAG_INT (1U << 31) typedef enum HAKO_Intrinsic { HAKO_Intrinsic_BaseObjects = 1 << 0, HAKO_Intrinsic_Date = 1 << 1, HAKO_Intrinsic_Eval = 1 << 2, HAKO_Intrinsic_StringNormalize = 1 << 3, HAKO_Intrinsic_RegExp = 1 << 4, HAKO_Intrinsic_RegExpCompiler = 1 << 5, HAKO_Intrinsic_JSON = 1 << 6, HAKO_Intrinsic_Proxy = 1 << 7, HAKO_Intrinsic_MapSet = 1 << 8, HAKO_Intrinsic_TypedArrays = 1 << 9, HAKO_Intrinsic_Promise = 1 << 10, HAKO_Intrinsic_BigInt = 1 << 11, HAKO_Intrinsic_BigFloat = 1 << 12, HAKO_Intrinsic_BigDecimal = 1 << 13, HAKO_Intrinsic_OperatorOverloading = 1 << 14, HAKO_Intrinsic_BignumExt = 1 << 15 } HAKO_Intrinsic; typedef enum { HAKO_TYPED_UNKNOWN = 0, HAKO_TYPED_UINT8_ARRAY = 1, HAKO_TYPED_UINT8C_ARRAY = 2, HAKO_TYPED_INT8_ARRAY = 3, HAKO_TYPED_UINT16_ARRAY = 4, HAKO_TYPED_INT16_ARRAY = 5, HAKO_TYPED_UINT32_ARRAY = 6, HAKO_TYPED_INT32_ARRAY = 7, HAKO_TYPED_FLOAT32_ARRAY = 8, HAKO_TYPED_FLOAT64_ARRAY = 9 } HAKO_TypedArrayType; typedef enum IsEqualOp { HAKO_EqualOp_StrictEq = 0, HAKO_EqualOp_SameValue = 1, HAKO_EqualOp_SameValueZero = 2 } IsEqualOp; /** * @brief Creates a new Hako runtime * @category Runtime Management * * @return LEPUSRuntime* - Pointer to the newly created runtime * @tsreturn JSRuntimePointer */ LEPUSRuntime *HAKO_NewRuntime(); /** * @brief Frees a Hako runtime and associated resources * @category Runtime Management * * @param rt Runtime to free * @tsparam rt JSRuntimePointer */ void HAKO_FreeRuntime(LEPUSRuntime *rt); /** * @brief Configure which debug info is stripped from the compiled code * @category Runtime Management * * @param rt Runtime to configure * @param flags Flags to configure stripping behavior * @tsparam rt JSRuntimePointer * @tsparam flags number */ void HAKO_SetStripInfo(LEPUSRuntime *rt, int flags); /** * @brief Get the current debug info stripping configuration * @category Runtime Management * * @param rt Runtime to query * @return int - Current stripping flags * @tsparam rt JSRuntimePointer * @tsreturn number */ int HAKO_GetStripInfo(LEPUSRuntime *rt); /** * @brief Sets memory limit for the runtime * @category Runtime Management * * @param rt Runtime to set the limit for * @param limit Memory limit in bytes, or -1 to disable limit * @tsparam rt JSRuntimePointer * @tsparam limit number */ void HAKO_RuntimeSetMemoryLimit(LEPUSRuntime *rt, size_t limit); /** * @brief Computes memory usage statistics for the runtime * @category Memory * * @param rt Runtime to compute statistics for * @param ctx Context to use for creating the result object * @return LEPUSValue* - Object containing memory usage statistics * @tsparam rt JSRuntimePointer * @tsparam ctx JSContextPointer * @tsreturn JSValuePointer */ LEPUSValue *HAKO_RuntimeComputeMemoryUsage(LEPUSRuntime *rt, LEPUSContext *ctx); /** * @brief Dumps memory usage statistics as a string * @category Memory * * @param rt Runtime to dump statistics for * @return OwnedHeapChar* - String containing memory usage information * @tsparam rt JSRuntimePointer * @tsreturn CString */ OwnedHeapChar *HAKO_RuntimeDumpMemoryUsage(LEPUSRuntime *rt); /** * @brief Checks if there are pending promise jobs in the runtime * @category Promise * * @param rt Runtime to check * @return LEPUS_BOOL - True if jobs are pending, false otherwise * @tsparam rt JSRuntimePointer * @tsreturn LEPUS_BOOL */ LEPUS_BOOL HAKO_IsJobPending(LEPUSRuntime *rt); /** * @brief Executes pending promise jobs in the runtime * @category Promise * * @param rt Runtime to execute jobs in * @param maxJobsToExecute Maximum number of jobs to execute * @param lastJobContext Pointer to store the context of the last executed job * @return LEPUSValue* - Number of executed jobs or an exception * @tsparam rt JSRuntimePointer * @tsparam maxJobsToExecute number * @tsparam lastJobContext number * @tsreturn JSValuePointer */ LEPUSValue *HAKO_ExecutePendingJob(LEPUSRuntime *rt, int maxJobsToExecute, LEPUSContext **lastJobContext); /** * @brief Enables interrupt handler for the runtime * @category Interrupt Handling * * @param rt Runtime to enable interrupt handler for * @param opaque Pointer to user-defined data * @tsparam rt JSRuntimePointer * @tsparam opaque number */ void HAKO_RuntimeEnableInterruptHandler(LEPUSRuntime *rt, JSVoid *opaque); /** * @brief Disables interrupt handler for the runtime * @category Interrupt Handling * * @param rt Runtime to disable interrupt handler for * @tsparam rt JSRuntimePointer */ void HAKO_RuntimeDisableInterruptHandler(LEPUSRuntime *rt); /** * @brief Enables module loader for the runtime * @category Module Loading * * @param rt Runtime to enable module loader for * @param use_custom_normalize Whether to use custom module name normalization * @tsparam rt JSRuntimePointer * @tsparam use_custom_normalize number */ void HAKO_RuntimeEnableModuleLoader(LEPUSRuntime *rt, LEPUS_BOOL use_custom_normalize); /** * @brief Disables module loader for the runtime * @category Module Loading * * @param rt Runtime to disable module loader for * @tsparam rt JSRuntimePointer */ void HAKO_RuntimeDisableModuleLoader(LEPUSRuntime *rt); /** * @brief Throws a JavaScript reference error with a message * @category Error Handling * * @param ctx Context to throw the error in * @param message Error message * @tsparam ctx JSContextPointer * @tsparam message CString */ void HAKO_RuntimeJSThrow(LEPUSContext *ctx, CString *message); /** * @brief Creates a new JavaScript context * @category Context Management * * @param rt Runtime to create the context in * @param intrinsics HAKO_Intrinsic flags to enable * @return LEPUSContext* - Newly created context * @tsparam rt JSRuntimePointer * @tsparam intrinsics number * @tsreturn JSContextPointer */ LEPUSContext *HAKO_NewContext(LEPUSRuntime *rt, HAKO_Intrinsic intrinsics); /** * @brief sets opaque data for the context. you are responsible for freeing the data. * @category Context Management * * @param ctx Context to set the data for * @param data Pointer to the data * @tsparam ctx JSContextPointer * @tsparam data number */ void HAKO_SetContextData(LEPUSContext *ctx, JSVoid *data); /** * @brief Gets opaque data for the context * @category Context Management * * @param ctx Context to get the data from * @return JSVoid* - Pointer to the data * @tsparam ctx JSContextPointer * @tsreturn number */ JSVoid *HAKO_GetContextData(LEPUSContext *ctx); /** * @brief If no_lepus_strict_mode is set to true, these conditions will handle, differently: if the object is null or undefined, read properties will return null if the object is null or undefined, write properties will not throw exception. * @category Context Management * * @param ctx Context to set to no strict mode * @tsparam ctx JSContextPointer */ void HAKO_SetNoStrictMode(LEPUSContext *ctx); /** * @brief Sets the virtual stack size for a context * @category Context Management * * @param ctx Context to set the stack size for * @param size Stack size in bytes * @tsparam ctx JSContextPointer * @tsparam size number */ void HAKO_SetVirtualStackSize(LEPUSContext *ctx, uint32_t size); /** * @brief Frees a JavaScript context * @category Context Management * * @param ctx Context to free * @tsparam ctx JSContextPointer */ void HAKO_FreeContext(LEPUSContext *ctx); /** * @brief Sets the maximum stack size for a context * @category Context Management * * @param ctx Context to configure * @param stack_size Maximum stack size in bytes * @tsparam ctx JSContextPointer * @tsparam stack_size number */ void HAKO_ContextSetMaxStackSize(LEPUSContext *ctx, size_t stack_size); /** * @brief Gets a pointer to the undefined value * @category Constants * * @return LEPUSValueConst* - Pointer to the undefined value * @tsreturn JSValueConstPointer */ LEPUSValueConst *HAKO_GetUndefined(); /** * @brief Gets a pointer to the null value * @category Constants * * @return LEPUSValueConst* - Pointer to the null value * @tsreturn JSValueConstPointer */ LEPUSValueConst *HAKO_GetNull(); /** * @brief Gets a pointer to the false value * @category Constants * * @return LEPUSValueConst* - Pointer to the false value * @tsreturn JSValueConstPointer */ LEPUSValueConst *HAKO_GetFalse(); /** * @brief Gets a pointer to the true value * @category Constants * * @return LEPUSValueConst* - Pointer to the true value * @tsreturn JSValueConstPointer */ LEPUSValueConst *HAKO_GetTrue(); /** * @brief Duplicates a JavaScript value pointer * @category Value Management * * @param ctx Context to use * @param val Value to duplicate * @return LEPUSValue* - Pointer to the duplicated value * @tsparam ctx JSContextPointer * @tsparam val JSValueConstPointer * @tsreturn JSValuePointer */ LEPUSValue *HAKO_DupValuePointer(LEPUSContext *ctx, LEPUSValueConst *val); /** * @brief Frees a JavaScript value pointer * @category Value Management * * @param ctx Context the value belongs to * @param value Value pointer to free * @tsparam ctx JSContextPointer * @tsparam value JSValuePointer */ void HAKO_FreeValuePointer(LEPUSContext *ctx, LEPUSValue *value); /** * @brief Frees a JavaScript value pointer using a runtime * @category Value Management * * @param rt Runtime the value belongs to * @param value Value pointer to free * @tsparam rt JSRuntimePointer * @tsparam value JSValuePointer */ void HAKO_FreeValuePointerRuntime(LEPUSRuntime *rt, LEPUSValue *value); /** * @brief Frees a void pointer managed by a context * @category Value Management * * @param ctx Context that allocated the pointer * @param ptr Pointer to free * @tsparam ctx JSContextPointer * @tsparam ptr number */ void HAKO_FreeVoidPointer(LEPUSContext *ctx, JSVoid *ptr); /** * @brief Frees a C string managed by a context * @category Value Management * * @param ctx Context that allocated the string * @param str String to free * @tsparam ctx JSContextPointer * @tsparam str CString */ void HAKO_FreeCString(LEPUSContext *ctx, JSBorrowedChar *str); /** * @brief Throws a JavaScript error * @category Error Handling * * @param ctx Context to throw in * @param error Error to throw * @return LEPUSValue* - LEPUS_EXCEPTION * @tsparam ctx JSContextPointer * @tsparam error JSValueConstPointer * @tsreturn JSValuePointer */ LEPUSValue *HAKO_Throw(LEPUSContext *ctx, LEPUSValueConst *error); /** * @brief Creates a new Error object * @category Value Creation * * @param ctx Context to create in * @return LEPUSValue* - New Error object * @tsparam ctx JSContextPointer * @tsreturn JSValuePointer */ LEPUSValue *HAKO_NewError(LEPUSContext *ctx); /** * @brief Resolves the the last exception from a context, and returns its Error. Cannot be called twice. * @category Error Handling * * @param ctx Context to resolve in * @param maybe_exception Value that might be an exception * @return LEPUSValue* - Error object or NULL if not an exception * @tsparam ctx JSContextPointer * @tsparam maybe_exception JSValuePointer * @tsreturn JSValuePointer */ LEPUSValue *HAKO_GetLastError(LEPUSContext *ctx, LEPUSValue *maybe_exception); /** * @brief Creates a new empty object * @category Value Creation * * @param ctx Context to create in * @return LEPUSValue* - New object * @tsparam ctx JSContextPointer * @tsreturn JSValuePointer */ LEPUSValue *HAKO_NewObject(LEPUSContext *ctx); /** * @brief Creates a new object with specified prototype * @category Value Creation * * @param ctx Context to create in * @param proto Prototype object * @return LEPUSValue* - New object * @tsparam ctx JSContextPointer * @tsparam proto JSValueConstPointer * @tsreturn JSValuePointer */ LEPUSValue *HAKO_NewObjectProto(LEPUSContext *ctx, LEPUSValueConst *proto); /** * @brief Creates a new array * @category Value Creation * * @param ctx Context to create in * @return LEPUSValue* - New array * @tsparam ctx JSContextPointer * @tsreturn JSValuePointer */ LEPUSValue *HAKO_NewArray(LEPUSContext *ctx); /** * @brief Creates a new array buffer using existing memory * @category Value Creation * * @param ctx Context to create in * @param buffer Buffer to use * @param length Buffer length in bytes * @return LEPUSValue* - New ArrayBuffer * @tsparam ctx JSContextPointer * @tsparam buffer number * @tsparam length number * @tsreturn JSValuePointer */ LEPUSValue *HAKO_NewArrayBuffer(LEPUSContext *ctx, JSVoid *buffer, size_t length); /** * @brief Gets a property value by name * @category Value Operations * * @param ctx Context to use * @param this_val Object to get property from * @param prop_name Property name * @return LEPUSValue* - Property value * @tsparam ctx JSContextPointer * @tsparam this_val JSValueConstPointer * @tsparam prop_name JSValueConstPointer * @tsreturn JSValuePointer */ LEPUSValue *HAKO_GetProp(LEPUSContext *ctx, LEPUSValueConst *this_val, LEPUSValueConst *prop_name); /** * @brief Gets a property value by numeric index * @category Value Operations * * @param ctx Context to use * @param this_val Object to get property from * @param prop_name Property index * @return LEPUSValue* - Property value * @tsparam ctx JSContextPointer * @tsparam this_val JSValueConstPointer * @tsparam prop_name number * @tsreturn JSValuePointer */ LEPUSValue *HAKO_GetPropNumber(LEPUSContext *ctx, LEPUSValueConst *this_val, int prop_name); /** * @brief Sets a property value * @category Value Operations * * @param ctx Context to use * @param this_val Object to set property on * @param prop_name Property name * @param prop_value Property value * @return LEPUS_BOOL - True if successful, false otherwise, -1 if exception * @tsparam ctx JSContextPointer * @tsparam this_val JSValueConstPointer * @tsparam prop_name JSValueConstPointer * @tsparam prop_value JSValueConstPointer * @tsreturn LEPUS_BOOL */ LEPUS_BOOL HAKO_SetProp(LEPUSContext *ctx, LEPUSValueConst *this_val, LEPUSValueConst *prop_name, LEPUSValueConst *prop_value); /** * @brief Defines a property with custom attributes * @category Value Operations * * @param ctx Context to use * @param this_val Object to define property on * @param prop_name Property name * @param prop_value Property value * @param get Getter function or undefined * @param set Setter function or undefined * @param configurable Whether property is configurable * @param enumerable Whether property is enumerable * @param has_value Whether property has a value * @return LEPUS_BOOL - True if successful, false otherwise, -1 if exception * @tsparam ctx JSContextPointer * @tsparam this_val JSValueConstPointer * @tsparam prop_name JSValueConstPointer * @tsparam prop_value JSValueConstPointer * @tsparam get JSValueConstPointer * @tsparam set JSValueConstPointer * @tsparam configurable LEPUS_BOOL * @tsparam enumerable LEPUS_BOOL * @tsparam has_value LEPUS_BOOL * @tsreturn LEPUS_BOOL */ LEPUS_BOOL HAKO_DefineProp(LEPUSContext *ctx, LEPUSValueConst *this_val, LEPUSValueConst *prop_name, LEPUSValueConst *prop_value, LEPUSValueConst *get, LEPUSValueConst *set, LEPUS_BOOL configurable, LEPUS_BOOL enumerable, LEPUS_BOOL has_value); /** * @brief Gets all own property names of an object * @category Value Operations * * @param ctx Context to use * @param out_ptrs Pointer to array to store property names * @param out_len Pointer to store length of property names array * @param obj Object to get property names from * @param flags Property name flags * @return LEPUSValue* - Exception if error occurred, NULL otherwise * @tsparam ctx JSContextPointer * @tsparam out_ptrs number * @tsparam out_len number * @tsparam obj JSValueConstPointer * @tsparam flags number * @tsreturn JSValuePointer */ LEPUSValue *HAKO_GetOwnPropertyNames(LEPUSContext *ctx, LEPUSValue ***out_ptrs, uint32_t *out_len, LEPUSValueConst *obj, int flags); /** * @brief Gets the global object * @category Value Operations * * @param ctx Context to get global object from * @return LEPUSValue* - Global object * @tsparam ctx JSContextPointer * @tsreturn JSValuePointer */ LEPUSValue *HAKO_GetGlobalObject(LEPUSContext *ctx); /** * @brief Gets the length of an object (array length or string length) * @category Value Operations * * @param ctx Context to use * @param out_len Pointer to store length * @param value Object to get length from * @return int - 0 on success, negative on error * @tsparam ctx JSContextPointer * @tsparam out_len number * @tsparam value JSValueConstPointer * @tsreturn number */ int HAKO_GetLength(LEPUSContext *ctx, uint32_t *out_len, LEPUSValueConst *value); /** * @brief Creates a new floating point number * @category Value Creation * * @param ctx Context to create in * @param num Number value * @return LEPUSValue* - New number * @tsparam ctx JSContextPointer * @tsparam num number * @tsreturn JSValuePointer */ LEPUSValue *HAKO_NewFloat64(LEPUSContext *ctx, double num); /** * @brief Creates a new BigInt number * @category Value Creation * * @param ctx Context to create in * @param low Low 32 bits of the number * @param high High 32 bits of the number * @return LEPUSValue* - New BigInt * @tsparam ctx JSContextPointer * @tsparam low number * @tsparam high number * @tsreturn JSValuePointer */ LEPUSValue *HAKO_NewBigInt(LEPUSContext *ctx, int32_t low, int32_t high); /** * @brief Creates a new BigUInt number * @category Value Creation * * @param ctx Context to create in * @param low Low 32 bits of the number * @param high High 32 bits of the number * @return LEPUSValue* - New BigUInt * @tsparam ctx JSContextPointer * @tsparam low number * @tsparam high number * @tsreturn JSValuePointer */ LEPUSValue *HAKO_NewBigUInt(LEPUSContext *ctx, uint32_t low, uint32_t high); /** * @brief Sets the garbage collection threshold * @category Memory Management * * @param ctx Context to set the threshold for * @param threshold Threshold in bytes * @tsparam ctx JSContextPointer * @tsparam threshold number */ void HAKO_SetGCThreshold(LEPUSContext *ctx, int64_t threshold); /** * @brief Checks if the context is in garbage collection mode * @category Memory Management * * @param ctx Context to check * @return LEPUS_BOOL - True if in GC mode, false otherwise * @tsparam ctx JSContextPointer * @tsreturn LEPUS_BOOL */ LEPUS_BOOL HAKO_IsGCMode(LEPUSContext *ctx); /** * @brief Gets the floating point value of a number * @category Value Operations * * @param ctx Context to use * @param value Value to convert * @return double - Number value * @tsparam ctx JSContextPointer * @tsparam value JSValueConstPointer * @tsreturn number */ double HAKO_GetFloat64(LEPUSContext *ctx, LEPUSValueConst *value); /** * @brief Creates a new string * @category Value Creation * * @param ctx Context to create in * @param string String content * @return LEPUSValue* - New string * @tsparam ctx JSContextPointer * @tsparam string CString * @tsreturn JSValuePointer */ LEPUSValue *HAKO_NewString(LEPUSContext *ctx, BorrowedHeapChar *string); /** * @brief Gets the C string representation of a value * @category Value Operations * * @param ctx Context to use * @param value Value to convert * @return JSBorrowedChar* - String representation * @tsparam ctx JSContextPointer * @tsparam value JSValueConstPointer * @tsreturn CString */ JSBorrowedChar *HAKO_ToCString(LEPUSContext *ctx, LEPUSValueConst *value); /** * @brief Creates a new symbol * @category Value Creation * * @param ctx Context to create in * @param description Symbol description * @param isGlobal Whether to create a global symbol * @return LEPUSValue* - New symbol * @tsparam ctx JSContextPointer * @tsparam description CString * @tsparam isGlobal number * @tsreturn JSValuePointer */ LEPUSValue *HAKO_NewSymbol(LEPUSContext *ctx, BorrowedHeapChar *description, int isGlobal); /** * @brief Gets the description or key of a symbol * @category Value Operations * * @param ctx Context to use * @param value Symbol to get description from * @return JSBorrowedChar* - Symbol description or key * @tsparam ctx JSContextPointer * @tsparam value JSValueConstPointer * @tsreturn CString */ JSBorrowedChar *HAKO_GetSymbolDescriptionOrKey(LEPUSContext *ctx, LEPUSValueConst *value); /** * @brief Checks if a symbol is global * @category Value Operations * * @param ctx Context to use * @param value Symbol to check * @return LEPUS_BOOL - True if symbol is global, false otherwise * @tsparam ctx JSContextPointer * @tsparam value JSValueConstPointer * @tsreturn LEPUS_BOOL */ LEPUS_BOOL HAKO_IsGlobalSymbol(LEPUSContext *ctx, LEPUSValueConst *value); /** * @brief Gets the type of a value as a string * @category Value Operations * * @param ctx Context to use * @param value Value to get type of * @return OwnedHeapChar* - Type name * @tsparam ctx JSContextPointer * @tsparam value JSValueConstPointer * @tsreturn OwnedHeapChar */ OwnedHeapChar *HAKO_Typeof(LEPUSContext *ctx, LEPUSValueConst *value); /** * @brief Checks if a value is an array * @category Value Operations * * @param ctx Context to use * @param value Value to check * @return LEPUS_BOOL - True if value is an array, false otherwise (-1 if error) * @tsparam ctx JSContextPointer * @tsparam value JSValueConstPointer * @tsreturn LEPUS_BOOL */ LEPUS_BOOL HAKO_IsArray(LEPUSContext *ctx, LEPUSValueConst *value); /** * @brief Checks if a value is a typed array * @category Value Operations * * @param ctx Context to use * @param value Value to check * @return LEPUS_BOOL - True if value is a typed array, false otherwise (-1 if error) * @tsparam ctx JSContextPointer * @tsparam value JSValueConstPointer * @tsreturn LEPUS_BOOL */ LEPUS_BOOL HAKO_IsTypedArray(LEPUSContext *ctx, LEPUSValueConst *value); /** * @brief Gets the type of a typed array * @category Value Operations * * @param ctx Context to use * @param value Typed array to get type of * @return HAKO_TypedArrayType - Type id * @tsparam ctx JSContextPointer * @tsparam value JSValueConstPointer * @tsreturn number */ HAKO_TypedArrayType HAKO_GetTypedArrayType(LEPUSContext *ctx, LEPUSValueConst *value); /** * @brief Checks if a value is an ArrayBuffer * @category Value Operations * * @param value Value to check * @return LEPUS_BOOL - True if value is an ArrayBuffer, false otherwise (-1 if error) * @tsparam value JSValueConstPointer * @tsreturn LEPUS_BOOL */ LEPUS_BOOL HAKO_IsArrayBuffer(LEPUSValueConst *value); /** * @brief Checks if two values are equal according to the specified operation * @category Value Operations * * @param ctx Context to use * @param a First value * @param b Second value * @param op Equal operation type * @return LEPUS_BOOL - True if values are equal, false otherwise * @tsparam ctx JSContextPointer * @tsparam a JSValueConstPointer * @tsparam b JSValueConstPointer * @tsparam op number * @tsreturn LEPUS_BOOL */ LEPUS_BOOL HAKO_IsEqual(LEPUSContext *ctx, LEPUSValueConst *a, LEPUSValueConst *b, IsEqualOp op); /** * @brief Copy the buffer from a guest ArrayBuffer * @category Value Operations * * @param ctx Context to use * @param data ArrayBuffer to get buffer from * @param out_len Pointer to store length of the buffer * @return JSVoid* - Buffer pointer * @tsparam ctx JSContextPointer * @tsparam data JSValueConstPointer * @tsparam out_len number * @tsreturn number */ JSVoid *HAKO_CopyArrayBuffer(LEPUSContext *ctx, LEPUSValueConst *data, size_t *out_len); /** * @brief Copy the buffer pointer from a TypedArray * @category Value Operations * * @param ctx Context to use * @param data TypedArray to get buffer from * @param out_len Pointer to store length of the buffer * @return JSVoid* - Buffer pointer * @tsparam ctx JSContextPointer * @tsparam data JSValueConstPointer * @tsparam out_len number * @tsreturn number */ JSVoid *HAKO_CopyTypedArrayBuffer(LEPUSContext *ctx, LEPUSValueConst *data, size_t *out_len); /** * @brief Creates a new function with a host function ID * @category Value Creation * * @param ctx Context to create in * @param func_id Function ID to call on the host * @param name Function name * @return LEPUSValue* - New function * @tsparam ctx JSContextPointer * @tsparam func_id number * @tsparam name CString * @tsreturn JSValuePointer */ LEPUSValue *HAKO_NewFunction(LEPUSContext *ctx, uint32_t func_id, CString *name); /** * @brief Calls a function * @category Value Operations * * @param ctx Context to use * @param func_obj Function to call * @param this_obj This value * @param argc Number of arguments * @param argv_ptrs Array of argument pointers * @return LEPUSValue* - Function result * @tsparam ctx JSContextPointer * @tsparam func_obj JSValueConstPointer * @tsparam this_obj JSValueConstPointer * @tsparam argc number * @tsparam argv_ptrs number * @tsreturn JSValuePointer */ LEPUSValue *HAKO_Call(LEPUSContext *ctx, LEPUSValueConst *func_obj, LEPUSValueConst *this_obj, int argc, LEPUSValueConst **argv_ptrs); /** * @brief Gets a JavaScript value from an argv array * @category Value Operations * * @param argv Array of values * @param index Index to get * @return LEPUSValueConst* - Value at index * @tsparam argv number * @tsparam index number * @tsreturn JSValueConstPointer */ LEPUSValueConst *HAKO_ArgvGetJSValueConstPointer(LEPUSValueConst *argv, int index); /** * @brief Evaluates JavaScript code * @category Eval * * @param ctx Context to evaluate in * @param js_code Code to evaluate * @param js_code_length Code length * @param filename Filename for error reporting * @param detectModule Whether to auto-detect module code * @param evalFlags Evaluation flags * @return LEPUSValue* - Evaluation result * @tsparam ctx JSContextPointer * @tsparam js_code CString * @tsparam js_code_length number * @tsparam filename CString * @tsparam detectModule number * @tsparam evalFlags number * @tsreturn JSValuePointer */ LEPUSValue *HAKO_Eval(LEPUSContext *ctx, BorrowedHeapChar *js_code, size_t js_code_length, BorrowedHeapChar *filename, EvalDetectModule detectModule, EvalFlags evalFlags); /** * @brief Creates a new promise capability * @category Promise * * @param ctx Context to create in * @param resolve_funcs_out Array to store resolve and reject functions * @return LEPUSValue* - New promise * @tsparam ctx JSContextPointer * @tsparam resolve_funcs_out number * @tsreturn JSValuePointer */ LEPUSValue *HAKO_NewPromiseCapability(LEPUSContext *ctx, LEPUSValue **resolve_funcs_out); /** * @brief Checks if a value is a promise * @category Promise * * @param ctx Context to use * @param promise Value to check * @return LEPUS_BOOL - True if value is a promise, false otherwise * @tsparam ctx JSContextPointer * @tsparam promise JSValueConstPointer * @tsreturn LEPUS_BOOL */ LEPUS_BOOL HAKO_IsPromise(LEPUSContext *ctx, LEPUSValueConst *promise); /** * @brief Gets the state of a promise * @category Promise * * @param ctx Context to use * @param promise Promise to get state from * @return LEPUSPromiseStateEnum - Promise state * @tsparam ctx JSContextPointer * @tsparam promise JSValueConstPointer * @tsreturn number */ LEPUSPromiseStateEnum HAKO_PromiseState(LEPUSContext *ctx, LEPUSValueConst *promise); /** * @brief Gets the result value of a promise * @category Promise * * @param ctx Context to use * @param promise Promise to get result from * @return LEPUSValue* - Promise result * @tsparam ctx JSContextPointer * @tsparam promise JSValueConstPointer * @tsreturn JSValuePointer */ LEPUSValue *HAKO_PromiseResult(LEPUSContext *ctx, LEPUSValueConst *promise); /** * @brief Gets the namespace object of a module * @category Module Loading * * @param ctx Context to use * @param module_func_obj Module function object * @return LEPUSValue* - Module namespace * @tsparam ctx JSContextPointer * @tsparam module_func_obj JSValueConstPointer * @tsreturn JSValuePointer */ LEPUSValue *HAKO_GetModuleNamespace(LEPUSContext *ctx, LEPUSValueConst *module_func_obj); /** * @brief Dumps a value to a JSON string * @category Value Operations * * @param ctx Context to use * @param obj Value to dump * @return JSBorrowedChar* - JSON string representation * @tsparam ctx JSContextPointer * @tsparam obj JSValueConstPointer * @tsreturn CString */ JSBorrowedChar *HAKO_Dump(LEPUSContext *ctx, LEPUSValueConst *obj); /** * @brief Checks if the build is a debug build * @category Debug & Info * * @return LEPUS_BOOL - True if debug build, false otherwise * @tsreturn LEPUS_BOOL */ LEPUS_BOOL HAKO_BuildIsDebug(); /** * @brief Checks if the build has leak sanitizer enabled * @category Debug & Info * * @return LEPUS_BOOL - True if leak sanitizer is enabled, false otherwise * @tsreturn LEPUS_BOOL */ LEPUS_BOOL HAKO_BuildIsSanitizeLeak(); /** * @brief Performs a recoverable leak check * @category Debug & Info * * @return int - Result of leak check * @tsreturn number */ int HAKO_RecoverableLeakCheck(); /** * @brief Gets the version string * @category Debug & Info * * @return CString* - Version string * @tsreturn CString */ CString *HAKO_GetVersion(); /** * @brief Gets the PrimJS version number * @category Debug & Info * * @return uint64_t - PrimJS version * @tsreturn bigint */ uint64_t HAKO_GetPrimjsVersion(); /** * @brief Encodes a value to binary JSON format * @category Binary JSON * * @param ctx Context to use * @param val Value to encode * @return LEPUSValue* - ArrayBuffer containing encoded data * @tsparam ctx JSContextPointer * @tsparam val JSValueConstPointer * @tsreturn JSValuePointer */ LEPUSValue *HAKO_bjson_encode(LEPUSContext *ctx, LEPUSValueConst *val); /** * @brief Decodes a value from binary JSON format * @category Binary JSON * * @param ctx Context to use * @param data ArrayBuffer containing encoded data * @return LEPUSValue* - Decoded value * @tsparam ctx JSContextPointer * @tsparam data JSValueConstPointer * @tsreturn JSValuePointer */ LEPUSValue *HAKO_bjson_decode(LEPUSContext *ctx, LEPUSValueConst *data); /** * @brief Covnerts a value to JSON format * @category Value Operations * * @param ctx Context to use * @param val Value to stringify * @param indent Indentation level * @return LEPUSValue* - JSON string representation * @tsparam ctx JSContextPointer * @tsparam val JSValueConstPointer * @tsparam indent number * @tsreturn JSValuePointer */ LEPUSValue *HAKO_ToJson(LEPUSContext *ctx, LEPUSValueConst *val, int indent); /** * @brief Checks if a value is an Error * @category Error Handling * * @param ctx Context to use * @param val Value to check * @return LEPUS_BOOL - 1 if value is an error, 0 otherwise * @tsparam ctx JSContextPointer * @tsparam val JSValueConstPointer * @tsreturn LEPUS_BOOL */ LEPUS_BOOL HAKO_IsError(LEPUSContext *ctx, LEPUSValueConst *val); /** * @brief Checks if a value is an exception * @category Error Handling * * @param val Value to check * @return LEPUS_BOOL - 1 if value is an exception, 0 otherwise * @tsparam val JSValueConstPointer * @tsreturn LEPUS_BOOL */ LEPUS_BOOL HAKO_IsException(LEPUSValueConst *val); /** * @brief Creates a new date object * @category Value Creation * * @param ctx Context to create in * @param time Time value * @return LEPUSValue* - New date object * @tsparam ctx JSContextPointer * @tsparam time number * @tsreturn JSValuePointer */ LEPUSValue *HAKO_NewDate(LEPUSContext *ctx, double time); /** * @brief Gets the class ID of a value * @category Value Operations * * @param ctx Context to use * @param val Value to get class ID from * @return LEPUSClassID - Class ID of the value (0 if not a class) * @tsparam ctx JSContextPointer * @tsparam val JSValueConstPointer * @tsreturn number */ LEPUSClassID HAKO_GetClassID(LEPUSContext *ctx, LEPUSValueConst *val); /** * @brief Checks if a value is an instance of a class * @category Value Operations * * @param ctx Context to use * @param val Value to check * @param obj Class object to check against * @return LEPUS_BOOL TRUE, FALSE or (-1) in case of exception * @tsparam ctx JSContextPointer * @tsparam val JSValueConstPointer * @tsparam obj JSValueConstPointer * @tsreturn LEPUS_BOOL */ LEPUS_BOOL HAKO_IsInstanceOf(LEPUSContext *ctx, LEPUSValueConst *val, LEPUSValueConst *obj); /** * @brief Gets the build information * @category Debug & Info * * @return HakoBuildInfo* - Pointer to build information * @tsreturn number */ HakoBuildInfo *HAKO_BuildInfo(); /** * @brief Enables profiling of function calls * @category Debug & Info * * @param rt Runtime to enable profiling for * @param sampling Sampling rate - If sampling == 0, it's interpreted as "no sampling" which means we log 1/1 calls. * @param opaque Opaque data to pass to the callback * @tsparam rt JSRuntimePointer * @tsparam sampling number * @tsparam opaque number * @tsreturn void */ void HAKO_EnableProfileCalls(LEPUSRuntime *rt, uint32_t sampling, JSVoid *opaque); #ifdef HAKO_DEBUG_MODE #define HAKO_LOG(msg) hako_log(msg) #else #define HAKO_LOG(msg) ((void)0) #endif #ifdef __cplusplus } #endif #endif /* HAKO_H */ ``` ## /embedders/ts/.gitignore ```gitignore path="/embedders/ts/.gitignore" # Dependencies node_modules .pnp .pnp.js # Build output dist build *.tsbuildinfo # Logs logs *.log npm-debug.log* yarn-debug.log* yarn-error.log* pnpm-debug.log* # Test coverage coverage # Editor directories and files .vscode/* !.vscode/extensions.json !.vscode/settings.json .idea .DS_Store ``` ## /embedders/ts/README.md

Hako logo

Hako (ha-ko) or 箱 means “box” in Japanese.

[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://www.apache.org/licenses/LICENSE-2.0.txt) Hako is a embeddable, lightweight, secure, high-performance JavaScript engine. It is a fork of PrimJS; Hako has full support for ES2019 and later ESNext features, and offers superior performance and a better development experience when compared to QuickJS.
## Installation ```bash npm install hakojs ``` ## Runtime and Context Lifecycle Creating and properly disposing of runtimes and contexts: ```javascript import { createHakoRuntime, decodeVariant, HAKO_PROD } from "hakojs"; // Initialize with the WASM binary const wasmBinary = decodeVariant(HAKO_PROD); const runtime = await createHakoRuntime({ wasm: { io: { stdout: (lines) => console.log(lines), stderr: (lines) => console.error(lines), } }, loader: { binary: wasmBinary, } }); // Create a JavaScript execution context const vm = runtime.createContext(); // Always clean up resources when done vm.release(); runtime.release(); // Modern JavaScript using the Disposable pattern using runtime = await createHakoRuntime({...}); using vm = runtime.createContext(); ``` ## Code Evaluation ```javascript // Evaluate simple expressions using result = vm.evalCode("1 + 2"); if (!result.error) { const value = result.unwrap(); console.log(value.asNumber()); // 3 } // Using unwrapResult for error handling try { using successResult = vm.evalCode("40 + 2"); const value = vm.unwrapResult(successResult); console.log(value.asNumber()); // 42 } catch (error) { console.error("Error:", error); } // Evaluating with custom filename using result = vm.evalCode("1 + 2", { fileName: "test.js" }); ``` ## Resource Management ### VMValue Lifecycle ```javascript // Always dispose VMValues when no longer needed const strVal = vm.newString("hello"); try { // Use strVal... console.log(strVal.asString()); } finally { strVal.dispose(); } // Using statement with TypeScript 5.2+ using numVal = vm.newNumber(42.5); console.log(numVal.asNumber()); // Automatically disposed at end of scope ``` ### Creating and Managing Objects ```javascript using obj = vm.newObject(); // Set properties using nameVal = vm.newString("test"); using numVal = vm.newNumber(42); obj.setProperty("name", nameVal); obj.setProperty("value", numVal); // Get properties using retrievedName = obj.getProperty("name"); using retrievedValue = obj.getProperty("value"); console.log(retrievedName.asString()); // "test" console.log(retrievedValue.asNumber()); // 42 ``` ### Working with Arrays ```javascript const arr = vm.newArray(); // Add elements arr.setProperty(0, "hello"); arr.setProperty(1, 42); arr.setProperty(2, true); // Get length const lengthProp = arr.getProperty("length"); console.log(lengthProp.asNumber()); // 3 // Get elements const elem0 = arr.getProperty(0); const elem1 = arr.getProperty(1); const elem2 = arr.getProperty(2); console.log(elem0.asString()); // "hello" console.log(elem1.asNumber()); // 42 console.log(elem2.asBoolean()); // true // Always clean up resources arr.dispose(); elem0.dispose(); elem1.dispose(); elem2.dispose(); lengthProp.dispose(); ``` ## Converting Between JavaScript and VM Values ```javascript // Convert JavaScript values to VM values using testString = vm.newValue("hello"); using testNumber = vm.newValue(42.5); using testBool = vm.newValue(true); using testNull = vm.newValue(null); using testUndefined = vm.newValue(undefined); using testArray = vm.newValue([1, "two", true]); using testObj = vm.newValue({ name: "test", value: 42 }); using testBuffer = vm.newValue(new Uint8Array([1, 2, 3])); // Convert VM values to JavaScript values using str = vm.newString("hello"); using jsVal = str.toNativeValue(); console.log(jsVal.value); // "hello" jsVal.dispose(); // Always dispose NativeBox // Complex conversions using obj = vm.newObject(); obj.setProperty("name", "test"); obj.setProperty("value", 42); using objJS = obj.toNativeValue(); console.log(objJS.value); // { name: "test", value: 42 } objJS.dispose(); ``` ## Working with Functions ```javascript // Create a function in the VM using func = vm.newFunction("add", (a, b) => { return vm.newNumber(a.asNumber() + b.asNumber()); }); // Call the function using arg1 = vm.newNumber(5); using arg2 = vm.newNumber(7); using result = vm.callFunction(func, vm.undefined(), arg1, arg2); console.log(result.unwrap().asNumber()); // 12 ``` ## Error Handling ```javascript // Create and throw errors const errorMsg = new Error("Test error message"); using error = vm.newError(errorMsg); using exception = vm.throwError(error); const lastError = vm.getLastError(exception); console.log(lastError.message); // "Test error message" // Throw errors from strings using thrownError = vm.throwError("Direct error message"); const lastError = vm.getLastError(thrownError); console.log(lastError.message); // "Direct error message" // Handle evaluation errors using result = vm.evalCode('throw new Error("Test exception");'); if (result.error) { console.error("Evaluation failed:", vm.getLastError(result.error)); } else { // Use result.unwrap()... } ``` ## Promise Handling ```javascript // Example: Using promises with a fake file system const fakeFileSystem = new Map([["example.txt", "Example file content"]]); using readFileHandle = vm.newFunction("readFile", (pathHandle) => { const path = pathHandle.asString(); pathHandle.dispose(); // Create a promise const promise = vm.newPromise(); // Resolve it asynchronously setTimeout(() => { const content = fakeFileSystem.get(path); using contentHandle = vm.newString(content || ""); promise.resolve(contentHandle); // IMPORTANT: Execute pending jobs after resolving promise.settled.then(() => vm.runtime.executePendingJobs()); }, 100); return promise.handle; }); // Register the function in the global object using glob = vm.getGlobalObject(); glob.setProperty("readFile", readFileHandle); // Use the function in async code using result = vm.evalCode(`(async () => { const content = await readFile('example.txt') return content; })()`); // Resolve the promise in host JavaScript using promiseHandle = vm.unwrapResult(result); using resolvedResult = await vm.resolvePromise(promiseHandle); using resolvedHandle = vm.unwrapResult(resolvedResult); console.log(resolvedHandle.asString()); // "Example file content" ``` Sure, I'll add the map iterator example and update the module example to show calling the exported function. ## Iterating Maps with getIterator ```javascript // Create a Map in the VM using result = vm.evalCode(` const map = new Map(); map.set("key1", "value1"); map.set("key2", "value2"); map; `); using map = result.unwrap(); // Iterate over the map entries for (using entriesBox of vm.getIterator(map).unwrap()) { using entriesHandle = entriesBox.unwrap(); using keyHandle = entriesHandle.getProperty(0).toNativeValue(); using valueHandle = entriesHandle.getProperty(1).toNativeValue(); // Process key-value pairs if (keyHandle.value === "key1") { console.log(valueHandle.value); // "value1" } if (keyHandle.value === "key2") { console.log(valueHandle.value); // "value2" } } ``` ## Working with ES Modules ```javascript // Setup a module loader const moduleMap = new Map([ ["my-module", ` export const hello = (name) => { return "Hello, " + name + "!"; } `] ]); // Enable module loading runtime.enableModuleLoader((moduleName) => { return moduleMap.get(moduleName) || null; }); // Use modules in code using result = vm.evalCode(` import { hello } from 'my-module'; export const sayGoodbye = (name) => { return "Goodbye, " + name + "!"; } export const greeting = hello("World"); `, { type: "module" }); // Access exported values using jsValue = result.unwrap(); using jsObject = jsValue.toNativeValue(); console.log(jsObject.value.greeting); // "Hello, World!" // Call exported function directly console.log(jsObject.value.sayGoodbye("Tester")); // "Goodbye, Tester!" ``` ```javascript // Setup a module loader const moduleMap = new Map([ ["my-module", ` export const hello = (name) => { return "Hello, " + name + "!"; } `] ]); // Enable module loading runtime.enableModuleLoader((moduleName) => { return moduleMap.get(moduleName) || null; }); // Use modules in code using result = vm.evalCode(` import { hello } from 'my-module'; export const sayGoodbye = (name) => { return "Goodbye, " + name + "!"; } export const greeting = hello("World"); `, { type: "module" }); // Access exported values using jsValue = result.unwrap(); using jsObject = jsValue.toNativeValue(); console.log(jsObject.value.greeting); // "Hello, World!" ``` ## Monitoring and Control ```javascript // Add an interrupt handler to prevent infinite loops const handler = runtime.createGasInterruptHandler(1000); runtime.enableInterruptHandler(handler); // Set memory constraints vm.setMaxStackSize(1024 * 1024); // 1MB stack limit // Enable profiling const traceProfiler = createTraceProfiler(); // See implementation in the docs runtime.enableProfileCalls(traceProfiler); ``` ## Binary Data Transfer ```javascript // Working with ArrayBuffers const data = new Uint8Array([1, 2, 3, 4, 5]); using arrBuf = vm.newArrayBuffer(data); // Get the data back const retrievedData = arrBuf.copyArrayBuffer(); console.log(new Uint8Array(retrievedData)); // Uint8Array([1, 2, 3, 4, 5]) // Binary JSON serialization using obj = vm.newValue({ string: "hello", number: 42, boolean: true, array: [1, 2, 3], nested: { a: 1, b: 2 }, }); // Encode to binary JSON const encoded = vm.bjsonEncode(obj); // Decode from binary JSON using decoded = vm.bjsonDecode(encoded); ``` ## Memory Management Best Practices 1. **Always dispose VMValues** when they're no longer needed 2. **Use the `using` statement** when possible (TypeScript 5.2+) 3. **Check for `.error` in results** before unwrapping them 4. **Call `runtime.executePendingJobs()`** after resolving promises 5. **Release contexts and runtimes** when they're no longer needed 6. **Be careful with circular references** when converting between VM and JS values 7. **Use `vm.unwrapResult()`** to handle errors consistently ## Note If you're targeting a JavaScript runtime or browser that doesn't support `using` statements, you will need to use Rollup, Babel, or esbuild to transpile your code to a compatible version. The `using` statement is a TypeScript 5.2+ feature that allows for automatic resource management and it is used extensively inside Hako. ## /embedders/ts/biome.json ```json path="/embedders/ts/biome.json" { "$schema": "https://biomejs.dev/schemas/1.9.4/schema.json", "organizeImports": { "enabled": true }, "linter": { "ignore": ["tests", "src/variants/**/*.*", "node_modules/**/*.*", "dist/**/*.*"], "enabled": true, "rules": { "recommended": true } }, "formatter": { "include": ["src/**/*.js", "src/**/*.ts", "tests/**/*.js", "tests/**/*.ts"], "ignore": ["node_modules/**/*.*", "dist/**/*.*", "src/variants/**/*.*"], "enabled": true, "indentWidth": 2, "indentStyle": "space" }, "javascript": { "formatter": { "quoteStyle": "double", "trailingCommas": "es5", "semicolons": "always" } } } ``` ## /embedders/ts/build.ts ```ts path="/embedders/ts/build.ts" // Build script for the library import { build } from "esbuild"; import { existsSync, mkdirSync } from "node:fs"; if (!existsSync("./dist")) { mkdirSync("./dist"); } console.log("🔨 Building library..."); try { await build({ entryPoints: ["src/index.ts"], outdir: "dist", bundle: true, format: "esm", sourcemap: true, minify: false, platform: "neutral", target: "esnext" }); console.log("✅ Build completed successfully!"); } catch (error) { console.error("❌ Build failed:", error); process.exit(1); } ``` ## /embedders/ts/package-lock.json ```json path="/embedders/ts/package-lock.json" { "name": "hakojs", "version": "0.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "hakojs", "version": "0.0.0", "license": "MIT", "dependencies": { "uwasi": "1.4.0" }, "devDependencies": { "@types/node": "22.13.14", "esbuild": "0.25.1", "tsc-alias": "1.8.15", "typescript": "5.8.2", "vitest": "3.0.9", "zx": "8.5.2" } }, "node_modules/@esbuild/darwin-arm64": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.1.tgz", "integrity": "sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ==", "cpu": [ "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { "node": ">=18" } }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", "dev": true, "license": "MIT" }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" }, "engines": { "node": ">= 8" } }, "node_modules/@nodelib/fs.stat": { "version": "2.0.5", "dev": true, "license": "MIT", "engines": { "node": ">= 8" } }, "node_modules/@nodelib/fs.walk": { "version": "1.2.8", "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" }, "engines": { "node": ">= 8" } }, "node_modules/@rollup/rollup-darwin-arm64": { "version": "4.40.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.40.0.tgz", "integrity": "sha512-GwYOcOakYHdfnjjKwqpTGgn5a6cUX7+Ra2HeNj/GdXvO2VJOOXCiYYlRFU4CubFM67EhbmzLOmACKEfvp3J1kQ==", "cpu": [ "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@types/estree": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", "dev": true, "license": "MIT" }, "node_modules/@types/node": { "version": "22.13.14", "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.14.tgz", "integrity": "sha512-Zs/Ollc1SJ8nKUAgc7ivOEdIBM8JAKgrqqUYi2J997JuKO7/tpQC+WCetQ1sypiKCQWHdvdg9wBNpUPEWZae7w==", "dev": true, "license": "MIT", "dependencies": { "undici-types": "~6.20.0" } }, "node_modules/@vitest/expect": { "version": "3.0.9", "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.0.9.tgz", "integrity": "sha512-5eCqRItYgIML7NNVgJj6TVCmdzE7ZVgJhruW0ziSQV4V7PvLkDL1bBkBdcTs/VuIz0IxPb5da1IDSqc1TR9eig==", "dev": true, "license": "MIT", "dependencies": { "@vitest/spy": "3.0.9", "@vitest/utils": "3.0.9", "chai": "^5.2.0", "tinyrainbow": "^2.0.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/mocker": { "version": "3.0.9", "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.0.9.tgz", "integrity": "sha512-ryERPIBOnvevAkTq+L1lD+DTFBRcjueL9lOUfXsLfwP92h4e+Heb+PjiqS3/OURWPtywfafK0kj++yDFjWUmrA==", "dev": true, "license": "MIT", "dependencies": { "@vitest/spy": "3.0.9", "estree-walker": "^3.0.3", "magic-string": "^0.30.17" }, "funding": { "url": "https://opencollective.com/vitest" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^5.0.0 || ^6.0.0" }, "peerDependenciesMeta": { "msw": { "optional": true }, "vite": { "optional": true } } }, "node_modules/@vitest/pretty-format": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.1.1.tgz", "integrity": "sha512-dg0CIzNx+hMMYfNmSqJlLSXEmnNhMswcn3sXO7Tpldr0LiGmg3eXdLLhwkv2ZqgHb/d5xg5F7ezNFRA1fA13yA==", "dev": true, "license": "MIT", "dependencies": { "tinyrainbow": "^2.0.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/runner": { "version": "3.0.9", "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.0.9.tgz", "integrity": "sha512-NX9oUXgF9HPfJSwl8tUZCMP1oGx2+Sf+ru6d05QjzQz4OwWg0psEzwY6VexP2tTHWdOkhKHUIZH+fS6nA7jfOw==", "dev": true, "license": "MIT", "dependencies": { "@vitest/utils": "3.0.9", "pathe": "^2.0.3" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/snapshot": { "version": "3.0.9", "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.0.9.tgz", "integrity": "sha512-AiLUiuZ0FuA+/8i19mTYd+re5jqjEc2jZbgJ2up0VY0Ddyyxg/uUtBDpIFAy4uzKaQxOW8gMgBdAJJ2ydhu39A==", "dev": true, "license": "MIT", "dependencies": { "@vitest/pretty-format": "3.0.9", "magic-string": "^0.30.17", "pathe": "^2.0.3" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/snapshot/node_modules/@vitest/pretty-format": { "version": "3.0.9", "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.0.9.tgz", "integrity": "sha512-OW9F8t2J3AwFEwENg3yMyKWweF7oRJlMyHOMIhO5F3n0+cgQAJZBjNgrF8dLwFTEXl5jUqBLXd9QyyKv8zEcmA==", "dev": true, "license": "MIT", "dependencies": { "tinyrainbow": "^2.0.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/spy": { "version": "3.0.9", "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.0.9.tgz", "integrity": "sha512-/CcK2UDl0aQ2wtkp3YVWldrpLRNCfVcIOFGlVGKO4R5eajsH393Z1yiXLVQ7vWsj26JOEjeZI0x5sm5P4OGUNQ==", "dev": true, "license": "MIT", "dependencies": { "tinyspy": "^3.0.2" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/utils": { "version": "3.0.9", "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.0.9.tgz", "integrity": "sha512-ilHM5fHhZ89MCp5aAaM9uhfl1c2JdxVxl3McqsdVyVNN6JffnEen8UMCdRTzOhGXNQGo5GNL9QugHrz727Wnng==", "dev": true, "license": "MIT", "dependencies": { "@vitest/pretty-format": "3.0.9", "loupe": "^3.1.3", "tinyrainbow": "^2.0.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@vitest/utils/node_modules/@vitest/pretty-format": { "version": "3.0.9", "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.0.9.tgz", "integrity": "sha512-OW9F8t2J3AwFEwENg3yMyKWweF7oRJlMyHOMIhO5F3n0+cgQAJZBjNgrF8dLwFTEXl5jUqBLXd9QyyKv8zEcmA==", "dev": true, "license": "MIT", "dependencies": { "tinyrainbow": "^2.0.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/@yarnpkg/lockfile": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==", "dev": true, "license": "BSD-2-Clause" }, "node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { "color-convert": "^2.0.1" }, "engines": { "node": ">=8" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/anymatch": { "version": "3.1.3", "dev": true, "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" }, "engines": { "node": ">= 8" } }, "node_modules/array-union": { "version": "2.1.0", "dev": true, "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/assertion-error": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", "dev": true, "license": "MIT", "engines": { "node": ">=12" } }, "node_modules/at-least-node": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", "dev": true, "license": "ISC", "engines": { "node": ">= 4.0.0" } }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true, "license": "MIT" }, "node_modules/binary-extensions": { "version": "2.3.0", "dev": true, "license": "MIT", "engines": { "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" } }, "node_modules/braces": { "version": "3.0.3", "dev": true, "license": "MIT", "dependencies": { "fill-range": "^7.1.1" }, "engines": { "node": ">=8" } }, "node_modules/cac": { "version": "6.7.14", "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", "dev": true, "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/call-bind": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", "get-intrinsic": "^1.2.4", "set-function-length": "^1.2.2" }, "engines": { "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" }, "engines": { "node": ">= 0.4" } }, "node_modules/call-bound": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" }, "engines": { "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/chai": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/chai/-/chai-5.2.0.tgz", "integrity": "sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==", "dev": true, "license": "MIT", "dependencies": { "assertion-error": "^2.0.1", "check-error": "^2.1.1", "deep-eql": "^5.0.1", "loupe": "^3.1.0", "pathval": "^2.0.0" }, "engines": { "node": ">=12" } }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" }, "engines": { "node": ">=10" }, "funding": { "url": "https://github.com/chalk/chalk?sponsor=1" } }, "node_modules/check-error": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", "dev": true, "license": "MIT", "engines": { "node": ">= 16" } }, "node_modules/chokidar": { "version": "3.6.0", "dev": true, "license": "MIT", "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", "glob-parent": "~5.1.2", "is-binary-path": "~2.1.0", "is-glob": "~4.0.1", "normalize-path": "~3.0.0", "readdirp": "~3.6.0" }, "engines": { "node": ">= 8.10.0" }, "funding": { "url": "https://paulmillr.com/funding/" }, "optionalDependencies": { "fsevents": "~2.3.2" } }, "node_modules/ci-info": { "version": "3.9.0", "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", "dev": true, "funding": [ { "type": "github", "url": "https://github.com/sponsors/sibiraj-s" } ], "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" }, "engines": { "node": ">=7.0.0" } }, "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true, "license": "MIT" }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true, "license": "MIT" }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" }, "engines": { "node": ">= 8" } }, "node_modules/debug": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" }, "engines": { "node": ">=6.0" }, "peerDependenciesMeta": { "supports-color": { "optional": true } } }, "node_modules/deep-eql": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", "dev": true, "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/define-data-property": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", "dev": true, "license": "MIT", "dependencies": { "es-define-property": "^1.0.0", "es-errors": "^1.3.0", "gopd": "^1.0.1" }, "engines": { "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/dir-glob": { "version": "3.0.1", "dev": true, "license": "MIT", "dependencies": { "path-type": "^4.0.0" }, "engines": { "node": ">=8" } }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" }, "engines": { "node": ">= 0.4" } }, "node_modules/es-define-property": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/es-errors": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/es-module-lexer": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.6.0.tgz", "integrity": "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==", "dev": true, "license": "MIT" }, "node_modules/es-object-atoms": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0" }, "engines": { "node": ">= 0.4" } }, "node_modules/esbuild": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.1.tgz", "integrity": "sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==", "dev": true, "hasInstallScript": true, "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, "engines": { "node": ">=18" }, "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.1", "@esbuild/android-arm": "0.25.1", "@esbuild/android-arm64": "0.25.1", "@esbuild/android-x64": "0.25.1", "@esbuild/darwin-arm64": "0.25.1", "@esbuild/darwin-x64": "0.25.1", "@esbuild/freebsd-arm64": "0.25.1", "@esbuild/freebsd-x64": "0.25.1", "@esbuild/linux-arm": "0.25.1", "@esbuild/linux-arm64": "0.25.1", "@esbuild/linux-ia32": "0.25.1", "@esbuild/linux-loong64": "0.25.1", "@esbuild/linux-mips64el": "0.25.1", "@esbuild/linux-ppc64": "0.25.1", "@esbuild/linux-riscv64": "0.25.1", "@esbuild/linux-s390x": "0.25.1", "@esbuild/linux-x64": "0.25.1", "@esbuild/netbsd-arm64": "0.25.1", "@esbuild/netbsd-x64": "0.25.1", "@esbuild/openbsd-arm64": "0.25.1", "@esbuild/openbsd-x64": "0.25.1", "@esbuild/sunos-x64": "0.25.1", "@esbuild/win32-arm64": "0.25.1", "@esbuild/win32-ia32": "0.25.1", "@esbuild/win32-x64": "0.25.1" } }, "node_modules/estree-walker": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", "dev": true, "license": "MIT", "dependencies": { "@types/estree": "^1.0.0" } }, "node_modules/expect-type": { "version": "1.2.1", "dev": true, "license": "Apache-2.0", "engines": { "node": ">=12.0.0" } }, "node_modules/fast-glob": { "version": "3.3.3", "dev": true, "license": "MIT", "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", "glob-parent": "^5.1.2", "merge2": "^1.3.0", "micromatch": "^4.0.8" }, "engines": { "node": ">=8.6.0" } }, "node_modules/fastq": { "version": "1.19.1", "dev": true, "license": "ISC", "dependencies": { "reusify": "^1.0.4" } }, "node_modules/fill-range": { "version": "7.1.1", "dev": true, "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, "engines": { "node": ">=8" } }, "node_modules/find-yarn-workspace-root": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/find-yarn-workspace-root/-/find-yarn-workspace-root-2.0.0.tgz", "integrity": "sha512-1IMnbjt4KzsQfnhnzNd8wUEgXZ44IzZaZmnLYx7D5FZlaHt2gW20Cri8Q+E/t5tIj4+epTBub+2Zxu/vNILzqQ==", "dev": true, "license": "Apache-2.0", "dependencies": { "micromatch": "^4.0.2" } }, "node_modules/fs-extra": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", "dev": true, "license": "MIT", "dependencies": { "at-least-node": "^1.0.0", "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", "universalify": "^2.0.0" }, "engines": { "node": ">=10" } }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true, "license": "ISC" }, "node_modules/fsevents": { "version": "2.3.3", "dev": true, "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/get-intrinsic": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/get-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", "dev": true, "license": "MIT", "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" }, "engines": { "node": ">= 0.4" } }, "node_modules/get-tsconfig": { "version": "4.10.0", "dev": true, "license": "MIT", "dependencies": { "resolve-pkg-maps": "^1.0.0" }, "funding": { "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" } }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Glob versions prior to v9 are no longer supported", "dev": true, "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", "minimatch": "^3.1.1", "once": "^1.3.0", "path-is-absolute": "^1.0.0" }, "engines": { "node": "*" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, "node_modules/glob-parent": { "version": "5.1.2", "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.1" }, "engines": { "node": ">= 6" } }, "node_modules/globby": { "version": "11.1.0", "dev": true, "license": "MIT", "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", "fast-glob": "^3.2.9", "ignore": "^5.2.0", "merge2": "^1.4.1", "slash": "^3.0.0" }, "engines": { "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true, "license": "ISC" }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/has-property-descriptors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dev": true, "license": "MIT", "dependencies": { "es-define-property": "^1.0.0" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/has-symbols": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/hasown": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dev": true, "license": "MIT", "dependencies": { "function-bind": "^1.1.2" }, "engines": { "node": ">= 0.4" } }, "node_modules/ignore": { "version": "5.3.2", "dev": true, "license": "MIT", "engines": { "node": ">= 4" } }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dev": true, "license": "ISC", "dependencies": { "once": "^1.3.0", "wrappy": "1" } }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true, "license": "ISC" }, "node_modules/is-binary-path": { "version": "2.1.0", "dev": true, "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" }, "engines": { "node": ">=8" } }, "node_modules/is-docker": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", "dev": true, "license": "MIT", "bin": { "is-docker": "cli.js" }, "engines": { "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/is-extglob": { "version": "2.1.1", "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/is-glob": { "version": "4.0.3", "dev": true, "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" }, "engines": { "node": ">=0.10.0" } }, "node_modules/is-number": { "version": "7.0.0", "dev": true, "license": "MIT", "engines": { "node": ">=0.12.0" } }, "node_modules/is-wsl": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", "dev": true, "license": "MIT", "dependencies": { "is-docker": "^2.0.0" }, "engines": { "node": ">=8" } }, "node_modules/isarray": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", "dev": true, "license": "MIT" }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "dev": true, "license": "ISC" }, "node_modules/json-stable-stringify": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.2.1.tgz", "integrity": "sha512-Lp6HbbBgosLmJbjx0pBLbgvx68FaFU1sdkmBuckmhhJ88kL13OA51CDtR2yJB50eCNMH9wRqtQNNiAqQH4YXnA==", "dev": true, "license": "MIT", "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "isarray": "^2.0.5", "jsonify": "^0.0.1", "object-keys": "^1.1.1" }, "engines": { "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/jsonfile": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", "dev": true, "license": "MIT", "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "node_modules/jsonify": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz", "integrity": "sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==", "dev": true, "license": "Public Domain", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/klaw-sync": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/klaw-sync/-/klaw-sync-6.0.0.tgz", "integrity": "sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ==", "dev": true, "license": "MIT", "dependencies": { "graceful-fs": "^4.1.11" } }, "node_modules/loupe": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.3.tgz", "integrity": "sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==", "dev": true, "license": "MIT" }, "node_modules/magic-string": { "version": "0.30.17", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", "dev": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0" } }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/merge2": { "version": "1.4.1", "dev": true, "license": "MIT", "engines": { "node": ">= 8" } }, "node_modules/micromatch": { "version": "4.0.8", "dev": true, "license": "MIT", "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { "node": ">=8.6" } }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, "engines": { "node": "*" } }, "node_modules/minimist": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true, "license": "MIT" }, "node_modules/mylas": { "version": "2.1.13", "dev": true, "license": "MIT", "engines": { "node": ">=12.0.0" }, "funding": { "type": "github", "url": "https://github.com/sponsors/raouldeheer" } }, "node_modules/nanoid": { "version": "3.3.11", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", "dev": true, "funding": [ { "type": "github", "url": "https://github.com/sponsors/ai" } ], "license": "MIT", "bin": { "nanoid": "bin/nanoid.cjs" }, "engines": { "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, "node_modules/normalize-path": { "version": "3.0.0", "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" } }, "node_modules/once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, "license": "ISC", "dependencies": { "wrappy": "1" } }, "node_modules/open": { "version": "7.4.2", "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", "dev": true, "license": "MIT", "dependencies": { "is-docker": "^2.0.0", "is-wsl": "^2.1.1" }, "engines": { "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/patch-package": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/patch-package/-/patch-package-8.0.0.tgz", "integrity": "sha512-da8BVIhzjtgScwDJ2TtKsfT5JFWz1hYoBl9rUQ1f38MC2HwnEIkK8VN3dKMKcP7P7bvvgzNDbfNHtx3MsQb5vA==", "dev": true, "license": "MIT", "dependencies": { "@yarnpkg/lockfile": "^1.1.0", "chalk": "^4.1.2", "ci-info": "^3.7.0", "cross-spawn": "^7.0.3", "find-yarn-workspace-root": "^2.0.0", "fs-extra": "^9.0.0", "json-stable-stringify": "^1.0.2", "klaw-sync": "^6.0.0", "minimist": "^1.2.6", "open": "^7.4.2", "rimraf": "^2.6.3", "semver": "^7.5.3", "slash": "^2.0.0", "tmp": "^0.0.33", "yaml": "^2.2.2" }, "bin": { "patch-package": "index.js" }, "engines": { "node": ">=14", "npm": ">5" } }, "node_modules/patch-package/node_modules/slash": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", "dev": true, "license": "MIT", "engines": { "node": ">=6" } }, "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/path-type": { "version": "4.0.0", "dev": true, "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/pathe": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", "dev": true, "license": "MIT" }, "node_modules/pathval": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", "dev": true, "license": "MIT", "engines": { "node": ">= 14.16" } }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "dev": true, "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", "dev": true, "license": "MIT", "engines": { "node": ">=8.6" }, "funding": { "url": "https://github.com/sponsors/jonschlinkert" } }, "node_modules/plimit-lit": { "version": "1.6.1", "dev": true, "license": "MIT", "dependencies": { "queue-lit": "^1.5.1" }, "engines": { "node": ">=12" } }, "node_modules/postcss": { "version": "8.5.3", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", "dev": true, "funding": [ { "type": "opencollective", "url": "https://opencollective.com/postcss/" }, { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/postcss" }, { "type": "github", "url": "https://github.com/sponsors/ai" } ], "license": "MIT", "dependencies": { "nanoid": "^3.3.8", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, "engines": { "node": "^10 || ^12 || >=14" } }, "node_modules/queue-lit": { "version": "1.5.2", "dev": true, "license": "MIT", "engines": { "node": ">=12" } }, "node_modules/queue-microtask": { "version": "1.2.3", "dev": true, "funding": [ { "type": "github", "url": "https://github.com/sponsors/feross" }, { "type": "patreon", "url": "https://www.patreon.com/feross" }, { "type": "consulting", "url": "https://feross.org/support" } ], "license": "MIT" }, "node_modules/readdirp": { "version": "3.6.0", "dev": true, "license": "MIT", "dependencies": { "picomatch": "^2.2.1" }, "engines": { "node": ">=8.10.0" } }, "node_modules/resolve-pkg-maps": { "version": "1.0.0", "dev": true, "license": "MIT", "funding": { "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } }, "node_modules/reusify": { "version": "1.1.0", "dev": true, "license": "MIT", "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" } }, "node_modules/rimraf": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "license": "ISC", "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" } }, "node_modules/rollup": { "version": "4.40.0", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.40.0.tgz", "integrity": "sha512-Noe455xmA96nnqH5piFtLobsGbCij7Tu+tb3c1vYjNbTkfzGqXqQXG3wJaYXkRZuQ0vEYN4bhwg7QnIrqB5B+w==", "dev": true, "license": "MIT", "dependencies": { "@types/estree": "1.0.7" }, "bin": { "rollup": "dist/bin/rollup" }, "engines": { "node": ">=18.0.0", "npm": ">=8.0.0" }, "optionalDependencies": { "@rollup/rollup-android-arm-eabi": "4.40.0", "@rollup/rollup-android-arm64": "4.40.0", "@rollup/rollup-darwin-arm64": "4.40.0", "@rollup/rollup-darwin-x64": "4.40.0", "@rollup/rollup-freebsd-arm64": "4.40.0", "@rollup/rollup-freebsd-x64": "4.40.0", "@rollup/rollup-linux-arm-gnueabihf": "4.40.0", "@rollup/rollup-linux-arm-musleabihf": "4.40.0", "@rollup/rollup-linux-arm64-gnu": "4.40.0", "@rollup/rollup-linux-arm64-musl": "4.40.0", "@rollup/rollup-linux-loongarch64-gnu": "4.40.0", "@rollup/rollup-linux-powerpc64le-gnu": "4.40.0", "@rollup/rollup-linux-riscv64-gnu": "4.40.0", "@rollup/rollup-linux-riscv64-musl": "4.40.0", "@rollup/rollup-linux-s390x-gnu": "4.40.0", "@rollup/rollup-linux-x64-gnu": "4.40.0", "@rollup/rollup-linux-x64-musl": "4.40.0", "@rollup/rollup-win32-arm64-msvc": "4.40.0", "@rollup/rollup-win32-ia32-msvc": "4.40.0", "@rollup/rollup-win32-x64-msvc": "4.40.0", "fsevents": "~2.3.2" } }, "node_modules/run-parallel": { "version": "1.2.0", "dev": true, "funding": [ { "type": "github", "url": "https://github.com/sponsors/feross" }, { "type": "patreon", "url": "https://www.patreon.com/feross" }, { "type": "consulting", "url": "https://feross.org/support" } ], "license": "MIT", "dependencies": { "queue-microtask": "^1.2.2" } }, "node_modules/semver": { "version": "7.7.1", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" }, "engines": { "node": ">=10" } }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "dev": true, "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", "gopd": "^1.0.1", "has-property-descriptors": "^1.0.2" }, "engines": { "node": ">= 0.4" } }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" }, "engines": { "node": ">=8" } }, "node_modules/shebang-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/siginfo": { "version": "2.0.0", "dev": true, "license": "ISC" }, "node_modules/slash": { "version": "3.0.0", "dev": true, "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, "node_modules/stackback": { "version": "0.0.2", "dev": true, "license": "MIT" }, "node_modules/std-env": { "version": "3.9.0", "dev": true, "license": "MIT" }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" }, "engines": { "node": ">=8" } }, "node_modules/tinybench": { "version": "2.9.0", "dev": true, "license": "MIT" }, "node_modules/tinyexec": { "version": "0.3.2", "dev": true, "license": "MIT" }, "node_modules/tinypool": { "version": "1.0.2", "dev": true, "license": "MIT", "engines": { "node": "^18.0.0 || >=20.0.0" } }, "node_modules/tinyrainbow": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", "dev": true, "license": "MIT", "engines": { "node": ">=14.0.0" } }, "node_modules/tinyspy": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz", "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==", "dev": true, "license": "MIT", "engines": { "node": ">=14.0.0" } }, "node_modules/tmp": { "version": "0.0.33", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", "dev": true, "license": "MIT", "dependencies": { "os-tmpdir": "~1.0.2" }, "engines": { "node": ">=0.6.0" } }, "node_modules/to-regex-range": { "version": "5.0.1", "dev": true, "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, "engines": { "node": ">=8.0" } }, "node_modules/tsc-alias": { "version": "1.8.15", "dev": true, "license": "MIT", "dependencies": { "chokidar": "^3.5.3", "commander": "^9.0.0", "get-tsconfig": "^4.10.0", "globby": "^11.0.4", "mylas": "^2.1.9", "normalize-path": "^3.0.0", "plimit-lit": "^1.2.6" }, "bin": { "tsc-alias": "dist/bin/index.js" }, "engines": { "node": ">=16.20.2" } }, "node_modules/tsc-alias/node_modules/commander": { "version": "9.5.0", "dev": true, "license": "MIT", "engines": { "node": "^12.20.0 || >=14" } }, "node_modules/typescript": { "version": "5.8.2", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz", "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==", "dev": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { "node": ">=14.17" } }, "node_modules/undici-types": { "version": "6.20.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", "dev": true, "license": "MIT" }, "node_modules/universalify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", "dev": true, "license": "MIT", "engines": { "node": ">= 10.0.0" } }, "node_modules/uwasi": { "version": "1.4.0", "license": "MIT" }, "node_modules/vite": { "version": "6.2.6", "resolved": "https://registry.npmjs.org/vite/-/vite-6.2.6.tgz", "integrity": "sha512-9xpjNl3kR4rVDZgPNdTL0/c6ao4km69a/2ihNQbcANz8RuCOK3hQBmLSJf3bRKVQjVMda+YvizNE8AwvogcPbw==", "dev": true, "license": "MIT", "dependencies": { "esbuild": "^0.25.0", "postcss": "^8.5.3", "rollup": "^4.30.1" }, "bin": { "vite": "bin/vite.js" }, "engines": { "node": "^18.0.0 || ^20.0.0 || >=22.0.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "peerDependenciesMeta": { "@types/node": { "optional": true }, "jiti": { "optional": true }, "less": { "optional": true }, "lightningcss": { "optional": true }, "sass": { "optional": true }, "sass-embedded": { "optional": true }, "stylus": { "optional": true }, "sugarss": { "optional": true }, "terser": { "optional": true }, "tsx": { "optional": true }, "yaml": { "optional": true } } }, "node_modules/vite-node": { "version": "3.0.9", "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.0.9.tgz", "integrity": "sha512-w3Gdx7jDcuT9cNn9jExXgOyKmf5UOTb6WMHz8LGAm54eS1Elf5OuBhCxl6zJxGhEeIkgsE1WbHuoL0mj/UXqXg==", "dev": true, "license": "MIT", "dependencies": { "cac": "^6.7.14", "debug": "^4.4.0", "es-module-lexer": "^1.6.0", "pathe": "^2.0.3", "vite": "^5.0.0 || ^6.0.0" }, "bin": { "vite-node": "vite-node.mjs" }, "engines": { "node": "^18.0.0 || ^20.0.0 || >=22.0.0" }, "funding": { "url": "https://opencollective.com/vitest" } }, "node_modules/vitest": { "version": "3.0.9", "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.0.9.tgz", "integrity": "sha512-BbcFDqNyBlfSpATmTtXOAOj71RNKDDvjBM/uPfnxxVGrG+FSH2RQIwgeEngTaTkuU/h0ScFvf+tRcKfYXzBybQ==", "dev": true, "license": "MIT", "dependencies": { "@vitest/expect": "3.0.9", "@vitest/mocker": "3.0.9", "@vitest/pretty-format": "^3.0.9", "@vitest/runner": "3.0.9", "@vitest/snapshot": "3.0.9", "@vitest/spy": "3.0.9", "@vitest/utils": "3.0.9", "chai": "^5.2.0", "debug": "^4.4.0", "expect-type": "^1.1.0", "magic-string": "^0.30.17", "pathe": "^2.0.3", "std-env": "^3.8.0", "tinybench": "^2.9.0", "tinyexec": "^0.3.2", "tinypool": "^1.0.2", "tinyrainbow": "^2.0.0", "vite": "^5.0.0 || ^6.0.0", "vite-node": "3.0.9", "why-is-node-running": "^2.3.0" }, "bin": { "vitest": "vitest.mjs" }, "engines": { "node": "^18.0.0 || ^20.0.0 || >=22.0.0" }, "funding": { "url": "https://opencollective.com/vitest" }, "peerDependencies": { "@edge-runtime/vm": "*", "@types/debug": "^4.1.12", "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "@vitest/browser": "3.0.9", "@vitest/ui": "3.0.9", "happy-dom": "*", "jsdom": "*" }, "peerDependenciesMeta": { "@edge-runtime/vm": { "optional": true }, "@types/debug": { "optional": true }, "@types/node": { "optional": true }, "@vitest/browser": { "optional": true }, "@vitest/ui": { "optional": true }, "happy-dom": { "optional": true }, "jsdom": { "optional": true } } }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "bin/node-which" }, "engines": { "node": ">= 8" } }, "node_modules/why-is-node-running": { "version": "2.3.0", "dev": true, "license": "MIT", "dependencies": { "siginfo": "^2.0.0", "stackback": "0.0.2" }, "bin": { "why-is-node-running": "cli.js" }, "engines": { "node": ">=8" } }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true, "license": "ISC" }, "node_modules/yaml": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.1.tgz", "integrity": "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==", "dev": true, "license": "ISC", "bin": { "yaml": "bin.mjs" }, "engines": { "node": ">= 14" } }, "node_modules/zx": { "version": "8.5.2", "dev": true, "license": "Apache-2.0", "bin": { "zx": "build/cli.js" }, "engines": { "node": ">= 12.17.0" } } } } ``` ## /embedders/ts/package.json ```json path="/embedders/ts/package.json" { "name": "hakojs", "version": "0.0.0", "description": "A secure, embeddable JavaScript engine that runs untrusted code inside WebAssembly sandboxes with fine-grained permissions and resource limits", "private": true, "type": "module", "exports": { "./biome": "./biome.json", ".": { "import": "./dist/index.js", "types": "./dist/index.d.ts" } }, "sideEffects": false, "files": [ "dist" ], "scripts": { "build": "node --experimental-strip-types build.ts && tsc --outDir ./dist && tsc-alias -p tsconfig.json", "dev": "esbuild src/index.ts --bundle --format=esm --outdir=dist --watch", "test": "vitest run", "test:watch": "vitest", "format": "biome format --write", "lint": "biome lint --error-on-warnings", "lint:fix": "biome lint --fix", "patch:deps": "patch -p1 -i patches/uwasi+1.4.0.patch", "generate:version": "node --experimental-strip-types tools/update-verison.ts", "generate:builds": "node --experimental-strip-types tools/generate-builds.ts" }, "keywords": [ "javascript-engine", "quicksjs", "wasm", "webassembly", "sandbox", "security", "containerization", "untrusted-code", "code-execution", "isolation", "permissions", "resource-limits", "edge-functions", "serverless", "plugin-system", "embeddable" ], "author": { "name": "Andrew Sampson", "email": "collab@andrew.im", "url": "https://andrew.im" }, "repository": "https://github.com/andrewmd5/hako", "homepage": "https://hakojs.com", "bugs": { "url": "https://github.com/andrewmd5/hako/issues" }, "license": "Apache-2.0", "devDependencies": { "@types/node": "22.13.14", "esbuild": "0.25.1", "tsc-alias": "1.8.15", "typescript": "5.8.2", "vitest": "3.0.9", "zx": "8.5.2" }, "dependencies": { "uwasi": "1.4.0" } } ``` ## /embedders/ts/patches/uwasi+1.4.0.patch ```patch path="/embedders/ts/patches/uwasi+1.4.0.patch" diff --git a/node_modules/uwasi/lib/esm/features/random.js b/node_modules/uwasi/lib/esm/features/random.js index 0cf5a36..b6e17e6 100644 --- a/node_modules/uwasi/lib/esm/features/random.js +++ b/node_modules/uwasi/lib/esm/features/random.js @@ -1,10 +1,10 @@ import { WASIAbi } from "../abi.js"; -import { defaultRandomFillSync } from "../platforms/crypto.js"; + /** * Create a feature provider that provides `random_get` with `crypto` APIs as backend by default. */ export function useRandom(useOptions = {}) { - const randomFillSync = useOptions.randomFillSync || defaultRandomFillSync; + const randomFillSync = useOptions.randomFillSync || crypto.getRandomValues; return (options, abi, memoryView) => { return { random_get: (bufferOffset, length) => { diff --git a/node_modules/uwasi/lib/esm/index.js b/node_modules/uwasi/lib/esm/index.js index 7f34757..9c844fc 100644 --- a/node_modules/uwasi/lib/esm/index.js +++ b/node_modules/uwasi/lib/esm/index.js @@ -20,10 +20,6 @@ export class WASI { const featureName = useFeature.name || "Unknown feature"; const imports = useFeature(options, abi, this.view.bind(this)); for (const key in imports) { - if (key in this.wasiImport) { - const previousProvider = importProviders[key] || "Unknown feature"; - throw new Error(`Import conflict: Function '${key}' is already provided by '${previousProvider}' and is being redefined by '${featureName}'`); - } importProviders[key] = featureName; } this.wasiImport = Object.assign(Object.assign({}, this.wasiImport), imports); diff --git a/node_modules/uwasi/lib/esm/platforms/crypto.browser.js b/node_modules/uwasi/lib/esm/platforms/crypto.browser.js deleted file mode 100644 index 18d960a..0000000 --- a/node_modules/uwasi/lib/esm/platforms/crypto.browser.js +++ /dev/null @@ -1,3 +0,0 @@ -export const defaultRandomFillSync = (buffer) => { - crypto.getRandomValues(buffer); -}; diff --git a/node_modules/uwasi/lib/esm/platforms/crypto.js b/node_modules/uwasi/lib/esm/platforms/crypto.js deleted file mode 100644 index 298ab30..0000000 --- a/node_modules/uwasi/lib/esm/platforms/crypto.js +++ /dev/null @@ -1,4 +0,0 @@ -import * as crypto from "crypto"; -export const defaultRandomFillSync = (buffer) => { - crypto.randomFillSync(buffer); -}; diff --git a/node_modules/uwasi/package.json b/node_modules/uwasi/package.json index 7465e49..2eef04c 100644 --- a/node_modules/uwasi/package.json +++ b/node_modules/uwasi/package.json @@ -2,10 +2,11 @@ "name": "uwasi", "version": "1.4.0", "description": "Micro modularized WASI runtime for JavaScript", - "main": "lib/cjs/index.js", - "module": "lib/esm/index.js", - "browser": { - "./lib/esm/platforms/crypto.js": "./lib/esm/platforms/crypto.browser.js" + "exports": { + ".": { + "import": "./lib/esm/index.js", + "require": "./lib/cjs/index.js" + } }, "scripts": { "build": "tsc -p tsconfig.esm.json && tsc -p tsconfig.cjs.json && echo '{ \"type\": \"module\" }' > lib/esm/package.json", ``` ## /embedders/ts/src/etc/errors.ts ```ts path="/embedders/ts/src/etc/errors.ts" /** * error.ts - Error handling utilities for PrimJS wrapper */ import type { HakoExports } from "@hako/etc/ffi"; import type { MemoryManager } from "@hako/mem/memory"; import type { JSContextPointer, JSValuePointer } from "@hako/etc/types"; /** * Base error class for Hako-related errors. * Used for errors that occur within the Hako runtime wrapper itself, * not for JavaScript errors that happen within a VM context. */ export class HakoError extends Error { /** * Creates a new HakoError instance. * * @param message - The error message */ constructor(message: string) { super(message); this.name = "HakoError"; } } /** * Custom error class for representing JavaScript errors that occur inside the PrimJS engine. * * This class contains both a native error message and optional additional JavaScript * error details extracted from the PrimJS context, providing rich error information * for debugging. */ export class PrimJSError extends Error { /** * Creates a new PrimJSError instance. * * @param message - The error message from the wrapper * @param jsError - Optional JavaScript error details from the PrimJS context * @param jsError.message - The error message from the JavaScript context * @param jsError.stack - Optional stack trace from the JavaScript context * @param jsError.name - Optional error name from the JavaScript context (e.g., "TypeError") * @param jsError.cause - Optional error cause if the error has a cause property */ constructor( message: string, public readonly jsError?: { message: string; stack?: string; name?: string; cause?: unknown; } ) { super(message); this.name = "PrimJSError"; } } /** * Error thrown when attempting to use a PrimJS resource after it has been freed. * * This is a memory safety error that happens when code tries to access objects, contexts, * or other resources that have already been released. */ export class PrimJSUseAfterFree extends Error { /** * The name of this error type. */ name = "PrimJSUseAfterFree"; } /** * Manages error handling operations for the PrimJS engine. * * Provides utilities for error creation, retrieval, and processing, with special * handling for bridging native JavaScript errors into the host environment. */ export class ErrorManager { private exports: HakoExports; private memory: MemoryManager; /** * Creates a new ErrorManager instance. * * @param exports - The WebAssembly exports interface for calling the PrimJS engine * @param memory - The memory manager for handling WebAssembly memory operations */ constructor(exports: HakoExports, memory: MemoryManager) { this.exports = exports; this.memory = memory; } /** * Checks if a JSValue is an exception and retrieves the error object. * * This function should only be called once for a given error state, as it * will reset the error state in the PrimJS context. * * @param ctx - PrimJS context pointer * @param ptr - Optional JSValue pointer to check. If not provided, the function * will check the last exception in the context. * @returns Pointer to the exception object or 0 if not an exception */ getLastErrorPointer( ctx: JSContextPointer, ptr?: JSValuePointer ): JSValuePointer { return this.exports.HAKO_GetLastError(ctx, ptr ? ptr : 0); } /** * Creates a new Error instance within the PrimJS context. * * This produces an empty Error object in the JavaScript environment that * can be populated with properties like message, name, etc. * * @param ctx - PrimJS context pointer * @returns Pointer to the new Error object */ newError(ctx: JSContextPointer): JSValuePointer { return this.exports.HAKO_NewError(ctx); } /** * Throws an error in the PrimJS context. * * This sets the given error as the current exception in the JavaScript environment, * equivalent to a `throw` statement in JavaScript. * * @param ctx - PrimJS context pointer * @param errorPtr - Pointer to the error JSValue to throw * @returns Pointer to the exception JSValue (typically used as an indicator of an error state) */ throwError(ctx: JSContextPointer, errorPtr: JSValuePointer): JSValuePointer { return this.exports.HAKO_Throw(ctx, errorPtr); } /** * Throws a reference error with the specified message in the PrimJS context. * * This is a convenience method that creates and throws a ReferenceError with * the given message in a single operation. * * @param ctx - PrimJS context pointer * @param message - Error message for the ReferenceError */ throwErrorMessage(ctx: JSContextPointer, message: string): void { const msgPtr = this.memory.allocateString(message); this.exports.HAKO_RuntimeJSThrow(ctx, msgPtr); this.memory.freeMemory(msgPtr); } /** * Extracts detailed error information from a PrimJS exception. * * This method attempts to retrieve rich error details including stack traces * and error causes by dumping and parsing the error object from the JavaScript context. * * @param ctx - PrimJS context pointer * @param ptr - Pointer to the exception JSValue * @returns A structured object containing error details * @private */ private dumpException( ctx: JSContextPointer, ptr: JSValuePointer ): { message: string; stack?: string; name?: string; cause?: unknown; } { let errorStr = ""; const errorStrPtr = this.exports.HAKO_Dump(ctx, ptr); errorStr = this.memory.readString(errorStrPtr); this.memory.freeCString(ctx, errorStrPtr); // Try to parse as JSON try { const errorObj = JSON.parse(errorStr); return { message: errorObj.message || errorStr, stack: errorObj.stack, name: errorObj.name, cause: errorObj.cause, }; } catch (e) { // Not valid JSON, just return the string return { message: errorStr }; } } /** * Creates a PrimJSError from a PrimJS exception. * * This method bridges the gap between errors in the JavaScript environment * and errors in the host environment, preserving important debugging information. * * @param ctx - PrimJS context pointer * @param ptr - Pointer to the exception JSValue * @returns A PrimJSError instance containing the error details */ getExceptionDetails(ctx: JSContextPointer, ptr: JSValuePointer): PrimJSError { const details = this.dumpException(ctx, ptr); const message = details.message; const error = new PrimJSError(message, details); if (details.stack) { error.stack = details.stack; } return error; } } ``` The content has been capped at 50000 tokens, and files over NaN bytes have been omitted. The user could consider applying other filters to refine the result. The better and more specific the context, the better the LLM can follow instructions. If the context seems verbose, the user can refine the filter using uithub. Thank you for using https://uithub.com - Perfect LLM context for any GitHub repo.