├── .gitignore ├── CHANGELOG ├── LICENSE ├── Makefile ├── README.md ├── cliff.toml ├── movies.csv.gz ├── package-lock.json ├── package.json ├── pnpm-lock.yaml ├── results ├── meilisearch.output ├── opensearch.output ├── pg.output ├── sqlite-disk.output ├── sqlite-mem.output └── typesense.output ├── search-phrases.ndjson.json └── src ├── driver ├── index.mjs ├── meilisearch.mjs ├── opensearch.mjs ├── pg.mjs ├── sqlite-disk.mjs ├── sqlite-mem.mjs ├── sqlite.mjs └── typesense.mjs └── util └── csv2ndjson.mjs /.gitignore: -------------------------------------------------------------------------------- 1 | # Local dockerized engine data 2 | .data 3 | 4 | # Secrets 5 | secrets/* 6 | 7 | # Direnv 8 | /.env 9 | /.envrc 10 | 11 | # NodeJS 12 | node_modules 13 | /movies.csv 14 | /movies.ndjson.json 15 | /fts-sqlite-disk-db.sqlite 16 | /fts-sqlite-disk-db.sqlite-journal 17 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | # Changelog 2 | All notable changes to this project will be documented in this file. 3 | 4 | ## [0.2.1] - 2022-10-15 5 | 6 | ### Bug Fixes 7 | 8 | - Include tag in release automation 9 | - Remove debug comment 10 | 11 | ## [0.2.0] - 2022-10-15 12 | 13 | ### Bug Fixes 14 | 15 | - Add license 16 | - Incorrect env breaking csv2ndjson. (#1) 17 | - Disable opensearch security for local runs (#3) 18 | 19 | ### Documentation 20 | 21 | - Improve ENV docs (#5) 22 | 23 | ### Workflow 24 | 25 | - Swtich to pnpm (#4) 26 | - Add release automation 27 | 28 | ## [0.1.0] - 2022-08-29 29 | 30 | ### Bug Fixes 31 | 32 | - Local volume data dirs 33 | - Opensearch 34 | 35 | ### Features 36 | 37 | - Working query 38 | 39 | ### Miscellaneous Tasks 40 | 41 | - Initial commit, basic docs and Makefile skeleton 42 | - Add gitignore 43 | - Update gitignore 44 | - Update timing 45 | - Add LICENSE 46 | - Add changelog stuff 47 | 48 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 VADOSWARE LLC 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all .data \ 2 | clean clean-data \ 3 | print-version \ 4 | # Check deps 5 | check-dep-nodejs check-dep-docker check-dep-gunzip check-env-FTS_ENGINE \ 6 | # Run a single experiment 7 | setup run ingest query \ 8 | # FTS Engine start 9 | engine-start engine-start-pg engine-start-meilisearch \ 10 | engine-start-sqlite \ 11 | engine-start-opensearch \ 12 | engine-start-tyepsense \ 13 | opensearch-volume-create \ 14 | # FTS Engine stop 15 | engine-stop engine-stop-pg engine-stop-meilisearch \ 16 | engine-stop-sqlite engine-stop-opensearch engine-stop-tyepsense \ 17 | opensearch-volume-delete 18 | 19 | GIT ?= git 20 | NODE ?= node 21 | GUNZIP ?= gunzip 22 | PNPM ?= pnpm 23 | SQLITE ?= sqlite3 24 | 25 | DOCKER ?= docker 26 | DOCKER_LISTEN_HOST ?= 127.0.0.1 27 | 28 | ROOT_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) 29 | VERSION ?= $(shell $(NODE) -e 'console.log(require("./package.json").version);') 30 | CURRENT_SHA ?= $(shell $(GIT) rev-parse --short HEAD) 31 | 32 | DATA_MOVIES_CSV_ZIPPED_PATH ?= $(ROOT_DIR)movies.csv.gz 33 | DATA_MOVIES_CSV_PATH ?= $(ROOT_DIR)movies.csv 34 | DATA_MOVIES_NDJSON_PATH ?= $(ROOT_DIR)movies.ndjson.json 35 | SEARCH_PHRASES_NDJSON_PATH ?= $(ROOT_DIR)search-phrases.ndjson.json 36 | 37 | SQLITE_DISK_DB_PATH ?= ./fts-sqlite-disk-db.sqlite 38 | 39 | all: setup run-all 40 | 41 | .data: 42 | @mkdir -p .data 43 | 44 | clean: clean-data 45 | 46 | clean-data: 47 | @echo "[note] this may need to run with sudo to remove container data dirs..." 48 | rm -rf ./.data 49 | 50 | CHANGELOG_FILE_PATH ?= CHANGELOG 51 | 52 | changelog: 53 | $(GIT) cliff --unreleased --tag=$(VERSION) --prepend=$(CHANGELOG_FILE_PATH) 54 | 55 | print-version: 56 | echo -n $(VERSION) 57 | 58 | ########### 59 | # Tooling # 60 | ########### 61 | 62 | check-dep-nodejs: 63 | ifeq (,$(shell which $(NODE))) 64 | $(error "please enture NodeJS is installed (see: https://nodejs.org)") 65 | endif 66 | 67 | check-dep-docker: 68 | ifeq (,$(shell which $(DOCKER))) 69 | $(error "please enture Docker is installed (see: https://docs.docker.com)") 70 | endif 71 | 72 | check-dep-gunzip: 73 | ifeq (,$(shell which $(GUNZIP))) 74 | $(error "please ensure gunzip is installed (see https://www.gnu.org/software/gzip)") 75 | endif 76 | 77 | check-dep-sqlite: 78 | ifeq (,$(shell which $(SQLITE))) 79 | $(error "please ensure SQLite is installed (see https://www.sqlite.org)") 80 | endif 81 | 82 | check-env-FTS_ENGINE: 83 | ifeq ("","$(FTS_ENGINE)") 84 | $(error "an FTS_ENGINE must be specified (ex. 'pg', 'meilisearch', 'sqlite', 'typesense', 'opensearch')") 85 | endif 86 | 87 | ######### 88 | # Build # 89 | ######### 90 | 91 | INPUT_CSV_PATH ?= $(DATA_MOVIES_CSV_ZIPPED_PATH) 92 | 93 | movies.csv: check-dep-gunzip 94 | @if [ ! -f "$(DATA_MOVIES_CSV_PATH)" ]; then \ 95 | echo -e "[info] unzipping [$(DATA_MOVIES_CSV_ZIPPED_PATH)]..."; \ 96 | $(GUNZIP) -fk $(DATA_MOVIES_CSV_ZIPPED_PATH); \ 97 | fi 98 | 99 | movies.ndjson.json: check-dep-gunzip movies.csv 100 | @if [ ! -f "$(DATA_MOVIES_NDJSON_PATH)" ]; then \ 101 | echo -e "[info] converting [$(DATA_MOVIES_CSV_PATH)] to [$(DATA_MOVIES_NDJSON_PATH)]..."; \ 102 | INPUT_CSV_PATH=$(DATA_MOVIES_CSV_PATH) OUTPUT_NDJSON_PATH=$(DATA_MOVIES_NDJSON_PATH) $(NODE) src/util/csv2ndjson.mjs; \ 103 | fi 104 | 105 | setup: 106 | $(PNPM) install 107 | 108 | run: 109 | @$(MAKE) --quiet --no-print-directory engine-start || true 110 | @$(MAKE) --quiet --no-print-directory ingest 111 | @$(MAKE) --quiet --no-print-directory query 112 | @$(MAKE) --quiet --no-print-directory engine-stop 113 | 114 | run-all: 115 | @$(MAKE) --quiet --no-print-directory run FTS_ENGINE=pg 116 | @$(MAKE) --quiet --no-print-directory run FTS_ENGINE=meilisearch 117 | @$(MAKE) --quiet --no-print-directory run FTS_ENGINE=typesense 118 | @$(MAKE) --quiet --no-print-directory run FTS_ENGINE=opensearch 119 | @$(MAKE) --quiet --no-print-directory run FTS_ENGINE=sqlite-disk 120 | @$(MAKE) --quiet --no-print-directory run FTS_ENGINE=sqlite-mem 121 | 122 | ###################### 123 | # Release Automation # 124 | ###################### 125 | 126 | release-major: 127 | $(PNPM) version major --no-git-tag-version 128 | $(MAKE) -s --no-print-directory changelog 129 | $(GIT) commit -am "release: v`$(MAKE) -s --no-print-directory print-version`" 130 | $(GIT) tag "v`$(MAKE) -s --no-print-directory print-version`" 131 | $(GIT) push --all 132 | 133 | release-minor: 134 | $(PNPM) version minor --no-git-tag-version 135 | $(MAKE) -s --no-print-directory changelog 136 | $(GIT) commit -am "release: v`$(MAKE) -s --no-print-directory print-version`" 137 | $(GIT) tag "v`$(MAKE) -s --no-print-directory print-version`" 138 | $(GIT) push --all 139 | 140 | release-patch: 141 | $(PNPM) version patch --no-git-tag-version 142 | $(MAKE) -s --no-print-directory changelog 143 | $(GIT) commit -am "release: v`$(MAKE) -s --no-print-directory print-version`" 144 | $(GIT) tag "v`$(MAKE) -s --no-print-directory print-version`" 145 | $(GIT) push --all 146 | 147 | ############# 148 | # Ingestion # 149 | ############# 150 | 151 | ingest: check-dep-nodejs check-env-FTS_ENGINE movies.ndjson.json 152 | ifeq ("pg","$(FTS_ENGINE)") 153 | @$(MAKE) --quiet --no-print-directory ingest-pg 154 | else ifeq ("meilisearch","$(FTS_ENGINE)") 155 | @$(MAKE) --quiet --no-print-directory ingest-meilisearch 156 | else ifeq ("typesense","$(FTS_ENGINE)") 157 | @$(MAKE) --quiet --no-print-directory ingest-typesense 158 | else ifeq ("opensearch","$(FTS_ENGINE)") 159 | @$(MAKE) --quiet --no-print-directory ingest-opensearch 160 | else ifeq ("sqlite-disk","$(FTS_ENGINE)") 161 | @$(MAKE) --quiet --no-print-directory ingest-sqlite-disk 162 | else ifeq ("sqlite-mem","$(FTS_ENGINE)") 163 | @$(MAKE) --quiet --no-print-directory ingest-sqlite-mem 164 | else 165 | $(error "failed to start unrecognized FTS engine [$(FTS_ENGINE)]") 166 | endif 167 | 168 | ingest-pg: 169 | @OP=ingest \ 170 | INGEST_INPUT_PATH=$(DATA_MOVIES_NDJSON_PATH) \ 171 | PG_URL=$(PG_URL) \ 172 | $(NODE) "src/driver/index.mjs" 173 | 174 | ingest-meilisearch: 175 | @OP=ingest \ 176 | INGEST_INPUT_PATH=$(DATA_MOVIES_NDJSON_PATH) \ 177 | MEILI_URL=http://$(MEILI_HOST):$(MEILI_PORT) \ 178 | MEILI_API_KEY=$(MEILI_MASTER_KEY) \ 179 | $(NODE) "src/driver/index.mjs" 180 | 181 | ingest-typesense: 182 | @OP=ingest \ 183 | INGEST_INPUT_PATH=$(DATA_MOVIES_NDJSON_PATH) \ 184 | TYPESENSE_HOST=$(TYPESENSE_HOST) \ 185 | TYPESENSE_PORT=$(TYPESENSE_PORT) \ 186 | TYPESENSE_API_KEY=$(TYPESENSE_API_KEY) \ 187 | $(NODE) "src/driver/index.mjs" 188 | 189 | ingest-opensearch: 190 | @OP=ingest \ 191 | INGEST_INPUT_PATH=$(DATA_MOVIES_NDJSON_PATH) \ 192 | OPENSEARCH_PROTOCOL=$(OPENSEARCH_PROTOCOL) \ 193 | OPENSEARCH_HOST=$(OPENSEARCH_HOST) \ 194 | OPENSEARCH_PORT=$(OPENSEARCH_PORT) \ 195 | OPENSEARCH_AUTH_USERNAME=$(OPENSEARCH_AUTH_USERNAME) \ 196 | OPENSEARCH_AUTH_PASSWORD=$(OPENSEARCH_AUTH_PASSWORD) \ 197 | $(NODE) "src/driver/index.mjs" 198 | 199 | ingest-sqlite-disk: 200 | @OP=ingest \ 201 | INGEST_INPUT_PATH=$(DATA_MOVIES_NDJSON_PATH) \ 202 | SQLITE_DISK_DB_PATH=$(SQLITE_DISK_DB_PATH) \ 203 | $(NODE) "src/driver/index.mjs" 204 | 205 | ingest-sqlite-mem: 206 | @OP=ingest+query \ 207 | INGEST_INPUT_PATH=$(DATA_MOVIES_NDJSON_PATH) \ 208 | QUERY_INPUT_PATH=$(SEARCH_PHRASES_NDJSON_PATH) \ 209 | SQLITE_DISK_DB_PATH=":memory:" \ 210 | $(NODE) "src/driver/index.mjs" 211 | 212 | ############ 213 | # Querying # 214 | ############ 215 | 216 | QUERIES_YAML_PATH ?= $(ROOT_DIR)queries.yaml 217 | 218 | ## Run the query 219 | query: check-dep-nodejs check-env-FTS_ENGINE 220 | ifeq ("pg","$(FTS_ENGINE)") 221 | @$(MAKE) --quiet --no-print-directory query-pg 222 | else ifeq ("meilisearch","$(FTS_ENGINE)") 223 | @$(MAKE) --quiet --no-print-directory query-meilisearch 224 | else ifeq ("typesense","$(FTS_ENGINE)") 225 | @$(MAKE) --quiet --no-print-directory query-typesense 226 | else ifeq ("opensearch","$(FTS_ENGINE)") 227 | @$(MAKE) --quiet --no-print-directory query-opensearch 228 | else ifeq ("sqlite-disk","$(FTS_ENGINE)") 229 | @$(MAKE) --quiet --no-print-directory query-sqlite-disk 230 | else ifeq ("sqlite-mem","$(FTS_ENGINE)") 231 | @$(MAKE) --quiet --no-print-directory query-sqlite-mem 232 | else 233 | $(error "failed to start unrecognized FTS engine [$(FTS_ENGINE)]") 234 | endif 235 | 236 | query-pg: 237 | @OP=query \ 238 | TIMING=true \ 239 | QUERY_INPUT_PATH=$(SEARCH_PHRASES_NDJSON_PATH) \ 240 | PG_URL=$(PG_URL) \ 241 | $(NODE) "src/driver/index.mjs" 242 | 243 | query-meilisearch: 244 | @OP=query \ 245 | TIMING=true \ 246 | QUERY_INPUT_PATH=$(SEARCH_PHRASES_NDJSON_PATH) \ 247 | MEILI_URL=http://$(MEILI_HOST):$(MEILI_PORT) \ 248 | MEILI_API_KEY=$(MEILI_MASTER_KEY) \ 249 | $(NODE) "src/driver/index.mjs" 250 | 251 | query-typesense: 252 | @OP=query \ 253 | TIMING=true \ 254 | QUERY_INPUT_PATH=$(SEARCH_PHRASES_NDJSON_PATH) \ 255 | TYPESENSE_HOST=$(TYPESENSE_HOST) \ 256 | TYPESENSE_PORT=$(TYPESENSE_PORT) \ 257 | TYPESENSE_API_KEY=$(TYPESENSE_API_KEY) \ 258 | $(NODE) "src/driver/index.mjs" 259 | 260 | query-opensearch: 261 | @OP=query \ 262 | TIMING=true \ 263 | QUERY_INPUT_PATH=$(SEARCH_PHRASES_NDJSON_PATH) \ 264 | OPENSEARCH_PROTOCOL=$(OPENSEARCH_PROTOCOL) \ 265 | OPENSEARCH_HOST=$(OPENSEARCH_HOST) \ 266 | OPENSEARCH_PORT=$(OPENSEARCH_PORT) \ 267 | OPENSEARCH_AUTH_USERNAME=$(OPENSEARCH_AUTH_USERNAME) \ 268 | OPENSEARCH_AUTH_PASSWORD=$(OPENSEARCH_AUTH_PASSWORD) \ 269 | $(NODE) "src/driver/index.mjs" 270 | 271 | query-sqlite-disk: 272 | @OP=query \ 273 | TIMING=true \ 274 | QUERY_INPUT_PATH=$(SEARCH_PHRASES_NDJSON_PATH) \ 275 | SQLITE_DISK_DB_PATH=$(SQLITE_DISK_DB_PATH) \ 276 | $(NODE) "src/driver/index.mjs" 277 | 278 | query-sqlite-mem: 279 | @echo -e "ingest and query for sqlite memory happen *at the same time*, this is a no-op" 280 | 281 | ####################### 282 | # FTS Engines - Start # 283 | ####################### 284 | 285 | ## Start the FTS engine of choice 286 | engine-start: check-dep-docker 287 | ifeq ("pg","$(FTS_ENGINE)") 288 | $(MAKE) engine-start-pg 289 | else ifeq ("meilisearch","$(FTS_ENGINE)") 290 | $(MAKE) engine-start-meilisearch 291 | else ifeq ("typesense","$(FTS_ENGINE)") 292 | $(MAKE) engine-start-typesense 293 | else ifeq ("opensearch","$(FTS_ENGINE)") 294 | $(MAKE) engine-start-opensearch 295 | else ifeq ("sqlite-disk","$(FTS_ENGINE)") 296 | $(MAKE) engine-start-sqlite-disk 297 | else ifeq ("sqlite-mem","$(FTS_ENGINE)") 298 | $(MAKE) engine-start-sqlite-disk 299 | else 300 | $(error "failed to start unrecognized FTS engine [$(FTS_ENGINE)]") 301 | endif 302 | 303 | WAIT4X_IMAGE ?= atkrad/wait4x:2.6.2@sha256:594886afdd1f4d6678e97a4fb7d9bbd951c750d255b1197ada90ffe3f260c271 304 | 305 | ############### 306 | # FTS Engines # 307 | ############### 308 | 309 | PG_CONTAINER_NAME ?= fts-pg 310 | PG_IMAGE ?= postgres:14.5-alpine3.16@sha256:9ece045f37060bf6b0a36ffbd5afa4f56636370791abae5062ed6005ec0e5110 311 | PG_PASSWORD ?= fts 312 | PG_USER ?= fts 313 | PG_PORT ?= 5432 314 | PG_HOST ?= localhost 315 | PG_DB ?= fts 316 | PG_URL ?= "postgres://$(PG_USER):$(PG_PASSWORD)@$(PG_HOST):$(PG_PORT)/$(PG_DB)" 317 | 318 | engine-start-pg: 319 | @$(DOCKER) run \ 320 | --rm \ 321 | --detach \ 322 | -p $(DOCKER_LISTEN_HOST):$(PG_PORT):$(PG_PORT) \ 323 | -e POSTGRES_USER=$(PG_USER) \ 324 | -e POSTGRES_PASSWORD=$(PG_PASSWORD) \ 325 | -v $(PWD)/.data/postgres:/var/lib/postgresql/data \ 326 | --name=$(PG_CONTAINER_NAME) \ 327 | $(PG_IMAGE) 328 | @echo "[info] started docker container [$(PG_CONTAINER_NAME)]..." 329 | @echo "[info] waiting for TCP connectivity to [$(PG_CONTAINER_NAME)]..." 330 | @$(DOCKER) run --rm --net=host $(WAIT4X_IMAGE) tcp $(PG_HOST):$(PG_PORT) 331 | sleep 3 332 | 333 | ############################ 334 | # FTS Engine - MeiliSearch # 335 | ############################ 336 | 337 | MEILI_CONTAINER_NAME ?= fts-meili 338 | MEILI_IMAGE ?= getmeili/meilisearch:v0.28.1@sha256:dc55a924c56420ae0bbcf8724311de46816aa623fdc90bc89bdb98e72dad08ce 339 | MEILI_MASTER_KEY ?= meilisearch 340 | MEILI_ENV ?= production 341 | MEILI_PORT ?= 7700 342 | MEILI_HOST ?= localhost 343 | 344 | engine-start-meilisearch: 345 | $(DOCKER) run --rm \ 346 | --detach \ 347 | -p $(DOCKER_LISTEN_HOST):$(MEILI_PORT):$(MEILI_PORT) \ 348 | -e MEILI_MASTER_KEY=$(MEILI_MASTER_KEY) \ 349 | --name=$(MEILI_CONTAINER_NAME) \ 350 | -v $(PWD)/.data/meilisearch:/meili_data \ 351 | $(MEILI_IMAGE) \ 352 | /bin/meilisearch \ 353 | --env="$(MEILI_ENV)" 354 | @echo "[info] waiting for TCP connectivity to [$(MEILI_CONTAINER_NAME)]..." 355 | @$(DOCKER) run --rm --net=host $(WAIT4X_IMAGE) tcp $(MEILI_HOST):$(MEILI_PORT) 356 | sleep 3 357 | 358 | ########################## 359 | # FTS Engine - Typesense # 360 | ########################## 361 | 362 | TYPESENSE_CONTAINER_NAME ?= fts-typesense 363 | TYPESENSE_IMAGE ?= typesense/typesense:0.23.1@sha256:827ac4dda3cd766c5e6db955729d9abaf9ae08722d3c50e047d3f8afea23a726 364 | TYPESENSE_API_KEY ?= badtypesenseapikey 365 | TYPESENSE_PORT ?= 8108 366 | TYPESENSE_HOST ?= localhost 367 | 368 | engine-start-typesense: 369 | @$(DOCKER) run --rm \ 370 | --detach \ 371 | -p $(DOCKER_LISTEN_HOST):$(TYPESENSE_PORT):$(TYPESENSE_PORT) \ 372 | --name=$(TYPESENSE_CONTAINER_NAME) \ 373 | -v $(PWD)/.data/typesense:/data \ 374 | $(TYPESENSE_IMAGE) \ 375 | --data-dir /data \ 376 | --api-key="$(TYPESENSE_API_KEY)" 377 | @echo "[info] started docker container [$(TYPESENSE_CONTAINER_NAME)]..." 378 | @echo "[info] waiting for TCP connectivity to [$(TYPESENSE_CONTAINER_NAME)]..." 379 | @$(DOCKER) run --rm --net=host $(WAIT4X_IMAGE) tcp $(TYPESENSE_HOST):$(TYPESENSE_PORT) 380 | sleep 3 381 | 382 | ########################### 383 | # FTS Engine - OpenSearch # 384 | ########################### 385 | 386 | OPENSEARCH_CONTAINER_NAME ?= fts-opensearch 387 | OPENSEARCH_IMAGE ?= opensearchproject/opensearch:2.2.0@sha256:174ee3a36ded56043add6e9d9086c9c0e877c38b3161a9f89b5bfc8f83a24ab3 388 | OPENSEARCH_AUTH_PASSWORD ?= admin 389 | OPENSEARCH_AUTH_USERNAME ?= admin 390 | OPENSEARCH_PROTOCOL ?= http 391 | OPENSEARCH_HOST ?= localhost 392 | OPENSEARCH_PORT ?= 9200 393 | OPENSEARCH_PERF_PORT ?= 9600 394 | 395 | opensearch-volume-create: 396 | $(DOCKER) volume create $(OPENSEARCH_CONTAINER_NAME) 397 | 398 | engine-start-opensearch: .data opensearch-volume-create 399 | @$(DOCKER) run \ 400 | --detach \ 401 | --rm \ 402 | --name=$(OPENSEARCH_CONTAINER_NAME) \ 403 | -p $(DOCKER_LISTEN_HOST):$(OPENSEARCH_PORT):$(OPENSEARCH_PORT) \ 404 | -p $(DOCKER_LISTEN_HOST):$(OPENSEARCH_PERF_PORT):$(OPENSEARCH_PERF_PORT) \ 405 | -e "discovery.type=single-node" \ 406 | -e "plugins.security.disabled=true" \ 407 | -v $(OPENSEARCH_CONTAINER_NAME):/usr/share/opensearch/data \ 408 | $(OPENSEARCH_IMAGE) 409 | @echo "[info] started docker container [$(OPENSEARCH_CONTAINER_NAME)]..." 410 | @echo "[info] waiting for TCP connectivity to [$(OPENSEARCH_CONTAINER_NAME)]..." 411 | @$(DOCKER) run --rm --net=host $(WAIT4X_IMAGE) tcp $(OPENSEARCH_HOST):$(OPENSEARCH_PORT) 412 | sleep 10 413 | 414 | ####################### 415 | # FTS Engine - SQLite # 416 | ####################### 417 | 418 | engine-start-sqlite-disk: .data check-dep-sqlite 419 | @if [ ! -f "$(SQLITE_DISK_DB_PATH)" ] ; then \ 420 | touch $(SQLITE_DISK_DB_PATH); \ 421 | $(SQLITE) $(SQLITE_DISK_DB_PATH) ".databases"; \ 422 | fi; 423 | @echo "[info] using SQLite DB @ [$(SQLITE_DISK_DB_PATH)]..." 424 | 425 | engine-start-sqlite-disk-mem: .data check-dep-sqlite 426 | @echo "[info] using SQLite DB @ [$(SQLITE_DISK_DB_PATH)]..." 427 | 428 | ###################### 429 | # FTS Engines - Stop # 430 | ###################### 431 | 432 | ## Stop the FTS engine of choice 433 | engine-stop: check-dep-docker 434 | ifeq ("pg","$(FTS_ENGINE)") 435 | @$(MAKE) --quiet --no-print-directory engine-stop-pg 436 | else ifeq ("meilisearch","$(FTS_ENGINE)") 437 | @$(MAKE) --quiet --no-print-directory engine-stop-meilisearch 438 | else ifeq ("typesense","$(FTS_ENGINE)") 439 | @$(MAKE) --quiet --no-print-directory engine-stop-typesense 440 | else ifeq ("opensearch","$(FTS_ENGINE)") 441 | @$(MAKE) --quiet --no-print-directory engine-stop-opensearch 442 | else ifeq ("sqlite-disk","$(FTS_ENGINE)") 443 | @$(MAKE) --quiet --no-print-directory engine-stop-sqlite-disk 444 | else ifeq ("sqlite-mem","$(FTS_ENGINE)") 445 | @$(MAKE) --quiet --no-print-directory engine-stop-sqlite-mem 446 | else 447 | $(error "failed to stop unrecognized FTS engine [$(FTS_ENGINE)]") 448 | endif 449 | 450 | engine-stop-pg: 451 | @$(DOCKER) stop $(PG_CONTAINER_NAME) || true 452 | @$(DOCKER) rm $(PG_CONTAINER_NAME) || true 453 | 454 | engine-stop-meilisearch: 455 | @$(DOCKER) stop $(MEILI_CONTAINER_NAME) || true 456 | @$(DOCKER) rm $(MEILI_CONTAINER_NAME) || true 457 | 458 | engine-stop-typesense: 459 | @$(DOCKER) stop $(TYPESENSE_CONTAINER_NAME) || true 460 | @$(DOCKER) rm $(TYPESENSE_CONTAINER_NAME) || true 461 | 462 | opensearch-volume-delete: 463 | @$(DOCKER) volume rm $(OPENSEARCH_CONTAINER_NAME) || true 464 | 465 | engine-stop-opensearch: 466 | @$(DOCKER) stop $(OPENSEARCH_CONTAINER_NAME) || true 467 | @$(DOCKER) rm $(OPENSEARCH_CONTAINER_NAME) || true 468 | @if [ -n "$DELETE_DATA" ]; then \ 469 | $(MAKE) --quiet --no-print-directory opensearch-volume-delete; \ 470 | fi 471 | 472 | engine-stop-sqlite-disk: 473 | @echo "[info] Plesae delete SQLite @ [$(SQLITE_DISK_DB_PATH)] manually" 474 | 475 | engine-stop-sqlite-mem: 476 | @echo "[info] SQLite DB stop is a no-op" 477 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Postgres Full Text Search ("FTS") benchmark 2 | 3 | This is a benchmark of Postgres FTS versus other solutions: 4 | 5 | - [SQLite FTS][sqlite-fts] 6 | - [MeiliSearch][meilisearch] 7 | - [Typesense][typesense] 8 | - [OpenSearch][opensearch] 9 | 10 | [sqlite-fts]: https://www.sqlite.org/fts5.html 11 | [meilisearch]: https://www.meilisearch.com 12 | [typesense]: https://typesense.org 13 | [opensearch]: https://opensearch.org/ 14 | 15 | ## Prerequisites 16 | 17 | To run the tests, please ensure you have the following installed on your machine: 18 | 19 | - `gunzip` (part of the [`gzip` software distribution][gzip]) 20 | - [Docker][docker] 21 | - [NodeJS][nodejs] (`node` and `npm`) 22 | - [`pnpm`][pnpm] (i.e. `npm install -g pnpm`) 23 | - [`sqlite`][sqlite] 24 | 25 | [gzip]: https://www.gnu.org/software/gzip/ 26 | [docker]: https://docs.docker.com 27 | [nodejs]: https://nodejs.org 28 | [sqlite]: https://sqlite.org 29 | [pnpm]: https://pnpm.io 30 | 31 | ## Quickstart 32 | 33 | To set up testing data and **run the full benchmark with *all* FTS engines**: 34 | 35 | ```console 36 | make # equivalent to `make setup run-all` 37 | ``` 38 | 39 | To run only a single benchmark (in this case, with Postgres FTS): 40 | 41 | ```console 42 | FTS_ENGINE=pg make setup run 43 | ``` 44 | (`FTS_ENGINE = 'pg' | 'meilisearch' | 'typesense' | 'opensearch' | 'sqlite-disk'`) 45 | 46 | To only install dependencies: 47 | 48 | ```console 49 | make setup 50 | ``` 51 | 52 | ## Dataset 53 | 54 | The benchmark in this repository uses the a public domain movie dataset: 55 | 56 | - [On Kaggle](https://www.kaggle.com/datasets/rounakbanik/the-movies-dataset?select=movies_metadata.csv) 57 | - [On HuggingFace](https://huggingface.co/spaces/Kamand/Movie_Recommendation/blob/main/movies_metadata.csv), in particular the following columns: 58 | 59 | - `homepage` 60 | - `title` 61 | - `original_title` 62 | - `overview` 63 | - `production_companies` 64 | - `spoken_languages` 65 | - `tagline` 66 | 67 | Data is processed from CSV into [newline delimited JSON][ndjson] (see `movies.ndjson.json.gz`). 68 | 69 | [ndjson]: http://ndjson.org 70 | 71 | ## How the benchmark works 72 | 73 | ### Environment variables 74 | 75 | | ENV Variable | Default | Example | Description | 76 | |-------------------------------|----------------------------------|---------------------------------------|---------------------------------------------------------| 77 | | `FTS_ENGINE` | N/A | `pg` | The FTS engine to use | 78 | | `DEBUG` | N/A | `true` | Enable debug mode | 79 | | `TIMING` | N/A | `true` | Enable timing information display | 80 | | `DATA_MOVIES_CSV_ZIPPED_PATH` | `./movies.csv.gz` | `/path/to/movies.csv.gz` | Path to the movie data set | 81 | | `DATA_MOVIES_CSV_PATH` | `./movies.csv` | `/path/to/movies.csv` | Path to the movie data set, uncompressed | 82 | | `DATA_MOVIES_NDJSON_PATH` | `./movies.ndjson.json` | `/path/to/movies.ndjson.json` | Path to the newline delimited JSON data for movies | 83 | | `SEARCH_PHRASES_NDJSON_PATH` | `./search-phrases.ndjson.json` | `/path/to/search-phrases.ndjson.json` | Path to search phrases to use as newline delimited JSON | 84 | 85 | Some variables are used per-run and are normally set by more ergonomic top-level `Makefile` targets: 86 | 87 | | ENV Variable | Default | Example | Description | 88 | |----------------------------|-----------------------------------------------------------------------|----------------------------|---------------------------------------------------------------| 89 | | `INPUT_CSV_PATH` | `$(DATA_MOVIES_CSV_ZIPPED_PATH)` | `/path/to/movies2.csv.gz` | Path to compressed CSV (normally unzipped by Makefile target) | 90 | | `OP` | N/A | `ingest` | Operation to perform | 91 | | `SQLITE_DISK_DB_PATH` | `./fts-sqlite-disk-db.sqlite` | `:memory:` | SQLite DB path | 92 | | `PG_URL` | `postgres://$(PG_USER):$(PG_PASSWORD)@$(PG_HOST):$(PG_PORT)/$(PG_DB)` | `postgres://localhost` | Postgres DB path | 93 | | `TYPESENSE_HOST` | `localhost` | `typesense.domain.tld` | Hostname for Typesense server | 94 | | `TYPESENSE_PORT` | `8108` | `8109` | Port for Typesense server | 95 | | `TYPESENSE_API_KEY` | `badtypesenseapikey` | `tttttttttttttttt` | API key for Typesense server | 96 | | `MEILI_HOST` | `localhost` | `meili.domain.tld` | Hostname for MeiliSearch server | 97 | | `MEILI_PORT` | `7700` | `7701` | Port for MeiliSearch | 98 | | `MEILI_URL` | `http://$(MEILI_HOST):$(MEILI_PORT)` | `https://meili.domain.tld` | Full URL to use when accessing Meilisearch | 99 | | `MEILI_API_KEY` | `$(MEILI_MASTER_KEY)` | `xxxxxxxxxxxxxxxxxxx` | MeiliSearch API key | 100 | | `OPENSEARCH_PROTOCOL` | `http` | `https` | Protocol to use when accessing OpenSearch service | 101 | | `OPENSEARCH_HOST` | `localhost` | `opensearch.domain.tld` | Host for OpenSearch server | 102 | | `OPENSEARCH_PORT` | `9200` | `9201` | Port for OpenSearch server | 103 | | `OPENSEARCH_AUTH_USERNAME` | `admin` | `admin` | Admin username for OpenSearch server | 104 | | `OPENSEARCH_AUTH_PASSWORD` | `admin` | `hunter2` | Admin password for OpenSearch server | 105 | 106 | See `Makefile` for the code and other variables that might be excluded here. 107 | 108 | ### Running a single benchmark 109 | 110 | A single benchmark can be run with the following command: 111 | 112 | ```console 113 | FTS_ENGINE= make setup run 114 | ``` 115 | 116 | Options for `FTS_ENGINE`: 117 | 118 | - `pg` 119 | - `meilisearch` 120 | - `typesense` 121 | - `sqlite`. 122 | 123 | To run the ingest & query tests with Postgres: 124 | 125 | ```console 126 | TIMING=true FTS_ENGINE=pg make run 127 | ``` 128 | 129 | If an error occurs during set up, consider tearing down the existing `FTS_ENGINE`: 130 | 131 | ```console 132 | FTS_ENGINE=pg make engine-stop 133 | ``` 134 | 135 | ### Setup/Teardown of a single backing service 136 | 137 | To control the setup/teardown of a single backing service, use the `engine-start` and `engine-stop` top level targets. 138 | 139 | For example, if you wanted to start MeiliSearch and poke around on the instance: 140 | 141 | ```console 142 | FTS_ENGINE=meilisearch make engine-start 143 | ``` 144 | 145 | After this command returns, you should have an instance of meilisearch running with a stable name (`fts-$(FTS_ENGINE)`): 146 | 147 | ``` 148 | $ docker ps 149 | CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 150 | 4d7c0efdf5cf getmeili/meilisearch:v0.28.1 "tini -- /bin/meilis…" 7 seconds ago Up 6 seconds 127.0.0.1:7700->7700/tcp fts-meili 151 | ``` 152 | 153 | To stop the service: 154 | 155 | ```console 156 | FTS_ENGINE=meilisearch make engine-stop 157 | ``` 158 | 159 | ### Ingesting documents 160 | 161 | Ingesting data into each separate solution is different, and code to do each can be found under `src/driver/.js`. For example, the `src/driver/pg.mjs` contains the code to enable document ingestion to Postgres. 162 | 163 | ### Performing queries 164 | 165 | Queries to be performed in the test are specified via YAML and stored in `search-phrases.ndjson.json`. 166 | 167 | This file is read by the automation and related scripts. 168 | 169 | ### Clearing data 170 | 171 | To clear all the data inbetween runs: 172 | 173 | ```console 174 | sudo make clean # sudo is likely needed to clear docker container data folders 175 | ``` 176 | -------------------------------------------------------------------------------- /cliff.toml: -------------------------------------------------------------------------------- 1 | # configuration file for git-cliff (0.1.0) 2 | 3 | [changelog] 4 | 5 | # changelog header 6 | header = """ 7 | # Changelog 8 | All notable changes to this project will be documented in this file.\n 9 | """ 10 | # template for the changelog body 11 | # https://tera.netlify.app/docs/#introduction 12 | body = """ 13 | {% if version %}\ 14 | ## [{{ version | replace(from="v", to="") }}] - {{ timestamp | date(format="%Y-%m-%d") }} 15 | {% else %}\ 16 | ## [unreleased] 17 | {% endif %}\ 18 | {% for group, commits in commits | group_by(attribute="group") %} 19 | ### {{ group | upper_first }} 20 | {% for commit in commits %} 21 | - {{ commit.message | upper_first }}\ 22 | {% endfor %} 23 | {% endfor %}\n 24 | """ 25 | # remove the leading and trailing whitespaces from the template 26 | trim = true 27 | 28 | # changelog footer 29 | footer = """ 30 | 31 | """ 32 | 33 | [git] 34 | # allow only conventional commits 35 | # https://www.conventionalcommits.org 36 | conventional_commits = true 37 | 38 | # regex for parsing and grouping commits 39 | commit_parsers = [ 40 | { message = "^feat", group = "Features"}, 41 | { message = "^fix", group = "Bug Fixes"}, 42 | { message = "^doc", group = "Documentation"}, 43 | { message = "^perf", group = "Performance"}, 44 | { message = "^pkg", group = "Packaging"}, 45 | { message = "^refactor", group = "Refactor"}, 46 | { message = "^edition", group = "Editions"}, 47 | { message = "^style", group = "Styling"}, 48 | { message = "^test", group = "Testing"}, 49 | { message = "^notes", group = "Notes"}, 50 | { message = "^workflow", group = "Workflow"}, 51 | { message = "^ops", group = "Operations"}, 52 | { message = "^infra", group = "Infrastructure"}, 53 | { message = "^chore\\(release\\): prepare for", skip = true}, 54 | { message = "^chore", group = "Miscellaneous Tasks"}, 55 | { message = "^hide", group = "Hidden", skip = true}, 56 | { body = ".*security", group = "Security"}, 57 | ] 58 | 59 | # filter out the commits that are not matched by commit parsers 60 | filter_commits = true 61 | 62 | # glob pattern for matching git tags 63 | tag_pattern = "v[0-9]*" 64 | 65 | # regex for skipping tags 66 | skip_tags = ".*beta.*" 67 | -------------------------------------------------------------------------------- /movies.csv.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/VADOSWARE/fts-benchmark/7b9285bc993394161c235ddc11b99a9600e37fa0/movies.csv.gz -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pg-fts-benchmark", 3 | "version": "0.2.1", 4 | "lockfileVersion": 2, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "pg-fts-benchmark", 9 | "version": "0.2.1", 10 | "dependencies": { 11 | "@babel/runtime": "^7.18.9", 12 | "@opensearch-project/opensearch": "^2.0.0", 13 | "async-wait-for-promise": "^1.2.0", 14 | "better-sqlite3": "^7.6.2", 15 | "meilisearch": "^0.27.0", 16 | "papaparse": "^5.3.2", 17 | "slonik": "^30.3.1", 18 | "typesense": "^1.4.0" 19 | }, 20 | "engines": { 21 | "node": ">=17.4.0" 22 | } 23 | }, 24 | "node_modules/@babel/runtime": { 25 | "version": "7.19.4", 26 | "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.19.4.tgz", 27 | "integrity": "sha512-EXpLCrk55f+cYqmHsSR+yD/0gAIMxxA9QK9lnQWzhMCvt+YmoBN7Zx94s++Kv0+unHk39vxNO8t+CMA2WSS3wA==", 28 | "dependencies": { 29 | "regenerator-runtime": "^0.13.4" 30 | }, 31 | "engines": { 32 | "node": ">=6.9.0" 33 | } 34 | }, 35 | "node_modules/@opensearch-project/opensearch": { 36 | "version": "2.0.0", 37 | "resolved": "https://registry.npmjs.org/@opensearch-project/opensearch/-/opensearch-2.0.0.tgz", 38 | "integrity": "sha512-/5wP76x90clGq0Xw0MbMsml1+PQHpyY+WVqLCzAFNXSFEjSbq+fWrVjH1vX+VZkRQTzKrqNjaUTqYMA9YHRggA==", 39 | "dependencies": { 40 | "debug": "^4.3.1", 41 | "hpagent": "^0.1.1", 42 | "ms": "^2.1.3", 43 | "secure-json-parse": "^2.4.0" 44 | }, 45 | "engines": { 46 | "node": ">=10", 47 | "yarn": "^1.22.10" 48 | } 49 | }, 50 | "node_modules/ajv": { 51 | "version": "6.12.6", 52 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", 53 | "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", 54 | "dependencies": { 55 | "fast-deep-equal": "^3.1.1", 56 | "fast-json-stable-stringify": "^2.0.0", 57 | "json-schema-traverse": "^0.4.1", 58 | "uri-js": "^4.2.2" 59 | }, 60 | "funding": { 61 | "type": "github", 62 | "url": "https://github.com/sponsors/epoberezkin" 63 | } 64 | }, 65 | "node_modules/async-wait-for-promise": { 66 | "version": "1.2.0", 67 | "resolved": "https://registry.npmjs.org/async-wait-for-promise/-/async-wait-for-promise-1.2.0.tgz", 68 | "integrity": "sha512-yD+1pBLFILAxKASOqF0dQbODVr5Mlw2L3l/gs5gNauqH/DiOOl8lOGoV7q1F5v7fS8jNSylt4y9EUtO21NVaxA==", 69 | "engines": { 70 | "node": ">=14.17.0" 71 | } 72 | }, 73 | "node_modules/axios": { 74 | "version": "0.26.1", 75 | "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", 76 | "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", 77 | "dependencies": { 78 | "follow-redirects": "^1.14.8" 79 | } 80 | }, 81 | "node_modules/base64-js": { 82 | "version": "1.5.1", 83 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", 84 | "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", 85 | "funding": [ 86 | { 87 | "type": "github", 88 | "url": "https://github.com/sponsors/feross" 89 | }, 90 | { 91 | "type": "patreon", 92 | "url": "https://www.patreon.com/feross" 93 | }, 94 | { 95 | "type": "consulting", 96 | "url": "https://feross.org/support" 97 | } 98 | ] 99 | }, 100 | "node_modules/better-sqlite3": { 101 | "version": "7.6.2", 102 | "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-7.6.2.tgz", 103 | "integrity": "sha512-S5zIU1Hink2AH4xPsN0W43T1/AJ5jrPh7Oy07ocuW/AKYYY02GWzz9NH0nbSMn/gw6fDZ5jZ1QsHt1BXAwJ6Lg==", 104 | "hasInstallScript": true, 105 | "dependencies": { 106 | "bindings": "^1.5.0", 107 | "prebuild-install": "^7.1.0" 108 | } 109 | }, 110 | "node_modules/bindings": { 111 | "version": "1.5.0", 112 | "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", 113 | "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", 114 | "dependencies": { 115 | "file-uri-to-path": "1.0.0" 116 | } 117 | }, 118 | "node_modules/bl": { 119 | "version": "4.1.0", 120 | "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", 121 | "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", 122 | "dependencies": { 123 | "buffer": "^5.5.0", 124 | "inherits": "^2.0.4", 125 | "readable-stream": "^3.4.0" 126 | } 127 | }, 128 | "node_modules/bluebird": { 129 | "version": "3.7.2", 130 | "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", 131 | "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" 132 | }, 133 | "node_modules/boolean": { 134 | "version": "3.2.0", 135 | "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz", 136 | "integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==" 137 | }, 138 | "node_modules/buffer": { 139 | "version": "5.7.1", 140 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", 141 | "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", 142 | "funding": [ 143 | { 144 | "type": "github", 145 | "url": "https://github.com/sponsors/feross" 146 | }, 147 | { 148 | "type": "patreon", 149 | "url": "https://www.patreon.com/feross" 150 | }, 151 | { 152 | "type": "consulting", 153 | "url": "https://feross.org/support" 154 | } 155 | ], 156 | "dependencies": { 157 | "base64-js": "^1.3.1", 158 | "ieee754": "^1.1.13" 159 | } 160 | }, 161 | "node_modules/buffer-from": { 162 | "version": "1.1.2", 163 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", 164 | "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" 165 | }, 166 | "node_modules/buffer-writer": { 167 | "version": "2.0.0", 168 | "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", 169 | "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==", 170 | "engines": { 171 | "node": ">=4" 172 | } 173 | }, 174 | "node_modules/bufferput": { 175 | "version": "0.1.3", 176 | "resolved": "https://registry.npmjs.org/bufferput/-/bufferput-0.1.3.tgz", 177 | "integrity": "sha512-nmPV88vDNzf0VMU1bdQ4A1oBlRR9y+CXfwWKfyKUgI2ZIkvreNzLMM3tkz0Lapb6f+Cz1V001UWRBsoGVCjqdw==", 178 | "engines": { 179 | "node": ">=0.3.0" 180 | } 181 | }, 182 | "node_modules/chownr": { 183 | "version": "1.1.4", 184 | "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", 185 | "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" 186 | }, 187 | "node_modules/concat-stream": { 188 | "version": "2.0.0", 189 | "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", 190 | "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", 191 | "engines": [ 192 | "node >= 6.0" 193 | ], 194 | "dependencies": { 195 | "buffer-from": "^1.0.0", 196 | "inherits": "^2.0.3", 197 | "readable-stream": "^3.0.2", 198 | "typedarray": "^0.0.6" 199 | } 200 | }, 201 | "node_modules/cross-fetch": { 202 | "version": "3.1.5", 203 | "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", 204 | "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", 205 | "dependencies": { 206 | "node-fetch": "2.6.7" 207 | } 208 | }, 209 | "node_modules/debug": { 210 | "version": "4.3.4", 211 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", 212 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", 213 | "dependencies": { 214 | "ms": "2.1.2" 215 | }, 216 | "engines": { 217 | "node": ">=6.0" 218 | }, 219 | "peerDependenciesMeta": { 220 | "supports-color": { 221 | "optional": true 222 | } 223 | } 224 | }, 225 | "node_modules/debug/node_modules/ms": { 226 | "version": "2.1.2", 227 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 228 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 229 | }, 230 | "node_modules/decompress-response": { 231 | "version": "6.0.0", 232 | "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", 233 | "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", 234 | "dependencies": { 235 | "mimic-response": "^3.1.0" 236 | }, 237 | "engines": { 238 | "node": ">=10" 239 | }, 240 | "funding": { 241 | "url": "https://github.com/sponsors/sindresorhus" 242 | } 243 | }, 244 | "node_modules/deep-extend": { 245 | "version": "0.6.0", 246 | "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", 247 | "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", 248 | "engines": { 249 | "node": ">=4.0.0" 250 | } 251 | }, 252 | "node_modules/deepmerge": { 253 | "version": "4.2.2", 254 | "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", 255 | "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==", 256 | "engines": { 257 | "node": ">=0.10.0" 258 | } 259 | }, 260 | "node_modules/define-properties": { 261 | "version": "1.1.4", 262 | "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", 263 | "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", 264 | "dependencies": { 265 | "has-property-descriptors": "^1.0.0", 266 | "object-keys": "^1.1.1" 267 | }, 268 | "engines": { 269 | "node": ">= 0.4" 270 | }, 271 | "funding": { 272 | "url": "https://github.com/sponsors/ljharb" 273 | } 274 | }, 275 | "node_modules/detect-libc": { 276 | "version": "2.0.1", 277 | "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", 278 | "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", 279 | "engines": { 280 | "node": ">=8" 281 | } 282 | }, 283 | "node_modules/end-of-stream": { 284 | "version": "1.4.4", 285 | "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", 286 | "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", 287 | "dependencies": { 288 | "once": "^1.4.0" 289 | } 290 | }, 291 | "node_modules/es6-error": { 292 | "version": "4.1.1", 293 | "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", 294 | "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==" 295 | }, 296 | "node_modules/expand-template": { 297 | "version": "2.0.3", 298 | "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", 299 | "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", 300 | "engines": { 301 | "node": ">=6" 302 | } 303 | }, 304 | "node_modules/fast-deep-equal": { 305 | "version": "3.1.3", 306 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", 307 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" 308 | }, 309 | "node_modules/fast-json-stable-stringify": { 310 | "version": "2.1.0", 311 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", 312 | "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" 313 | }, 314 | "node_modules/fast-json-stringify": { 315 | "version": "2.7.13", 316 | "resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-2.7.13.tgz", 317 | "integrity": "sha512-ar+hQ4+OIurUGjSJD1anvYSDcUflywhKjfxnsW4TBTD7+u0tJufv6DKRWoQk3vI6YBOWMoz0TQtfbe7dxbQmvA==", 318 | "dependencies": { 319 | "ajv": "^6.11.0", 320 | "deepmerge": "^4.2.2", 321 | "rfdc": "^1.2.0", 322 | "string-similarity": "^4.0.1" 323 | }, 324 | "engines": { 325 | "node": ">= 10.0.0" 326 | } 327 | }, 328 | "node_modules/fast-printf": { 329 | "version": "1.6.9", 330 | "resolved": "https://registry.npmjs.org/fast-printf/-/fast-printf-1.6.9.tgz", 331 | "integrity": "sha512-FChq8hbz65WMj4rstcQsFB0O7Cy++nmbNfLYnD9cYv2cRn8EG6k/MGn9kO/tjO66t09DLDugj3yL+V2o6Qftrg==", 332 | "dependencies": { 333 | "boolean": "^3.1.4" 334 | }, 335 | "engines": { 336 | "node": ">=10.0" 337 | } 338 | }, 339 | "node_modules/fast-safe-stringify": { 340 | "version": "2.1.1", 341 | "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", 342 | "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==" 343 | }, 344 | "node_modules/file-uri-to-path": { 345 | "version": "1.0.0", 346 | "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", 347 | "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" 348 | }, 349 | "node_modules/follow-redirects": { 350 | "version": "1.15.2", 351 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", 352 | "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==", 353 | "funding": [ 354 | { 355 | "type": "individual", 356 | "url": "https://github.com/sponsors/RubenVerborgh" 357 | } 358 | ], 359 | "engines": { 360 | "node": ">=4.0" 361 | }, 362 | "peerDependenciesMeta": { 363 | "debug": { 364 | "optional": true 365 | } 366 | } 367 | }, 368 | "node_modules/fs-constants": { 369 | "version": "1.0.0", 370 | "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", 371 | "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" 372 | }, 373 | "node_modules/function-bind": { 374 | "version": "1.1.1", 375 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 376 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" 377 | }, 378 | "node_modules/get-intrinsic": { 379 | "version": "1.1.3", 380 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", 381 | "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", 382 | "dependencies": { 383 | "function-bind": "^1.1.1", 384 | "has": "^1.0.3", 385 | "has-symbols": "^1.0.3" 386 | }, 387 | "funding": { 388 | "url": "https://github.com/sponsors/ljharb" 389 | } 390 | }, 391 | "node_modules/get-stack-trace": { 392 | "version": "2.1.1", 393 | "resolved": "https://registry.npmjs.org/get-stack-trace/-/get-stack-trace-2.1.1.tgz", 394 | "integrity": "sha512-dhqSDD9lHU/6FvIZ9KbXGmVK6IKr9ZskZtNOUvhlCiONlnqatu4FmAeRbxCfJJVuQ0NWfz6dAbibKQg19B7AmQ==", 395 | "dependencies": { 396 | "bluebird": "^3.7.1", 397 | "source-map": "^0.8.0-beta.0" 398 | }, 399 | "engines": { 400 | "node": ">=8.0" 401 | } 402 | }, 403 | "node_modules/github-from-package": { 404 | "version": "0.0.0", 405 | "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", 406 | "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" 407 | }, 408 | "node_modules/globalthis": { 409 | "version": "1.0.3", 410 | "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", 411 | "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", 412 | "dependencies": { 413 | "define-properties": "^1.1.3" 414 | }, 415 | "engines": { 416 | "node": ">= 0.4" 417 | }, 418 | "funding": { 419 | "url": "https://github.com/sponsors/ljharb" 420 | } 421 | }, 422 | "node_modules/has": { 423 | "version": "1.0.3", 424 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 425 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 426 | "dependencies": { 427 | "function-bind": "^1.1.1" 428 | }, 429 | "engines": { 430 | "node": ">= 0.4.0" 431 | } 432 | }, 433 | "node_modules/has-property-descriptors": { 434 | "version": "1.0.0", 435 | "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", 436 | "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", 437 | "dependencies": { 438 | "get-intrinsic": "^1.1.1" 439 | }, 440 | "funding": { 441 | "url": "https://github.com/sponsors/ljharb" 442 | } 443 | }, 444 | "node_modules/has-symbols": { 445 | "version": "1.0.3", 446 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", 447 | "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", 448 | "engines": { 449 | "node": ">= 0.4" 450 | }, 451 | "funding": { 452 | "url": "https://github.com/sponsors/ljharb" 453 | } 454 | }, 455 | "node_modules/hpagent": { 456 | "version": "0.1.2", 457 | "resolved": "https://registry.npmjs.org/hpagent/-/hpagent-0.1.2.tgz", 458 | "integrity": "sha512-ePqFXHtSQWAFXYmj+JtOTHr84iNrII4/QRlAAPPE+zqnKy4xJo7Ie1Y4kC7AdB+LxLxSTTzBMASsEcy0q8YyvQ==" 459 | }, 460 | "node_modules/hyperid": { 461 | "version": "2.3.1", 462 | "resolved": "https://registry.npmjs.org/hyperid/-/hyperid-2.3.1.tgz", 463 | "integrity": "sha512-mIbI7Ymn6MCdODaW1/6wdf5lvvXzmPsARN4zTLakMmcziBOuP4PxCBJvHF6kbAIHX6H4vAELx/pDmt0j6Th5RQ==", 464 | "dependencies": { 465 | "uuid": "^8.3.2", 466 | "uuid-parse": "^1.1.0" 467 | } 468 | }, 469 | "node_modules/ieee754": { 470 | "version": "1.2.1", 471 | "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", 472 | "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", 473 | "funding": [ 474 | { 475 | "type": "github", 476 | "url": "https://github.com/sponsors/feross" 477 | }, 478 | { 479 | "type": "patreon", 480 | "url": "https://www.patreon.com/feross" 481 | }, 482 | { 483 | "type": "consulting", 484 | "url": "https://feross.org/support" 485 | } 486 | ] 487 | }, 488 | "node_modules/inherits": { 489 | "version": "2.0.4", 490 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 491 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 492 | }, 493 | "node_modules/ini": { 494 | "version": "1.3.8", 495 | "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", 496 | "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" 497 | }, 498 | "node_modules/int64-buffer": { 499 | "version": "0.99.1007", 500 | "resolved": "https://registry.npmjs.org/int64-buffer/-/int64-buffer-0.99.1007.tgz", 501 | "integrity": "sha512-XDBEu44oSTqlvCSiOZ/0FoUkpWu/vwjJLGSKDabNISPQNZ5wub1FodGHBljRsrR0IXRPq7SslshZYMuA55CgTQ==", 502 | "engines": { 503 | "node": ">= 4.5.0" 504 | } 505 | }, 506 | "node_modules/is-plain-object": { 507 | "version": "5.0.0", 508 | "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", 509 | "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==", 510 | "engines": { 511 | "node": ">=0.10.0" 512 | } 513 | }, 514 | "node_modules/iso8601-duration": { 515 | "version": "1.3.0", 516 | "resolved": "https://registry.npmjs.org/iso8601-duration/-/iso8601-duration-1.3.0.tgz", 517 | "integrity": "sha512-K4CiUBzo3YeWk76FuET/dQPH03WE04R94feo5TSKQCXpoXQt9E4yx2CnY737QZnSAI3PI4WlKo/zfqizGx52QQ==" 518 | }, 519 | "node_modules/json-schema-traverse": { 520 | "version": "0.4.1", 521 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 522 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" 523 | }, 524 | "node_modules/lodash.sortby": { 525 | "version": "4.7.0", 526 | "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", 527 | "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==" 528 | }, 529 | "node_modules/loglevel": { 530 | "version": "1.8.0", 531 | "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.8.0.tgz", 532 | "integrity": "sha512-G6A/nJLRgWOuuwdNuA6koovfEV1YpqqAG4pRUlFaz3jj2QNZ8M4vBqnVA+HBTmU/AMNUtlOsMmSpF6NyOjztbA==", 533 | "engines": { 534 | "node": ">= 0.6.0" 535 | }, 536 | "funding": { 537 | "type": "tidelift", 538 | "url": "https://tidelift.com/funding/github/npm/loglevel" 539 | } 540 | }, 541 | "node_modules/lru-cache": { 542 | "version": "6.0.0", 543 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", 544 | "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", 545 | "dependencies": { 546 | "yallist": "^4.0.0" 547 | }, 548 | "engines": { 549 | "node": ">=10" 550 | } 551 | }, 552 | "node_modules/meilisearch": { 553 | "version": "0.27.0", 554 | "resolved": "https://registry.npmjs.org/meilisearch/-/meilisearch-0.27.0.tgz", 555 | "integrity": "sha512-kZOZFIuSO7c6xRf+Y2/9/h6A9pl0sCl/G44X4KuaSwxGbruOZPhmxbeVEgLHBv4pUFvQ56rNVTA/2d/5GCU1YA==", 556 | "dependencies": { 557 | "cross-fetch": "^3.1.5" 558 | } 559 | }, 560 | "node_modules/mimic-response": { 561 | "version": "3.1.0", 562 | "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", 563 | "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", 564 | "engines": { 565 | "node": ">=10" 566 | }, 567 | "funding": { 568 | "url": "https://github.com/sponsors/sindresorhus" 569 | } 570 | }, 571 | "node_modules/minimist": { 572 | "version": "1.2.7", 573 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", 574 | "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==", 575 | "funding": { 576 | "url": "https://github.com/sponsors/ljharb" 577 | } 578 | }, 579 | "node_modules/mkdirp-classic": { 580 | "version": "0.5.3", 581 | "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", 582 | "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" 583 | }, 584 | "node_modules/ms": { 585 | "version": "2.1.3", 586 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 587 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" 588 | }, 589 | "node_modules/multi-fork": { 590 | "version": "0.0.2", 591 | "resolved": "https://registry.npmjs.org/multi-fork/-/multi-fork-0.0.2.tgz", 592 | "integrity": "sha512-SHWGuze0cZNiH+JGJQFlB1k7kZLGFCvW1Xo5Fcpe86KICkC3aVTJWpjUcmyYcLCB0I6gdzKLCia/bTIw2ggl8A==" 593 | }, 594 | "node_modules/napi-build-utils": { 595 | "version": "1.0.2", 596 | "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", 597 | "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" 598 | }, 599 | "node_modules/node-abi": { 600 | "version": "3.26.0", 601 | "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.26.0.tgz", 602 | "integrity": "sha512-jRVtMFTChbi2i/jqo/i2iP9634KMe+7K1v35mIdj3Mn59i5q27ZYhn+sW6npISM/PQg7HrP2kwtRBMmh5Uvzdg==", 603 | "dependencies": { 604 | "semver": "^7.3.5" 605 | }, 606 | "engines": { 607 | "node": ">=10" 608 | } 609 | }, 610 | "node_modules/node-fetch": { 611 | "version": "2.6.7", 612 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", 613 | "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", 614 | "dependencies": { 615 | "whatwg-url": "^5.0.0" 616 | }, 617 | "engines": { 618 | "node": "4.x || >=6.0.0" 619 | }, 620 | "peerDependencies": { 621 | "encoding": "^0.1.0" 622 | }, 623 | "peerDependenciesMeta": { 624 | "encoding": { 625 | "optional": true 626 | } 627 | } 628 | }, 629 | "node_modules/object-keys": { 630 | "version": "1.1.1", 631 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", 632 | "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", 633 | "engines": { 634 | "node": ">= 0.4" 635 | } 636 | }, 637 | "node_modules/obuf": { 638 | "version": "1.1.2", 639 | "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", 640 | "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" 641 | }, 642 | "node_modules/once": { 643 | "version": "1.4.0", 644 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 645 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", 646 | "dependencies": { 647 | "wrappy": "1" 648 | } 649 | }, 650 | "node_modules/p-defer": { 651 | "version": "3.0.0", 652 | "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-3.0.0.tgz", 653 | "integrity": "sha512-ugZxsxmtTln604yeYd29EGrNhazN2lywetzpKhfmQjW/VJmhpDmWbiX+h0zL8V91R0UXkhb3KtPmyq9PZw3aYw==", 654 | "engines": { 655 | "node": ">=8" 656 | } 657 | }, 658 | "node_modules/packet-reader": { 659 | "version": "1.0.0", 660 | "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", 661 | "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" 662 | }, 663 | "node_modules/papaparse": { 664 | "version": "5.3.2", 665 | "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.3.2.tgz", 666 | "integrity": "sha512-6dNZu0Ki+gyV0eBsFKJhYr+MdQYAzFUGlBMNj3GNrmHxmz1lfRa24CjFObPXtjcetlOv5Ad299MhIK0znp3afw==" 667 | }, 668 | "node_modules/pg": { 669 | "version": "8.8.0", 670 | "resolved": "https://registry.npmjs.org/pg/-/pg-8.8.0.tgz", 671 | "integrity": "sha512-UXYN0ziKj+AeNNP7VDMwrehpACThH7LUl/p8TDFpEUuSejCUIwGSfxpHsPvtM6/WXFy6SU4E5RG4IJV/TZAGjw==", 672 | "dependencies": { 673 | "buffer-writer": "2.0.0", 674 | "packet-reader": "1.0.0", 675 | "pg-connection-string": "^2.5.0", 676 | "pg-pool": "^3.5.2", 677 | "pg-protocol": "^1.5.0", 678 | "pg-types": "^2.1.0", 679 | "pgpass": "1.x" 680 | }, 681 | "engines": { 682 | "node": ">= 8.0.0" 683 | }, 684 | "peerDependencies": { 685 | "pg-native": ">=3.0.1" 686 | }, 687 | "peerDependenciesMeta": { 688 | "pg-native": { 689 | "optional": true 690 | } 691 | } 692 | }, 693 | "node_modules/pg-connection-string": { 694 | "version": "2.5.0", 695 | "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz", 696 | "integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==" 697 | }, 698 | "node_modules/pg-copy-streams": { 699 | "version": "6.0.4", 700 | "resolved": "https://registry.npmjs.org/pg-copy-streams/-/pg-copy-streams-6.0.4.tgz", 701 | "integrity": "sha512-FH6q2nFo0n2cFacLyIKorjDz8AOYtxrAANx1XMvYbKWNM2geY731gZstuP4mXMlqO6urRl9oIscFxf3GMIg3Ng==", 702 | "dependencies": { 703 | "obuf": "^1.1.2" 704 | } 705 | }, 706 | "node_modules/pg-copy-streams-binary": { 707 | "version": "2.2.0", 708 | "resolved": "https://registry.npmjs.org/pg-copy-streams-binary/-/pg-copy-streams-binary-2.2.0.tgz", 709 | "integrity": "sha512-jPCWgTR8004wz5XOI2sc09+IMwE7YMeINYCabwPMCPtlgj2ay81VLCClMkj/u+xOeisRcN8vCrIZ4FrqlaTyBQ==", 710 | "dependencies": { 711 | "bl": "^4.0.3", 712 | "bufferput": "^0.1.3", 713 | "ieee754": "^1.1.13", 714 | "int64-buffer": "^0.99.1007", 715 | "multi-fork": "0.0.2", 716 | "through2": "^3.0.1" 717 | } 718 | }, 719 | "node_modules/pg-copy-streams-binary/node_modules/through2": { 720 | "version": "3.0.2", 721 | "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", 722 | "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", 723 | "dependencies": { 724 | "inherits": "^2.0.4", 725 | "readable-stream": "2 || 3" 726 | } 727 | }, 728 | "node_modules/pg-cursor": { 729 | "version": "2.7.4", 730 | "resolved": "https://registry.npmjs.org/pg-cursor/-/pg-cursor-2.7.4.tgz", 731 | "integrity": "sha512-CNWwOzTTZ9QvphoOL+Wg/7pmVr9GnAWBjPbuK2FRclrB4A/WRO/ssCJ9BlkzIGmmofK2M/LyokNHgsLSn+fMHA==", 732 | "peerDependencies": { 733 | "pg": "^8" 734 | } 735 | }, 736 | "node_modules/pg-int8": { 737 | "version": "1.0.1", 738 | "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", 739 | "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", 740 | "engines": { 741 | "node": ">=4.0.0" 742 | } 743 | }, 744 | "node_modules/pg-numeric": { 745 | "version": "1.0.2", 746 | "resolved": "https://registry.npmjs.org/pg-numeric/-/pg-numeric-1.0.2.tgz", 747 | "integrity": "sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==", 748 | "engines": { 749 | "node": ">=4" 750 | } 751 | }, 752 | "node_modules/pg-pool": { 753 | "version": "3.5.2", 754 | "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.5.2.tgz", 755 | "integrity": "sha512-His3Fh17Z4eg7oANLob6ZvH8xIVen3phEZh2QuyrIl4dQSDVEabNducv6ysROKpDNPSD+12tONZVWfSgMvDD9w==", 756 | "peerDependencies": { 757 | "pg": ">=8.0" 758 | } 759 | }, 760 | "node_modules/pg-protocol": { 761 | "version": "1.5.0", 762 | "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.5.0.tgz", 763 | "integrity": "sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ==" 764 | }, 765 | "node_modules/pg-types": { 766 | "version": "4.0.0", 767 | "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-4.0.0.tgz", 768 | "integrity": "sha512-q4I7zG+d2mDg52WdrOA0TmBvab9ZBC8DE8+opl3gSegnH5ml+0pKbICOfRKXgwQ5aa6NRjLoF5pEDs0YpGvFrw==", 769 | "dependencies": { 770 | "pg-int8": "1.0.1", 771 | "pg-numeric": "1.0.2", 772 | "postgres-array": "~3.0.1", 773 | "postgres-bytea": "~3.0.0", 774 | "postgres-date": "~2.0.1", 775 | "postgres-interval": "^3.0.0", 776 | "postgres-range": "^1.1.1" 777 | }, 778 | "engines": { 779 | "node": ">=10" 780 | } 781 | }, 782 | "node_modules/pg-types/node_modules/postgres-interval": { 783 | "version": "3.0.0", 784 | "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-3.0.0.tgz", 785 | "integrity": "sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==", 786 | "engines": { 787 | "node": ">=12" 788 | } 789 | }, 790 | "node_modules/pg/node_modules/pg-types": { 791 | "version": "2.2.0", 792 | "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", 793 | "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", 794 | "dependencies": { 795 | "pg-int8": "1.0.1", 796 | "postgres-array": "~2.0.0", 797 | "postgres-bytea": "~1.0.0", 798 | "postgres-date": "~1.0.4", 799 | "postgres-interval": "^1.1.0" 800 | }, 801 | "engines": { 802 | "node": ">=4" 803 | } 804 | }, 805 | "node_modules/pg/node_modules/postgres-array": { 806 | "version": "2.0.0", 807 | "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", 808 | "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", 809 | "engines": { 810 | "node": ">=4" 811 | } 812 | }, 813 | "node_modules/pg/node_modules/postgres-bytea": { 814 | "version": "1.0.0", 815 | "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", 816 | "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==", 817 | "engines": { 818 | "node": ">=0.10.0" 819 | } 820 | }, 821 | "node_modules/pg/node_modules/postgres-date": { 822 | "version": "1.0.7", 823 | "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", 824 | "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", 825 | "engines": { 826 | "node": ">=0.10.0" 827 | } 828 | }, 829 | "node_modules/pg/node_modules/postgres-interval": { 830 | "version": "1.2.0", 831 | "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", 832 | "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", 833 | "dependencies": { 834 | "xtend": "^4.0.0" 835 | }, 836 | "engines": { 837 | "node": ">=0.10.0" 838 | } 839 | }, 840 | "node_modules/pgpass": { 841 | "version": "1.0.5", 842 | "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", 843 | "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", 844 | "dependencies": { 845 | "split2": "^4.1.0" 846 | } 847 | }, 848 | "node_modules/postgres-array": { 849 | "version": "3.0.1", 850 | "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-3.0.1.tgz", 851 | "integrity": "sha512-h7i53Dw2Yq3a1uuZ6lbVFAkvMMwssJ8jkzeAg0XaZm1XIFF/t/s+tockdqbWTymyEm07dVenOQbFisEi+kj8uA==", 852 | "engines": { 853 | "node": ">=12" 854 | } 855 | }, 856 | "node_modules/postgres-bytea": { 857 | "version": "3.0.0", 858 | "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-3.0.0.tgz", 859 | "integrity": "sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==", 860 | "dependencies": { 861 | "obuf": "~1.1.2" 862 | }, 863 | "engines": { 864 | "node": ">= 6" 865 | } 866 | }, 867 | "node_modules/postgres-date": { 868 | "version": "2.0.1", 869 | "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-2.0.1.tgz", 870 | "integrity": "sha512-YtMKdsDt5Ojv1wQRvUhnyDJNSr2dGIC96mQVKz7xufp07nfuFONzdaowrMHjlAzY6GDLd4f+LUHHAAM1h4MdUw==", 871 | "engines": { 872 | "node": ">=12" 873 | } 874 | }, 875 | "node_modules/postgres-interval": { 876 | "version": "4.0.0", 877 | "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-4.0.0.tgz", 878 | "integrity": "sha512-OWeL7kyEKJiY7mCmVY+c7/6uhAlt/colA/Nl/Mgls/M3jssrQzFra04iNWnD/qAmG7TsCSgWAASCyiaoBOP/sg==", 879 | "engines": { 880 | "node": ">=12" 881 | } 882 | }, 883 | "node_modules/postgres-range": { 884 | "version": "1.1.3", 885 | "resolved": "https://registry.npmjs.org/postgres-range/-/postgres-range-1.1.3.tgz", 886 | "integrity": "sha512-VdlZoocy5lCP0c/t66xAfclglEapXPCIVhqqJRncYpvbCgImF0w67aPKfbqUMr72tO2k5q0TdTZwCLjPTI6C9g==" 887 | }, 888 | "node_modules/prebuild-install": { 889 | "version": "7.1.1", 890 | "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", 891 | "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", 892 | "dependencies": { 893 | "detect-libc": "^2.0.0", 894 | "expand-template": "^2.0.3", 895 | "github-from-package": "0.0.0", 896 | "minimist": "^1.2.3", 897 | "mkdirp-classic": "^0.5.3", 898 | "napi-build-utils": "^1.0.1", 899 | "node-abi": "^3.3.0", 900 | "pump": "^3.0.0", 901 | "rc": "^1.2.7", 902 | "simple-get": "^4.0.0", 903 | "tar-fs": "^2.0.0", 904 | "tunnel-agent": "^0.6.0" 905 | }, 906 | "bin": { 907 | "prebuild-install": "bin.js" 908 | }, 909 | "engines": { 910 | "node": ">=10" 911 | } 912 | }, 913 | "node_modules/pump": { 914 | "version": "3.0.0", 915 | "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", 916 | "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", 917 | "dependencies": { 918 | "end-of-stream": "^1.1.0", 919 | "once": "^1.3.1" 920 | } 921 | }, 922 | "node_modules/punycode": { 923 | "version": "2.1.1", 924 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", 925 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", 926 | "engines": { 927 | "node": ">=6" 928 | } 929 | }, 930 | "node_modules/rc": { 931 | "version": "1.2.8", 932 | "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", 933 | "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", 934 | "dependencies": { 935 | "deep-extend": "^0.6.0", 936 | "ini": "~1.3.0", 937 | "minimist": "^1.2.0", 938 | "strip-json-comments": "~2.0.1" 939 | }, 940 | "bin": { 941 | "rc": "cli.js" 942 | } 943 | }, 944 | "node_modules/readable-stream": { 945 | "version": "3.6.0", 946 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", 947 | "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", 948 | "dependencies": { 949 | "inherits": "^2.0.3", 950 | "string_decoder": "^1.1.1", 951 | "util-deprecate": "^1.0.1" 952 | }, 953 | "engines": { 954 | "node": ">= 6" 955 | } 956 | }, 957 | "node_modules/regenerator-runtime": { 958 | "version": "0.13.10", 959 | "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.10.tgz", 960 | "integrity": "sha512-KepLsg4dU12hryUO7bp/axHAKvwGOCV0sGloQtpagJ12ai+ojVDqkeGSiRX1zlq+kjIMZ1t7gpze+26QqtdGqw==" 961 | }, 962 | "node_modules/rfdc": { 963 | "version": "1.3.0", 964 | "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", 965 | "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==" 966 | }, 967 | "node_modules/roarr": { 968 | "version": "7.13.0", 969 | "resolved": "https://registry.npmjs.org/roarr/-/roarr-7.13.0.tgz", 970 | "integrity": "sha512-NA7ikXPPxjGv/51R9pYd3G4f9nq0x6zLe9XPzbm3l+efBnckO2Lsac4KB6NRfoBzAKvLE5Lh8J5Fsm3IdHycuA==", 971 | "dependencies": { 972 | "boolean": "^3.1.4", 973 | "fast-json-stringify": "^2.7.10", 974 | "fast-printf": "^1.6.9", 975 | "fast-safe-stringify": "^2.1.1", 976 | "globalthis": "^1.0.2", 977 | "semver-compare": "^1.0.0" 978 | }, 979 | "engines": { 980 | "node": ">=12.0" 981 | } 982 | }, 983 | "node_modules/safe-buffer": { 984 | "version": "5.2.1", 985 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 986 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", 987 | "funding": [ 988 | { 989 | "type": "github", 990 | "url": "https://github.com/sponsors/feross" 991 | }, 992 | { 993 | "type": "patreon", 994 | "url": "https://www.patreon.com/feross" 995 | }, 996 | { 997 | "type": "consulting", 998 | "url": "https://feross.org/support" 999 | } 1000 | ] 1001 | }, 1002 | "node_modules/secure-json-parse": { 1003 | "version": "2.5.0", 1004 | "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.5.0.tgz", 1005 | "integrity": "sha512-ZQruFgZnIWH+WyO9t5rWt4ZEGqCKPwhiw+YbzTwpmT9elgLrLcfuyUiSnwwjUiVy9r4VM3urtbNF1xmEh9IL2w==" 1006 | }, 1007 | "node_modules/semver": { 1008 | "version": "7.3.8", 1009 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", 1010 | "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", 1011 | "dependencies": { 1012 | "lru-cache": "^6.0.0" 1013 | }, 1014 | "bin": { 1015 | "semver": "bin/semver.js" 1016 | }, 1017 | "engines": { 1018 | "node": ">=10" 1019 | } 1020 | }, 1021 | "node_modules/semver-compare": { 1022 | "version": "1.0.0", 1023 | "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", 1024 | "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==" 1025 | }, 1026 | "node_modules/serialize-error": { 1027 | "version": "8.1.0", 1028 | "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-8.1.0.tgz", 1029 | "integrity": "sha512-3NnuWfM6vBYoy5gZFvHiYsVbafvI9vZv/+jlIigFn4oP4zjNPK3LhcY0xSCgeb1a5L8jO71Mit9LlNoi2UfDDQ==", 1030 | "dependencies": { 1031 | "type-fest": "^0.20.2" 1032 | }, 1033 | "engines": { 1034 | "node": ">=10" 1035 | }, 1036 | "funding": { 1037 | "url": "https://github.com/sponsors/sindresorhus" 1038 | } 1039 | }, 1040 | "node_modules/simple-concat": { 1041 | "version": "1.0.1", 1042 | "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", 1043 | "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", 1044 | "funding": [ 1045 | { 1046 | "type": "github", 1047 | "url": "https://github.com/sponsors/feross" 1048 | }, 1049 | { 1050 | "type": "patreon", 1051 | "url": "https://www.patreon.com/feross" 1052 | }, 1053 | { 1054 | "type": "consulting", 1055 | "url": "https://feross.org/support" 1056 | } 1057 | ] 1058 | }, 1059 | "node_modules/simple-get": { 1060 | "version": "4.0.1", 1061 | "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", 1062 | "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", 1063 | "funding": [ 1064 | { 1065 | "type": "github", 1066 | "url": "https://github.com/sponsors/feross" 1067 | }, 1068 | { 1069 | "type": "patreon", 1070 | "url": "https://www.patreon.com/feross" 1071 | }, 1072 | { 1073 | "type": "consulting", 1074 | "url": "https://feross.org/support" 1075 | } 1076 | ], 1077 | "dependencies": { 1078 | "decompress-response": "^6.0.0", 1079 | "once": "^1.3.1", 1080 | "simple-concat": "^1.0.0" 1081 | } 1082 | }, 1083 | "node_modules/slonik": { 1084 | "version": "30.4.4", 1085 | "resolved": "https://registry.npmjs.org/slonik/-/slonik-30.4.4.tgz", 1086 | "integrity": "sha512-5Z1QJhRCDyq0J+0yiUN6COETKtvrYdmukeQn5RZUSt7EvzYo4oTm7D4j2ZV4DN0DMHsaQBSnW/tIgX+UHRJYmQ==", 1087 | "dependencies": { 1088 | "concat-stream": "^2.0.0", 1089 | "es6-error": "^4.1.1", 1090 | "fast-safe-stringify": "^2.1.1", 1091 | "get-stack-trace": "^2.1.1", 1092 | "hyperid": "^2.3.1", 1093 | "is-plain-object": "^5.0.0", 1094 | "iso8601-duration": "^1.3.0", 1095 | "p-defer": "^3.0.0", 1096 | "pg": "^8.7.3", 1097 | "pg-copy-streams": "^6.0.2", 1098 | "pg-copy-streams-binary": "^2.2.0", 1099 | "pg-cursor": "^2.7.3", 1100 | "pg-protocol": "^1.5.0", 1101 | "pg-types": "^4.0.0", 1102 | "postgres-array": "^3.0.1", 1103 | "postgres-interval": "^4.0.0", 1104 | "roarr": "^7.11.0", 1105 | "serialize-error": "^8.0.0", 1106 | "through2": "^4.0.2", 1107 | "zod": "^3.18.0" 1108 | }, 1109 | "engines": { 1110 | "node": ">=10.0" 1111 | } 1112 | }, 1113 | "node_modules/source-map": { 1114 | "version": "0.8.0-beta.0", 1115 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", 1116 | "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", 1117 | "dependencies": { 1118 | "whatwg-url": "^7.0.0" 1119 | }, 1120 | "engines": { 1121 | "node": ">= 8" 1122 | } 1123 | }, 1124 | "node_modules/source-map/node_modules/tr46": { 1125 | "version": "1.0.1", 1126 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", 1127 | "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", 1128 | "dependencies": { 1129 | "punycode": "^2.1.0" 1130 | } 1131 | }, 1132 | "node_modules/source-map/node_modules/webidl-conversions": { 1133 | "version": "4.0.2", 1134 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", 1135 | "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" 1136 | }, 1137 | "node_modules/source-map/node_modules/whatwg-url": { 1138 | "version": "7.1.0", 1139 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", 1140 | "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", 1141 | "dependencies": { 1142 | "lodash.sortby": "^4.7.0", 1143 | "tr46": "^1.0.1", 1144 | "webidl-conversions": "^4.0.2" 1145 | } 1146 | }, 1147 | "node_modules/split2": { 1148 | "version": "4.1.0", 1149 | "resolved": "https://registry.npmjs.org/split2/-/split2-4.1.0.tgz", 1150 | "integrity": "sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==", 1151 | "engines": { 1152 | "node": ">= 10.x" 1153 | } 1154 | }, 1155 | "node_modules/string_decoder": { 1156 | "version": "1.3.0", 1157 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", 1158 | "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", 1159 | "dependencies": { 1160 | "safe-buffer": "~5.2.0" 1161 | } 1162 | }, 1163 | "node_modules/string-similarity": { 1164 | "version": "4.0.4", 1165 | "resolved": "https://registry.npmjs.org/string-similarity/-/string-similarity-4.0.4.tgz", 1166 | "integrity": "sha512-/q/8Q4Bl4ZKAPjj8WerIBJWALKkaPRfrvhfF8k/B23i4nzrlRj2/go1m90In7nG/3XDSbOo0+pu6RvCTM9RGMQ==" 1167 | }, 1168 | "node_modules/strip-json-comments": { 1169 | "version": "2.0.1", 1170 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", 1171 | "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", 1172 | "engines": { 1173 | "node": ">=0.10.0" 1174 | } 1175 | }, 1176 | "node_modules/tar-fs": { 1177 | "version": "2.1.1", 1178 | "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", 1179 | "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", 1180 | "dependencies": { 1181 | "chownr": "^1.1.1", 1182 | "mkdirp-classic": "^0.5.2", 1183 | "pump": "^3.0.0", 1184 | "tar-stream": "^2.1.4" 1185 | } 1186 | }, 1187 | "node_modules/tar-stream": { 1188 | "version": "2.2.0", 1189 | "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", 1190 | "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", 1191 | "dependencies": { 1192 | "bl": "^4.0.3", 1193 | "end-of-stream": "^1.4.1", 1194 | "fs-constants": "^1.0.0", 1195 | "inherits": "^2.0.3", 1196 | "readable-stream": "^3.1.1" 1197 | }, 1198 | "engines": { 1199 | "node": ">=6" 1200 | } 1201 | }, 1202 | "node_modules/through2": { 1203 | "version": "4.0.2", 1204 | "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", 1205 | "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", 1206 | "dependencies": { 1207 | "readable-stream": "3" 1208 | } 1209 | }, 1210 | "node_modules/tr46": { 1211 | "version": "0.0.3", 1212 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", 1213 | "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" 1214 | }, 1215 | "node_modules/tunnel-agent": { 1216 | "version": "0.6.0", 1217 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", 1218 | "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", 1219 | "dependencies": { 1220 | "safe-buffer": "^5.0.1" 1221 | }, 1222 | "engines": { 1223 | "node": "*" 1224 | } 1225 | }, 1226 | "node_modules/type-fest": { 1227 | "version": "0.20.2", 1228 | "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", 1229 | "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", 1230 | "engines": { 1231 | "node": ">=10" 1232 | }, 1233 | "funding": { 1234 | "url": "https://github.com/sponsors/sindresorhus" 1235 | } 1236 | }, 1237 | "node_modules/typedarray": { 1238 | "version": "0.0.6", 1239 | "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", 1240 | "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" 1241 | }, 1242 | "node_modules/typesense": { 1243 | "version": "1.4.1", 1244 | "resolved": "https://registry.npmjs.org/typesense/-/typesense-1.4.1.tgz", 1245 | "integrity": "sha512-M+3UCEohGA2IIOVVwXazFjx4iu8PtJJ3rm0D9mtYS/FxvPstA6OI9OH9kKpqRwry6hRyMWtcBF3BrN5aljhk/g==", 1246 | "dependencies": { 1247 | "axios": "^0.26.0", 1248 | "loglevel": "^1.8.0" 1249 | }, 1250 | "peerDependencies": { 1251 | "@babel/runtime": "^7.17.2" 1252 | } 1253 | }, 1254 | "node_modules/uri-js": { 1255 | "version": "4.4.1", 1256 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", 1257 | "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", 1258 | "dependencies": { 1259 | "punycode": "^2.1.0" 1260 | } 1261 | }, 1262 | "node_modules/util-deprecate": { 1263 | "version": "1.0.2", 1264 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 1265 | "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" 1266 | }, 1267 | "node_modules/uuid": { 1268 | "version": "8.3.2", 1269 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", 1270 | "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", 1271 | "bin": { 1272 | "uuid": "dist/bin/uuid" 1273 | } 1274 | }, 1275 | "node_modules/uuid-parse": { 1276 | "version": "1.1.0", 1277 | "resolved": "https://registry.npmjs.org/uuid-parse/-/uuid-parse-1.1.0.tgz", 1278 | "integrity": "sha512-OdmXxA8rDsQ7YpNVbKSJkNzTw2I+S5WsbMDnCtIWSQaosNAcWtFuI/YK1TjzUI6nbkgiqEyh8gWngfcv8Asd9A==" 1279 | }, 1280 | "node_modules/webidl-conversions": { 1281 | "version": "3.0.1", 1282 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", 1283 | "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" 1284 | }, 1285 | "node_modules/whatwg-url": { 1286 | "version": "5.0.0", 1287 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", 1288 | "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", 1289 | "dependencies": { 1290 | "tr46": "~0.0.3", 1291 | "webidl-conversions": "^3.0.0" 1292 | } 1293 | }, 1294 | "node_modules/wrappy": { 1295 | "version": "1.0.2", 1296 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 1297 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" 1298 | }, 1299 | "node_modules/xtend": { 1300 | "version": "4.0.2", 1301 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", 1302 | "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", 1303 | "engines": { 1304 | "node": ">=0.4" 1305 | } 1306 | }, 1307 | "node_modules/yallist": { 1308 | "version": "4.0.0", 1309 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", 1310 | "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" 1311 | }, 1312 | "node_modules/zod": { 1313 | "version": "3.19.1", 1314 | "resolved": "https://registry.npmjs.org/zod/-/zod-3.19.1.tgz", 1315 | "integrity": "sha512-LYjZsEDhCdYET9ikFu6dVPGp2YH9DegXjdJToSzD9rO6fy4qiRYFoyEYwps88OseJlPyl2NOe2iJuhEhL7IpEA==", 1316 | "funding": { 1317 | "url": "https://github.com/sponsors/colinhacks" 1318 | } 1319 | } 1320 | }, 1321 | "dependencies": { 1322 | "@babel/runtime": { 1323 | "version": "7.19.4", 1324 | "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.19.4.tgz", 1325 | "integrity": "sha512-EXpLCrk55f+cYqmHsSR+yD/0gAIMxxA9QK9lnQWzhMCvt+YmoBN7Zx94s++Kv0+unHk39vxNO8t+CMA2WSS3wA==", 1326 | "requires": { 1327 | "regenerator-runtime": "^0.13.4" 1328 | } 1329 | }, 1330 | "@opensearch-project/opensearch": { 1331 | "version": "2.0.0", 1332 | "resolved": "https://registry.npmjs.org/@opensearch-project/opensearch/-/opensearch-2.0.0.tgz", 1333 | "integrity": "sha512-/5wP76x90clGq0Xw0MbMsml1+PQHpyY+WVqLCzAFNXSFEjSbq+fWrVjH1vX+VZkRQTzKrqNjaUTqYMA9YHRggA==", 1334 | "requires": { 1335 | "debug": "^4.3.1", 1336 | "hpagent": "^0.1.1", 1337 | "ms": "^2.1.3", 1338 | "secure-json-parse": "^2.4.0" 1339 | } 1340 | }, 1341 | "ajv": { 1342 | "version": "6.12.6", 1343 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", 1344 | "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", 1345 | "requires": { 1346 | "fast-deep-equal": "^3.1.1", 1347 | "fast-json-stable-stringify": "^2.0.0", 1348 | "json-schema-traverse": "^0.4.1", 1349 | "uri-js": "^4.2.2" 1350 | } 1351 | }, 1352 | "async-wait-for-promise": { 1353 | "version": "1.2.0", 1354 | "resolved": "https://registry.npmjs.org/async-wait-for-promise/-/async-wait-for-promise-1.2.0.tgz", 1355 | "integrity": "sha512-yD+1pBLFILAxKASOqF0dQbODVr5Mlw2L3l/gs5gNauqH/DiOOl8lOGoV7q1F5v7fS8jNSylt4y9EUtO21NVaxA==" 1356 | }, 1357 | "axios": { 1358 | "version": "0.26.1", 1359 | "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", 1360 | "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", 1361 | "requires": { 1362 | "follow-redirects": "^1.14.8" 1363 | } 1364 | }, 1365 | "base64-js": { 1366 | "version": "1.5.1", 1367 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", 1368 | "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" 1369 | }, 1370 | "better-sqlite3": { 1371 | "version": "7.6.2", 1372 | "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-7.6.2.tgz", 1373 | "integrity": "sha512-S5zIU1Hink2AH4xPsN0W43T1/AJ5jrPh7Oy07ocuW/AKYYY02GWzz9NH0nbSMn/gw6fDZ5jZ1QsHt1BXAwJ6Lg==", 1374 | "requires": { 1375 | "bindings": "^1.5.0", 1376 | "prebuild-install": "^7.1.0" 1377 | } 1378 | }, 1379 | "bindings": { 1380 | "version": "1.5.0", 1381 | "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", 1382 | "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", 1383 | "requires": { 1384 | "file-uri-to-path": "1.0.0" 1385 | } 1386 | }, 1387 | "bl": { 1388 | "version": "4.1.0", 1389 | "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", 1390 | "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", 1391 | "requires": { 1392 | "buffer": "^5.5.0", 1393 | "inherits": "^2.0.4", 1394 | "readable-stream": "^3.4.0" 1395 | } 1396 | }, 1397 | "bluebird": { 1398 | "version": "3.7.2", 1399 | "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", 1400 | "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" 1401 | }, 1402 | "boolean": { 1403 | "version": "3.2.0", 1404 | "resolved": "https://registry.npmjs.org/boolean/-/boolean-3.2.0.tgz", 1405 | "integrity": "sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==" 1406 | }, 1407 | "buffer": { 1408 | "version": "5.7.1", 1409 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", 1410 | "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", 1411 | "requires": { 1412 | "base64-js": "^1.3.1", 1413 | "ieee754": "^1.1.13" 1414 | } 1415 | }, 1416 | "buffer-from": { 1417 | "version": "1.1.2", 1418 | "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", 1419 | "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==" 1420 | }, 1421 | "buffer-writer": { 1422 | "version": "2.0.0", 1423 | "resolved": "https://registry.npmjs.org/buffer-writer/-/buffer-writer-2.0.0.tgz", 1424 | "integrity": "sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==" 1425 | }, 1426 | "bufferput": { 1427 | "version": "0.1.3", 1428 | "resolved": "https://registry.npmjs.org/bufferput/-/bufferput-0.1.3.tgz", 1429 | "integrity": "sha512-nmPV88vDNzf0VMU1bdQ4A1oBlRR9y+CXfwWKfyKUgI2ZIkvreNzLMM3tkz0Lapb6f+Cz1V001UWRBsoGVCjqdw==" 1430 | }, 1431 | "chownr": { 1432 | "version": "1.1.4", 1433 | "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", 1434 | "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" 1435 | }, 1436 | "concat-stream": { 1437 | "version": "2.0.0", 1438 | "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", 1439 | "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", 1440 | "requires": { 1441 | "buffer-from": "^1.0.0", 1442 | "inherits": "^2.0.3", 1443 | "readable-stream": "^3.0.2", 1444 | "typedarray": "^0.0.6" 1445 | } 1446 | }, 1447 | "cross-fetch": { 1448 | "version": "3.1.5", 1449 | "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz", 1450 | "integrity": "sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==", 1451 | "requires": { 1452 | "node-fetch": "2.6.7" 1453 | } 1454 | }, 1455 | "debug": { 1456 | "version": "4.3.4", 1457 | "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", 1458 | "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", 1459 | "requires": { 1460 | "ms": "2.1.2" 1461 | }, 1462 | "dependencies": { 1463 | "ms": { 1464 | "version": "2.1.2", 1465 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", 1466 | "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" 1467 | } 1468 | } 1469 | }, 1470 | "decompress-response": { 1471 | "version": "6.0.0", 1472 | "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", 1473 | "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", 1474 | "requires": { 1475 | "mimic-response": "^3.1.0" 1476 | } 1477 | }, 1478 | "deep-extend": { 1479 | "version": "0.6.0", 1480 | "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", 1481 | "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==" 1482 | }, 1483 | "deepmerge": { 1484 | "version": "4.2.2", 1485 | "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", 1486 | "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==" 1487 | }, 1488 | "define-properties": { 1489 | "version": "1.1.4", 1490 | "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.4.tgz", 1491 | "integrity": "sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==", 1492 | "requires": { 1493 | "has-property-descriptors": "^1.0.0", 1494 | "object-keys": "^1.1.1" 1495 | } 1496 | }, 1497 | "detect-libc": { 1498 | "version": "2.0.1", 1499 | "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", 1500 | "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==" 1501 | }, 1502 | "end-of-stream": { 1503 | "version": "1.4.4", 1504 | "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", 1505 | "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", 1506 | "requires": { 1507 | "once": "^1.4.0" 1508 | } 1509 | }, 1510 | "es6-error": { 1511 | "version": "4.1.1", 1512 | "resolved": "https://registry.npmjs.org/es6-error/-/es6-error-4.1.1.tgz", 1513 | "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==" 1514 | }, 1515 | "expand-template": { 1516 | "version": "2.0.3", 1517 | "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", 1518 | "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==" 1519 | }, 1520 | "fast-deep-equal": { 1521 | "version": "3.1.3", 1522 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", 1523 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" 1524 | }, 1525 | "fast-json-stable-stringify": { 1526 | "version": "2.1.0", 1527 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", 1528 | "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" 1529 | }, 1530 | "fast-json-stringify": { 1531 | "version": "2.7.13", 1532 | "resolved": "https://registry.npmjs.org/fast-json-stringify/-/fast-json-stringify-2.7.13.tgz", 1533 | "integrity": "sha512-ar+hQ4+OIurUGjSJD1anvYSDcUflywhKjfxnsW4TBTD7+u0tJufv6DKRWoQk3vI6YBOWMoz0TQtfbe7dxbQmvA==", 1534 | "requires": { 1535 | "ajv": "^6.11.0", 1536 | "deepmerge": "^4.2.2", 1537 | "rfdc": "^1.2.0", 1538 | "string-similarity": "^4.0.1" 1539 | } 1540 | }, 1541 | "fast-printf": { 1542 | "version": "1.6.9", 1543 | "resolved": "https://registry.npmjs.org/fast-printf/-/fast-printf-1.6.9.tgz", 1544 | "integrity": "sha512-FChq8hbz65WMj4rstcQsFB0O7Cy++nmbNfLYnD9cYv2cRn8EG6k/MGn9kO/tjO66t09DLDugj3yL+V2o6Qftrg==", 1545 | "requires": { 1546 | "boolean": "^3.1.4" 1547 | } 1548 | }, 1549 | "fast-safe-stringify": { 1550 | "version": "2.1.1", 1551 | "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", 1552 | "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==" 1553 | }, 1554 | "file-uri-to-path": { 1555 | "version": "1.0.0", 1556 | "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", 1557 | "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" 1558 | }, 1559 | "follow-redirects": { 1560 | "version": "1.15.2", 1561 | "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz", 1562 | "integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==" 1563 | }, 1564 | "fs-constants": { 1565 | "version": "1.0.0", 1566 | "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", 1567 | "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" 1568 | }, 1569 | "function-bind": { 1570 | "version": "1.1.1", 1571 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 1572 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" 1573 | }, 1574 | "get-intrinsic": { 1575 | "version": "1.1.3", 1576 | "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.3.tgz", 1577 | "integrity": "sha512-QJVz1Tj7MS099PevUG5jvnt9tSkXN8K14dxQlikJuPt4uD9hHAHjLyLBiLR5zELelBdD9QNRAXZzsJx0WaDL9A==", 1578 | "requires": { 1579 | "function-bind": "^1.1.1", 1580 | "has": "^1.0.3", 1581 | "has-symbols": "^1.0.3" 1582 | } 1583 | }, 1584 | "get-stack-trace": { 1585 | "version": "2.1.1", 1586 | "resolved": "https://registry.npmjs.org/get-stack-trace/-/get-stack-trace-2.1.1.tgz", 1587 | "integrity": "sha512-dhqSDD9lHU/6FvIZ9KbXGmVK6IKr9ZskZtNOUvhlCiONlnqatu4FmAeRbxCfJJVuQ0NWfz6dAbibKQg19B7AmQ==", 1588 | "requires": { 1589 | "bluebird": "^3.7.1", 1590 | "source-map": "^0.8.0-beta.0" 1591 | } 1592 | }, 1593 | "github-from-package": { 1594 | "version": "0.0.0", 1595 | "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", 1596 | "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==" 1597 | }, 1598 | "globalthis": { 1599 | "version": "1.0.3", 1600 | "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", 1601 | "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", 1602 | "requires": { 1603 | "define-properties": "^1.1.3" 1604 | } 1605 | }, 1606 | "has": { 1607 | "version": "1.0.3", 1608 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 1609 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 1610 | "requires": { 1611 | "function-bind": "^1.1.1" 1612 | } 1613 | }, 1614 | "has-property-descriptors": { 1615 | "version": "1.0.0", 1616 | "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz", 1617 | "integrity": "sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==", 1618 | "requires": { 1619 | "get-intrinsic": "^1.1.1" 1620 | } 1621 | }, 1622 | "has-symbols": { 1623 | "version": "1.0.3", 1624 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", 1625 | "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" 1626 | }, 1627 | "hpagent": { 1628 | "version": "0.1.2", 1629 | "resolved": "https://registry.npmjs.org/hpagent/-/hpagent-0.1.2.tgz", 1630 | "integrity": "sha512-ePqFXHtSQWAFXYmj+JtOTHr84iNrII4/QRlAAPPE+zqnKy4xJo7Ie1Y4kC7AdB+LxLxSTTzBMASsEcy0q8YyvQ==" 1631 | }, 1632 | "hyperid": { 1633 | "version": "2.3.1", 1634 | "resolved": "https://registry.npmjs.org/hyperid/-/hyperid-2.3.1.tgz", 1635 | "integrity": "sha512-mIbI7Ymn6MCdODaW1/6wdf5lvvXzmPsARN4zTLakMmcziBOuP4PxCBJvHF6kbAIHX6H4vAELx/pDmt0j6Th5RQ==", 1636 | "requires": { 1637 | "uuid": "^8.3.2", 1638 | "uuid-parse": "^1.1.0" 1639 | } 1640 | }, 1641 | "ieee754": { 1642 | "version": "1.2.1", 1643 | "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", 1644 | "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" 1645 | }, 1646 | "inherits": { 1647 | "version": "2.0.4", 1648 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", 1649 | "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" 1650 | }, 1651 | "ini": { 1652 | "version": "1.3.8", 1653 | "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", 1654 | "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==" 1655 | }, 1656 | "int64-buffer": { 1657 | "version": "0.99.1007", 1658 | "resolved": "https://registry.npmjs.org/int64-buffer/-/int64-buffer-0.99.1007.tgz", 1659 | "integrity": "sha512-XDBEu44oSTqlvCSiOZ/0FoUkpWu/vwjJLGSKDabNISPQNZ5wub1FodGHBljRsrR0IXRPq7SslshZYMuA55CgTQ==" 1660 | }, 1661 | "is-plain-object": { 1662 | "version": "5.0.0", 1663 | "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz", 1664 | "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==" 1665 | }, 1666 | "iso8601-duration": { 1667 | "version": "1.3.0", 1668 | "resolved": "https://registry.npmjs.org/iso8601-duration/-/iso8601-duration-1.3.0.tgz", 1669 | "integrity": "sha512-K4CiUBzo3YeWk76FuET/dQPH03WE04R94feo5TSKQCXpoXQt9E4yx2CnY737QZnSAI3PI4WlKo/zfqizGx52QQ==" 1670 | }, 1671 | "json-schema-traverse": { 1672 | "version": "0.4.1", 1673 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 1674 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" 1675 | }, 1676 | "lodash.sortby": { 1677 | "version": "4.7.0", 1678 | "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", 1679 | "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==" 1680 | }, 1681 | "loglevel": { 1682 | "version": "1.8.0", 1683 | "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.8.0.tgz", 1684 | "integrity": "sha512-G6A/nJLRgWOuuwdNuA6koovfEV1YpqqAG4pRUlFaz3jj2QNZ8M4vBqnVA+HBTmU/AMNUtlOsMmSpF6NyOjztbA==" 1685 | }, 1686 | "lru-cache": { 1687 | "version": "6.0.0", 1688 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", 1689 | "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", 1690 | "requires": { 1691 | "yallist": "^4.0.0" 1692 | } 1693 | }, 1694 | "meilisearch": { 1695 | "version": "0.27.0", 1696 | "resolved": "https://registry.npmjs.org/meilisearch/-/meilisearch-0.27.0.tgz", 1697 | "integrity": "sha512-kZOZFIuSO7c6xRf+Y2/9/h6A9pl0sCl/G44X4KuaSwxGbruOZPhmxbeVEgLHBv4pUFvQ56rNVTA/2d/5GCU1YA==", 1698 | "requires": { 1699 | "cross-fetch": "^3.1.5" 1700 | } 1701 | }, 1702 | "mimic-response": { 1703 | "version": "3.1.0", 1704 | "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", 1705 | "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==" 1706 | }, 1707 | "minimist": { 1708 | "version": "1.2.7", 1709 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.7.tgz", 1710 | "integrity": "sha512-bzfL1YUZsP41gmu/qjrEk0Q6i2ix/cVeAhbCbqH9u3zYutS1cLg00qhrD0M2MVdCcx4Sc0UpP2eBWo9rotpq6g==" 1711 | }, 1712 | "mkdirp-classic": { 1713 | "version": "0.5.3", 1714 | "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", 1715 | "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" 1716 | }, 1717 | "ms": { 1718 | "version": "2.1.3", 1719 | "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", 1720 | "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" 1721 | }, 1722 | "multi-fork": { 1723 | "version": "0.0.2", 1724 | "resolved": "https://registry.npmjs.org/multi-fork/-/multi-fork-0.0.2.tgz", 1725 | "integrity": "sha512-SHWGuze0cZNiH+JGJQFlB1k7kZLGFCvW1Xo5Fcpe86KICkC3aVTJWpjUcmyYcLCB0I6gdzKLCia/bTIw2ggl8A==" 1726 | }, 1727 | "napi-build-utils": { 1728 | "version": "1.0.2", 1729 | "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", 1730 | "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==" 1731 | }, 1732 | "node-abi": { 1733 | "version": "3.26.0", 1734 | "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.26.0.tgz", 1735 | "integrity": "sha512-jRVtMFTChbi2i/jqo/i2iP9634KMe+7K1v35mIdj3Mn59i5q27ZYhn+sW6npISM/PQg7HrP2kwtRBMmh5Uvzdg==", 1736 | "requires": { 1737 | "semver": "^7.3.5" 1738 | } 1739 | }, 1740 | "node-fetch": { 1741 | "version": "2.6.7", 1742 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", 1743 | "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", 1744 | "requires": { 1745 | "whatwg-url": "^5.0.0" 1746 | } 1747 | }, 1748 | "object-keys": { 1749 | "version": "1.1.1", 1750 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", 1751 | "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" 1752 | }, 1753 | "obuf": { 1754 | "version": "1.1.2", 1755 | "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", 1756 | "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" 1757 | }, 1758 | "once": { 1759 | "version": "1.4.0", 1760 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 1761 | "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", 1762 | "requires": { 1763 | "wrappy": "1" 1764 | } 1765 | }, 1766 | "p-defer": { 1767 | "version": "3.0.0", 1768 | "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-3.0.0.tgz", 1769 | "integrity": "sha512-ugZxsxmtTln604yeYd29EGrNhazN2lywetzpKhfmQjW/VJmhpDmWbiX+h0zL8V91R0UXkhb3KtPmyq9PZw3aYw==" 1770 | }, 1771 | "packet-reader": { 1772 | "version": "1.0.0", 1773 | "resolved": "https://registry.npmjs.org/packet-reader/-/packet-reader-1.0.0.tgz", 1774 | "integrity": "sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==" 1775 | }, 1776 | "papaparse": { 1777 | "version": "5.3.2", 1778 | "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.3.2.tgz", 1779 | "integrity": "sha512-6dNZu0Ki+gyV0eBsFKJhYr+MdQYAzFUGlBMNj3GNrmHxmz1lfRa24CjFObPXtjcetlOv5Ad299MhIK0znp3afw==" 1780 | }, 1781 | "pg": { 1782 | "version": "8.8.0", 1783 | "resolved": "https://registry.npmjs.org/pg/-/pg-8.8.0.tgz", 1784 | "integrity": "sha512-UXYN0ziKj+AeNNP7VDMwrehpACThH7LUl/p8TDFpEUuSejCUIwGSfxpHsPvtM6/WXFy6SU4E5RG4IJV/TZAGjw==", 1785 | "requires": { 1786 | "buffer-writer": "2.0.0", 1787 | "packet-reader": "1.0.0", 1788 | "pg-connection-string": "^2.5.0", 1789 | "pg-pool": "^3.5.2", 1790 | "pg-protocol": "^1.5.0", 1791 | "pg-types": "^2.1.0", 1792 | "pgpass": "1.x" 1793 | }, 1794 | "dependencies": { 1795 | "pg-types": { 1796 | "version": "2.2.0", 1797 | "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", 1798 | "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", 1799 | "requires": { 1800 | "pg-int8": "1.0.1", 1801 | "postgres-array": "~2.0.0", 1802 | "postgres-bytea": "~1.0.0", 1803 | "postgres-date": "~1.0.4", 1804 | "postgres-interval": "^1.1.0" 1805 | } 1806 | }, 1807 | "postgres-array": { 1808 | "version": "2.0.0", 1809 | "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", 1810 | "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==" 1811 | }, 1812 | "postgres-bytea": { 1813 | "version": "1.0.0", 1814 | "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.0.tgz", 1815 | "integrity": "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==" 1816 | }, 1817 | "postgres-date": { 1818 | "version": "1.0.7", 1819 | "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", 1820 | "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==" 1821 | }, 1822 | "postgres-interval": { 1823 | "version": "1.2.0", 1824 | "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", 1825 | "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", 1826 | "requires": { 1827 | "xtend": "^4.0.0" 1828 | } 1829 | } 1830 | } 1831 | }, 1832 | "pg-connection-string": { 1833 | "version": "2.5.0", 1834 | "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.5.0.tgz", 1835 | "integrity": "sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==" 1836 | }, 1837 | "pg-copy-streams": { 1838 | "version": "6.0.4", 1839 | "resolved": "https://registry.npmjs.org/pg-copy-streams/-/pg-copy-streams-6.0.4.tgz", 1840 | "integrity": "sha512-FH6q2nFo0n2cFacLyIKorjDz8AOYtxrAANx1XMvYbKWNM2geY731gZstuP4mXMlqO6urRl9oIscFxf3GMIg3Ng==", 1841 | "requires": { 1842 | "obuf": "^1.1.2" 1843 | } 1844 | }, 1845 | "pg-copy-streams-binary": { 1846 | "version": "2.2.0", 1847 | "resolved": "https://registry.npmjs.org/pg-copy-streams-binary/-/pg-copy-streams-binary-2.2.0.tgz", 1848 | "integrity": "sha512-jPCWgTR8004wz5XOI2sc09+IMwE7YMeINYCabwPMCPtlgj2ay81VLCClMkj/u+xOeisRcN8vCrIZ4FrqlaTyBQ==", 1849 | "requires": { 1850 | "bl": "^4.0.3", 1851 | "bufferput": "^0.1.3", 1852 | "ieee754": "^1.1.13", 1853 | "int64-buffer": "^0.99.1007", 1854 | "multi-fork": "0.0.2", 1855 | "through2": "^3.0.1" 1856 | }, 1857 | "dependencies": { 1858 | "through2": { 1859 | "version": "3.0.2", 1860 | "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz", 1861 | "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==", 1862 | "requires": { 1863 | "inherits": "^2.0.4", 1864 | "readable-stream": "2 || 3" 1865 | } 1866 | } 1867 | } 1868 | }, 1869 | "pg-cursor": { 1870 | "version": "2.7.4", 1871 | "resolved": "https://registry.npmjs.org/pg-cursor/-/pg-cursor-2.7.4.tgz", 1872 | "integrity": "sha512-CNWwOzTTZ9QvphoOL+Wg/7pmVr9GnAWBjPbuK2FRclrB4A/WRO/ssCJ9BlkzIGmmofK2M/LyokNHgsLSn+fMHA==", 1873 | "requires": {} 1874 | }, 1875 | "pg-int8": { 1876 | "version": "1.0.1", 1877 | "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", 1878 | "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==" 1879 | }, 1880 | "pg-numeric": { 1881 | "version": "1.0.2", 1882 | "resolved": "https://registry.npmjs.org/pg-numeric/-/pg-numeric-1.0.2.tgz", 1883 | "integrity": "sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==" 1884 | }, 1885 | "pg-pool": { 1886 | "version": "3.5.2", 1887 | "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.5.2.tgz", 1888 | "integrity": "sha512-His3Fh17Z4eg7oANLob6ZvH8xIVen3phEZh2QuyrIl4dQSDVEabNducv6ysROKpDNPSD+12tONZVWfSgMvDD9w==", 1889 | "requires": {} 1890 | }, 1891 | "pg-protocol": { 1892 | "version": "1.5.0", 1893 | "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.5.0.tgz", 1894 | "integrity": "sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ==" 1895 | }, 1896 | "pg-types": { 1897 | "version": "4.0.0", 1898 | "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-4.0.0.tgz", 1899 | "integrity": "sha512-q4I7zG+d2mDg52WdrOA0TmBvab9ZBC8DE8+opl3gSegnH5ml+0pKbICOfRKXgwQ5aa6NRjLoF5pEDs0YpGvFrw==", 1900 | "requires": { 1901 | "pg-int8": "1.0.1", 1902 | "pg-numeric": "1.0.2", 1903 | "postgres-array": "~3.0.1", 1904 | "postgres-bytea": "~3.0.0", 1905 | "postgres-date": "~2.0.1", 1906 | "postgres-interval": "^3.0.0", 1907 | "postgres-range": "^1.1.1" 1908 | }, 1909 | "dependencies": { 1910 | "postgres-interval": { 1911 | "version": "3.0.0", 1912 | "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-3.0.0.tgz", 1913 | "integrity": "sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==" 1914 | } 1915 | } 1916 | }, 1917 | "pgpass": { 1918 | "version": "1.0.5", 1919 | "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", 1920 | "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", 1921 | "requires": { 1922 | "split2": "^4.1.0" 1923 | } 1924 | }, 1925 | "postgres-array": { 1926 | "version": "3.0.1", 1927 | "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-3.0.1.tgz", 1928 | "integrity": "sha512-h7i53Dw2Yq3a1uuZ6lbVFAkvMMwssJ8jkzeAg0XaZm1XIFF/t/s+tockdqbWTymyEm07dVenOQbFisEi+kj8uA==" 1929 | }, 1930 | "postgres-bytea": { 1931 | "version": "3.0.0", 1932 | "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-3.0.0.tgz", 1933 | "integrity": "sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==", 1934 | "requires": { 1935 | "obuf": "~1.1.2" 1936 | } 1937 | }, 1938 | "postgres-date": { 1939 | "version": "2.0.1", 1940 | "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-2.0.1.tgz", 1941 | "integrity": "sha512-YtMKdsDt5Ojv1wQRvUhnyDJNSr2dGIC96mQVKz7xufp07nfuFONzdaowrMHjlAzY6GDLd4f+LUHHAAM1h4MdUw==" 1942 | }, 1943 | "postgres-interval": { 1944 | "version": "4.0.0", 1945 | "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-4.0.0.tgz", 1946 | "integrity": "sha512-OWeL7kyEKJiY7mCmVY+c7/6uhAlt/colA/Nl/Mgls/M3jssrQzFra04iNWnD/qAmG7TsCSgWAASCyiaoBOP/sg==" 1947 | }, 1948 | "postgres-range": { 1949 | "version": "1.1.3", 1950 | "resolved": "https://registry.npmjs.org/postgres-range/-/postgres-range-1.1.3.tgz", 1951 | "integrity": "sha512-VdlZoocy5lCP0c/t66xAfclglEapXPCIVhqqJRncYpvbCgImF0w67aPKfbqUMr72tO2k5q0TdTZwCLjPTI6C9g==" 1952 | }, 1953 | "prebuild-install": { 1954 | "version": "7.1.1", 1955 | "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", 1956 | "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", 1957 | "requires": { 1958 | "detect-libc": "^2.0.0", 1959 | "expand-template": "^2.0.3", 1960 | "github-from-package": "0.0.0", 1961 | "minimist": "^1.2.3", 1962 | "mkdirp-classic": "^0.5.3", 1963 | "napi-build-utils": "^1.0.1", 1964 | "node-abi": "^3.3.0", 1965 | "pump": "^3.0.0", 1966 | "rc": "^1.2.7", 1967 | "simple-get": "^4.0.0", 1968 | "tar-fs": "^2.0.0", 1969 | "tunnel-agent": "^0.6.0" 1970 | } 1971 | }, 1972 | "pump": { 1973 | "version": "3.0.0", 1974 | "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", 1975 | "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", 1976 | "requires": { 1977 | "end-of-stream": "^1.1.0", 1978 | "once": "^1.3.1" 1979 | } 1980 | }, 1981 | "punycode": { 1982 | "version": "2.1.1", 1983 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", 1984 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" 1985 | }, 1986 | "rc": { 1987 | "version": "1.2.8", 1988 | "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", 1989 | "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", 1990 | "requires": { 1991 | "deep-extend": "^0.6.0", 1992 | "ini": "~1.3.0", 1993 | "minimist": "^1.2.0", 1994 | "strip-json-comments": "~2.0.1" 1995 | } 1996 | }, 1997 | "readable-stream": { 1998 | "version": "3.6.0", 1999 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", 2000 | "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", 2001 | "requires": { 2002 | "inherits": "^2.0.3", 2003 | "string_decoder": "^1.1.1", 2004 | "util-deprecate": "^1.0.1" 2005 | } 2006 | }, 2007 | "regenerator-runtime": { 2008 | "version": "0.13.10", 2009 | "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.10.tgz", 2010 | "integrity": "sha512-KepLsg4dU12hryUO7bp/axHAKvwGOCV0sGloQtpagJ12ai+ojVDqkeGSiRX1zlq+kjIMZ1t7gpze+26QqtdGqw==" 2011 | }, 2012 | "rfdc": { 2013 | "version": "1.3.0", 2014 | "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", 2015 | "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==" 2016 | }, 2017 | "roarr": { 2018 | "version": "7.13.0", 2019 | "resolved": "https://registry.npmjs.org/roarr/-/roarr-7.13.0.tgz", 2020 | "integrity": "sha512-NA7ikXPPxjGv/51R9pYd3G4f9nq0x6zLe9XPzbm3l+efBnckO2Lsac4KB6NRfoBzAKvLE5Lh8J5Fsm3IdHycuA==", 2021 | "requires": { 2022 | "boolean": "^3.1.4", 2023 | "fast-json-stringify": "^2.7.10", 2024 | "fast-printf": "^1.6.9", 2025 | "fast-safe-stringify": "^2.1.1", 2026 | "globalthis": "^1.0.2", 2027 | "semver-compare": "^1.0.0" 2028 | } 2029 | }, 2030 | "safe-buffer": { 2031 | "version": "5.2.1", 2032 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", 2033 | "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" 2034 | }, 2035 | "secure-json-parse": { 2036 | "version": "2.5.0", 2037 | "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.5.0.tgz", 2038 | "integrity": "sha512-ZQruFgZnIWH+WyO9t5rWt4ZEGqCKPwhiw+YbzTwpmT9elgLrLcfuyUiSnwwjUiVy9r4VM3urtbNF1xmEh9IL2w==" 2039 | }, 2040 | "semver": { 2041 | "version": "7.3.8", 2042 | "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.8.tgz", 2043 | "integrity": "sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==", 2044 | "requires": { 2045 | "lru-cache": "^6.0.0" 2046 | } 2047 | }, 2048 | "semver-compare": { 2049 | "version": "1.0.0", 2050 | "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", 2051 | "integrity": "sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==" 2052 | }, 2053 | "serialize-error": { 2054 | "version": "8.1.0", 2055 | "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-8.1.0.tgz", 2056 | "integrity": "sha512-3NnuWfM6vBYoy5gZFvHiYsVbafvI9vZv/+jlIigFn4oP4zjNPK3LhcY0xSCgeb1a5L8jO71Mit9LlNoi2UfDDQ==", 2057 | "requires": { 2058 | "type-fest": "^0.20.2" 2059 | } 2060 | }, 2061 | "simple-concat": { 2062 | "version": "1.0.1", 2063 | "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", 2064 | "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==" 2065 | }, 2066 | "simple-get": { 2067 | "version": "4.0.1", 2068 | "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", 2069 | "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", 2070 | "requires": { 2071 | "decompress-response": "^6.0.0", 2072 | "once": "^1.3.1", 2073 | "simple-concat": "^1.0.0" 2074 | } 2075 | }, 2076 | "slonik": { 2077 | "version": "30.4.4", 2078 | "resolved": "https://registry.npmjs.org/slonik/-/slonik-30.4.4.tgz", 2079 | "integrity": "sha512-5Z1QJhRCDyq0J+0yiUN6COETKtvrYdmukeQn5RZUSt7EvzYo4oTm7D4j2ZV4DN0DMHsaQBSnW/tIgX+UHRJYmQ==", 2080 | "requires": { 2081 | "concat-stream": "^2.0.0", 2082 | "es6-error": "^4.1.1", 2083 | "fast-safe-stringify": "^2.1.1", 2084 | "get-stack-trace": "^2.1.1", 2085 | "hyperid": "^2.3.1", 2086 | "is-plain-object": "^5.0.0", 2087 | "iso8601-duration": "^1.3.0", 2088 | "p-defer": "^3.0.0", 2089 | "pg": "^8.7.3", 2090 | "pg-copy-streams": "^6.0.2", 2091 | "pg-copy-streams-binary": "^2.2.0", 2092 | "pg-cursor": "^2.7.3", 2093 | "pg-protocol": "^1.5.0", 2094 | "pg-types": "^4.0.0", 2095 | "postgres-array": "^3.0.1", 2096 | "postgres-interval": "^4.0.0", 2097 | "roarr": "^7.11.0", 2098 | "serialize-error": "^8.0.0", 2099 | "through2": "^4.0.2", 2100 | "zod": "^3.18.0" 2101 | } 2102 | }, 2103 | "source-map": { 2104 | "version": "0.8.0-beta.0", 2105 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", 2106 | "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", 2107 | "requires": { 2108 | "whatwg-url": "^7.0.0" 2109 | }, 2110 | "dependencies": { 2111 | "tr46": { 2112 | "version": "1.0.1", 2113 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", 2114 | "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", 2115 | "requires": { 2116 | "punycode": "^2.1.0" 2117 | } 2118 | }, 2119 | "webidl-conversions": { 2120 | "version": "4.0.2", 2121 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", 2122 | "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" 2123 | }, 2124 | "whatwg-url": { 2125 | "version": "7.1.0", 2126 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", 2127 | "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", 2128 | "requires": { 2129 | "lodash.sortby": "^4.7.0", 2130 | "tr46": "^1.0.1", 2131 | "webidl-conversions": "^4.0.2" 2132 | } 2133 | } 2134 | } 2135 | }, 2136 | "split2": { 2137 | "version": "4.1.0", 2138 | "resolved": "https://registry.npmjs.org/split2/-/split2-4.1.0.tgz", 2139 | "integrity": "sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==" 2140 | }, 2141 | "string_decoder": { 2142 | "version": "1.3.0", 2143 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", 2144 | "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", 2145 | "requires": { 2146 | "safe-buffer": "~5.2.0" 2147 | } 2148 | }, 2149 | "string-similarity": { 2150 | "version": "4.0.4", 2151 | "resolved": "https://registry.npmjs.org/string-similarity/-/string-similarity-4.0.4.tgz", 2152 | "integrity": "sha512-/q/8Q4Bl4ZKAPjj8WerIBJWALKkaPRfrvhfF8k/B23i4nzrlRj2/go1m90In7nG/3XDSbOo0+pu6RvCTM9RGMQ==" 2153 | }, 2154 | "strip-json-comments": { 2155 | "version": "2.0.1", 2156 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", 2157 | "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==" 2158 | }, 2159 | "tar-fs": { 2160 | "version": "2.1.1", 2161 | "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz", 2162 | "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==", 2163 | "requires": { 2164 | "chownr": "^1.1.1", 2165 | "mkdirp-classic": "^0.5.2", 2166 | "pump": "^3.0.0", 2167 | "tar-stream": "^2.1.4" 2168 | } 2169 | }, 2170 | "tar-stream": { 2171 | "version": "2.2.0", 2172 | "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", 2173 | "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", 2174 | "requires": { 2175 | "bl": "^4.0.3", 2176 | "end-of-stream": "^1.4.1", 2177 | "fs-constants": "^1.0.0", 2178 | "inherits": "^2.0.3", 2179 | "readable-stream": "^3.1.1" 2180 | } 2181 | }, 2182 | "through2": { 2183 | "version": "4.0.2", 2184 | "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", 2185 | "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", 2186 | "requires": { 2187 | "readable-stream": "3" 2188 | } 2189 | }, 2190 | "tr46": { 2191 | "version": "0.0.3", 2192 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", 2193 | "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" 2194 | }, 2195 | "tunnel-agent": { 2196 | "version": "0.6.0", 2197 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", 2198 | "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", 2199 | "requires": { 2200 | "safe-buffer": "^5.0.1" 2201 | } 2202 | }, 2203 | "type-fest": { 2204 | "version": "0.20.2", 2205 | "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", 2206 | "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==" 2207 | }, 2208 | "typedarray": { 2209 | "version": "0.0.6", 2210 | "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", 2211 | "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" 2212 | }, 2213 | "typesense": { 2214 | "version": "1.4.1", 2215 | "resolved": "https://registry.npmjs.org/typesense/-/typesense-1.4.1.tgz", 2216 | "integrity": "sha512-M+3UCEohGA2IIOVVwXazFjx4iu8PtJJ3rm0D9mtYS/FxvPstA6OI9OH9kKpqRwry6hRyMWtcBF3BrN5aljhk/g==", 2217 | "requires": { 2218 | "axios": "^0.26.0", 2219 | "loglevel": "^1.8.0" 2220 | } 2221 | }, 2222 | "uri-js": { 2223 | "version": "4.4.1", 2224 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", 2225 | "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", 2226 | "requires": { 2227 | "punycode": "^2.1.0" 2228 | } 2229 | }, 2230 | "util-deprecate": { 2231 | "version": "1.0.2", 2232 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", 2233 | "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" 2234 | }, 2235 | "uuid": { 2236 | "version": "8.3.2", 2237 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", 2238 | "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" 2239 | }, 2240 | "uuid-parse": { 2241 | "version": "1.1.0", 2242 | "resolved": "https://registry.npmjs.org/uuid-parse/-/uuid-parse-1.1.0.tgz", 2243 | "integrity": "sha512-OdmXxA8rDsQ7YpNVbKSJkNzTw2I+S5WsbMDnCtIWSQaosNAcWtFuI/YK1TjzUI6nbkgiqEyh8gWngfcv8Asd9A==" 2244 | }, 2245 | "webidl-conversions": { 2246 | "version": "3.0.1", 2247 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", 2248 | "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" 2249 | }, 2250 | "whatwg-url": { 2251 | "version": "5.0.0", 2252 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", 2253 | "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", 2254 | "requires": { 2255 | "tr46": "~0.0.3", 2256 | "webidl-conversions": "^3.0.0" 2257 | } 2258 | }, 2259 | "wrappy": { 2260 | "version": "1.0.2", 2261 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 2262 | "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" 2263 | }, 2264 | "xtend": { 2265 | "version": "4.0.2", 2266 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", 2267 | "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" 2268 | }, 2269 | "yallist": { 2270 | "version": "4.0.0", 2271 | "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", 2272 | "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" 2273 | }, 2274 | "zod": { 2275 | "version": "3.19.1", 2276 | "resolved": "https://registry.npmjs.org/zod/-/zod-3.19.1.tgz", 2277 | "integrity": "sha512-LYjZsEDhCdYET9ikFu6dVPGp2YH9DegXjdJToSzD9rO6fy4qiRYFoyEYwps88OseJlPyl2NOe2iJuhEhL7IpEA==" 2278 | } 2279 | } 2280 | } 2281 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "pg-fts-benchmark", 3 | "version": "0.2.1", 4 | "description": "Full text search benchmark for Postgres and other F/OSS search engines", 5 | "engines": { 6 | "node": ">=17.4.0" 7 | }, 8 | "dependencies": { 9 | "@babel/runtime": "^7.18.9", 10 | "@opensearch-project/opensearch": "^2.0.0", 11 | "async-wait-for-promise": "^1.2.0", 12 | "better-sqlite3": "^7.6.2", 13 | "meilisearch": "^0.27.0", 14 | "papaparse": "^5.3.2", 15 | "slonik": "^30.3.1", 16 | "typesense": "^1.4.0" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: 5.4 2 | 3 | specifiers: 4 | '@babel/runtime': ^7.18.9 5 | '@opensearch-project/opensearch': ^2.0.0 6 | async-wait-for-promise: ^1.2.0 7 | better-sqlite3: ^7.6.2 8 | meilisearch: ^0.27.0 9 | papaparse: ^5.3.2 10 | slonik: ^30.3.1 11 | typesense: ^1.4.0 12 | 13 | dependencies: 14 | '@babel/runtime': 7.18.9 15 | '@opensearch-project/opensearch': 2.0.0 16 | async-wait-for-promise: 1.2.0 17 | better-sqlite3: 7.6.2 18 | meilisearch: 0.27.0 19 | papaparse: 5.3.2 20 | slonik: 30.3.1 21 | typesense: 1.4.0_@babel+runtime@7.18.9 22 | 23 | packages: 24 | 25 | /@babel/runtime/7.18.9: 26 | resolution: {integrity: sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==} 27 | engines: {node: '>=6.9.0'} 28 | dependencies: 29 | regenerator-runtime: 0.13.9 30 | dev: false 31 | 32 | /@opensearch-project/opensearch/2.0.0: 33 | resolution: {integrity: sha512-/5wP76x90clGq0Xw0MbMsml1+PQHpyY+WVqLCzAFNXSFEjSbq+fWrVjH1vX+VZkRQTzKrqNjaUTqYMA9YHRggA==} 34 | engines: {node: '>=10', yarn: ^1.22.10} 35 | dependencies: 36 | debug: 4.3.4 37 | hpagent: 0.1.2 38 | ms: 2.1.3 39 | secure-json-parse: 2.5.0 40 | transitivePeerDependencies: 41 | - supports-color 42 | dev: false 43 | 44 | /ajv/6.12.6: 45 | resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} 46 | dependencies: 47 | fast-deep-equal: 3.1.3 48 | fast-json-stable-stringify: 2.1.0 49 | json-schema-traverse: 0.4.1 50 | uri-js: 4.4.1 51 | dev: false 52 | 53 | /async-wait-for-promise/1.2.0: 54 | resolution: {integrity: sha512-yD+1pBLFILAxKASOqF0dQbODVr5Mlw2L3l/gs5gNauqH/DiOOl8lOGoV7q1F5v7fS8jNSylt4y9EUtO21NVaxA==} 55 | engines: {node: '>=14.17.0'} 56 | dev: false 57 | 58 | /axios/0.26.1: 59 | resolution: {integrity: sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==} 60 | dependencies: 61 | follow-redirects: 1.15.1 62 | transitivePeerDependencies: 63 | - debug 64 | dev: false 65 | 66 | /base64-js/1.5.1: 67 | resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} 68 | dev: false 69 | 70 | /better-sqlite3/7.6.2: 71 | resolution: {integrity: sha512-S5zIU1Hink2AH4xPsN0W43T1/AJ5jrPh7Oy07ocuW/AKYYY02GWzz9NH0nbSMn/gw6fDZ5jZ1QsHt1BXAwJ6Lg==} 72 | requiresBuild: true 73 | dependencies: 74 | bindings: 1.5.0 75 | prebuild-install: 7.1.1 76 | dev: false 77 | 78 | /bindings/1.5.0: 79 | resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} 80 | dependencies: 81 | file-uri-to-path: 1.0.0 82 | dev: false 83 | 84 | /bl/4.1.0: 85 | resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} 86 | dependencies: 87 | buffer: 5.7.1 88 | inherits: 2.0.4 89 | readable-stream: 3.6.0 90 | dev: false 91 | 92 | /bluebird/3.7.2: 93 | resolution: {integrity: sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==} 94 | dev: false 95 | 96 | /boolean/3.2.0: 97 | resolution: {integrity: sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==} 98 | dev: false 99 | 100 | /buffer-from/1.1.2: 101 | resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} 102 | dev: false 103 | 104 | /buffer-writer/2.0.0: 105 | resolution: {integrity: sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==} 106 | engines: {node: '>=4'} 107 | dev: false 108 | 109 | /buffer/5.7.1: 110 | resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} 111 | dependencies: 112 | base64-js: 1.5.1 113 | ieee754: 1.2.1 114 | dev: false 115 | 116 | /bufferput/0.1.3: 117 | resolution: {integrity: sha512-nmPV88vDNzf0VMU1bdQ4A1oBlRR9y+CXfwWKfyKUgI2ZIkvreNzLMM3tkz0Lapb6f+Cz1V001UWRBsoGVCjqdw==} 118 | engines: {node: '>=0.3.0'} 119 | dev: false 120 | 121 | /chownr/1.1.4: 122 | resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} 123 | dev: false 124 | 125 | /concat-stream/2.0.0: 126 | resolution: {integrity: sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==} 127 | engines: {'0': node >= 6.0} 128 | dependencies: 129 | buffer-from: 1.1.2 130 | inherits: 2.0.4 131 | readable-stream: 3.6.0 132 | typedarray: 0.0.6 133 | dev: false 134 | 135 | /cross-fetch/3.1.5: 136 | resolution: {integrity: sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==} 137 | dependencies: 138 | node-fetch: 2.6.7 139 | transitivePeerDependencies: 140 | - encoding 141 | dev: false 142 | 143 | /debug/4.3.4: 144 | resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} 145 | engines: {node: '>=6.0'} 146 | peerDependencies: 147 | supports-color: '*' 148 | peerDependenciesMeta: 149 | supports-color: 150 | optional: true 151 | dependencies: 152 | ms: 2.1.2 153 | dev: false 154 | 155 | /decompress-response/6.0.0: 156 | resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} 157 | engines: {node: '>=10'} 158 | dependencies: 159 | mimic-response: 3.1.0 160 | dev: false 161 | 162 | /deep-extend/0.6.0: 163 | resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} 164 | engines: {node: '>=4.0.0'} 165 | dev: false 166 | 167 | /deepmerge/4.2.2: 168 | resolution: {integrity: sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==} 169 | engines: {node: '>=0.10.0'} 170 | dev: false 171 | 172 | /define-properties/1.1.4: 173 | resolution: {integrity: sha512-uckOqKcfaVvtBdsVkdPv3XjveQJsNQqmhXgRi8uhvWWuPYZCNlzT8qAyblUgNoXdHdjMTzAqeGjAoli8f+bzPA==} 174 | engines: {node: '>= 0.4'} 175 | dependencies: 176 | has-property-descriptors: 1.0.0 177 | object-keys: 1.1.1 178 | dev: false 179 | 180 | /detect-libc/2.0.1: 181 | resolution: {integrity: sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==} 182 | engines: {node: '>=8'} 183 | dev: false 184 | 185 | /end-of-stream/1.4.4: 186 | resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} 187 | dependencies: 188 | once: 1.4.0 189 | dev: false 190 | 191 | /es6-error/4.1.1: 192 | resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==} 193 | dev: false 194 | 195 | /expand-template/2.0.3: 196 | resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} 197 | engines: {node: '>=6'} 198 | dev: false 199 | 200 | /fast-deep-equal/3.1.3: 201 | resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} 202 | dev: false 203 | 204 | /fast-json-stable-stringify/2.1.0: 205 | resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} 206 | dev: false 207 | 208 | /fast-json-stringify/2.7.13: 209 | resolution: {integrity: sha512-ar+hQ4+OIurUGjSJD1anvYSDcUflywhKjfxnsW4TBTD7+u0tJufv6DKRWoQk3vI6YBOWMoz0TQtfbe7dxbQmvA==} 210 | engines: {node: '>= 10.0.0'} 211 | dependencies: 212 | ajv: 6.12.6 213 | deepmerge: 4.2.2 214 | rfdc: 1.3.0 215 | string-similarity: 4.0.4 216 | dev: false 217 | 218 | /fast-printf/1.6.9: 219 | resolution: {integrity: sha512-FChq8hbz65WMj4rstcQsFB0O7Cy++nmbNfLYnD9cYv2cRn8EG6k/MGn9kO/tjO66t09DLDugj3yL+V2o6Qftrg==} 220 | engines: {node: '>=10.0'} 221 | dependencies: 222 | boolean: 3.2.0 223 | dev: false 224 | 225 | /fast-safe-stringify/2.1.1: 226 | resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} 227 | dev: false 228 | 229 | /file-uri-to-path/1.0.0: 230 | resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} 231 | dev: false 232 | 233 | /follow-redirects/1.15.1: 234 | resolution: {integrity: sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==} 235 | engines: {node: '>=4.0'} 236 | peerDependencies: 237 | debug: '*' 238 | peerDependenciesMeta: 239 | debug: 240 | optional: true 241 | dev: false 242 | 243 | /fs-constants/1.0.0: 244 | resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} 245 | dev: false 246 | 247 | /function-bind/1.1.1: 248 | resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} 249 | dev: false 250 | 251 | /get-intrinsic/1.1.2: 252 | resolution: {integrity: sha512-Jfm3OyCxHh9DJyc28qGk+JmfkpO41A4XkneDSujN9MDXrm4oDKdHvndhZ2dN94+ERNfkYJWDclW6k2L/ZGHjXA==} 253 | dependencies: 254 | function-bind: 1.1.1 255 | has: 1.0.3 256 | has-symbols: 1.0.3 257 | dev: false 258 | 259 | /get-stack-trace/2.1.1: 260 | resolution: {integrity: sha512-dhqSDD9lHU/6FvIZ9KbXGmVK6IKr9ZskZtNOUvhlCiONlnqatu4FmAeRbxCfJJVuQ0NWfz6dAbibKQg19B7AmQ==} 261 | engines: {node: '>=8.0'} 262 | dependencies: 263 | bluebird: 3.7.2 264 | source-map: 0.8.0-beta.0 265 | dev: false 266 | 267 | /github-from-package/0.0.0: 268 | resolution: {integrity: sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=} 269 | dev: false 270 | 271 | /globalthis/1.0.3: 272 | resolution: {integrity: sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==} 273 | engines: {node: '>= 0.4'} 274 | dependencies: 275 | define-properties: 1.1.4 276 | dev: false 277 | 278 | /has-property-descriptors/1.0.0: 279 | resolution: {integrity: sha512-62DVLZGoiEBDHQyqG4w9xCuZ7eJEwNmJRWw2VY84Oedb7WFcA27fiEVe8oUQx9hAUJ4ekurquucTGwsyO1XGdQ==} 280 | dependencies: 281 | get-intrinsic: 1.1.2 282 | dev: false 283 | 284 | /has-symbols/1.0.3: 285 | resolution: {integrity: sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==} 286 | engines: {node: '>= 0.4'} 287 | dev: false 288 | 289 | /has/1.0.3: 290 | resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} 291 | engines: {node: '>= 0.4.0'} 292 | dependencies: 293 | function-bind: 1.1.1 294 | dev: false 295 | 296 | /hpagent/0.1.2: 297 | resolution: {integrity: sha512-ePqFXHtSQWAFXYmj+JtOTHr84iNrII4/QRlAAPPE+zqnKy4xJo7Ie1Y4kC7AdB+LxLxSTTzBMASsEcy0q8YyvQ==} 298 | dev: false 299 | 300 | /hyperid/2.3.1: 301 | resolution: {integrity: sha512-mIbI7Ymn6MCdODaW1/6wdf5lvvXzmPsARN4zTLakMmcziBOuP4PxCBJvHF6kbAIHX6H4vAELx/pDmt0j6Th5RQ==} 302 | dependencies: 303 | uuid: 8.3.2 304 | uuid-parse: 1.1.0 305 | dev: false 306 | 307 | /ieee754/1.2.1: 308 | resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} 309 | dev: false 310 | 311 | /inherits/2.0.4: 312 | resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} 313 | dev: false 314 | 315 | /ini/1.3.8: 316 | resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} 317 | dev: false 318 | 319 | /int64-buffer/0.99.1007: 320 | resolution: {integrity: sha512-XDBEu44oSTqlvCSiOZ/0FoUkpWu/vwjJLGSKDabNISPQNZ5wub1FodGHBljRsrR0IXRPq7SslshZYMuA55CgTQ==} 321 | engines: {node: '>= 4.5.0'} 322 | dev: false 323 | 324 | /is-plain-object/5.0.0: 325 | resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} 326 | engines: {node: '>=0.10.0'} 327 | dev: false 328 | 329 | /iso8601-duration/1.3.0: 330 | resolution: {integrity: sha512-K4CiUBzo3YeWk76FuET/dQPH03WE04R94feo5TSKQCXpoXQt9E4yx2CnY737QZnSAI3PI4WlKo/zfqizGx52QQ==} 331 | dev: false 332 | 333 | /json-schema-traverse/0.4.1: 334 | resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} 335 | dev: false 336 | 337 | /lodash.sortby/4.7.0: 338 | resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} 339 | dev: false 340 | 341 | /loglevel/1.8.0: 342 | resolution: {integrity: sha512-G6A/nJLRgWOuuwdNuA6koovfEV1YpqqAG4pRUlFaz3jj2QNZ8M4vBqnVA+HBTmU/AMNUtlOsMmSpF6NyOjztbA==} 343 | engines: {node: '>= 0.6.0'} 344 | dev: false 345 | 346 | /lru-cache/6.0.0: 347 | resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} 348 | engines: {node: '>=10'} 349 | dependencies: 350 | yallist: 4.0.0 351 | dev: false 352 | 353 | /meilisearch/0.27.0: 354 | resolution: {integrity: sha512-kZOZFIuSO7c6xRf+Y2/9/h6A9pl0sCl/G44X4KuaSwxGbruOZPhmxbeVEgLHBv4pUFvQ56rNVTA/2d/5GCU1YA==} 355 | dependencies: 356 | cross-fetch: 3.1.5 357 | transitivePeerDependencies: 358 | - encoding 359 | dev: false 360 | 361 | /mimic-response/3.1.0: 362 | resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} 363 | engines: {node: '>=10'} 364 | dev: false 365 | 366 | /minimist/1.2.6: 367 | resolution: {integrity: sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==} 368 | dev: false 369 | 370 | /mkdirp-classic/0.5.3: 371 | resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} 372 | dev: false 373 | 374 | /ms/2.1.2: 375 | resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} 376 | dev: false 377 | 378 | /ms/2.1.3: 379 | resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} 380 | dev: false 381 | 382 | /multi-fork/0.0.2: 383 | resolution: {integrity: sha1-gFiuxGFBJMftqhWBm4juiJ0+tOA=} 384 | dev: false 385 | 386 | /napi-build-utils/1.0.2: 387 | resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==} 388 | dev: false 389 | 390 | /node-abi/3.24.0: 391 | resolution: {integrity: sha512-YPG3Co0luSu6GwOBsmIdGW6Wx0NyNDLg/hriIyDllVsNwnI6UeqaWShxC3lbH4LtEQUgoLP3XR1ndXiDAWvmRw==} 392 | engines: {node: '>=10'} 393 | dependencies: 394 | semver: 7.3.7 395 | dev: false 396 | 397 | /node-fetch/2.6.7: 398 | resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==} 399 | engines: {node: 4.x || >=6.0.0} 400 | peerDependencies: 401 | encoding: ^0.1.0 402 | peerDependenciesMeta: 403 | encoding: 404 | optional: true 405 | dependencies: 406 | whatwg-url: 5.0.0 407 | dev: false 408 | 409 | /object-keys/1.1.1: 410 | resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} 411 | engines: {node: '>= 0.4'} 412 | dev: false 413 | 414 | /obuf/1.1.2: 415 | resolution: {integrity: sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==} 416 | dev: false 417 | 418 | /once/1.4.0: 419 | resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} 420 | dependencies: 421 | wrappy: 1.0.2 422 | dev: false 423 | 424 | /p-defer/3.0.0: 425 | resolution: {integrity: sha512-ugZxsxmtTln604yeYd29EGrNhazN2lywetzpKhfmQjW/VJmhpDmWbiX+h0zL8V91R0UXkhb3KtPmyq9PZw3aYw==} 426 | engines: {node: '>=8'} 427 | dev: false 428 | 429 | /packet-reader/1.0.0: 430 | resolution: {integrity: sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==} 431 | dev: false 432 | 433 | /papaparse/5.3.2: 434 | resolution: {integrity: sha512-6dNZu0Ki+gyV0eBsFKJhYr+MdQYAzFUGlBMNj3GNrmHxmz1lfRa24CjFObPXtjcetlOv5Ad299MhIK0znp3afw==} 435 | dev: false 436 | 437 | /pg-connection-string/2.5.0: 438 | resolution: {integrity: sha512-r5o/V/ORTA6TmUnyWZR9nCj1klXCO2CEKNRlVuJptZe85QuhFayC7WeMic7ndayT5IRIR0S0xFxFi2ousartlQ==} 439 | dev: false 440 | 441 | /pg-copy-streams-binary/2.2.0: 442 | resolution: {integrity: sha512-jPCWgTR8004wz5XOI2sc09+IMwE7YMeINYCabwPMCPtlgj2ay81VLCClMkj/u+xOeisRcN8vCrIZ4FrqlaTyBQ==} 443 | dependencies: 444 | bl: 4.1.0 445 | bufferput: 0.1.3 446 | ieee754: 1.2.1 447 | int64-buffer: 0.99.1007 448 | multi-fork: 0.0.2 449 | through2: 3.0.2 450 | dev: false 451 | 452 | /pg-copy-streams/6.0.2: 453 | resolution: {integrity: sha512-74doDsDUI3ti1IzeieA7c/VsTpZkBdgjMeag3BtJFV+3J0m7Z3UMJB8iQW+zUWHZGVF9d/WIRfledEaPfKcPEA==} 454 | dependencies: 455 | obuf: 1.1.2 456 | dev: false 457 | 458 | /pg-cursor/2.7.4_pg@8.8.0: 459 | resolution: {integrity: sha512-CNWwOzTTZ9QvphoOL+Wg/7pmVr9GnAWBjPbuK2FRclrB4A/WRO/ssCJ9BlkzIGmmofK2M/LyokNHgsLSn+fMHA==} 460 | peerDependencies: 461 | pg: ^8 462 | dependencies: 463 | pg: 8.8.0 464 | dev: false 465 | 466 | /pg-int8/1.0.1: 467 | resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} 468 | engines: {node: '>=4.0.0'} 469 | dev: false 470 | 471 | /pg-numeric/1.0.2: 472 | resolution: {integrity: sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==} 473 | engines: {node: '>=4'} 474 | dev: false 475 | 476 | /pg-pool/3.5.2_pg@8.8.0: 477 | resolution: {integrity: sha512-His3Fh17Z4eg7oANLob6ZvH8xIVen3phEZh2QuyrIl4dQSDVEabNducv6ysROKpDNPSD+12tONZVWfSgMvDD9w==} 478 | peerDependencies: 479 | pg: '>=8.0' 480 | dependencies: 481 | pg: 8.8.0 482 | dev: false 483 | 484 | /pg-protocol/1.5.0: 485 | resolution: {integrity: sha512-muRttij7H8TqRNu/DxrAJQITO4Ac7RmX3Klyr/9mJEOBeIpgnF8f9jAfRz5d3XwQZl5qBjF9gLsUtMPJE0vezQ==} 486 | dev: false 487 | 488 | /pg-types/2.2.0: 489 | resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} 490 | engines: {node: '>=4'} 491 | dependencies: 492 | pg-int8: 1.0.1 493 | postgres-array: 2.0.0 494 | postgres-bytea: 1.0.0 495 | postgres-date: 1.0.7 496 | postgres-interval: 1.2.0 497 | dev: false 498 | 499 | /pg-types/4.0.0: 500 | resolution: {integrity: sha512-q4I7zG+d2mDg52WdrOA0TmBvab9ZBC8DE8+opl3gSegnH5ml+0pKbICOfRKXgwQ5aa6NRjLoF5pEDs0YpGvFrw==} 501 | engines: {node: '>=10'} 502 | dependencies: 503 | pg-int8: 1.0.1 504 | pg-numeric: 1.0.2 505 | postgres-array: 3.0.1 506 | postgres-bytea: 3.0.0 507 | postgres-date: 2.0.1 508 | postgres-interval: 3.0.0 509 | postgres-range: 1.1.2 510 | dev: false 511 | 512 | /pg/8.8.0: 513 | resolution: {integrity: sha512-UXYN0ziKj+AeNNP7VDMwrehpACThH7LUl/p8TDFpEUuSejCUIwGSfxpHsPvtM6/WXFy6SU4E5RG4IJV/TZAGjw==} 514 | engines: {node: '>= 8.0.0'} 515 | peerDependencies: 516 | pg-native: '>=3.0.1' 517 | peerDependenciesMeta: 518 | pg-native: 519 | optional: true 520 | dependencies: 521 | buffer-writer: 2.0.0 522 | packet-reader: 1.0.0 523 | pg-connection-string: 2.5.0 524 | pg-pool: 3.5.2_pg@8.8.0 525 | pg-protocol: 1.5.0 526 | pg-types: 2.2.0 527 | pgpass: 1.0.5 528 | dev: false 529 | 530 | /pgpass/1.0.5: 531 | resolution: {integrity: sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==} 532 | dependencies: 533 | split2: 4.1.0 534 | dev: false 535 | 536 | /postgres-array/2.0.0: 537 | resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} 538 | engines: {node: '>=4'} 539 | dev: false 540 | 541 | /postgres-array/3.0.1: 542 | resolution: {integrity: sha512-h7i53Dw2Yq3a1uuZ6lbVFAkvMMwssJ8jkzeAg0XaZm1XIFF/t/s+tockdqbWTymyEm07dVenOQbFisEi+kj8uA==} 543 | engines: {node: '>=12'} 544 | dev: false 545 | 546 | /postgres-bytea/1.0.0: 547 | resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==} 548 | engines: {node: '>=0.10.0'} 549 | dev: false 550 | 551 | /postgres-bytea/3.0.0: 552 | resolution: {integrity: sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw==} 553 | engines: {node: '>= 6'} 554 | dependencies: 555 | obuf: 1.1.2 556 | dev: false 557 | 558 | /postgres-date/1.0.7: 559 | resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} 560 | engines: {node: '>=0.10.0'} 561 | dev: false 562 | 563 | /postgres-date/2.0.1: 564 | resolution: {integrity: sha512-YtMKdsDt5Ojv1wQRvUhnyDJNSr2dGIC96mQVKz7xufp07nfuFONzdaowrMHjlAzY6GDLd4f+LUHHAAM1h4MdUw==} 565 | engines: {node: '>=12'} 566 | dev: false 567 | 568 | /postgres-interval/1.2.0: 569 | resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} 570 | engines: {node: '>=0.10.0'} 571 | dependencies: 572 | xtend: 4.0.2 573 | dev: false 574 | 575 | /postgres-interval/3.0.0: 576 | resolution: {integrity: sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw==} 577 | engines: {node: '>=12'} 578 | dev: false 579 | 580 | /postgres-interval/4.0.0: 581 | resolution: {integrity: sha512-OWeL7kyEKJiY7mCmVY+c7/6uhAlt/colA/Nl/Mgls/M3jssrQzFra04iNWnD/qAmG7TsCSgWAASCyiaoBOP/sg==} 582 | engines: {node: '>=12'} 583 | dev: false 584 | 585 | /postgres-range/1.1.2: 586 | resolution: {integrity: sha512-CmPJDSpd3/xYJrtw/tI0Cv029B0zMtnesUOHCZmgvypGBLn+eExXcjCS5OY7mpiw6imYEvd2IMD36sAOYA9U1w==} 587 | dev: false 588 | 589 | /prebuild-install/7.1.1: 590 | resolution: {integrity: sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==} 591 | engines: {node: '>=10'} 592 | hasBin: true 593 | dependencies: 594 | detect-libc: 2.0.1 595 | expand-template: 2.0.3 596 | github-from-package: 0.0.0 597 | minimist: 1.2.6 598 | mkdirp-classic: 0.5.3 599 | napi-build-utils: 1.0.2 600 | node-abi: 3.24.0 601 | pump: 3.0.0 602 | rc: 1.2.8 603 | simple-get: 4.0.1 604 | tar-fs: 2.1.1 605 | tunnel-agent: 0.6.0 606 | dev: false 607 | 608 | /pump/3.0.0: 609 | resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==} 610 | dependencies: 611 | end-of-stream: 1.4.4 612 | once: 1.4.0 613 | dev: false 614 | 615 | /punycode/2.1.1: 616 | resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==} 617 | engines: {node: '>=6'} 618 | dev: false 619 | 620 | /rc/1.2.8: 621 | resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} 622 | hasBin: true 623 | dependencies: 624 | deep-extend: 0.6.0 625 | ini: 1.3.8 626 | minimist: 1.2.6 627 | strip-json-comments: 2.0.1 628 | dev: false 629 | 630 | /readable-stream/3.6.0: 631 | resolution: {integrity: sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==} 632 | engines: {node: '>= 6'} 633 | dependencies: 634 | inherits: 2.0.4 635 | string_decoder: 1.3.0 636 | util-deprecate: 1.0.2 637 | dev: false 638 | 639 | /regenerator-runtime/0.13.9: 640 | resolution: {integrity: sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==} 641 | dev: false 642 | 643 | /rfdc/1.3.0: 644 | resolution: {integrity: sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==} 645 | dev: false 646 | 647 | /roarr/7.12.3: 648 | resolution: {integrity: sha512-EhX9kTlWj4wTqQ0qVX2XvnYZqXhyi3zO/Rq7zAkCcmnawBAZrRpii71PiFbjyWS8yi1TrxWrShpcGBT6WGdCAw==} 649 | engines: {node: '>=12.0'} 650 | dependencies: 651 | boolean: 3.2.0 652 | fast-json-stringify: 2.7.13 653 | fast-printf: 1.6.9 654 | fast-safe-stringify: 2.1.1 655 | globalthis: 1.0.3 656 | semver-compare: 1.0.0 657 | dev: false 658 | 659 | /safe-buffer/5.2.1: 660 | resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} 661 | dev: false 662 | 663 | /secure-json-parse/2.5.0: 664 | resolution: {integrity: sha512-ZQruFgZnIWH+WyO9t5rWt4ZEGqCKPwhiw+YbzTwpmT9elgLrLcfuyUiSnwwjUiVy9r4VM3urtbNF1xmEh9IL2w==} 665 | dev: false 666 | 667 | /semver-compare/1.0.0: 668 | resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==} 669 | dev: false 670 | 671 | /semver/7.3.7: 672 | resolution: {integrity: sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==} 673 | engines: {node: '>=10'} 674 | hasBin: true 675 | dependencies: 676 | lru-cache: 6.0.0 677 | dev: false 678 | 679 | /serialize-error/8.1.0: 680 | resolution: {integrity: sha512-3NnuWfM6vBYoy5gZFvHiYsVbafvI9vZv/+jlIigFn4oP4zjNPK3LhcY0xSCgeb1a5L8jO71Mit9LlNoi2UfDDQ==} 681 | engines: {node: '>=10'} 682 | dependencies: 683 | type-fest: 0.20.2 684 | dev: false 685 | 686 | /simple-concat/1.0.1: 687 | resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} 688 | dev: false 689 | 690 | /simple-get/4.0.1: 691 | resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} 692 | dependencies: 693 | decompress-response: 6.0.0 694 | once: 1.4.0 695 | simple-concat: 1.0.1 696 | dev: false 697 | 698 | /slonik/30.3.1: 699 | resolution: {integrity: sha512-b+oY3WJisbOcMWUYjuiWQSEIzcvcY7vrR+PGDFNWY4cf0c59IGburobLFYiXs+AbIe0lFG+XJAwiLk58g31LqQ==} 700 | engines: {node: '>=10.0'} 701 | dependencies: 702 | concat-stream: 2.0.0 703 | es6-error: 4.1.1 704 | fast-safe-stringify: 2.1.1 705 | get-stack-trace: 2.1.1 706 | hyperid: 2.3.1 707 | is-plain-object: 5.0.0 708 | iso8601-duration: 1.3.0 709 | p-defer: 3.0.0 710 | pg: 8.8.0 711 | pg-copy-streams: 6.0.2 712 | pg-copy-streams-binary: 2.2.0 713 | pg-cursor: 2.7.4_pg@8.8.0 714 | pg-protocol: 1.5.0 715 | pg-types: 4.0.0 716 | postgres-array: 3.0.1 717 | postgres-interval: 4.0.0 718 | roarr: 7.12.3 719 | serialize-error: 8.1.0 720 | through2: 4.0.2 721 | zod: 3.18.0 722 | transitivePeerDependencies: 723 | - pg-native 724 | dev: false 725 | 726 | /source-map/0.8.0-beta.0: 727 | resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} 728 | engines: {node: '>= 8'} 729 | dependencies: 730 | whatwg-url: 7.1.0 731 | dev: false 732 | 733 | /split2/4.1.0: 734 | resolution: {integrity: sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==} 735 | engines: {node: '>= 10.x'} 736 | dev: false 737 | 738 | /string-similarity/4.0.4: 739 | resolution: {integrity: sha512-/q/8Q4Bl4ZKAPjj8WerIBJWALKkaPRfrvhfF8k/B23i4nzrlRj2/go1m90In7nG/3XDSbOo0+pu6RvCTM9RGMQ==} 740 | dev: false 741 | 742 | /string_decoder/1.3.0: 743 | resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} 744 | dependencies: 745 | safe-buffer: 5.2.1 746 | dev: false 747 | 748 | /strip-json-comments/2.0.1: 749 | resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} 750 | engines: {node: '>=0.10.0'} 751 | dev: false 752 | 753 | /tar-fs/2.1.1: 754 | resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==} 755 | dependencies: 756 | chownr: 1.1.4 757 | mkdirp-classic: 0.5.3 758 | pump: 3.0.0 759 | tar-stream: 2.2.0 760 | dev: false 761 | 762 | /tar-stream/2.2.0: 763 | resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} 764 | engines: {node: '>=6'} 765 | dependencies: 766 | bl: 4.1.0 767 | end-of-stream: 1.4.4 768 | fs-constants: 1.0.0 769 | inherits: 2.0.4 770 | readable-stream: 3.6.0 771 | dev: false 772 | 773 | /through2/3.0.2: 774 | resolution: {integrity: sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==} 775 | dependencies: 776 | inherits: 2.0.4 777 | readable-stream: 3.6.0 778 | dev: false 779 | 780 | /through2/4.0.2: 781 | resolution: {integrity: sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==} 782 | dependencies: 783 | readable-stream: 3.6.0 784 | dev: false 785 | 786 | /tr46/0.0.3: 787 | resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} 788 | dev: false 789 | 790 | /tr46/1.0.1: 791 | resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} 792 | dependencies: 793 | punycode: 2.1.1 794 | dev: false 795 | 796 | /tunnel-agent/0.6.0: 797 | resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} 798 | dependencies: 799 | safe-buffer: 5.2.1 800 | dev: false 801 | 802 | /type-fest/0.20.2: 803 | resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} 804 | engines: {node: '>=10'} 805 | dev: false 806 | 807 | /typedarray/0.0.6: 808 | resolution: {integrity: sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==} 809 | dev: false 810 | 811 | /typesense/1.4.0_@babel+runtime@7.18.9: 812 | resolution: {integrity: sha512-+Y6WYNB3+z5bR1/F5AfHQyqdeKGOZW0k2l0HSFgCFl+3wo6oY42lAhJG2JZk6k8ux3j4866IyruKsCG5NtlHMQ==} 813 | peerDependencies: 814 | '@babel/runtime': ^7.17.2 815 | dependencies: 816 | '@babel/runtime': 7.18.9 817 | axios: 0.26.1 818 | loglevel: 1.8.0 819 | transitivePeerDependencies: 820 | - debug 821 | dev: false 822 | 823 | /uri-js/4.4.1: 824 | resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} 825 | dependencies: 826 | punycode: 2.1.1 827 | dev: false 828 | 829 | /util-deprecate/1.0.2: 830 | resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} 831 | dev: false 832 | 833 | /uuid-parse/1.1.0: 834 | resolution: {integrity: sha512-OdmXxA8rDsQ7YpNVbKSJkNzTw2I+S5WsbMDnCtIWSQaosNAcWtFuI/YK1TjzUI6nbkgiqEyh8gWngfcv8Asd9A==} 835 | dev: false 836 | 837 | /uuid/8.3.2: 838 | resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} 839 | hasBin: true 840 | dev: false 841 | 842 | /webidl-conversions/3.0.1: 843 | resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} 844 | dev: false 845 | 846 | /webidl-conversions/4.0.2: 847 | resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} 848 | dev: false 849 | 850 | /whatwg-url/5.0.0: 851 | resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} 852 | dependencies: 853 | tr46: 0.0.3 854 | webidl-conversions: 3.0.1 855 | dev: false 856 | 857 | /whatwg-url/7.1.0: 858 | resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} 859 | dependencies: 860 | lodash.sortby: 4.7.0 861 | tr46: 1.0.1 862 | webidl-conversions: 4.0.2 863 | dev: false 864 | 865 | /wrappy/1.0.2: 866 | resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} 867 | dev: false 868 | 869 | /xtend/4.0.2: 870 | resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} 871 | engines: {node: '>=0.4'} 872 | dev: false 873 | 874 | /yallist/4.0.0: 875 | resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} 876 | dev: false 877 | 878 | /zod/3.18.0: 879 | resolution: {integrity: sha512-gwTm8RfUCe8l9rDwN5r2A17DkAa8Ez4Yl4yXqc5VqeGaXaJahzYYXbTwvhroZi0SNBqTwh/bKm2N0mpCzuw4bA==} 880 | dev: false 881 | -------------------------------------------------------------------------------- /results/meilisearch.output: -------------------------------------------------------------------------------- 1 | [info] importing driver from [./meilisearch.mjs] 2 | [info] finished initializing driver [meilisearch] 3 | [info] processing lines in [/home/mrman/code/work/supabase/pg-fts-benchmark/movies.ndjson.json]... 4 | [info] successfully processed [44946] lines 5 | [info] importing driver from [./meilisearch.mjs] 6 | [info] finished initializing driver [meilisearch] 7 | [info] processing lines in [/home/mrman/code/work/supabase/pg-fts-benchmark/search-phrases.ndjson.json]... 8 | | `meilisearch` | "super hero" | `56` | `4.82` | `0.0861` | 9 | | `meilisearch` | "superhero" | `14` | `4.39` | `0.313` | 10 | | `meilisearch` | "superman" | `41` | `3.45` | `0.0841` | 11 | | `meilisearch` | "suprman" | `29` | `2.69` | `0.0929` | 12 | | `meilisearch` | "love" | `812` | `12.4` | `0.0153` | 13 | | `meilisearch` | "world war" | `316` | `8.53` | `0.0270` | 14 | | `meilisearch` | "spy" | `47` | `3.57` | `0.0760` | 15 | | `meilisearch` | "romance" | `35` | `3.05` | `0.0871` | 16 | | `meilisearch` | "comedy" | `67` | `3.46` | `0.0516` | 17 | | `meilisearch` | "awakening" | `15` | `3.63` | `0.242` | 18 | [info] successfully processed [10] lines 19 | -------------------------------------------------------------------------------- /results/opensearch.output: -------------------------------------------------------------------------------- 1 | fts-opensearch 2 | 9455e8276b7388cb58884cd7817330a611f9094c504d93c08cd59f615441e95a 3 | [info] started docker container [fts-opensearch]... 4 | [info] waiting for TCP connectivity to [fts-opensearch]... 5 | 2022-08-31T06:59:37Z INF [TCP] Checking the localhost:9200 ... 6 | [info] importing driver from [./opensearch.mjs] 7 | [info] finished initializing driver [opensearch] 8 | [info] ingesting lines in [/home/mrman/code/work/supabase/pg-fts-benchmark/movies.ndjson.json]... 9 | [error] successfully wrote batch of [20000] documents to ES 10 | [error] successfully wrote batch of [20000] documents to ES 11 | [error] successfully wrote batch of [20000] documents to ES 12 | [error] successfully wrote batch of [20000] documents to ES 13 | [error] successfully wrote batch of [9884] documents to ES 14 | [info] importing driver from [./opensearch.mjs] 15 | [info] finished initializing driver [opensearch] 16 | [info] ingesting lines in [/home/mrman/code/work/supabase/pg-fts-benchmark/search-phrases.ndjson.json]... 17 | [timing] phrase [super hero]: returned [431] results in 96.915658.ms 18 | [timing] phrase [superhero]: returned [45] results in 12.583994.ms 19 | [timing] phrase [superman]: returned [25] results in 10.57763.ms 20 | [timing] phrase [suprman]: returned [0] results in 7.280828.ms 21 | [timing] phrase [love]: returned [3036] results in 133.216874.ms 22 | [timing] phrase [world war]: returned [3805] results in 172.439469.ms 23 | [timing] phrase [spy]: returned [168] results in 15.957199.ms 24 | [timing] phrase [romance]: returned [383] results in 25.489779.ms 25 | [timing] phrase [comedy]: returned [756] results in 38.907331.ms 26 | [timing] phrase [awakening]: returned [32] results in 9.015631.ms 27 | fts-opensearch 28 | Error: No such container: fts-opensearch 29 | fts-opensearch 30 | -------------------------------------------------------------------------------- /results/pg.output: -------------------------------------------------------------------------------- 1 | [info] importing driver from [./pg.mjs] 2 | [info] finished initializing driver [pg] 3 | [info] processing lines in [/home/mrman/code/work/supabase/pg-fts-benchmark/movies.ndjson.json]... 4 | [info] successfully processed [44946] lines 5 | [info] importing driver from [./pg.mjs] 6 | [info] finished initializing driver [pg] 7 | [info] processing lines in [/home/mrman/code/work/supabase/pg-fts-benchmark/search-phrases.ndjson.json]... 8 | | `pg` | "super hero" | `34` | `3.68` | `0.108` | 9 | | `pg` | "superhero" | `86` | `1.59` | `0.0184` | 10 | | `pg` | "superman" | `47` | `1.24` | `0.0264` | 11 | | `pg` | "suprman" | `0` | `0.999` | `Infinity` | 12 | | `pg` | "love" | `5417` | `15.3` | `0.00282` | 13 | | `pg` | "world war" | `834` | `2.94` | `0.00352` | 14 | | `pg` | "spy" | `349` | `1.78` | `0.00510` | 15 | | `pg` | "romance" | `630` | `2.14` | `0.00339` | 16 | | `pg` | "comedy" | `1213` | `3.55` | `0.00292` | 17 | | `pg` | "awakening" | `210` | `1.93` | `0.00919` | 18 | [info] successfully processed [10] lines 19 | -------------------------------------------------------------------------------- /results/sqlite-disk.output: -------------------------------------------------------------------------------- 1 | [info] using SQLite DB @ [./fts-sqlite-disk-db.sqlite]... 2 | [info] importing driver from [./sqlite-disk.mjs] 3 | [info] using SQLite DB @ [./fts-sqlite-disk-db.sqlite] 4 | [info] finished initializing driver [sqlite-disk] 5 | [info] ingesting lines in [/home/mrman/code/work/supabase/pg-fts-benchmark/movies.ndjson.json]... 6 | [info] importing driver from [./sqlite-disk.mjs] 7 | [info] using SQLite DB @ [./fts-sqlite-disk-db.sqlite] 8 | [info] finished initializing driver [sqlite-disk] 9 | [info] ingesting lines in [/home/mrman/code/work/supabase/pg-fts-benchmark/search-phrases.ndjson.json]... 10 | [timing] phrase [super hero]: returned [20] results in 0.633051.ms 11 | [timing] phrase [superhero]: returned [67] results in 0.540679.ms 12 | [timing] phrase [superman]: returned [47] results in 0.460226.ms 13 | [timing] phrase [suprman]: returned [0] results in 0.124516.ms 14 | [timing] phrase [love]: returned [4691] results in 26.88778.ms 15 | [timing] phrase [world war]: returned [781] results in 5.13194.ms 16 | [timing] phrase [spy]: returned [241] results in 1.043932.ms 17 | [timing] phrase [romance]: returned [554] results in 2.00016.ms 18 | [timing] phrase [comedy]: returned [1220] results in 4.285304.ms 19 | [timing] phrase [awakening]: returned [63] results in 0.335899.ms 20 | [info] Plesae delete SQLite @ [./fts-sqlite-disk-db.sqlite] manually 21 | -------------------------------------------------------------------------------- /results/sqlite-mem.output: -------------------------------------------------------------------------------- 1 | [info] using SQLite DB @ [./fts-sqlite-disk-db.sqlite]... 2 | [info] importing driver from [./sqlite-mem.mjs] 3 | [info] using SQLite DB @ [:memory:] 4 | [info] finished initializing driver [sqlite-mem] 5 | [info] ingesting lines in [/home/mrman/code/work/supabase/pg-fts-benchmark/movies.ndjson.json]... 6 | [info] ingesting lines in [/home/mrman/code/work/supabase/pg-fts-benchmark/search-phrases.ndjson.json]... 7 | [timing] phrase [super hero]: returned [20] results in 0.590835.ms 8 | [timing] phrase [superhero]: returned [67] results in 0.349986.ms 9 | [timing] phrase [superman]: returned [47] results in 0.351138.ms 10 | [timing] phrase [suprman]: returned [0] results in 0.07513.ms 11 | [timing] phrase [love]: returned [4691] results in 17.030276.ms 12 | [timing] phrase [world war]: returned [781] results in 2.770685.ms 13 | [timing] phrase [spy]: returned [241] results in 0.606127.ms 14 | [timing] phrase [romance]: returned [554] results in 1.383845.ms 15 | [timing] phrase [comedy]: returned [1220] results in 3.116755.ms 16 | [timing] phrase [awakening]: returned [63] results in 0.25198.ms 17 | ingest and query for sqlite memory happen *at the same time*, this is a no-op 18 | [info] SQLite DB stop is a no-op 19 | -------------------------------------------------------------------------------- /results/typesense.output: -------------------------------------------------------------------------------- 1 | 01327528fa3471bec4934b67bba3292593ce4a6c5d5e03c5ecc3f1f15876fc99 2 | [info] started docker container [fts-typesense]... 3 | [info] waiting for TCP connectivity to [fts-typesense]... 4 | 2022-08-31T06:56:17Z INF [TCP] Checking the localhost:8108 ... 5 | [info] importing driver from [./typesense.mjs] 6 | [info] finished initializing driver [typesense] 7 | [info] ingesting lines in [/home/mrman/code/work/supabase/pg-fts-benchmark/movies.ndjson.json]... 8 | [info] importing driver from [./typesense.mjs] 9 | [info] finished initializing driver [typesense] 10 | [info] ingesting lines in [/home/mrman/code/work/supabase/pg-fts-benchmark/search-phrases.ndjson.json]... 11 | [timing] phrase [super hero]: returned [8] results in 11.896117.ms 12 | [timing] phrase [superhero]: returned [8] results in 4.079828.ms 13 | [timing] phrase [superman]: returned [28] results in 4.222797.ms 14 | [timing] phrase [suprman]: returned [28] results in 3.663458.ms 15 | [timing] phrase [love]: returned [745] results in 34.869289.ms 16 | [timing] phrase [world war]: returned [11] results in 2.438208.ms 17 | [timing] phrase [spy]: returned [47] results in 3.214292.ms 18 | [timing] phrase [romance]: returned [34] results in 2.48651.ms 19 | [timing] phrase [comedy]: returned [55] results in 3.314717.ms 20 | [timing] phrase [awakening]: returned [14] results in 2.889301.ms 21 | fts-typesense 22 | Error: No such container: fts-typesense 23 | -------------------------------------------------------------------------------- /search-phrases.ndjson.json: -------------------------------------------------------------------------------- 1 | "super hero" 2 | "superhero" 3 | "superman" 4 | "suprman" 5 | "love" 6 | "world war" 7 | "spy" 8 | "romance" 9 | "comedy" 10 | "awakening" 11 | -------------------------------------------------------------------------------- /src/driver/index.mjs: -------------------------------------------------------------------------------- 1 | /* global process */ 2 | import * as readline from "node:readline/promises"; 3 | import * as fs from "node:fs"; 4 | 5 | async function executeIngest({ driver, inputPath }) { 6 | let processed = 0; 7 | 8 | if (!inputPath) { throw new Error(`Missing/invalid [${inputPath}]`); } 9 | 10 | const lines = readline.createInterface({ 11 | input: fs.createReadStream(inputPath), 12 | crlfDelay: Infinity, 13 | }); 14 | 15 | let before; 16 | let elapsed; 17 | let ids; 18 | 19 | process.stderr.write(`[info] ingesting lines in [${inputPath}]...\n`); 20 | for await (const line of lines) { 21 | // Parse incoming line as JSON 22 | let obj; 23 | try { 24 | obj = JSON.parse(line); 25 | } catch (err) { 26 | process.stderr.write(`failed to parse line as JSON: [${line}]\n`); 27 | } 28 | 29 | await driver.ingest({ 30 | document: obj, 31 | }); 32 | processed++; 33 | } 34 | 35 | // For drivers that care when ingestion has completed (for example those that batch updates) 36 | // Mark ingestion completed, allow driver to perform any final operations 37 | if (driver.ingestWait) { await driver.ingestWait(); } 38 | 39 | if (process.env.DEBUG) { 40 | process.stderr.write(`[info] successfully processed [${processed}] lines\n`); 41 | } 42 | } 43 | 44 | async function executeQuery({ driver, inputPath }) { 45 | let processed = 0; 46 | const lines = readline.createInterface({ 47 | input: fs.createReadStream(inputPath), 48 | crlfDelay: Infinity, 49 | }); 50 | 51 | let before; 52 | let elapsed; 53 | let ids; 54 | 55 | process.stderr.write(`[info] ingesting and running search phrases in [${inputPath}]...\n`); 56 | for await (const line of lines) { 57 | // Parse incoming line as JSON 58 | let obj; 59 | try { 60 | obj = JSON.parse(line); 61 | } catch (err) { 62 | process.stderr.write(`failed to parse line as JSON: [${line}]\n`); 63 | } 64 | 65 | if (process.env.TIMING) { before = process.hrtime(); } 66 | 67 | const { ids } = await driver.query({ phrase: obj }); 68 | 69 | if (process.env.TIMING) { 70 | elapsed = process.hrtime(before)[1] / 1_000_000; 71 | if (process.env.TIMING_FORMAT === "md-table") { 72 | process.stderr.write(`| \`${process.env.FTS_ENGINE}\` | "${obj}" | \`${ids.length}\` | \`${elapsed.toPrecision(3)}\` | \`${(elapsed / ids.length * 1.0).toPrecision(3)}\` |\n`); 73 | } else { 74 | process.stderr.write(`[timing] phrase ["${obj}"]: returned [${ids.length}] results in ${elapsed}.ms\n`); 75 | } 76 | } 77 | 78 | processed++; 79 | } 80 | 81 | if (process.env.DEBUG && processed % 1000 === 0) { 82 | process.stderr.write(`[info] successfully queried [${processed}] lines\n`); 83 | } 84 | 85 | if (!process.env.TIMING) { 86 | process.stderr.write(`[info] set TIMING=true to see timing data for each query!\n`); 87 | } 88 | 89 | process.stderr.write(`[info] finished running search queries\n`); 90 | } 91 | 92 | // Ingest ndjson into a given search engine driver 93 | export async function execute({ op, driver, ingestInputPath, queryInputPath }) { 94 | // Handle the intended operation 95 | switch (op) { 96 | // Ingestion 97 | case "ingest": 98 | await executeIngest({ driver, inputPath: ingestInputPath }); 99 | break; 100 | 101 | // Querying 102 | case "query": 103 | await executeQuery({ driver, inputPath: queryInputPath }); 104 | break; 105 | 106 | // Ingestion 107 | case "ingest+query": 108 | await executeIngest({ driver, inputPath: ingestInputPath }); 109 | await executeQuery({ driver, inputPath: queryInputPath }); 110 | break; 111 | 112 | // Unknown operation 113 | default: 114 | throw new Error(`Missing/invalid operation [${op}]`); 115 | } 116 | } 117 | 118 | // Initialize the driver set by FTS_ENGINE 119 | async function createDriver({ engine }) { 120 | const driverJSPath = `./${engine}.mjs`; 121 | console.log(`[info] importing driver from [${driverJSPath}]`); 122 | 123 | const driver = await import(driverJSPath); 124 | if (!driver.build || typeof driver.build !== "function") { throw new Error(`Invalid driver @ [${driverJSPath}], should expose a 'build' function`); } 125 | 126 | const result = driver.build(); 127 | if (!(result instanceof Promise)) { throw new Error(`Invalid driver @ [${driverJSPath}], 'build' function should return a Promise`); } 128 | 129 | return await result; 130 | } 131 | 132 | async function main() { 133 | if (!process.env.FTS_ENGINE) { 134 | throw new Error(`[error] Invalid/missing FTS engine [${process.env.FTS_ENGINE}] (did you specify FTS_ENGINE ?)`); 135 | } 136 | 137 | // Set up and initialize driver (an object expected to contain ingest, init and query functions) 138 | const driver = await createDriver({ engine: process.env.FTS_ENGINE }); 139 | process.stderr.write(`[info] finished initializing driver [${process.env.FTS_ENGINE}]\n`); 140 | 141 | const op = process.env.OP; 142 | // Process operation 143 | switch (op) { 144 | case 'query': 145 | case 'ingest': 146 | case 'ingest+query': 147 | 148 | if (op.includes("ingest") && (!process.env.INGEST_INPUT_PATH || !fs.existsSync(process.env.INGEST_INPUT_PATH))) { 149 | throw new Error(`[error] Invalid/missing input path [${process.env.INGEST_INPUT_PATH}] (did you a valid ndjson file for INGEST_INPUT_PATH?)`); 150 | } 151 | 152 | if (op.includes("query") && (!process.env.QUERY_INPUT_PATH || !fs.existsSync(process.env.QUERY_INPUT_PATH))) { 153 | throw new Error(`[error] Invalid/missing input path [${process.env.QUERY_INPUT_PATH}] (did you a valid ndjson file for QUERY_INPUT_PATH?)`); 154 | } 155 | 156 | await execute({ 157 | driver, 158 | op: process.env.OP, 159 | ingestInputPath: process.env.INGEST_INPUT_PATH, 160 | queryInputPath: process.env.QUERY_INPUT_PATH, 161 | }); 162 | break; 163 | 164 | default: 165 | throw new Error(`[error] Invalid operation [${process.env.OP}] (did you specify OP?)`); 166 | } 167 | } 168 | 169 | main(); 170 | -------------------------------------------------------------------------------- /src/driver/meilisearch.mjs: -------------------------------------------------------------------------------- 1 | /* global process */ 2 | import { waitFor, TimeoutError } from "async-wait-for-promise"; 3 | import { MeiliSearch } from "meilisearch"; 4 | 5 | const INDEX_NAME = "movies"; 6 | const LARGE_LIMIT = 100_000; 7 | 8 | async function connectMeilisearch() { 9 | // Create MeiliSearch Host 10 | if (!process.env.MEILI_URL) { 11 | throw new Error(`[error] Missing/invalid MeiliSearch URL [${process.env.MEILI_URL}] (did you specify MEILI_URL?)`); 12 | } 13 | const url = process.env.MEILI_URL; 14 | 15 | // Create MeiliSearch API Key 16 | if (!process.env.MEILI_API_KEY) { 17 | throw new Error(`[error] Missing/invalid MeiliSearch URL [${process.env.MEILI_API_KEY}] (did you specify MEILI_API_KEY?)`); 18 | } 19 | const apiKey = process.env.MEILI_API_KEY; 20 | 21 | // Create MeiliSearch client 22 | const client = new MeiliSearch({ host: url, apiKey }); 23 | 24 | if (process.env.FTS_ENGINE_RESET_AT_INIT) { 25 | let deleteIndexResult = await client.index.deleteIndex(); 26 | // Wait for task to complete 27 | await waitFor( 28 | async () => { 29 | const taskNow = await client.getTask(deleteIndexResult.taskUid); 30 | if (taskNow.status !== "succeeded") { return null; } 31 | return true; 32 | }, 33 | { timeoutMs: 5 * 1000 }, 34 | ); 35 | } 36 | 37 | // Create the index 38 | const indexCreateResult = await client.createIndex(INDEX_NAME, { primaryKey: 'id' }); 39 | try { 40 | // Wait for task to complete 41 | await waitFor( 42 | async () => { 43 | const taskNow = await client.getTask(indexCreateResult.taskUid); 44 | 45 | if (taskNow.status === "failed" && taskNow.error.code === "index_already_exists") { 46 | return true; 47 | } 48 | 49 | if (taskNow.status === "succeeded") { return true; } 50 | 51 | return null; 52 | }, 53 | { timeoutMs: 6000 * 1000 }, 54 | ); 55 | } catch (err) { 56 | process.stderr.write(`[error] failed to create index \n`); 57 | throw err; 58 | } 59 | 60 | const index = client.index(INDEX_NAME); 61 | 62 | return { 63 | client, 64 | index, 65 | }; 66 | } 67 | 68 | let CURRENT_BATCH = []; 69 | const BATCH_SIZE = 10_000; 70 | 71 | export async function build() { 72 | const { client, index } = await connectMeilisearch(); 73 | 74 | // Build a functoin for sending batches 75 | const sendBatch = async (batch) => { 76 | if (process.env.DEBUG) { 77 | process.stderr.write(`[debug] sending batch ([${BATCH_SIZE}] documents)\n`); 78 | } 79 | 80 | const updateDocumentsResult = await index.updateDocuments(batch); 81 | 82 | // Wait for meilisearch task to complete 83 | await waitFor( 84 | async () => { 85 | const taskNow = await client.getTask(updateDocumentsResult.taskUid); 86 | if (taskNow.status === "succeeded") { return true; } 87 | return null; 88 | }, 89 | { timeoutMs: 60 * 1000, intervalMs: 10, }, 90 | ); 91 | }; 92 | 93 | return { 94 | // Ingesting search documents 95 | async ingest({ document }) { 96 | if (CURRENT_BATCH.length < BATCH_SIZE) { 97 | CURRENT_BATCH.push({ 98 | id: document.id, 99 | title: document.title, 100 | overview: document.overview, 101 | original_title: document.original_title, 102 | }); 103 | return; 104 | } 105 | 106 | await sendBatch(CURRENT_BATCH); 107 | 108 | CURRENT_BATCH = []; 109 | }, 110 | 111 | // Querying search phrases 112 | async query({ phrase }) { 113 | 114 | const results = await index.search(phrase, { limit: LARGE_LIMIT }); 115 | 116 | // Gather IDs of hits 117 | const ids = results.hits.map(r => r.id); 118 | if (process.env.DEBUG) { 119 | process.stderr.write(`[debug] Search for [${phrase}] returned [${ids.length}] ids\n`); 120 | } 121 | 122 | return { ids }; 123 | }, 124 | 125 | /// Final ingest wait 126 | async ingestWait() { 127 | // Send final batch 128 | await sendBatch(CURRENT_BATCH); 129 | }, 130 | }; 131 | } 132 | -------------------------------------------------------------------------------- /src/driver/opensearch.mjs: -------------------------------------------------------------------------------- 1 | /* global process */ 2 | import { waitFor, TimeoutError } from "async-wait-for-promise"; 3 | import { Client } from "@opensearch-project/opensearch"; 4 | 5 | const INDEX_NAME = "movies"; 6 | const INDEX_SETTINGS = { 7 | settings: { 8 | index: { 9 | number_of_shards: 1, 10 | number_of_replicas: 1, 11 | } 12 | } 13 | }; 14 | 15 | async function connectOpenSearch() { 16 | // Create OpenSearch Host 17 | if (!process.env.OPENSEARCH_HOST) { 18 | throw new Error(`[error] Missing/invalid OpenSearch host [${process.env.OPENSEARCH_HOST}] (did you specify OPENSEARCH_HOST?)`); 19 | } 20 | const host = process.env.OPENSEARCH_HOST; 21 | 22 | // Create OpenSearch Protocol 23 | const protocol = process.env.OPENSEARCH_PROTOCOL ?? "https"; 24 | 25 | // Create OpenSearch Port 26 | if (!process.env.OPENSEARCH_PORT) { 27 | throw new Error(`[error] Missing/invalid OpenSearch port [${process.env.OPENSEARCH_PORT}] (did you specify OPENSEARCH_PORT?)`); 28 | } 29 | const port = process.env.OPENSEARCH_PORT; 30 | 31 | if (!process.env.OPENSEARCH_AUTH_USERNAME) { 32 | throw new Error(`[error] Missing/invalid OpenSearch auth username [${process.env.OPENSEARCH_AUTH_USERNAME}] (did you specify OPENSEARCH_AUTH_USERNAME?)`); 33 | } 34 | const username = process.env.OPENSEARCH_AUTH_USERNAME; 35 | 36 | if (!process.env.OPENSEARCH_AUTH_PASSWORD) { 37 | throw new Error(`[error] Missing/invalid OpenSearch auth password [${process.env.OPENSEARCH_AUTH_PASSWORD}] (did you specify OPENSEARCH_AUTH_PASSWORD?)`); 38 | } 39 | const password = process.env.OPENSEARCH_AUTH_PASSWORD; 40 | 41 | const node = `${protocol}://${username}:${password}@${host}:${port}`; 42 | if (process.env.DEBUG) { 43 | process.stderr.write(`[info] connecting to node [${node}]\n`); 44 | } 45 | 46 | // Create OpenSearch client 47 | const client = new Client({ 48 | node, 49 | ssl: { rejectUnauthorized: false }, 50 | }); 51 | 52 | if (process.env.FTS_ENGINE_RESET_AT_INIT) { 53 | await client.indices.delete({ 54 | index: INDEX_NAME, 55 | }); 56 | } 57 | 58 | // Create the index 59 | try { 60 | await client.indices.create({ 61 | index: INDEX_NAME, 62 | body: INDEX_SETTINGS, 63 | }); 64 | } catch (err) { 65 | if (err.meta && err.meta.body && err.meta.body.error && err.meta.body.error.root_cause.some(c => c.type === "resource_already_exists_exception")) { 66 | if (process.env.DEBUG) { 67 | process.stderr.write(`[debug] skipping creating index [${INDEX_NAME}], it already exists`); 68 | } 69 | } else { 70 | process.stderr.write(`[error] failed to create [${INDEX_NAME}]`); 71 | throw err; 72 | } 73 | } 74 | 75 | return { client }; 76 | } 77 | 78 | let CURRENT_BATCH = []; 79 | const BATCH_SIZE = 10_000; 80 | 81 | export async function build() { 82 | const { client, index } = await connectOpenSearch(); 83 | 84 | // Build a functoin for sending batches 85 | const sendBatch = async (batch) => { 86 | if (process.env.DEBUG) { 87 | process.stderr.write(`[debug] sending batch ([${BATCH_SIZE}] documents)\n`); 88 | } 89 | 90 | const result = await client.bulk({ 91 | body: CURRENT_BATCH, 92 | }); 93 | 94 | const failed = Math.min(0, CURRENT_BATCH.length - result.body.items.length); 95 | 96 | if (failed > 0) { 97 | process.stderr.write(`[error] failed to insert all items into batch (${failed} failed)\n`); 98 | } 99 | 100 | process.stderr.write(`[error] successfully wrote batch of [${CURRENT_BATCH.length - failed}] documents to ES\n`); 101 | }; 102 | 103 | return { 104 | // Ingesting search documents 105 | async ingest({ document }) { 106 | if (CURRENT_BATCH.length < BATCH_SIZE * 2) { 107 | CURRENT_BATCH.push({ 108 | index: { 109 | _index: INDEX_NAME, 110 | _id: document.id, 111 | }, 112 | }); 113 | CURRENT_BATCH.push({ 114 | title: document.title, 115 | original_title: document.original_title, 116 | overview: document.overview, 117 | }); 118 | return; 119 | } 120 | 121 | await sendBatch(CURRENT_BATCH); 122 | 123 | CURRENT_BATCH = []; 124 | }, 125 | 126 | // Querying search phrases 127 | async query({ phrase }) { 128 | 129 | // Get first page of results 130 | const resp = await client.search({ 131 | index: INDEX_NAME, 132 | body: { 133 | size: 10_000, // max 134 | query: { 135 | multi_match: { 136 | query: phrase, 137 | fields: [ "title", "original_title", "overview" ], 138 | }, 139 | }, 140 | }, 141 | }); 142 | 143 | // Gather IDs of hits 144 | const ids = resp.body.hits.hits.map(r => r.id); 145 | if (process.env.DEBUG && !process.env.TIMING_FORMAT) { 146 | process.stderr.write(`[debug] Search for [${phrase}] returned [${ids.length}] ids\n`); 147 | } 148 | 149 | return { ids }; 150 | }, 151 | 152 | /// Final ingest wait 153 | async ingestWait() { 154 | if (CURRENT_BATCH.length === 0) { return; } 155 | // Send final batch 156 | await sendBatch(CURRENT_BATCH); 157 | }, 158 | }; 159 | } 160 | -------------------------------------------------------------------------------- /src/driver/pg.mjs: -------------------------------------------------------------------------------- 1 | /* global process */ 2 | import { createPool, sql } from "slonik"; 3 | 4 | async function buildPool() { 5 | if (!process.env.PG_URL) { 6 | throw new Error(`[error] Missing/invalid Postgres URL connection [${process.env.PG_URL}] (did you specify PG_URL?)`); 7 | } 8 | 9 | const pool = await createPool(process.env.PG_URL); 10 | 11 | // Set up the initial table 12 | await pool.query(sql` 13 | CREATE TABLE IF NOT EXISTS movies ( 14 | id bigint PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY, 15 | title text NOT NULL, 16 | original_title text NOT NULL, 17 | tagline text, 18 | overview text NOT NULL, 19 | released_at timestamptz NOT NULL, 20 | created_at timestamptz NOT NULL DEFAULT NOW(), 21 | fts_doc_en tsvector GENERATED ALWAYS AS (to_tsvector('english', title || ' ' || original_title || ' ' || overview || ' ' )) STORED 22 | ); 23 | 24 | CREATE INDEX IF NOT EXISTS movies_fts_doc_en_idx ON movies USING GIN (fts_doc_en); 25 | `); 26 | 27 | if (process.env.FTS_ENGINE_RESET_AT_INIT) { 28 | await pool.query(`TRUNCATE TABLE movies`); 29 | } 30 | 31 | return pool; 32 | } 33 | 34 | export async function build() { 35 | const pool = await buildPool(); 36 | 37 | return { 38 | 39 | // Ingesting search documents 40 | async ingest({ document }) { 41 | try { 42 | // Ignore rows without proper release dates 43 | if (!document.release_date || document.release_date?.trim().length === 0) { 44 | if (process.env.DEBUG) { 45 | process.stderr.write(`[error] invalid release date for doc: [${document.id}] (title? "${document.title}"`); 46 | } 47 | return; 48 | } 49 | 50 | await pool.query(sql` 51 | INSERT into movies 52 | (id, title, original_title, overview, released_at) 53 | VALUES 54 | (${document.id}, ${document.title}, ${document.original_title}, ${document.overview}, ${new Date(document.release_date).toISOString()}::timestamptz) 55 | ON CONFLICT (id) DO UPDATE SET 56 | title=${document.title} 57 | , original_title=${document.original_title} 58 | , overview=${document.overview} 59 | , released_at=${new Date(document.release_date).toISOString()}::timestamptz 60 | ; 61 | `); 62 | } catch (err) { 63 | if (process.env.DEBUG) { 64 | process.stderr.write(`[error] failed to ingest document:\n ${JSON.stringify(document, null, 2)}`); 65 | } 66 | throw err; 67 | } 68 | }, 69 | 70 | // Querying search phrases 71 | async query({ phrase }) { 72 | const results = await pool.query(sql` 73 | SELECT id, title 74 | FROM movies 75 | WHERE fts_doc_en @@ websearch_to_tsquery('english', ${phrase}::text) 76 | `); 77 | 78 | const ids = results.rows.map(r => r.id); 79 | if (process.env.DEBUG) { 80 | process.stderr.write(`[debug] Search for [${phrase}] returned [${ids.length}] ids\n`); 81 | } 82 | 83 | return { ids }; 84 | }, 85 | }; 86 | } 87 | -------------------------------------------------------------------------------- /src/driver/sqlite-disk.mjs: -------------------------------------------------------------------------------- 1 | import { build as _build } from "./sqlite.mjs"; 2 | 3 | export async function build(args) { 4 | return _build({ 5 | ...args, 6 | }); 7 | } 8 | -------------------------------------------------------------------------------- /src/driver/sqlite-mem.mjs: -------------------------------------------------------------------------------- 1 | import { build as _build } from "./sqlite.mjs"; 2 | 3 | export async function build(args) { 4 | return _build({ 5 | ...args, 6 | dbPath: ":memory:", 7 | }); 8 | } 9 | -------------------------------------------------------------------------------- /src/driver/sqlite.mjs: -------------------------------------------------------------------------------- 1 | /* global process */ 2 | import Database from "better-sqlite3"; 3 | 4 | const DEFAULT_BATCH_SIZE = 10_000; 5 | 6 | async function connect({ dbPath, batchSize, currentBatch }) { 7 | dbPath = dbPath ?? process.env.SQLITE_DISK_DB_PATH; 8 | 9 | if (!dbPath) { 10 | throw new Error(`[error] Missing/invalid SQLite DB path [${dbPath}] (did you specify SQLITE_DISK_DB_PATH?)`); 11 | } 12 | 13 | process.stderr.write(`[info] using SQLite DB @ [${dbPath}]\n`); 14 | const db = new Database(dbPath, { fileMustExist: true }); 15 | 16 | // Set up the initial table 17 | db.exec(`CREATE VIRTUAL TABLE IF NOT EXISTS movies_fts USING fts5(title, original_title, overview);`); 18 | 19 | if (process.env.FTS_ENGINE_RESET_AT_INIT) { 20 | await db.run(`TRUNCATE TABLE movies`); 21 | } 22 | 23 | const insert = await db.prepare(` 24 | INSERT INTO movies_fts 25 | (rowid, title,original_title,overview) 26 | VALUES 27 | (@id, @title, @original_title, @overview) 28 | `); 29 | const search = await db.prepare("SELECT rowid as id,* FROM movies_fts WHERE title MATCH @phrase OR original_title MATCH @phrase OR overview MATCH @phrase"); 30 | 31 | return { 32 | batchSize, 33 | db, 34 | currentBatch: currentBatch || [], 35 | statements: { 36 | insert, 37 | search, 38 | }, 39 | }; 40 | } 41 | 42 | export async function build(args) { 43 | const { db, statements, batchSize, currentBatch } = await connect({ 44 | ...args, 45 | batchSize: args && args.batchSize ? args.batchSize : DEFAULT_BATCH_SIZE, 46 | currentBatch: args.currentBatch ?? [], 47 | }); 48 | 49 | if (!batchSize || typeof batchSize !== "number") { 50 | throw new Error(`Missing/invalid batch size [${batchSize}]`); 51 | } 52 | 53 | const sendBatch = async (b) => { 54 | if (process.env.DEBUG) { 55 | process.stderr.write(`[debug] sending batch ([${batchSize}] documents)\n`); 56 | } 57 | 58 | const runTransaction = db.transaction((docs) => { 59 | for (const doc of docs) { 60 | try { 61 | statements.insert.run(doc); 62 | } catch (err) { 63 | if (err.code !== "SQLITE_CONSTRAINT_PRIMARYKEY") { throw err; } 64 | } 65 | } 66 | }); 67 | 68 | await runTransaction(b); 69 | }; 70 | 71 | return { 72 | 73 | // Ingesting search documents 74 | async ingest({ document }) { 75 | if (currentBatch.length < batchSize) { 76 | currentBatch.push({ 77 | id: document.id, 78 | title: document.title, 79 | original_title: document.original_title, 80 | overview: document.overview, 81 | }); 82 | return; 83 | } 84 | 85 | await sendBatch(currentBatch); 86 | currentBatch.splice(0, currentBatch.length); 87 | }, 88 | 89 | // Querying search phrases 90 | async query({ phrase }) { 91 | const results = await statements.search.all({ phrase }); 92 | 93 | const ids = results.map(r => r.id); 94 | if (process.env.DEBUG && !process.env.TIMING_FORMAT) { 95 | process.stderr.write(`[debug] Search for [${phrase}] returned [${ids.length}] ids\n`); 96 | } 97 | 98 | return { ids }; 99 | }, 100 | 101 | /// Final ingest wait 102 | async ingestWait() { 103 | if (currentBatch.length === 0) { return; } 104 | // Send final batch 105 | await sendBatch(currentBatch); 106 | }, 107 | 108 | }; 109 | } 110 | -------------------------------------------------------------------------------- /src/driver/typesense.mjs: -------------------------------------------------------------------------------- 1 | /* global process */ 2 | import { waitFor, TimeoutError } from "async-wait-for-promise"; 3 | import { Client } from "typesense"; 4 | 5 | const COLLECTION_NAME = "movies"; 6 | const COLLECTION_SCHEMA = { 7 | name: COLLECTION_NAME, 8 | num_documents: 0, 9 | fields: [ 10 | { 11 | name: 'title', 12 | type: 'string', 13 | facet: false 14 | }, 15 | { 16 | name: 'original_title', 17 | type: 'string', 18 | facet: false 19 | }, 20 | { 21 | name: 'overview', 22 | type: 'string', 23 | facet: false 24 | }, 25 | ], 26 | }; 27 | 28 | const LARGE_LIMIT = 100_000; 29 | 30 | async function connectTypesense() { 31 | // Create Typesense Host 32 | if (!process.env.TYPESENSE_HOST) { 33 | throw new Error(`[error] Missing/invalid Typesense host [${process.env.TYPESENSE_HOST}] (did you specify TYPESENSE_HOST?)`); 34 | } 35 | const host = process.env.TYPESENSE_HOST; 36 | 37 | // Create Typesense Port 38 | if (!process.env.TYPESENSE_PORT) { 39 | throw new Error(`[error] Missing/invalid Typesense port [${process.env.TYPESENSE_PORT}] (did you specify TYPESENSE_PORT?)`); 40 | } 41 | const port = process.env.TYPESENSE_PORT; 42 | 43 | // Create Typesense API Key 44 | if (!process.env.TYPESENSE_API_KEY) { 45 | throw new Error(`[error] Missing/invalid Typesense URL [${process.env.TYPESENSE_API_KEY}] (did you specify TYPESENSE_API_KEY?)`); 46 | } 47 | const apiKey = process.env.TYPESENSE_API_KEY; 48 | 49 | // Create Typesense client 50 | const client = new Client({ 51 | nodes: [ { host, port, protocol: 'http' } ], 52 | apiKey, 53 | numretries: 3, 54 | connectionTimeoutSeconds: 300, 55 | logLevel: process.env.DEBUG ? 'debug' : 'info', 56 | }); 57 | 58 | if (process.env.FTS_ENGINE_RESET_AT_INIT) { 59 | await client.collections(COLLECTION_NAME).delete(); 60 | } 61 | 62 | // Create the index 63 | try { 64 | await client.collections().create(COLLECTION_SCHEMA); 65 | } catch (err) { 66 | if (err.name !== "ObjectAlreadyExists") { 67 | process.stderr.write(`[error] unexpected exception while creating collection \n`); 68 | throw err; 69 | } 70 | } 71 | 72 | return { client }; 73 | } 74 | 75 | let CURRENT_BATCH = []; 76 | const BATCH_SIZE = 10_000; 77 | 78 | export async function build() { 79 | const { client, index } = await connectTypesense(); 80 | 81 | // Build a functoin for sending batches 82 | const sendBatch = async (batch) => { 83 | if (process.env.DEBUG) { 84 | process.stderr.write(`[debug] sending batch ([${BATCH_SIZE}] documents)\n`); 85 | } 86 | 87 | const results = await client.collections(COLLECTION_NAME).documents().import(batch, { action: 'upsert' }); 88 | 89 | const failed = results.filter(item => item.success === false); 90 | if (failed.length > 0) { 91 | throw new Error("Failed to ingest!"); 92 | } 93 | 94 | }; 95 | 96 | return { 97 | // Ingesting search documents 98 | async ingest({ document }) { 99 | if (CURRENT_BATCH.length < BATCH_SIZE) { 100 | CURRENT_BATCH.push({ 101 | id: document.id, 102 | title: document.title, 103 | original_title: document.original_title, 104 | overview: document.overview, 105 | }); 106 | return; 107 | } 108 | 109 | await sendBatch(CURRENT_BATCH); 110 | 111 | CURRENT_BATCH = []; 112 | }, 113 | 114 | // Querying search phrases 115 | async query({ phrase }) { 116 | 117 | let allHits = []; 118 | let newest; 119 | let page = 1; 120 | 121 | // Get first page of results 122 | newest = await client.collections(COLLECTION_NAME).documents().search({ 123 | q: phrase, 124 | //query_by: "title,original_title,overview", 125 | query_by: "title", 126 | page, 127 | per_page: 250, 128 | }); 129 | allHits = allHits.concat(newest.hits); 130 | 131 | // Exhaust pagination list 132 | while (newest.hits.length === 250) { 133 | page++; 134 | 135 | newest = await client.collections(COLLECTION_NAME).documents().search({ 136 | q: phrase, 137 | //query_by: "title,original_title,overview", 138 | query_by: "title", 139 | per_page: 250, 140 | page, 141 | }); 142 | 143 | // Add the 144 | allHits = allHits.concat(newest.hits); 145 | } 146 | 147 | // Gather IDs of hits 148 | const ids = allHits.map(r => r.document.id); 149 | if (process.env.DEBUG && !process.env.TIMING_FORMAT) { 150 | process.stderr.write(`[debug] Search for [${phrase}] returned [${ids.length}] ids\n`); 151 | } 152 | 153 | return { ids }; 154 | }, 155 | 156 | /// Final ingest wait 157 | async ingestWait() { 158 | if (CURRENT_BATCH.length === 0) { return; } 159 | // Send final batch 160 | await sendBatch(CURRENT_BATCH); 161 | }, 162 | }; 163 | } 164 | -------------------------------------------------------------------------------- /src/util/csv2ndjson.mjs: -------------------------------------------------------------------------------- 1 | /* global process */ 2 | 3 | import { default as Papa } from "papaparse"; 4 | import { createReadStream, createWriteStream, existsSync } from "node:fs"; 5 | 6 | export async function convert({ 7 | inputPath, 8 | outputPath, 9 | }) { 10 | 11 | // Quick (leaky) check that files exist 12 | if (!inputPath || !existsSync(inputPath)) { 13 | throw new Error(`Invalid or missing input path [${inputPath}] (did you specify INPUT_CSV_PATH ?)`); 14 | } 15 | 16 | if (!outputPath) { 17 | throw new Error(`Invalid output path [${outputPath}] (did you specify OUTPUT_NDJSON_PATH ?)`); 18 | } 19 | 20 | // Open the output file 21 | const outputStream = createWriteStream(outputPath); 22 | 23 | // Parse the file 24 | await new Promise((resolve, reject) => { 25 | Papa.parse( 26 | createReadStream(inputPath), 27 | { 28 | header: true, 29 | delimeter: ",", 30 | skipEmptyLines: true, 31 | error: reject, 32 | complete: () => resolve(), 33 | chunk: (results) => { 34 | for (const row of results.data) { 35 | try { 36 | const record = { 37 | ...row, 38 | production_companies: JSON.parse(row.production_companies.replaceAll("'",'"')), 39 | production_countries: JSON.parse(row.production_countries.replaceAll("'",'"')), 40 | genres: JSON.parse(row.genres.replaceAll("'",'"')), 41 | spoken_languages: JSON.parse(row.spoken_languages.replaceAll("'",'"')), 42 | }; 43 | outputStream.write(`${JSON.stringify(record)}\n`); 44 | } catch (err) { 45 | process.stderr.write(`[warn] failed to write row with ID [${row.id}]: [${row.title}]\n`); 46 | } 47 | } 48 | }, 49 | }, 50 | ); 51 | }); 52 | } 53 | 54 | // Conver the input to the output 55 | convert({ 56 | inputPath: process.env.INPUT_CSV_PATH, 57 | outputPath: process.env.OUTPUT_NDJSON_PATH, 58 | }); 59 | --------------------------------------------------------------------------------