diff --git a/.bumpversion.toml b/.bumpversion.toml index dbf6aa0b..61ebc426 100644 --- a/.bumpversion.toml +++ b/.bumpversion.toml @@ -50,11 +50,6 @@ pre_commit_hooks = [ optional_value = "final" values = ["beta", "final"] -[[tool.bumpversion.files]] -filename = "node/package.json" -replace = "\"version\": \"{new_version}\"," -search = "\"version\": \"{current_version}\"," - [[tool.bumpversion.files]] filename = "nodejs/package.json" replace = "\"version\": \"{new_version}\"," @@ -66,39 +61,8 @@ glob = "nodejs/npm/*/package.json" replace = "\"version\": \"{new_version}\"," search = "\"version\": \"{current_version}\"," -# vectodb node binary packages -[[tool.bumpversion.files]] -glob = "node/package.json" -replace = "\"@lancedb/vectordb-darwin-arm64\": \"{new_version}\"" -search = "\"@lancedb/vectordb-darwin-arm64\": \"{current_version}\"" - -[[tool.bumpversion.files]] -glob = "node/package.json" -replace = "\"@lancedb/vectordb-darwin-x64\": \"{new_version}\"" -search = "\"@lancedb/vectordb-darwin-x64\": \"{current_version}\"" - -[[tool.bumpversion.files]] -glob = "node/package.json" -replace = "\"@lancedb/vectordb-linux-arm64-gnu\": \"{new_version}\"" -search = "\"@lancedb/vectordb-linux-arm64-gnu\": \"{current_version}\"" - -[[tool.bumpversion.files]] -glob = "node/package.json" -replace = "\"@lancedb/vectordb-linux-x64-gnu\": \"{new_version}\"" -search = "\"@lancedb/vectordb-linux-x64-gnu\": \"{current_version}\"" - -[[tool.bumpversion.files]] -glob = "node/package.json" -replace = "\"@lancedb/vectordb-win32-x64-msvc\": \"{new_version}\"" -search = "\"@lancedb/vectordb-win32-x64-msvc\": \"{current_version}\"" - # Cargo files # ------------ -[[tool.bumpversion.files]] -filename = "rust/ffi/node/Cargo.toml" -replace = "\nversion = \"{new_version}\"" -search = "\nversion = \"{current_version}\"" - [[tool.bumpversion.files]] filename = "rust/lancedb/Cargo.toml" replace = "\nversion = \"{new_version}\"" diff --git a/.github/workflows/node.yml b/.github/workflows/node.yml deleted file mode 100644 index fc04b99a..00000000 --- a/.github/workflows/node.yml +++ /dev/null @@ -1,147 +0,0 @@ -name: Node - -on: - push: - branches: - - main - pull_request: - paths: - - node/** - - rust/ffi/node/** - - .github/workflows/node.yml - - docker-compose.yml - -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true - -env: - # Disable full debug symbol generation to speed up CI build and keep memory down - # "1" means line tables only, which is useful for panic tracebacks. - # - # Use native CPU to accelerate tests if possible, especially for f16 - # target-cpu=haswell fixes failing ci build - RUSTFLAGS: "-C debuginfo=1 -C target-cpu=haswell -C target-feature=+f16c,+avx2,+fma" - RUST_BACKTRACE: "1" - -jobs: - linux: - name: Linux (Node ${{ matrix.node-version }}) - timeout-minutes: 30 - strategy: - matrix: - node-version: [ "18", "20" ] - runs-on: "ubuntu-22.04" - defaults: - run: - shell: bash - working-directory: node - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - lfs: true - - uses: actions/setup-node@v3 - with: - node-version: ${{ matrix.node-version }} - cache: 'npm' - cache-dependency-path: node/package-lock.json - - uses: Swatinem/rust-cache@v2 - - name: Install dependencies - run: | - sudo apt update - sudo apt install -y protobuf-compiler libssl-dev - - name: Build - run: | - npm ci - npm run build - npm run pack-build - npm install --no-save ./dist/lancedb-vectordb-*.tgz - # Remove index.node to test with dependency installed - rm index.node - - name: Test - run: npm run test - macos: - timeout-minutes: 30 - runs-on: "macos-13" - defaults: - run: - shell: bash - working-directory: node - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - lfs: true - - uses: actions/setup-node@v3 - with: - node-version: 20 - cache: 'npm' - cache-dependency-path: node/package-lock.json - - uses: Swatinem/rust-cache@v2 - - name: Install dependencies - run: brew install protobuf - - name: Build - run: | - npm ci - npm run build - npm run pack-build - npm install --no-save ./dist/lancedb-vectordb-*.tgz - # Remove index.node to test with dependency installed - rm index.node - - name: Test - run: | - npm run test - aws-integtest: - timeout-minutes: 45 - runs-on: "ubuntu-22.04" - defaults: - run: - shell: bash - working-directory: node - env: - AWS_ACCESS_KEY_ID: ACCESSKEY - AWS_SECRET_ACCESS_KEY: SECRETKEY - AWS_DEFAULT_REGION: us-west-2 - # this one is for s3 - AWS_ENDPOINT: http://localhost:4566 - # this one is for dynamodb - DYNAMODB_ENDPOINT: http://localhost:4566 - ALLOW_HTTP: true - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 0 - lfs: true - - uses: actions/setup-node@v3 - with: - node-version: 20 - cache: 'npm' - cache-dependency-path: node/package-lock.json - - name: start local stack - run: docker compose -f ../docker-compose.yml up -d --wait - - name: create s3 - run: aws s3 mb s3://lancedb-integtest --endpoint $AWS_ENDPOINT - - name: create ddb - run: | - aws dynamodb create-table \ - --table-name lancedb-integtest \ - --attribute-definitions '[{"AttributeName": "base_uri", "AttributeType": "S"}, {"AttributeName": "version", "AttributeType": "N"}]' \ - --key-schema '[{"AttributeName": "base_uri", "KeyType": "HASH"}, {"AttributeName": "version", "KeyType": "RANGE"}]' \ - --provisioned-throughput '{"ReadCapacityUnits": 10, "WriteCapacityUnits": 10}' \ - --endpoint-url $DYNAMODB_ENDPOINT - - uses: Swatinem/rust-cache@v2 - - name: Install dependencies - run: | - sudo apt update - sudo apt install -y protobuf-compiler libssl-dev - - name: Build - run: | - npm ci - npm run build - npm run pack-build - npm install --no-save ./dist/lancedb-vectordb-*.tgz - # Remove index.node to test with dependency installed - rm index.node - - name: Test - run: npm run integration-test diff --git a/.github/workflows/npm-publish.yml b/.github/workflows/npm-publish.yml index 3067a8eb..0651f793 100644 --- a/.github/workflows/npm-publish.yml +++ b/.github/workflows/npm-publish.yml @@ -365,200 +365,3 @@ jobs: ARGS="$ARGS --tag preview" fi npm publish $ARGS - - - # ---------------------------------------------------------------------------- - # vectordb release (legacy) - # ---------------------------------------------------------------------------- - # TODO: delete this when we drop vectordb - node: - name: vectordb Typescript - runs-on: ubuntu-latest - defaults: - run: - shell: bash - working-directory: node - steps: - - name: Checkout - uses: actions/checkout@v4 - - uses: actions/setup-node@v3 - with: - node-version: 20 - cache: "npm" - cache-dependency-path: node/package-lock.json - - name: Install dependencies - run: | - sudo apt update - sudo apt install -y protobuf-compiler libssl-dev - - name: Build - run: | - npm ci - npm run tsc - npm pack - - name: Upload Linux Artifacts - uses: actions/upload-artifact@v4 - with: - name: node-package - path: | - node/vectordb-*.tgz - - node-macos: - name: vectordb ${{ matrix.config.arch }} - strategy: - matrix: - config: - - arch: x86_64-apple-darwin - runner: macos-13 - - arch: aarch64-apple-darwin - # xlarge is implicitly arm64. - runner: macos-14 - runs-on: ${{ matrix.config.runner }} - steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Install system dependencies - run: brew install protobuf - - name: Install npm dependencies - run: | - cd node - npm ci - - name: Build MacOS native node modules - run: bash ci/build_macos_artifacts.sh ${{ matrix.config.arch }} - - name: Upload Darwin Artifacts - uses: actions/upload-artifact@v4 - with: - name: node-native-darwin-${{ matrix.config.arch }} - path: | - node/dist/lancedb-vectordb-darwin*.tgz - - node-linux-gnu: - name: vectordb (${{ matrix.config.arch}}-unknown-linux-gnu) - runs-on: ${{ matrix.config.runner }} - strategy: - fail-fast: false - matrix: - config: - - arch: x86_64 - runner: ubuntu-latest - - arch: aarch64 - # For successful fat LTO builds, we need a large runner to avoid OOM errors. - runner: warp-ubuntu-latest-arm64-4x - steps: - - name: Checkout - uses: actions/checkout@v4 - # To avoid OOM errors on ARM, we create a swap file. - - name: Configure aarch64 build - if: ${{ matrix.config.arch == 'aarch64' }} - run: | - free -h - sudo fallocate -l 16G /swapfile - sudo chmod 600 /swapfile - sudo mkswap /swapfile - sudo swapon /swapfile - echo "/swapfile swap swap defaults 0 0" >> sudo /etc/fstab - # print info - swapon --show - free -h - - name: Build Linux Artifacts - run: | - bash ci/build_linux_artifacts.sh ${{ matrix.config.arch }} ${{ matrix.config.arch }}-unknown-linux-gnu - - name: Upload Linux Artifacts - uses: actions/upload-artifact@v4 - with: - name: node-native-linux-${{ matrix.config.arch }}-gnu - path: | - node/dist/lancedb-vectordb-linux*.tgz - - node-windows: - name: vectordb ${{ matrix.target }} - runs-on: windows-2022 - strategy: - fail-fast: false - matrix: - target: [x86_64-pc-windows-msvc] - steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Install Protoc v21.12 - working-directory: C:\ - run: | - New-Item -Path 'C:\protoc' -ItemType Directory - Set-Location C:\protoc - Invoke-WebRequest https://github.com/protocolbuffers/protobuf/releases/download/v21.12/protoc-21.12-win64.zip -OutFile C:\protoc\protoc.zip - 7z x protoc.zip - Add-Content $env:GITHUB_PATH "C:\protoc\bin" - shell: powershell - - name: Install npm dependencies - run: | - cd node - npm ci - - name: Build Windows native node modules - run: .\ci\build_windows_artifacts.ps1 ${{ matrix.target }} - - name: Upload Windows Artifacts - uses: actions/upload-artifact@v4 - with: - name: node-native-windows - path: | - node/dist/lancedb-vectordb-win32*.tgz - - release: - name: vectordb NPM Publish - needs: [node, node-macos, node-linux-gnu, node-windows] - runs-on: ubuntu-latest - permissions: - contents: write - # Only runs on tags that matches the make-release action - if: startsWith(github.ref, 'refs/tags/v') - steps: - - uses: actions/download-artifact@v4 - with: - pattern: node-* - - name: Display structure of downloaded files - run: ls -R - - uses: actions/setup-node@v3 - with: - node-version: 20 - registry-url: "https://registry.npmjs.org" - - name: Publish to NPM - env: - NODE_AUTH_TOKEN: ${{ secrets.LANCEDB_NPM_REGISTRY_TOKEN }} - run: | - # Tag beta as "preview" instead of default "latest". See lancedb - # npm publish step for more info. - if [[ $GITHUB_REF =~ refs/tags/v(.*)-beta.* ]]; then - PUBLISH_ARGS="--tag preview" - fi - - mv */*.tgz . - for filename in *.tgz; do - npm publish $PUBLISH_ARGS $filename - done - - name: Deprecate - env: - NODE_AUTH_TOKEN: ${{ secrets.LANCEDB_NPM_REGISTRY_TOKEN }} - # We need to deprecate the old package to avoid confusion. - # Each time we publish a new version, it gets undeprecated. - run: npm deprecate vectordb "Use @lancedb/lancedb instead." - - name: Checkout - uses: actions/checkout@v4 - with: - ref: main - - name: Update package-lock.json - run: | - git config user.name 'Lance Release' - git config user.email 'lance-dev@lancedb.com' - bash ci/update_lockfiles.sh - - name: Push new commit - uses: ad-m/github-push-action@master - with: - github_token: ${{ secrets.LANCEDB_RELEASE_TOKEN }} - branch: main - - name: Notify Slack Action - uses: ravsamhq/notify-slack-action@2.3.0 - if: ${{ always() }} - with: - status: ${{ job.status }} - notify_when: "failure" - notification_title: "{workflow} is failing" - env: - SLACK_WEBHOOK_URL: ${{ secrets.ACTION_MONITORING_SLACK }} diff --git a/Cargo.lock b/Cargo.lock index a6956c08..abbaebc7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1480,7 +1480,7 @@ checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" dependencies = [ "glob", "libc", - "libloading 0.8.8", + "libloading", ] [[package]] @@ -1573,15 +1573,6 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" -[[package]] -name = "conv" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ff10625fd0ac447827aa30ea8b861fead473bb60aeb73af6c1c58caf0d1299" -dependencies = [ - "custom_derive", -] - [[package]] name = "convert_case" version = "0.6.0" @@ -1797,12 +1788,6 @@ dependencies = [ "syn 2.0.103", ] -[[package]] -name = "custom_derive" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef8ae57c4978a2acd8b869ce6b9ca1dfe817bff704c220209fdef2c0b75a01b9" - [[package]] name = "darling" version = "0.20.11" @@ -4430,7 +4415,7 @@ dependencies = [ "regex", "reqwest", "rstest", - "semver 1.0.26", + "semver", "serde", "serde_json", "serde_with", @@ -4459,31 +4444,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "lancedb-node" -version = "0.21.2" -dependencies = [ - "arrow-array", - "arrow-ipc", - "arrow-schema", - "async-trait", - "chrono", - "conv", - "env_logger", - "futures", - "half", - "lance", - "lance-index", - "lance-linalg", - "lancedb", - "lzma-sys", - "neon", - "object_store", - "once_cell", - "snafu", - "tokio", -] - [[package]] name = "lancedb-nodejs" version = "0.21.2" @@ -4607,16 +4567,6 @@ version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" -[[package]] -name = "libloading" -version = "0.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "351a32417a12d5f7e82c368a66781e307834dae04c6ce0cd4456d52989229883" -dependencies = [ - "cfg-if", - "winapi", -] - [[package]] name = "libloading" version = "0.8.8" @@ -4995,7 +4945,7 @@ dependencies = [ "proc-macro2", "quote", "regex", - "semver 1.0.26", + "semver", "syn 2.0.103", ] @@ -5005,48 +4955,7 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "427802e8ec3a734331fec1035594a210ce1ff4dc5bc1950530920ab717964ea3" dependencies = [ - "libloading 0.8.8", -] - -[[package]] -name = "neon" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28e15415261d880aed48122e917a45e87bb82cf0260bb6db48bbab44b7464373" -dependencies = [ - "neon-build", - "neon-macros", - "neon-runtime", - "semver 0.9.0", - "smallvec", -] - -[[package]] -name = "neon-build" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bac98a702e71804af3dacfde41edde4a16076a7bbe889ae61e56e18c5b1c811" - -[[package]] -name = "neon-macros" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7288eac8b54af7913c60e0eb0e2a7683020dffa342ab3fd15e28f035ba897cf" -dependencies = [ - "quote", - "syn 1.0.109", - "syn-mid", -] - -[[package]] -name = "neon-runtime" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4676720fa8bb32c64c3d9f49c47a47289239ec46b4bdb66d0913cc512cb0daca" -dependencies = [ - "cfg-if", - "libloading 0.6.7", - "smallvec", + "libloading", ] [[package]] @@ -6728,7 +6637,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ - "semver 1.0.26", + "semver", ] [[package]] @@ -6993,27 +6902,12 @@ dependencies = [ "libc", ] -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser", -] - [[package]] name = "semver" version = "1.0.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - [[package]] name = "seq-macro" version = "0.3.6" @@ -7413,17 +7307,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "syn-mid" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea305d57546cc8cd04feb14b62ec84bf17f50e3f7b12560d7bfa9265f39d9ed" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "sync_wrapper" version = "1.0.2" @@ -8059,7 +7942,7 @@ checksum = "90b70b37e9074642bc5f60bb23247fd072a84314ca9e71cdf8527593406a0dd3" dependencies = [ "gemm 0.18.2", "half", - "libloading 0.8.8", + "libloading", "memmap2 0.9.5", "num", "num-traits", diff --git a/Cargo.toml b/Cargo.toml index 9a1db033..20d3ca7a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,5 @@ [workspace] members = [ - "rust/ffi/node", "rust/lancedb", "nodejs", "python", diff --git a/ci/build_linux_artifacts.sh b/ci/build_linux_artifacts.sh deleted file mode 100755 index 4a84e86a..00000000 --- a/ci/build_linux_artifacts.sh +++ /dev/null @@ -1,22 +0,0 @@ -#!/bin/bash -set -e -ARCH=${1:-x86_64} -TARGET_TRIPLE=${2:-x86_64-unknown-linux-gnu} - -# We pass down the current user so that when we later mount the local files -# into the container, the files are accessible by the current user. -pushd ci/manylinux_node -docker build \ - -t lancedb-node-manylinux \ - --build-arg="ARCH=$ARCH" \ - --build-arg="DOCKER_USER=$(id -u)" \ - --progress=plain \ - . -popd - -# We turn on memory swap to avoid OOM killer -docker run \ - -v $(pwd):/io -w /io \ - --memory-swap=-1 \ - lancedb-node-manylinux \ - bash ci/manylinux_node/build_vectordb.sh $ARCH $TARGET_TRIPLE diff --git a/ci/build_macos_artifacts.sh b/ci/build_macos_artifacts.sh deleted file mode 100644 index ca5280aa..00000000 --- a/ci/build_macos_artifacts.sh +++ /dev/null @@ -1,34 +0,0 @@ -# Builds the macOS artifacts (node binaries). -# Usage: ./ci/build_macos_artifacts.sh [target] -# Targets supported: x86_64-apple-darwin aarch64-apple-darwin -set -e - -prebuild_rust() { - # Building here for the sake of easier debugging. - pushd rust/ffi/node - echo "Building rust library for $1" - export RUST_BACKTRACE=1 - cargo build --release --target $1 - popd -} - -build_node_binaries() { - pushd node - echo "Building node library for $1" - npm run build-release -- --target $1 - npm run pack-build -- --target $1 - popd -} - -if [ -n "$1" ]; then - targets=$1 -else - targets="x86_64-apple-darwin aarch64-apple-darwin" -fi - -echo "Building artifacts for targets: $targets" -for target in $targets - do - prebuild_rust $target - build_node_binaries $target -done \ No newline at end of file diff --git a/ci/build_windows_artifacts.ps1 b/ci/build_windows_artifacts.ps1 deleted file mode 100644 index 02f2d207..00000000 --- a/ci/build_windows_artifacts.ps1 +++ /dev/null @@ -1,42 +0,0 @@ -# Builds the Windows artifacts (node binaries). -# Usage: .\ci\build_windows_artifacts.ps1 [target] -# Targets supported: -# - x86_64-pc-windows-msvc -# - i686-pc-windows-msvc -# - aarch64-pc-windows-msvc - -function Prebuild-Rust { - param ( - [string]$target - ) - - # Building here for the sake of easier debugging. - Push-Location -Path "rust/ffi/node" - Write-Host "Building rust library for $target" - $env:RUST_BACKTRACE=1 - cargo build --release --target $target - Pop-Location -} - -function Build-NodeBinaries { - param ( - [string]$target - ) - - Push-Location -Path "node" - Write-Host "Building node library for $target" - npm run build-release -- --target $target - npm run pack-build -- --target $target - Pop-Location -} - -$targets = $args[0] -if (-not $targets) { - $targets = "x86_64-pc-windows-msvc", "aarch64-pc-windows-msvc" -} - -Write-Host "Building artifacts for targets: $targets" -foreach ($target in $targets) { - Prebuild-Rust $target - Build-NodeBinaries $target -} diff --git a/ci/build_windows_artifacts_nodejs.ps1 b/ci/build_windows_artifacts_nodejs.ps1 deleted file mode 100644 index 5c1ac4fa..00000000 --- a/ci/build_windows_artifacts_nodejs.ps1 +++ /dev/null @@ -1,42 +0,0 @@ -# Builds the Windows artifacts (nodejs binaries). -# Usage: .\ci\build_windows_artifacts_nodejs.ps1 [target] -# Targets supported: -# - x86_64-pc-windows-msvc -# - i686-pc-windows-msvc -# - aarch64-pc-windows-msvc - -function Prebuild-Rust { - param ( - [string]$target - ) - - # Building here for the sake of easier debugging. - Push-Location -Path "rust/lancedb" - Write-Host "Building rust library for $target" - $env:RUST_BACKTRACE=1 - cargo build --release --target $target - Pop-Location -} - -function Build-NodeBinaries { - param ( - [string]$target - ) - - Push-Location -Path "nodejs" - Write-Host "Building nodejs library for $target" - $env:RUST_TARGET=$target - npm run build-release - Pop-Location -} - -$targets = $args[0] -if (-not $targets) { - $targets = "x86_64-pc-windows-msvc", "aarch64-pc-windows-msvc" -} - -Write-Host "Building artifacts for targets: $targets" -foreach ($target in $targets) { - Prebuild-Rust $target - Build-NodeBinaries $target -} diff --git a/ci/manylinux_node/Dockerfile b/ci/manylinux_node/Dockerfile deleted file mode 100644 index 1d06d4f6..00000000 --- a/ci/manylinux_node/Dockerfile +++ /dev/null @@ -1,27 +0,0 @@ -# Many linux dockerfile with Rust, Node, and Lance dependencies installed. -# This container allows building the node modules native libraries in an -# environment with a very old glibc, so that we are compatible with a wide -# range of linux distributions. -ARG ARCH=x86_64 - -FROM quay.io/pypa/manylinux_2_28_${ARCH} - -ARG ARCH=x86_64 -ARG DOCKER_USER=default_user - -# Protobuf is also installed as root. -COPY install_protobuf.sh install_protobuf.sh -RUN ./install_protobuf.sh ${ARCH} - -ENV DOCKER_USER=${DOCKER_USER} -# Create a group and user, but only if it doesn't exist -RUN echo ${ARCH} && id -u ${DOCKER_USER} >/dev/null 2>&1 || adduser --user-group --create-home --uid ${DOCKER_USER} build_user - -# We switch to the user to install Rust and Node, since those like to be -# installed at the user level. -USER ${DOCKER_USER} - -COPY prepare_manylinux_node.sh prepare_manylinux_node.sh -RUN cp /prepare_manylinux_node.sh $HOME/ && \ - cd $HOME && \ - ./prepare_manylinux_node.sh ${ARCH} diff --git a/ci/manylinux_node/build_vectordb.sh b/ci/manylinux_node/build_vectordb.sh deleted file mode 100755 index 8d703816..00000000 --- a/ci/manylinux_node/build_vectordb.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash -# Builds the node module for manylinux. Invoked by ci/build_linux_artifacts.sh. -set -e -ARCH=${1:-x86_64} -TARGET_TRIPLE=${2:-x86_64-unknown-linux-gnu} - -#Alpine doesn't have .bashrc -FILE=$HOME/.bashrc && test -f $FILE && source $FILE - -cd node -npm ci -npm run build-release -npm run pack-build -- -t $TARGET_TRIPLE diff --git a/ci/manylinux_node/install_protobuf.sh b/ci/manylinux_node/install_protobuf.sh deleted file mode 100755 index 8ea18ddd..00000000 --- a/ci/manylinux_node/install_protobuf.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash -# Installs protobuf compiler. Should be run as root. -set -e - -if [[ $1 == x86_64* ]]; then - ARCH=x86_64 -else - # gnu target - ARCH=aarch_64 -fi - -PB_REL=https://github.com/protocolbuffers/protobuf/releases -PB_VERSION=23.1 -curl -LO $PB_REL/download/v$PB_VERSION/protoc-$PB_VERSION-linux-$ARCH.zip -unzip protoc-$PB_VERSION-linux-$ARCH.zip -d /usr/local \ No newline at end of file diff --git a/ci/manylinux_node/prepare_manylinux_node.sh b/ci/manylinux_node/prepare_manylinux_node.sh deleted file mode 100755 index 0db4b60e..00000000 --- a/ci/manylinux_node/prepare_manylinux_node.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/bin/bash -set -e - -install_node() { - echo "Installing node..." - - curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash - - source "$HOME"/.bashrc - - nvm install --no-progress 18 -} - -install_rust() { - echo "Installing rust..." - curl https://sh.rustup.rs -sSf | bash -s -- -y - export PATH="$PATH:/root/.cargo/bin" -} - -install_node -install_rust \ No newline at end of file diff --git a/node/.eslintrc.js b/node/.eslintrc.js deleted file mode 100644 index fe7d61e1..00000000 --- a/node/.eslintrc.js +++ /dev/null @@ -1,22 +0,0 @@ -module.exports = { - env: { - browser: true, - es2021: true - }, - extends: 'standard-with-typescript', - overrides: [ - ], - parserOptions: { - project: './tsconfig.json', - ecmaVersion: 'latest', - sourceType: 'module' - }, - rules: { - "@typescript-eslint/method-signature-style": "off", - "@typescript-eslint/quotes": "off", - "@typescript-eslint/semi": "off", - "@typescript-eslint/explicit-function-return-type": "off", - "@typescript-eslint/space-before-function-paren": "off", - "@typescript-eslint/indent": "off", - } -} diff --git a/node/.npmignore b/node/.npmignore deleted file mode 100644 index 3da85495..00000000 --- a/node/.npmignore +++ /dev/null @@ -1,4 +0,0 @@ -gen_test_data.py -index.node -dist/lancedb*.tgz -vectordb*.tgz \ No newline at end of file diff --git a/node/CHANGELOG.md b/node/CHANGELOG.md deleted file mode 100644 index 12867409..00000000 --- a/node/CHANGELOG.md +++ /dev/null @@ -1,64 +0,0 @@ -# Changelog - -All notable changes to this project will be documented in this file. - -The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), -and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). - -## [0.1.5] - 2023-06-00 - -### Added - -- Support for macOS X86 - -## [0.1.4] - 2023-06-03 - -### Added - -- Select / Project query API - -### Changed - -- Deprecated created_index in favor of createIndex - -## [0.1.3] - 2023-06-01 - -### Added - -- Support S3 and Google Cloud Storage -- Embedding functions support -- OpenAI embedding function - -## [0.1.2] - 2023-05-27 - -### Added - -- Append records API -- Extra query params to to nodejs client -- Create_index API - -### Fixed - -- bugfix: string columns should be converted to Utf8Array (#94) - -## [0.1.1] - 2023-05-16 - -### Added - -- create_table API -- limit parameter for queries -- Typescript / JavaScript examples -- Linux support - -## [0.1.0] - 2023-05-16 - -### Added - -- Initial JavaScript / Node.js library for LanceDB -- Read-only api to query LanceDB datasets -- Supports macOS arm only - -## [pre-0.1.0] - -- Various prototypes / test builds - diff --git a/node/README.md b/node/README.md deleted file mode 100644 index a4647732..00000000 --- a/node/README.md +++ /dev/null @@ -1,66 +0,0 @@ -# LanceDB - -A JavaScript / Node.js library for [LanceDB](https://github.com/lancedb/lancedb). - -**DEPRECATED: This library is deprecated. Please use the new client, -[@lancedb/lancedb](https://www.npmjs.com/package/@lancedb/lancedb).** - -## Installation - -```bash -npm install vectordb -``` - -This will download the appropriate native library for your platform. We currently -support: - -* Linux (x86_64 and aarch64) -* MacOS (Intel and ARM/M1/M2) -* Windows (x86_64 only) - -We do not yet support musl-based Linux (such as Alpine Linux) or aarch64 Windows. - -## Usage - -### Basic Example - -```javascript -const lancedb = require('vectordb'); -const db = await lancedb.connect('data/sample-lancedb'); -const table = await db.createTable("my_table", - [{ id: 1, vector: [0.1, 1.0], item: "foo", price: 10.0 }, - { id: 2, vector: [3.9, 0.5], item: "bar", price: 20.0 }]) -const results = await table.search([0.1, 0.3]).limit(20).execute(); -console.log(results); -``` - -The [examples](./examples) folder contains complete examples. - -## Development - -To build everything fresh: - -```bash -npm install -npm run build -``` - -Then you should be able to run the tests with: - -```bash -npm test -``` - -### Fix lints - -To run the linter and have it automatically fix all errors - -```bash -npm run lint -- --fix -``` - -To build documentation - -```bash -npx typedoc --plugin typedoc-plugin-markdown --out ../docs/src/javascript src/index.ts -``` diff --git a/node/examples/js-openai/index.js b/node/examples/js-openai/index.js deleted file mode 100644 index 5eb095dc..00000000 --- a/node/examples/js-openai/index.js +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2023 Lance Developers. -// -// 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. - -'use strict' - -async function example () { - const lancedb = require('vectordb') - // You need to provide an OpenAI API key, here we read it from the OPENAI_API_KEY environment variable - const apiKey = process.env.OPENAI_API_KEY - // The embedding function will create embeddings for the 'text' column(text in this case) - const embedding = new lancedb.OpenAIEmbeddingFunction('text', apiKey) - - const db = await lancedb.connect('data/sample-lancedb') - - const data = [ - { id: 1, text: 'Black T-Shirt', price: 10 }, - { id: 2, text: 'Leather Jacket', price: 50 } - ] - - const table = await db.createTable('vectors', data, embedding) - console.log(await db.tableNames()) - - const results = await table - .search('keeps me warm') - .limit(1) - .execute() - console.log(results[0].text) -} - -example().then(_ => { console.log('All done!') }) diff --git a/node/examples/js-openai/package.json b/node/examples/js-openai/package.json deleted file mode 100644 index 12f44bb5..00000000 --- a/node/examples/js-openai/package.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "vectordb-example-js-openai", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "author": "Lance Devs", - "license": "Apache-2.0", - "dependencies": { - "vectordb": "file:../..", - "openai": "^3.2.1" - } -} diff --git a/node/examples/js-transformers/index.js b/node/examples/js-transformers/index.js deleted file mode 100644 index 4400cbc6..00000000 --- a/node/examples/js-transformers/index.js +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2023 Lance Developers. -// -// 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. - -'use strict' - - -async function example() { - - const lancedb = require('vectordb') - - // Import transformers and the all-MiniLM-L6-v2 model (https://huggingface.co/Xenova/all-MiniLM-L6-v2) - const { pipeline } = await import('@xenova/transformers') - const pipe = await pipeline('feature-extraction', 'Xenova/all-MiniLM-L6-v2'); - - - // Create embedding function from pipeline which returns a list of vectors from batch - // sourceColumn is the name of the column in the data to be embedded - // - // Output of pipe is a Tensor { data: Float32Array(384) }, so filter for the vector - const embed_fun = {} - embed_fun.sourceColumn = 'text' - embed_fun.embed = async function (batch) { - let result = [] - for (let text of batch) { - const res = await pipe(text, { pooling: 'mean', normalize: true }) - result.push(Array.from(res['data'])) - } - return (result) - } - - // Link a folder and create a table with data - const db = await lancedb.connect('data/sample-lancedb') - - const data = [ - { id: 1, text: 'Cherry', type: 'fruit' }, - { id: 2, text: 'Carrot', type: 'vegetable' }, - { id: 3, text: 'Potato', type: 'vegetable' }, - { id: 4, text: 'Apple', type: 'fruit' }, - { id: 5, text: 'Banana', type: 'fruit' } - ] - - const table = await db.createTable('food_table', data, embed_fun) - - - // Query the table - const results = await table - .search("a sweet fruit to eat") - .metricType("cosine") - .limit(2) - .execute() - console.log(results.map(r => r.text)) - -} - -example().then(_ => { console.log("Done!") }) diff --git a/node/examples/js-transformers/package.json b/node/examples/js-transformers/package.json deleted file mode 100644 index b823f90b..00000000 --- a/node/examples/js-transformers/package.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "name": "vectordb-example-js-transformers", - "version": "1.0.0", - "description": "Example for using transformers.js with lancedb", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "author": "Lance Devs", - "license": "Apache-2.0", - "dependencies": { - "@xenova/transformers": "^2.4.1", - "vectordb": "file:../.." - } - -} diff --git a/node/examples/js-youtube-transcripts/index.js b/node/examples/js-youtube-transcripts/index.js deleted file mode 100644 index 6c7a5787..00000000 --- a/node/examples/js-youtube-transcripts/index.js +++ /dev/null @@ -1,122 +0,0 @@ -// Copyright 2023 Lance Developers. -// -// 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. - -'use strict' - -const lancedb = require('vectordb') -const fs = require('fs/promises') -const readline = require('readline/promises') -const { stdin: input, stdout: output } = require('process') -const { Configuration, OpenAIApi } = require('openai') - -// Download file from XYZ -const INPUT_FILE_NAME = 'data/youtube-transcriptions_sample.jsonl'; - -(async () => { - // You need to provide an OpenAI API key, here we read it from the OPENAI_API_KEY environment variable - const apiKey = process.env.OPENAI_API_KEY - // The embedding function will create embeddings for the 'context' column - const embedFunction = new lancedb.OpenAIEmbeddingFunction('context', apiKey) - - // Connects to LanceDB - const db = await lancedb.connect('data/youtube-lancedb') - - // Open the vectors table or create one if it does not exist - let tbl - if ((await db.tableNames()).includes('vectors')) { - tbl = await db.openTable('vectors', embedFunction) - } else { - tbl = await createEmbeddingsTable(db, embedFunction) - } - - // Use OpenAI Completion API to generate and answer based on the context that LanceDB provides - const configuration = new Configuration({ apiKey }) - const openai = new OpenAIApi(configuration) - const rl = readline.createInterface({ input, output }) - try { - while (true) { - const query = await rl.question('Prompt: ') - const results = await tbl - .search(query) - .select(['title', 'text', 'context']) - .limit(3) - .execute() - - // console.table(results) - - const response = await openai.createCompletion({ - model: 'text-davinci-003', - prompt: createPrompt(query, results), - max_tokens: 400, - temperature: 0, - top_p: 1, - frequency_penalty: 0, - presence_penalty: 0 - }) - console.log(response.data.choices[0].text) - } - } catch (err) { - console.log('Error: ', err) - } finally { - rl.close() - } - process.exit(1) -})() - -async function createEmbeddingsTable (db, embedFunction) { - console.log(`Creating embeddings from ${INPUT_FILE_NAME}`) - // read the input file into a JSON array, skipping empty lines - const lines = (await fs.readFile(INPUT_FILE_NAME, 'utf-8')) - .toString() - .split('\n') - .filter(line => line.length > 0) - .map(line => JSON.parse(line)) - - const data = contextualize(lines, 20, 'video_id') - return await db.createTable('vectors', data, embedFunction) -} - -// Each transcript has a small text column, we include previous transcripts in order to -// have more context information when creating embeddings -function contextualize (rows, contextSize, groupColumn) { - const grouped = [] - rows.forEach(row => { - if (!grouped[row[groupColumn]]) { - grouped[row[groupColumn]] = [] - } - grouped[row[groupColumn]].push(row) - }) - - const data = [] - Object.keys(grouped).forEach(key => { - for (let i = 0; i < grouped[key].length; i++) { - const start = i - contextSize > 0 ? i - contextSize : 0 - grouped[key][i].context = grouped[key].slice(start, i + 1).map(r => r.text).join(' ') - } - data.push(...grouped[key]) - }) - return data -} - -// Creates a prompt by aggregating all relevant contexts -function createPrompt (query, context) { - let prompt = - 'Answer the question based on the context below.\n\n' + - 'Context:\n' - - // need to make sure our prompt is not larger than max size - prompt = prompt + context.map(c => c.context).join('\n\n---\n\n').substring(0, 3750) - prompt = prompt + `\n\nQuestion: ${query}\nAnswer:` - return prompt -} diff --git a/node/examples/js-youtube-transcripts/package.json b/node/examples/js-youtube-transcripts/package.json deleted file mode 100644 index 12f44bb5..00000000 --- a/node/examples/js-youtube-transcripts/package.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "name": "vectordb-example-js-openai", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "author": "Lance Devs", - "license": "Apache-2.0", - "dependencies": { - "vectordb": "file:../..", - "openai": "^3.2.1" - } -} diff --git a/node/examples/js/index.js b/node/examples/js/index.js deleted file mode 100644 index 625ef1f2..00000000 --- a/node/examples/js/index.js +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2023 Lance Developers. -// -// 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. - -'use strict' - -async function example () { - const lancedb = require('vectordb') - const db = await lancedb.connect('data/sample-lancedb') - - const data = [ - { id: 1, vector: [0.1, 0.2], price: 10 }, - { id: 2, vector: [1.1, 1.2], price: 50 } - ] - - const table = await db.createTable('vectors', data) - console.log(await db.tableNames()) - - const results = await table - .search([0.1, 0.3]) - .limit(20) - .execute() - console.log(results) -} - -example() diff --git a/node/examples/js/package.json b/node/examples/js/package.json deleted file mode 100644 index 0bcb7e96..00000000 --- a/node/examples/js/package.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "vectordb-example-js", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "author": "Lance Devs", - "license": "Apache-2.0", - "dependencies": { - "vectordb": "file:../.." - } -} diff --git a/node/examples/ts/package.json b/node/examples/ts/package.json deleted file mode 100644 index 2e0c7b5d..00000000 --- a/node/examples/ts/package.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "name": "vectordb-example-ts", - "version": "1.0.0", - "description": "", - "main": "dist/index.js", - "types": "dist/index.d.ts", - "scripts": { - "tsc": "tsc -b", - "build": "tsc" - }, - "author": "Lance Devs", - "license": "Apache-2.0", - "devDependencies": { - "@types/node": "^18.16.2", - "ts-node": "^10.9.1", - "ts-node-dev": "^2.0.0", - "typescript": "*" - }, - "dependencies": { - "vectordb": "file:../.." - } -} diff --git a/node/examples/ts/src/index.ts b/node/examples/ts/src/index.ts deleted file mode 100644 index 6aa73d47..00000000 --- a/node/examples/ts/src/index.ts +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2023 Lance Developers. -// -// 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. - -import * as vectordb from 'vectordb'; - -async function example () { - const db = await vectordb.connect('data/sample-lancedb') - - const data = [ - { id: 1, vector: [0.1, 0.2], price: 10 }, - { id: 2, vector: [1.1, 1.2], price: 50 } - ] - - const table = await db.createTable('vectors', data) - console.log(await db.tableNames()) - - const results = await table - .search([0.1, 0.3]) - .limit(20) - .execute() - console.log(results) -} - -example().then(_ => { console.log ("All done!") }) diff --git a/node/examples/ts/tsconfig.json b/node/examples/ts/tsconfig.json deleted file mode 100644 index a3fe259b..00000000 --- a/node/examples/ts/tsconfig.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "include": ["src/**/*.ts"], - "compilerOptions": { - "target": "es2016", - "module": "commonjs", - "declaration": true, - "outDir": "./dist", - "strict": true - } -} diff --git a/node/native.js b/node/native.js deleted file mode 100644 index d3afd658..00000000 --- a/node/native.js +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2023 Lance Developers. -// -// 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. - -const { currentTarget } = require('@neon-rs/load') - -let nativeLib - -try { - // When developing locally, give preference to the local built library - nativeLib = require('./index.node') -} catch { - try { - nativeLib = require(`@lancedb/vectordb-${currentTarget()}`) - } catch (e) { - throw new Error(`vectordb: failed to load native library. - You may need to run \`npm install @lancedb/vectordb-${currentTarget()}\`. - - If that does not work, please file a bug report at https://github.com/lancedb/lancedb/issues - - Source error: ${e}`) - } -} - -// Dynamic require for runtime. -module.exports = nativeLib diff --git a/node/package-lock.json b/node/package-lock.json deleted file mode 100644 index 0b9025ce..00000000 --- a/node/package-lock.json +++ /dev/null @@ -1,5239 +0,0 @@ -{ - "name": "vectordb", - "version": "0.21.2", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "vectordb", - "version": "0.21.2", - "cpu": [ - "x64", - "arm64" - ], - "license": "Apache-2.0", - "os": [ - "darwin", - "linux", - "win32" - ], - "dependencies": { - "@neon-rs/load": "^0.0.74", - "axios": "^1.4.0" - }, - "devDependencies": { - "@neon-rs/cli": "^0.0.160", - "@types/chai": "^4.3.4", - "@types/chai-as-promised": "^7.1.5", - "@types/mocha": "^10.0.1", - "@types/node": "^18.16.2", - "@types/sinon": "^10.0.15", - "@types/temp": "^0.9.1", - "@types/uuid": "^9.0.3", - "@typescript-eslint/eslint-plugin": "^5.59.1", - "apache-arrow-old": "npm:apache-arrow@13.0.0", - "cargo-cp-artifact": "^0.1", - "chai": "^4.3.7", - "chai-as-promised": "^7.1.1", - "eslint": "^8.39.0", - "eslint-config-standard-with-typescript": "^34.0.1", - "eslint-plugin-import": "^2.26.0", - "eslint-plugin-n": "^15.7.0", - "eslint-plugin-promise": "^6.1.1", - "mocha": "^10.2.0", - "openai": "^4.24.1", - "sinon": "^15.1.0", - "temp": "^0.9.4", - "ts-node": "^10.9.1", - "ts-node-dev": "^2.0.0", - "typedoc": "^0.24.7", - "typedoc-plugin-markdown": "^3.15.3", - "typescript": "^5.1.0", - "uuid": "^9.0.0" - }, - "optionalDependencies": { - "@lancedb/vectordb-darwin-arm64": "0.21.2", - "@lancedb/vectordb-darwin-x64": "0.21.2", - "@lancedb/vectordb-linux-arm64-gnu": "0.21.2", - "@lancedb/vectordb-linux-x64-gnu": "0.21.2", - "@lancedb/vectordb-win32-x64-msvc": "0.21.2" - }, - "peerDependencies": { - "@apache-arrow/ts": "^14.0.2", - "apache-arrow": "^14.0.2" - } - }, - "node_modules/@75lb/deep-merge": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@75lb/deep-merge/-/deep-merge-1.1.2.tgz", - "integrity": "sha512-08K9ou5VNbheZFxM5tDWoqjA3ImC50DiuuJ2tj1yEPRfkp8lLLg6XAaJ4On+a0yAXor/8ay5gHnAIshRM44Kpw==", - "dependencies": { - "lodash": "^4.17.21", - "typical": "^7.1.1" - }, - "engines": { - "node": ">=12.17" - } - }, - "node_modules/@75lb/deep-merge/node_modules/typical": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/typical/-/typical-7.2.0.tgz", - "integrity": "sha512-W1+HdVRUl8fS3MZ9ogD51GOb46xMmhAZzR0WPw5jcgIZQJVvkddYzAl4YTU6g5w33Y1iRQLdIi2/1jhi2RNL0g==", - "engines": { - "node": ">=12.17" - } - }, - "node_modules/@apache-arrow/ts": { - "version": "14.0.2", - "resolved": "https://registry.npmjs.org/@apache-arrow/ts/-/ts-14.0.2.tgz", - "integrity": "sha512-CtwAvLkK0CZv7xsYeCo91ml6PvlfzAmAJZkRYuz2GNBwfYufj5SVi0iuSMwIMkcU/szVwvLdzORSLa5PlF/2ug==", - "peer": true, - "dependencies": { - "@types/command-line-args": "5.2.0", - "@types/command-line-usage": "5.0.2", - "@types/node": "20.3.0", - "@types/pad-left": "2.1.1", - "command-line-args": "5.2.1", - "command-line-usage": "7.0.1", - "flatbuffers": "23.5.26", - "json-bignum": "^0.0.3", - "pad-left": "^2.1.0", - "tslib": "^2.5.3" - } - }, - "node_modules/@apache-arrow/ts/node_modules/@types/node": { - "version": "20.3.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.0.tgz", - "integrity": "sha512-cumHmIAf6On83X7yP+LrsEyUOf/YlociZelmpRYaGFydoaPdxdt80MAbu6vWerQT2COCp2nPvHdsbD7tHn/YlQ==", - "peer": true - }, - "node_modules/@cargo-messages/android-arm-eabi": { - "version": "0.0.160", - "resolved": "https://registry.npmjs.org/@cargo-messages/android-arm-eabi/-/android-arm-eabi-0.0.160.tgz", - "integrity": "sha512-PTgCEmBHEPKJbxwlHVXB3aGES+NqpeBvn6hJNYWIkET3ZQCSJnScMlIDQXEkWndK7J+hW3Or3H32a93B/MbbfQ==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@cargo-messages/darwin-arm64": { - "version": "0.0.160", - "resolved": "https://registry.npmjs.org/@cargo-messages/darwin-arm64/-/darwin-arm64-0.0.160.tgz", - "integrity": "sha512-YSVUuc8TUTi/XmZVg9KrH0bDywKLqC1zeTyZYAYDDmqVDZW9KeTnbBUECKRs56iyHeO+kuEkVW7MKf7j2zb/FA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@cargo-messages/darwin-x64": { - "version": "0.0.160", - "resolved": "https://registry.npmjs.org/@cargo-messages/darwin-x64/-/darwin-x64-0.0.160.tgz", - "integrity": "sha512-U+YlAR+9tKpBljnNPWMop5YhvtwfIPQSAaUYN2llteC7ZNU5/cv8CGT1vm7uFNxr2LeGuAtRbzIh2gUmTV8mng==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@cargo-messages/linux-arm-gnueabihf": { - "version": "0.0.160", - "resolved": "https://registry.npmjs.org/@cargo-messages/linux-arm-gnueabihf/-/linux-arm-gnueabihf-0.0.160.tgz", - "integrity": "sha512-wqAelTzVv1E7Ls4aviqUbem5xjzCaJQxQtVnLhv6pf1k0UyEHCS2WdufFFmWcojGe7QglI4uve3KTe01MKYj0A==", - "cpu": [ - "arm" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@cargo-messages/linux-x64-gnu": { - "version": "0.0.160", - "resolved": "https://registry.npmjs.org/@cargo-messages/linux-x64-gnu/-/linux-x64-gnu-0.0.160.tgz", - "integrity": "sha512-LQ6e7O7YYkWfDNIi/53q2QG/+lZok72LOG+NKDVCrrY4TYUcrTqWAybOV6IlkVntKPnpx8YB95umSQGeVuvhpQ==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@cargo-messages/win32-arm64-msvc": { - "version": "0.0.160", - "resolved": "https://registry.npmjs.org/@cargo-messages/win32-arm64-msvc/-/win32-arm64-msvc-0.0.160.tgz", - "integrity": "sha512-VDMBhyun02gIDwmEhkYP1W9Z0tYqn4drgY5Iua1qV2tYOU58RVkWhzUYxM9rzYbnwKZlltgM46J/j5QZ3VaFrA==", - "cpu": [ - "arm64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@cargo-messages/win32-x64-msvc": { - "version": "0.0.160", - "resolved": "https://registry.npmjs.org/@cargo-messages/win32-x64-msvc/-/win32-x64-msvc-0.0.160.tgz", - "integrity": "sha512-vnoglDxF6zj0W/Co9D0H/bgnrhUuO5EumIf9v3ujLtBH94rAX11JsXh/FgC/8wQnQSsLyWSq70YxNS2wdETxjA==", - "cpu": [ - "x64" - ], - "dev": true, - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", - "dev": true, - "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.11.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.11.1.tgz", - "integrity": "sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==", - "dev": true, - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", - "dev": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/js": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", - "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", - "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", - "deprecated": "Use @eslint/config-array instead", - "dev": true, - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.3", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", - "dev": true - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "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 - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@lancedb/vectordb-darwin-arm64": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/@lancedb/vectordb-darwin-arm64/-/vectordb-darwin-arm64-0.21.2.tgz", - "integrity": "sha512-NAQnIKLw9K33KMODNXBEW0qC8/safWzZtqbVC7j1GcE7PSk0Uc6x7w5nrH5gvleZggjaxY9jaRVTqmtg7PNmqw==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@lancedb/vectordb-darwin-x64": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/@lancedb/vectordb-darwin-x64/-/vectordb-darwin-x64-0.21.2.tgz", - "integrity": "sha512-PudbltlbRiXvBf/bkAaDPL8+RqcI4TG69u00rQHxwkhH7PgPYRTUjfzfaQfiDXZuLXuZHQq703RyoHOqzsHN0Q==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@lancedb/vectordb-linux-arm64-gnu": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/@lancedb/vectordb-linux-arm64-gnu/-/vectordb-linux-arm64-gnu-0.21.2.tgz", - "integrity": "sha512-3lJ8lootlwLmhqabCdg0DKftv0Ujep6NTWAoLWK/6VQe2IgHmu/ZPRNQkOSZ5tnYlmRyDiMDMB2tlAzo45sV8Q==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@lancedb/vectordb-linux-x64-gnu": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/@lancedb/vectordb-linux-x64-gnu/-/vectordb-linux-x64-gnu-0.21.2.tgz", - "integrity": "sha512-5I2drMOIyRODlAHPsipQBTrRRgcOZ45N5GsuhqcKnz3Tg8GAdc1MQKyK3BrdJzKHLPdRtIyRJ6QTLB3wZvDsQQ==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@lancedb/vectordb-win32-x64-msvc": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/@lancedb/vectordb-win32-x64-msvc/-/vectordb-win32-x64-msvc-0.21.2.tgz", - "integrity": "sha512-gjpFukq0NTQSRpWPNIpq4XFtaudjSNBT6DMsagC61D2nx9ZLEdSAdU0wdkeluQwhoMvNnXEPdP9HxDSFUXk+Ww==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@neon-rs/cli": { - "version": "0.0.160", - "resolved": "https://registry.npmjs.org/@neon-rs/cli/-/cli-0.0.160.tgz", - "integrity": "sha512-GQjzHPJVTOARbX3nP/fAWqBq7JlQ8XgfYlCa+iwzIXf0LC1EyfJTX+vqGD/36b9lKoyY01Z/aDUB9o/qF6ztHA==", - "dev": true, - "bin": { - "neon": "index.js" - }, - "optionalDependencies": { - "@cargo-messages/android-arm-eabi": "0.0.160", - "@cargo-messages/darwin-arm64": "0.0.160", - "@cargo-messages/darwin-x64": "0.0.160", - "@cargo-messages/linux-arm-gnueabihf": "0.0.160", - "@cargo-messages/linux-x64-gnu": "0.0.160", - "@cargo-messages/win32-arm64-msvc": "0.0.160", - "@cargo-messages/win32-x64-msvc": "0.0.160" - } - }, - "node_modules/@neon-rs/load": { - "version": "0.0.74", - "resolved": "https://registry.npmjs.org/@neon-rs/load/-/load-0.0.74.tgz", - "integrity": "sha512-/cPZD907UNz55yrc/ud4wDgQKtU1TvkD9jeqZWG6J4IMmZkp6zgjkQcKA8UvpkZlcpPHvc8J17sGzLFbP/LUYg==" - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@rtsao/scc": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", - "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", - "dev": true - }, - "node_modules/@sinonjs/commons": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", - "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", - "dev": true, - "dependencies": { - "type-detect": "4.0.8" - } - }, - "node_modules/@sinonjs/commons/node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/@sinonjs/fake-timers": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", - "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^3.0.0" - } - }, - "node_modules/@sinonjs/samsam": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.2.tgz", - "integrity": "sha512-v46t/fwnhejRSFTGqbpn9u+LQ9xJDse10gNnPgAcxgdoCDMXj/G2asWAC/8Qs+BAZDicX+MNZouXT1A7c83kVw==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^3.0.1", - "lodash.get": "^4.4.2", - "type-detect": "^4.1.0" - } - }, - "node_modules/@sinonjs/text-encoding": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.3.tgz", - "integrity": "sha512-DE427ROAphMQzU4ENbliGYrBSYPXF+TtLg9S8vzeA+OF4ZKzoDdzfL8sxuMUGS/lgRhM6j1URSk9ghf7Xo1tyA==", - "dev": true - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", - "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "dev": true - }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", - "dev": true - }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true - }, - "node_modules/@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", - "dev": true - }, - "node_modules/@types/chai": { - "version": "4.3.20", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.20.tgz", - "integrity": "sha512-/pC9HAB5I/xMlc5FP77qjCnI16ChlJfW0tGa0IUcFn38VJrTV6DeZ60NU5KZBtaOZqjdpwTWohz5HU1RrhiYxQ==", - "dev": true - }, - "node_modules/@types/chai-as-promised": { - "version": "7.1.8", - "resolved": "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-7.1.8.tgz", - "integrity": "sha512-ThlRVIJhr69FLlh6IctTXFkmhtP3NpMZ2QGq69StYLyKZFp/HOp1VdKZj7RvfNWYYcJ1xlbLGLLWj1UvP5u/Gw==", - "dev": true, - "dependencies": { - "@types/chai": "*" - } - }, - "node_modules/@types/command-line-args": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@types/command-line-args/-/command-line-args-5.2.0.tgz", - "integrity": "sha512-UuKzKpJJ/Ief6ufIaIzr3A/0XnluX7RvFgwkV89Yzvm77wCh1kFaFmqN8XEnGcN62EuHdedQjEMb8mYxFLGPyA==" - }, - "node_modules/@types/command-line-usage": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/@types/command-line-usage/-/command-line-usage-5.0.2.tgz", - "integrity": "sha512-n7RlEEJ+4x4TS7ZQddTmNSxP+zziEG0TNsMfiRIxcIVXt71ENJ9ojeXmGO3wPoTdn7pJcU2xc3CJYMktNT6DPg==" - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true - }, - "node_modules/@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true - }, - "node_modules/@types/mocha": { - "version": "10.0.9", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.9.tgz", - "integrity": "sha512-sicdRoWtYevwxjOHNMPTl3vSfJM6oyW8o1wXeI7uww6b6xHg8eBznQDNSGBCDJmsE8UMxP05JgZRtsKbTqt//Q==", - "dev": true - }, - "node_modules/@types/node": { - "version": "18.19.55", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.55.tgz", - "integrity": "sha512-zzw5Vw52205Zr/nmErSEkN5FLqXPuKX/k5d1D7RKHATGqU7y6YfX9QxZraUzUrFGqH6XzOzG196BC35ltJC4Cw==", - "dev": true, - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@types/node-fetch": { - "version": "2.6.11", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.11.tgz", - "integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==", - "dev": true, - "dependencies": { - "@types/node": "*", - "form-data": "^4.0.0" - } - }, - "node_modules/@types/pad-left": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/@types/pad-left/-/pad-left-2.1.1.tgz", - "integrity": "sha512-Xd22WCRBydkGSApl5Bw0PhAOHKSVjNL3E3AwzKaps96IMraPqy5BvZIsBVK6JLwdybUzjHnuWVwpDd0JjTfHXA==" - }, - "node_modules/@types/semver": { - "version": "7.5.8", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", - "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", - "dev": true - }, - "node_modules/@types/sinon": { - "version": "10.0.20", - "resolved": "https://registry.npmjs.org/@types/sinon/-/sinon-10.0.20.tgz", - "integrity": "sha512-2APKKruFNCAZgx3daAyACGzWuJ028VVCUDk6o2rw/Z4PXT0ogwdV4KUegW0MwVs0Zu59auPXbbuBJHF12Sx1Eg==", - "dev": true, - "dependencies": { - "@types/sinonjs__fake-timers": "*" - } - }, - "node_modules/@types/sinonjs__fake-timers": { - "version": "8.1.5", - "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.5.tgz", - "integrity": "sha512-mQkU2jY8jJEF7YHjHvsQO8+3ughTL1mcnn96igfhONmR+fUPSKIkefQYpSe8bsly2Ep7oQbn/6VG5/9/0qcArQ==", - "dev": true - }, - "node_modules/@types/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ==", - "dev": true - }, - "node_modules/@types/strip-json-comments": { - "version": "0.0.30", - "resolved": "https://registry.npmjs.org/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz", - "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==", - "dev": true - }, - "node_modules/@types/temp": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/@types/temp/-/temp-0.9.4.tgz", - "integrity": "sha512-+VfWIwrlept2VBTj7Y2wQnI/Xfscy1u8Pyj/puYwss6V1IblXn1x7S0S9eFh6KyBolgLCm+rUFzhFAbdkR691g==", - "dev": true, - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/uuid": { - "version": "9.0.8", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.8.tgz", - "integrity": "sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA==", - "dev": true - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.62.0.tgz", - "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", - "dev": true, - "dependencies": { - "@eslint-community/regexpp": "^4.4.0", - "@typescript-eslint/scope-manager": "5.62.0", - "@typescript-eslint/type-utils": "5.62.0", - "@typescript-eslint/utils": "5.62.0", - "debug": "^4.3.4", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "natural-compare-lite": "^1.4.0", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^5.0.0", - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.62.0.tgz", - "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", - "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "5.62.0", - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/typescript-estree": "5.62.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", - "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.62.0.tgz", - "integrity": "sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==", - "dev": true, - "dependencies": { - "@typescript-eslint/typescript-estree": "5.62.0", - "@typescript-eslint/utils": "5.62.0", - "debug": "^4.3.4", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "*" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/types": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", - "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", - "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", - "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@types/json-schema": "^7.0.9", - "@types/semver": "^7.3.12", - "@typescript-eslint/scope-manager": "5.62.0", - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/typescript-estree": "5.62.0", - "eslint-scope": "^5.1.1", - "semver": "^7.3.7" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", - "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.62.0", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@ungap/structured-clone": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true - }, - "node_modules/abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "dev": true, - "dependencies": { - "event-target-shim": "^5.0.0" - }, - "engines": { - "node": ">=6.5" - } - }, - "node_modules/acorn": { - "version": "8.12.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", - "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" - } - }, - "node_modules/acorn-walk": { - "version": "8.3.4", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", - "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", - "dev": true, - "dependencies": { - "acorn": "^8.11.0" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/agentkeepalive": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", - "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", - "dev": true, - "dependencies": { - "humanize-ms": "^1.2.1" - }, - "engines": { - "node": ">= 8.0.0" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-sequence-parser": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ansi-sequence-parser/-/ansi-sequence-parser-1.1.1.tgz", - "integrity": "sha512-vJXt3yiaUL4UU546s3rPXlsry/RnM730G1+HkpKE012AN0sx1eOrxSu95oKDIonskeLTijMgqWZ3uDEe3NFvyg==", - "dev": true - }, - "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==", - "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", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/apache-arrow": { - "version": "14.0.2", - "resolved": "https://registry.npmjs.org/apache-arrow/-/apache-arrow-14.0.2.tgz", - "integrity": "sha512-EBO2xJN36/XoY81nhLcwCJgFwkboDZeyNQ+OPsG7bCoQjc2BT0aTyH/MR6SrL+LirSNz+cYqjGRlupMMlP1aEg==", - "peer": true, - "dependencies": { - "@types/command-line-args": "5.2.0", - "@types/command-line-usage": "5.0.2", - "@types/node": "20.3.0", - "@types/pad-left": "2.1.1", - "command-line-args": "5.2.1", - "command-line-usage": "7.0.1", - "flatbuffers": "23.5.26", - "json-bignum": "^0.0.3", - "pad-left": "^2.1.0", - "tslib": "^2.5.3" - }, - "bin": { - "arrow2csv": "bin/arrow2csv.js" - } - }, - "node_modules/apache-arrow-old": { - "name": "apache-arrow", - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/apache-arrow/-/apache-arrow-13.0.0.tgz", - "integrity": "sha512-3gvCX0GDawWz6KFNC28p65U+zGh/LZ6ZNKWNu74N6CQlKzxeoWHpi4CgEQsgRSEMuyrIIXi1Ea2syja7dwcHvw==", - "dev": true, - "dependencies": { - "@types/command-line-args": "5.2.0", - "@types/command-line-usage": "5.0.2", - "@types/node": "20.3.0", - "@types/pad-left": "2.1.1", - "command-line-args": "5.2.1", - "command-line-usage": "7.0.1", - "flatbuffers": "23.5.26", - "json-bignum": "^0.0.3", - "pad-left": "^2.1.0", - "tslib": "^2.5.3" - }, - "bin": { - "arrow2csv": "bin/arrow2csv.js" - } - }, - "node_modules/apache-arrow-old/node_modules/@types/node": { - "version": "20.3.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.0.tgz", - "integrity": "sha512-cumHmIAf6On83X7yP+LrsEyUOf/YlociZelmpRYaGFydoaPdxdt80MAbu6vWerQT2COCp2nPvHdsbD7tHn/YlQ==", - "dev": true - }, - "node_modules/apache-arrow/node_modules/@types/node": { - "version": "20.3.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.0.tgz", - "integrity": "sha512-cumHmIAf6On83X7yP+LrsEyUOf/YlociZelmpRYaGFydoaPdxdt80MAbu6vWerQT2COCp2nPvHdsbD7tHn/YlQ==", - "peer": true - }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/array-back": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-3.1.0.tgz", - "integrity": "sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==", - "engines": { - "node": ">=6" - } - }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", - "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "is-array-buffer": "^3.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-includes": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", - "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.4", - "is-string": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/array.prototype.findlastindex": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz", - "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flat": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", - "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flatmap": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", - "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", - "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.2.1", - "get-intrinsic": "^1.2.3", - "is-array-buffer": "^3.0.4", - "is-shared-array-buffer": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" - }, - "node_modules/available-typed-arrays": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", - "dev": true, - "dependencies": { - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/axios": { - "version": "1.8.4", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.8.4.tgz", - "integrity": "sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==", - "license": "MIT", - "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.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 - }, - "node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, - "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, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/browser-stdout": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", - "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", - "dev": true - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "node_modules/builtins": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.1.0.tgz", - "integrity": "sha512-SW9lzGTLvWTP1AY8xeAMZimqDrIaSdLQUcVr9DMef51niJ022Ri87SwRRKYm4A6iHfkPaiVUu/Duw2Wc4J7kKg==", - "dev": true, - "dependencies": { - "semver": "^7.0.0" - } - }, - "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", - "dev": true, - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", - "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cargo-cp-artifact": { - "version": "0.1.9", - "resolved": "https://registry.npmjs.org/cargo-cp-artifact/-/cargo-cp-artifact-0.1.9.tgz", - "integrity": "sha512-6F+UYzTaGB+awsTXg0uSJA1/b/B3DDJzpKVRu0UmyI7DmNeaAl2RFHuTGIN6fEgpadRxoXGb7gbC1xo4C3IdyA==", - "dev": true, - "bin": { - "cargo-cp-artifact": "bin/cargo-cp-artifact.js" - } - }, - "node_modules/chai": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz", - "integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==", - "dev": true, - "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.3", - "deep-eql": "^4.1.3", - "get-func-name": "^2.0.2", - "loupe": "^2.3.6", - "pathval": "^1.1.1", - "type-detect": "^4.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chai-as-promised": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-7.1.2.tgz", - "integrity": "sha512-aBDHZxRzYnUYuIAIPBH2s511DjlKPzXNlXSGFC8CwmroWQLfrW0LtE1nK3MAwwNhJPa9raEjNCmRoFpG0Hurdw==", - "dev": true, - "dependencies": { - "check-error": "^1.0.2" - }, - "peerDependencies": { - "chai": ">= 2.1.2 < 6" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "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/chalk-template": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/chalk-template/-/chalk-template-0.4.0.tgz", - "integrity": "sha512-/ghrgmhfY8RaSdeo43hNXxpoHAtxdbskUHjPpfqUWGttFgycUhYPGx3YZBCnUCvOa7Doivn1IZec3DEGFoMgLg==", - "dependencies": { - "chalk": "^4.1.2" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/chalk-template?sponsor=1" - } - }, - "node_modules/check-error": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", - "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", - "dev": true, - "dependencies": { - "get-func-name": "^2.0.2" - }, - "engines": { - "node": "*" - } - }, - "node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "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/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "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==", - "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==" - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/command-line-args": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-5.2.1.tgz", - "integrity": "sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==", - "dependencies": { - "array-back": "^3.1.0", - "find-replace": "^3.0.0", - "lodash.camelcase": "^4.3.0", - "typical": "^4.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/command-line-usage": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-7.0.1.tgz", - "integrity": "sha512-NCyznE//MuTjwi3y84QVUGEOT+P5oto1e1Pk/jFPVdPPfsG03qpTIl3yw6etR+v73d0lXsoojRpvbru2sqePxQ==", - "dependencies": { - "array-back": "^6.2.2", - "chalk-template": "^0.4.0", - "table-layout": "^3.0.0", - "typical": "^7.1.1" - }, - "engines": { - "node": ">=12.20.0" - } - }, - "node_modules/command-line-usage/node_modules/array-back": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-6.2.2.tgz", - "integrity": "sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw==", - "engines": { - "node": ">=12.17" - } - }, - "node_modules/command-line-usage/node_modules/typical": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/typical/-/typical-7.2.0.tgz", - "integrity": "sha512-W1+HdVRUl8fS3MZ9ogD51GOb46xMmhAZzR0WPw5jcgIZQJVvkddYzAl4YTU6g5w33Y1iRQLdIi2/1jhi2RNL0g==", - "engines": { - "node": ">=12.17" - } - }, - "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 - }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, - "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, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/data-view-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", - "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.6", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/data-view-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", - "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/data-view-byte-offset": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", - "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.6", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decamelize": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", - "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/deep-eql": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", - "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", - "dev": true, - "dependencies": { - "type-detect": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "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, - "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/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dev": true, - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/diff": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", - "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/dynamic-dedupe": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz", - "integrity": "sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ==", - "dev": true, - "dependencies": { - "xtend": "^4.0.0" - } - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/es-abstract": { - "version": "1.23.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", - "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", - "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "arraybuffer.prototype.slice": "^1.0.3", - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "data-view-buffer": "^1.0.1", - "data-view-byte-length": "^1.0.1", - "data-view-byte-offset": "^1.0.0", - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-set-tostringtag": "^2.0.3", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.4", - "get-symbol-description": "^1.0.2", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.3", - "has-symbols": "^1.0.3", - "hasown": "^2.0.2", - "internal-slot": "^1.0.7", - "is-array-buffer": "^3.0.4", - "is-callable": "^1.2.7", - "is-data-view": "^1.0.1", - "is-negative-zero": "^2.0.3", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.3", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.13", - "is-weakref": "^1.0.2", - "object-inspect": "^1.13.1", - "object-keys": "^1.1.1", - "object.assign": "^4.1.5", - "regexp.prototype.flags": "^1.5.2", - "safe-array-concat": "^1.1.2", - "safe-regex-test": "^1.0.3", - "string.prototype.trim": "^1.2.9", - "string.prototype.trimend": "^1.0.8", - "string.prototype.trimstart": "^1.0.8", - "typed-array-buffer": "^1.0.2", - "typed-array-byte-length": "^1.0.1", - "typed-array-byte-offset": "^1.0.2", - "typed-array-length": "^1.0.6", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.15" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.4" - }, - "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, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", - "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", - "dev": true, - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", - "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.4", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-shim-unscopables": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", - "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", - "dev": true, - "dependencies": { - "hasown": "^2.0.0" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", - "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", - "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", - "dev": true, - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.1", - "@humanwhocodes/config-array": "^0.13.0", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-config-standard": { - "version": "17.0.0", - "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.0.0.tgz", - "integrity": "sha512-/2ks1GKyqSOkH7JFvXJicu0iMpoojkwB+f5Du/1SC0PtBL+s8v30k9njRZ21pm2drKYm2342jFnGWzttxPmZVg==", - "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" - } - ], - "peerDependencies": { - "eslint": "^8.0.1", - "eslint-plugin-import": "^2.25.2", - "eslint-plugin-n": "^15.0.0", - "eslint-plugin-promise": "^6.0.0" - } - }, - "node_modules/eslint-config-standard-with-typescript": { - "version": "34.0.1", - "resolved": "https://registry.npmjs.org/eslint-config-standard-with-typescript/-/eslint-config-standard-with-typescript-34.0.1.tgz", - "integrity": "sha512-J7WvZeLtd0Vr9F+v4dZbqJCLD16cbIy4U+alJMq4MiXdpipdBM3U5NkXaGUjePc4sb1ZE01U9g6VuTBpHHz1fg==", - "deprecated": "Please use eslint-config-love, instead.", - "dev": true, - "dependencies": { - "@typescript-eslint/parser": "^5.43.0", - "eslint-config-standard": "17.0.0" - }, - "peerDependencies": { - "@typescript-eslint/eslint-plugin": "^5.43.0", - "eslint": "^8.0.1", - "eslint-plugin-import": "^2.25.2", - "eslint-plugin-n": "^15.0.0", - "eslint-plugin-promise": "^6.0.0", - "typescript": "*" - } - }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", - "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", - "dev": true, - "dependencies": { - "debug": "^3.2.7", - "is-core-module": "^2.13.0", - "resolve": "^1.22.4" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-module-utils": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz", - "integrity": "sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==", - "dev": true, - "dependencies": { - "debug": "^3.2.7" - }, - "engines": { - "node": ">=4" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } - } - }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-es": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-4.1.0.tgz", - "integrity": "sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ==", - "dev": true, - "dependencies": { - "eslint-utils": "^2.0.0", - "regexpp": "^3.0.0" - }, - "engines": { - "node": ">=8.10.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=4.19.1" - } - }, - "node_modules/eslint-plugin-es/node_modules/eslint-utils": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", - "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^1.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/eslint-plugin-es/node_modules/eslint-visitor-keys": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", - "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/eslint-plugin-import": { - "version": "2.31.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz", - "integrity": "sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A==", - "dev": true, - "dependencies": { - "@rtsao/scc": "^1.1.0", - "array-includes": "^3.1.8", - "array.prototype.findlastindex": "^1.2.5", - "array.prototype.flat": "^1.3.2", - "array.prototype.flatmap": "^1.3.2", - "debug": "^3.2.7", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.9", - "eslint-module-utils": "^2.12.0", - "hasown": "^2.0.2", - "is-core-module": "^2.15.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.fromentries": "^2.0.8", - "object.groupby": "^1.0.3", - "object.values": "^1.2.0", - "semver": "^6.3.1", - "string.prototype.trimend": "^1.0.8", - "tsconfig-paths": "^3.15.0" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" - } - }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/eslint-plugin-n": { - "version": "15.7.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-15.7.0.tgz", - "integrity": "sha512-jDex9s7D/Qial8AGVIHq4W7NswpUD5DPDL2RH8Lzd9EloWUuvUkHfv4FRLMipH5q2UtyurorBkPeNi1wVWNh3Q==", - "dev": true, - "dependencies": { - "builtins": "^5.0.1", - "eslint-plugin-es": "^4.1.0", - "eslint-utils": "^3.0.0", - "ignore": "^5.1.1", - "is-core-module": "^2.11.0", - "minimatch": "^3.1.2", - "resolve": "^1.22.1", - "semver": "^7.3.8" - }, - "engines": { - "node": ">=12.22.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } - }, - "node_modules/eslint-plugin-promise": { - "version": "6.6.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.6.0.tgz", - "integrity": "sha512-57Zzfw8G6+Gq7axm2Pdo3gW/Rx3h9Yywgn61uE/3elTCOePEHVrn2i5CdfBwA1BLK0Q0WqctICIUSqXZW/VprQ==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" - } - }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/eslint-utils": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", - "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", - "dev": true, - "dependencies": { - "eslint-visitor-keys": "^2.0.0" - }, - "engines": { - "node": "^10.0.0 || ^12.0.0 || >= 14.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - }, - "peerDependencies": { - "eslint": ">=5" - } - }, - "node_modules/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", - "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", - "dev": true, - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esquery/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/event-target-shim": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dev": true, - "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.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", - "dev": true, - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-replace": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-3.0.0.tgz", - "integrity": "sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==", - "dependencies": { - "array-back": "^3.0.1" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", - "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, - "bin": { - "flat": "cli.js" - } - }, - "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", - "dev": true, - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatbuffers": { - "version": "23.5.26", - "resolved": "https://registry.npmjs.org/flatbuffers/-/flatbuffers-23.5.26.tgz", - "integrity": "sha512-vE+SI9vrJDwi1oETtTIFldC/o9GsVKRM+s6EL0nQgxXlYV1Vc4Tk30hj4xGICftInKQKj1F3up2n8UbIVobISQ==" - }, - "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true - }, - "node_modules/follow-redirects": { - "version": "1.15.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", - "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.3" - } - }, - "node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/form-data-encoder": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz", - "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==", - "dev": true - }, - "node_modules/formdata-node": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", - "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", - "dev": true, - "dependencies": { - "node-domexception": "1.0.0", - "web-streams-polyfill": "4.0.0-beta.3" - }, - "engines": { - "node": ">= 12.20" - } - }, - "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 - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "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, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/function.prototype.name": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-func-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", - "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", - "dev": true, - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-symbol-description": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", - "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/glob": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", - "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globalthis": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", - "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", - "dev": true, - "dependencies": { - "define-properties": "^1.2.1", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "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.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "node_modules/handlebars": { - "version": "4.7.8", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", - "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", - "dev": true, - "dependencies": { - "minimist": "^1.2.5", - "neo-async": "^2.6.2", - "source-map": "^0.6.1", - "wordwrap": "^1.0.0" - }, - "bin": { - "handlebars": "bin/handlebars" - }, - "engines": { - "node": ">=0.4.7" - }, - "optionalDependencies": { - "uglify-js": "^3.1.4" - } - }, - "node_modules/has-bigints": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", - "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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==", - "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, - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.3" - }, - "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, - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/he": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", - "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", - "dev": true, - "bin": { - "he": "bin/he" - } - }, - "node_modules/humanize-ms": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", - "dev": true, - "dependencies": { - "ms": "^2.0.0" - } - }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "engines": { - "node": ">=0.8.19" - } - }, - "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, - "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 - }, - "node_modules/internal-slot": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", - "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", - "dev": true, - "dependencies": { - "es-errors": "^1.3.0", - "hasown": "^2.0.0", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/is-array-buffer": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", - "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "version": "2.15.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.15.1.tgz", - "integrity": "sha512-z0vtXSwucUJtANQWldhbtbt7BnL0vxiFjIdDLAatwhDYty2bad6s+rijD6Ri4YuYJubLzIJLUidCh09e1djEVQ==", - "dev": true, - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-data-view": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", - "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", - "dev": true, - "dependencies": { - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", - "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-plain-obj": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", - "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", - "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", - "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", - "dev": true, - "dependencies": { - "which-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-unicode-supported": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", - "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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 - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-bignum": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/json-bignum/-/json-bignum-0.0.3.tgz", - "integrity": "sha512-2WHyXj3OfHSgNyuzDbSxI1w2jgw5gkWSWhS7Qg4bWXx1nLk3jnbwfUeS0PSba3IzpTUWdHxBieELUzXRjQB2zg==", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "json5": "lib/cli.js" - } - }, - "node_modules/jsonc-parser": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", - "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", - "dev": true - }, - "node_modules/just-extend": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-6.2.0.tgz", - "integrity": "sha512-cYofQu2Xpom82S6qD778jBDpwvvy39s1l/hrYij2u9AMdQcGRpaBu6kY4mVhuno5kJVi1DAz4aiphA2WI1/OAw==", - "dev": true - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" - }, - "node_modules/lodash.camelcase": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==" - }, - "node_modules/lodash.get": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", - "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", - "dev": true - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "node_modules/log-symbols": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", - "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", - "dev": true, - "dependencies": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/loupe": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", - "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", - "dev": true, - "dependencies": { - "get-func-name": "^2.0.1" - } - }, - "node_modules/lunr": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", - "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", - "dev": true - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "node_modules/marked": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz", - "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==", - "dev": true, - "bin": { - "marked": "bin/marked.js" - }, - "engines": { - "node": ">= 12" - } - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.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, - "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, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dev": true, - "dependencies": { - "minimist": "^1.2.6" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/mocha": { - "version": "10.7.3", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.7.3.tgz", - "integrity": "sha512-uQWxAu44wwiACGqjbPYmjo7Lg8sFrS3dQe7PP2FQI+woptP4vZXSMcfMyFL/e1yFEeEpV4RtyTpZROOKmxis+A==", - "dev": true, - "dependencies": { - "ansi-colors": "^4.1.3", - "browser-stdout": "^1.3.1", - "chokidar": "^3.5.3", - "debug": "^4.3.5", - "diff": "^5.2.0", - "escape-string-regexp": "^4.0.0", - "find-up": "^5.0.0", - "glob": "^8.1.0", - "he": "^1.2.0", - "js-yaml": "^4.1.0", - "log-symbols": "^4.1.0", - "minimatch": "^5.1.6", - "ms": "^2.1.3", - "serialize-javascript": "^6.0.2", - "strip-json-comments": "^3.1.1", - "supports-color": "^8.1.1", - "workerpool": "^6.5.1", - "yargs": "^16.2.0", - "yargs-parser": "^20.2.9", - "yargs-unparser": "^2.0.0" - }, - "bin": { - "_mocha": "bin/_mocha", - "mocha": "bin/mocha.js" - }, - "engines": { - "node": ">= 14.0.0" - } - }, - "node_modules/mocha/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/mocha/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/mocha/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "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 - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true - }, - "node_modules/natural-compare-lite": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", - "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", - "dev": true - }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true - }, - "node_modules/nise": { - "version": "5.1.9", - "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.9.tgz", - "integrity": "sha512-qOnoujW4SV6e40dYxJOb3uvuoPHtmLzIk4TFo+j0jPJoC+5Z9xja5qH5JZobEPsa8+YYphMrOSwnrshEhG2qww==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^3.0.0", - "@sinonjs/fake-timers": "^11.2.2", - "@sinonjs/text-encoding": "^0.7.2", - "just-extend": "^6.2.0", - "path-to-regexp": "^6.2.1" - } - }, - "node_modules/nise/node_modules/@sinonjs/fake-timers": { - "version": "11.3.1", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-11.3.1.tgz", - "integrity": "sha512-EVJO7nW5M/F5Tur0Rf2z/QoMo+1Ia963RiMtapiQrEWvY0iBUvADo8Beegwjpnle5BHkyHuoxSTW3jF43H1XRA==", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^3.0.1" - } - }, - "node_modules/node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "github", - "url": "https://paypal.me/jimmywarting" - } - ], - "engines": { - "node": ">=10.5.0" - } - }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dev": true, - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.2.tgz", - "integrity": "sha512-IRZSRuzJiynemAXPYtPe5BoI/RESNYR7TYm50MC5Mqbd3Jmw5y790sErYw3V6SryFJD64b74qQQs9wn5Bg/k3g==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", - "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.5", - "define-properties": "^1.2.1", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.fromentries": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", - "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.groupby": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz", - "integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.values": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", - "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "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, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/openai": { - "version": "4.67.3", - "resolved": "https://registry.npmjs.org/openai/-/openai-4.67.3.tgz", - "integrity": "sha512-HT2tZgjLgRqbLQNKmYtjdF/4TQuiBvg1oGvTDhwpSEQzxo6/oM1us8VQ53vBK2BiKvCxFuq6gKGG70qfwrNhKg==", - "dev": true, - "dependencies": { - "@types/node": "^18.11.18", - "@types/node-fetch": "^2.6.4", - "abort-controller": "^3.0.0", - "agentkeepalive": "^4.2.1", - "form-data-encoder": "1.7.2", - "formdata-node": "^4.3.2", - "node-fetch": "^2.6.7" - }, - "bin": { - "openai": "bin/cli" - }, - "peerDependencies": { - "zod": "^3.23.8" - }, - "peerDependenciesMeta": { - "zod": { - "optional": true - } - } - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/pad-left": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/pad-left/-/pad-left-2.1.0.tgz", - "integrity": "sha512-HJxs9K9AztdIQIAIa/OIazRAUW/L6B9hbQDxO4X07roW3eo9XqZc2ur9bn1StH9CnbbI9EgvejHQX7CBpCF1QA==", - "dependencies": { - "repeat-string": "^1.5.4" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "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, - "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, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/path-to-regexp": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", - "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", - "dev": true - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/possible-typed-array-names": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", - "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "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" - } - ] - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz", - "integrity": "sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-errors": "^1.3.0", - "set-function-name": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regexpp": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", - "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/mysticatea" - } - }, - "node_modules/repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", - "engines": { - "node": ">=0.10" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", - "dev": true, - "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/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, - "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/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "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" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-array-concat": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", - "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "get-intrinsic": "^1.2.4", - "has-symbols": "^1.0.3", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">=0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "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" - } - ] - }, - "node_modules/safe-regex-test": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", - "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.6", - "es-errors": "^1.3.0", - "is-regex": "^1.1.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/serialize-javascript": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", - "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", - "dev": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "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, - "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/set-function-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", - "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", - "dev": true, - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "functions-have-names": "^1.2.3", - "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, - "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, - "engines": { - "node": ">=8" - } - }, - "node_modules/shiki": { - "version": "0.14.7", - "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.7.tgz", - "integrity": "sha512-dNPAPrxSc87ua2sKJ3H5dQ/6ZaY8RNnaAqK+t0eG7p0Soi2ydiqbGOTaZCqaYvA/uZYfS1LJnemt3Q+mSfcPCg==", - "dev": true, - "dependencies": { - "ansi-sequence-parser": "^1.1.0", - "jsonc-parser": "^3.2.0", - "vscode-oniguruma": "^1.7.0", - "vscode-textmate": "^8.0.0" - } - }, - "node_modules/side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/sinon": { - "version": "15.2.0", - "resolved": "https://registry.npmjs.org/sinon/-/sinon-15.2.0.tgz", - "integrity": "sha512-nPS85arNqwBXaIsFCkolHjGIkFo+Oxu9vbgmBJizLAhqe6P2o3Qmj3KCUoRkfhHtvgDhZdWD3risLHAUJ8npjw==", - "deprecated": "16.1.1", - "dev": true, - "dependencies": { - "@sinonjs/commons": "^3.0.0", - "@sinonjs/fake-timers": "^10.3.0", - "@sinonjs/samsam": "^8.0.0", - "diff": "^5.1.0", - "nise": "^5.1.4", - "supports-color": "^7.2.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/sinon" - } - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/stream-read-all": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/stream-read-all/-/stream-read-all-3.0.1.tgz", - "integrity": "sha512-EWZT9XOceBPlVJRrYcykW8jyRSZYbkb/0ZK36uLEmoWVO5gxBOnntNTseNzfREsqxqdfEGQrD8SXQ3QWbBmq8A==", - "engines": { - "node": ">=10" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string.prototype.trim": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", - "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.0", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", - "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", - "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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==", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/table-layout": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/table-layout/-/table-layout-3.0.2.tgz", - "integrity": "sha512-rpyNZYRw+/C+dYkcQ3Pr+rLxW4CfHpXjPDnG7lYhdRoUcZTUt+KEsX+94RGp/aVp/MQU35JCITv2T/beY4m+hw==", - "dependencies": { - "@75lb/deep-merge": "^1.1.1", - "array-back": "^6.2.2", - "command-line-args": "^5.2.1", - "command-line-usage": "^7.0.0", - "stream-read-all": "^3.0.1", - "typical": "^7.1.1", - "wordwrapjs": "^5.1.0" - }, - "bin": { - "table-layout": "bin/cli.js" - }, - "engines": { - "node": ">=12.17" - } - }, - "node_modules/table-layout/node_modules/array-back": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/array-back/-/array-back-6.2.2.tgz", - "integrity": "sha512-gUAZ7HPyb4SJczXAMUXMGAvI976JoK3qEx9v1FTmeYuJj0IBiaKttG1ydtGKdkfqWkIkouke7nG8ufGy77+Cvw==", - "engines": { - "node": ">=12.17" - } - }, - "node_modules/table-layout/node_modules/typical": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/typical/-/typical-7.2.0.tgz", - "integrity": "sha512-W1+HdVRUl8fS3MZ9ogD51GOb46xMmhAZzR0WPw5jcgIZQJVvkddYzAl4YTU6g5w33Y1iRQLdIi2/1jhi2RNL0g==", - "engines": { - "node": ">=12.17" - } - }, - "node_modules/temp": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/temp/-/temp-0.9.4.tgz", - "integrity": "sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==", - "dev": true, - "dependencies": { - "mkdirp": "^0.5.1", - "rimraf": "~2.6.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/temp/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, - "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/temp/node_modules/rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "dev": true - }, - "node_modules/tree-kill": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", - "dev": true, - "bin": { - "tree-kill": "cli.js" - } - }, - "node_modules/ts-node": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", - "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "dev": true, - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, - "node_modules/ts-node-dev": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ts-node-dev/-/ts-node-dev-2.0.0.tgz", - "integrity": "sha512-ywMrhCfH6M75yftYvrvNarLEY+SUXtUvU8/0Z6llrHQVBx12GiFk5sStF8UdfE/yfzk9IAq7O5EEbTQsxlBI8w==", - "dev": true, - "dependencies": { - "chokidar": "^3.5.1", - "dynamic-dedupe": "^0.3.0", - "minimist": "^1.2.6", - "mkdirp": "^1.0.4", - "resolve": "^1.0.0", - "rimraf": "^2.6.1", - "source-map-support": "^0.5.12", - "tree-kill": "^1.2.2", - "ts-node": "^10.4.0", - "tsconfig": "^7.0.0" - }, - "bin": { - "ts-node-dev": "lib/bin.js", - "tsnd": "lib/bin.js" - }, - "engines": { - "node": ">=0.8.0" - }, - "peerDependencies": { - "node-notifier": "*", - "typescript": "*" - }, - "peerDependenciesMeta": { - "node-notifier": { - "optional": true - } - } - }, - "node_modules/ts-node-dev/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, - "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/ts-node-dev/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/ts-node-dev/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, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/ts-node/node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/tsconfig": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-7.0.0.tgz", - "integrity": "sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==", - "dev": true, - "dependencies": { - "@types/strip-bom": "^3.0.0", - "@types/strip-json-comments": "0.0.30", - "strip-bom": "^3.0.0", - "strip-json-comments": "^2.0.0" - } - }, - "node_modules/tsconfig-paths": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", - "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", - "dev": true, - "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - } - }, - "node_modules/tsconfig/node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/tslib": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.7.0.tgz", - "integrity": "sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==" - }, - "node_modules/tsutils": { - "version": "3.21.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", - "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "engines": { - "node": ">= 6" - }, - "peerDependencies": { - "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" - } - }, - "node_modules/tsutils/node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-detect": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", - "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typed-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", - "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "es-errors": "^1.3.0", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/typed-array-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", - "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-byte-offset": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", - "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-length": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz", - "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13", - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typedoc": { - "version": "0.24.8", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.24.8.tgz", - "integrity": "sha512-ahJ6Cpcvxwaxfu4KtjA8qZNqS43wYt6JL27wYiIgl1vd38WW/KWX11YuAeZhuz9v+ttrutSsgK+XO1CjL1kA3w==", - "dev": true, - "dependencies": { - "lunr": "^2.3.9", - "marked": "^4.3.0", - "minimatch": "^9.0.0", - "shiki": "^0.14.1" - }, - "bin": { - "typedoc": "bin/typedoc" - }, - "engines": { - "node": ">= 14.14" - }, - "peerDependencies": { - "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x || 5.1.x" - } - }, - "node_modules/typedoc-plugin-markdown": { - "version": "3.17.1", - "resolved": "https://registry.npmjs.org/typedoc-plugin-markdown/-/typedoc-plugin-markdown-3.17.1.tgz", - "integrity": "sha512-QzdU3fj0Kzw2XSdoL15ExLASt2WPqD7FbLeaqwT70+XjKyTshBnUlQA5nNREO1C2P8Uen0CDjsBLMsCQ+zd0lw==", - "dev": true, - "dependencies": { - "handlebars": "^4.7.7" - }, - "peerDependencies": { - "typedoc": ">=0.24.0" - } - }, - "node_modules/typedoc/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/typedoc/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/typescript": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.1.6.tgz", - "integrity": "sha512-zaWCozRZ6DLEWAWFrVDz1H6FVXzUSfTy5FUMWsQlU8Ym5JP9eO4xkTIROFCQvhQf61z6O/G6ugw3SgAnvvm+HA==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/typical": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/typical/-/typical-4.0.0.tgz", - "integrity": "sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==", - "engines": { - "node": ">=8" - } - }, - "node_modules/uglify-js": { - "version": "3.19.3", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", - "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", - "dev": true, - "optional": true, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", - "dev": true, - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true - }, - "node_modules/vscode-oniguruma": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.7.0.tgz", - "integrity": "sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==", - "dev": true - }, - "node_modules/vscode-textmate": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-8.0.0.tgz", - "integrity": "sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==", - "dev": true - }, - "node_modules/web-streams-polyfill": { - "version": "4.0.0-beta.3", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", - "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", - "dev": true, - "engines": { - "node": ">= 14" - } - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "dev": true - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dev": true, - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "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, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", - "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", - "dev": true - }, - "node_modules/wordwrapjs": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-5.1.0.tgz", - "integrity": "sha512-JNjcULU2e4KJwUNv6CHgI46UvDGitb6dGryHajXTDiLgg1/RiGoPSDw4kZfYnwGtEXf2ZMeIewDQgFGzkCB2Sg==", - "engines": { - "node": ">=12.17" - } - }, - "node_modules/workerpool": { - "version": "6.5.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", - "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", - "dev": true - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "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 - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true, - "engines": { - "node": ">=0.4" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-unparser": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", - "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", - "dev": true, - "dependencies": { - "camelcase": "^6.0.0", - "decamelize": "^4.0.0", - "flat": "^5.0.2", - "is-plain-obj": "^2.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - } -} diff --git a/node/package.json b/node/package.json deleted file mode 100644 index a2365749..00000000 --- a/node/package.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "name": "vectordb", - "version": "0.21.2", - "description": " Serverless, low-latency vector database for AI applications", - "private": false, - "main": "dist/index.js", - "types": "dist/index.d.ts", - "scripts": { - "tsc": "tsc -b", - "build": "npm run tsc && cargo-cp-artifact --artifact cdylib lancedb_node index.node -- cargo build -p lancedb-node --message-format=json", - "build-release": "npm run build -- --release", - "test": "npm run tsc && mocha -recursive dist/test", - "integration-test": "npm run tsc && mocha -recursive dist/integration_test", - "lint": "eslint native.js src --ext .js,.ts", - "clean": "rm -rf node_modules *.node dist/", - "pack-build": "neon pack-build", - "check-npm": "printenv && which node && which npm && npm --version" - }, - "repository": { - "type": "git", - "url": "https://github.com/lancedb/lancedb.git" - }, - "homepage": "https://lancedb.github.io/lancedb/", - "bugs": { - "url": "https://github.com/lancedb/lancedb/issues" - }, - "keywords": [ - "data-format", - "data-science", - "machine-learning", - "data-analytics" - ], - "author": "Lance Devs", - "license": "Apache-2.0", - "devDependencies": { - "@neon-rs/cli": "^0.0.160", - "@types/chai": "^4.3.4", - "@types/chai-as-promised": "^7.1.5", - "@types/mocha": "^10.0.1", - "@types/node": "^18.16.2", - "@types/sinon": "^10.0.15", - "@types/temp": "^0.9.1", - "@types/uuid": "^9.0.3", - "@typescript-eslint/eslint-plugin": "^5.59.1", - "apache-arrow-old": "npm:apache-arrow@13.0.0", - "cargo-cp-artifact": "^0.1", - "chai": "^4.3.7", - "chai-as-promised": "^7.1.1", - "eslint": "^8.39.0", - "eslint-config-standard-with-typescript": "^34.0.1", - "eslint-plugin-import": "^2.26.0", - "eslint-plugin-n": "^15.7.0", - "eslint-plugin-promise": "^6.1.1", - "mocha": "^10.2.0", - "openai": "^4.24.1", - "sinon": "^15.1.0", - "temp": "^0.9.4", - "ts-node": "^10.9.1", - "ts-node-dev": "^2.0.0", - "typedoc": "^0.24.7", - "typedoc-plugin-markdown": "^3.15.3", - "typescript": "^5.1.0", - "uuid": "^9.0.0" - }, - "dependencies": { - "@neon-rs/load": "^0.0.74", - "axios": "^1.4.0" - }, - "peerDependencies": { - "@apache-arrow/ts": "^14.0.2", - "apache-arrow": "^14.0.2" - }, - "os": [ - "darwin", - "linux", - "win32" - ], - "cpu": [ - "x64", - "arm64" - ], - "neon": { - "targets": { - "x86_64-apple-darwin": "@lancedb/vectordb-darwin-x64", - "aarch64-apple-darwin": "@lancedb/vectordb-darwin-arm64", - "x86_64-unknown-linux-gnu": "@lancedb/vectordb-linux-x64-gnu", - "aarch64-unknown-linux-gnu": "@lancedb/vectordb-linux-arm64-gnu", - "x86_64-pc-windows-msvc": "@lancedb/vectordb-win32-x64-msvc" - } - }, - "optionalDependencies": { - "@lancedb/vectordb-darwin-x64": "0.21.2", - "@lancedb/vectordb-darwin-arm64": "0.21.2", - "@lancedb/vectordb-linux-x64-gnu": "0.21.2", - "@lancedb/vectordb-linux-arm64-gnu": "0.21.2", - "@lancedb/vectordb-win32-x64-msvc": "0.21.2" - } -} diff --git a/node/src/arrow.ts b/node/src/arrow.ts deleted file mode 100644 index 457c3040..00000000 --- a/node/src/arrow.ts +++ /dev/null @@ -1,635 +0,0 @@ -// Copyright 2023 Lance Developers. -// -// 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. - -import { - Field, - makeBuilder, - RecordBatchFileWriter, - Utf8, - type Vector, - FixedSizeList, - vectorFromArray, - Schema, - Table as ArrowTable, - RecordBatchStreamWriter, - List, - RecordBatch, - makeData, - Struct, - type Float, - DataType, - Binary, - Float32 -} from "apache-arrow"; -import { type EmbeddingFunction } from "./index"; -import { sanitizeSchema } from "./sanitize"; - -/* - * Options to control how a column should be converted to a vector array - */ -export class VectorColumnOptions { - /** Vector column type. */ - type: Float = new Float32(); - - constructor(values?: Partial) { - Object.assign(this, values); - } -} - -/** Options to control the makeArrowTable call. */ -export class MakeArrowTableOptions { - /* - * Schema of the data. - * - * If this is not provided then the data type will be inferred from the - * JS type. Integer numbers will become int64, floating point numbers - * will become float64 and arrays will become variable sized lists with - * the data type inferred from the first element in the array. - * - * The schema must be specified if there are no records (e.g. to make - * an empty table) - */ - schema?: Schema; - - /* - * Mapping from vector column name to expected type - * - * Lance expects vector columns to be fixed size list arrays (i.e. tensors) - * However, `makeArrowTable` will not infer this by default (it creates - * variable size list arrays). This field can be used to indicate that a column - * should be treated as a vector column and converted to a fixed size list. - * - * The keys should be the names of the vector columns. The value specifies the - * expected data type of the vector columns. - * - * If `schema` is provided then this field is ignored. - * - * By default, the column named "vector" will be assumed to be a float32 - * vector column. - */ - vectorColumns: Record = { - vector: new VectorColumnOptions() - }; - - embeddings?: EmbeddingFunction; - - /** - * If true then string columns will be encoded with dictionary encoding - * - * Set this to true if your string columns tend to repeat the same values - * often. For more precise control use the `schema` property to specify the - * data type for individual columns. - * - * If `schema` is provided then this property is ignored. - */ - dictionaryEncodeStrings: boolean = false; - - constructor(values?: Partial) { - Object.assign(this, values); - } -} - -/** - * An enhanced version of the {@link makeTable} function from Apache Arrow - * that supports nested fields and embeddings columns. - * - * This function converts an array of Record (row-major JS objects) - * to an Arrow Table (a columnar structure) - * - * Note that it currently does not support nulls. - * - * If a schema is provided then it will be used to determine the resulting array - * types. Fields will also be reordered to fit the order defined by the schema. - * - * If a schema is not provided then the types will be inferred and the field order - * will be controlled by the order of properties in the first record. - * - * If the input is empty then a schema must be provided to create an empty table. - * - * When a schema is not specified then data types will be inferred. The inference - * rules are as follows: - * - * - boolean => Bool - * - number => Float64 - * - String => Utf8 - * - Buffer => Binary - * - Record => Struct - * - Array => List - * - * @param data input data - * @param options options to control the makeArrowTable call. - * - * @example - * - * ```ts - * - * import { fromTableToBuffer, makeArrowTable } from "../arrow"; - * import { Field, FixedSizeList, Float16, Float32, Int32, Schema } from "apache-arrow"; - * - * const schema = new Schema([ - * new Field("a", new Int32()), - * new Field("b", new Float32()), - * new Field("c", new FixedSizeList(3, new Field("item", new Float16()))), - * ]); - * const table = makeArrowTable([ - * { a: 1, b: 2, c: [1, 2, 3] }, - * { a: 4, b: 5, c: [4, 5, 6] }, - * { a: 7, b: 8, c: [7, 8, 9] }, - * ], { schema }); - * ``` - * - * By default it assumes that the column named `vector` is a vector column - * and it will be converted into a fixed size list array of type float32. - * The `vectorColumns` option can be used to support other vector column - * names and data types. - * - * ```ts - * - * const schema = new Schema([ - new Field("a", new Float64()), - new Field("b", new Float64()), - new Field( - "vector", - new FixedSizeList(3, new Field("item", new Float32())) - ), - ]); - const table = makeArrowTable([ - { a: 1, b: 2, vector: [1, 2, 3] }, - { a: 4, b: 5, vector: [4, 5, 6] }, - { a: 7, b: 8, vector: [7, 8, 9] }, - ]); - assert.deepEqual(table.schema, schema); - * ``` - * - * You can specify the vector column types and names using the options as well - * - * ```typescript - * - * const schema = new Schema([ - new Field('a', new Float64()), - new Field('b', new Float64()), - new Field('vec1', new FixedSizeList(3, new Field('item', new Float16()))), - new Field('vec2', new FixedSizeList(3, new Field('item', new Float16()))) - ]); - * const table = makeArrowTable([ - { a: 1, b: 2, vec1: [1, 2, 3], vec2: [2, 4, 6] }, - { a: 4, b: 5, vec1: [4, 5, 6], vec2: [8, 10, 12] }, - { a: 7, b: 8, vec1: [7, 8, 9], vec2: [14, 16, 18] } - ], { - vectorColumns: { - vec1: { type: new Float16() }, - vec2: { type: new Float16() } - } - } - * assert.deepEqual(table.schema, schema) - * ``` - */ -export function makeArrowTable( - data: Array>, - options?: Partial -): ArrowTable { - if ( - data.length === 0 && - (options?.schema === undefined || options?.schema === null) - ) { - throw new Error("At least one record or a schema needs to be provided"); - } - - const opt = new MakeArrowTableOptions(options !== undefined ? options : {}); - if (opt.schema !== undefined && opt.schema !== null) { - opt.schema = sanitizeSchema(opt.schema); - opt.schema = validateSchemaEmbeddings(opt.schema, data, opt.embeddings); - } - - const columns: Record = {}; - // TODO: sample dataset to find missing columns - // Prefer the field ordering of the schema, if present - const columnNames = - opt.schema != null ? (opt.schema.names as string[]) : Object.keys(data[0]); - for (const colName of columnNames) { - if ( - data.length !== 0 && - !Object.prototype.hasOwnProperty.call(data[0], colName) - ) { - // The field is present in the schema, but not in the data, skip it - continue; - } - // Extract a single column from the records (transpose from row-major to col-major) - let values = data.map((datum) => datum[colName]); - - // By default (type === undefined) arrow will infer the type from the JS type - let type; - if (opt.schema !== undefined) { - // If there is a schema provided, then use that for the type instead - type = opt.schema?.fields.filter((f) => f.name === colName)[0]?.type; - if (DataType.isInt(type) && type.bitWidth === 64) { - // wrap in BigInt to avoid bug: https://github.com/apache/arrow/issues/40051 - values = values.map((v) => { - if (v === null) { - return v; - } - return BigInt(v); - }); - } - } else { - // Otherwise, check to see if this column is one of the vector columns - // defined by opt.vectorColumns and, if so, use the fixed size list type - const vectorColumnOptions = opt.vectorColumns[colName]; - if (vectorColumnOptions !== undefined) { - type = newVectorType(values[0].length, vectorColumnOptions.type); - } - } - - try { - // Convert an Array of JS values to an arrow vector - columns[colName] = makeVector(values, type, opt.dictionaryEncodeStrings); - } catch (error: unknown) { - // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - throw Error(`Could not convert column "${colName}" to Arrow: ${error}`); - } - } - - if (opt.schema != null) { - // `new ArrowTable(columns)` infers a schema which may sometimes have - // incorrect nullability (it assumes nullable=true if there are 0 rows) - // - // `new ArrowTable(schema, columns)` will also fail because it will create a - // batch with an inferred schema and then complain that the batch schema - // does not match the provided schema. - // - // To work around this we first create a table with the wrong schema and - // then patch the schema of the batches so we can use - // `new ArrowTable(schema, batches)` which does not do any schema inference - const firstTable = new ArrowTable(columns); - const batchesFixed = firstTable.batches.map( - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - (batch) => new RecordBatch(opt.schema!, batch.data) - ); - return new ArrowTable(opt.schema, batchesFixed); - } else { - return new ArrowTable(columns); - } -} - -/** - * Create an empty Arrow table with the provided schema - */ -export function makeEmptyTable(schema: Schema): ArrowTable { - return makeArrowTable([], { schema }); -} - -// Helper function to convert Array> to a variable sized list array -function makeListVector(lists: any[][]): Vector { - if (lists.length === 0 || lists[0].length === 0) { - throw Error("Cannot infer list vector from empty array or empty list"); - } - const sampleList = lists[0]; - let inferredType; - try { - const sampleVector = makeVector(sampleList); - inferredType = sampleVector.type; - } catch (error: unknown) { - // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - throw Error(`Cannot infer list vector. Cannot infer inner type: ${error}`); - } - - const listBuilder = makeBuilder({ - type: new List(new Field("item", inferredType, true)) - }); - for (const list of lists) { - listBuilder.append(list); - } - return listBuilder.finish().toVector(); -} - -// Helper function to convert an Array of JS values to an Arrow Vector -function makeVector( - values: any[], - type?: DataType, - stringAsDictionary?: boolean -): Vector { - if (type !== undefined) { - // No need for inference, let Arrow create it - return vectorFromArray(values, type); - } - if (values.length === 0) { - throw Error( - "makeVector requires at least one value or the type must be specfied" - ); - } - const sampleValue = values.find((val) => val !== null && val !== undefined); - if (sampleValue === undefined) { - throw Error( - "makeVector cannot infer the type if all values are null or undefined" - ); - } - if (Array.isArray(sampleValue)) { - // Default Arrow inference doesn't handle list types - return makeListVector(values); - } else if (Buffer.isBuffer(sampleValue)) { - // Default Arrow inference doesn't handle Buffer - return vectorFromArray(values, new Binary()); - } else if ( - !(stringAsDictionary ?? false) && - (typeof sampleValue === "string" || sampleValue instanceof String) - ) { - // If the type is string then don't use Arrow's default inference unless dictionaries are requested - // because it will always use dictionary encoding for strings - return vectorFromArray(values, new Utf8()); - } else { - // Convert a JS array of values to an arrow vector - return vectorFromArray(values); - } -} - -async function applyEmbeddings( - table: ArrowTable, - embeddings?: EmbeddingFunction, - schema?: Schema -): Promise { - if (embeddings == null) { - return table; - } - if (schema !== undefined && schema !== null) { - schema = sanitizeSchema(schema); - } - - // Convert from ArrowTable to Record - const colEntries = [...Array(table.numCols).keys()].map((_, idx) => { - const name = table.schema.fields[idx].name; - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - const vec = table.getChildAt(idx)!; - return [name, vec]; - }); - const newColumns = Object.fromEntries(colEntries); - - const sourceColumn = newColumns[embeddings.sourceColumn]; - const destColumn = embeddings.destColumn ?? "vector"; - const innerDestType = embeddings.embeddingDataType ?? new Float32(); - if (sourceColumn === undefined) { - throw new Error( - `Cannot apply embedding function because the source column '${embeddings.sourceColumn}' was not present in the data` - ); - } - - if (table.numRows === 0) { - if (Object.prototype.hasOwnProperty.call(newColumns, destColumn)) { - // We have an empty table and it already has the embedding column so no work needs to be done - // Note: we don't return an error like we did below because this is a common occurrence. For example, - // if we call convertToTable with 0 records and a schema that includes the embedding - return table; - } - if (embeddings.embeddingDimension !== undefined) { - const destType = newVectorType( - embeddings.embeddingDimension, - innerDestType - ); - newColumns[destColumn] = makeVector([], destType); - } else if (schema != null) { - const destField = schema.fields.find((f) => f.name === destColumn); - if (destField != null) { - newColumns[destColumn] = makeVector([], destField.type); - } else { - throw new Error( - `Attempt to apply embeddings to an empty table failed because schema was missing embedding column '${destColumn}'` - ); - } - } else { - throw new Error( - "Attempt to apply embeddings to an empty table when the embeddings function does not specify `embeddingDimension`" - ); - } - } else { - if (Object.prototype.hasOwnProperty.call(newColumns, destColumn)) { - throw new Error( - `Attempt to apply embeddings to table failed because column ${destColumn} already existed` - ); - } - if (table.batches.length > 1) { - throw new Error( - "Internal error: `makeArrowTable` unexpectedly created a table with more than one batch" - ); - } - const values = sourceColumn.toArray(); - const vectors = await embeddings.embed(values as T[]); - if (vectors.length !== values.length) { - throw new Error( - "Embedding function did not return an embedding for each input element" - ); - } - const destType = newVectorType(vectors[0].length, innerDestType); - newColumns[destColumn] = makeVector(vectors, destType); - } - - const newTable = new ArrowTable(newColumns); - if (schema != null) { - if (schema.fields.find((f) => f.name === destColumn) === undefined) { - throw new Error( - `When using embedding functions and specifying a schema the schema should include the embedding column but the column ${destColumn} was missing` - ); - } - return alignTable(newTable, schema); - } - return newTable; -} - -/* - * Convert an Array of records into an Arrow Table, optionally applying an - * embeddings function to it. - * - * This function calls `makeArrowTable` first to create the Arrow Table. - * Any provided `makeTableOptions` (e.g. a schema) will be passed on to - * that call. - * - * The embedding function will be passed a column of values (based on the - * `sourceColumn` of the embedding function) and expects to receive back - * number[][] which will be converted into a fixed size list column. By - * default this will be a fixed size list of Float32 but that can be - * customized by the `embeddingDataType` property of the embedding function. - * - * If a schema is provided in `makeTableOptions` then it should include the - * embedding columns. If no schema is provded then embedding columns will - * be placed at the end of the table, after all of the input columns. - */ -export async function convertToTable( - data: Array>, - embeddings?: EmbeddingFunction, - makeTableOptions?: Partial -): Promise { - const table = makeArrowTable(data, makeTableOptions); - return await applyEmbeddings(table, embeddings, makeTableOptions?.schema); -} - -// Creates the Arrow Type for a Vector column with dimension `dim` -function newVectorType( - dim: number, - innerType: T -): FixedSizeList { - // Somewhere we always default to have the elements nullable, so we need to set it to true - // otherwise we often get schema mismatches because the stored data always has schema with nullable elements - const children = new Field("item", innerType, true); - return new FixedSizeList(dim, children); -} - -/** - * Serialize an Array of records into a buffer using the Arrow IPC File serialization - * - * This function will call `convertToTable` and pass on `embeddings` and `schema` - * - * `schema` is required if data is empty - */ -export async function fromRecordsToBuffer( - data: Array>, - embeddings?: EmbeddingFunction, - schema?: Schema -): Promise { - if (schema !== undefined && schema !== null) { - schema = sanitizeSchema(schema); - } - const table = await convertToTable(data, embeddings, { schema, embeddings }); - const writer = RecordBatchFileWriter.writeAll(table); - return Buffer.from(await writer.toUint8Array()); -} - -/** - * Serialize an Array of records into a buffer using the Arrow IPC Stream serialization - * - * This function will call `convertToTable` and pass on `embeddings` and `schema` - * - * `schema` is required if data is empty - */ -export async function fromRecordsToStreamBuffer( - data: Array>, - embeddings?: EmbeddingFunction, - schema?: Schema -): Promise { - if (schema !== null && schema !== undefined) { - schema = sanitizeSchema(schema); - } - const table = await convertToTable(data, embeddings, { schema }); - const writer = RecordBatchStreamWriter.writeAll(table); - return Buffer.from(await writer.toUint8Array()); -} - -/** - * Serialize an Arrow Table into a buffer using the Arrow IPC File serialization - * - * This function will apply `embeddings` to the table in a manner similar to - * `convertToTable`. - * - * `schema` is required if the table is empty - */ -export async function fromTableToBuffer( - table: ArrowTable, - embeddings?: EmbeddingFunction, - schema?: Schema -): Promise { - if (schema !== null && schema !== undefined) { - schema = sanitizeSchema(schema); - } - const tableWithEmbeddings = await applyEmbeddings(table, embeddings, schema); - const writer = RecordBatchFileWriter.writeAll(tableWithEmbeddings); - return Buffer.from(await writer.toUint8Array()); -} - -/** - * Serialize an Arrow Table into a buffer using the Arrow IPC Stream serialization - * - * This function will apply `embeddings` to the table in a manner similar to - * `convertToTable`. - * - * `schema` is required if the table is empty - */ -export async function fromTableToStreamBuffer( - table: ArrowTable, - embeddings?: EmbeddingFunction, - schema?: Schema -): Promise { - if (schema !== null && schema !== undefined) { - schema = sanitizeSchema(schema); - } - const tableWithEmbeddings = await applyEmbeddings(table, embeddings, schema); - const writer = RecordBatchStreamWriter.writeAll(tableWithEmbeddings); - return Buffer.from(await writer.toUint8Array()); -} - -function alignBatch(batch: RecordBatch, schema: Schema): RecordBatch { - const alignedChildren = []; - for (const field of schema.fields) { - const indexInBatch = batch.schema.fields?.findIndex( - (f) => f.name === field.name - ); - if (indexInBatch < 0) { - throw new Error( - `The column ${field.name} was not found in the Arrow Table` - ); - } - alignedChildren.push(batch.data.children[indexInBatch]); - } - const newData = makeData({ - type: new Struct(schema.fields), - length: batch.numRows, - nullCount: batch.nullCount, - children: alignedChildren - }); - return new RecordBatch(schema, newData); -} - -function alignTable(table: ArrowTable, schema: Schema): ArrowTable { - const alignedBatches = table.batches.map((batch) => - alignBatch(batch, schema) - ); - return new ArrowTable(schema, alignedBatches); -} - -// Creates an empty Arrow Table -export function createEmptyTable(schema: Schema): ArrowTable { - return new ArrowTable(sanitizeSchema(schema)); -} - -function validateSchemaEmbeddings( - schema: Schema, - data: Array>, - embeddings: EmbeddingFunction | undefined -) { - const fields = []; - const missingEmbeddingFields = []; - - // First we check if the field is a `FixedSizeList` - // Then we check if the data contains the field - // if it does not, we add it to the list of missing embedding fields - // Finally, we check if those missing embedding fields are `this._embeddings` - // if they are not, we throw an error - for (const field of schema.fields) { - if (field.type instanceof FixedSizeList) { - if (data.length !== 0 && data?.[0]?.[field.name] === undefined) { - missingEmbeddingFields.push(field); - } else { - fields.push(field); - } - } else { - fields.push(field); - } - } - - if (missingEmbeddingFields.length > 0 && embeddings === undefined) { - throw new Error( - `Table has embeddings: "${missingEmbeddingFields - .map((f) => f.name) - .join(",")}", but no embedding function was provided` - ); - } - - return new Schema(fields, schema.metadata); -} diff --git a/node/src/embedding/embedding_function.ts b/node/src/embedding/embedding_function.ts deleted file mode 100644 index 4900a976..00000000 --- a/node/src/embedding/embedding_function.ts +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright 2023 Lance Developers. -// -// 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. - -import { type Float } from 'apache-arrow' - -/** - * An embedding function that automatically creates vector representation for a given column. - */ -export interface EmbeddingFunction { - /** - * The name of the column that will be used as input for the Embedding Function. - */ - sourceColumn: string - - /** - * The data type of the embedding - * - * The embedding function should return `number`. This will be converted into - * an Arrow float array. By default this will be Float32 but this property can - * be used to control the conversion. - */ - embeddingDataType?: Float - - /** - * The dimension of the embedding - * - * This is optional, normally this can be determined by looking at the results of - * `embed`. If this is not specified, and there is an attempt to apply the embedding - * to an empty table, then that process will fail. - */ - embeddingDimension?: number - - /** - * The name of the column that will contain the embedding - * - * By default this is "vector" - */ - destColumn?: string - - /** - * Should the source column be excluded from the resulting table - * - * By default the source column is included. Set this to true and - * only the embedding will be stored. - */ - excludeSource?: boolean - - /** - * Creates a vector representation for the given values. - */ - embed: (data: T[]) => Promise -} - -export function isEmbeddingFunction (value: any): value is EmbeddingFunction { - return typeof value.sourceColumn === 'string' && - typeof value.embed === 'function' -} diff --git a/node/src/embedding/openai.ts b/node/src/embedding/openai.ts deleted file mode 100644 index a84d4ba6..00000000 --- a/node/src/embedding/openai.ts +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright 2023 Lance Developers. -// -// 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. - -import { type EmbeddingFunction } from '../index' -import type OpenAI from 'openai' - -export class OpenAIEmbeddingFunction implements EmbeddingFunction { - private readonly _openai: OpenAI - private readonly _modelName: string - - constructor (sourceColumn: string, openAIKey: string, modelName: string = 'text-embedding-ada-002') { - /** - * @type {import("openai").default} - */ - let Openai - try { - // eslint-disable-next-line @typescript-eslint/no-var-requires - Openai = require('openai') - } catch { - throw new Error('please install openai@^4.24.1 using npm install openai') - } - - this.sourceColumn = sourceColumn - const configuration = { - apiKey: openAIKey - } - - this._openai = new Openai(configuration) - this._modelName = modelName - } - - async embed (data: string[]): Promise { - const response = await this._openai.embeddings.create({ - model: this._modelName, - input: data - }) - - const embeddings: number[][] = [] - for (let i = 0; i < response.data.length; i++) { - embeddings.push(response.data[i].embedding) - } - return embeddings - } - - sourceColumn: string -} diff --git a/node/src/index.ts b/node/src/index.ts deleted file mode 100644 index ccac74e5..00000000 --- a/node/src/index.ts +++ /dev/null @@ -1,1399 +0,0 @@ -// Copyright 2023 Lance Developers. -// -// 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. - -import { type Schema, Table as ArrowTable, tableFromIPC } from "apache-arrow"; -import { - createEmptyTable, - fromRecordsToBuffer, - fromTableToBuffer, - makeArrowTable -} from "./arrow"; -import type { EmbeddingFunction } from "./embedding/embedding_function"; -import { RemoteConnection } from "./remote"; -import { Query } from "./query"; -import { isEmbeddingFunction } from "./embedding/embedding_function"; -import { type Literal, toSQL } from "./util"; - -import { type HttpMiddleware } from "./middleware"; - -const { - databaseNew, - databaseTableNames, - databaseOpenTable, - databaseDropTable, - tableCreate, - tableAdd, - tableCreateScalarIndex, - tableCreateVectorIndex, - tableCountRows, - tableDelete, - tableUpdate, - tableMergeInsert, - tableCleanupOldVersions, - tableCompactFiles, - tableListIndices, - tableIndexStats, - tableSchema, - tableAddColumns, - tableAlterColumns, - tableDropColumns, - tableDropIndex - // eslint-disable-next-line @typescript-eslint/no-var-requires -} = require("../native.js"); - -export { Query }; -export type { EmbeddingFunction }; -export { OpenAIEmbeddingFunction } from "./embedding/openai"; -export { - convertToTable, - makeArrowTable, - type MakeArrowTableOptions -} from "./arrow"; - -const defaultAwsRegion = "us-east-1"; - -const defaultRequestTimeout = 10_000 - -export interface AwsCredentials { - accessKeyId: string - - secretKey: string - - sessionToken?: string -} - -export interface ConnectionOptions { - /** - * LanceDB database URI. - * - * - `/path/to/database` - local database - * - `s3://bucket/path/to/database` or `gs://bucket/path/to/database` - database on cloud storage - * - `db://host:port` - remote database (LanceDB cloud) - */ - uri: string - - /** User provided AWS crednetials. - * - * If not provided, LanceDB will use the default credentials provider chain. - * - * @deprecated Pass `aws_access_key_id`, `aws_secret_access_key`, and `aws_session_token` - * through `storageOptions` instead. - */ - awsCredentials?: AwsCredentials - - /** AWS region to connect to. Default is {@link defaultAwsRegion} - * - * @deprecated Pass `region` through `storageOptions` instead. - */ - awsRegion?: string - - /** - * User provided options for object storage. For example, S3 credentials or request timeouts. - * - * The various options are described at https://lancedb.github.io/lancedb/guides/storage/ - */ - storageOptions?: Record - - /** - * API key for the remote connections - * - * Can also be passed by setting environment variable `LANCEDB_API_KEY` - */ - apiKey?: string - - /** Region to connect. Default is 'us-east-1' */ - region?: string - - /** - * Override the host URL for the remote connection. - * - * This is useful for local testing. - */ - hostOverride?: string - - /** - * Duration in milliseconds for request timeout. Default = 10,000 (10 seconds) - */ - timeout?: number - - /** - * (For LanceDB OSS only): The interval, in seconds, at which to check for - * updates to the table from other processes. If None, then consistency is not - * checked. For performance reasons, this is the default. For strong - * consistency, set this to zero seconds. Then every read will check for - * updates from other processes. As a compromise, you can set this to a - * non-zero value for eventual consistency. If more than that interval - * has passed since the last check, then the table will be checked for updates. - * Note: this consistency only applies to read operations. Write operations are - * always consistent. - */ - readConsistencyInterval?: number -} - -function getAwsArgs(opts: ConnectionOptions): any[] { - const callArgs: any[] = []; - const awsCredentials = opts.awsCredentials; - if (awsCredentials !== undefined) { - callArgs.push(awsCredentials.accessKeyId); - callArgs.push(awsCredentials.secretKey); - callArgs.push(awsCredentials.sessionToken); - } else { - callArgs.fill(undefined, 0, 3); - } - - callArgs.push(opts.awsRegion); - return callArgs; -} - -export interface CreateTableOptions { - // Name of Table - name: string - - // Data to insert into the Table - data?: Array> | ArrowTable | undefined - - // Optional Arrow Schema for this table - schema?: Schema | undefined - - // Optional embedding function used to create embeddings - embeddingFunction?: EmbeddingFunction | undefined - - // WriteOptions for this operation - writeOptions?: WriteOptions | undefined -} - -/** - * Connect to a LanceDB instance at the given URI. - * - * Accepted formats: - * - * - `/path/to/database` - local database - * - `s3://bucket/path/to/database` or `gs://bucket/path/to/database` - database on cloud storage - * - `db://host:port` - remote database (LanceDB cloud) - * - * @param uri The uri of the database. If the database uri starts with `db://` then it connects to a remote database. - * - * @see {@link ConnectionOptions} for more details on the URI format. - */ -export async function connect(uri: string): Promise; -/** - * Connect to a LanceDB instance with connection options. - * - * @param opts The {@link ConnectionOptions} to use when connecting to the database. - */ -export async function connect( - opts: Partial -): Promise; -export async function connect( - arg: string | Partial -): Promise { - let partOpts: Partial; - if (typeof arg === "string") { - partOpts = { uri: arg }; - } else { - const keys = Object.keys(arg); - if (keys.length === 1 && keys[0] === "uri" && typeof arg.uri === "string") { - partOpts = { uri: arg.uri }; - } else { - partOpts = arg; - } - } - - let defaultRegion = process.env.AWS_REGION ?? process.env.AWS_DEFAULT_REGION; - defaultRegion = (defaultRegion ?? "").trim() !== "" ? defaultRegion : defaultAwsRegion; - - const opts: ConnectionOptions = { - uri: partOpts.uri ?? "", - awsCredentials: partOpts.awsCredentials ?? undefined, - awsRegion: partOpts.awsRegion ?? defaultRegion, - apiKey: partOpts.apiKey ?? undefined, - region: partOpts.region ?? defaultRegion, - timeout: partOpts.timeout ?? defaultRequestTimeout, - readConsistencyInterval: partOpts.readConsistencyInterval ?? undefined, - storageOptions: partOpts.storageOptions ?? undefined, - hostOverride: partOpts.hostOverride ?? undefined - } - if (opts.uri.startsWith("db://")) { - // Remote connection - return new RemoteConnection(opts); - } - - const storageOptions = opts.storageOptions ?? {}; - if (opts.awsCredentials?.accessKeyId !== undefined) { - storageOptions.aws_access_key_id = opts.awsCredentials.accessKeyId; - } - if (opts.awsCredentials?.secretKey !== undefined) { - storageOptions.aws_secret_access_key = opts.awsCredentials.secretKey; - } - if (opts.awsCredentials?.sessionToken !== undefined) { - storageOptions.aws_session_token = opts.awsCredentials.sessionToken; - } - if (opts.awsRegion !== undefined) { - storageOptions.region = opts.awsRegion; - } - // It's a pain to pass a record to Rust, so we convert it to an array of key-value pairs - const storageOptionsArr = Object.entries(storageOptions); - - const db = await databaseNew( - opts.uri, - storageOptionsArr, - opts.readConsistencyInterval - ); - return new LocalConnection(db, opts); -} - -/** - * A LanceDB Connection that allows you to open tables and create new ones. - * - * Connection could be local against filesystem or remote against a server. - */ -export interface Connection { - uri: string - - tableNames(): Promise - - /** - * Open a table in the database. - * - * @param name The name of the table. - * @param embeddings An embedding function to use on this table - */ - openTable( - name: string, - embeddings?: EmbeddingFunction - ): Promise> - - /** - * Creates a new Table, optionally initializing it with new data. - * - * @param {string} name - The name of the table. - * @param data - Array of Records to be inserted into the table - * @param schema - An Arrow Schema that describe this table columns - * @param {EmbeddingFunction} embeddings - An embedding function to use on this table - * @param {WriteOptions} writeOptions - The write options to use when creating the table. - */ - createTable({ - name, - data, - schema, - embeddingFunction, - writeOptions - }: CreateTableOptions): Promise> - - /** - * Creates a new Table and initialize it with new data. - * - * @param {string} name - The name of the table. - * @param data - Non-empty Array of Records to be inserted into the table - */ - createTable( - name: string, - data: Array> | ArrowTable - ): Promise - - /** - * Creates a new Table and initialize it with new data. - * - * @param {string} name - The name of the table. - * @param data - Non-empty Array of Records to be inserted into the table - * @param {WriteOptions} options - The write options to use when creating the table. - */ - createTable( - name: string, - data: Array> | ArrowTable, - options: WriteOptions - ): Promise
- - /** - * Creates a new Table and initialize it with new data. - * - * @param {string} name - The name of the table. - * @param data - Non-empty Array of Records to be inserted into the table - * @param {EmbeddingFunction} embeddings - An embedding function to use on this table - */ - createTable( - name: string, - data: Array> | ArrowTable, - embeddings: EmbeddingFunction - ): Promise> - /** - * Creates a new Table and initialize it with new data. - * - * @param {string} name - The name of the table. - * @param data - Non-empty Array of Records to be inserted into the table - * @param {EmbeddingFunction} embeddings - An embedding function to use on this table - * @param {WriteOptions} options - The write options to use when creating the table. - */ - createTable( - name: string, - data: Array> | ArrowTable, - embeddings: EmbeddingFunction, - options: WriteOptions - ): Promise> - - /** - * Drop an existing table. - * @param name The name of the table to drop. - */ - dropTable(name: string): Promise - - /** - * Instrument the behavior of this Connection with middleware. - * - * The middleware will be called in the order they are added. - * - * Currently this functionality is only supported for remote Connections. - * - * @param {HttpMiddleware} - Middleware which will instrument the Connection. - * @returns - this Connection instrumented by the passed middleware - */ - withMiddleware(middleware: HttpMiddleware): Connection -} - -/** - * A LanceDB Table is the collection of Records. Each Record has one or more vector fields. - */ -export interface Table { - name: string - - /** - * Creates a search query to find the nearest neighbors of the given search term - * @param query The query search term - */ - search: (query: T) => Query - - /** - * Insert records into this Table. - * - * @param data Records to be inserted into the Table - * @return The number of rows added to the table - */ - add: (data: Array> | ArrowTable) => Promise - - /** - * Insert records into this Table, replacing its contents. - * - * @param data Records to be inserted into the Table - * @return The number of rows added to the table - */ - overwrite: ( - data: Array> | ArrowTable - ) => Promise - - /** - * Create an ANN index on this Table vector index. - * - * @param indexParams The parameters of this Index, @see VectorIndexParams. - */ - createIndex: (indexParams: VectorIndexParams) => Promise - - /** - * Create a scalar index on this Table for the given column - * - * @param column The column to index - * @param replace If false, fail if an index already exists on the column - * it is always set to true for remote connections - * - * Scalar indices, like vector indices, can be used to speed up scans. A scalar - * index can speed up scans that contain filter expressions on the indexed column. - * For example, the following scan will be faster if the column `my_col` has - * a scalar index: - * - * ```ts - * const con = await lancedb.connect('./.lancedb'); - * const table = await con.openTable('images'); - * const results = await table.where('my_col = 7').execute(); - * ``` - * - * Scalar indices can also speed up scans containing a vector search and a - * prefilter: - * - * ```ts - * const con = await lancedb.connect('././lancedb'); - * const table = await con.openTable('images'); - * const results = await table.search([1.0, 2.0]).where('my_col != 7').prefilter(true); - * ``` - * - * Scalar indices can only speed up scans for basic filters using - * equality, comparison, range (e.g. `my_col BETWEEN 0 AND 100`), and set - * membership (e.g. `my_col IN (0, 1, 2)`) - * - * Scalar indices can be used if the filter contains multiple indexed columns and - * the filter criteria are AND'd or OR'd together - * (e.g. `my_col < 0 AND other_col> 100`) - * - * Scalar indices may be used if the filter contains non-indexed columns but, - * depending on the structure of the filter, they may not be usable. For example, - * if the column `not_indexed` does not have a scalar index then the filter - * `my_col = 0 OR not_indexed = 1` will not be able to use any scalar index on - * `my_col`. - * - * @examples - * - * ```ts - * const con = await lancedb.connect('././lancedb') - * const table = await con.openTable('images') - * await table.createScalarIndex('my_col') - * ``` - */ - createScalarIndex: (column: string, replace?: boolean) => Promise - - /** - * Returns the number of rows in this table. - */ - countRows: (filter?: string) => Promise - - /** - * Delete rows from this table. - * - * This can be used to delete a single row, many rows, all rows, or - * sometimes no rows (if your predicate matches nothing). - * - * @param filter A filter in the same format used by a sql WHERE clause. The - * filter must not be empty. - * - * @examples - * - * ```ts - * const con = await lancedb.connect("./.lancedb") - * const data = [ - * {id: 1, vector: [1, 2]}, - * {id: 2, vector: [3, 4]}, - * {id: 3, vector: [5, 6]}, - * ]; - * const tbl = await con.createTable("my_table", data) - * await tbl.delete("id = 2") - * await tbl.countRows() // Returns 2 - * ``` - * - * If you have a list of values to delete, you can combine them into a - * stringified list and use the `IN` operator: - * - * ```ts - * const to_remove = [1, 5]; - * await tbl.delete(`id IN (${to_remove.join(",")})`) - * await tbl.countRows() // Returns 1 - * ``` - */ - delete: (filter: string) => Promise - - /** - * Update rows in this table. - * - * This can be used to update a single row, many rows, all rows, or - * sometimes no rows (if your predicate matches nothing). - * - * @param args see {@link UpdateArgs} and {@link UpdateSqlArgs} for more details - * - * @examples - * - * ```ts - * const con = await lancedb.connect("./.lancedb") - * const data = [ - * {id: 1, vector: [3, 3], name: 'Ye'}, - * {id: 2, vector: [4, 4], name: 'Mike'}, - * ]; - * const tbl = await con.createTable("my_table", data) - * - * await tbl.update({ - * where: "id = 2", - * values: { vector: [2, 2], name: "Michael" }, - * }) - * - * let results = await tbl.search([1, 1]).execute(); - * // Returns [ - * // {id: 2, vector: [2, 2], name: 'Michael'} - * // {id: 1, vector: [3, 3], name: 'Ye'} - * // ] - * ``` - * - */ - update: (args: UpdateArgs | UpdateSqlArgs) => Promise - - /** - * Runs a "merge insert" operation on the table - * - * This operation can add rows, update rows, and remove rows all in a single - * transaction. It is a very generic tool that can be used to create - * behaviors like "insert if not exists", "update or insert (i.e. upsert)", - * or even replace a portion of existing data with new data (e.g. replace - * all data where month="january") - * - * The merge insert operation works by combining new data from a - * **source table** with existing data in a **target table** by using a - * join. There are three categories of records. - * - * "Matched" records are records that exist in both the source table and - * the target table. "Not matched" records exist only in the source table - * (e.g. these are new data) "Not matched by source" records exist only - * in the target table (this is old data) - * - * The MergeInsertArgs can be used to customize what should happen for - * each category of data. - * - * Please note that the data may appear to be reordered as part of this - * operation. This is because updated rows will be deleted from the - * dataset and then reinserted at the end with the new values. - * - * @param on a column to join on. This is how records from the source - * table and target table are matched. - * @param data the new data to insert - * @param args parameters controlling how the operation should behave - */ - mergeInsert: ( - on: string, - data: Array> | ArrowTable, - args: MergeInsertArgs - ) => Promise - - /** - * List the indicies on this table. - */ - listIndices: () => Promise - - /** - * Get statistics about an index. - */ - indexStats: (indexName: string) => Promise - - filter(value: string): Query - - schema: Promise - - // TODO: Support BatchUDF - /** - * Add new columns with defined values. - * - * @param newColumnTransforms pairs of column names and the SQL expression to use - * to calculate the value of the new column. These - * expressions will be evaluated for each row in the - * table, and can reference existing columns in the table. - */ - addColumns( - newColumnTransforms: Array<{ name: string, valueSql: string }> - ): Promise - - /** - * Alter the name or nullability of columns. - * - * @param columnAlterations One or more alterations to apply to columns. - */ - alterColumns(columnAlterations: ColumnAlteration[]): Promise - - /** - * Drop one or more columns from the dataset - * - * This is a metadata-only operation and does not remove the data from the - * underlying storage. In order to remove the data, you must subsequently - * call ``compact_files`` to rewrite the data without the removed columns and - * then call ``cleanup_files`` to remove the old files. - * - * @param columnNames The names of the columns to drop. These can be nested - * column references (e.g. "a.b.c") or top-level column - * names (e.g. "a"). - */ - dropColumns(columnNames: string[]): Promise - - /** - * Drop an index from the table - * - * @param indexName The name of the index to drop - */ - dropIndex(indexName: string): Promise - - /** - * Instrument the behavior of this Table with middleware. - * - * The middleware will be called in the order they are added. - * - * Currently this functionality is only supported for remote tables. - * - * @param {HttpMiddleware} - Middleware which will instrument the Table. - * @returns - this Table instrumented by the passed middleware - */ - withMiddleware(middleware: HttpMiddleware): Table -} - -/** - * A definition of a column alteration. The alteration changes the column at - * `path` to have the new name `name`, to be nullable if `nullable` is true, - * and to have the data type `data_type`. At least one of `rename` or `nullable` - * must be provided. - */ -export interface ColumnAlteration { - /** - * The path to the column to alter. This is a dot-separated path to the column. - * If it is a top-level column then it is just the name of the column. If it is - * a nested column then it is the path to the column, e.g. "a.b.c" for a column - * `c` nested inside a column `b` nested inside a column `a`. - */ - path: string - rename?: string - /** - * Set the new nullability. Note that a nullable column cannot be made non-nullable. - */ - nullable?: boolean -} - -export interface UpdateArgs { - /** - * A filter in the same format used by a sql WHERE clause. The filter may be empty, - * in which case all rows will be updated. - */ - where?: string - - /** - * A key-value map of updates. The keys are the column names, and the values are the - * new values to set - */ - values: Record -} - -export interface UpdateSqlArgs { - /** - * A filter in the same format used by a sql WHERE clause. The filter may be empty, - * in which case all rows will be updated. - */ - where?: string - - /** - * A key-value map of updates. The keys are the column names, and the values are the - * new values to set as SQL expressions. - */ - valuesSql: Record -} - -export interface MergeInsertArgs { - /** - * If true then rows that exist in both the source table (new data) and - * the target table (old data) will be updated, replacing the old row - * with the corresponding matching row. - * - * If there are multiple matches then the behavior is undefined. - * Currently this causes multiple copies of the row to be created - * but that behavior is subject to change. - * - * Optionally, a filter can be specified. This should be an SQL - * filter where fields with the prefix "target." refer to fields - * in the target table (old data) and fields with the prefix - * "source." refer to fields in the source table (new data). For - * example, the filter "target.lastUpdated < source.lastUpdated" will - * only update matched rows when the incoming `lastUpdated` value is - * newer. - * - * Rows that do not match the filter will not be updated. Rows that - * do not match the filter do become "not matched" rows. - */ - whenMatchedUpdateAll?: string | boolean - /** - * If true then rows that exist only in the source table (new data) - * will be inserted into the target table. - */ - whenNotMatchedInsertAll?: boolean - /** - * If true then rows that exist only in the target table (old data) - * will be deleted. - * - * If this is a string then it will be treated as an SQL filter and - * only rows that both do not match any row in the source table and - * match the given filter will be deleted. - * - * This can be used to replace a selection of existing data with - * new data. - */ - whenNotMatchedBySourceDelete?: string | boolean -} - -export enum IndexStatus { - Pending = "pending", - Indexing = "indexing", - Done = "done", - Failed = "failed" -} - -export interface VectorIndex { - columns: string[] - name: string - uuid: string - status: IndexStatus -} - -export interface IndexStats { - numIndexedRows: number | null - numUnindexedRows: number | null - indexType: string - distanceType?: string - numIndices?: number -} - -/** - * A connection to a LanceDB database. - */ -export class LocalConnection implements Connection { - private readonly _options: () => ConnectionOptions; - private readonly _db: any; - - constructor(db: any, options: ConnectionOptions) { - this._options = () => options; - this._db = db; - } - - get uri(): string { - return this._options().uri; - } - - /** - * Get the names of all tables in the database. - */ - async tableNames(): Promise { - return databaseTableNames.call(this._db); - } - - /** - * Open a table in the database. - * - * @param name The name of the table. - */ - async openTable(name: string): Promise
; - - /** - * Open a table in the database. - * - * @param name The name of the table. - * @param embeddings An embedding function to use on this Table - */ - async openTable( - name: string, - embeddings: EmbeddingFunction - ): Promise>; - async openTable( - name: string, - embeddings?: EmbeddingFunction - ): Promise>; - async openTable( - name: string, - embeddings?: EmbeddingFunction - ): Promise> { - const tbl = await databaseOpenTable.call(this._db, name); - if (embeddings !== undefined) { - return new LocalTable(tbl, name, this._options(), embeddings); - } else { - return new LocalTable(tbl, name, this._options()); - } - } - - async createTable( - name: string | CreateTableOptions, - data?: Array> | ArrowTable, - optsOrEmbedding?: WriteOptions | EmbeddingFunction, - opt?: WriteOptions - ): Promise> { - if (typeof name === "string") { - let writeOptions: WriteOptions = new DefaultWriteOptions(); - if (opt !== undefined && isWriteOptions(opt)) { - writeOptions = opt; - } else if ( - optsOrEmbedding !== undefined && - isWriteOptions(optsOrEmbedding) - ) { - writeOptions = optsOrEmbedding; - } - - let embeddings: undefined | EmbeddingFunction; - if ( - optsOrEmbedding !== undefined && - isEmbeddingFunction(optsOrEmbedding) - ) { - embeddings = optsOrEmbedding; - } - return await this.createTableImpl({ - name, - data, - embeddingFunction: embeddings, - writeOptions - }); - } - return await this.createTableImpl(name); - } - - private async createTableImpl({ - name, - data, - schema, - embeddingFunction, - writeOptions = new DefaultWriteOptions() - }: { - name: string - data?: Array> | ArrowTable | undefined - schema?: Schema | undefined - embeddingFunction?: EmbeddingFunction | undefined - writeOptions?: WriteOptions | undefined - }): Promise> { - let buffer: Buffer; - - function isEmpty( - data: Array> | ArrowTable - ): boolean { - if (data instanceof ArrowTable) { - return data.data.length === 0; - } - return data.length === 0; - } - - if (data === undefined || isEmpty(data)) { - if (schema === undefined) { - throw new Error("Either data or schema needs to defined"); - } - buffer = await fromTableToBuffer(createEmptyTable(schema)); - } else if (data instanceof ArrowTable) { - buffer = await fromTableToBuffer(data, embeddingFunction, schema); - } else { - // data is Array> - buffer = await fromRecordsToBuffer(data, embeddingFunction, schema); - } - - const tbl = await tableCreate.call( - this._db, - name, - buffer, - writeOptions?.writeMode?.toString(), - ...getAwsArgs(this._options()) - ); - if (embeddingFunction !== undefined) { - return new LocalTable(tbl, name, this._options(), embeddingFunction); - } else { - return new LocalTable(tbl, name, this._options()); - } - } - - /** - * Drop an existing table. - * @param name The name of the table to drop. - */ - async dropTable(name: string): Promise { - await databaseDropTable.call(this._db, name); - } - - withMiddleware(middleware: HttpMiddleware): Connection { - return this; - } -} - -export class LocalTable implements Table { - private _tbl: any; - private readonly _name: string; - private readonly _isElectron: boolean; - private readonly _embeddings?: EmbeddingFunction; - private readonly _options: () => ConnectionOptions; - - constructor(tbl: any, name: string, options: ConnectionOptions); - /** - * @param tbl - * @param name - * @param options - * @param embeddings An embedding function to use when interacting with this table - */ - constructor( - tbl: any, - name: string, - options: ConnectionOptions, - embeddings: EmbeddingFunction - ); - constructor( - tbl: any, - name: string, - options: ConnectionOptions, - embeddings?: EmbeddingFunction - ) { - this._tbl = tbl; - this._name = name; - this._embeddings = embeddings; - this._options = () => options; - this._isElectron = this.checkElectron(); - } - - get name(): string { - return this._name; - } - - /** - * Creates a search query to find the nearest neighbors of the given search term - * @param query The query search term - */ - search(query: T): Query { - return new Query(query, this._tbl, this._embeddings); - } - - /** - * Creates a filter query to find all rows matching the specified criteria - * @param value The filter criteria (like SQL where clause syntax) - */ - filter(value: string): Query { - return new Query(undefined, this._tbl, this._embeddings).filter(value); - } - - where = this.filter; - - /** - * Insert records into this Table. - * - * @param data Records to be inserted into the Table - * @return The number of rows added to the table - */ - async add( - data: Array> | ArrowTable - ): Promise { - const schema = await this.schema; - - let tbl: ArrowTable; - - if (data instanceof ArrowTable) { - tbl = data; - } else { - tbl = makeArrowTable(data, { schema, embeddings: this._embeddings }); - } - - return tableAdd - .call( - this._tbl, - await fromTableToBuffer(tbl, this._embeddings, schema), - WriteMode.Append.toString(), - ...getAwsArgs(this._options()) - ) - .then((newTable: any) => { - this._tbl = newTable; - }); - } - - /** - * Insert records into this Table, replacing its contents. - * - * @param data Records to be inserted into the Table - * @return The number of rows added to the table - */ - async overwrite( - data: Array> | ArrowTable - ): Promise { - let buffer: Buffer; - if (data instanceof ArrowTable) { - buffer = await fromTableToBuffer(data, this._embeddings); - } else { - buffer = await fromRecordsToBuffer(data, this._embeddings); - } - return tableAdd - .call( - this._tbl, - buffer, - WriteMode.Overwrite.toString(), - ...getAwsArgs(this._options()) - ) - .then((newTable: any) => { - this._tbl = newTable; - }); - } - - /** - * Create an ANN index on this Table vector index. - * - * @param indexParams The parameters of this Index, @see VectorIndexParams. - */ - async createIndex(indexParams: VectorIndexParams): Promise { - return tableCreateVectorIndex - .call(this._tbl, indexParams) - .then((newTable: any) => { - this._tbl = newTable; - }); - } - - async createScalarIndex(column: string, replace?: boolean): Promise { - if (replace === undefined) { - replace = true; - } - return tableCreateScalarIndex.call(this._tbl, column, replace); - } - - /** - * Returns the number of rows in this table. - */ - async countRows(filter?: string): Promise { - return tableCountRows.call(this._tbl, filter); - } - - /** - * Delete rows from this table. - * - * @param filter A filter in the same format used by a sql WHERE clause. - */ - async delete(filter: string): Promise { - return tableDelete.call(this._tbl, filter).then((newTable: any) => { - this._tbl = newTable; - }); - } - - /** - * Update rows in this table. - * - * @param args see {@link UpdateArgs} and {@link UpdateSqlArgs} for more details - * - * @returns - */ - async update(args: UpdateArgs | UpdateSqlArgs): Promise { - let filter: string | null; - let updates: Record; - - if ("valuesSql" in args) { - filter = args.where ?? null; - updates = args.valuesSql; - } else { - filter = args.where ?? null; - updates = {}; - for (const [key, value] of Object.entries(args.values)) { - updates[key] = toSQL(value); - } - } - - return tableUpdate - .call(this._tbl, filter, updates) - .then((newTable: any) => { - this._tbl = newTable; - }); - } - - async mergeInsert( - on: string, - data: Array> | ArrowTable, - args: MergeInsertArgs - ): Promise { - let whenMatchedUpdateAll = false; - let whenMatchedUpdateAllFilt = null; - if ( - args.whenMatchedUpdateAll !== undefined && - args.whenMatchedUpdateAll !== null - ) { - whenMatchedUpdateAll = true; - if (args.whenMatchedUpdateAll !== true) { - whenMatchedUpdateAllFilt = args.whenMatchedUpdateAll; - } - } - const whenNotMatchedInsertAll = args.whenNotMatchedInsertAll ?? false; - let whenNotMatchedBySourceDelete = false; - let whenNotMatchedBySourceDeleteFilt = null; - if ( - args.whenNotMatchedBySourceDelete !== undefined && - args.whenNotMatchedBySourceDelete !== null - ) { - whenNotMatchedBySourceDelete = true; - if (args.whenNotMatchedBySourceDelete !== true) { - whenNotMatchedBySourceDeleteFilt = args.whenNotMatchedBySourceDelete; - } - } - - const schema = await this.schema; - let tbl: ArrowTable; - if (data instanceof ArrowTable) { - tbl = data; - } else { - tbl = makeArrowTable(data, { schema }); - } - const buffer = await fromTableToBuffer(tbl, this._embeddings, schema); - - this._tbl = await tableMergeInsert.call( - this._tbl, - on, - whenMatchedUpdateAll, - whenMatchedUpdateAllFilt, - whenNotMatchedInsertAll, - whenNotMatchedBySourceDelete, - whenNotMatchedBySourceDeleteFilt, - buffer - ); - } - - /** - * Clean up old versions of the table, freeing disk space. - * - * @param olderThan The minimum age in minutes of the versions to delete. If not - * provided, defaults to two weeks. - * @param deleteUnverified Because they may be part of an in-progress - * transaction, uncommitted files newer than 7 days old are - * not deleted by default. This means that failed transactions - * can leave around data that takes up disk space for up to - * 7 days. You can override this safety mechanism by setting - * this option to `true`, only if you promise there are no - * in progress writes while you run this operation. Failure to - * uphold this promise can lead to corrupted tables. - * @returns - */ - async cleanupOldVersions( - olderThan?: number, - deleteUnverified?: boolean - ): Promise { - return tableCleanupOldVersions - .call(this._tbl, olderThan, deleteUnverified) - .then((res: { newTable: any, metrics: CleanupStats }) => { - this._tbl = res.newTable; - return res.metrics; - }); - } - - /** - * Run the compaction process on the table. - * - * This can be run after making several small appends to optimize the table - * for faster reads. - * - * @param options Advanced options configuring compaction. In most cases, you - * can omit this arguments, as the default options are sensible - * for most tables. - * @returns Metrics about the compaction operation. - */ - async compactFiles(options?: CompactionOptions): Promise { - const optionsArg = options ?? {}; - return tableCompactFiles - .call(this._tbl, optionsArg) - .then((res: { newTable: any, metrics: CompactionMetrics }) => { - this._tbl = res.newTable; - return res.metrics; - }); - } - - async listIndices(): Promise { - return tableListIndices.call(this._tbl); - } - - async indexStats(indexName: string): Promise { - return tableIndexStats.call(this._tbl, indexName); - } - - get schema(): Promise { - // empty table - return this.getSchema(); - } - - private async getSchema(): Promise { - const buffer = await tableSchema.call(this._tbl, this._isElectron); - const table = tableFromIPC(buffer); - return table.schema; - } - - // See https://github.com/electron/electron/issues/2288 - private checkElectron(): boolean { - try { - // eslint-disable-next-line no-prototype-builtins - return ( - Object.prototype.hasOwnProperty.call(process?.versions, "electron") || - navigator?.userAgent?.toLowerCase()?.includes(" electron") - ); - } catch (e) { - return false; - } - } - - async addColumns( - newColumnTransforms: Array<{ name: string, valueSql: string }> - ): Promise { - return tableAddColumns.call(this._tbl, newColumnTransforms); - } - - async alterColumns(columnAlterations: ColumnAlteration[]): Promise { - return tableAlterColumns.call(this._tbl, columnAlterations); - } - - async dropColumns(columnNames: string[]): Promise { - return tableDropColumns.call(this._tbl, columnNames); - } - - async dropIndex(indexName: string): Promise { - return tableDropIndex.call(this._tbl, indexName); - } - - withMiddleware(middleware: HttpMiddleware): Table { - return this; - } -} - -export interface CleanupStats { - /** - * The number of bytes removed from disk. - */ - bytesRemoved: number - /** - * The number of old table versions removed. - */ - oldVersions: number -} - -export interface CompactionOptions { - /** - * The number of rows per fragment to target. Fragments that have fewer rows - * will be compacted into adjacent fragments to produce larger fragments. - * Defaults to 1024 * 1024. - */ - targetRowsPerFragment?: number - /** - * The maximum number of T per group. Defaults to 1024. - */ - maxRowsPerGroup?: number - /** - * If true, fragments that have rows that are deleted may be compacted to - * remove the deleted rows. This can improve the performance of queries. - * Default is true. - */ - materializeDeletions?: boolean - /** - * A number between 0 and 1, representing the proportion of rows that must be - * marked deleted before a fragment is a candidate for compaction to remove - * the deleted rows. Default is 10%. - */ - materializeDeletionsThreshold?: number - /** - * The number of threads to use for compaction. If not provided, defaults to - * the number of cores on the machine. - */ - numThreads?: number -} - -export interface CompactionMetrics { - /** - * The number of fragments that were removed. - */ - fragmentsRemoved: number - /** - * The number of new fragments that were created. - */ - fragmentsAdded: number - /** - * The number of files that were removed. Each fragment may have more than one - * file. - */ - filesRemoved: number - /** - * The number of files added. This is typically equal to the number of - * fragments added. - */ - filesAdded: number -} - -/// Config to build IVF_PQ index. -/// -export interface IvfPQIndexConfig { - /** - * The column to be indexed - */ - column?: string - - /** - * A unique name for the index - */ - index_name?: string - - /** - * Metric type, l2 or Cosine - */ - metric_type?: MetricType - - /** - * The number of partitions this index - */ - num_partitions?: number - - /** - * The max number of iterations for kmeans training. - */ - max_iters?: number - - /** - * Train as optimized product quantization. - */ - use_opq?: boolean - - /** - * Number of subvectors to build PQ code - */ - num_sub_vectors?: number - /** - * The number of bits to present one PQ centroid. - */ - num_bits?: number - - /** - * Max number of iterations to train OPQ, if `use_opq` is true. - */ - max_opq_iters?: number - - /** - * Replace an existing index with the same name if it exists. - */ - replace?: boolean - - /** - * Cache size of the index - */ - index_cache_size?: number - - type: "ivf_pq" -} - -export type VectorIndexParams = IvfPQIndexConfig; - -/** - * Write mode for writing a table. - */ -export enum WriteMode { - /** Create a new {@link Table}. */ - Create = "create", - /** Overwrite the existing {@link Table} if presented. */ - Overwrite = "overwrite", - /** Append new data to the table. */ - Append = "append", -} - -/** - * Write options when creating a Table. - */ -export interface WriteOptions { - /** A {@link WriteMode} to use on this operation */ - writeMode?: WriteMode -} - -export class DefaultWriteOptions implements WriteOptions { - writeMode = WriteMode.Create; -} - -export function isWriteOptions(value: any): value is WriteOptions { - return ( - Object.keys(value).length === 1 && - (value.writeMode === undefined || typeof value.writeMode === "string") - ); -} - -/** - * Distance metrics type. - */ -export enum MetricType { - /** - * Euclidean distance - */ - L2 = "l2", - - /** - * Cosine distance - */ - Cosine = "cosine", - - /** - * Dot product - */ - Dot = "dot", -} diff --git a/node/src/integration_test/test.ts b/node/src/integration_test/test.ts deleted file mode 100644 index 1520f5c0..00000000 --- a/node/src/integration_test/test.ts +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright 2023 LanceDB Developers. -// -// 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. - -import { describe } from 'mocha' -import * as chai from 'chai' -import { assert } from 'chai' -import * as chaiAsPromised from 'chai-as-promised' -import { v4 as uuidv4 } from 'uuid' - -import * as lancedb from '../index' -import { tmpdir } from 'os' -import * as fs from 'fs' -import * as path from 'path' - -chai.use(chaiAsPromised) - -describe('LanceDB AWS Integration test', function () { - it('s3+ddb schema is processed correctly', async function () { - this.timeout(15000) - - // WARNING: specifying engine is NOT a publicly supported feature in lancedb yet - // THE API WILL CHANGE - const conn = await lancedb.connect('s3://lancedb-integtest?engine=ddb&ddbTableName=lancedb-integtest') - const data = [{ vector: Array(128).fill(1.0) }] - - const tableName = uuidv4() - let table = await conn.createTable(tableName, data, { writeMode: lancedb.WriteMode.Overwrite }) - - const futs = [table.add(data), table.add(data), table.add(data), table.add(data), table.add(data)] - await Promise.allSettled(futs) - - table = await conn.openTable(tableName) - assert.equal(await table.countRows(), 6) - }) -}) - -describe('LanceDB Mirrored Store Integration test', function () { - it('s3://...?mirroredStore=... param is processed correctly', async function () { - this.timeout(600000) - - const dir = await fs.promises.mkdtemp(path.join(tmpdir(), 'lancedb-mirror-')) - console.log(dir) - const conn = await lancedb.connect({ uri: `s3://lancedb-integtest?mirroredStore=${dir}`, storageOptions: { allowHttp: 'true' } }) - const data = Array(200).fill({ vector: Array(128).fill(1.0), id: 0 }) - data.push(...Array(200).fill({ vector: Array(128).fill(1.0), id: 1 })) - data.push(...Array(200).fill({ vector: Array(128).fill(1.0), id: 2 })) - data.push(...Array(200).fill({ vector: Array(128).fill(1.0), id: 3 })) - - const tableName = uuidv4() - - // try create table and check if it's mirrored - const t = await conn.createTable(tableName, data, { writeMode: lancedb.WriteMode.Overwrite }) - - const mirroredPath = path.join(dir, `${tableName}.lance`) - - const files = await fs.promises.readdir(mirroredPath, { withFileTypes: true }) - // there should be three dirs - assert.equal(files.length, 3, 'files after table creation') - assert.isTrue(files[0].isDirectory()) - assert.isTrue(files[1].isDirectory()) - - const transactionFiles = await fs.promises.readdir(path.join(mirroredPath, '_transactions'), { withFileTypes: true }) - assert.equal(transactionFiles.length, 1, 'transactionFiles after table creation') - assert.isTrue(transactionFiles[0].name.endsWith('.txn')) - - const versionFiles = await fs.promises.readdir(path.join(mirroredPath, '_versions'), { withFileTypes: true }) - assert.equal(versionFiles.length, 1, 'versionFiles after table creation') - assert.isTrue(versionFiles[0].name.endsWith('.manifest')) - - const dataFiles = await fs.promises.readdir(path.join(mirroredPath, 'data'), { withFileTypes: true }) - assert.equal(dataFiles.length, 1, 'dataFiles after table creation') - assert.isTrue(dataFiles[0].name.endsWith('.lance')) - - // try create index and check if it's mirrored - await t.createIndex({ column: 'vector', type: 'ivf_pq' }) - - const filesAfterIndex = await fs.promises.readdir(mirroredPath, { withFileTypes: true }) - // there should be four dirs - assert.equal(filesAfterIndex.length, 4, 'filesAfterIndex') - assert.isTrue(filesAfterIndex[0].isDirectory()) - assert.isTrue(filesAfterIndex[1].isDirectory()) - assert.isTrue(filesAfterIndex[2].isDirectory()) - - // Two TXs now - const transactionFilesAfterIndex = await fs.promises.readdir(path.join(mirroredPath, '_transactions'), { withFileTypes: true }) - assert.equal(transactionFilesAfterIndex.length, 2, 'transactionFilesAfterIndex') - assert.isTrue(transactionFilesAfterIndex[0].name.endsWith('.txn')) - assert.isTrue(transactionFilesAfterIndex[1].name.endsWith('.txn')) - - const dataFilesAfterIndex = await fs.promises.readdir(path.join(mirroredPath, 'data'), { withFileTypes: true }) - assert.equal(dataFilesAfterIndex.length, 1, 'dataFilesAfterIndex') - assert.isTrue(dataFilesAfterIndex[0].name.endsWith('.lance')) - - const indicesFiles = await fs.promises.readdir(path.join(mirroredPath, '_indices'), { withFileTypes: true }) - assert.equal(indicesFiles.length, 1, 'indicesFiles') - assert.isTrue(indicesFiles[0].isDirectory()) - - const indexFiles = await fs.promises.readdir(path.join(mirroredPath, '_indices', indicesFiles[0].name), { withFileTypes: true }) - console.log(`DEBUG indexFiles in ${indicesFiles[0].name}:`, indexFiles.map(f => `${f.name} (${f.isFile() ? 'file' : 'dir'})`)) - assert.equal(indexFiles.length, 2, 'indexFiles') - const fileNames = indexFiles.map(f => f.name).sort() - assert.isTrue(fileNames.includes('auxiliary.idx'), 'auxiliary.idx should be present') - assert.isTrue(fileNames.includes('index.idx'), 'index.idx should be present') - assert.isTrue(indexFiles.every(f => f.isFile()), 'all index files should be files') - - // try delete and check if it's mirrored - await t.delete('id = 0') - - const filesAfterDelete = await fs.promises.readdir(mirroredPath, { withFileTypes: true }) - // there should be five dirs - assert.equal(filesAfterDelete.length, 5, 'filesAfterDelete') - assert.isTrue(filesAfterDelete[0].isDirectory()) - assert.isTrue(filesAfterDelete[1].isDirectory()) - assert.isTrue(filesAfterDelete[2].isDirectory()) - assert.isTrue(filesAfterDelete[3].isDirectory()) - assert.isTrue(filesAfterDelete[4].isDirectory()) - - // Three TXs now - const transactionFilesAfterDelete = await fs.promises.readdir(path.join(mirroredPath, '_transactions'), { withFileTypes: true }) - assert.equal(transactionFilesAfterDelete.length, 3, 'transactionFilesAfterDelete') - assert.isTrue(transactionFilesAfterDelete[0].name.endsWith('.txn')) - assert.isTrue(transactionFilesAfterDelete[1].name.endsWith('.txn')) - - const dataFilesAfterDelete = await fs.promises.readdir(path.join(mirroredPath, 'data'), { withFileTypes: true }) - assert.equal(dataFilesAfterDelete.length, 1, 'dataFilesAfterDelete') - assert.isTrue(dataFilesAfterDelete[0].name.endsWith('.lance')) - - const indicesFilesAfterDelete = await fs.promises.readdir(path.join(mirroredPath, '_indices'), { withFileTypes: true }) - assert.equal(indicesFilesAfterDelete.length, 1, 'indicesFilesAfterDelete') - assert.isTrue(indicesFilesAfterDelete[0].isDirectory()) - - const indexFilesAfterDelete = await fs.promises.readdir(path.join(mirroredPath, '_indices', indicesFilesAfterDelete[0].name), { withFileTypes: true }) - console.log(`DEBUG indexFilesAfterDelete in ${indicesFilesAfterDelete[0].name}:`, indexFilesAfterDelete.map(f => `${f.name} (${f.isFile() ? 'file' : 'dir'})`)) - assert.equal(indexFilesAfterDelete.length, 2, 'indexFilesAfterDelete') - const fileNamesAfterDelete = indexFilesAfterDelete.map(f => f.name).sort() - assert.isTrue(fileNamesAfterDelete.includes('auxiliary.idx'), 'auxiliary.idx should be present after delete') - assert.isTrue(fileNamesAfterDelete.includes('index.idx'), 'index.idx should be present after delete') - assert.isTrue(indexFilesAfterDelete.every(f => f.isFile()), 'all index files should be files after delete') - - const deletionFiles = await fs.promises.readdir(path.join(mirroredPath, '_deletions'), { withFileTypes: true }) - assert.equal(deletionFiles.length, 1, 'deletionFiles') - assert.isTrue(deletionFiles[0].name.endsWith('.arrow')) - }) -}) diff --git a/node/src/middleware.ts b/node/src/middleware.ts deleted file mode 100644 index 2eb5446d..00000000 --- a/node/src/middleware.ts +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2024 LanceDB Developers. -// -// 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. - -/** - * Middleware for Remote LanceDB Connection or Table - */ -export interface HttpMiddleware { - /** - * A callback that can be used to instrument the behavior of http requests to remote - * tables. It can be used to add headers, modify the request, or even short-circuit - * the request and return a response without making the request to the remote endpoint. - * It can also be used to modify the response from the remote endpoint. - * - * @param {RemoteResponse} res - Request to the remote endpoint - * @param {onRemoteRequestNext} next - Callback to advance the middleware chain - */ - onRemoteRequest( - req: RemoteRequest, - next: (req: RemoteRequest) => Promise, - ): Promise -}; - -export enum Method { - GET, - POST -} - -/** - * A LanceDB Remote HTTP Request - */ -export interface RemoteRequest { - uri: string - method: Method - headers: Map - params?: Map - body?: any -} - -/** - * A LanceDB Remote HTTP Response - */ -export interface RemoteResponse { - status: number - statusText: string - headers: Map - body: () => Promise -} diff --git a/node/src/query.ts b/node/src/query.ts deleted file mode 100644 index f622050c..00000000 --- a/node/src/query.ts +++ /dev/null @@ -1,163 +0,0 @@ -// Copyright 2023 LanceDB Developers. -// -// 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. - -import { Vector, tableFromIPC } from 'apache-arrow' -import { type EmbeddingFunction } from './embedding/embedding_function' -import { type MetricType } from '.' - -// eslint-disable-next-line @typescript-eslint/no-var-requires -const { tableSearch } = require('../native.js') - -/** - * A builder for nearest neighbor queries for LanceDB. - */ -export class Query { - private readonly _query?: T - private readonly _tbl?: any - private _queryVector?: number[] - private _limit?: number - private _refineFactor?: number - private _nprobes: number - private _select?: string[] - private _filter?: string - private _metricType?: MetricType - private _prefilter: boolean - private _fastSearch: boolean - protected readonly _embeddings?: EmbeddingFunction - - constructor (query?: T, tbl?: any, embeddings?: EmbeddingFunction) { - this._tbl = tbl - this._query = query - this._limit = 10 - this._nprobes = 20 - this._refineFactor = undefined - this._select = undefined - this._filter = undefined - this._metricType = undefined - this._embeddings = embeddings - this._prefilter = false - this._fastSearch = false - } - - /*** - * Sets the number of results that will be returned - * default value is 10 - * @param value number of results - */ - limit (value: number): Query { - this._limit = value - return this - } - - /** - * Refine the results by reading extra elements and re-ranking them in memory. - * @param value refine factor to use in this query. - */ - refineFactor (value: number): Query { - this._refineFactor = value - return this - } - - /** - * The number of probes used. A higher number makes search more accurate but also slower. - * @param value The number of probes used. - */ - nprobes (value: number): Query { - this._nprobes = value - return this - } - - /** - * A filter statement to be applied to this query. - * @param value A filter in the same format used by a sql WHERE clause. - */ - filter (value: string): Query { - this._filter = value - return this - } - - where = this.filter - - /** Return only the specified columns. - * - * @param value Only select the specified columns. If not specified, all columns will be returned. - */ - select (value: string[]): Query { - this._select = value - return this - } - - /** - * The MetricType used for this Query. - * @param value The metric to the. @see MetricType for the different options - */ - metricType (value: MetricType): Query { - this._metricType = value - return this - } - - prefilter (value: boolean): Query { - this._prefilter = value - return this - } - - /** - * Skip searching un-indexed data. This can make search faster, but will miss - * any data that is not yet indexed. - */ - fastSearch (value: boolean): Query { - this._fastSearch = value - return this - } - - /** - * Execute the query and return the results as an Array of Objects - */ - async execute> (): Promise { - if (this._query !== undefined) { - if (this._embeddings !== undefined) { - this._queryVector = (await this._embeddings.embed([this._query]))[0] - } else { - this._queryVector = this._query as number[] - } - } - - const isElectron = this.isElectron() - const buffer = await tableSearch.call(this._tbl, this, isElectron) - const data = tableFromIPC(buffer) - - return data.toArray().map((entry: Record) => { - const newObject: Record = {} - Object.keys(entry).forEach((key: string) => { - if (entry[key] instanceof Vector) { - // toJSON() returns f16 array correctly - newObject[key] = (entry[key] as any).toJSON() - } else { - newObject[key] = entry[key] as any - } - }) - return newObject as unknown as T - }) - } - - // See https://github.com/electron/electron/issues/2288 - private isElectron (): boolean { - try { - // eslint-disable-next-line no-prototype-builtins - return (process?.versions?.hasOwnProperty('electron') || navigator?.userAgent?.toLowerCase()?.includes(' electron')) - } catch (e) { - return false - } - } -} diff --git a/node/src/remote/client.ts b/node/src/remote/client.ts deleted file mode 100644 index cf99a182..00000000 --- a/node/src/remote/client.ts +++ /dev/null @@ -1,302 +0,0 @@ -// Copyright 2023 LanceDB Developers. -// -// 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. - -import axios, { type AxiosError, type AxiosResponse, type ResponseType } from 'axios' - -import { tableFromIPC, type Table as ArrowTable } from 'apache-arrow' - -import { type RemoteResponse, type RemoteRequest, Method } from '../middleware' -import type { MetricType } from '..' - -interface HttpLancedbClientMiddleware { - onRemoteRequest( - req: RemoteRequest, - next: (req: RemoteRequest) => Promise, - ): Promise -} - -/** - * Invoke the middleware chain and at the end call the remote endpoint - */ -async function callWithMiddlewares ( - req: RemoteRequest, - middlewares: HttpLancedbClientMiddleware[], - opts?: MiddlewareInvocationOptions -): Promise { - async function call ( - i: number, - req: RemoteRequest - ): Promise { - // if we have reached the end of the middleware chain, make the request - if (i > middlewares.length) { - const headers = Object.fromEntries(req.headers.entries()) - const params = Object.fromEntries(req.params?.entries() ?? []) - const timeout = opts?.timeout - let res - if (req.method === Method.POST) { - res = await axios.post( - req.uri, - req.body, - { - headers, - params, - timeout, - responseType: opts?.responseType - } - ) - } else { - res = await axios.get( - req.uri, - { - headers, - params, - timeout - } - ) - } - - return toLanceRes(res) - } - - // call next middleware in chain - return await middlewares[i - 1].onRemoteRequest( - req, - async (req) => { - return await call(i + 1, req) - } - ) - } - - return await call(1, req) -} - -interface MiddlewareInvocationOptions { - responseType?: ResponseType - timeout?: number -} - -/** - * Marshall the library response into a LanceDB response - */ -function toLanceRes (res: AxiosResponse): RemoteResponse { - const headers = new Map() - for (const h in res.headers) { - headers.set(h, res.headers[h]) - } - - return { - status: res.status, - statusText: res.statusText, - headers, - body: async () => { - return res.data - } - } -} - -async function decodeErrorData( - res: RemoteResponse, - responseType?: ResponseType -): Promise { - const errorData = await res.body() - if (responseType === 'arraybuffer') { - return new TextDecoder().decode(errorData) - } else { - if (typeof errorData === 'object') { - return JSON.stringify(errorData) - } - - return errorData - } -} - -export class HttpLancedbClient { - private readonly _url: string - private readonly _apiKey: () => string - private readonly _middlewares: HttpLancedbClientMiddleware[] - private readonly _timeout: number | undefined - - public constructor ( - url: string, - apiKey: string, - timeout?: number, - private readonly _dbName?: string - - ) { - this._url = url - this._apiKey = () => apiKey - this._middlewares = [] - this._timeout = timeout - } - - get uri (): string { - return this._url - } - - public async search ( - tableName: string, - vector: number[], - k: number, - nprobes: number, - prefilter: boolean, - refineFactor?: number, - columns?: string[], - filter?: string, - metricType?: MetricType, - fastSearch?: boolean - ): Promise> { - const result = await this.post( - `/v1/table/${tableName}/query/`, - { - vector, - k, - nprobes, - refine_factor: refineFactor, - columns, - filter, - prefilter, - metric: metricType, - fast_search: fastSearch - }, - undefined, - undefined, - 'arraybuffer' - ) - const table = tableFromIPC(await result.body()) - return table - } - - /** - * Sent GET request. - */ - public async get (path: string, params?: Record): Promise { - const req = { - uri: `${this._url}${path}`, - method: Method.GET, - headers: new Map(Object.entries({ - 'Content-Type': 'application/json', - 'x-api-key': this._apiKey(), - ...(this._dbName !== undefined ? { 'x-lancedb-database': this._dbName } : {}) - })), - params: new Map(Object.entries(params ?? {})) - } - - let response - try { - response = await callWithMiddlewares(req, this._middlewares) - return response - } catch (err: any) { - console.error(serializeErrorAsJson(err)) - if (err.response === undefined) { - throw new Error(`Network Error: ${err.message as string}`) - } - - response = toLanceRes(err.response) - } - - if (response.status !== 200) { - const errorData = await decodeErrorData(response) - throw new Error( - `Server Error, status: ${response.status}, ` + - `message: ${response.statusText}: ${errorData}` - ) - } - - return response - } - - /** - * Sent POST request. - */ - public async post ( - path: string, - data?: any, - params?: Record, - content?: string | undefined, - responseType?: ResponseType | undefined - ): Promise { - const req = { - uri: `${this._url}${path}`, - method: Method.POST, - headers: new Map(Object.entries({ - 'Content-Type': content ?? 'application/json', - 'x-api-key': this._apiKey(), - ...(this._dbName !== undefined ? { 'x-lancedb-database': this._dbName } : {}) - })), - params: new Map(Object.entries(params ?? {})), - body: data - } - - let response - try { - response = await callWithMiddlewares(req, this._middlewares, { - responseType, - timeout: this._timeout - }) - - // return response - } catch (err: any) { - console.error(serializeErrorAsJson(err)) - - if (err.response === undefined) { - throw new Error(`Network Error: ${err.message as string}`) - } - response = toLanceRes(err.response) - } - - if (response.status !== 200) { - const errorData = await decodeErrorData(response, responseType) - throw new Error( - `Server Error, status: ${response.status}, ` + - `message: ${response.statusText}: ${errorData}` - ) - } - - return response - } - - /** - * Instrument this client with middleware - * @param mw - The middleware that instruments the client - * @returns - an instance of this client instrumented with the middleware - */ - public withMiddleware (mw: HttpLancedbClientMiddleware): HttpLancedbClient { - const wrapped = this.clone() - wrapped._middlewares.push(mw) - return wrapped - } - - /** - * Make a clone of this client - */ - private clone (): HttpLancedbClient { - const clone = new HttpLancedbClient(this._url, this._apiKey(), this._timeout, this._dbName) - for (const mw of this._middlewares) { - clone._middlewares.push(mw) - } - return clone - } -} - -function serializeErrorAsJson(err: AxiosError) { - const error = JSON.parse(JSON.stringify(err, Object.getOwnPropertyNames(err))) - error.response = err.response != null - ? JSON.parse(JSON.stringify( - err.response, - // config contains the request data, too noisy - Object.getOwnPropertyNames(err.response).filter(prop => prop !== 'config') - )) - : null - return JSON.stringify({ error }) -} diff --git a/node/src/remote/index.ts b/node/src/remote/index.ts deleted file mode 100644 index a8035047..00000000 --- a/node/src/remote/index.ts +++ /dev/null @@ -1,567 +0,0 @@ -// Copyright 2023 LanceDB Developers. -// -// 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. - -import { - type EmbeddingFunction, - type Table, - type VectorIndexParams, - type Connection, - type ConnectionOptions, - type CreateTableOptions, - type VectorIndex, - type WriteOptions, - type IndexStats, - type UpdateArgs, - type UpdateSqlArgs, - makeArrowTable, - type MergeInsertArgs, - type ColumnAlteration -} from '../index' -import { Query } from '../query' - -import { Vector, Table as ArrowTable } from 'apache-arrow' -import { HttpLancedbClient } from './client' -import { isEmbeddingFunction } from '../embedding/embedding_function' -import { - createEmptyTable, - fromRecordsToStreamBuffer, - fromTableToStreamBuffer -} from '../arrow' -import { toSQL, TTLCache } from '../util' -import { type HttpMiddleware } from '../middleware' - -/** - * Remote connection. - */ -export class RemoteConnection implements Connection { - private _client: HttpLancedbClient - private readonly _dbName: string - private readonly _tableCache = new TTLCache(300_000) - - constructor (opts: ConnectionOptions) { - if (!opts.uri.startsWith('db://')) { - throw new Error(`Invalid remote DB URI: ${opts.uri}`) - } - if (opts.apiKey == null || opts.apiKey === '') { - opts = Object.assign({}, opts, { apiKey: process.env.LANCEDB_API_KEY }) - } - if (opts.apiKey === undefined || opts.region === undefined) { - throw new Error( - 'API key and region are must be passed for remote connections. ' + - 'API key can also be set through LANCEDB_API_KEY env variable.') - } - - this._dbName = opts.uri.slice('db://'.length) - let server: string - if (opts.hostOverride === undefined) { - server = `https://${this._dbName}.${opts.region}.api.lancedb.com` - } else { - server = opts.hostOverride - } - this._client = new HttpLancedbClient( - server, - opts.apiKey, - opts.timeout, - opts.hostOverride === undefined ? undefined : this._dbName - ) - } - - get uri (): string { - // add the lancedb+ prefix back - return 'db://' + this._client.uri - } - - async tableNames ( - pageToken: string = '', - limit: number = 10 - ): Promise { - const response = await this._client.get('/v1/table/', { - limit: `${limit}`, - page_token: pageToken - }) - const body = await response.body() - for (const table of body.tables) { - this._tableCache.set(table, true) - } - return body.tables - } - - async openTable (name: string): Promise
- async openTable( - name: string, - embeddings: EmbeddingFunction - ): Promise> - async openTable( - name: string, - embeddings?: EmbeddingFunction - ): Promise> { - // check if the table exists - if (this._tableCache.get(name) === undefined) { - await this._client.post(`/v1/table/${encodeURIComponent(name)}/describe/`) - this._tableCache.set(name, true) - } - - if (embeddings !== undefined) { - return new RemoteTable(this._client, name, embeddings) - } else { - return new RemoteTable(this._client, name) - } - } - - async createTable( - nameOrOpts: string | CreateTableOptions, - data?: Array> | ArrowTable, - optsOrEmbedding?: WriteOptions | EmbeddingFunction, - opt?: WriteOptions - ): Promise> { - // Logic copied from LocatlConnection, refactor these to a base class + connectionImpl pattern - let schema - let embeddings: undefined | EmbeddingFunction - let tableName: string - if (typeof nameOrOpts === 'string') { - if ( - optsOrEmbedding !== undefined && - isEmbeddingFunction(optsOrEmbedding) - ) { - embeddings = optsOrEmbedding - } - tableName = nameOrOpts - } else { - schema = nameOrOpts.schema - embeddings = nameOrOpts.embeddingFunction - tableName = nameOrOpts.name - if (data === undefined) { - data = nameOrOpts.data - } - } - - let buffer: Buffer - - function isEmpty ( - data: Array> | ArrowTable - ): boolean { - if (data instanceof ArrowTable) { - return data.numRows === 0 - } - return data.length === 0 - } - - if (data === undefined || isEmpty(data)) { - if (schema === undefined) { - throw new Error('Either data or schema needs to defined') - } - buffer = await fromTableToStreamBuffer(createEmptyTable(schema)) - } else if (data instanceof ArrowTable) { - buffer = await fromTableToStreamBuffer(data, embeddings) - } else { - // data is Array> - buffer = await fromRecordsToStreamBuffer(data, embeddings) - } - - const res = await this._client.post( - `/v1/table/${encodeURIComponent(tableName)}/create/`, - buffer, - undefined, - 'application/vnd.apache.arrow.stream' - ) - if (res.status !== 200) { - throw new Error( - `Server Error, status: ${res.status}, ` + - // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - `message: ${res.statusText}: ${await res.body()}` - ) - } - - this._tableCache.set(tableName, true) - if (embeddings === undefined) { - return new RemoteTable(this._client, tableName) - } else { - return new RemoteTable(this._client, tableName, embeddings) - } - } - - async dropTable (name: string): Promise { - await this._client.post(`/v1/table/${encodeURIComponent(name)}/drop/`) - this._tableCache.delete(name) - } - - withMiddleware (middleware: HttpMiddleware): Connection { - const wrapped = this.clone() - wrapped._client = wrapped._client.withMiddleware(middleware) - return wrapped - } - - private clone (): RemoteConnection { - const clone: RemoteConnection = Object.create(RemoteConnection.prototype) - return Object.assign(clone, this) - } -} - -export class RemoteQuery extends Query { - constructor ( - query: T, - private readonly _client: HttpLancedbClient, - private readonly _name: string, - embeddings?: EmbeddingFunction - ) { - super(query, undefined, embeddings) - } - - // TODO: refactor this to a base class + queryImpl pattern - async execute>(): Promise { - const embeddings = this._embeddings - const query = (this as any)._query - let queryVector: number[] - - if (embeddings !== undefined) { - queryVector = (await embeddings.embed([query]))[0] - } else { - queryVector = query as number[] - } - - const data = await this._client.search( - this._name, - queryVector, - (this as any)._limit, - (this as any)._nprobes, - (this as any)._prefilter, - (this as any)._refineFactor, - (this as any)._select, - (this as any)._filter, - (this as any)._metricType, - (this as any)._fastSearch - ) - - return data.toArray().map((entry: Record) => { - const newObject: Record = {} - Object.keys(entry).forEach((key: string) => { - if (entry[key] instanceof Vector) { - newObject[key] = (entry[key] as any).toArray() - } else { - newObject[key] = entry[key] as any - } - }) - return newObject as unknown as T - }) - } -} - -// we are using extend until we have next next version release -// Table and Connection has both been refactored to interfaces -export class RemoteTable implements Table { - private _client: HttpLancedbClient - private readonly _embeddings?: EmbeddingFunction - private readonly _name: string - - constructor (client: HttpLancedbClient, name: string) - constructor ( - client: HttpLancedbClient, - name: string, - embeddings: EmbeddingFunction - ) - constructor ( - client: HttpLancedbClient, - name: string, - embeddings?: EmbeddingFunction - ) { - this._client = client - this._name = name - this._embeddings = embeddings - } - - get name (): string { - return this._name - } - - get schema (): Promise { - return this._client - .post(`/v1/table/${encodeURIComponent(this._name)}/describe/`) - .then(async (res) => { - if (res.status !== 200) { - throw new Error( - `Server Error, status: ${res.status}, ` + - // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - `message: ${res.statusText}: ${await res.body()}` - ) - } - return (await res.body())?.schema - }) - } - - search (query: T): Query { - return new RemoteQuery(query, this._client, encodeURIComponent(this._name)) //, this._embeddings_new) - } - - filter (where: string): Query { - throw new Error('Not implemented') - } - - async mergeInsert (on: string, data: Array> | ArrowTable, args: MergeInsertArgs): Promise { - let tbl: ArrowTable - if (data instanceof ArrowTable) { - tbl = data - } else { - tbl = makeArrowTable(data, await this.schema) - } - - const queryParams: any = { - on - } - if (args.whenMatchedUpdateAll !== false && args.whenMatchedUpdateAll !== null && args.whenMatchedUpdateAll !== undefined) { - queryParams.when_matched_update_all = 'true' - if (typeof args.whenMatchedUpdateAll === 'string') { - queryParams.when_matched_update_all_filt = args.whenMatchedUpdateAll - } - } else { - queryParams.when_matched_update_all = 'false' - } - if (args.whenNotMatchedInsertAll ?? false) { - queryParams.when_not_matched_insert_all = 'true' - } else { - queryParams.when_not_matched_insert_all = 'false' - } - if (args.whenNotMatchedBySourceDelete !== false && args.whenNotMatchedBySourceDelete !== null && args.whenNotMatchedBySourceDelete !== undefined) { - queryParams.when_not_matched_by_source_delete = 'true' - if (typeof args.whenNotMatchedBySourceDelete === 'string') { - queryParams.when_not_matched_by_source_delete_filt = args.whenNotMatchedBySourceDelete - } - } else { - queryParams.when_not_matched_by_source_delete = 'false' - } - - const buffer = await fromTableToStreamBuffer(tbl, this._embeddings) - const res = await this._client.post( - `/v1/table/${encodeURIComponent(this._name)}/merge_insert/`, - buffer, - queryParams, - 'application/vnd.apache.arrow.stream' - ) - if (res.status !== 200) { - throw new Error( - `Server Error, status: ${res.status}, ` + - // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - `message: ${res.statusText}: ${await res.body()}` - ) - } - } - - async add (data: Array> | ArrowTable): Promise { - let tbl: ArrowTable - if (data instanceof ArrowTable) { - tbl = data - } else { - tbl = makeArrowTable(data, await this.schema) - } - - const buffer = await fromTableToStreamBuffer(tbl, this._embeddings) - const res = await this._client.post( - `/v1/table/${encodeURIComponent(this._name)}/insert/`, - buffer, - { - mode: 'append' - }, - 'application/vnd.apache.arrow.stream' - ) - if (res.status !== 200) { - throw new Error( - `Server Error, status: ${res.status}, ` + - // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - `message: ${res.statusText}: ${await res.body()}` - ) - } - return tbl.numRows - } - - async overwrite (data: Array> | ArrowTable): Promise { - let tbl: ArrowTable - if (data instanceof ArrowTable) { - tbl = data - } else { - tbl = makeArrowTable(data) - } - const buffer = await fromTableToStreamBuffer(tbl, this._embeddings) - const res = await this._client.post( - `/v1/table/${encodeURIComponent(this._name)}/insert/`, - buffer, - { - mode: 'overwrite' - }, - 'application/vnd.apache.arrow.stream' - ) - if (res.status !== 200) { - throw new Error( - `Server Error, status: ${res.status}, ` + - // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - `message: ${res.statusText}: ${await res.body()}` - ) - } - return tbl.numRows - } - - async createIndex (indexParams: VectorIndexParams): Promise { - const unsupportedParams = [ - 'index_name', - 'num_partitions', - 'max_iters', - 'use_opq', - 'num_sub_vectors', - 'num_bits', - 'max_opq_iters', - 'replace' - ] - for (const param of unsupportedParams) { - // eslint-disable-next-line @typescript-eslint/strict-boolean-expressions - if (indexParams[param as keyof VectorIndexParams]) { - throw new Error(`${param} is not supported for remote connections`) - } - } - - const column = indexParams.column ?? 'vector' - const indexType = 'vector' - const metricType = indexParams.metric_type ?? 'L2' - const indexCacheSize = indexParams.index_cache_size ?? null - - const data = { - column, - index_type: indexType, - metric_type: metricType, - index_cache_size: indexCacheSize - } - const res = await this._client.post( - `/v1/table/${encodeURIComponent(this._name)}/create_index/`, - data - ) - if (res.status !== 200) { - throw new Error( - `Server Error, status: ${res.status}, ` + - // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - `message: ${res.statusText}: ${await res.body()}` - ) - } - } - - async createScalarIndex (column: string): Promise { - const indexType = 'scalar' - - const data = { - column, - index_type: indexType, - replace: true - } - const res = await this._client.post( - `/v1/table/${encodeURIComponent(this._name)}/create_scalar_index/`, - data - ) - if (res.status !== 200) { - throw new Error( - `Server Error, status: ${res.status}, ` + - // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - `message: ${res.statusText}: ${await res.body()}` - ) - } - } - async dropIndex (index_name: string): Promise { - const res = await this._client.post( - `/v1/table/${encodeURIComponent(this._name)}/index/${encodeURIComponent(index_name)}/drop/` - ) - if (res.status !== 200) { - throw new Error( - `Server Error, status: ${res.status}, ` + - // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - `message: ${res.statusText}: ${await res.body()}` - ) - } - } - - async countRows (filter?: string): Promise { - const result = await this._client.post(`/v1/table/${encodeURIComponent(this._name)}/count_rows/`, { - predicate: filter - }) - return (await result.body()) - } - - async delete (filter: string): Promise { - await this._client.post(`/v1/table/${encodeURIComponent(this._name)}/delete/`, { - predicate: filter - }) - } - - async update (args: UpdateArgs | UpdateSqlArgs): Promise { - let filter: string | null - let updates: Record - - if ('valuesSql' in args) { - filter = args.where ?? null - updates = args.valuesSql - } else { - filter = args.where ?? null - updates = {} - for (const [key, value] of Object.entries(args.values)) { - updates[key] = toSQL(value) - } - } - await this._client.post(`/v1/table/${encodeURIComponent(this._name)}/update/`, { - predicate: filter, - updates: Object.entries(updates).map(([key, value]) => [key, value]) - }) - } - - async listIndices (): Promise { - const results = await this._client.post( - `/v1/table/${encodeURIComponent(this._name)}/index/list/` - ) - return (await results.body()).indexes?.map((index: any) => ({ - columns: index.columns, - name: index.index_name, - uuid: index.index_uuid, - status: index.status - })) - } - - async indexStats (indexName: string): Promise { - const results = await this._client.post( - `/v1/table/${encodeURIComponent(this._name)}/index/${indexName}/stats/` - ) - const body = await results.body() - return { - numIndexedRows: body?.num_indexed_rows, - numUnindexedRows: body?.num_unindexed_rows, - indexType: body?.index_type, - distanceType: body?.distance_type - } - } - - async addColumns (newColumnTransforms: Array<{ name: string, valueSql: string }>): Promise { - throw new Error('Add columns is not yet supported in LanceDB Cloud.') - } - - async alterColumns (columnAlterations: ColumnAlteration[]): Promise { - throw new Error('Alter columns is not yet supported in LanceDB Cloud.') - } - - async dropColumns (columnNames: string[]): Promise { - throw new Error('Drop columns is not yet supported in LanceDB Cloud.') - } - - withMiddleware(middleware: HttpMiddleware): Table { - const wrapped = this.clone() - wrapped._client = wrapped._client.withMiddleware(middleware) - return wrapped - } - - private clone (): RemoteTable { - const clone: RemoteTable = Object.create(RemoteTable.prototype) - return Object.assign(clone, this) - } -} diff --git a/node/src/sanitize.ts b/node/src/sanitize.ts deleted file mode 100644 index cc5d958d..00000000 --- a/node/src/sanitize.ts +++ /dev/null @@ -1,508 +0,0 @@ -// Copyright 2023 LanceDB Developers. -// -// 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. - -// The utilities in this file help sanitize data from the user's arrow -// library into the types expected by vectordb's arrow library. Node -// generally allows for mulitple versions of the same library (and sometimes -// even multiple copies of the same version) to be installed at the same -// time. However, arrow-js uses instanceof which expected that the input -// comes from the exact same library instance. This is not always the case -// and so we must sanitize the input to ensure that it is compatible. - -import { - Field, - Utf8, - FixedSizeBinary, - FixedSizeList, - Schema, - List, - Struct, - Float, - Bool, - Date_, - Decimal, - type DataType, - Dictionary, - Binary, - Float32, - Interval, - Map_, - Duration, - Union, - Time, - Timestamp, - Type, - Null, - Int, - type Precision, - type DateUnit, - Int8, - Int16, - Int32, - Int64, - Uint8, - Uint16, - Uint32, - Uint64, - Float16, - Float64, - DateDay, - DateMillisecond, - DenseUnion, - SparseUnion, - TimeNanosecond, - TimeMicrosecond, - TimeMillisecond, - TimeSecond, - TimestampNanosecond, - TimestampMicrosecond, - TimestampMillisecond, - TimestampSecond, - IntervalDayTime, - IntervalYearMonth, - DurationNanosecond, - DurationMicrosecond, - DurationMillisecond, - DurationSecond -} from "apache-arrow"; -import type { IntBitWidth, TimeBitWidth } from "apache-arrow/type"; - -function sanitizeMetadata( - metadataLike?: unknown -): Map | undefined { - if (metadataLike === undefined || metadataLike === null) { - return undefined; - } - if (!(metadataLike instanceof Map)) { - throw Error("Expected metadata, if present, to be a Map"); - } - for (const item of metadataLike) { - if (!(typeof item[0] === "string" || !(typeof item[1] === "string"))) { - throw Error( - "Expected metadata, if present, to be a Map but it had non-string keys or values" - ); - } - } - return metadataLike as Map; -} - -function sanitizeInt(typeLike: object) { - if ( - !("bitWidth" in typeLike) || - typeof typeLike.bitWidth !== "number" || - !("isSigned" in typeLike) || - typeof typeLike.isSigned !== "boolean" - ) { - throw Error( - "Expected an Int Type to have a `bitWidth` and `isSigned` property" - ); - } - return new Int(typeLike.isSigned, typeLike.bitWidth as IntBitWidth); -} - -function sanitizeFloat(typeLike: object) { - if (!("precision" in typeLike) || typeof typeLike.precision !== "number") { - throw Error("Expected a Float Type to have a `precision` property"); - } - return new Float(typeLike.precision as Precision); -} - -function sanitizeDecimal(typeLike: object) { - if ( - !("scale" in typeLike) || - typeof typeLike.scale !== "number" || - !("precision" in typeLike) || - typeof typeLike.precision !== "number" || - !("bitWidth" in typeLike) || - typeof typeLike.bitWidth !== "number" - ) { - throw Error( - "Expected a Decimal Type to have `scale`, `precision`, and `bitWidth` properties" - ); - } - return new Decimal(typeLike.scale, typeLike.precision, typeLike.bitWidth); -} - -function sanitizeDate(typeLike: object) { - if (!("unit" in typeLike) || typeof typeLike.unit !== "number") { - throw Error("Expected a Date type to have a `unit` property"); - } - return new Date_(typeLike.unit as DateUnit); -} - -function sanitizeTime(typeLike: object) { - if ( - !("unit" in typeLike) || - typeof typeLike.unit !== "number" || - !("bitWidth" in typeLike) || - typeof typeLike.bitWidth !== "number" - ) { - throw Error( - "Expected a Time type to have `unit` and `bitWidth` properties" - ); - } - return new Time(typeLike.unit, typeLike.bitWidth as TimeBitWidth); -} - -function sanitizeTimestamp(typeLike: object) { - if (!("unit" in typeLike) || typeof typeLike.unit !== "number") { - throw Error("Expected a Timestamp type to have a `unit` property"); - } - let timezone = null; - if ("timezone" in typeLike && typeof typeLike.timezone === "string") { - timezone = typeLike.timezone; - } - return new Timestamp(typeLike.unit, timezone); -} - -function sanitizeTypedTimestamp( - typeLike: object, - Datatype: - | typeof TimestampNanosecond - | typeof TimestampMicrosecond - | typeof TimestampMillisecond - | typeof TimestampSecond -) { - let timezone = null; - if ("timezone" in typeLike && typeof typeLike.timezone === "string") { - timezone = typeLike.timezone; - } - return new Datatype(timezone); -} - -function sanitizeInterval(typeLike: object) { - if (!("unit" in typeLike) || typeof typeLike.unit !== "number") { - throw Error("Expected an Interval type to have a `unit` property"); - } - return new Interval(typeLike.unit); -} - -function sanitizeList(typeLike: object) { - if (!("children" in typeLike) || !Array.isArray(typeLike.children)) { - throw Error( - "Expected a List type to have an array-like `children` property" - ); - } - if (typeLike.children.length !== 1) { - throw Error("Expected a List type to have exactly one child"); - } - return new List(sanitizeField(typeLike.children[0])); -} - -function sanitizeStruct(typeLike: object) { - if (!("children" in typeLike) || !Array.isArray(typeLike.children)) { - throw Error( - "Expected a Struct type to have an array-like `children` property" - ); - } - return new Struct(typeLike.children.map((child) => sanitizeField(child))); -} - -function sanitizeUnion(typeLike: object) { - if ( - !("typeIds" in typeLike) || - !("mode" in typeLike) || - typeof typeLike.mode !== "number" - ) { - throw Error( - "Expected a Union type to have `typeIds` and `mode` properties" - ); - } - if (!("children" in typeLike) || !Array.isArray(typeLike.children)) { - throw Error( - "Expected a Union type to have an array-like `children` property" - ); - } - - return new Union( - typeLike.mode, - typeLike.typeIds as any, - typeLike.children.map((child) => sanitizeField(child)) - ); -} - -function sanitizeTypedUnion( - typeLike: object, - UnionType: typeof DenseUnion | typeof SparseUnion -) { - if (!("typeIds" in typeLike)) { - throw Error( - "Expected a DenseUnion/SparseUnion type to have a `typeIds` property" - ); - } - if (!("children" in typeLike) || !Array.isArray(typeLike.children)) { - throw Error( - "Expected a DenseUnion/SparseUnion type to have an array-like `children` property" - ); - } - - return new UnionType( - typeLike.typeIds as any, - typeLike.children.map((child) => sanitizeField(child)) - ); -} - -function sanitizeFixedSizeBinary(typeLike: object) { - if (!("byteWidth" in typeLike) || typeof typeLike.byteWidth !== "number") { - throw Error( - "Expected a FixedSizeBinary type to have a `byteWidth` property" - ); - } - return new FixedSizeBinary(typeLike.byteWidth); -} - -function sanitizeFixedSizeList(typeLike: object) { - if (!("listSize" in typeLike) || typeof typeLike.listSize !== "number") { - throw Error("Expected a FixedSizeList type to have a `listSize` property"); - } - if (!("children" in typeLike) || !Array.isArray(typeLike.children)) { - throw Error( - "Expected a FixedSizeList type to have an array-like `children` property" - ); - } - if (typeLike.children.length !== 1) { - throw Error("Expected a FixedSizeList type to have exactly one child"); - } - return new FixedSizeList( - typeLike.listSize, - sanitizeField(typeLike.children[0]) - ); -} - -function sanitizeMap(typeLike: object) { - if (!("children" in typeLike) || !Array.isArray(typeLike.children)) { - throw Error( - "Expected a Map type to have an array-like `children` property" - ); - } - if (!("keysSorted" in typeLike) || typeof typeLike.keysSorted !== "boolean") { - throw Error("Expected a Map type to have a `keysSorted` property"); - } - return new Map_( - typeLike.children.map((field) => sanitizeField(field)) as any, - typeLike.keysSorted - ); -} - -function sanitizeDuration(typeLike: object) { - if (!("unit" in typeLike) || typeof typeLike.unit !== "number") { - throw Error("Expected a Duration type to have a `unit` property"); - } - return new Duration(typeLike.unit); -} - -function sanitizeDictionary(typeLike: object) { - if (!("id" in typeLike) || typeof typeLike.id !== "number") { - throw Error("Expected a Dictionary type to have an `id` property"); - } - if (!("indices" in typeLike) || typeof typeLike.indices !== "object") { - throw Error("Expected a Dictionary type to have an `indices` property"); - } - if (!("dictionary" in typeLike) || typeof typeLike.dictionary !== "object") { - throw Error("Expected a Dictionary type to have an `dictionary` property"); - } - if (!("isOrdered" in typeLike) || typeof typeLike.isOrdered !== "boolean") { - throw Error("Expected a Dictionary type to have an `isOrdered` property"); - } - return new Dictionary( - sanitizeType(typeLike.dictionary), - sanitizeType(typeLike.indices) as any, - typeLike.id, - typeLike.isOrdered - ); -} - -function sanitizeType(typeLike: unknown): DataType { - if (typeof typeLike !== "object" || typeLike === null) { - throw Error("Expected a Type but object was null/undefined"); - } - if (!("typeId" in typeLike) || !(typeof typeLike.typeId !== "function")) { - throw Error("Expected a Type to have a typeId function"); - } - let typeId: Type; - if (typeof typeLike.typeId === "function") { - typeId = (typeLike.typeId as () => unknown)() as Type; - } else if (typeof typeLike.typeId === "number") { - typeId = typeLike.typeId as Type; - } else { - throw Error("Type's typeId property was not a function or number"); - } - - switch (typeId) { - case Type.NONE: - throw Error("Received a Type with a typeId of NONE"); - case Type.Null: - return new Null(); - case Type.Int: - return sanitizeInt(typeLike); - case Type.Float: - return sanitizeFloat(typeLike); - case Type.Binary: - return new Binary(); - case Type.Utf8: - return new Utf8(); - case Type.Bool: - return new Bool(); - case Type.Decimal: - return sanitizeDecimal(typeLike); - case Type.Date: - return sanitizeDate(typeLike); - case Type.Time: - return sanitizeTime(typeLike); - case Type.Timestamp: - return sanitizeTimestamp(typeLike); - case Type.Interval: - return sanitizeInterval(typeLike); - case Type.List: - return sanitizeList(typeLike); - case Type.Struct: - return sanitizeStruct(typeLike); - case Type.Union: - return sanitizeUnion(typeLike); - case Type.FixedSizeBinary: - return sanitizeFixedSizeBinary(typeLike); - case Type.FixedSizeList: - return sanitizeFixedSizeList(typeLike); - case Type.Map: - return sanitizeMap(typeLike); - case Type.Duration: - return sanitizeDuration(typeLike); - case Type.Dictionary: - return sanitizeDictionary(typeLike); - case Type.Int8: - return new Int8(); - case Type.Int16: - return new Int16(); - case Type.Int32: - return new Int32(); - case Type.Int64: - return new Int64(); - case Type.Uint8: - return new Uint8(); - case Type.Uint16: - return new Uint16(); - case Type.Uint32: - return new Uint32(); - case Type.Uint64: - return new Uint64(); - case Type.Float16: - return new Float16(); - case Type.Float32: - return new Float32(); - case Type.Float64: - return new Float64(); - case Type.DateMillisecond: - return new DateMillisecond(); - case Type.DateDay: - return new DateDay(); - case Type.TimeNanosecond: - return new TimeNanosecond(); - case Type.TimeMicrosecond: - return new TimeMicrosecond(); - case Type.TimeMillisecond: - return new TimeMillisecond(); - case Type.TimeSecond: - return new TimeSecond(); - case Type.TimestampNanosecond: - return sanitizeTypedTimestamp(typeLike, TimestampNanosecond); - case Type.TimestampMicrosecond: - return sanitizeTypedTimestamp(typeLike, TimestampMicrosecond); - case Type.TimestampMillisecond: - return sanitizeTypedTimestamp(typeLike, TimestampMillisecond); - case Type.TimestampSecond: - return sanitizeTypedTimestamp(typeLike, TimestampSecond); - case Type.DenseUnion: - return sanitizeTypedUnion(typeLike, DenseUnion); - case Type.SparseUnion: - return sanitizeTypedUnion(typeLike, SparseUnion); - case Type.IntervalDayTime: - return new IntervalDayTime(); - case Type.IntervalYearMonth: - return new IntervalYearMonth(); - case Type.DurationNanosecond: - return new DurationNanosecond(); - case Type.DurationMicrosecond: - return new DurationMicrosecond(); - case Type.DurationMillisecond: - return new DurationMillisecond(); - case Type.DurationSecond: - return new DurationSecond(); - } -} - -function sanitizeField(fieldLike: unknown): Field { - if (fieldLike instanceof Field) { - return fieldLike; - } - if (typeof fieldLike !== "object" || fieldLike === null) { - throw Error("Expected a Field but object was null/undefined"); - } - if ( - !("type" in fieldLike) || - !("name" in fieldLike) || - !("nullable" in fieldLike) - ) { - throw Error( - "The field passed in is missing a `type`/`name`/`nullable` property" - ); - } - const type = sanitizeType(fieldLike.type); - const name = fieldLike.name; - if (!(typeof name === "string")) { - throw Error("The field passed in had a non-string `name` property"); - } - const nullable = fieldLike.nullable; - if (!(typeof nullable === "boolean")) { - throw Error("The field passed in had a non-boolean `nullable` property"); - } - let metadata; - if ("metadata" in fieldLike) { - metadata = sanitizeMetadata(fieldLike.metadata); - } - return new Field(name, type, nullable, metadata); -} - -/** - * Convert something schemaLike into a Schema instance - * - * This method is often needed even when the caller is using a Schema - * instance because they might be using a different instance of apache-arrow - * than lancedb is using. - */ -export function sanitizeSchema(schemaLike: unknown): Schema { - if (schemaLike instanceof Schema) { - return schemaLike; - } - if (typeof schemaLike !== "object" || schemaLike === null) { - throw Error("Expected a Schema but object was null/undefined"); - } - if (!("fields" in schemaLike)) { - throw Error( - "The schema passed in does not appear to be a schema (no 'fields' property)" - ); - } - let metadata; - if ("metadata" in schemaLike) { - metadata = sanitizeMetadata(schemaLike.metadata); - } - if (!Array.isArray(schemaLike.fields)) { - throw Error( - "The schema passed in had a 'fields' property but it was not an array" - ); - } - const sanitizedFields = schemaLike.fields.map((field) => - sanitizeField(field) - ); - return new Schema(sanitizedFields, metadata); -} diff --git a/node/src/test/arrow.test.ts b/node/src/test/arrow.test.ts deleted file mode 100644 index 38005e6a..00000000 --- a/node/src/test/arrow.test.ts +++ /dev/null @@ -1,360 +0,0 @@ -// Copyright 2024 Lance Developers. -// -// 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. - -import { describe } from 'mocha' -import { assert, expect, use as chaiUse } from 'chai' -import * as chaiAsPromised from 'chai-as-promised' - -import { convertToTable, fromTableToBuffer, makeArrowTable, makeEmptyTable } from '../arrow' -import { - Field, - FixedSizeList, - Float16, - Float32, - Int32, - tableFromIPC, - Schema, - Float64, - type Table, - Binary, - Bool, - Utf8, - Struct, - List, - DataType, - Dictionary, - Int64, - MetadataVersion -} from 'apache-arrow' -import { - Dictionary as OldDictionary, - Field as OldField, - FixedSizeList as OldFixedSizeList, - Float32 as OldFloat32, - Int32 as OldInt32, - Struct as OldStruct, - Schema as OldSchema, - TimestampNanosecond as OldTimestampNanosecond, - Utf8 as OldUtf8 -} from 'apache-arrow-old' -import { type EmbeddingFunction } from '../embedding/embedding_function' - -chaiUse(chaiAsPromised) - -function sampleRecords (): Array> { - return [ - { - binary: Buffer.alloc(5), - boolean: false, - number: 7, - string: 'hello', - struct: { x: 0, y: 0 }, - list: ['anime', 'action', 'comedy'] - } - ] -} - -// Helper method to verify various ways to create a table -async function checkTableCreation (tableCreationMethod: (records: any, recordsReversed: any, schema: Schema) => Promise
): Promise { - const records = sampleRecords() - const recordsReversed = [{ - list: ['anime', 'action', 'comedy'], - struct: { x: 0, y: 0 }, - string: 'hello', - number: 7, - boolean: false, - binary: Buffer.alloc(5) - }] - const schema = new Schema([ - new Field('binary', new Binary(), false), - new Field('boolean', new Bool(), false), - new Field('number', new Float64(), false), - new Field('string', new Utf8(), false), - new Field('struct', new Struct([ - new Field('x', new Float64(), false), - new Field('y', new Float64(), false) - ])), - new Field('list', new List(new Field('item', new Utf8(), false)), false) - ]) - - const table = await tableCreationMethod(records, recordsReversed, schema) - schema.fields.forEach((field, idx) => { - const actualField = table.schema.fields[idx] - assert.isFalse(actualField.nullable) - assert.equal(table.getChild(field.name)?.type.toString(), field.type.toString()) - assert.equal(table.getChildAt(idx)?.type.toString(), field.type.toString()) - }) -} - -describe('The function makeArrowTable', function () { - it('will use data types from a provided schema instead of inference', async function () { - const schema = new Schema([ - new Field('a', new Int32()), - new Field('b', new Float32()), - new Field('c', new FixedSizeList(3, new Field('item', new Float16()))), - new Field('d', new Int64()) - ]) - const table = makeArrowTable( - [ - { a: 1, b: 2, c: [1, 2, 3], d: 9 }, - { a: 4, b: 5, c: [4, 5, 6], d: 10 }, - { a: 7, b: 8, c: [7, 8, 9], d: null } - ], - { schema } - ) - - const buf = await fromTableToBuffer(table) - assert.isAbove(buf.byteLength, 0) - - const actual = tableFromIPC(buf) - assert.equal(actual.numRows, 3) - const actualSchema = actual.schema - assert.deepEqual(actualSchema, schema) - }) - - it('will assume the column `vector` is FixedSizeList by default', async function () { - const schema = new Schema([ - new Field('a', new Float64()), - new Field('b', new Float64()), - new Field( - 'vector', - new FixedSizeList(3, new Field('item', new Float32(), true)) - ) - ]) - const table = makeArrowTable([ - { a: 1, b: 2, vector: [1, 2, 3] }, - { a: 4, b: 5, vector: [4, 5, 6] }, - { a: 7, b: 8, vector: [7, 8, 9] } - ]) - - const buf = await fromTableToBuffer(table) - assert.isAbove(buf.byteLength, 0) - - const actual = tableFromIPC(buf) - assert.equal(actual.numRows, 3) - const actualSchema = actual.schema - assert.deepEqual(actualSchema, schema) - }) - - it('can support multiple vector columns', async function () { - const schema = new Schema([ - new Field('a', new Float64()), - new Field('b', new Float64()), - new Field('vec1', new FixedSizeList(3, new Field('item', new Float16(), true))), - new Field('vec2', new FixedSizeList(3, new Field('item', new Float16(), true))) - ]) - const table = makeArrowTable( - [ - { a: 1, b: 2, vec1: [1, 2, 3], vec2: [2, 4, 6] }, - { a: 4, b: 5, vec1: [4, 5, 6], vec2: [8, 10, 12] }, - { a: 7, b: 8, vec1: [7, 8, 9], vec2: [14, 16, 18] } - ], - { - vectorColumns: { - vec1: { type: new Float16() }, - vec2: { type: new Float16() } - } - } - ) - - const buf = await fromTableToBuffer(table) - assert.isAbove(buf.byteLength, 0) - - const actual = tableFromIPC(buf) - assert.equal(actual.numRows, 3) - const actualSchema = actual.schema - assert.deepEqual(actualSchema, schema) - }) - - it('will allow different vector column types', async function () { - const table = makeArrowTable( - [ - { fp16: [1], fp32: [1], fp64: [1] } - ], - { - vectorColumns: { - fp16: { type: new Float16() }, - fp32: { type: new Float32() }, - fp64: { type: new Float64() } - } - } - ) - - assert.equal(table.getChild('fp16')?.type.children[0].type.toString(), new Float16().toString()) - assert.equal(table.getChild('fp32')?.type.children[0].type.toString(), new Float32().toString()) - assert.equal(table.getChild('fp64')?.type.children[0].type.toString(), new Float64().toString()) - }) - - it('will use dictionary encoded strings if asked', async function () { - const table = makeArrowTable([{ str: 'hello' }]) - assert.isTrue(DataType.isUtf8(table.getChild('str')?.type)) - - const tableWithDict = makeArrowTable([{ str: 'hello' }], { dictionaryEncodeStrings: true }) - assert.isTrue(DataType.isDictionary(tableWithDict.getChild('str')?.type)) - - const schema = new Schema([ - new Field('str', new Dictionary(new Utf8(), new Int32())) - ]) - - const tableWithDict2 = makeArrowTable([{ str: 'hello' }], { schema }) - assert.isTrue(DataType.isDictionary(tableWithDict2.getChild('str')?.type)) - }) - - it('will infer data types correctly', async function () { - await checkTableCreation(async (records) => makeArrowTable(records)) - }) - - it('will allow a schema to be provided', async function () { - await checkTableCreation(async (records, _, schema) => makeArrowTable(records, { schema })) - }) - - it('will use the field order of any provided schema', async function () { - await checkTableCreation(async (_, recordsReversed, schema) => makeArrowTable(recordsReversed, { schema })) - }) - - it('will make an empty table', async function () { - await checkTableCreation(async (_, __, schema) => makeArrowTable([], { schema })) - }) -}) - -class DummyEmbedding implements EmbeddingFunction { - public readonly sourceColumn = 'string' - public readonly embeddingDimension = 2 - public readonly embeddingDataType = new Float16() - - async embed (data: string[]): Promise { - return data.map( - () => [0.0, 0.0] - ) - } -} - -class DummyEmbeddingWithNoDimension implements EmbeddingFunction { - public readonly sourceColumn = 'string' - - async embed (data: string[]): Promise { - return data.map( - () => [0.0, 0.0] - ) - } -} - -describe('convertToTable', function () { - it('will infer data types correctly', async function () { - await checkTableCreation(async (records) => await convertToTable(records)) - }) - - it('will allow a schema to be provided', async function () { - await checkTableCreation(async (records, _, schema) => await convertToTable(records, undefined, { schema })) - }) - - it('will use the field order of any provided schema', async function () { - await checkTableCreation(async (_, recordsReversed, schema) => await convertToTable(recordsReversed, undefined, { schema })) - }) - - it('will make an empty table', async function () { - await checkTableCreation(async (_, __, schema) => await convertToTable([], undefined, { schema })) - }) - - it('will apply embeddings', async function () { - const records = sampleRecords() - const table = await convertToTable(records, new DummyEmbedding()) - assert.isTrue(DataType.isFixedSizeList(table.getChild('vector')?.type)) - assert.equal(table.getChild('vector')?.type.children[0].type.toString(), new Float16().toString()) - }) - - it('will fail if missing the embedding source column', async function () { - return await expect(convertToTable([{ id: 1 }], new DummyEmbedding())).to.be.rejectedWith("'string' was not present") - }) - - it('use embeddingDimension if embedding missing from table', async function () { - const schema = new Schema([ - new Field('string', new Utf8(), false) - ]) - // Simulate getting an empty Arrow table (minus embedding) from some other source - // In other words, we aren't starting with records - const table = makeEmptyTable(schema) - - // If the embedding specifies the dimension we are fine - await fromTableToBuffer(table, new DummyEmbedding()) - - // We can also supply a schema and should be ok - const schemaWithEmbedding = new Schema([ - new Field('string', new Utf8(), false), - new Field('vector', new FixedSizeList(2, new Field('item', new Float16(), false)), false) - ]) - await fromTableToBuffer(table, new DummyEmbeddingWithNoDimension(), schemaWithEmbedding) - - // Otherwise we will get an error - return await expect(fromTableToBuffer(table, new DummyEmbeddingWithNoDimension())).to.be.rejectedWith('does not specify `embeddingDimension`') - }) - - it('will apply embeddings to an empty table', async function () { - const schema = new Schema([ - new Field('string', new Utf8(), false), - new Field('vector', new FixedSizeList(2, new Field('item', new Float16(), false)), false) - ]) - const table = await convertToTable([], new DummyEmbedding(), { schema }) - assert.isTrue(DataType.isFixedSizeList(table.getChild('vector')?.type)) - assert.equal(table.getChild('vector')?.type.children[0].type.toString(), new Float16().toString()) - }) - - it('will complain if embeddings present but schema missing embedding column', async function () { - const schema = new Schema([ - new Field('string', new Utf8(), false) - ]) - return await expect(convertToTable([], new DummyEmbedding(), { schema })).to.be.rejectedWith('column vector was missing') - }) - - it('will provide a nice error if run twice', async function () { - const records = sampleRecords() - const table = await convertToTable(records, new DummyEmbedding()) - // fromTableToBuffer will try and apply the embeddings again - return await expect(fromTableToBuffer(table, new DummyEmbedding())).to.be.rejectedWith('already existed') - }) -}) - -describe('makeEmptyTable', function () { - it('will make an empty table', async function () { - await checkTableCreation(async (_, __, schema) => makeEmptyTable(schema)) - }) -}) - -describe('when using two versions of arrow', function () { - it('can still import data', async function() { - const schema = new OldSchema([ - new OldField('id', new OldInt32()), - new OldField('vector', new OldFixedSizeList(1024, new OldField("item", new OldFloat32(), true))), - new OldField('struct', new OldStruct([ - new OldField('nested', new OldDictionary(new OldUtf8(), new OldInt32(), 1, true)), - new OldField('ts_with_tz', new OldTimestampNanosecond("some_tz")), - new OldField('ts_no_tz', new OldTimestampNanosecond(null)) - ])) - ]) as any - // We use arrow version 13 to emulate a "foreign arrow" and this version doesn't have metadataVersion - // In theory, this wouldn't matter. We don't rely on that property. However, it causes deepEqual to - // fail so we patch it back in - schema.metadataVersion = MetadataVersion.V5 - const table = makeArrowTable( - [], - { schema } - ) - - const buf = await fromTableToBuffer(table) - assert.isAbove(buf.byteLength, 0) - const actual = tableFromIPC(buf) - const actualSchema = actual.schema - assert.deepEqual(actualSchema, schema) - }) -}) diff --git a/node/src/test/embedding/openai.ts b/node/src/test/embedding/openai.ts deleted file mode 100644 index 07a7b57f..00000000 --- a/node/src/test/embedding/openai.ts +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2023 Lance Developers. -// -// 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. - -import { describe } from 'mocha' -import { assert } from 'chai' - -import { OpenAIEmbeddingFunction } from '../../embedding/openai' -import { isEmbeddingFunction } from '../../embedding/embedding_function' - -// eslint-disable-next-line @typescript-eslint/no-var-requires -const OpenAIApi = require('openai') -// eslint-disable-next-line @typescript-eslint/no-var-requires -const { stub } = require('sinon') - -describe('OpenAPIEmbeddings', function () { - const stubValue = { - data: [ - { - embedding: Array(1536).fill(1.0) - }, - { - embedding: Array(1536).fill(2.0) - } - ] - } - - describe('#embed', function () { - it('should create vector embeddings', async function () { - const openAIStub = stub(OpenAIApi.Embeddings.prototype, 'create').returns(stubValue) - const f = new OpenAIEmbeddingFunction('text', 'sk-key') - const vectors = await f.embed(['abc', 'def']) - assert.isTrue(openAIStub.calledOnce) - assert.equal(vectors.length, 2) - assert.deepEqual(vectors[0], stubValue.data[0].embedding) - assert.deepEqual(vectors[1], stubValue.data[1].embedding) - }) - }) - - describe('isEmbeddingFunction', function () { - it('should match the isEmbeddingFunction guard', function () { - assert.isTrue(isEmbeddingFunction(new OpenAIEmbeddingFunction('text', 'sk-key'))) - }) - }) -}) diff --git a/node/src/test/io.ts b/node/src/test/io.ts deleted file mode 100644 index 238c44a1..00000000 --- a/node/src/test/io.ts +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2023 Lance Developers. -// -// 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. - -// IO tests - -import { describe } from 'mocha' -import { assert } from 'chai' - -import * as lancedb from '../index' -import { type ConnectionOptions } from '../index' - -describe('LanceDB S3 client', function () { - if (process.env.TEST_S3_BASE_URL != null) { - const baseUri = process.env.TEST_S3_BASE_URL - it('should have a valid url', async function () { - const opts = { uri: `${baseUri}/valid_url` } - const table = await createTestDB(opts, 2, 20) - const con = await lancedb.connect(opts) - assert.equal(con.uri, opts.uri) - - const results = await table.search([0.1, 0.3]).limit(5).execute() - assert.equal(results.length, 5) - }).timeout(10_000) - } else { - describe.skip('Skip S3 test', function () {}) - } - - if (process.env.TEST_S3_BASE_URL != null && process.env.TEST_AWS_ACCESS_KEY_ID != null && process.env.TEST_AWS_SECRET_ACCESS_KEY != null) { - const baseUri = process.env.TEST_S3_BASE_URL - it('use custom credentials', async function () { - const opts: ConnectionOptions = { - uri: `${baseUri}/custom_credentials`, - awsCredentials: { - accessKeyId: process.env.TEST_AWS_ACCESS_KEY_ID as string, - secretKey: process.env.TEST_AWS_SECRET_ACCESS_KEY as string - } - } - const table = await createTestDB(opts, 2, 20) - console.log(table) - const con = await lancedb.connect(opts) - console.log(con) - assert.equal(con.uri, opts.uri) - - const results = await table.search([0.1, 0.3]).limit(5).execute() - assert.equal(results.length, 5) - }).timeout(10_000) - } else { - describe.skip('Skip S3 test', function () {}) - } -}) - -async function createTestDB (opts: ConnectionOptions, numDimensions: number = 2, numRows: number = 2): Promise { - const con = await lancedb.connect(opts) - - const data = [] - for (let i = 0; i < numRows; i++) { - const vector = [] - for (let j = 0; j < numDimensions; j++) { - vector.push(i + (j * 0.1)) - } - data.push({ id: i + 1, name: `name_${i}`, price: i + 10, is_active: (i % 2 === 0), vector }) - } - - return await con.createTable('vectors_2', data) -} diff --git a/node/src/test/test.ts b/node/src/test/test.ts deleted file mode 100644 index 3f00e751..00000000 --- a/node/src/test/test.ts +++ /dev/null @@ -1,1279 +0,0 @@ -// Copyright 2023 LanceDB Developers. -// -// 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. - -import { describe } from "mocha"; -import { track } from "temp"; -import { assert, expect } from 'chai' -import * as chai from "chai"; -import * as chaiAsPromised from "chai-as-promised"; - -import * as lancedb from "../index"; -import { - type AwsCredentials, - type EmbeddingFunction, - MetricType, - Query, - WriteMode, - DefaultWriteOptions, - isWriteOptions, - type LocalTable -} from "../index"; -import { - FixedSizeList, - Field, - Int32, - makeVector, - Schema, - Utf8, - Table as ArrowTable, - vectorFromArray, - Float64, - Float32, - Float16, - Int64 -} from "apache-arrow"; -import type { RemoteRequest, RemoteResponse } from "../middleware"; - -chai.use(chaiAsPromised); - -describe("LanceDB client", function () { - describe("when creating a connection to lancedb", function () { - it("should have a valid url", async function () { - const uri = await createTestDB(); - const con = await lancedb.connect(uri); - assert.equal(con.uri, uri); - }); - - it("should accept an options object", async function () { - const uri = await createTestDB(); - const con = await lancedb.connect({ uri }); - assert.equal(con.uri, uri); - }); - - it("should accept custom aws credentials", async function () { - const uri = await createTestDB(); - const awsCredentials: AwsCredentials = { - accessKeyId: "", - secretKey: "" - }; - const con = await lancedb.connect({ - uri, - awsCredentials - }); - assert.equal(con.uri, uri); - }); - - it("should accept custom storage options", async function () { - const uri = await createTestDB(); - const storageOptions = { - region: "us-west-2", - timeout: "30s" - }; - const con = await lancedb.connect({ - uri, - storageOptions - }); - assert.equal(con.uri, uri); - }); - - it("should return the existing table names", async function () { - const uri = await createTestDB(); - const con = await lancedb.connect(uri); - assert.deepEqual(await con.tableNames(), ["vectors"]); - }); - - it("read consistency level", async function () { - const uri = await createTestDB(); - const db1 = await lancedb.connect({ uri }); - const table1 = await db1.openTable("vectors"); - - const db2 = await lancedb.connect({ - uri, - readConsistencyInterval: 0 - }) - const table2 = await db2.openTable("vectors"); - - assert.equal(await table2.countRows(), 2); - await table1.add([ - { - id: 3, - name: 'name_2', - price: 10, - is_active: true, - vector: [0, 0.1] - } - ]); - assert.equal(await table2.countRows(), 3); - }); - }); - - describe("when querying an existing dataset", function () { - it("should open a table", async function () { - const uri = await createTestDB(); - const con = await lancedb.connect(uri); - const table = await con.openTable("vectors"); - assert.equal(table.name, "vectors"); - }); - - it("execute a query", async function () { - const uri = await createTestDB(); - const con = await lancedb.connect(uri); - const table = await con.openTable("vectors"); - const results = await table.search([0.1, 0.3]).execute(); - - assert.equal(results.length, 2); - assert.equal(results[0].price, 10); - const vector = results[0].vector as Float32Array; - assert.approximately(vector[0], 0.0, 0.2); - assert.approximately(vector[0], 0.1, 0.3); - }); - - it("limits # of results", async function () { - const uri = await createTestDB(2, 100); - const con = await lancedb.connect(uri); - const table = await con.openTable("vectors"); - let results = await table.search([0.1, 0.3]).limit(1).execute(); - assert.equal(results.length, 1); - assert.equal(results[0].id, 1); - - // there is a default limit if unspecified - results = await table.search([0.1, 0.3]).execute(); - assert.equal(results.length, 10); - }); - - it("uses a filter / where clause without vector search", async function () { - // eslint-disable-next-line @typescript-eslint/explicit-function-return-type - const assertResults = (results: Array>) => { - assert.equal(results.length, 50); - }; - - const uri = await createTestDB(2, 100); - const con = await lancedb.connect(uri); - const table = (await con.openTable("vectors")) as LocalTable; - let results = await table.filter("id % 2 = 0").limit(100).execute(); - assertResults(results); - results = await table.where("id % 2 = 0").limit(100).execute(); - assertResults(results); - - // Should reject a bad filter - await expect(table.filter("id % 2 = 0 AND").execute()).to.be.rejectedWith( - /.*sql parser error: .*/ - ); - }); - - it("uses a filter / where clause", async function () { - // eslint-disable-next-line @typescript-eslint/explicit-function-return-type - const assertResults = (results: Array>) => { - assert.equal(results.length, 1); - assert.equal(results[0].id, 2); - }; - - const uri = await createTestDB(); - const con = await lancedb.connect(uri); - const table = await con.openTable("vectors"); - let results = await table.search([0.1, 0.1]).filter("id == 2").execute(); - assertResults(results); - results = await table.search([0.1, 0.1]).where("id == 2").execute(); - assertResults(results); - }); - - it("should correctly process prefilter/postfilter", async function () { - const uri = await createTestDB(16, 300); - const con = await lancedb.connect(uri); - const table = await con.openTable("vectors"); - await table.createIndex({ - type: "ivf_pq", - column: "vector", - num_partitions: 2, - max_iters: 2, - num_sub_vectors: 2 - }); - // post filter should return less than the limit - let results = await table - .search(new Array(16).fill(0.1)) - .limit(10) - .filter("id >= 10") - .prefilter(false) - .execute(); - assert.isTrue(results.length < 10); - - // pre filter should return exactly the limit - results = await table - .search(new Array(16).fill(0.1)) - .limit(10) - .filter("id >= 10") - .prefilter(true) - .execute(); - assert.isTrue(results.length === 10); - }); - - it("should allow creation and use of scalar indices", async function () { - const uri = await createTestDB(16, 300); - const con = await lancedb.connect(uri); - const table = await con.openTable("vectors"); - await table.createScalarIndex("id", true); - - // Prefiltering should still work the same - const results = await table - .search(new Array(16).fill(0.1)) - .limit(10) - .filter("id >= 10") - .prefilter(true) - .execute(); - assert.isTrue(results.length === 10); - }); - - it("select only a subset of columns", async function () { - const uri = await createTestDB(); - const con = await lancedb.connect(uri); - const table = await con.openTable("vectors"); - const results = await table - .search([0.1, 0.1]) - .select(["is_active", "vector"]) - .execute(); - assert.equal(results.length, 2); - // vector and _distance are always returned - assert.isDefined(results[0].vector); - assert.isDefined(results[0]._distance); - assert.isDefined(results[0].is_active); - - assert.isUndefined(results[0].id); - assert.isUndefined(results[0].name); - assert.isUndefined(results[0].price); - }); - }); - - describe("when creating a new dataset", function () { - it("create an empty table", async function () { - const dir = await track().mkdir("lancejs"); - const con = await lancedb.connect(dir); - - const schema = new Schema([ - new Field("id", new Int32()), - new Field("name", new Utf8()) - ]); - const table = await con.createTable({ - name: "vectors", - schema - }); - assert.equal(table.name, "vectors"); - assert.deepEqual(await con.tableNames(), ["vectors"]); - }); - - it("create a table with a schema and records", async function () { - const dir = await track().mkdir("lancejs"); - const con = await lancedb.connect(dir); - - const schema = new Schema([ - new Field("id", new Int32()), - new Field("name", new Utf8()), - new Field( - "vector", - new FixedSizeList(2, new Field("item", new Float32(), true)), - false - ) - ]); - const data = [ - { - vector: [0.5, 0.2], - name: "foo", - id: 0 - }, - { - vector: [0.3, 0.1], - name: "bar", - id: 1 - } - ]; - // even thought the keys in data is out of order it should still work - const table = await con.createTable({ - name: "vectors", - data, - schema - }); - assert.equal(table.name, "vectors"); - assert.deepEqual(await con.tableNames(), ["vectors"]); - }); - - it("create a table with a empty data array", async function () { - const dir = await track().mkdir("lancejs"); - const con = await lancedb.connect(dir); - - const schema = new Schema([ - new Field("id", new Int32()), - new Field("name", new Utf8()) - ]); - const table = await con.createTable({ - name: "vectors", - schema, - data: [] - }); - assert.equal(table.name, "vectors"); - assert.deepEqual(await con.tableNames(), ["vectors"]); - }); - - it("create a table from an Arrow Table", async function () { - const dir = await track().mkdir("lancejs"); - // Also test the connect function with an object - const con = await lancedb.connect({ uri: dir }); - - const i32s = new Int32Array(new Array(10)); - const i32 = makeVector(i32s); - - const data = new ArrowTable({ vector: i32 }); - - const table = await con.createTable({ - name: "vectors", - data - }); - assert.equal(table.name, "vectors"); - assert.equal(await table.countRows(), 10); - assert.equal(await table.countRows("vector IS NULL"), 0); - assert.deepEqual(await con.tableNames(), ["vectors"]); - }); - - it("creates a new table from javascript objects", async function () { - const dir = await track().mkdir("lancejs"); - const con = await lancedb.connect(dir); - - const data = [ - { id: 1, vector: [0.1, 0.2], price: 10 }, - { - id: 2, - vector: [1.1, 1.2], - price: 50 - } - ]; - - const tableName = `vectors_${Math.floor(Math.random() * 100)}`; - const table = await con.createTable(tableName, data); - assert.equal(table.name, tableName); - assert.equal(await table.countRows(), 2); - }); - - it("creates a new table from javascript objects with variable sized list", async function () { - const dir = await track().mkdir("lancejs"); - const con = await lancedb.connect(dir); - - const data = [ - { - id: 1, - vector: [0.1, 0.2], - list_of_str: ["a", "b", "c"], - list_of_num: [1, 2, 3] - }, - { - id: 2, - vector: [1.1, 1.2], - list_of_str: ["x", "y"], - list_of_num: [4, 5, 6] - } - ]; - - const tableName = "with_variable_sized_list"; - const table = (await con.createTable(tableName, data)) as LocalTable; - assert.equal(table.name, tableName); - assert.equal(await table.countRows(), 2); - const rs = await table.filter("id>1").execute(); - assert.equal(rs.length, 1); - assert.deepEqual(rs[0].list_of_str, ["x", "y"]); - assert.isTrue(rs[0].list_of_num instanceof Array); - }); - - it("create table from arrow table", async () => { - const dim = 128; - const total = 256; - const dir = await track().mkdir("lancejs"); - const con = await lancedb.connect(dir); - - const schema = new Schema([ - new Field("id", new Int32()), - new Field( - "vector", - new FixedSizeList(dim, new Field("item", new Float16(), true)), - false - ) - ]); - const data = lancedb.makeArrowTable( - Array.from(Array(total), (_, i) => ({ - id: i, - vector: Array.from(Array(dim), Math.random) - })), - { schema } - ); - const table = await con.createTable("f16", data); - assert.equal(table.name, "f16"); - assert.equal(await table.countRows(), total); - assert.equal(await table.countRows("id < 5"), 5); - assert.deepEqual(await con.tableNames(), ["f16"]); - assert.deepEqual(await table.schema, schema); - - await table.createIndex({ - num_sub_vectors: 2, - num_partitions: 2, - type: "ivf_pq" - }); - - const q = Array.from(Array(dim), Math.random); - const r = await table.search(q).limit(5).execute(); - assert.equal(r.length, 5); - r.forEach((v) => { - assert.equal(Object.prototype.hasOwnProperty.call(v, "vector"), true); - assert.equal( - v.vector?.constructor.name, - "Array", - "vector column is list of floats" - ); - }); - }).timeout(120000); - - it("use overwrite flag to overwrite existing table", async function () { - const dir = await track().mkdir("lancejs"); - const con = await lancedb.connect(dir); - - const data = [ - { id: 1, vector: [0.1, 0.2], price: 10 }, - { - id: 2, - vector: [1.1, 1.2], - price: 50 - } - ]; - - const tableName = "overwrite"; - await con.createTable(tableName, data, { writeMode: WriteMode.Create }); - - const newData = [ - { id: 1, vector: [0.1, 0.2], price: 10 }, - { id: 2, vector: [1.1, 1.2], price: 50 }, - { - id: 3, - vector: [1.1, 1.2], - price: 50 - } - ]; - - await expect(con.createTable(tableName, newData)).to.be.rejectedWith( - Error, - "already exists" - ); - - const table = await con.createTable(tableName, newData, { - writeMode: WriteMode.Overwrite - }); - assert.equal(table.name, tableName); - assert.equal(await table.countRows(), 3); - }); - - it("appends records to an existing table ", async function () { - const dir = await track().mkdir("lancejs"); - const con = await lancedb.connect(dir); - - const data = [ - { - id: 1, - vector: [0.1, 0.2], - price: 10, - name: "a" - }, - { - id: 2, - vector: [1.1, 1.2], - price: 50, - name: "b" - } - ]; - - const table = await con.createTable("vectors", data); - assert.equal(await table.countRows(), 2); - - const dataAdd = [ - { - id: 3, - vector: [2.1, 2.2], - price: 10, - name: "c" - }, - { - id: 4, - vector: [3.1, 3.2], - price: 50, - name: "d" - } - ]; - await table.add(dataAdd); - assert.equal(await table.countRows(), 4); - }); - - it("appends records with fields in a different order", async function () { - const dir = await track().mkdir("lancejs"); - const con = await lancedb.connect(dir); - - const data = [ - { - id: 1, - vector: [0.1, 0.2], - price: 10, - name: "a" - }, - { - id: 2, - vector: [1.1, 1.2], - price: 50, - name: "b" - } - ]; - - const table = await con.createTable("vectors", data); - - const dataAdd = [ - { - id: 3, - vector: [2.1, 2.2], - name: "c", - price: 10 - }, - { - id: 4, - vector: [3.1, 3.2], - name: "d", - price: 50 - } - ]; - await table.add(dataAdd); - assert.equal(await table.countRows(), 4); - }); - - it("overwrite all records in a table", async function () { - const uri = await createTestDB(); - const con = await lancedb.connect(uri); - - const table = await con.openTable("vectors"); - assert.equal(await table.countRows(), 2); - - const dataOver = [ - { - vector: [2.1, 2.2], - price: 10, - name: "foo" - }, - { - vector: [3.1, 3.2], - price: 50, - name: "bar" - } - ]; - await table.overwrite(dataOver); - assert.equal(await table.countRows(), 2); - }); - - it("can merge insert records into the table", async function () { - const dir = await track().mkdir("lancejs"); - const con = await lancedb.connect(dir); - - const data = [ - { id: 1, age: 1 }, - { id: 2, age: 1 } - ]; - const table = await con.createTable("my_table", data); - - // insert if not exists - let newData = [ - { id: 2, age: 2 }, - { id: 3, age: 2 } - ]; - await table.mergeInsert("id", newData, { - whenNotMatchedInsertAll: true - }); - assert.equal(await table.countRows(), 3); - assert.equal(await table.countRows("age = 2"), 1); - - // conditional update - newData = [ - { id: 2, age: 3 }, - { id: 3, age: 3 } - ]; - await table.mergeInsert("id", newData, { - whenMatchedUpdateAll: "target.age = 1" - }); - assert.equal(await table.countRows(), 3); - assert.equal(await table.countRows("age = 1"), 1); - assert.equal(await table.countRows("age = 3"), 1); - - newData = [ - { id: 3, age: 4 }, - { id: 4, age: 4 } - ]; - await table.mergeInsert("id", newData, { - whenNotMatchedInsertAll: true, - whenMatchedUpdateAll: true - }); - assert.equal(await table.countRows(), 4); - assert.equal((await table.filter("age = 4").execute()).length, 2); - - newData = [{ id: 5, age: 5 }]; - await table.mergeInsert("id", newData, { - whenNotMatchedInsertAll: true, - whenMatchedUpdateAll: true, - whenNotMatchedBySourceDelete: "age < 4" - }); - assert.equal(await table.countRows(), 3); - - await table.mergeInsert("id", newData, { - whenNotMatchedInsertAll: true, - whenMatchedUpdateAll: true, - whenNotMatchedBySourceDelete: true - }); - assert.equal(await table.countRows(), 1); - }); - - it("can update records in the table", async function () { - const uri = await createTestDB(); - const con = await lancedb.connect(uri); - - const table = await con.openTable("vectors"); - assert.equal(await table.countRows(), 2); - - await table.update({ - where: "price = 10", - valuesSql: { price: "100" } - }); - const results = await table.search([0.1, 0.2]).execute(); - assert.equal(results[0].price, 100); - assert.equal(results[1].price, 11); - }); - - it("can update the records using a literal value", async function () { - const uri = await createTestDB(); - const con = await lancedb.connect(uri); - - const table = await con.openTable("vectors"); - assert.equal(await table.countRows(), 2); - - await table.update({ - where: "price = 10", - values: { price: 100 } - }); - const results = await table.search([0.1, 0.2]).execute(); - assert.equal(results[0].price, 100); - assert.equal(results[1].price, 11); - }); - - it("can update every record in the table", async function () { - const uri = await createTestDB(); - const con = await lancedb.connect(uri); - - const table = await con.openTable("vectors"); - assert.equal(await table.countRows(), 2); - - await table.update({ valuesSql: { price: "100" } }); - const results = await table.search([0.1, 0.2]).execute(); - - assert.equal(results[0].price, 100); - assert.equal(results[1].price, 100); - }); - - it("can delete records from a table", async function () { - const uri = await createTestDB(); - const con = await lancedb.connect(uri); - - const table = await con.openTable("vectors"); - assert.equal(await table.countRows(), 2); - - await table.delete("price = 10"); - assert.equal(await table.countRows(), 1); - }); - it("can manually provide embedding columns", async function () { - const uri = await createTestDB(); - const con = await lancedb.connect(uri); - const schema = new Schema([ - new Field("id", new Int32()), - new Field("text", new Utf8()), - new Field( - "vector", - new FixedSizeList(2, new Field("item", new Float32(), true)) - ) - ]); - const data = [ - { id: 1, text: "foo", vector: [0.1, 0.2] }, - { id: 2, text: "bar", vector: [0.3, 0.4] } - ]; - let table = await con.createTable({ - name: "embed_vectors", - data, - schema - }); - assert.equal(table.name, "embed_vectors"); - table = await con.openTable("embed_vectors"); - assert.equal(await table.countRows(), 2); - }); - - it("will error if no implementation for embedding column found", async function () { - const uri = await createTestDB(); - const con = await lancedb.connect(uri); - const schema = new Schema([ - new Field("id", new Int32()), - new Field("text", new Utf8()), - new Field( - "vector", - new FixedSizeList(2, new Field("item", new Float32(), true)) - ) - ]); - const data = [ - { id: 1, text: "foo" }, - { id: 2, text: "bar" } - ]; - - const table = con.createTable({ - name: "embed_vectors", - data, - schema - }); - await assert.isRejected(table); - }); - }); - - describe("when searching an empty dataset", function () { - it("should not fail", async function () { - const dir = await track().mkdir("lancejs"); - const con = await lancedb.connect(dir); - - const schema = new Schema([ - new Field( - "vector", - new FixedSizeList(128, new Field("float32", new Float32())) - ) - ]); - const table = await con.createTable({ - name: "vectors", - schema - }); - const result = await table.search(Array(128).fill(0.1)).execute(); - assert.isEmpty(result); - }); - }); - - describe("when searching an empty-after-delete dataset", function () { - it("should not fail", async function () { - const dir = await track().mkdir("lancejs"); - const con = await lancedb.connect(dir); - - const schema = new Schema([ - new Field( - "vector", - new FixedSizeList(128, new Field("float32", new Float32())) - ) - ]); - const table = await con.createTable({ - name: "vectors", - schema - }); - await table.add([{ vector: Array(128).fill(0.1) }]); - // https://github.com/lancedb/lance/issues/1635 - await table.delete("true"); - const result = await table.search(Array(128).fill(0.1)).execute(); - assert.isEmpty(result); - }); - }); - - describe("when creating a vector index", function () { - it("overwrite all records in a table", async function () { - const uri = await createTestDB(32, 300); - const con = await lancedb.connect(uri); - const table = await con.openTable("vectors"); - await table.createIndex({ - type: "ivf_pq", - column: "vector", - num_partitions: 2, - max_iters: 2, - num_sub_vectors: 2 - }); - }).timeout(10_000); // Timeout is high partially because GH macos runner is pretty slow - - it("replace an existing index", async function () { - const uri = await createTestDB(16, 300); - const con = await lancedb.connect(uri); - const table = await con.openTable("vectors"); - - await table.createIndex({ - type: "ivf_pq", - column: "vector", - num_partitions: 2, - max_iters: 2, - num_sub_vectors: 2 - }); - - // Replace should fail if the index already exists - await expect( - table.createIndex({ - type: "ivf_pq", - column: "vector", - num_partitions: 2, - max_iters: 2, - num_sub_vectors: 2, - replace: false - }) - ).to.be.rejectedWith("LanceError(Index)"); - - // Default replace = true - await table.createIndex({ - type: "ivf_pq", - column: "vector", - num_partitions: 2, - max_iters: 2, - num_sub_vectors: 2 - }); - }).timeout(50_000); - - it("it should fail when the column is not a vector", async function () { - const uri = await createTestDB(32, 300); - const con = await lancedb.connect(uri); - const table = await con.openTable("vectors"); - const createIndex = table.createIndex({ - type: "ivf_pq", - column: "name", - num_partitions: 2, - max_iters: 2, - num_sub_vectors: 2 - }); - await expect(createIndex).to.be.rejectedWith( - "index cannot be created on the column `name` which has data type Utf8" - ); - }); - - it("it should fail when num_partitions is invalid", async function () { - const uri = await createTestDB(32, 300); - const con = await lancedb.connect(uri); - const table = await con.openTable("vectors"); - const createIndex = table.createIndex({ - type: "ivf_pq", - column: "name", - num_partitions: -1, - max_iters: 2, - num_sub_vectors: 2 - }); - await expect(createIndex).to.be.rejectedWith( - "num_partitions: must be > 0" - ); - }); - - it("should be able to list index and stats", async function () { - const uri = await createTestDB(32, 300); - const con = await lancedb.connect(uri); - const table = await con.openTable("vectors"); - await table.createIndex({ - type: "ivf_pq", - column: "vector", - num_partitions: 2, - max_iters: 2, - num_sub_vectors: 2 - }); - - const indices = await table.listIndices(); - expect(indices).to.have.lengthOf(1); - expect(indices[0].name).to.equal("vector_idx"); - expect(indices[0].uuid).to.not.be.equal(undefined); - expect(indices[0].columns).to.have.lengthOf(1); - expect(indices[0].columns[0]).to.equal("vector"); - - const stats = await table.indexStats(indices[0].name); - expect(stats.numIndexedRows).to.equal(300); - expect(stats.numUnindexedRows).to.equal(0); - expect(stats.indexType).to.equal("IVF_PQ"); - expect(stats.distanceType).to.equal("l2"); - expect(stats.numIndices).to.equal(1); - }).timeout(50_000); - - // not yet implemented - // it("can drop index", async function () { - // const uri = await createTestDB(32, 300); - // const con = await lancedb.connect(uri); - // const table = await con.openTable("vectors"); - // await table.createIndex({ - // type: "ivf_pq", - // column: "vector", - // num_partitions: 2, - // max_iters: 2, - // num_sub_vectors: 2 - // }); - // - // const indices = await table.listIndices(); - // expect(indices).to.have.lengthOf(1); - // expect(indices[0].name).to.equal("vector_idx"); - // - // await table.dropIndex("vector_idx"); - // expect(await table.listIndices()).to.have.lengthOf(0); - // }).timeout(50_000); - }); - - describe("when using a custom embedding function", function () { - class TextEmbedding implements EmbeddingFunction { - sourceColumn: string; - - constructor(targetColumn: string) { - this.sourceColumn = targetColumn; - } - - _embedding_map = new Map([ - ["foo", [2.1, 2.2]], - ["bar", [3.1, 3.2]] - ]); - - async embed(data: string[]): Promise { - return data.map( - (datum) => this._embedding_map.get(datum) ?? [0.0, 0.0] - ); - } - } - - it("should encode the original data into embeddings", async function () { - const dir = await track().mkdir("lancejs"); - const con = await lancedb.connect(dir); - const embeddings = new TextEmbedding("name"); - - const data = [ - { - price: 10, - name: "foo" - }, - { - price: 50, - name: "bar" - } - ]; - const table = await con.createTable("vectors", data, embeddings, { - writeMode: WriteMode.Create - }); - const results = await table.search("foo").execute(); - assert.equal(results.length, 2); - }); - - it("should create embeddings for Arrow Table", async function () { - const dir = await track().mkdir("lancejs"); - const con = await lancedb.connect(dir); - const embeddingFunction = new TextEmbedding("name"); - - const names = vectorFromArray(["foo", "bar"], new Utf8()); - const data = new ArrowTable({ name: names }); - - const table = await con.createTable({ - name: "vectors", - data, - embeddingFunction - }); - assert.equal(table.name, "vectors"); - const results = await table.search("foo").execute(); - assert.equal(results.length, 2); - }); - }); - - describe("when inspecting the schema", function () { - it("should return the schema", async function () { - const uri = await createTestDB(); - const db = await lancedb.connect(uri); - // the fsl inner field must be named 'item' and be nullable - const expectedSchema = new Schema([ - new Field("id", new Int32()), - new Field( - "vector", - new FixedSizeList(128, new Field("item", new Float32(), true)) - ), - new Field("s", new Utf8()) - ]); - const table = await db.createTable({ - name: "some_table", - schema: expectedSchema - }); - const schema = await table.schema; - assert.deepEqual(expectedSchema, schema); - }); - }); -}); - -describe("Remote LanceDB client", function () { - describe("when the server is not reachable", function () { - it("produces a network error", async function () { - const con = await lancedb.connect({ - uri: "db://test-1234", - region: "asdfasfasfdf", - apiKey: "some-api-key" - }); - - // GET - try { - await con.tableNames(); - } catch (err) { - expect(err).to.have.property( - "message", - "Network Error: getaddrinfo ENOTFOUND test-1234.asdfasfasfdf.api.lancedb.com" - ); - } - - // POST - try { - await con.createTable({ - name: "vectors", - schema: new Schema([]) - }); - } catch (err) { - expect(err).to.have.property( - "message", - "Network Error: getaddrinfo ENOTFOUND test-1234.asdfasfasfdf.api.lancedb.com" - ); - } - - // Search - const table = await con - .withMiddleware( - new (class { - async onRemoteRequest( - req: RemoteRequest, - next: (req: RemoteRequest) => Promise - ) { - // intercept call to check if the table exists and make the call succeed - if (req.uri.endsWith("/describe/")) { - return { - status: 200, - statusText: "OK", - headers: new Map(), - body: async () => ({}) - }; - } - - return await next(req); - } - })() - ) - .openTable("vectors"); - - try { - await table.search([0.1, 0.3]).execute(); - } catch (err) { - expect(err).to.have.property( - "message", - "Network Error: getaddrinfo ENOTFOUND test-1234.asdfasfasfdf.api.lancedb.com" - ); - } - }); - }); -}); - -describe("Query object", function () { - it("sets custom parameters", async function () { - const query = new Query([0.1, 0.3]) - .limit(1) - .metricType(MetricType.Cosine) - .refineFactor(100) - .select(["a", "b"]) - .nprobes(20) as Record; - assert.equal(query._limit, 1); - assert.equal(query._metricType, MetricType.Cosine); - assert.equal(query._refineFactor, 100); - assert.equal(query._nprobes, 20); - assert.deepEqual(query._select, ["a", "b"]); - }); -}); - -async function createTestDB( - numDimensions: number = 2, - numRows: number = 2 -): Promise { - const dir = await track().mkdir("lancejs"); - const con = await lancedb.connect(dir); - - const data = []; - for (let i = 0; i < numRows; i++) { - const vector = []; - for (let j = 0; j < numDimensions; j++) { - vector.push(i + j * 0.1); - } - data.push({ - id: i + 1, - name: `name_${i}`, - price: i + 10, - is_active: i % 2 === 0, - vector - }); - } - - await con.createTable("vectors", data); - return dir; -} - -describe("Drop table", function () { - it("drop a table", async function () { - const dir = await track().mkdir("lancejs"); - const con = await lancedb.connect(dir); - - const data = [ - { - price: 10, - name: "foo", - vector: [1, 2, 3] - }, - { - price: 50, - name: "bar", - vector: [4, 5, 6] - } - ]; - await con.createTable("t1", data); - await con.createTable("t2", data); - - assert.deepEqual(await con.tableNames(), ["t1", "t2"]); - - await con.dropTable("t1"); - assert.deepEqual(await con.tableNames(), ["t2"]); - }); -}); - -describe("WriteOptions", function () { - context("#isWriteOptions", function () { - it("should not match empty object", function () { - assert.equal(isWriteOptions({}), false); - }); - it("should match write options", function () { - assert.equal(isWriteOptions({ writeMode: WriteMode.Create }), true); - }); - it("should match undefined write mode", function () { - assert.equal(isWriteOptions({ writeMode: undefined }), true); - }); - it("should match default write options", function () { - assert.equal(isWriteOptions(new DefaultWriteOptions()), true); - }); - }); -}); - -describe("Compact and cleanup", function () { - it("can cleanup after compaction", async function () { - const dir = await track().mkdir("lancejs"); - const con = await lancedb.connect(dir); - - const data = [ - { - price: 10, - name: "foo", - vector: [1, 2, 3] - }, - { - price: 50, - name: "bar", - vector: [4, 5, 6] - } - ]; - const table = (await con.createTable("t1", data)) as LocalTable; - - const newData = [ - { - price: 30, - name: "baz", - vector: [7, 8, 9] - } - ]; - await table.add(newData); - - const compactionMetrics = await table.compactFiles({ - numThreads: 2 - }); - assert.equal(compactionMetrics.fragmentsRemoved, 2); - assert.equal(compactionMetrics.fragmentsAdded, 1); - assert.equal(await table.countRows(), 3); - - await table.cleanupOldVersions(); - assert.equal(await table.countRows(), 3); - - // should have no effect, but this validates the arguments are parsed. - await table.compactFiles({ - targetRowsPerFragment: 102410, - maxRowsPerGroup: 1024, - materializeDeletions: true, - materializeDeletionsThreshold: 0.5, - numThreads: 2 - }); - - const cleanupMetrics = await table.cleanupOldVersions(0, true); - assert.isAtLeast(cleanupMetrics.bytesRemoved, 1); - assert.isAtLeast(cleanupMetrics.oldVersions, 1); - assert.equal(await table.countRows(), 3); - }); -}); - -describe("schema evolution", function () { - // Create a new sample table - it("can add a new column to the schema", async function () { - const dir = await track().mkdir("lancejs"); - const con = await lancedb.connect(dir); - const table = await con.createTable("vectors", [ - { id: 1n, vector: [0.1, 0.2] } - ]); - - await table.addColumns([ - { name: "price", valueSql: "cast(10.0 as float)" } - ]); - - const expectedSchema = new Schema([ - new Field("id", new Int64()), - new Field( - "vector", - new FixedSizeList(2, new Field("item", new Float32(), true)) - ), - new Field("price", new Float32()) - ]); - expect(await table.schema).to.deep.equal(expectedSchema); - }); - - it("can alter the columns in the schema", async function () { - const dir = await track().mkdir("lancejs"); - const con = await lancedb.connect(dir); - const schema = new Schema([ - new Field("id", new Int64(), false), - new Field( - "vector", - new FixedSizeList(2, new Field("item", new Float32(), true)) - ), - new Field("price", new Float64(), false) - ]); - const table = await con.createTable("vectors", [ - { id: 1n, vector: [0.1, 0.2], price: 10.0 } - ]); - expect(await table.schema).to.deep.equal(schema); - - await table.alterColumns([ - { path: "id", rename: "new_id" }, - { path: "price", nullable: true } - ]); - - const expectedSchema = new Schema([ - new Field("new_id", new Int64(), false), - new Field( - "vector", - new FixedSizeList(2, new Field("item", new Float32(), true)) - ), - new Field("price", new Float64(), true) - ]); - expect(await table.schema).to.deep.equal(expectedSchema); - }); - - it("can drop a column from the schema", async function () { - const dir = await track().mkdir("lancejs"); - const con = await lancedb.connect(dir); - const table = await con.createTable("vectors", [ - { id: 1n, vector: [0.1, 0.2] } - ]); - await table.dropColumns(["vector"]); - - const expectedSchema = new Schema([new Field("id", new Int64(), false)]); - expect(await table.schema).to.deep.equal(expectedSchema); - }); -}); diff --git a/node/src/test/util.ts b/node/src/test/util.ts deleted file mode 100644 index 07e96e0b..00000000 --- a/node/src/test/util.ts +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2023 LanceDB Developers. -// -// 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. - -import { toSQL } from '../util' -import * as chai from 'chai' - -const expect = chai.expect - -describe('toSQL', function () { - it('should turn string to SQL expression', function () { - expect(toSQL('foo')).to.equal("'foo'") - }) - - it('should turn number to SQL expression', function () { - expect(toSQL(123)).to.equal('123') - }) - - it('should turn boolean to SQL expression', function () { - expect(toSQL(true)).to.equal('TRUE') - }) - - it('should turn null to SQL expression', function () { - expect(toSQL(null)).to.equal('NULL') - }) - - it('should turn Date to SQL expression', function () { - const date = new Date('05 October 2011 14:48 UTC') - expect(toSQL(date)).to.equal("'2011-10-05T14:48:00.000Z'") - }) - - it('should turn array to SQL expression', function () { - expect(toSQL(['foo', 'bar', true, 1])).to.equal("['foo', 'bar', TRUE, 1]") - }) -}) diff --git a/node/src/util.ts b/node/src/util.ts deleted file mode 100644 index a84fc29d..00000000 --- a/node/src/util.ts +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2023 LanceDB Developers. -// -// 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. - -export type Literal = string | number | boolean | null | Date | Literal[] - -export function toSQL (value: Literal): string { - if (typeof value === 'string') { - return `'${value}'` - } - - if (typeof value === 'number') { - return value.toString() - } - - if (typeof value === 'boolean') { - return value ? 'TRUE' : 'FALSE' - } - - if (value === null) { - return 'NULL' - } - - if (value instanceof Date) { - return `'${value.toISOString()}'` - } - - if (Array.isArray(value)) { - return `[${value.map(toSQL).join(', ')}]` - } - - // eslint-disable-next-line @typescript-eslint/restrict-template-expressions - throw new Error(`Unsupported value type: ${typeof value} value: (${value})`) -} - -export class TTLCache { - private readonly cache: Map - - /** - * @param ttl Time to live in milliseconds - */ - constructor (private readonly ttl: number) { - this.cache = new Map() - } - - get (key: string): any | undefined { - const entry = this.cache.get(key) - if (entry === undefined) { - return undefined - } - - if (entry.expires < Date.now()) { - this.cache.delete(key) - return undefined - } - - return entry.value - } - - set (key: string, value: any): void { - this.cache.set(key, { value, expires: Date.now() + this.ttl }) - } - - delete (key: string): void { - this.cache.delete(key) - } -} diff --git a/node/tsconfig.json b/node/tsconfig.json deleted file mode 100644 index dbfa506c..00000000 --- a/node/tsconfig.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "include": [ - "src/**/*.ts", - "src/*.ts" - ], - "compilerOptions": { - "target": "ES2020", - "module": "commonjs", - "declaration": true, - "outDir": "./dist", - "strict": true, - "sourceMap": true, - } -} \ No newline at end of file diff --git a/rust/ffi/node/Cargo.toml b/rust/ffi/node/Cargo.toml deleted file mode 100644 index b71a6339..00000000 --- a/rust/ffi/node/Cargo.toml +++ /dev/null @@ -1,42 +0,0 @@ -[package] -name = "lancedb-node" -version = "0.21.2" -description = "Serverless, low-latency vector database for AI applications" -license.workspace = true -edition.workspace = true -repository.workspace = true -keywords.workspace = true -categories.workspace = true -exclude = ["index.node"] -rust-version = "1.75" - -[lib] -crate-type = ["cdylib"] - -[dependencies] -arrow-array = { workspace = true } -arrow-ipc = { workspace = true } -arrow-schema = { workspace = true } -chrono = { workspace = true } -conv = "0.3.3" -once_cell = "1" -futures = "0.3" -half = { workspace = true } -lance = { workspace = true } -lance-index = { workspace = true } -lance-linalg = { workspace = true } -lancedb = { path = "../../lancedb" } -tokio = { version = "1.23", features = ["rt-multi-thread"] } -neon = { version = "0.10.1", default-features = false, features = [ - "channel-api", - "napi-6", - "promise-api", - "task-api", -] } -object_store = { workspace = true, features = ["aws"] } -snafu = { workspace = true } -async-trait = "0" -env_logger = "0" - -# Prevent dynamic linking of lzma, which comes from datafusion -lzma-sys = { version = "*", features = ["static"] } diff --git a/rust/ffi/node/README.md b/rust/ffi/node/README.md deleted file mode 100644 index 0b9493d6..00000000 --- a/rust/ffi/node/README.md +++ /dev/null @@ -1,3 +0,0 @@ -The LanceDB node bridge (lancedb-node) allows javascript applications to access LanceDB datasets. - -It is build using [Neon](https://neon-bindings.com). See the node project for an example of how it is used / tests diff --git a/rust/ffi/node/src/arrow.rs b/rust/ffi/node/src/arrow.rs deleted file mode 100644 index 8f509cf5..00000000 --- a/rust/ffi/node/src/arrow.rs +++ /dev/null @@ -1,37 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: Copyright The LanceDB Authors - -use std::io::Cursor; -use std::ops::Deref; - -use arrow_array::RecordBatch; -use arrow_ipc::reader::FileReader; -use arrow_ipc::writer::FileWriter; -use arrow_schema::SchemaRef; - -use crate::error::Result; - -pub fn arrow_buffer_to_record_batch(slice: &[u8]) -> Result<(Vec, SchemaRef)> { - let mut batches: Vec = Vec::new(); - let file_reader = FileReader::try_new(Cursor::new(slice), None)?; - let schema = file_reader.schema(); - for b in file_reader { - let record_batch = b?; - batches.push(record_batch); - } - Ok((batches, schema)) -} - -pub fn record_batch_to_buffer(batches: Vec) -> Result> { - if batches.is_empty() { - return Ok(Vec::new()); - } - - let schema = batches.first().unwrap().schema(); - let mut fr = FileWriter::try_new(Vec::new(), schema.deref())?; - for batch in batches.iter() { - fr.write(batch)? - } - fr.finish()?; - Ok(fr.into_inner()?) -} diff --git a/rust/ffi/node/src/convert.rs b/rust/ffi/node/src/convert.rs deleted file mode 100644 index e197b75b..00000000 --- a/rust/ffi/node/src/convert.rs +++ /dev/null @@ -1,42 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: Copyright The LanceDB Authors - -use neon::prelude::*; -use neon::types::buffer::TypedArray; - -use crate::error::ResultExt; - -pub fn vec_str_to_array<'a, C: Context<'a>>(vec: &[String], cx: &mut C) -> JsResult<'a, JsArray> { - let a = JsArray::new(cx, vec.len() as u32); - for (i, s) in vec.iter().enumerate() { - let v = cx.string(s); - a.set(cx, i as u32, v)?; - } - Ok(a) -} - -pub fn js_array_to_vec(array: &JsArray, cx: &mut FunctionContext) -> Vec { - let mut query_vec: Vec = Vec::new(); - for i in 0..array.len(cx) { - let entry: Handle = array.get(cx, i).unwrap(); - query_vec.push(entry.value(cx) as f32); - } - query_vec -} - -// Creates a new JsBuffer from a rust buffer with a special logic for electron -pub fn new_js_buffer<'a>( - buffer: Vec, - cx: &mut TaskContext<'a>, - is_electron: bool, -) -> NeonResult> { - if is_electron { - // Electron does not support `external`: https://github.com/neon-bindings/neon/pull/937 - let mut js_buffer = JsBuffer::new(cx, buffer.len()).or_throw(cx)?; - let buffer_data = js_buffer.as_mut_slice(cx); - buffer_data.copy_from_slice(buffer.as_slice()); - Ok(js_buffer) - } else { - Ok(JsBuffer::external(cx, buffer)) - } -} diff --git a/rust/ffi/node/src/error.rs b/rust/ffi/node/src/error.rs deleted file mode 100644 index bb02f570..00000000 --- a/rust/ffi/node/src/error.rs +++ /dev/null @@ -1,86 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: Copyright The LanceDB Authors - -use arrow_schema::ArrowError; -use neon::context::Context; -use neon::prelude::NeonResult; -use snafu::Snafu; - -#[derive(Debug, Snafu)] -pub enum Error { - #[allow(dead_code)] - #[snafu(display("column '{name}' is missing"))] - MissingColumn { name: String }, - #[snafu(display("{name}: {message}"))] - OutOfRange { name: String, message: String }, - #[allow(dead_code)] - #[snafu(display("{index_type} is not a valid index type"))] - InvalidIndexType { index_type: String }, - - #[snafu(display("{message}"))] - LanceDB { message: String }, - #[snafu(display("{message}"))] - Neon { message: String }, -} - -pub type Result = std::result::Result; - -impl From for Error { - fn from(e: lancedb::error::Error) -> Self { - Self::LanceDB { - message: e.to_string(), - } - } -} - -impl From for Error { - fn from(e: lance::Error) -> Self { - Self::LanceDB { - message: e.to_string(), - } - } -} - -impl From for Error { - fn from(value: ArrowError) -> Self { - Self::LanceDB { - message: value.to_string(), - } - } -} - -impl From for Error { - fn from(value: neon::result::Throw) -> Self { - Self::Neon { - message: value.to_string(), - } - } -} - -impl From> for Error { - fn from(value: std::sync::mpsc::SendError) -> Self { - Self::Neon { - message: value.to_string(), - } - } -} - -/// ResultExt is used to transform a [`Result`] into a [`NeonResult`], -/// so it can be returned as a JavaScript error -/// Copied from [Neon](https://github.com/neon-bindings/neon/blob/4c2e455a9e6814f1ba0178616d63caec7f4df317/crates/neon/src/result/mod.rs#L88) -pub trait ResultExt { - fn or_throw<'a, C: Context<'a>>(self, cx: &mut C) -> NeonResult; -} - -/// Implement ResultExt for the std Result so it can be used any Result type -impl ResultExt for std::result::Result -where - E: std::fmt::Display, -{ - fn or_throw<'a, C: Context<'a>>(self, cx: &mut C) -> NeonResult { - match self { - Ok(value) => Ok(value), - Err(error) => cx.throw_error(error.to_string()), - } - } -} diff --git a/rust/ffi/node/src/index.rs b/rust/ffi/node/src/index.rs deleted file mode 100644 index 103613e9..00000000 --- a/rust/ffi/node/src/index.rs +++ /dev/null @@ -1,5 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: Copyright The LanceDB Authors - -pub mod scalar; -pub mod vector; diff --git a/rust/ffi/node/src/index/scalar.rs b/rust/ffi/node/src/index/scalar.rs deleted file mode 100644 index a8c25901..00000000 --- a/rust/ffi/node/src/index/scalar.rs +++ /dev/null @@ -1,37 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: Copyright The LanceDB Authors - -use lancedb::index::{scalar::BTreeIndexBuilder, Index}; -use neon::{ - context::{Context, FunctionContext}, - result::JsResult, - types::{JsBoolean, JsBox, JsPromise, JsString}, -}; - -use crate::{error::ResultExt, runtime, table::JsTable}; - -pub fn table_create_scalar_index(mut cx: FunctionContext) -> JsResult { - let js_table = cx.this().downcast_or_throw::, _>(&mut cx)?; - let column = cx.argument::(0)?.value(&mut cx); - let replace = cx.argument::(1)?.value(&mut cx); - - let rt = runtime(&mut cx)?; - - let (deferred, promise) = cx.promise(); - let channel = cx.channel(); - let table = js_table.table.clone(); - - rt.spawn(async move { - let idx_result = table - .create_index(&[column], Index::BTree(BTreeIndexBuilder::default())) - .replace(replace) - .execute() - .await; - - deferred.settle_with(&channel, move |mut cx| { - idx_result.or_throw(&mut cx)?; - Ok(cx.undefined()) - }); - }); - Ok(promise) -} diff --git a/rust/ffi/node/src/index/vector.rs b/rust/ffi/node/src/index/vector.rs deleted file mode 100644 index 8a875126..00000000 --- a/rust/ffi/node/src/index/vector.rs +++ /dev/null @@ -1,77 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: Copyright The LanceDB Authors - -use lancedb::index::vector::IvfPqIndexBuilder; -use lancedb::index::Index; -use lancedb::DistanceType; -use neon::context::FunctionContext; -use neon::prelude::*; -use std::convert::TryFrom; - -use crate::error::ResultExt; -use crate::neon_ext::js_object_ext::JsObjectExt; -use crate::runtime; -use crate::table::JsTable; - -pub fn table_create_vector_index(mut cx: FunctionContext) -> JsResult { - let js_table = cx.this().downcast_or_throw::, _>(&mut cx)?; - let index_params = cx.argument::(0)?; - - let rt = runtime(&mut cx)?; - - let (deferred, promise) = cx.promise(); - let channel = cx.channel(); - let table = js_table.table.clone(); - - let column_name = index_params - .get_opt::(&mut cx, "column")? - .map(|s| s.value(&mut cx)) - .unwrap_or("vector".to_string()); // Backward compatibility - - let replace = index_params - .get_opt::(&mut cx, "replace")? - .map(|r| r.value(&mut cx)); - - let tbl = table.clone(); - let ivf_pq_builder = get_index_params_builder(&mut cx, index_params).or_throw(&mut cx)?; - - let mut index_builder = tbl.create_index(&[column_name], Index::IvfPq(ivf_pq_builder)); - if let Some(replace) = replace { - index_builder = index_builder.replace(replace); - } - - rt.spawn(async move { - let idx_result = index_builder.execute().await; - deferred.settle_with(&channel, move |mut cx| { - idx_result.or_throw(&mut cx)?; - Ok(cx.boxed(JsTable::from(table))) - }); - }); - Ok(promise) -} - -fn get_index_params_builder( - cx: &mut FunctionContext, - obj: Handle, -) -> crate::error::Result { - if obj.get_opt::(cx, "index_name")?.is_some() { - return Err(crate::error::Error::LanceDB { - message: "Setting the index_name is no longer supported".to_string(), - }); - } - let mut builder = IvfPqIndexBuilder::default(); - if let Some(metric_type) = obj.get_opt::(cx, "metric_type")? { - let distance_type = DistanceType::try_from(metric_type.value(cx).as_str())?; - builder = builder.distance_type(distance_type); - } - if let Some(np) = obj.get_opt_u32(cx, "num_partitions")? { - builder = builder.num_partitions(np); - } - if let Some(ns) = obj.get_opt_u32(cx, "num_sub_vectors")? { - builder = builder.num_sub_vectors(ns); - } - if let Some(max_iters) = obj.get_opt_u32(cx, "max_iters")? { - builder = builder.max_iterations(max_iters); - } - Ok(builder) -} diff --git a/rust/ffi/node/src/lib.rs b/rust/ffi/node/src/lib.rs deleted file mode 100644 index 229a4cea..00000000 --- a/rust/ffi/node/src/lib.rs +++ /dev/null @@ -1,174 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: Copyright The LanceDB Authors - -use neon::prelude::*; -use once_cell::sync::OnceCell; -use tokio::runtime::Runtime; - -use lancedb::connect; -use lancedb::connection::Connection; - -use crate::error::ResultExt; -use crate::query::JsQuery; -use crate::table::JsTable; - -mod arrow; -mod convert; -mod error; -mod index; -mod neon_ext; -mod query; -mod table; - -struct JsDatabase { - database: Connection, -} - -impl Finalize for JsDatabase {} - -fn runtime<'a, C: Context<'a>>(cx: &mut C) -> NeonResult<&'static Runtime> { - static RUNTIME: OnceCell = OnceCell::new(); - static LOG: OnceCell<()> = OnceCell::new(); - - LOG.get_or_init(env_logger::init); - - RUNTIME.get_or_try_init(|| Runtime::new().or_throw(cx)) -} - -fn database_new(mut cx: FunctionContext) -> JsResult { - let path = cx.argument::(0)?.value(&mut cx); - let read_consistency_interval = cx - .argument_opt(2) - .and_then(|arg| arg.downcast::(&mut cx).ok()) - .map(|v| v.value(&mut cx)) - .map(std::time::Duration::from_secs_f64); - - let storage_options_js = cx.argument::(1)?.to_vec(&mut cx)?; - let mut storage_options: Vec<(String, String)> = Vec::with_capacity(storage_options_js.len()); - for handle in storage_options_js { - let obj = handle.downcast::(&mut cx).unwrap(); - let key = obj.get::(&mut cx, 0)?.value(&mut cx); - let value = obj.get::(&mut cx, 1)?.value(&mut cx); - - storage_options.push((key, value)); - } - - let rt = runtime(&mut cx)?; - let channel = cx.channel(); - let (deferred, promise) = cx.promise(); - - let mut conn_builder = connect(&path).storage_options(storage_options); - - if let Some(interval) = read_consistency_interval { - conn_builder = conn_builder.read_consistency_interval(interval); - } - rt.spawn(async move { - let database = conn_builder.execute().await; - - deferred.settle_with(&channel, move |mut cx| { - let db = JsDatabase { - database: database.or_throw(&mut cx)?, - }; - Ok(cx.boxed(db)) - }); - }); - Ok(promise) -} - -fn database_table_names(mut cx: FunctionContext) -> JsResult { - let db = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - - let rt = runtime(&mut cx)?; - let (deferred, promise) = cx.promise(); - let channel = cx.channel(); - let database = db.database.clone(); - - rt.spawn(async move { - let tables_rst = database.table_names().execute().await; - - deferred.settle_with(&channel, move |mut cx| { - let tables = tables_rst.or_throw(&mut cx)?; - let table_names = convert::vec_str_to_array(&tables, &mut cx); - table_names - }); - }); - Ok(promise) -} - -fn database_open_table(mut cx: FunctionContext) -> JsResult { - let db = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - let table_name = cx.argument::(0)?.value(&mut cx); - - let rt = runtime(&mut cx)?; - let channel = cx.channel(); - let database = db.database.clone(); - - let (deferred, promise) = cx.promise(); - rt.spawn(async move { - let table_rst = database.open_table(&table_name).execute().await; - - deferred.settle_with(&channel, move |mut cx| { - let js_table = JsTable::from(table_rst.or_throw(&mut cx)?); - Ok(cx.boxed(js_table)) - }); - }); - Ok(promise) -} - -fn database_drop_table(mut cx: FunctionContext) -> JsResult { - let db = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - let table_name = cx.argument::(0)?.value(&mut cx); - - let rt = runtime(&mut cx)?; - let channel = cx.channel(); - let database = db.database.clone(); - - let (deferred, promise) = cx.promise(); - rt.spawn(async move { - let result = database.drop_table(&table_name).await; - deferred.settle_with(&channel, move |mut cx| { - result.or_throw(&mut cx)?; - Ok(cx.null()) - }); - }); - Ok(promise) -} - -#[neon::main] -fn main(mut cx: ModuleContext) -> NeonResult<()> { - cx.export_function("databaseNew", database_new)?; - cx.export_function("databaseTableNames", database_table_names)?; - cx.export_function("databaseOpenTable", database_open_table)?; - cx.export_function("databaseDropTable", database_drop_table)?; - cx.export_function("tableSearch", JsQuery::js_search)?; - cx.export_function("tableCreate", JsTable::js_create)?; - cx.export_function("tableAdd", JsTable::js_add)?; - cx.export_function("tableCountRows", JsTable::js_count_rows)?; - cx.export_function("tableDelete", JsTable::js_delete)?; - cx.export_function("tableUpdate", JsTable::js_update)?; - cx.export_function("tableMergeInsert", JsTable::js_merge_insert)?; - cx.export_function("tableCleanupOldVersions", JsTable::js_cleanup)?; - cx.export_function("tableCompactFiles", JsTable::js_compact)?; - cx.export_function("tableListIndices", JsTable::js_list_indices)?; - cx.export_function("tableIndexStats", JsTable::js_index_stats)?; - cx.export_function( - "tableCreateScalarIndex", - index::scalar::table_create_scalar_index, - )?; - cx.export_function( - "tableCreateVectorIndex", - index::vector::table_create_vector_index, - )?; - cx.export_function("tableSchema", JsTable::js_schema)?; - cx.export_function("tableAddColumns", JsTable::js_add_columns)?; - cx.export_function("tableAlterColumns", JsTable::js_alter_columns)?; - cx.export_function("tableDropColumns", JsTable::js_drop_columns)?; - cx.export_function("tableDropIndex", JsTable::js_drop_index)?; - Ok(()) -} diff --git a/rust/ffi/node/src/neon_ext.rs b/rust/ffi/node/src/neon_ext.rs deleted file mode 100644 index 6f07dce6..00000000 --- a/rust/ffi/node/src/neon_ext.rs +++ /dev/null @@ -1,4 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: Copyright The LanceDB Authors - -pub mod js_object_ext; diff --git a/rust/ffi/node/src/neon_ext/js_object_ext.rs b/rust/ffi/node/src/neon_ext/js_object_ext.rs deleted file mode 100644 index 868a6661..00000000 --- a/rust/ffi/node/src/neon_ext/js_object_ext.rs +++ /dev/null @@ -1,72 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: Copyright The LanceDB Authors - -use crate::error::{Error, Result}; -use neon::prelude::*; - -// extends neon's [JsObject] with helper functions to extract properties -pub trait JsObjectExt { - fn get_opt_u32(&self, cx: &mut FunctionContext, key: &str) -> Result>; - fn get_usize(&self, cx: &mut FunctionContext, key: &str) -> Result; - #[allow(dead_code)] - fn get_opt_usize(&self, cx: &mut FunctionContext, key: &str) -> Result>; -} - -impl JsObjectExt for JsObject { - fn get_opt_u32(&self, cx: &mut FunctionContext, key: &str) -> Result> { - let val_opt = self - .get_opt::(cx, key)? - .map(|s| f64_to_u32_safe(s.value(cx), key)); - val_opt.transpose() - } - - fn get_usize(&self, cx: &mut FunctionContext, key: &str) -> Result { - let val = self.get::(cx, key)?.value(cx); - f64_to_usize_safe(val, key) - } - - fn get_opt_usize(&self, cx: &mut FunctionContext, key: &str) -> Result> { - let val_opt = self - .get_opt::(cx, key)? - .map(|s| f64_to_usize_safe(s.value(cx), key)); - val_opt.transpose() - } -} - -fn f64_to_u32_safe(n: f64, key: &str) -> Result { - use conv::*; - - n.approx_as::().map_err(|e| match e { - FloatError::NegOverflow(_) => Error::OutOfRange { - name: key.into(), - message: "must be > 0".to_string(), - }, - FloatError::PosOverflow(_) => Error::OutOfRange { - name: key.into(), - message: format!("must be < {}", u32::MAX), - }, - FloatError::NotANumber(_) => Error::OutOfRange { - name: key.into(), - message: "not a valid number".to_string(), - }, - }) -} - -fn f64_to_usize_safe(n: f64, key: &str) -> Result { - use conv::*; - - n.approx_as::().map_err(|e| match e { - FloatError::NegOverflow(_) => Error::OutOfRange { - name: key.into(), - message: "must be > 0".to_string(), - }, - FloatError::PosOverflow(_) => Error::OutOfRange { - name: key.into(), - message: format!("must be < {}", usize::MAX), - }, - FloatError::NotANumber(_) => Error::OutOfRange { - name: key.into(), - message: "not a valid number".to_string(), - }, - }) -} diff --git a/rust/ffi/node/src/query.rs b/rust/ffi/node/src/query.rs deleted file mode 100644 index 1ada244b..00000000 --- a/rust/ffi/node/src/query.rs +++ /dev/null @@ -1,138 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: Copyright The LanceDB Authors - -use std::convert::TryFrom; -use std::ops::Deref; - -use futures::{TryFutureExt, TryStreamExt}; -use lancedb::query::{ExecutableQuery, QueryBase, Select}; -use lancedb::DistanceType; -use neon::context::FunctionContext; -use neon::handle::Handle; -use neon::prelude::*; - -use crate::arrow::record_batch_to_buffer; -use crate::error::ResultExt; -use crate::neon_ext::js_object_ext::JsObjectExt; -use crate::table::JsTable; -use crate::{convert, runtime}; - -pub struct JsQuery {} - -impl JsQuery { - pub(crate) fn js_search(mut cx: FunctionContext) -> JsResult { - let js_table = cx.this().downcast_or_throw::, _>(&mut cx)?; - let query_obj = cx.argument::(0)?; - - let limit = query_obj - .get_opt::(&mut cx, "_limit")? - .map(|value| { - let limit = value.value(&mut cx); - if limit <= 0.0 { - panic!("Limit must be a positive integer"); - } - limit as u64 - }); - let select = query_obj - .get_opt::(&mut cx, "_select")? - .map(|arr| { - let js_array = arr.deref(); - let mut projection_vec: Vec = Vec::new(); - for i in 0..js_array.len(&mut cx) { - let entry: Handle = js_array.get(&mut cx, i).unwrap(); - projection_vec.push(entry.value(&mut cx)); - } - projection_vec - }); - - let prefilter = query_obj - .get::(&mut cx, "_prefilter")? - .value(&mut cx); - - let fast_search = query_obj - .get_opt::(&mut cx, "_fastSearch")? - .map(|val| val.value(&mut cx)); - - let is_electron = cx - .argument::(1) - .or_throw(&mut cx)? - .value(&mut cx); - - let rt = runtime(&mut cx)?; - - let (deferred, promise) = cx.promise(); - let channel = cx.channel(); - let table = js_table.table.clone(); - - let mut builder = table.query(); - if let Some(filter) = query_obj - .get_opt::(&mut cx, "_filter")? - .map(|s| s.value(&mut cx)) - { - builder = builder.only_if(filter); - } - if let Some(select) = select { - builder = builder.select(Select::columns(select.as_slice())); - } - if let Some(limit) = limit { - builder = builder.limit(limit as usize); - }; - if let Some(true) = fast_search { - builder = builder.fast_search(); - } - - let query_vector = query_obj.get_opt::(&mut cx, "_queryVector")?; - if let Some(query) = query_vector.map(|q| convert::js_array_to_vec(q.deref(), &mut cx)) { - let mut vector_builder = builder.nearest_to(query).unwrap(); - if let Some(distance_type) = query_obj - .get_opt::(&mut cx, "_metricType")? - .map(|s| s.value(&mut cx)) - .map(|s| DistanceType::try_from(s.as_str()).unwrap()) - { - vector_builder = vector_builder.distance_type(distance_type); - } - - let nprobes = query_obj.get_usize(&mut cx, "_nprobes").or_throw(&mut cx)?; - vector_builder = vector_builder.nprobes(nprobes); - - if !prefilter { - vector_builder = vector_builder.postfilter(); - } - rt.spawn(async move { - let results = vector_builder - .execute() - .and_then(|stream| { - stream - .try_collect::>() - .map_err(lancedb::error::Error::from) - }) - .await; - - deferred.settle_with(&channel, move |mut cx| { - let results = results.or_throw(&mut cx)?; - let buffer = record_batch_to_buffer(results).or_throw(&mut cx)?; - convert::new_js_buffer(buffer, &mut cx, is_electron) - }); - }); - } else { - rt.spawn(async move { - let results = builder - .execute() - .and_then(|stream| { - stream - .try_collect::>() - .map_err(lancedb::error::Error::from) - }) - .await; - - deferred.settle_with(&channel, move |mut cx| { - let results = results.or_throw(&mut cx)?; - let buffer = record_batch_to_buffer(results).or_throw(&mut cx)?; - convert::new_js_buffer(buffer, &mut cx, is_electron) - }); - }); - }; - - Ok(promise) - } -} diff --git a/rust/ffi/node/src/table.rs b/rust/ffi/node/src/table.rs deleted file mode 100644 index a2e16ed7..00000000 --- a/rust/ffi/node/src/table.rs +++ /dev/null @@ -1,645 +0,0 @@ -// SPDX-License-Identifier: Apache-2.0 -// SPDX-FileCopyrightText: Copyright The LanceDB Authors - -use std::ops::Deref; - -use arrow_array::{RecordBatch, RecordBatchIterator}; -use lance::dataset::optimize::CompactionOptions; -use lance::dataset::{ColumnAlteration, NewColumnTransform, WriteMode, WriteParams}; -use lancedb::table::{OptimizeAction, WriteOptions}; - -use crate::arrow::{arrow_buffer_to_record_batch, record_batch_to_buffer}; -use lancedb::table::Table as LanceDbTable; -use neon::prelude::*; -use neon::types::buffer::TypedArray; - -use crate::error::ResultExt; -use crate::{convert, runtime, JsDatabase}; - -pub struct JsTable { - pub table: LanceDbTable, -} - -impl Finalize for JsTable {} - -impl From for JsTable { - fn from(table: LanceDbTable) -> Self { - Self { table } - } -} - -impl JsTable { - pub(crate) fn js_create(mut cx: FunctionContext) -> JsResult { - let db = cx - .this() - .downcast_or_throw::, _>(&mut cx)?; - let table_name = cx.argument::(0)?.value(&mut cx); - let buffer = cx.argument::(1)?; - let (batches, schema) = - arrow_buffer_to_record_batch(buffer.as_slice(&cx)).or_throw(&mut cx)?; - - // Write mode - let mode = match cx.argument::(2)?.value(&mut cx).as_str() { - "overwrite" => WriteMode::Overwrite, - "append" => WriteMode::Append, - "create" => WriteMode::Create, - _ => { - return cx.throw_error("Table::create only supports 'overwrite' and 'create' modes") - } - }; - let params = WriteParams { - mode, - ..WriteParams::default() - }; - - let rt = runtime(&mut cx)?; - let channel = cx.channel(); - - let (deferred, promise) = cx.promise(); - let database = db.database.clone(); - - rt.spawn(async move { - let batch_reader = RecordBatchIterator::new(batches.into_iter().map(Ok), schema); - let table_rst = database - .create_table(&table_name, batch_reader) - .write_options(WriteOptions { - lance_write_params: Some(params), - }) - .execute() - .await; - - deferred.settle_with(&channel, move |mut cx| { - let table = table_rst.or_throw(&mut cx)?; - Ok(cx.boxed(Self::from(table))) - }); - }); - Ok(promise) - } - - pub(crate) fn js_add(mut cx: FunctionContext) -> JsResult { - let js_table = cx.this().downcast_or_throw::, _>(&mut cx)?; - let buffer = cx.argument::(0)?; - let write_mode = cx.argument::(1)?.value(&mut cx); - let (batches, schema) = - arrow_buffer_to_record_batch(buffer.as_slice(&cx)).or_throw(&mut cx)?; - let rt = runtime(&mut cx)?; - let channel = cx.channel(); - let table = js_table.table.clone(); - - let (deferred, promise) = cx.promise(); - let write_mode = match write_mode.as_str() { - "create" => WriteMode::Create, - "append" => WriteMode::Append, - "overwrite" => WriteMode::Overwrite, - s => return cx.throw_error(format!("invalid write mode {}", s)), - }; - - let params = WriteParams { - mode: write_mode, - ..WriteParams::default() - }; - - rt.spawn(async move { - let batch_reader = RecordBatchIterator::new(batches.into_iter().map(Ok), schema); - let add_result = table - .add(batch_reader) - .write_options(WriteOptions { - lance_write_params: Some(params), - }) - .execute() - .await; - - deferred.settle_with(&channel, move |mut cx| { - add_result.or_throw(&mut cx)?; - Ok(cx.boxed(Self::from(table))) - }); - }); - Ok(promise) - } - - pub(crate) fn js_count_rows(mut cx: FunctionContext) -> JsResult { - let js_table = cx.this().downcast_or_throw::, _>(&mut cx)?; - let filter = cx - .argument_opt(0) - .and_then(|filt| { - if filt.is_a::(&mut cx) || filt.is_a::(&mut cx) { - None - } else { - Some( - filt.downcast_or_throw::(&mut cx) - .map(|js_filt| js_filt.deref().value(&mut cx)), - ) - } - }) - .transpose()?; - let rt = runtime(&mut cx)?; - let (deferred, promise) = cx.promise(); - let channel = cx.channel(); - let table = js_table.table.clone(); - - rt.spawn(async move { - let num_rows_result = table.count_rows(filter).await; - - deferred.settle_with(&channel, move |mut cx| { - let num_rows = num_rows_result.or_throw(&mut cx)?; - Ok(cx.number(num_rows as f64)) - }); - }); - Ok(promise) - } - - pub(crate) fn js_delete(mut cx: FunctionContext) -> JsResult { - let js_table = cx.this().downcast_or_throw::, _>(&mut cx)?; - let rt = runtime(&mut cx)?; - let (deferred, promise) = cx.promise(); - let predicate = cx.argument::(0)?.value(&mut cx); - let channel = cx.channel(); - let table = js_table.table.clone(); - - rt.spawn(async move { - let delete_result = table.delete(&predicate).await; - - deferred.settle_with(&channel, move |mut cx| { - delete_result.or_throw(&mut cx)?; - Ok(cx.boxed(Self::from(table))) - }) - }); - Ok(promise) - } - - pub(crate) fn js_merge_insert(mut cx: FunctionContext) -> JsResult { - let js_table = cx.this().downcast_or_throw::, _>(&mut cx)?; - let rt = runtime(&mut cx)?; - let (deferred, promise) = cx.promise(); - let channel = cx.channel(); - let table = js_table.table.clone(); - - let key = cx.argument::(0)?.value(&mut cx); - let mut builder = table.merge_insert(&[&key]); - if cx.argument::(1)?.value(&mut cx) { - let filter = cx.argument_opt(2).unwrap(); - if filter.is_a::(&mut cx) { - builder.when_matched_update_all(None); - } else { - let filter = filter - .downcast_or_throw::(&mut cx)? - .deref() - .value(&mut cx); - builder.when_matched_update_all(Some(filter)); - } - } - if cx.argument::(3)?.value(&mut cx) { - builder.when_not_matched_insert_all(); - } - if cx.argument::(4)?.value(&mut cx) { - let filter = cx.argument_opt(5).unwrap(); - if filter.is_a::(&mut cx) { - builder.when_not_matched_by_source_delete(None); - } else { - let filter = filter - .downcast_or_throw::(&mut cx)? - .deref() - .value(&mut cx); - builder.when_not_matched_by_source_delete(Some(filter)); - } - } - - let buffer = cx.argument::(6)?; - let (batches, schema) = - arrow_buffer_to_record_batch(buffer.as_slice(&cx)).or_throw(&mut cx)?; - - rt.spawn(async move { - let new_data = RecordBatchIterator::new(batches.into_iter().map(Ok), schema); - let merge_insert_result = builder.execute(Box::new(new_data)).await; - - deferred.settle_with(&channel, move |mut cx| { - merge_insert_result.or_throw(&mut cx)?; - Ok(cx.boxed(Self::from(table))) - }) - }); - Ok(promise) - } - - pub(crate) fn js_update(mut cx: FunctionContext) -> JsResult { - let js_table = cx.this().downcast_or_throw::, _>(&mut cx)?; - let table = js_table.table.clone(); - - let rt = runtime(&mut cx)?; - let (deferred, promise) = cx.promise(); - let channel = cx.channel(); - - // create a vector of updates from the passed map - let updates_arg = cx.argument::(1)?; - let properties = updates_arg.get_own_property_names(&mut cx)?; - let mut updates: Vec<(String, String)> = - Vec::with_capacity(properties.len(&mut cx) as usize); - - let len_properties = properties.len(&mut cx); - for i in 0..len_properties { - let property = properties - .get_value(&mut cx, i)? - .downcast_or_throw::(&mut cx)?; - - let value = updates_arg - .get_value(&mut cx, property)? - .downcast_or_throw::(&mut cx)?; - - let property = property.value(&mut cx); - let value = value.value(&mut cx); - updates.push((property, value)); - } - - // get the filter/predicate if the user passed one - let predicate = cx.argument_opt(0); - let predicate = predicate.unwrap().downcast::(&mut cx); - let predicate = match predicate { - Ok(_) => { - let val = predicate.map(|s| s.value(&mut cx)).unwrap(); - Some(val) - } - Err(_) => { - // if the predicate is not string, check it's null otherwise an invalid - // type was passed - cx.argument::(0)?; - None - } - }; - - rt.spawn(async move { - let updates_arg = updates - .iter() - .map(|(k, v)| (k.as_str(), v.as_str())) - .collect::>(); - - let predicate = predicate.as_deref(); - - let mut update_op = table.update(); - if let Some(predicate) = predicate { - update_op = update_op.only_if(predicate); - } - for (column, value) in updates_arg { - update_op = update_op.column(column, value); - } - let update_result = update_op.execute().await; - deferred.settle_with(&channel, move |mut cx| { - update_result.or_throw(&mut cx)?; - Ok(cx.boxed(Self::from(table))) - }) - }); - - Ok(promise) - } - - pub(crate) fn js_cleanup(mut cx: FunctionContext) -> JsResult { - let js_table = cx.this().downcast_or_throw::, _>(&mut cx)?; - let rt = runtime(&mut cx)?; - let (deferred, promise) = cx.promise(); - let table = js_table.table.clone(); - let channel = cx.channel(); - - let older_than: i64 = cx - .argument_opt(0) - .and_then(|val| val.downcast::(&mut cx).ok()) - .map(|val| val.value(&mut cx) as i64) - .unwrap_or_else(|| 2 * 7 * 24 * 60); // 2 weeks - let older_than = chrono::Duration::try_minutes(older_than).unwrap(); - let delete_unverified: Option = Some( - cx.argument_opt(1) - .and_then(|val| val.downcast::(&mut cx).ok()) - .map(|val| val.value(&mut cx)) - .unwrap_or_default(), - ); - let error_if_tagged_old_versions: Option = Some( - cx.argument_opt(2) - .and_then(|val| val.downcast::(&mut cx).ok()) - .map(|val| val.value(&mut cx)) - .unwrap_or_default(), - ); - - rt.spawn(async move { - let stats = table - .optimize(OptimizeAction::Prune { - older_than: Some(older_than), - delete_unverified, - error_if_tagged_old_versions, - }) - .await; - - deferred.settle_with(&channel, move |mut cx| { - let stats = stats.or_throw(&mut cx)?; - - let prune_stats = stats.prune.as_ref().expect("Prune stats missing"); - let output_metrics = JsObject::new(&mut cx); - let bytes_removed = cx.number(prune_stats.bytes_removed as f64); - output_metrics.set(&mut cx, "bytesRemoved", bytes_removed)?; - - let old_versions = cx.number(prune_stats.old_versions as f64); - output_metrics.set(&mut cx, "oldVersions", old_versions)?; - - let output_table = cx.boxed(Self::from(table)); - - let output = JsObject::new(&mut cx); - output.set(&mut cx, "metrics", output_metrics)?; - output.set(&mut cx, "newTable", output_table)?; - - Ok(output) - }) - }); - Ok(promise) - } - - pub(crate) fn js_compact(mut cx: FunctionContext) -> JsResult { - let js_table = cx.this().downcast_or_throw::, _>(&mut cx)?; - let rt = runtime(&mut cx)?; - let (deferred, promise) = cx.promise(); - let table = js_table.table.clone(); - let channel = cx.channel(); - - let js_options = cx.argument::(0)?; - let mut options = CompactionOptions::default(); - - if let Some(target_rows) = - js_options.get_opt::(&mut cx, "targetRowsPerFragment")? - { - options.target_rows_per_fragment = target_rows.value(&mut cx) as usize; - } - if let Some(max_per_group) = - js_options.get_opt::(&mut cx, "maxRowsPerGroup")? - { - options.max_rows_per_group = max_per_group.value(&mut cx) as usize; - } - if let Some(materialize_deletions) = - js_options.get_opt::(&mut cx, "materializeDeletions")? - { - options.materialize_deletions = materialize_deletions.value(&mut cx); - } - if let Some(materialize_deletions_threshold) = - js_options.get_opt::(&mut cx, "materializeDeletionsThreshold")? - { - options.materialize_deletions_threshold = - materialize_deletions_threshold.value(&mut cx) as f32; - } - if let Some(num_threads) = js_options.get_opt::(&mut cx, "numThreads")? { - options.num_threads = Some(num_threads.value(&mut cx) as usize); - } - - rt.spawn(async move { - let stats = table - .optimize(OptimizeAction::Compact { - options, - remap_options: None, - }) - .await; - - deferred.settle_with(&channel, move |mut cx| { - let stats = stats.or_throw(&mut cx)?; - let stats = stats.compaction.as_ref().expect("Compact stats missing"); - - let output_metrics = JsObject::new(&mut cx); - let fragments_removed = cx.number(stats.fragments_removed as f64); - output_metrics.set(&mut cx, "fragmentsRemoved", fragments_removed)?; - - let fragments_added = cx.number(stats.fragments_added as f64); - output_metrics.set(&mut cx, "fragmentsAdded", fragments_added)?; - - let files_removed = cx.number(stats.files_removed as f64); - output_metrics.set(&mut cx, "filesRemoved", files_removed)?; - - let files_added = cx.number(stats.files_added as f64); - output_metrics.set(&mut cx, "filesAdded", files_added)?; - - let output_table = cx.boxed(Self::from(table)); - - let output = JsObject::new(&mut cx); - output.set(&mut cx, "metrics", output_metrics)?; - output.set(&mut cx, "newTable", output_table)?; - - Ok(output) - }) - }); - Ok(promise) - } - - pub(crate) fn js_list_indices(mut cx: FunctionContext) -> JsResult { - let js_table = cx.this().downcast_or_throw::, _>(&mut cx)?; - let rt = runtime(&mut cx)?; - let (deferred, promise) = cx.promise(); - // let predicate = cx.argument::(0)?.value(&mut cx); - let channel = cx.channel(); - let table = js_table.table.clone(); - - rt.spawn(async move { - let indices = table.as_native().unwrap().load_indices().await; - - deferred.settle_with(&channel, move |mut cx| { - let indices = indices.or_throw(&mut cx)?; - - let output = JsArray::new(&mut cx, indices.len() as u32); - for (i, index) in indices.iter().enumerate() { - let js_index = JsObject::new(&mut cx); - let index_name = cx.string(index.index_name.clone()); - js_index.set(&mut cx, "name", index_name)?; - - let index_uuid = cx.string(index.index_uuid.clone()); - js_index.set(&mut cx, "uuid", index_uuid)?; - - let js_index_columns = JsArray::new(&mut cx, index.columns.len() as u32); - for (j, column) in index.columns.iter().enumerate() { - let js_column = cx.string(column.clone()); - js_index_columns.set(&mut cx, j as u32, js_column)?; - } - js_index.set(&mut cx, "columns", js_index_columns)?; - - output.set(&mut cx, i as u32, js_index)?; - } - - Ok(output) - }) - }); - Ok(promise) - } - - pub(crate) fn js_index_stats(mut cx: FunctionContext) -> JsResult { - let js_table = cx.this().downcast_or_throw::, _>(&mut cx)?; - let rt = runtime(&mut cx)?; - let (deferred, promise) = cx.promise(); - let index_name = cx.argument::(0)?.value(&mut cx); - let channel = cx.channel(); - let table = js_table.table.clone(); - - rt.spawn(async move { - let load_stats = table.index_stats(index_name).await; - - deferred.settle_with(&channel, move |mut cx| { - let stats = load_stats.or_throw(&mut cx)?; - - if let Some(stats) = stats { - let output = JsObject::new(&mut cx); - let num_indexed_rows = cx.number(stats.num_indexed_rows as f64); - output.set(&mut cx, "numIndexedRows", num_indexed_rows)?; - let num_unindexed_rows = cx.number(stats.num_unindexed_rows as f64); - output.set(&mut cx, "numUnindexedRows", num_unindexed_rows)?; - if let Some(distance_type) = stats.distance_type { - let distance_type = cx.string(distance_type.to_string()); - output.set(&mut cx, "distanceType", distance_type)?; - } - let index_type = cx.string(stats.index_type.to_string()); - output.set(&mut cx, "indexType", index_type)?; - - if let Some(num_indices) = stats.num_indices { - let num_indices = cx.number(num_indices as f64); - output.set(&mut cx, "numIndices", num_indices)?; - } - - Ok(output.as_value(&mut cx)) - } else { - Ok(JsNull::new(&mut cx).as_value(&mut cx)) - } - }) - }); - - Ok(promise) - } - - pub(crate) fn js_schema(mut cx: FunctionContext) -> JsResult { - let js_table = cx.this().downcast_or_throw::, _>(&mut cx)?; - let rt = runtime(&mut cx)?; - let (deferred, promise) = cx.promise(); - let channel = cx.channel(); - let table = js_table.table.clone(); - - let is_electron = cx - .argument::(0) - .or_throw(&mut cx)? - .value(&mut cx); - - rt.spawn(async move { - let schema = table.schema().await; - deferred.settle_with(&channel, move |mut cx| { - let schema = schema.or_throw(&mut cx)?; - let batches = vec![RecordBatch::new_empty(schema)]; - let buffer = record_batch_to_buffer(batches).or_throw(&mut cx)?; - convert::new_js_buffer(buffer, &mut cx, is_electron) - }) - }); - Ok(promise) - } - - pub(crate) fn js_add_columns(mut cx: FunctionContext) -> JsResult { - let expressions = cx - .argument::(0)? - .to_vec(&mut cx)? - .into_iter() - .map(|val| { - let obj = val.downcast_or_throw::(&mut cx)?; - let name = obj.get::(&mut cx, "name")?.value(&mut cx); - let sql = obj - .get::(&mut cx, "valueSql")? - .value(&mut cx); - Ok((name, sql)) - }) - .collect::>>()?; - - let transforms = NewColumnTransform::SqlExpressions(expressions); - - let js_table = cx.this().downcast_or_throw::, _>(&mut cx)?; - let rt = runtime(&mut cx)?; - - let (deferred, promise) = cx.promise(); - let channel = cx.channel(); - let table = js_table.table.clone(); - - rt.spawn(async move { - let result = table.add_columns(transforms, None).await; - deferred.settle_with(&channel, move |mut cx| { - result.or_throw(&mut cx)?; - Ok(cx.undefined()) - }) - }); - - Ok(promise) - } - - pub(crate) fn js_alter_columns(mut cx: FunctionContext) -> JsResult { - let alterations = cx - .argument::(0)? - .to_vec(&mut cx)? - .into_iter() - .map(|val| { - let obj = val.downcast_or_throw::(&mut cx)?; - let path = obj.get::(&mut cx, "path")?.value(&mut cx); - let rename = obj - .get_opt::(&mut cx, "rename")? - .map(|val| val.value(&mut cx)); - let nullable = obj - .get_opt::(&mut cx, "nullable")? - .map(|val| val.value(&mut cx)); - // TODO: support data type here. Will need to do some serialization/deserialization - - if rename.is_none() && nullable.is_none() { - return cx.throw_error("At least one of 'name' or 'nullable' must be provided"); - } - - Ok(ColumnAlteration { - path, - rename, - nullable, - // TODO: wire up this field - data_type: None, - }) - }) - .collect::>>()?; - - let js_table = cx.this().downcast_or_throw::, _>(&mut cx)?; - let rt = runtime(&mut cx)?; - - let (deferred, promise) = cx.promise(); - let channel = cx.channel(); - let table = js_table.table.clone(); - - rt.spawn(async move { - let result = table.alter_columns(&alterations).await; - deferred.settle_with(&channel, move |mut cx| { - result.or_throw(&mut cx)?; - Ok(cx.undefined()) - }) - }); - - Ok(promise) - } - - pub(crate) fn js_drop_columns(mut cx: FunctionContext) -> JsResult { - let columns = cx - .argument::(0)? - .to_vec(&mut cx)? - .into_iter() - .map(|val| { - Ok(val - .downcast_or_throw::(&mut cx)? - .value(&mut cx)) - }) - .collect::>>()?; - - let js_table = cx.this().downcast_or_throw::, _>(&mut cx)?; - let rt = runtime(&mut cx)?; - - let (deferred, promise) = cx.promise(); - let channel = cx.channel(); - let table = js_table.table.clone(); - - rt.spawn(async move { - let col_refs = columns.iter().map(|s| s.as_str()).collect::>(); - let result = table.drop_columns(&col_refs).await; - deferred.settle_with(&channel, move |mut cx| { - result.or_throw(&mut cx)?; - Ok(cx.undefined()) - }) - }); - - Ok(promise) - } - - pub(crate) fn js_drop_index(_cx: FunctionContext) -> JsResult { - todo!("not implemented") - } -}