diff --git a/.github/workflows/cicd.yml b/.github/workflows/cicd.yml new file mode 100644 index 00000000..b7487aa2 --- /dev/null +++ b/.github/workflows/cicd.yml @@ -0,0 +1,191 @@ +name: cicd + +env: + PYPI_API_TOKEN: ${{ secrets.PYPI_API_TOKEN }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }} + +on: + push: + paths: + - "python/**" + - "cli/**" + - ".github/workflows/cicd.yml" + +permissions: + id-token: write + contents: write + +jobs: + lint-sdk: + name: Lint python SDK + timeout-minutes: 5 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.9" + cache: "pip" + - run: pip install .[dev] + - run: python -m ruff check ./python + - run: python -m mypy --strict ./python + test-sdk: + name: Unit test python SDK + timeout-minutes: 5 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.9" + cache: "pip" + - run: pip install -e .[dev] + - run: coverage run -m pytest -vv ./python/tests/ + - run: coverage report | grep 'TOTAL' | awk '{print "COVERAGE_PCT=" $4}' >> $GITHUB_ENV + - name: Publish SDK test coverage + uses: schneegans/dynamic-badges-action@v1.7.0 + with: + auth: ${{ secrets.GIST_ACCESS_TOKEN }} + gistID: a9b9bfdfa0620696fba9e76223790f53 + filename: sdk-coverage.json + label: SDK coverage + message: ${{ env.COVERAGE_PCT }} + minColorRange: 50 + maxColorRange: 80 + valColorRange: ${{ env.COVERAGE_PCT }} + build: + timeout-minutes: 15 + runs-on: ubuntu-latest + name: Build package + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.9" + cache: "pip" + - uses: actions/setup-go@v5 + with: + go-version: "1.21" + cache: false + - run: python3 -m pip install build>=1.2.1 + - run: make package + - uses: actions/upload-artifact@v4 + with: + name: package + path: ./dist/* + test-cli-windows: + name: Test CLI on windows + needs: + - build + runs-on: windows-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: "3.9" + cache: "pip" + - uses: actions/download-artifact@v4 + id: download + with: + name: package + path: ./dist + - run: cmd /r dir /b /a-d dist > files.txt + - run: | + $files = Get-Content files.txt + foreach ($file in $files) { + pip install dist/$file + } + - run: numerous --help + lint-cli: + name: Lint CLI + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version: "1.22" + cache: false + - name: Lint (golangci-lint) + uses: golangci/golangci-lint-action@v4 + with: + version: v1.56.2 + working-directory: cli + args: --config=../.golangci.yml --verbose + - name: Install gofumpt + shell: bash + run: | + wget https://github.com/mvdan/gofumpt/releases/download/v0.6.0/gofumpt_v0.6.0_linux_amd64 + mv gofumpt_v0.6.0_linux_amd64 gofumpt + chmod +x gofumpt + mv gofumpt /usr/local/bin + - name: Check gofumpt formatting + shell: bash + run: | + unformatted_files=$(gofumpt -l .) + if [[ "$unformatted_files" != "" ]]; then + echo "Some files do not adhere to gofumpt formatting:" + echo "$unformatted_files" + exit 1 + fi + test-cli: + name: Unit test CLI + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version: "1.21" + cache: false + - name: Tests + working-directory: cli + run: go test -coverprofile=c.out ./... + - name: Extract Test Coverage Percentage + working-directory: cli + run: go tool cover -func c.out | fgrep total | awk '{print "COVERAGE_PCT=" $3}' >> $GITHUB_ENV + - name: Publish Test Coverage + uses: schneegans/dynamic-badges-action@v1.7.0 + with: + auth: ${{ secrets.GIST_ACCESS_TOKEN }} + gistID: a9b9bfdfa0620696fba9e76223790f53 + filename: cli-coverage.json + label: CLI coverage + message: ${{ env.COVERAGE_PCT }} + minColorRange: 50 + maxColorRange: 80 + valColorRange: ${{ env.COVERAGE_PCT }} + release: + timeout-minutes: 15 + runs-on: ubuntu-latest + name: Release + needs: + - lint-cli + - test-cli + - test-sdk + - lint-sdk + - build + - test-cli-windows + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + - uses: actions/setup-python@v5 + with: + python-version: "3.9" + cache: "pip" + - uses: actions/download-artifact@v4 + id: download + with: + name: package + path: ./dist + - uses: actions/setup-go@v5 + with: + go-version: "1.21" + cache: false + - run: pip install python-semantic-release==9.6.0 twine==5.0.0 + - run: semantic-release version --commit --tag --push + - run: semantic-release publish + - run: twine upload --non-interactive dist/* diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..ec9d35ad --- /dev/null +++ b/.gitignore @@ -0,0 +1,178 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST +cli/build/ + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ +lcov.info + + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +# Editor specific files +.vscode + +# Makefile rules +.lint-*.txt + +# Autogenerated documentation sources +docs/source/api + +# CLI codebase +cli/build +!cli/internal/gql/build +cli/cli.db +cli/c.out diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 00000000..08f6e2f1 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,27 @@ +# https://golangci-lint.run/usage/configuration/ +run: + timeout: 5m + +linters-settings: + nlreturn: + block-size: 2 + testifylint: + disable: + - require-error + +linters: + enable: + - gocritic + - gomnd + - misspell + - nlreturn + - perfsprint + - predeclared + - stylecheck + - testifylint + - thelper + - usestdlibvars + - whitespace + +issues: + max-same-issues: 10 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..cc360361 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,41 @@ +default_stages: ["pre-commit", "pre-push"] +default_install_hook_types: [pre-commit, pre-push] +repos: + - repo: https://github.com/astral-sh/ruff-pre-commit + # Ruff version. + rev: v0.4.1 + hooks: + # Run the linter. + - id: ruff + args: [--fix] + # Run the formatter. + - id: ruff-format + - repo: https://github.com/pre-commit/mirrors-mypy + rev: v1.8.0 + hooks: + - id: mypy + entry: mypy python + pass_filenames: false + additional_dependencies: + - "pytest-asyncio" + - repo: local + hooks: + - id: pytest-check + stages: [pre-push] + types: [python] + name: pytest-check + entry: python -m pytest -v python/tests/ + language: system + pass_filenames: false + always_run: true + - repo: local + hooks: + - id: golangci-lint + name: golangci-lint + language: system + stages: [pre-commit, pre-push] + entry: bash -c 'cd cli && golangci-lint run --allow-parallel-runners' + - repo: https://github.com/Bahjat/pre-commit-golang + rev: v1.0.3 + hooks: + - id: gofumpt diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..f6e2a6ad --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,93 @@ +# CHANGELOG + + + +## v0.1.0 (2024-05-03) + +### Ci + +* ci: fix twine command arguments ([`29cf529`](https://github.com/numerous-com/numerous-sdk/commit/29cf52900f976b969cf4ea77893a13c7cb00104c)) + +* ci: formatting, install proper python-semantic-release ([`6f3815f`](https://github.com/numerous-com/numerous-sdk/commit/6f3815f7097025eb65c35309382c83c58e119f4a)) + +* ci: setup semantic release publish ([`bbe9154`](https://github.com/numerous-com/numerous-sdk/commit/bbe915428c90458f8cf62d35b59849a3d1f8f8e0)) + + +## v0.0.42 (2024-05-02) + +### Chore + +* chore: fix errors in make clean ([`4a4424a`](https://github.com/numerous-com/numerous-sdk/commit/4a4424a44257c444c6823d92f4a3d0f2d03cf3bf)) + +### Ci + +* ci: fix release build ([`cb99a9c`](https://github.com/numerous-com/numerous-sdk/commit/cb99a9cb2ff1c2dff7b18dfc09db15ab11873cda)) + +* ci: update setup-go version ([`6acabe1`](https://github.com/numerous-com/numerous-sdk/commit/6acabe12ecbd6e4fb85fe3aad70f648aa35ddcff)) + +* ci: fix semantic release ([`4b5e985`](https://github.com/numerous-com/numerous-sdk/commit/4b5e985cd242d1cbb497d298254479edc497d379)) + +* ci: rename publish to Release ([`e5eb4bc`](https://github.com/numerous-com/numerous-sdk/commit/e5eb4bcca58dc0988553c2cd86a85934d43c8138)) + +* ci: setup semantic release ([`b742e40`](https://github.com/numerous-com/numerous-sdk/commit/b742e40a32dd84c0964e97f663926fd879fb7ce7)) + +### Fix + +* fix(cli): improvements to numerous init output and folder creation ([`ae34d0c`](https://github.com/numerous-com/numerous-sdk/commit/ae34d0c114074ddf95c1dac548d522dad91bc010)) + + +## v0.0.41 (2024-05-02) + +### Chore + +* chore: fix Makefiles and add actions ([`2b7f383`](https://github.com/numerous-com/numerous-sdk/commit/2b7f3837fe0daf9e96821e6d7f029575e221d847)) + +### Ci + +* ci: sdk test coverage ([`381a0de`](https://github.com/numerous-com/numerous-sdk/commit/381a0dee47a8ce8f9a6b8f0a96c27076584a0cd0)) + +* ci: publish cli test coverage ([`bc149af`](https://github.com/numerous-com/numerous-sdk/commit/bc149af300216ff4ff06a13c08fe68fc365ae6f7)) + +* ci: fix cli test working dir, only make package twice, and make package venv requirement ([`e7c55b5`](https://github.com/numerous-com/numerous-sdk/commit/e7c55b5e356e13116c0e28b364e59c7ffb4aca63)) + +* ci: fix workflow dependencies ([`61bdfe8`](https://github.com/numerous-com/numerous-sdk/commit/61bdfe85daef60013a31f16e98390b21f1cbb155)) + +* ci: use a single workflow ([`8a73ad2`](https://github.com/numerous-com/numerous-sdk/commit/8a73ad2c01473e8633c6cd1de0824d657b91d701)) + +* ci: fix issues and comment out stuff that doesn't work yet ([`24ed7c2`](https://github.com/numerous-com/numerous-sdk/commit/24ed7c275ac027b7ffab5bfa6c59f247c6e8f7fd)) + +### Documentation + +* docs: update readme ([`4e9184a`](https://github.com/numerous-com/numerous-sdk/commit/4e9184ae3f1dc6820ba728404ec046afbada1ee6)) + +* docs: update README.md and remove CLI readme ([`75b534e`](https://github.com/numerous-com/numerous-sdk/commit/75b534eb3e751f0899b8f267625a938380d36398)) + +### Fix + +* fix: CLI binaries in SDK package ([`af063d3`](https://github.com/numerous-com/numerous-sdk/commit/af063d34158b954362258527a2aa0d3a5448bfc6)) + +### Refactor + +* refactor(cli): restructure appdev code ([`420f639`](https://github.com/numerous-com/numerous-sdk/commit/420f63949bb9ee2500a0d8a43b021eb2d2feeaf2)) + +### Test + +* test(cli): use temp dir in watcher test ([`b931cd1`](https://github.com/numerous-com/numerous-sdk/commit/b931cd124a1f183f82d671fe65ae516475857eb2)) + +### Unknown + +* pre-commit ([`6e9de59`](https://github.com/numerous-com/numerous-sdk/commit/6e9de591698246950b9edae3d2524a19c6dc1c63)) + +* update schema ([`8b687f5`](https://github.com/numerous-com/numerous-sdk/commit/8b687f55ee69577c2654f8e70507cc58d8f1f2a9)) + +* add cli assets ([`3174b0f`](https://github.com/numerous-com/numerous-sdk/commit/3174b0fc22c4610bfc71ca17fe657b24011dd4df)) + +* update cli ([`0148046`](https://github.com/numerous-com/numerous-sdk/commit/0148046124add2dfaf067eddd2b9d6bad3bbc71a)) + +* fix python linting errors ([`ef546e3`](https://github.com/numerous-com/numerous-sdk/commit/ef546e38d9c6717b969a1dc74865916e5ef5295f)) + +* update python sdk ([`e2d031e`](https://github.com/numerous-com/numerous-sdk/commit/e2d031e0c706ce51cfc0f018cd434ed0ae3ecb88)) + +* update cli ([`3ce4221`](https://github.com/numerous-com/numerous-sdk/commit/3ce422137818928c8751f5350e88f5f9d55a96ce)) + +* initial commit ([`2dd346b`](https://github.com/numerous-com/numerous-sdk/commit/2dd346b033a8cd0d76f74ed8427c4a81400aedfe)) diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 00000000..b499612a --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,2 @@ +global-include py.typed +include python/src/numerous/cli/build/* \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..e45a77cb --- /dev/null +++ b/Makefile @@ -0,0 +1,127 @@ +SHELL = bash +TARGET_SYSTEMS := darwin windows linux +TARGET_ARCHS := amd64 arm64 + +# CLI related variables +GO_ENV = CGO_ENABLED=0 +GO_BUILD = cd cli && $(GO_ENV) go build + +CLI_DIR=./cli +CLI_BUILD_DIR_NAME=build +CLI_BUILD_DIR=$(CLI_DIR)/$(CLI_BUILD_DIR_NAME) +CLI_SOURCE_FILES=$(shell find $(CLI_DIR) -name *.go -type f) + +CLI_BUILD_TARGETS := $(foreach SYS,$(TARGET_SYSTEMS),$(foreach ARCH,$(TARGET_ARCHS),$(CLI_BUILD_DIR)/$(SYS)_$(ARCH))) + +get_cli_target_from_sdk_binary = $(word 1,$(subst $(SDK_CLI_BINARY_DIR)/,,$(CLI_BUILD_DIR)/$@)) +getsystem = $(word 3,$(subst _, ,$(subst /, ,$@))) +getarch = $(word 4,$(subst _, ,$(subst /, ,$@))) + +GQL_HTTP_URL = https://api.numerous.com/query +GQL_WS_URL = wss://api.numerous.com/query +LDFLAGS = -s -w \ + -X "numerous/cli/internal/gql.httpURL=$(GQL_HTTP_URL)" \ + -X "numerous/cli/internal/gql.wsURL=$(GQL_WS_URL)" + +# Python SDK related variables +SDK_CLI_BINARY_DIR=python/src/numerous/cli/build +SDK_CLI_BINARY_TARGETS := $(foreach SYS,$(TARGET_SYSTEMS),$(foreach ARCH,$(TARGET_ARCHS),$(SDK_CLI_BINARY_DIR)/$(SYS)_$(ARCH))) +SDK_CHECK_VENV=@if [ -z "${VIRTUAL_ENV}" ]; then echo "-- Error: An activated virtual environment is required"; exit 1; fi + +# RULES +.DEFAULT_GOAL := help + +.PHONY: clean test lint dep package sdk-binaries sdk-test sdk-lint sdk-dep cli-test cli-lint cli-dep cli-all cli-build cli-local + +clean: + rm -rf $(CLI_BUILD_DIR) + rm -rf $(SDK_CLI_BINARY_DIR) + rm -rf dist + rm -f .lint-ruff.txt + rm -f .lint-mypy.txt + +package: sdk-binaries + @echo "-- Building SDK package" + python -m build + +test: sdk-test cli-test + +lint: sdk-lint cli-lint + +dep: sdk-dep cli-dep + +sdk-lint: + @echo "-- Running SDK linters" + $(SDK_CHECK_VENV) + ruff check . && echo -n "true" > .lint-ruff.txt || echo -n "false" > .lint-ruff.txt; + mypy --strict . && echo -n "true" > .lint-mypy.txt || echo -n "false" > .lint-mypy.txt; + $$(cat .lint-ruff.txt) && $$(cat .lint-mypy.txt) + +sdk-test: + @echo "-- Running tests for sdk" + $(SDK_CHECK_VENV) + pytest python/tests + +sdk-dep: + @echo "-- Installing SDK dependencies" + $(SDK_CHECK_VENV) + pip install -e .[dev] -q + +sdk-binaries: $(SDK_CLI_BINARY_TARGETS) + +# Directory for CLI binaries, in SDK +$(SDK_CLI_BINARY_DIR): + @echo "-- Creating SDK binary directory" + mkdir $(SDK_CLI_BINARY_DIR) + +# CLI executables in SDK +$(SDK_CLI_BINARY_DIR)/%: $(SDK_CLI_BINARY_DIR) $(CLI_BUILD_DIR)/% + echo "Copying built binary $@" + cp $(get_cli_target_from_sdk_binary) $@ + +# CLI for specific OS/architecture +cli-all: $(CLI_BUILD_TARGETS) + +$(CLI_BUILD_TARGETS): %: $(CLI_SOURCE_FILES) + @echo "-- Building CLI for OS $(getsystem) architecture $(getarch) in $@" + export GOARCH=$(getarch) GOOS=$(getsystem) && $(GO_BUILD) -ldflags '$(LDFLAGS)' -o ../$@ . + +cli-local: + @echo "-- Building local CLI" + $(GO_BUILD) -o $(CLI_BUILD_DIR_NAME)/local . + +cli-build: + @echo "-- Building CLI" + $(GO_BUILD) -ldflags '$(LDFLAGS)' -o $(CLI_BUILD_DIR_NAME)/numerous . + +cli-lint: + @echo "-- Running CLI linters" + cd cli && golangci-lint run + cd cli && gofumpt -l -w . + +cli-test: + @echo "-- Running CLI tests" + cd cli && go test -coverprofile=c.out ./... + +cli-dep: + @echo "-- Installing CLI dependencies" + cd cli && go mod download + cd cli && go mod tidy > /dev/null + +help: + @echo "Make targets (help is default):" + @echo " test Run all tests" + @echo " lint Run all linters" + @echo " dep Install all dependencies" + @echo " package Package the SDK python package including CLI builds" + @echo " sdk-binaries Build CLI binaries in SDK package" + @echo " sdk-test Run SDK tests" + @echo " sdk-lint Run SDK linters" + @echo " sdk-dep Install SDK dependencies" + @echo " cli-test Run CLI tests" + @echo " cli-lint Run CLI linters" + @echo " cli-dep Install CLI dependencies" + @echo " cli-all Build CLI for all systems" + @echo " cli-build Build CLI for current system" + @echo " cli-local Build local CLI for current system" + @echo " help Display this message" diff --git a/README.md b/README.md new file mode 100644 index 00000000..eb2620bb --- /dev/null +++ b/README.md @@ -0,0 +1,105 @@ +Numerous Software Development Kit +================================= + +💫 The python SDK for developing apps for the numerous platform. + +📥 Simply install the SDK into your python environment with: + + pip install numerous + +🛠 And then you can simply enter the following command, to get a list of possible +commands. + + numerous + +👩🏼‍🎓 See the [numerous documentation](https://www.numerous.com/docs) for more information! + +Badges +------ + +[![CICD badge](https://github.com/numerous-com/numerous-sdk/actions/workflows/cicd.yml/badge.svg)](https://github.com/numerous-com/numerous-sdk/actions/workflows/cicd.yml) +![cli coverage badge](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/jfeodor/a9b9bfdfa0620696fba9e76223790f53/raw/cli-coverage.json) +![sdk coverage badge](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/jfeodor/a9b9bfdfa0620696fba9e76223790f53/raw/sdk-coverage.json) + +Development +=========== + +Most common tasks are defined in the `Makefile`. Use `make help` to get an +overview. + +In order to setup pre-commit hooks, use [pre-commit](https://pre-commit.com/) to +to setup hooks for linters and tests. This requires pre-commit to be installed +of course, and it is included in the python SDK development dependencies. + +To install pre-commit and pre-push hooks + + pre-commit install + +And you can run them on demand + + pre-commit run --all + +Development of python SDK 🐍 +---------------------------- + +Create a virtual environment and activate it + + python -m venv ./venv + ./venv/bin/activate + +Install the package in editable mode (including development dependencies) + + pip install -e ./python[dev] + +Run the tests + + make sdk-test + +And the linters + + make sdk-lint + +Development of go CLI 🐹 +------------------------ + +The numerous CLI enables tool development. + +### Building and running + +To build simply run `make build` without arguments, and the executable is stored +as `cli/build/numerous` + +### Development + +While developing you can run the CLI like below, inside the `cli` folder. + + go run . + + # e.g. + go run . init + go run . dev + +From the root folder, you can lint with: + + make cli-lint + +And you can run tests with + + make cli-test + +### Trying out Numerous app engine development + +In the examples folder are two tools `examples/action.py` (containing +`ActionTool`), and `examples/parameters.py` (containing `ParameterTool`). These +can be used to test the first-class tool development features. + +**Note: You need an activated python environment with the python SDK +installed.** See +[the python sdk development section](#development-of-python-sdk-🐍) for information +about how to install it. + +For example, if you built using `make cli-build`, you can run + +``` +./cli/build/numerous dev examples/numerous/parameters.py:ParameterApp +``` diff --git a/cli/.gitignore b/cli/.gitignore new file mode 100644 index 00000000..10ce3ac0 --- /dev/null +++ b/cli/.gitignore @@ -0,0 +1,4 @@ +build +!internal/gql/build +cli.db +c.out \ No newline at end of file diff --git a/cli/appdev/app_definition.go b/cli/appdev/app_definition.go new file mode 100644 index 00000000..436e1b72 --- /dev/null +++ b/cli/appdev/app_definition.go @@ -0,0 +1,172 @@ +package appdev + +import ( + "errors" + "fmt" + "log/slog" + "strings" +) + +type AppDefinitionElement struct { + Name string `json:"name"` + Label string `json:"label"` + Type string `json:"type"` + Default any `json:"default"` + SliderMinValue float64 `json:"slider_min_value"` + SliderMaxValue float64 `json:"slider_max_value"` + Elements []AppDefinitionElement `json:"elements,omitempty"` + Parent *AppDefinitionElement `json:"-"` // ignore in JSON +} + +func (a AppDefinitionElement) setAsParentOnChildren() { + for i := 0; i < len(a.Elements); i++ { + e := &a.Elements[i] + e.Parent = &a + e.setAsParentOnChildren() + } +} + +func (a AppDefinitionElement) GetPath() []string { + if a.Parent == nil { + return []string{a.Name} + } else { + return append(a.Parent.GetPath(), a.Name) + } +} + +func (a AppDefinitionElement) String() string { + elementsField := "" + if a.Elements != nil { + elements := make([]string, 0) + for _, e := range a.Elements { + elements = append(elements, e.String()) + } + elementsField = fmt.Sprintf(", Elements: {%s}", strings.Join(elements, ", ")) + } + + return fmt.Sprintf("AppElementDefinition{Name: `%s`, Type: `%s`, Default: \"%v\"%s}", a.Name, a.Type, a.Default, elementsField) +} + +func (a AppDefinitionElement) CreateSessionElement() (*AppSessionElement, error) { + sessionElement := AppSessionElement{ + Name: a.Name, + Label: a.Label, + Type: a.Type, + } + + switch a.Type { + case "string": + switch d := a.Default.(type) { + case string: + sessionElement.StringValue.Valid = true + sessionElement.StringValue.String = d + default: + return nil, fmt.Errorf("parameter %s of type %s has invalid default \"%v\"", a.Name, a.Type, d) + } + case "number": + switch d := a.Default.(type) { + case float64: + sessionElement.NumberValue.Valid = true + sessionElement.NumberValue.Float64 = d + default: + return nil, fmt.Errorf("parameter %s of type %s has invalid default \"%v\"", a.Name, a.Type, d) + } + case "container": + sessionElement.Elements = createSessionElements(a.Elements) + case "action": + case "html": + switch d := a.Default.(type) { + case string: + sessionElement.HTMLValue.Valid = true + sessionElement.HTMLValue.String = d + default: + return nil, fmt.Errorf("parameter %s of type %s has invalid default \"%v\"", a.Name, a.Type, d) + } + case "slider": + switch d := a.Default.(type) { + case float64: + sessionElement.SliderValue.Valid = true + sessionElement.SliderValue.Float64 = d + sessionElement.SliderMinValue.Valid = true + sessionElement.SliderMinValue.Float64 = a.SliderMinValue + sessionElement.SliderMaxValue.Valid = true + sessionElement.SliderMaxValue.Float64 = a.SliderMaxValue + default: + return nil, fmt.Errorf("parameter %s of type %s has invalid default \"%v\"", a.Name, a.Type, d) + } + default: + return nil, fmt.Errorf("unexpected element type \"%s\"", a.Type) + } + + return &sessionElement, nil +} + +type AppDefinition struct { + Title string `json:"title"` + Name string `json:"name"` + Elements []AppDefinitionElement `json:"elements"` +} + +var ErrAppDefinitionElementNotFound = errors.New("element definition not found") + +func (ad *AppDefinition) GetElementByPath(path []string) (*AppDefinitionElement, error) { + var element *AppDefinitionElement + elements := ad.Elements + + for _, name := range path { + found := false + for _, e := range elements { + if name != e.Name { + continue + } + + found = true + element = &e + if e.Type == "container" { + elements = e.Elements + } + } + + if !found { + return nil, ErrAppDefinitionElementNotFound + } + } + + if element == nil { + return nil, ErrAppDefinitionElementNotFound + } else { + return element, nil + } +} + +func (ad *AppDefinition) SetElementParents() { + for _, e := range ad.Elements { + e.setAsParentOnChildren() + } +} + +func (ad AppDefinition) CreateSession() AppSession { + return AppSession{ + Title: ad.Title, + Name: ad.Name, + Elements: ad.CreateAppSessionElements(), + } +} + +func (ad AppDefinition) CreateAppSessionElements() []AppSessionElement { + return createSessionElements(ad.Elements) +} + +func createSessionElements(definitionElements []AppDefinitionElement) []AppSessionElement { + elements := []AppSessionElement{} + + for _, def := range definitionElements { + if e, err := def.CreateSessionElement(); err != nil { + slog.Warn("could not create session element", slog.Any("error", err)) + } else { + elements = append(elements, *e) + } + } + + return elements +} diff --git a/cli/appdev/app_definition_test.go b/cli/appdev/app_definition_test.go new file mode 100644 index 00000000..b2cfcbaf --- /dev/null +++ b/cli/appdev/app_definition_test.go @@ -0,0 +1,355 @@ +package appdev + +import ( + "database/sql" + "fmt" + "testing" + + "github.com/stretchr/testify/assert" +) + +type CreateSessionElementTestCase struct { + name string + def AppDefinitionElement + expected AppSessionElement +} + +var createSessionElementTestCases = []CreateSessionElementTestCase{ + { + name: "string field", + def: AppDefinitionElement{ + Label: "String Label", + Type: "string", + Default: "default string value", + }, + expected: AppSessionElement{ + Label: "String Label", + Type: "string", + StringValue: sql.NullString{Valid: true, String: "default string value"}, + }, + }, + { + name: "number field", + def: AppDefinitionElement{ + Label: "Number Label", + Type: "number", + Default: 10.0, + }, + expected: AppSessionElement{ + Label: "Number Label", + Type: "number", + NumberValue: sql.NullFloat64{Valid: true, Float64: 10.0}, + }, + }, + { + name: "slider field", + def: AppDefinitionElement{ + Label: "Slider label", + Type: "slider", + Default: 10.0, + SliderMinValue: 123.0, + SliderMaxValue: 456.0, + }, + expected: AppSessionElement{ + Label: "Slider label", + Type: "slider", + SliderValue: sql.NullFloat64{Valid: true, Float64: 10.0}, + SliderMinValue: sql.NullFloat64{Valid: true, Float64: 123.0}, + SliderMaxValue: sql.NullFloat64{Valid: true, Float64: 456.0}, + }, + }, + { + name: "html field", + def: AppDefinitionElement{ + Label: "HTML label", + Type: "html", + Default: "

default html value

", + }, + expected: AppSessionElement{ + Label: "HTML label", + Type: "html", + HTMLValue: sql.NullString{Valid: true, String: "

default html value

"}, + }, + }, + { + name: "container with 1 child", + def: AppDefinitionElement{ + Label: "Container Label", + Type: "container", + Elements: []AppDefinitionElement{ + {Label: "string label", Type: "string", Default: "default string"}, + }, + }, + expected: AppSessionElement{ + Label: "Container Label", + Type: "container", + Elements: []AppSessionElement{ + {Label: "string label", Type: "string", StringValue: sql.NullString{Valid: true, String: "default string"}}, + }, + }, + }, + { + name: "nested container with 1 child", + def: AppDefinitionElement{ + Label: "Container Label", + Type: "container", + Elements: []AppDefinitionElement{ + { + Label: "Nested container Label", + Type: "container", + Elements: []AppDefinitionElement{ + {Type: "string", Default: "default string"}, + }, + }, + }, + }, + expected: AppSessionElement{ + Label: "Container Label", + Type: "container", + Elements: []AppSessionElement{ + { + Label: "Nested container Label", + Type: "container", + Elements: []AppSessionElement{ + {Type: "string", StringValue: sql.NullString{Valid: true, String: "default string"}}, + }, + }, + }, + }, + }, +} + +func TestCreateSessionElement(t *testing.T) { + for _, testcase := range createSessionElementTestCases { + t.Run(testcase.name, func(t *testing.T) { + sess, err := testcase.def.CreateSessionElement() + + assert.NoError(t, err) + assert.Equal(t, testcase.expected, *sess) + }) + } +} + +func TestCreateSessionElementError(t *testing.T) { + createErrorTestTestCases := []AppDefinitionElement{ + {Type: "string", Default: 123.45}, + {Type: "number", Default: "some string value"}, + } + + for _, definition := range createErrorTestTestCases { + definition.Name = "element_name" + testName := fmt.Sprintf("%s element definition with non-%s default returns error", definition.Type, definition.Type) + t.Run(testName, func(t *testing.T) { + sess, err := definition.CreateSessionElement() + + expectedError := fmt.Sprintf("parameter element_name of type %s has invalid default \"%v\"", definition.Type, definition.Default) + assert.Nil(t, sess) + assert.EqualError(t, err, expectedError) + }) + } +} + +type CreateAppSessionTestCase struct { + name string + def AppDefinition + expected AppSession +} + +var createAppSessionTestCases = []CreateAppSessionTestCase{ + { + name: "empty app session", + def: AppDefinition{ + Elements: []AppDefinitionElement{}, + }, + expected: AppSession{ + Elements: []AppSessionElement{}, + }, + }, + { + name: "container with multiple children", + def: AppDefinition{ + Name: "App", + Elements: []AppDefinitionElement{ + { + Name: "container_element", + Type: "container", + Elements: []AppDefinitionElement{ + {Name: "string_element", Type: "string", Default: "default value"}, + {Name: "number_element", Type: "number", Default: 123.45}, + }, + }, + }, + }, + expected: AppSession{ + Name: "App", + Elements: []AppSessionElement{ + { + Name: "container_element", + Type: "container", + Elements: []AppSessionElement{ + { + Name: "string_element", + Type: "string", + StringValue: sql.NullString{Valid: true, String: "default value"}, + }, + { + Name: "number_element", + Type: "number", + NumberValue: sql.NullFloat64{Valid: true, Float64: 123.45}, + }, + }, + }, + }, + }, + }, + { + name: "sibling containers", + def: AppDefinition{ + Elements: []AppDefinitionElement{ + {Name: "c1", Type: "container", Elements: []AppDefinitionElement{{Type: "string", Default: "default"}}}, + {Name: "c2", Type: "container", Elements: []AppDefinitionElement{{Type: "string", Default: "default"}}}, + }, + }, + expected: AppSession{ + Elements: []AppSessionElement{ + { + Name: "c1", + Type: "container", + Elements: []AppSessionElement{ + {Type: "string", StringValue: sql.NullString{Valid: true, String: "default"}}, + }, + }, + { + Name: "c2", + Type: "container", + Elements: []AppSessionElement{ + {Type: "string", StringValue: sql.NullString{Valid: true, String: "default"}}, + }, + }, + }, + }, + }, +} + +func TestCreateAppSessionReturnsExpected(t *testing.T) { + for _, testcase := range createAppSessionTestCases { + t.Run(testcase.name, func(t *testing.T) { + s := testcase.def.CreateSession() + assert.Equal(t, testcase.expected, s) + }) + } +} + +type GetElementByPathTestCase struct { + name string + def AppDefinition + path []string + expected *AppDefinitionElement +} + +func TestAppDefinitionGetElementByPath(t *testing.T) { + testCases := []GetElementByPathTestCase{ + { + name: "returns root element", + def: AppDefinition{ + Elements: []AppDefinitionElement{ + { + Name: "elem", + Type: "string", + Default: "default string", + }, + }, + }, + path: []string{"elem"}, + expected: &AppDefinitionElement{ + Name: "elem", + Type: "string", + Default: "default string", + }, + }, + { + name: "returns nested element", + def: AppDefinition{ + Elements: []AppDefinitionElement{ + { + Name: "cont", + Type: "container", + Elements: []AppDefinitionElement{ + { + Name: "child", + Type: "number", + Default: 1.2, + }, + }, + }, + }, + }, + path: []string{"cont", "child"}, + expected: &AppDefinitionElement{ + Name: "child", + Type: "number", + Default: 1.2, + }, + }, + } + + for _, testcase := range testCases { + elem, err := testcase.def.GetElementByPath(testcase.path) + assert.NoError(t, err) + assert.Equal(t, testcase.expected, elem) + } +} + +type GetElementByPathErrorTestCase struct { + name string + def AppDefinition + path []string + err error +} + +var errorTestCases = []GetElementByPathErrorTestCase{ + { + name: "returns error for non-existing root element", + def: AppDefinition{ + Elements: []AppDefinitionElement{ + { + Name: "elem", + Type: "number", + Default: 1.2, + }, + }, + }, + path: []string{"cont", "child"}, + err: ErrAppDefinitionElementNotFound, + }, + { + name: "returns error for non-existing nested element", + def: AppDefinition{ + Elements: []AppDefinitionElement{ + { + Name: "cont", + Type: "container", + Elements: []AppDefinitionElement{ + { + Name: "child", + Type: "number", + Default: 1.2, + }, + }, + }, + }, + }, + path: []string{"cont", "non-existing"}, + err: ErrAppDefinitionElementNotFound, + }, +} + +func TestAppDefinitionGetElementByPathError(t *testing.T) { + for _, testcase := range errorTestCases { + t.Run(testcase.name, func(t *testing.T) { + elem, err := testcase.def.GetElementByPath(testcase.path) + assert.ErrorIs(t, err, ErrAppDefinitionElementNotFound) + assert.Nil(t, elem) + }) + } +} diff --git a/cli/appdev/app_session.go b/cli/appdev/app_session.go new file mode 100644 index 00000000..189e6222 --- /dev/null +++ b/cli/appdev/app_session.go @@ -0,0 +1,133 @@ +package appdev + +import ( + "database/sql" + "errors" + "fmt" + "strconv" + "time" + + "gorm.io/gorm" +) + +type AppSession struct { + gorm.Model + Title string + Name string + CreatedAt time.Time + Elements []AppSessionElement + ClientID string +} + +var ErrAppSessionElementNotFound = errors.New("element not found") + +func (s AppSession) GetElementByID(elementID string) (*AppSessionElement, error) { + for _, e := range s.Elements { + if strconv.FormatUint(uint64(e.ID), 10) == elementID { + return &e, nil + } + } + + return nil, fmt.Errorf("no element with ID \"%s\"", elementID) +} + +func (s AppSession) GetElementByPath(elementPath []string) (*AppSessionElement, error) { + var element *AppSessionElement = nil + for _, name := range elementPath { + if e := s.getElementByNameAndParent(name, element); e == nil { + return nil, ErrAppSessionElementNotFound + } else { + element = e + } + } + + if element != nil { + return element, nil + } else { + return nil, ErrAppSessionElementNotFound + } +} + +func (s AppSession) getElementByNameAndParent(name string, parent *AppSessionElement) *AppSessionElement { + for _, e := range s.Elements { + if e.Name != name { + continue + } + + noParent := !e.ParentID.Valid && parent == nil + if noParent { + return &e + } + + matchingParent := e.ParentID.Valid && parent != nil && e.ParentID.String == strconv.FormatUint(uint64(parent.ID), 10) + if matchingParent { + return &e + } + } + + return nil +} + +type AppSessionElement struct { + gorm.Model + AppSessionID uint + ParentID sql.NullString + Name string + Label string + Type string + NumberValue sql.NullFloat64 + StringValue sql.NullString + SliderValue sql.NullFloat64 + HTMLValue sql.NullString + Elements []AppSessionElement `gorm:"foreignKey:ParentID"` + SliderMinValue sql.NullFloat64 + SliderMaxValue sql.NullFloat64 +} + +func (s AppSession) GetAllChildren() []AppSessionElement { + children := make([]AppSessionElement, 0) + + for _, e := range s.Elements { + children = append(children, e.GetAllChildren()...) + } + + return children +} + +func (s AppSessionElement) GetAllChildren() []AppSessionElement { + children := make([]AppSessionElement, 0) + + for _, e := range s.Elements { + e.ParentID = sql.NullString{Valid: true, String: strconv.FormatUint(uint64(s.ID), 10)} + children = append(children, e) + children = append(children, e.GetAllChildren()...) + } + + return children +} + +func (s AppSession) GetParentOf(e *AppSessionElement) *AppSessionElement { + if !e.ParentID.Valid { + return nil + } + + for _, p := range s.Elements { + if strconv.FormatUint(uint64(p.ID), 10) == e.ParentID.String { + return &p + } + } + + return nil +} + +func (s AppSession) GetPath(e AppSessionElement) []string { + var path []string + + elem := &e + for elem != nil { + path = append([]string{elem.Name}, path...) + elem = s.GetParentOf(elem) + } + + return path +} diff --git a/cli/appdev/app_session_test.go b/cli/appdev/app_session_test.go new file mode 100644 index 00000000..1c4775ad --- /dev/null +++ b/cli/appdev/app_session_test.go @@ -0,0 +1,83 @@ +package appdev + +import ( + "database/sql" + "testing" + + "github.com/stretchr/testify/assert" + "gorm.io/gorm" +) + +func TestGetElementByID(t *testing.T) { + session := AppSession{ + Elements: []AppSessionElement{ + {Model: gorm.Model{ID: 1}, Name: "Elem 1"}, + {Model: gorm.Model{ID: 2}, Name: "Elem 2"}, + {Model: gorm.Model{ID: 3}, Name: "Elem 3"}, + {Model: gorm.Model{ID: 4}, Name: "Elem 4"}, + }, + } + + t.Run("returns expected element", func(t *testing.T) { + wantName := "Elem 2" + + gotElem, gotErr := session.GetElementByID("2") + assert.NoError(t, gotErr) + + assert.NoError(t, gotErr) + assert.Equal(t, wantName, gotElem.Name) + }) + + t.Run("returns error element does not exist", func(t *testing.T) { + _, gotErr := session.GetElementByID("10") + assert.EqualError(t, gotErr, "no element with ID \"10\"") + }) +} + +func TestGetElementByPath(t *testing.T) { + session := AppSession{ + Elements: []AppSessionElement{ + {Model: gorm.Model{ID: 1}, Name: "elem_1"}, + {Model: gorm.Model{ID: 2}, Name: "elem_2"}, + {Model: gorm.Model{ID: 3}, Name: "elem_3", ParentID: sql.NullString{String: "2", Valid: true}}, + {Model: gorm.Model{ID: 4}, Name: "elem_4", ParentID: sql.NullString{String: "3", Valid: true}}, + }, + } + + t.Run("get expected root level element", func(t *testing.T) { + var wantID uint = 1 + gotElem, gotErr := session.GetElementByPath([]string{"elem_1"}) + + assert.NoError(t, gotErr) + if assert.NotNil(t, gotElem) { + assert.Equal(t, wantID, gotElem.ID) + } + }) + + t.Run("cannot get nested element at root", func(t *testing.T) { + _, gotErr := session.GetElementByPath([]string{"elem_3"}) + assert.ErrorIs(t, gotErr, ErrAppSessionElementNotFound) + }) + + t.Run("returns expected child element", func(t *testing.T) { + var wantID uint = 3 + gotElem, gotErr := session.GetElementByPath([]string{"elem_2", "elem_3"}) + + assert.NoError(t, gotErr) + assert.Equal(t, wantID, gotElem.ID) + }) + + t.Run("returns expected nested element", func(t *testing.T) { + var wantID uint = 4 + gotElem, gotErr := session.GetElementByPath([]string{"elem_2", "elem_3", "elem_4"}) + + assert.NoError(t, gotErr) + assert.Equal(t, wantID, gotElem.ID) + }) + + t.Run("does not return child that does not exist", func(t *testing.T) { + gotElem, gotErr := session.GetElementByPath([]string{"elem_2", "elem_3", "elem_4", "non_existing"}) + assert.ErrorIs(t, gotErr, ErrAppSessionElementNotFound) + assert.Nil(t, gotElem) + }) +} diff --git a/cli/appdev/diff.go b/cli/appdev/diff.go new file mode 100644 index 00000000..83b2f4a2 --- /dev/null +++ b/cli/appdev/diff.go @@ -0,0 +1,114 @@ +package appdev + +import ( + "errors" + "log/slog" + "strconv" +) + +// Represents the difference between an existing AppSession, and a new +// AppDefinition. +type AppSessionDifference struct { + Added []AppSessionElement + Removed []AppSessionElement + Updated []AppSessionElement +} + +// Returns the difference between the elements in the provided existing app +// session, and the provided new app definition. +// +// Elements are matched by their paths within the app, where a path is a list of +// element names, ending with the elements own name, preceded by all the parent +// elements' names. +func GetAppSessionDifference(existing AppSession, newDef AppDefinition) AppSessionDifference { + return AppSessionDifference{ + Removed: getRemovedElements(existing, newDef), + Added: getAddedElementsFromTool(existing, newDef), + Updated: getUpdatedElementsFromTool(existing, newDef), + } +} + +func getRemovedElements(session AppSession, newDef AppDefinition) []AppSessionElement { + var removed []AppSessionElement + + for _, sess := range session.Elements { + path := session.GetPath(sess) + _, err := newDef.GetElementByPath(path) + if err != nil { + removed = append(removed, sess) + } + } + + return removed +} + +func getAddedElementsFromTool(session AppSession, newDef AppDefinition) []AppSessionElement { + var added []AppSessionElement + + for _, newDef := range newDef.Elements { + added = append(added, getAddedElementsFromElement(session, newDef)...) + } + + return added +} + +func getAddedElementsFromElement(session AppSession, newDef AppDefinitionElement) []AppSessionElement { + var added []AppSessionElement + + p := newDef.GetPath() + _, err := session.GetElementByPath(p) + + if errors.Is(err, ErrAppSessionElementNotFound) { + newElem, err := newDef.CreateSessionElement() + if err != nil { + slog.Info("could not create new added element", slog.Any("error", err)) + return added + } + + if newDef.Parent != nil { + if parent, err := session.GetElementByPath(newDef.Parent.GetPath()); err == nil { + newElem.ParentID.Valid = true + newElem.ParentID.String = strconv.FormatUint(uint64(parent.ID), 10) + } + } + + newElem.AppSessionID = session.ID + + return append(added, *newElem) + } else { + for _, newChild := range newDef.Elements { + added = append(added, getAddedElementsFromElement(session, newChild)...) + } + + return added + } +} + +func getUpdatedElementsFromTool(session AppSession, newDefApp AppDefinition) []AppSessionElement { + var updated []AppSessionElement + + for _, newDefElem := range newDefApp.Elements { + updated = append(updated, getUpdatedElementsFromElement(session, newDefElem)...) + } + + return updated +} + +func getUpdatedElementsFromElement(session AppSession, newDefElem AppDefinitionElement) []AppSessionElement { + var updated []AppSessionElement + + p := newDefElem.GetPath() + sessionElement, err := session.GetElementByPath(p) + + if err == nil { + if sessionElement.Label != newDefElem.Label { + sessionElement.Label = newDefElem.Label + updated = append(updated, *sessionElement) + } + for _, newChild := range newDefElem.Elements { + updated = append(updated, getUpdatedElementsFromElement(session, newChild)...) + } + } + + return updated +} diff --git a/cli/appdev/diff_test.go b/cli/appdev/diff_test.go new file mode 100644 index 00000000..7bf9c80b --- /dev/null +++ b/cli/appdev/diff_test.go @@ -0,0 +1,348 @@ +package appdev + +import ( + "database/sql" + "testing" + + "github.com/stretchr/testify/assert" + "gorm.io/gorm" +) + +type differenceTestCase struct { + name string + session AppSession + newDef AppDefinition + expectedDiff AppSessionDifference +} + +func TestGetToolSessionDifference(t *testing.T) { + testCases := []differenceTestCase{ + { + name: "element removed", + session: AppSession{ + Model: gorm.Model{ID: 0}, + Elements: []AppSessionElement{ + { + Model: gorm.Model{ID: 0}, + Name: "number_element", + Type: "number", + NumberValue: sql.NullFloat64{Valid: true, Float64: 10.0}, + }, + { + Model: gorm.Model{ID: 1}, + Name: "string_element", + Type: "string", + StringValue: sql.NullString{Valid: true, String: "some string value"}, + }, + }, + }, + newDef: AppDefinition{ + Elements: []AppDefinitionElement{ + {Name: "number_element", Type: "number", Default: 123.0}, + }, + }, + expectedDiff: AppSessionDifference{ + Removed: []AppSessionElement{ + { + Model: gorm.Model{ID: 1}, + Name: "string_element", + Type: "string", + StringValue: sql.NullString{Valid: true, String: "some string value"}, + }, + }, + }, + }, + { + name: "element added", + session: AppSession{ + Model: gorm.Model{ID: 0}, + Elements: []AppSessionElement{ + { + Model: gorm.Model{ID: 0}, + Name: "number_element", + Type: "number", + NumberValue: sql.NullFloat64{Valid: true, Float64: 10.0}, + }, + }, + }, + newDef: AppDefinition{ + Elements: []AppDefinitionElement{ + {Name: "number_element", Type: "number", Default: 123.0}, + {Name: "string_element", Type: "string", Default: "default string value"}, + }, + }, + expectedDiff: AppSessionDifference{ + Added: []AppSessionElement{ + { + Name: "string_element", + Type: "string", + StringValue: sql.NullString{Valid: true, String: "default string value"}, + }, + }, + }, + }, + { + name: "element label updated", + session: AppSession{ + Model: gorm.Model{ID: 0}, + Elements: []AppSessionElement{ + { + Model: gorm.Model{ID: 0}, + Name: "number_element", + Label: "Number Label", + Type: "number", + NumberValue: sql.NullFloat64{Valid: true, Float64: 10.0}, + }, + { + Model: gorm.Model{ID: 1}, + Name: "string_element", + Label: "String Label", + Type: "string", + StringValue: sql.NullString{Valid: true, String: "default string value"}, + }, + }, + }, + newDef: AppDefinition{ + Elements: []AppDefinitionElement{ + {Name: "number_element", Type: "number", Label: "Number Label", Default: 10.0}, + {Name: "string_element", Type: "string", Label: "Updated String Label", Default: "default string value"}, + }, + }, + expectedDiff: AppSessionDifference{ + Updated: []AppSessionElement{ + { + Model: gorm.Model{ID: 1}, + Name: "string_element", + Type: "string", + Label: "Updated String Label", + StringValue: sql.NullString{Valid: true, String: "default string value"}, + }, + }, + }, + }, + { + name: "nested element added", + session: AppSession{ + Model: gorm.Model{ID: 0}, + Elements: []AppSessionElement{ + { + Model: gorm.Model{ID: 5}, + Name: "container_element", + Type: "container", + }, + { + Model: gorm.Model{ID: 6}, + Name: "number_element", + Type: "number", + NumberValue: sql.NullFloat64{Valid: true, Float64: 10.0}, + ParentID: sql.NullString{Valid: true, String: "5"}, + }, + }, + }, + newDef: AppDefinition{ + Elements: []AppDefinitionElement{ + {Name: "container_element", Type: "container", Elements: []AppDefinitionElement{ + {Name: "number_element", Type: "number", Default: 123.0}, + {Name: "string_element", Type: "string", Default: "default string value"}, + }}, + }, + }, + expectedDiff: AppSessionDifference{ + Added: []AppSessionElement{ + { + Name: "string_element", + Type: "string", + StringValue: sql.NullString{Valid: true, String: "default string value"}, + ParentID: sql.NullString{Valid: true, String: "5"}, + }, + }, + }, + }, + { + name: "nested element label updated", + session: AppSession{ + Model: gorm.Model{ID: 0}, + Elements: []AppSessionElement{ + { + Model: gorm.Model{ID: 1}, + Name: "container_element", + Type: "container", + }, + { + Model: gorm.Model{ID: 2}, + Name: "nested_container_element", + Type: "container", + ParentID: sql.NullString{Valid: true, String: "1"}, + }, + { + Model: gorm.Model{ID: 3}, + Name: "number_element", + Label: "Number Label", + Type: "number", + NumberValue: sql.NullFloat64{Valid: true, Float64: 10.0}, + ParentID: sql.NullString{Valid: true, String: "1"}, + }, + { + Model: gorm.Model{ID: 4}, + Name: "string_element", + Label: "String Label", + Type: "string", + StringValue: sql.NullString{Valid: true, String: "default string value"}, + ParentID: sql.NullString{Valid: true, String: "2"}, + }, + }, + }, + newDef: AppDefinition{ + Elements: []AppDefinitionElement{ + { + Name: "container_element", Type: "container", Elements: []AppDefinitionElement{ + {Name: "number_element", Label: "Updated Number Label", Type: "number", Default: 123.0}, + { + Name: "nested_container_element", Type: "container", Elements: []AppDefinitionElement{ + {Name: "string_element", Label: "Updated String Label", Type: "string", Default: "default string value"}, + }, + }, + }, + }, + }, + }, + expectedDiff: AppSessionDifference{ + Updated: []AppSessionElement{ + { + Model: gorm.Model{ID: 3}, + Name: "number_element", + Label: "Updated Number Label", + Type: "number", + NumberValue: sql.NullFloat64{Valid: true, Float64: 10.0}, + ParentID: sql.NullString{Valid: true, String: "1"}, + }, + { + Model: gorm.Model{ID: 4}, + Name: "string_element", + Label: "Updated String Label", + Type: "string", + StringValue: sql.NullString{Valid: true, String: "default string value"}, + ParentID: sql.NullString{Valid: true, String: "2"}, + }, + }, + }, + }, + { + name: "unchanged session with doubled child has empty diff", + session: AppSession{ + Model: gorm.Model{ + ID: 0, + }, + Name: "ContainerTool", + Elements: []AppSessionElement{ + { + Model: gorm.Model{ID: 0}, + Name: "my_container", + Type: "container", + Elements: []AppSessionElement{ + { + Model: gorm.Model{ID: 0}, + AppSessionID: 0, + Name: "child", + Type: "string", + StringValue: sql.NullString{String: "", Valid: true}, + }, + }, + }, + { + Model: gorm.Model{ID: 1}, + AppSessionID: 0, + Name: "print_child", + Type: "action", + }, + { + Model: gorm.Model{ID: 2}, + AppSessionID: 0, + ParentID: sql.NullString{String: "0", Valid: true}, + Name: "child", + Type: "string", + StringValue: sql.NullString{String: "", Valid: true}, + }, + }, + }, + newDef: AppDefinition{ + Name: "ContainerTool", + Elements: []AppDefinitionElement{ + { + Name: "my_container", + Type: "container", + Elements: []AppDefinitionElement{ + { + Name: "child", + Type: "string", + Default: "", + }, + }, + }, + { + Name: "print_child", + Type: "action", + }, + }, + }, + expectedDiff: AppSessionDifference{}, + }, + { + name: "container added diff is nested", + session: AppSession{ + Model: gorm.Model{ + ID: 0, + }, + Elements: []AppSessionElement{ + { + Model: gorm.Model{ID: 0}, + Name: "action", + Type: "action", + AppSessionID: 0, + }, + }, + }, + newDef: AppDefinition{ + Elements: []AppDefinitionElement{ + { + Name: "container", + Type: "container", + Elements: []AppDefinitionElement{ + {Name: "child", Type: "string", Default: "default"}, + }, + }, + { + Name: "action", + Type: "action", + }, + }, + }, + expectedDiff: AppSessionDifference{ + Added: []AppSessionElement{ + { + Name: "container", + Type: "container", + Elements: []AppSessionElement{ + { + Name: "child", + Type: "string", + StringValue: sql.NullString{String: "default", Valid: true}, + }, + }, + }, + }, + }, + }, + } + + for _, testCase := range testCases { + name := testCase.name + t.Run(name, func(t *testing.T) { + testCase.newDef.SetElementParents() + diff := GetAppSessionDifference(testCase.session, testCase.newDef) + if !assert.Equal(t, testCase.expectedDiff, diff) { + println() + } + }) + } +} diff --git a/cli/appdev/log.go b/cli/appdev/log.go new file mode 100644 index 00000000..8326c016 --- /dev/null +++ b/cli/appdev/log.go @@ -0,0 +1,16 @@ +package appdev + +import ( + "encoding/json" + "log/slog" +) + +func SlogJSON(key string, value any) slog.Attr { + j, err := json.Marshal(value) + + if err != nil { + return slog.Group(key, slog.Any("error", err), slog.Any("value", value)) + } else { + return slog.String(key, string(j)) + } +} diff --git a/cli/appdev/output.go b/cli/appdev/output.go new file mode 100644 index 00000000..963a519c --- /dev/null +++ b/cli/appdev/output.go @@ -0,0 +1,291 @@ +package appdev + +import ( + "fmt" + "strings" + + "github.com/charmbracelet/lipgloss" +) + +type Output interface { + StartingApp(port string) + StartedApp() + AppModuleNotFound(err error) + AwaitingAppChanges() + ErrorReadingApp(readOutput string, err error) + ErrorParsingApp(err error) + ErrorStartingApp(err error) + ErrorWatchingAppFiles(err error) + FileUpdatedRestartingApp() + ErrorUpdateAddingElement() + ErrorUpdateRemovingElement() + ErrorUpdateUpdatingElement() + ErrorCreatingAppSession(err error) + ErrorGettingAppOutputStream(streamName string) + PrintAppLogLine(line string) + Stopping() + ErrorLoadingApp(appError *ParseAppDefinitionError) +} + +type FmtOutput struct { + appModulePath string + appClassName string +} + +func (o *FmtOutput) StartingApp(port string) { + fmt.Printf("Starting %s:%s at http://localhost:%s\n", o.appModulePath, o.appClassName, port) +} + +func (o *FmtOutput) StartedApp() { + fmt.Printf("Started %s:%s\n", o.appModulePath, o.appClassName) +} + +func (o *FmtOutput) AppModuleNotFound(err error) { + fmt.Printf("Could not find app module %s: %s\n", o.appModulePath, err) +} + +func (o *FmtOutput) AwaitingAppChanges() { + fmt.Printf("Waiting for changes to '%s'...\n", o.appModulePath) +} + +func (o *FmtOutput) ErrorReadingApp(readOutput string, err error) { + fmt.Printf("An error occurred while reading the app definition of %s:%s!\n", o.appModulePath, o.appClassName) +} + +func (o *FmtOutput) ErrorParsingApp(err error) { + fmt.Println("The app definition was not valid.") +} + +func (o *FmtOutput) ErrorStartingApp(err error) { + fmt.Printf("Could not start %s:%s", o.appModulePath, o.appClassName) + fmt.Printf("Error: %s", err) +} + +func (o *FmtOutput) ErrorWatchingAppFiles(err error) { + fmt.Printf("file watcher for %s did not start: %s\n", o.appModulePath, err.Error()) +} + +func (o *FmtOutput) FileUpdatedRestartingApp() { + fmt.Printf("watcher: %s updated, restarting app.\n", o.appModulePath) +} + +func (o *FmtOutput) ErrorUpdateAddingElement() { + fmt.Println("Could not update app, error adding elements.") +} + +func (o *FmtOutput) ErrorUpdateRemovingElement() { + fmt.Println("Could not update app, error removing elements.") +} + +func (o *FmtOutput) ErrorUpdateUpdatingElement() { + fmt.Println("Could not update app, error updating elements.") +} + +func (o *FmtOutput) ErrorCreatingAppSession(err error) { + fmt.Printf("Could not create app session: %s\n", err) +} + +func (o *FmtOutput) ErrorGettingAppOutputStream(streamName string) { + fmt.Printf("%s:%s> Could not access stream %s in app\n", o.appModulePath, o.appClassName, streamName) +} + +func (o *FmtOutput) PrintAppLogLine(line string) { + fmt.Printf("%s:%s> %s", o.appModulePath, o.appClassName, line) +} + +func (o *FmtOutput) Stopping() { + fmt.Println("Stopping development server") +} + +func (o *FmtOutput) ErrorLoadingApp(appError *ParseAppDefinitionError) { + switch { + case appError.ModuleNotFound != nil: + fmt.Printf("The module '%s' imported in your python code was not found\n", appError.ModuleNotFound.Module) + fmt.Println("Common reasons for this include:") + fmt.Println(" * Some of your external dependencies have not been installed") + fmt.Println(" * You have not activated the correct virtual environment") + fmt.Println(" * Or there might be an error in your import") + case appError.AppNotFound != nil: + fmt.Printf("The app '%s' was not found in the specified module '%s'\n", appError.AppNotFound.App, o.appModulePath) + if len(appError.AppNotFound.FoundApps) > 0 { + fmt.Println("The following apps were found in the module") + for _, app := range appError.AppNotFound.FoundApps { + fmt.Println(" * ", app) + } + } else { + fmt.Println("We found no defined apps in that module, are you sure it is the correct one?") + } + case appError.Syntax != nil: + fmt.Printf("A syntax error occurred, loading your app module '%s'\n", o.appModulePath) + fmt.Println("Syntex error message:", appError.Syntax.Msg) + fmt.Printf("The error occurred at line %d, column %d:\n", appError.Syntax.Pos.Line, appError.Syntax.Pos.Offset) + fmt.Println(appError.Syntax.Context) + case appError.Unknown != nil: + fmt.Printf("An unhandled exception of type '%s' was raised loading '%s'\n", appError.Unknown.Typename, o.appModulePath) + fmt.Println(appError.Unknown.Traceback) + } +} + +var ( + ColorOK = lipgloss.Color("#23DD65") + ColorLifecycle = lipgloss.Color("#2365DD") + ColorError = lipgloss.Color("#FF2323") + ColorNotice = lipgloss.Color("#DDAA22") +) + +type LipglossOutput struct { + appModulePath string + appClassName string + okStyle lipgloss.Style + lifecycleStyle lipgloss.Style + logNameStyle lipgloss.Style + noticeStyle lipgloss.Style + errorHeaderStyle lipgloss.Style + errorBodyStyle lipgloss.Style + errorContextStyle lipgloss.Style +} + +func NewLipglossOutput(appModulePath string, appClassName string) LipglossOutput { + return LipglossOutput{ + appModulePath: appModulePath, + appClassName: appClassName, + okStyle: lipgloss.NewStyle().Bold(true).Foreground(ColorOK), + lifecycleStyle: lipgloss.NewStyle().Bold(true).Foreground(ColorLifecycle), + logNameStyle: lipgloss.NewStyle().Border(lipgloss.NormalBorder(), false, true, false, false).Faint(true), + noticeStyle: lipgloss.NewStyle().Foreground(ColorNotice), + errorHeaderStyle: lipgloss.NewStyle().Bold(true).Foreground(ColorError), + errorBodyStyle: lipgloss.NewStyle().Foreground(ColorError), + errorContextStyle: lipgloss.NewStyle(). + Foreground(ColorError). + BorderForeground(ColorError). + BorderLeft(true). + Border(lipgloss.NormalBorder(), false, false, false, true), + } +} + +func (o *LipglossOutput) printErrorHeader(format string, args ...any) { + o.printStyle(o.errorHeaderStyle, format, args...) +} + +func (o *LipglossOutput) printErrorBody(format string, args ...any) { + o.printStyle(o.errorBodyStyle, format, args...) +} + +func (o *LipglossOutput) printErrorContext(format string, args ...any) { + o.printStyle(o.errorContextStyle, format, args...) +} + +func (o *LipglossOutput) printNotice(format string, args ...any) { + o.printStyle(o.noticeStyle, format, args...) +} + +func (o *LipglossOutput) printOK(format string, args ...any) { + o.printStyle(o.okStyle, format, args...) +} + +func (o *LipglossOutput) printLifecycle(format string, args ...any) { + o.printStyle(o.lifecycleStyle, format, args...) +} + +func (o *LipglossOutput) printStyle(style lipgloss.Style, format string, args ...any) { + msg := fmt.Sprintf(format, args...) + fmt.Println(style.Render(msg)) +} + +func (o *LipglossOutput) StartingApp(port string) { + o.printLifecycle("Starting %s:%s app at http://localhost:%s", o.appModulePath, o.appClassName, port) +} + +func (o *LipglossOutput) StartedApp() { + o.printOK("Started %s:%s", o.appModulePath, o.appClassName) +} + +func (o *LipglossOutput) AppModuleNotFound(err error) { + o.printErrorHeader("Could not find app module %s: %s", o.appModulePath, err) +} + +func (o *LipglossOutput) AwaitingAppChanges() { + o.printLifecycle("Waiting for changes to '%s'...", o.appModulePath) +} + +func (o *LipglossOutput) ErrorReadingApp(readOutput string, err error) { + o.printErrorHeader("An error occurred while reading the app definition of %s:%s: %s", o.appModulePath, o.appClassName, err) + o.printErrorBody("This could be due to a bug in the numerous app engine.") + o.printErrorBody("The following error message was produced, while reading the app:") + for _, line := range strings.Split(readOutput, "\n") { + o.printErrorContext(line) + } +} + +func (o *LipglossOutput) ErrorParsingApp(err error) { + o.printErrorHeader("An error occurred while reading the app definition of %s:%s: %s", o.appModulePath, o.appClassName, err) +} + +func (o *LipglossOutput) ErrorStartingApp(err error) { + o.printErrorHeader("Could not start %s:%s: %s", o.appModulePath, o.appClassName, err.Error()) +} + +func (o *LipglossOutput) ErrorWatchingAppFiles(err error) { + o.printErrorHeader("Error watching '%s' for changes: %s", o.appModulePath, err.Error()) +} + +func (o *LipglossOutput) FileUpdatedRestartingApp() { + o.printNotice("File '%s' changed, restarting app...", o.appModulePath) +} + +func (o *LipglossOutput) ErrorUpdateAddingElement() { + o.printErrorHeader("Could not update app, error adding elements.") +} + +func (o *LipglossOutput) ErrorUpdateRemovingElement() { + o.printErrorHeader("Could not update app, error removing elements.") +} + +func (o *LipglossOutput) ErrorUpdateUpdatingElement() { + o.printErrorHeader("Could not update app, error updating elements.") +} + +func (o *LipglossOutput) ErrorCreatingAppSession(err error) { + o.printErrorHeader("Could not create app session:" + err.Error()) +} + +func (o *LipglossOutput) ErrorGettingAppOutputStream(streamName string) { + o.printErrorHeader("Could not access stream %s running %s:%s\n", streamName, o.appModulePath, o.appClassName) +} + +func (o *LipglossOutput) PrintAppLogLine(line string) { + fmt.Print(o.logNameStyle.Render(fmt.Sprintf("%s:%s", o.appModulePath, o.appClassName))) + fmt.Println(line) +} + +func (o *LipglossOutput) Stopping() { + o.printNotice("Stopping development server") +} + +func (o *LipglossOutput) ErrorLoadingApp(appError *ParseAppDefinitionError) { + switch { + case appError.ModuleNotFound != nil: + o.printErrorHeader("The module '%s' imported in your python code was not found", appError.ModuleNotFound.Module) + o.printNotice("Common reasons for this include:") + o.printNotice(" * Some of your external dependencies have not been installed") + o.printNotice(" * You have not activated the correct virtual environment") + o.printNotice(" * Or there might be an error in your import") + case appError.AppNotFound != nil: + o.printErrorHeader("The app '%s' was not found in the specified module '%s'", appError.AppNotFound.App, o.appModulePath) + if len(appError.AppNotFound.FoundApps) > 0 { + o.printNotice("The following apps were found in the module") + for _, app := range appError.AppNotFound.FoundApps { + o.printNotice(" * %s", app) + } + } else { + o.printNotice("We found no defined apps in that module, are you sure it is the correct one?") + } + case appError.Syntax != nil: + o.printErrorHeader("A syntax error occurred, loading your app module '%s': %s", o.appModulePath, appError.Syntax.Msg) + o.printErrorBody("The error occurred in \"%s\", line %d, column %d:", o.appModulePath, appError.Syntax.Pos.Line, appError.Syntax.Pos.Offset) + o.printErrorContext(appError.Syntax.Context) + case appError.Unknown != nil: + o.printErrorHeader("An unhandled exception of type '%s' was raised loading '%s'", appError.Unknown.Typename, o.appModulePath) + o.printErrorContext(appError.Unknown.Traceback) + } +} diff --git a/cli/appdev/parse.go b/cli/appdev/parse.go new file mode 100644 index 00000000..7d145b07 --- /dev/null +++ b/cli/appdev/parse.go @@ -0,0 +1,60 @@ +package appdev + +import ( + "encoding/json" + "log/slog" +) + +type AppCodeCoordinate struct { + Line uint `json:"line"` + Offset uint `json:"offset"` +} + +type AppSyntaxError struct { + Msg string `json:"msg"` + Context string `json:"context"` + Pos AppCodeCoordinate `json:"pos"` +} + +type AppModuleNotFoundError struct { + Module string `json:"module"` +} + +type AppUnknownError struct { + Typename string `json:"typename"` + Traceback string `json:"traceback"` +} + +type AppNotFoundError struct { + App string `json:"app"` + FoundApps []string `json:"found_apps"` +} + +type ParseAppDefinitionError struct { + AppNotFound *AppNotFoundError `json:"appnotfound"` + Syntax *AppSyntaxError `json:"appsyntax"` + ModuleNotFound *AppModuleNotFoundError `json:"modulenotfound"` + Unknown *AppUnknownError `json:"unknown"` +} + +type ParseAppDefinitionResult struct { + App *AppDefinition `json:"app"` + Error *ParseAppDefinitionError `json:"error"` +} + +func ParseAppDefinition(definition []byte) (ParseAppDefinitionResult, error) { + var result ParseAppDefinitionResult + + if err := json.Unmarshal(definition, &result); err != nil { + slog.Warn( + "Failed to unmarshal app definition", + slog.Any("definition", definition), + ) + + return result, err + } else if result.App != nil { + result.App.SetElementParents() + } + + return result, nil +} diff --git a/cli/appdev/parse_test.go b/cli/appdev/parse_test.go new file mode 100644 index 00000000..8e4ac9c5 --- /dev/null +++ b/cli/appdev/parse_test.go @@ -0,0 +1,167 @@ +package appdev + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestParseAppDefinitionReturnsResultWithApp(t *testing.T) { + containerDef := AppDefinitionElement{ + Name: "Container", + Type: "container", + } + containerDef.Elements = []AppDefinitionElement{{Name: "Text", Type: "string", Default: "default text", Parent: &containerDef}} + + testCases := []struct { + json string + expected ParseAppDefinitionResult + }{ + { + json: `{"app": {"name": "App Name", "elements": []}}`, + expected: ParseAppDefinitionResult{App: &AppDefinition{Name: "App Name", Elements: []AppDefinitionElement{}}}, + }, + { + json: `{"app": {"name": "App Name", "elements": [{"name": "Text", "type": "string", "default": "default text"}]}}`, + expected: ParseAppDefinitionResult{App: &AppDefinition{Name: "App Name", Elements: []AppDefinitionElement{ + {Name: "Text", Type: "string", Default: "default text"}, + }}}, + }, + { + json: `{"app": {"name": "App Name", "elements": [{"name": "Number", "type": "number", "default": 12.3}]}}`, + expected: ParseAppDefinitionResult{App: &AppDefinition{Name: "App Name", Elements: []AppDefinitionElement{ + {Name: "Number", Type: "number", Default: 12.3}, + }}}, + }, + { + json: `{"app": {"name": "App Name", "elements": [{"name": "Slider", "type": "slider", "default": 1.2, "slider_min_value": 3.4, "slider_max_value": 5.6}]}}`, + expected: ParseAppDefinitionResult{App: &AppDefinition{Name: "App Name", Elements: []AppDefinitionElement{ + {Name: "Slider", Type: "slider", Default: 1.2, SliderMinValue: 3.4, SliderMaxValue: 5.6}, + }}}, + }, + { + json: `{"app": {"name": "App Name", "elements": [{"name": "Html", "type": "html", "default": "

default html

"}]}}`, + expected: ParseAppDefinitionResult{App: &AppDefinition{Name: "App Name", Elements: []AppDefinitionElement{ + {Name: "Html", Type: "html", Default: "

default html

"}, + }}}, + }, + { + json: `{"app": {"name": "App Name", "elements": [{"name": "Container", "type": "container", "elements": [{"name": "Text", "type": "string", "default": "default text"}]}]}}`, + expected: ParseAppDefinitionResult{App: &AppDefinition{Name: "App Name", Elements: []AppDefinitionElement{containerDef}}}, + }, + { + json: `{"app": {"name": "App Name", "elements": [{"name": "Container", "type": "container", "elements": [{"name": "Text", "type": "string", "default": "default text"}]}, {"name": "Sibling", "type": "action"}]}}`, + expected: ParseAppDefinitionResult{App: &AppDefinition{Name: "App Name", Elements: []AppDefinitionElement{containerDef, {Name: "Sibling", Type: "action"}}}}, + }, + } + + for _, testCase := range testCases { + result, err := ParseAppDefinition([]byte(testCase.json)) + assert.NoError(t, err) + assert.Equal(t, testCase.expected, result) + } +} + +func TestParseAppDefinitionReturnsResultWithError(t *testing.T) { + containerDef := AppDefinitionElement{ + Name: "Container", + Type: "container", + } + containerDef.Elements = []AppDefinitionElement{{Name: "Text", Type: "string", Default: "default text", Parent: &containerDef}} + + testCases := []struct { + json string + expected ParseAppDefinitionResult + }{ + { + json: ` + { + "error": { + "appnotfound": { + "app": "MyApp", + "found_apps": ["MyOtherApp"] + } + } + }`, + expected: ParseAppDefinitionResult{Error: &ParseAppDefinitionError{ + AppNotFound: &AppNotFoundError{ + App: "MyApp", + FoundApps: []string{"MyOtherApp"}, + }, + }}, + }, + { + json: ` + { + "error": { + "modulenotfound": { + "module": "somenotfoundmodule" + } + } + }`, + expected: ParseAppDefinitionResult{Error: &ParseAppDefinitionError{ + ModuleNotFound: &AppModuleNotFoundError{ + Module: "somenotfoundmodule", + }, + }}, + }, + { + json: ` + { + "error": { + "appsyntax": { + "context": "def bla(\n ^", + "msg": "error description", + "pos": {"line": 5, "offset": 7} + } + } + }`, + expected: ParseAppDefinitionResult{Error: &ParseAppDefinitionError{ + Syntax: &AppSyntaxError{ + Msg: "error description", + Context: "def bla(\n ^", + Pos: AppCodeCoordinate{Line: 5, Offset: 7}, + }, + }}, + }, + { + json: ` + { + "error": { + "unknown": { + "typename": "SomeError", + "traceback": "Traceback:\nFile: blabla\nFile: blabla\n" + } + } + }`, + expected: ParseAppDefinitionResult{ + Error: &ParseAppDefinitionError{ + Unknown: &AppUnknownError{ + Typename: "SomeError", + Traceback: "Traceback:\nFile: blabla\nFile: blabla\n", + }, + }, + }, + }, + } + + for _, testCase := range testCases { + result, err := ParseAppDefinition([]byte(testCase.json)) + assert.NoError(t, err) + assert.Equal(t, testCase.expected, result) + } +} + +func TestParseAppDefinitionReturnsError(t *testing.T) { + t.Run("invalid json returns error", func(t *testing.T) { + result, err := ParseAppDefinition([]byte(`{jens: 123}`)) + assert.Equal(t, ParseAppDefinitionResult{}, result) + assert.Error(t, err) + }) + + t.Run("unended json returns error", func(t *testing.T) { + result, err := ParseAppDefinition([]byte(`{"name": "App", "elements": []`)) + assert.Equal(t, ParseAppDefinitionResult{}, result) + assert.Error(t, err) + }) +} diff --git a/cli/appdev/repositories_test.go b/cli/appdev/repositories_test.go new file mode 100644 index 00000000..e3245934 --- /dev/null +++ b/cli/appdev/repositories_test.go @@ -0,0 +1,312 @@ +package appdev + +import ( + "database/sql" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "gorm.io/gorm" +) + +func compareToolSession(t *testing.T, s *AppSession) { + t.Helper() + assert.Equal(t, "Tool", s.Name) + + expectedTextElement := AppSessionElement{ + Model: gorm.Model{ID: 0}, + Name: "text_element", + Type: "string", + StringValue: sql.NullString{Valid: true, String: "default"}, + } + + expectedNumberElement := AppSessionElement{ + Model: gorm.Model{ID: 1}, + Name: "number_element", + Type: "number", + NumberValue: sql.NullFloat64{Valid: true, Float64: 1.0}, + } + + assert.Equal(t, []AppSessionElement{expectedTextElement, expectedNumberElement}, s.Elements) +} + +func compareSecondToolSession(t *testing.T, s *AppSession) { + t.Helper() + if s.Name != "SecondTool" { + t.Fatalf("got tool name %s, want %s", s.Name, "Tool") + } + + expectedTextElement := AppSessionElement{ + Model: gorm.Model{ID: 2}, + Name: "second_text_element", + Type: "string", + StringValue: sql.NullString{Valid: true, String: "second default"}, + } + expectedNumberElement := AppSessionElement{ + Model: gorm.Model{ID: 3}, + Name: "second_number_element", + Type: "number", + NumberValue: sql.NullFloat64{Valid: true, Float64: 10.0}, + } + + assert.Equal(t, []AppSessionElement{expectedTextElement, expectedNumberElement}, s.Elements) +} + +func TestToolSessionRepository(t *testing.T) { + def := AppDefinition{ + Name: "Tool", + Elements: []AppDefinitionElement{ + {Name: "text_element", Type: "string", Default: "default"}, + {Name: "number_element", Type: "number", Default: 1.0}, + }, + } + + secondDef := AppDefinition{ + Name: "SecondTool", + Elements: []AppDefinitionElement{ + {Name: "second_text_element", Type: "string", Default: "second default"}, + {Name: "second_number_element", Type: "number", Default: 10.0}, + }, + } + + t.Run("Create returns new ToolSession", func(t *testing.T) { + r := InMemoryAppSessionRepository{} + + s, err := r.Create(def) + require.NoError(t, err) + + compareToolSession(t, s) + }) + + t.Run("Read returns error before Create", func(t *testing.T) { + r := InMemoryAppSessionRepository{} + + if s, err := r.Read(0); err == nil { + t.Fatalf("r.Read(0) = (%#v, nil), want (nil, error)", s) + } else { + require.EqualError(t, err, ErrSessionNotCreated.Error()) + } + }) + + t.Run("Read returns ToolSession after Create", func(t *testing.T) { + r := InMemoryAppSessionRepository{} + + _, err := r.Create(def) + require.NoError(t, err) + + s, err := r.Read(0) + require.NoError(t, err) + + compareToolSession(t, s) + }) + + t.Run("Read returns same ToolSession no matter the ID", func(t *testing.T) { + r := InMemoryAppSessionRepository{} + + _, err := r.Create(def) + require.NoError(t, err) + + for i := uint(0); i < 1000; i += 100 { + s, err := r.Read(i) + require.NoError(t, err) + compareToolSession(t, s) + } + }) + + t.Run("Create overrides existing global ToolSession", func(t *testing.T) { + r := InMemoryAppSessionRepository{} + _, err := r.Create(def) + require.NoError(t, err) + + _, err = r.Create(secondDef) + require.NoError(t, err) + s, err := r.Read(0) + require.NoError(t, err) + + compareSecondToolSession(t, s) + }) + + t.Run("Delete panics", func(t *testing.T) { + r := InMemoryAppSessionRepository{} + + require.Panics(t, func() { + //nolint:errcheck + r.Delete(0) + }) + }) + + t.Run("assigns ids to nested elements", func(t *testing.T) { + r := InMemoryAppSessionRepository{} + + def := AppDefinition{ + Elements: []AppDefinitionElement{ + { + Name: "root", + Type: "container", + Elements: []AppDefinitionElement{ + { + Name: "middle", + Type: "container", + Elements: []AppDefinitionElement{{Name: "leaf", Type: "string", Default: "default"}}, + }, + }, + }, + }, + } + expected := AppSession{ + Model: gorm.Model{ID: 0}, + Elements: []AppSessionElement{ + { + Model: gorm.Model{ID: 0}, + Name: "root", + Type: "container", + Elements: []AppSessionElement{ + { + Model: gorm.Model{ID: 1}, + Name: "middle", + Type: "container", + Elements: []AppSessionElement{ + { + Model: gorm.Model{ID: 2}, + Name: "leaf", + Type: "string", + StringValue: sql.NullString{Valid: true, String: "default"}, + }, + }, + }, + }, + }, + { + Model: gorm.Model{ID: 1}, + Name: "middle", + Type: "container", + Elements: []AppSessionElement{ + { + Model: gorm.Model{ID: 2}, + Name: "leaf", + Type: "string", + StringValue: sql.NullString{Valid: true, String: "default"}, + }, + }, + ParentID: sql.NullString{Valid: true, String: "0"}, + }, + { + Model: gorm.Model{ID: 2}, + Name: "leaf", + Type: "string", + StringValue: sql.NullString{Valid: true, String: "default"}, + ParentID: sql.NullString{Valid: true, String: "1"}, + }, + }, + } + + actual, err := r.Create(def) + require.NoError(t, err) + assert.Equal(t, expected, *actual) + }) +} + +type addElementTestCase struct { + name string + def AppDefinition + added AppSessionElement + expected AppSessionElement +} + +var addTestCases = []addElementTestCase{ + { + name: "element added to empty session gets id 0", + def: AppDefinition{}, + added: AppSessionElement{ + Name: "text", + Type: "string", + StringValue: sql.NullString{Valid: true, String: "value"}, + }, + expected: AppSessionElement{ + Model: gorm.Model{ID: 0}, + Name: "text", + Type: "string", + StringValue: sql.NullString{Valid: true, String: "value"}, + }, + }, + { + name: "element added to non-empty session gets expected id", + def: AppDefinition{ + Elements: []AppDefinitionElement{ + {Name: "field1", Type: "string", Default: ""}, + {Name: "field2", Type: "string", Default: ""}, + {Name: "field3", Type: "string", Default: ""}, + }, + }, + added: AppSessionElement{ + Name: "field4", + Type: "string", + StringValue: sql.NullString{Valid: true, String: "value"}, + }, + expected: AppSessionElement{ + Model: gorm.Model{ID: 3}, + Name: "field4", + Type: "string", + StringValue: sql.NullString{Valid: true, String: "value"}, + }, + }, + { + name: "child element expected id", + def: AppDefinition{ + Elements: []AppDefinitionElement{ + {Name: "container", Type: "container", Elements: []AppDefinitionElement{}}, + }, + }, + added: AppSessionElement{ + Name: "child", + Type: "string", + StringValue: sql.NullString{Valid: true, String: "value"}, + ParentID: sql.NullString{Valid: true, String: "0"}, + }, + expected: AppSessionElement{ + Model: gorm.Model{ID: 1}, + Name: "child", + Type: "string", + StringValue: sql.NullString{Valid: true, String: "value"}, + ParentID: sql.NullString{Valid: true, String: "0"}, + }, + }, + { + name: "added container and child have expected ids", + def: AppDefinition{Elements: []AppDefinitionElement{}}, + added: AppSessionElement{ + Name: "container", + Type: "container", + Elements: []AppSessionElement{{ + Name: "child", + Type: "string", + StringValue: sql.NullString{Valid: true, String: "value"}, + }}, + }, + expected: AppSessionElement{ + Model: gorm.Model{ID: 0}, + Name: "container", + Type: "container", + Elements: []AppSessionElement{{ + Model: gorm.Model{ID: 1}, + Name: "child", + Type: "string", + StringValue: sql.NullString{Valid: true, String: "value"}, + ParentID: sql.NullString{Valid: true, String: "0"}, + }}, + }, + }, +} + +func TestAddElement(t *testing.T) { + for _, testcase := range addTestCases { + r := InMemoryAppSessionRepository{} + _, err := r.Create(testcase.def) + require.NoError(t, err) + + actual, err := r.AddElement(testcase.added) + + require.NoError(t, err) + assert.Equal(t, testcase.expected, *actual) + } +} diff --git a/cli/appdev/repository.go b/cli/appdev/repository.go new file mode 100644 index 00000000..1dac3f6a --- /dev/null +++ b/cli/appdev/repository.go @@ -0,0 +1,182 @@ +package appdev + +import ( + "errors" + "log/slog" + "strconv" + + "gorm.io/gorm" + "gorm.io/gorm/clause" +) + +var ErrRemoveNonExistingElement error = errors.New("cannot remove element that does not exist") + +type AppSessionRepository interface { + Create(definition AppDefinition) (*AppSession, error) + Delete(id uint) error + Read(id uint) (*AppSession, error) + UpdateElement(element AppSessionElement) error + AddElement(element AppSessionElement) (*AppSessionElement, error) + RemoveElement(element AppSessionElement) error +} + +type DBAppSessionRepository struct { + db *gorm.DB +} + +func NewDBAppSessionRepository(db *gorm.DB) *DBAppSessionRepository { + return &DBAppSessionRepository{db: db} +} + +func (r *DBAppSessionRepository) Create(def AppDefinition) (*AppSession, error) { + appSession := def.CreateSession() + if err := r.db.Create(&appSession).First(&appSession).Error; err != nil { + slog.Error(err.Error()) + return nil, errors.New("error creating app session") + } + slog.Debug("Created app session", slog.Any("app session", appSession)) + + return &appSession, nil +} + +func (r *DBAppSessionRepository) Delete(id uint) error { + if err := r.db.Delete(&AppSession{}, id).Error; err != nil { + slog.Error(err.Error()) + return err + } + + return nil +} + +func (r *DBAppSessionRepository) Read(id uint) (*AppSession, error) { + appSession := AppSession{Model: gorm.Model{ID: id}} + if err := r.db.Preload(clause.Associations).First(&appSession).Error; err != nil { + slog.Error(err.Error()) + return nil, err + } + + slog.Debug("Read app session", slog.Any("appSession", appSession)) + + return &appSession, nil +} + +func (r *DBAppSessionRepository) UpdateElement(element AppSessionElement) error { + if err := r.db.Save(&element).Error; err != nil { + slog.Error(err.Error()) + return err + } + + slog.Debug("Update app session element", slog.Any("elementID", element.ID)) + + return nil +} + +func (r *DBAppSessionRepository) AddElement(element AppSessionElement) (*AppSessionElement, error) { + panic("not implemented") +} + +func (r *DBAppSessionRepository) RemoveElement(element AppSessionElement) error { + panic("not implemented") +} + +type InMemoryAppSessionRepository struct { + session *AppSession + nextElementID uint +} + +func (r *InMemoryAppSessionRepository) getNewElementID() uint { + newID := r.nextElementID + r.nextElementID++ + + return newID +} + +func (r *InMemoryAppSessionRepository) Create(definition AppDefinition) (*AppSession, error) { + session := definition.CreateSession() + r.setSessionIDs(session.Elements) + childElements := session.GetAllChildren() + session.Elements = append(session.Elements, childElements...) + r.session = &session + + return &session, nil +} + +func (r *InMemoryAppSessionRepository) setSessionIDs(elements []AppSessionElement) { + for i := 0; i < len(elements); i++ { + e := &elements[i] + e.Model.ID = r.getNewElementID() + if e.Type == "container" { + r.setSessionIDs(e.Elements) + } + } +} + +var ErrSessionNotCreated error = errors.New("session not created yet") + +func (r *InMemoryAppSessionRepository) Delete(id uint) error { + panic("not implemented") +} + +func (r *InMemoryAppSessionRepository) Read(id uint) (*AppSession, error) { + if r.session == nil { + return nil, ErrSessionNotCreated + } else { + return r.session, nil + } +} + +func (r *InMemoryAppSessionRepository) UpdateElement(element AppSessionElement) error { + found := false + var index int + for i, v := range r.session.Elements { + if v.ID == element.ID { + index = i + found = true + } + } + + if found { + r.session.Elements[index] = element + return nil + } else { + return errors.New("tool session element does not exist") + } +} + +func (r *InMemoryAppSessionRepository) AddElement(element AppSessionElement) (*AppSessionElement, error) { + r.assignElementIds(&element) + r.session.Elements = append(r.session.Elements, element) + r.session.Elements = append(r.session.Elements, element.GetAllChildren()...) + + return &element, nil +} + +func (r *InMemoryAppSessionRepository) assignElementIds(element *AppSessionElement) { + element.Model.ID = r.getNewElementID() + for i := 0; i < len(element.Elements); i++ { + e := &element.Elements[i] + e.ParentID.Valid = true + e.ParentID.String = strconv.FormatUint(uint64(element.ID), 10) + r.assignElementIds(e) + } +} + +func (r *InMemoryAppSessionRepository) RemoveElement(element AppSessionElement) error { + newElements := make([]AppSessionElement, 0) + found := false + + for _, v := range r.session.Elements { + if v.ID == element.ID { + found = true + } else { + newElements = append(newElements, v) + } + } + + if !found { + return ErrRemoveNonExistingElement + } else { + r.session.Elements = newElements + return nil + } +} diff --git a/cli/appdev/service.go b/cli/appdev/service.go new file mode 100644 index 00000000..5c0b2e52 --- /dev/null +++ b/cli/appdev/service.go @@ -0,0 +1,293 @@ +package appdev + +import ( + "context" + "fmt" + "log/slog" + "strconv" +) + +const appSessionEventChanBufferSize = 100 + +type AppSessionEvent struct { + AppSessionID string + SourceClientID string + UpdatedElement *AppSessionElement + TriggeredActionElement *AppSessionElement + AddedElement *AppSessionElement + RemovedElement *AppSessionElement +} + +func (a *AppSessionEvent) Type() string { + if a.UpdatedElement != nil { + return "UpdatedElement" + } + + if a.TriggeredActionElement != nil { + return "TriggeredActionElement" + } + + if a.AddedElement != nil { + return "AddedElement" + } + + if a.RemovedElement != nil { + return "RemovedElement" + } + + return "Unknown" +} + +type AppSessionSubscription struct { + ID uint + Channel chan AppSessionEvent + ClientID string +} + +type AppSessionService struct { + subscriptions map[uint]AppSessionSubscription + nextSubscriptionID uint + appSessions AppSessionRepository +} + +type AppSessionElementUpdate struct { + ElementID string + StringValue *string + NumberValue *float64 + HTMLValue *string + SliderValue *float64 +} + +type AppSessionElementResult struct { + Session *AppSession + Element *AppSessionElement +} + +func NewAppSessionService(appSessions AppSessionRepository) AppSessionService { + return AppSessionService{ + appSessions: appSessions, + subscriptions: make(map[uint]AppSessionSubscription), + } +} + +// Update the identified app session with the given update and send updates to +// to all subscribers whose client IDs are different from the specified client ID. +func (s *AppSessionService) UpdateElement(appSessionID uint, clientID string, update AppSessionElementUpdate) (*AppSessionElementResult, error) { + session, err := s.appSessions.Read(appSessionID) + if err != nil { + return nil, err + } + + convertedAppSessionID := strconv.FormatUint(uint64(appSessionID), 10) + if e, err := session.GetElementByID(update.ElementID); err != nil { + slog.Debug("update element not found", slog.Any("id", update.ElementID)) + return nil, err + } else if err := s.updateElement(convertedAppSessionID, clientID, e, update); err != nil { + slog.Debug("update updating error", slog.Any("id", e.ID), slog.String("name", e.Name), slog.String("error", err.Error())) + return nil, err + } else { + slog.Debug("update element complete", slog.Any("id", e.ID), slog.String("name", e.Name)) + return &AppSessionElementResult{ + Session: session, + Element: e, + }, nil + } +} + +func (s *AppSessionService) updateElement(appSessionID string, clientID string, elem *AppSessionElement, update AppSessionElementUpdate) error { + switch elem.Type { + case "string": + if update.StringValue == nil { + return fmt.Errorf("string element %d update missing value", elem.ID) + } + elem.StringValue.String = *update.StringValue + elem.StringValue.Valid = true + case "number": + if update.NumberValue == nil { + return fmt.Errorf("number element %d update missing value", elem.ID) + } + elem.NumberValue.Float64 = *update.NumberValue + elem.NumberValue.Valid = true + case "html": + if update.HTMLValue == nil { + return fmt.Errorf("html element %d update missing value", elem.ID) + } + elem.HTMLValue.Valid = true + elem.HTMLValue.String = *update.HTMLValue + case "slider": + if update.SliderValue == nil { + return fmt.Errorf("slider element %d update missing value", elem.ID) + } + elem.SliderValue.Float64 = *update.SliderValue + elem.SliderValue.Valid = true + default: + return fmt.Errorf("updating %s element %d is unsupported", elem.Type, elem.ID) + } + + if err := s.appSessions.UpdateElement(*elem); err != nil { + return err + } + + event := AppSessionEvent{ + AppSessionID: appSessionID, + SourceClientID: clientID, + UpdatedElement: elem, + } + go s.sendEvent(clientID, event) // TODO: this is only needed for tests, fix + + return nil +} + +// Triggers the specified action in the specified app session, sending a trigger +// event to all subscribers whose client IDs are different from the specified +// client ID. +func (s *AppSessionService) TriggerAction(appSessionID uint, clientID string, actionElementID string) (*AppSessionElementResult, error) { + session, err := s.appSessions.Read(appSessionID) + if err != nil { + return nil, err + } + + convertedAppSessionID := strconv.FormatUint(uint64(appSessionID), 10) + if actionElement, err := session.GetElementByID(actionElementID); err != nil { + return nil, err + } else if actionElement.Type != "action" { + return nil, fmt.Errorf("cannot trigger action for element \"%s\" of type \"%s\"", actionElementID, actionElement.Type) + } else { + slog.Debug("triggering action", slog.Any("triggered action element", actionElementID)) + + event := AppSessionEvent{ + AppSessionID: convertedAppSessionID, + SourceClientID: clientID, + TriggeredActionElement: actionElement, + } + s.sendEvent(clientID, event) + + return &AppSessionElementResult{ + Session: session, + Element: actionElement, + }, nil + } +} + +func (s *AppSessionService) sendEvent(sourceClientID string, event AppSessionEvent) { + sent := false + + for _, s := range s.subscriptions { + if s.ClientID != sourceClientID { + slog.Info("sending event", slog.String("type", event.Type()), slog.String("sourceClientID", sourceClientID), slog.Any("subscriberClientID", s.ClientID)) + s.Channel <- event + sent = true + } + } + + if !sent { + slog.Info("no subscribers found for event", slog.String("type", event.Type()), slog.String("sourceClientID", sourceClientID)) + } +} + +// Subscribe for updates to an app session, for events not sent by the specified +// client ID. +func (s *AppSessionService) Subscribe(ctx context.Context, appSessionID string, clientID string) (chan AppSessionEvent, error) { + subscription := make(chan AppSessionEvent, appSessionEventChanBufferSize) + subID := s.nextSubscriptionID + s.nextSubscriptionID++ + s.addSubscription(clientID, subID, subscription) + + go func() { + <-ctx.Done() + s.removeSubscription(clientID, subID) + }() + + return subscription, nil +} + +func (s *AppSessionService) addSubscription(clientID string, subscriptionID uint, subscription chan AppSessionEvent) { + slog.Info("adding subscription", slog.String("clientID", clientID), slog.Uint64("subscriptionID", uint64(subscriptionID))) + s.subscriptions[subscriptionID] = AppSessionSubscription{ + ID: subscriptionID, + Channel: subscription, + ClientID: clientID, + } +} + +func (s *AppSessionService) removeSubscription(clientID string, subscriptionID uint) { + slog.Info("removing subscription", slog.String("clientID", clientID), slog.Uint64("subscriptionID", uint64(subscriptionID))) + delete(s.subscriptions, subscriptionID) +} + +// Add an element to an existing app session, sending an element added event to +// all subscribers whose client IDs are different from the specified client ID. +func (s *AppSessionService) AddElement(clientID string, element AppSessionElement) (*AppSession, error) { + slog.Debug("client adding element", slog.String("clientID", clientID), slog.Any("element", element)) + if element, err := s.appSessions.AddElement(element); err != nil { + slog.Info("error adding element", slog.Any("element", element), slog.Any("error", err)) + return nil, err + } else if session, err := s.appSessions.Read(element.AppSessionID); err != nil { + slog.Info("error adding element", slog.Any("element", element), slog.Any("error", err)) + return nil, err + } else { + event := AppSessionEvent{ + SourceClientID: clientID, + AppSessionID: strconv.FormatUint(uint64(element.AppSessionID), 10), + AddedElement: element, + } + s.sendEvent(clientID, event) // TODO: this is only needed for tests, fix + + for _, addedChild := range element.GetAllChildren() { + event := AppSessionEvent{ + SourceClientID: clientID, + AppSessionID: strconv.FormatUint(uint64(element.AppSessionID), 10), + AddedElement: &addedChild, + } + s.sendEvent(clientID, event) + } + + return session, nil + } +} + +// Remove an element from an existing app session, sending an element removed +// event to all subscribers whose client IDs are different from the specified +// client ID. +func (s *AppSessionService) RemoveElement(clientID string, element AppSessionElement) (*AppSession, error) { + slog.Debug("client removing element", slog.String("clientID", clientID), slog.Any("element", element)) + if err := s.appSessions.RemoveElement(element); err != nil { + slog.Info("error removing element", slog.Any("element", element), slog.Any("error", err)) + return nil, err + } else if session, err := s.appSessions.Read(element.AppSessionID); err != nil { + slog.Info("error removing element", slog.Any("element", element), slog.Any("error", err)) + return nil, err + } else { + event := AppSessionEvent{ + SourceClientID: clientID, + AppSessionID: strconv.FormatUint(uint64(element.AppSessionID), 10), + RemovedElement: &element, + } + go s.sendEvent(clientID, event) // TODO: consider why this is necessary + + return session, nil + } +} + +// Update an element label in an existing app session, sending an element updated +// event to all subscribers whose client IDs are different from the specified +// client ID. +func (s *AppSessionService) UpdateElementLabel(clientID string, element AppSessionElement) (*AppSession, error) { + slog.Debug("client updating element label", slog.String("clientID", clientID), slog.Any("element", element)) + if err := s.appSessions.UpdateElement(element); err != nil { + slog.Info("error updating element label", slog.Any("element", element), slog.Any("error", err)) + return nil, err + } else if session, err := s.appSessions.Read(element.AppSessionID); err != nil { + slog.Info("error updating element label", slog.Any("element", element), slog.Any("error", err)) + return nil, err + } else { + event := AppSessionEvent{ + SourceClientID: clientID, + AppSessionID: strconv.FormatUint(uint64(element.AppSessionID), 10), + UpdatedElement: &element, + } + s.sendEvent(clientID, event) // TODO: consider if this should be a Goroutine + + return session, nil + } +} diff --git a/cli/appdev/service_test.go b/cli/appdev/service_test.go new file mode 100644 index 00000000..f6d39061 --- /dev/null +++ b/cli/appdev/service_test.go @@ -0,0 +1,507 @@ +package appdev + +import ( + "context" + "database/sql" + "strconv" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "gorm.io/gorm" +) + +func convertID(id uint) string { + return strconv.FormatUint(uint64(id), 10) +} + +type AddElementTestCase struct { + name string + def AppDefinition + added AppSessionElement + expectedEvents []AppSessionEvent + expectedUpdatedSession AppSession +} + +var addElementTestCases = []AddElementTestCase{ + { + name: "add number element", + def: AppDefinition{}, + added: AppSessionElement{Name: "elem", Type: "number", NumberValue: sql.NullFloat64{Valid: true, Float64: 10.0}}, + expectedEvents: []AppSessionEvent{ + { + AppSessionID: "0", + SourceClientID: "addingClient", + AddedElement: &AppSessionElement{ + Name: "elem", + Type: "number", + NumberValue: sql.NullFloat64{Valid: true, Float64: 10.0}, + }, + }, + }, + expectedUpdatedSession: AppSession{ + Elements: []AppSessionElement{ + { + Model: gorm.Model{ID: 0}, + Name: "elem", + Type: "number", + NumberValue: sql.NullFloat64{Valid: true, Float64: 10.0}, + }, + }, + }, + }, + { + name: "add element to container", + def: AppDefinition{ + Elements: []AppDefinitionElement{ + { + Name: "container_element", + Type: "container", Elements: []AppDefinitionElement{}, + }, + }, + }, + added: AppSessionElement{ + ParentID: sql.NullString{Valid: true, String: "0"}, + Name: "added_element", + Type: "number", + NumberValue: sql.NullFloat64{Valid: true, Float64: 10.0}, + }, + expectedEvents: []AppSessionEvent{ + { + AppSessionID: "0", + SourceClientID: "addingClient", + AddedElement: &AppSessionElement{ + Model: gorm.Model{ID: 1}, + ParentID: sql.NullString{Valid: true, String: "0"}, + Name: "added_element", + Type: "number", + NumberValue: sql.NullFloat64{Valid: true, Float64: 10.0}, + }, + }, + }, + expectedUpdatedSession: AppSession{ + Elements: []AppSessionElement{ + { + Model: gorm.Model{ID: 0}, + Name: "container_element", + Type: "container", + Elements: []AppSessionElement{}, + }, + { + Model: gorm.Model{ID: 1}, + Name: "added_element", + Type: "number", + NumberValue: sql.NullFloat64{Valid: true, Float64: 10.0}, + ParentID: sql.NullString{Valid: true, String: "0"}, + }, + }, + }, + }, + { + name: "add container with child", + def: AppDefinition{Elements: []AppDefinitionElement{}}, + added: AppSessionElement{ + Name: "added_container", + Type: "container", + Elements: []AppSessionElement{ + { + Model: gorm.Model{ID: 1}, + Name: "added_child", + Type: "number", + NumberValue: sql.NullFloat64{Valid: true, Float64: 10.0}, + }, + }, + }, + expectedEvents: []AppSessionEvent{ + { + AppSessionID: "0", + SourceClientID: "addingClient", + AddedElement: &AppSessionElement{ + Model: gorm.Model{ID: 0}, + Name: "added_container", + Type: "container", + Elements: []AppSessionElement{ + { + Model: gorm.Model{ID: 1}, + Name: "added_child", + Type: "number", + NumberValue: sql.NullFloat64{Valid: true, Float64: 10.0}, + ParentID: sql.NullString{Valid: true, String: "0"}, + }, + }, + }, + }, + { + AppSessionID: "0", + SourceClientID: "addingClient", + AddedElement: &AppSessionElement{ + Model: gorm.Model{ID: 1}, + ParentID: sql.NullString{Valid: true, String: "0"}, + Name: "added_child", + Type: "number", + NumberValue: sql.NullFloat64{Valid: true, Float64: 10.0}, + }, + }, + }, + expectedUpdatedSession: AppSession{ + Elements: []AppSessionElement{ + { + Model: gorm.Model{ID: 0}, + Name: "added_container", + Type: "container", + Elements: []AppSessionElement{ + { + Model: gorm.Model{ID: 1}, + Name: "added_child", + Type: "number", + NumberValue: sql.NullFloat64{Valid: true, Float64: 10.0}, + ParentID: sql.NullString{Valid: true, String: "0"}, + }, + }, + }, + { + Model: gorm.Model{ID: 1}, + Name: "added_child", + Type: "number", + NumberValue: sql.NullFloat64{Valid: true, Float64: 10.0}, + ParentID: sql.NullString{Valid: true, String: "0"}, + }, + }, + }, + }, +} + +func TestAddElementReturnsSession(t *testing.T) { + for _, testcase := range addElementTestCases { + repo := NewMockAppSessionRepository() + service := NewAppSessionService(repo) + _, err := repo.Create(testcase.def) + assert.NoError(t, err) + + updatedSession, err := service.AddElement("addingClient", testcase.added) + assert.NoError(t, err) + + assert.Equal(t, testcase.expectedUpdatedSession, *updatedSession) + } +} + +func TestAddElementEmitsEvent(t *testing.T) { + for _, testcase := range addElementTestCases { + t.Run(testcase.name, func(t *testing.T) { + repo := NewMockAppSessionRepository() + service := NewAppSessionService(repo) + session, err := repo.Create(testcase.def) + assert.NoError(t, err) + appSessionID := strconv.FormatUint(uint64(session.ID), 10) + + ctx, cancel := context.WithCancel(context.Background()) + subscription, err := service.Subscribe(ctx, appSessionID, "subscribingClient") + assert.NoError(t, err) + time.Sleep(time.Microsecond * 100) // wait for subscription to start listening + + _, err = service.AddElement("addingClient", testcase.added) + assert.NoError(t, err) + + for _, expectedEvent := range testcase.expectedEvents { + select { + case ev := <-subscription: + println(ev.AddedElement.Name) + assert.Equal(t, expectedEvent, ev) + case <-time.After(time.Millisecond * 100): + t.Error("timed out waiting for subscription event") + } + } + cancel() + }) + } +} + +type RemoveElementReturnsSessionTestCase struct { + name string + def AppDefinition + removeElementPath []string + expectedUpdatedSession AppSession + expectedRemovedElement AppSessionElement +} + +var removeElementTestCases = []RemoveElementReturnsSessionTestCase{ + { + name: "root element", + def: AppDefinition{ + Elements: []AppDefinitionElement{ + {Name: "text_element", Type: "string", Default: "default"}, + }, + }, + removeElementPath: []string{"text_element"}, + expectedUpdatedSession: AppSession{Elements: []AppSessionElement{}}, + expectedRemovedElement: AppSessionElement{ + Model: gorm.Model{ID: 0}, + Name: "text_element", + Type: "string", + StringValue: sql.NullString{Valid: true, String: "default"}, + }, + }, + { + name: "nested element", + def: AppDefinition{ + Elements: []AppDefinitionElement{ + { + Name: "container_element", + Type: "container", + Elements: []AppDefinitionElement{ + {Name: "text_element", Type: "string", Default: "default"}, + }, + }, + }, + }, + removeElementPath: []string{"container_element", "text_element"}, + expectedUpdatedSession: AppSession{Elements: []AppSessionElement{ + { + Model: gorm.Model{ID: 0}, + Name: "container_element", + Type: "container", + Elements: []AppSessionElement{}, + }, + }}, + expectedRemovedElement: AppSessionElement{ + Model: gorm.Model{ID: 1}, + Name: "text_element", + Type: "string", + StringValue: sql.NullString{Valid: true, String: "default"}, + ParentID: sql.NullString{Valid: true, String: "0"}, + }, + }, +} + +func TestRemoveElementReturnsSession(t *testing.T) { + for _, testcase := range removeElementTestCases { + t.Run(testcase.name, func(t *testing.T) { + repo := NewMockAppSessionRepository() + service := NewAppSessionService(repo) + s, err := repo.Create(testcase.def) + assert.NoError(t, err) + toRemove, err := s.GetElementByPath(testcase.removeElementPath) + assert.NoError(t, err) + + if assert.NotNil(t, toRemove) { + updatedSession, err := service.RemoveElement("removingClient", *toRemove) + assert.NoError(t, err) + assert.Equal(t, &testcase.expectedUpdatedSession, updatedSession) + } + }) + } +} + +func TestRemoveElementEmitsEvent(t *testing.T) { + for _, testcase := range removeElementTestCases { + t.Run(testcase.name, func(t *testing.T) { + repo := NewMockAppSessionRepository() + service := NewAppSessionService(repo) + session, err := repo.Create(testcase.def) + assert.NoError(t, err) + toRemove, err := session.GetElementByPath(testcase.removeElementPath) + assert.NoError(t, err) + appSessionID := strconv.FormatUint(uint64(session.ID), 10) + + ctx, cancel := context.WithCancel(context.Background()) + subscription, err := service.Subscribe(ctx, appSessionID, "subscribingClient") + assert.NoError(t, err) + time.Sleep(time.Microsecond * 100) // wait for subscription to start listening + + if !assert.NotNil(t, toRemove) { + cancel() + return + } + + _, err = service.RemoveElement("removingClient", *toRemove) + assert.NoError(t, err) + + select { + case ev := <-subscription: + assert.Equal(t, testcase.expectedRemovedElement, *ev.RemovedElement) + cancel() + case <-time.After(time.Second): + t.Error("timed out waiting for subscription event") + cancel() + } + }) + } +} + +type TestUpdateElementTestCase struct { + name string + definition AppDefinition + elementUpdate AppSessionElementUpdate + expectedResultElement AppSessionElement + elementPath []string +} + +var ( + updateElementStringValue = "updated text" + updateElementNumberValue = 22.22 + updateElementHTMLValue = "

updated html value

" + updateElementSliderValue = 33.44 + updateElementTestCases = []TestUpdateElementTestCase{ + { + name: "string element", + definition: AppDefinition{ + Name: "App Name", + Elements: []AppDefinitionElement{ + {Name: "Text", Type: "string", Default: "default text"}, + }, + }, + elementPath: []string{"Text"}, + elementUpdate: AppSessionElementUpdate{StringValue: &updateElementStringValue}, + expectedResultElement: AppSessionElement{ + Name: "Text", + Type: "string", + StringValue: sql.NullString{Valid: true, String: updateElementStringValue}, + }, + }, + { + name: "number element", + definition: AppDefinition{ + Name: "App Name", + Elements: []AppDefinitionElement{ + {Name: "Number", Type: "number", Default: 11.11}, + }, + }, + elementPath: []string{"Number"}, + elementUpdate: AppSessionElementUpdate{NumberValue: &updateElementNumberValue}, + expectedResultElement: AppSessionElement{ + Name: "Number", + Type: "number", + NumberValue: sql.NullFloat64{Valid: true, Float64: updateElementNumberValue}, + }, + }, + { + name: "html element", + definition: AppDefinition{ + Name: "App Name", + Elements: []AppDefinitionElement{ + {Name: "Html", Type: "html", Default: "

updated html value

"}, + }, + }, + elementPath: []string{"Html"}, + elementUpdate: AppSessionElementUpdate{HTMLValue: &updateElementHTMLValue}, + expectedResultElement: AppSessionElement{ + Name: "Html", + Type: "html", + HTMLValue: sql.NullString{Valid: true, String: updateElementHTMLValue}, + }, + }, + { + name: "slider element", + definition: AppDefinition{ + Name: "App Name", + Elements: []AppDefinitionElement{ + {Name: "Slider", Type: "slider", Default: 11.22, SliderMinValue: -10.0, SliderMaxValue: 100.0}, + }, + }, + elementPath: []string{"Slider"}, + elementUpdate: AppSessionElementUpdate{SliderValue: &updateElementSliderValue}, + expectedResultElement: AppSessionElement{ + Name: "Slider", + Type: "slider", + SliderValue: sql.NullFloat64{Valid: true, Float64: updateElementSliderValue}, + SliderMinValue: sql.NullFloat64{Valid: true, Float64: -10.0}, + SliderMaxValue: sql.NullFloat64{Valid: true, Float64: 100.0}, + }, + }, + { + name: "element in container", + definition: AppDefinition{ + Name: "App Name", + Elements: []AppDefinitionElement{ + {Name: "Container", Type: "container", Elements: []AppDefinitionElement{ + {Name: "Text", Type: "string", Default: "default text"}, + }}, + }, + }, + elementPath: []string{"Container", "Text"}, + elementUpdate: AppSessionElementUpdate{StringValue: &updateElementStringValue}, + expectedResultElement: AppSessionElement{ + Name: "Text", + Type: "string", + StringValue: sql.NullString{Valid: true, String: updateElementStringValue}, + }, + }, + { + name: "element in nested container", + definition: AppDefinition{ + Name: "App Name", + Elements: []AppDefinitionElement{ + {Name: "Container1", Type: "container", Elements: []AppDefinitionElement{ + {Name: "Container2", Type: "container", Elements: []AppDefinitionElement{ + {Name: "Text", Type: "string", Default: "default text"}, + }}, + }}, + }, + }, + elementPath: []string{"Container1", "Container2", "Text"}, + elementUpdate: AppSessionElementUpdate{StringValue: &updateElementStringValue}, + expectedResultElement: AppSessionElement{ + Name: "Text", + Type: "string", + StringValue: sql.NullString{Valid: true, String: updateElementStringValue}, + }, + }, + } +) + +func TestUpdateElementReturnsResultElement(t *testing.T) { + for _, testcase := range updateElementTestCases { + t.Run(testcase.name, func(t *testing.T) { + repo := NewMockAppSessionRepository() + service := NewAppSessionService(repo) + + session, err := repo.Create(testcase.definition) + assert.NoError(t, err) + + element, err := session.GetElementByPath(testcase.elementPath) + assert.NoError(t, err) + + testcase.expectedResultElement.ID = element.ID + testcase.expectedResultElement.ParentID = element.ParentID + testcase.elementUpdate.ElementID = convertID(element.ID) + result, err := service.UpdateElement(session.ID, "updatingClient", testcase.elementUpdate) + assert.NoError(t, err) + assert.Equal(t, testcase.expectedResultElement, *result.Element) + }) + } +} + +func TestUpdateElementSendsEvent(t *testing.T) { + for _, testcase := range updateElementTestCases { + t.Run(testcase.name, func(t *testing.T) { + repo := NewMockAppSessionRepository() + service := NewAppSessionService(repo) + + session, err := repo.Create(testcase.definition) + assert.NoError(t, err) + + element, err := session.GetElementByPath(testcase.elementPath) + assert.NoError(t, err) + + ctx, cancel := context.WithCancel(context.Background()) + subscription, err := service.Subscribe(ctx, convertID(element.AppSessionID), "subscribingClient") + assert.NoError(t, err) + time.Sleep(time.Millisecond) + + testcase.expectedResultElement.ID = element.ID + testcase.expectedResultElement.ParentID = element.ParentID + testcase.elementUpdate.ElementID = convertID(element.ID) + _, err = service.UpdateElement(session.ID, "updatingClient", testcase.elementUpdate) + assert.NoError(t, err) + + select { + case ev := <-subscription: + assert.Equal(t, testcase.expectedResultElement, *ev.UpdatedElement) + cancel() + case <-time.After(time.Second): + t.Error("timed out waiting for subscription event") + cancel() + } + }) + } +} diff --git a/cli/appdev/test_repository.go b/cli/appdev/test_repository.go new file mode 100644 index 00000000..39093059 --- /dev/null +++ b/cli/appdev/test_repository.go @@ -0,0 +1,136 @@ +package appdev + +import ( + "errors" + "fmt" + "strconv" +) + +type MockAppSessionRepository struct { + toolSessions map[uint]AppSession + toolSessionElements map[uint]*AppSessionElement + nextToolSessionID uint + nextElementID uint +} + +func NewMockAppSessionRepository() *MockAppSessionRepository { + return &MockAppSessionRepository{ + toolSessions: make(map[uint]AppSession), + toolSessionElements: make(map[uint]*AppSessionElement), + } +} + +func (r *MockAppSessionRepository) Create(def AppDefinition) (*AppSession, error) { + toolSession := def.CreateSession() + toolSession.Model.ID = r.nextToolSessionID + r.addElementIDs(toolSession.Elements) + toolSession.Elements = append(toolSession.Elements, toolSession.GetAllChildren()...) + r.toolSessions[r.nextToolSessionID] = toolSession + r.nextToolSessionID++ + + return &toolSession, nil +} + +func (r *MockAppSessionRepository) addElementIDs(elements []AppSessionElement) { + for i := 0; i < len(elements); i++ { + element := &elements[i] + r.assignElementID(element) + r.toolSessionElements[element.ID] = element + r.addElementIDs(element.Elements) + } +} + +func (r *MockAppSessionRepository) Delete(id uint) error { + delete(r.toolSessions, id) + return nil +} + +func (r *MockAppSessionRepository) Read(id uint) (*AppSession, error) { + if toolSession, ok := r.toolSessions[id]; ok { + return &toolSession, nil + } else { + return nil, errors.New("tool session does not exist") + } +} + +func (r *MockAppSessionRepository) UpdateElement(element AppSessionElement) error { + if elementReference, ok := r.toolSessionElements[element.ID]; ok { + *elementReference = element + return nil + } else { + return errors.New("tool session element does not exist") + } +} + +func (r *MockAppSessionRepository) AddElement(element AppSessionElement) (*AppSessionElement, error) { + if session, ok := r.toolSessions[element.AppSessionID]; !ok { + return nil, fmt.Errorf("cannot add element to tool session %d that does not exist", element.AppSessionID) + } else { + r.assignElementID(&element) + session.Elements = append(session.Elements, element) + session.Elements = append(session.Elements, r.addChildElements(&element)...) + r.toolSessions[session.ID] = session + + return &element, nil + } +} + +func (r *MockAppSessionRepository) assignElementID(element *AppSessionElement) { + element.Model.ID = r.nextElementID + r.nextElementID++ +} + +func (r *MockAppSessionRepository) addChildElements(parent *AppSessionElement) []AppSessionElement { + added := []AppSessionElement{} + + for i := 0; i < len(parent.Elements); i++ { + e := &parent.Elements[i] + e.ParentID.Valid = true + e.ParentID.String = strconv.FormatUint(uint64(parent.ID), 10) + r.assignElementID(e) + added = append(added, *e) + if e.Type == "container" { + added = append(added, r.addChildElements(e)...) + } + } + + return added +} + +func (r *MockAppSessionRepository) RemoveElement(element AppSessionElement) error { + if session, ok := r.toolSessions[element.AppSessionID]; !ok { + return fmt.Errorf("cannot remove element from tool session %d that does not exist", element.AppSessionID) + } else { + newElements, found := removeElement(element, session.Elements) + + if !found { + return ErrRemoveNonExistingElement + } else { + session.Elements = newElements + r.toolSessions[session.ID] = session + + return nil + } + } +} + +func removeElement(removed AppSessionElement, elements []AppSessionElement) ([]AppSessionElement, bool) { + newElements := make([]AppSessionElement, 0) + found := false + + for _, v := range elements { + childNewElements, childFound := removeElement(removed, v.Elements) + v.Elements = childNewElements + if childFound { + found = true + } + + if v.ID == removed.ID { + found = true + } else { + newElements = append(newElements, v) + } + } + + return newElements, found +} diff --git a/cli/appdevsession/apprunner.go b/cli/appdevsession/apprunner.go new file mode 100644 index 00000000..c36bd588 --- /dev/null +++ b/cli/appdevsession/apprunner.go @@ -0,0 +1,175 @@ +package appdevsession + +import ( + "bufio" + "fmt" + "io" + "log/slog" + "os" + "strconv" + + "numerous/cli/appdev" +) + +type appRunner struct { + executor commandExecutor + appSessions appdev.AppSessionRepository + appSessionService appdev.AppSessionService + port string + pythonInterpeterPath string + appModulePath string + appClassName string + exit chan struct{} + output appdev.Output + cmd command +} + +// Runs the app, reading the definition from the app file, killing app process +// if it exists, updating the session (if it exists) with the new definition, +// and launching a python process running the app. +func (r *appRunner) Run() { + defer r.output.AwaitingAppChanges() + + if r.cmd != nil { + if err := r.cmd.Kill(); err != nil { + slog.Info("error killing python app process", slog.String("error", err.Error())) + } + } + + appdef := r.readApp() + if appdef == nil { + r.cmd = nil + return + } + + session, err := r.updateExistingSession(appdef) + if err != nil { + if session, err = r.appSessions.Create(*appdef); err != nil { + r.output.ErrorCreatingAppSession(err) + r.signalExit() + r.cmd = nil + + return + } + slog.Debug("created session", slog.String("name", session.Name), slog.Any("id", session.ID), slog.Int("elements", len(session.Elements))) + } + + r.cmd = r.runApp(*session) +} + +func (r *appRunner) readApp() *appdev.AppDefinition { + cmd := r.executor.Create(r.pythonInterpeterPath, "-m", "numerous", "read", r.appModulePath, r.appClassName) + output, err := cmd.Output() + if err != nil { + slog.Debug("Error reading app definition", slog.String("error", err.Error())) + r.output.ErrorReadingApp(string(output), err) + + return nil + } + + result, err := appdev.ParseAppDefinition(output) + if err != nil { + slog.Warn("Error parsing app definition", slog.String("error", err.Error())) + r.output.ErrorParsingApp(err) + + return nil + } + + if result.App != nil { + slog.Debug("Read app definition", slog.String("name", result.App.Name)) + return result.App + } else if result.Error != nil { + r.output.ErrorLoadingApp(result.Error) + } + + return nil +} + +func (r *appRunner) updateExistingSession(def *appdev.AppDefinition) (*appdev.AppSession, error) { + existingSession, err := r.appSessions.Read(0) + if err != nil { + return nil, err + } + + diff := appdev.GetAppSessionDifference(*existingSession, *def) + slog.Debug("got app session difference", slog.Int("added", len(diff.Added)), slog.Int("removed", len(diff.Removed))) + for _, added := range diff.Added { + if addedSession, err := r.appSessionService.AddElement("server", added); err == nil { + slog.Debug("added element", slog.Any("elementID", added.ID), slog.String("name", added.Name)) + existingSession = addedSession + } else { + slog.Debug("error adding element after update", slog.String("error", err.Error())) + r.output.ErrorUpdateAddingElement() + } + } + + for _, removed := range diff.Removed { + slog.Debug("handling removed element", slog.Any("element", removed)) + if removedSession, err := r.appSessionService.RemoveElement("server", removed); err == nil { + existingSession = removedSession + } else { + slog.Info("error removing element after update", slog.String("error", err.Error())) + r.output.ErrorUpdateRemovingElement() + } + } + + for _, updated := range diff.Updated { + slog.Debug("handling updated element", slog.Any("element", updated)) + if updatedSession, err := r.appSessionService.UpdateElementLabel("server", updated); err == nil { + existingSession = updatedSession + } else { + slog.Info("error updating element after update", slog.String("error", err.Error())) + r.output.ErrorUpdateUpdatingElement() + } + } + + return existingSession, nil +} + +func (r *appRunner) runApp(session appdev.AppSession) command { + cmd := r.executor.Create( + r.pythonInterpeterPath, + "-m", + "numerous", + "run", + "--graphql-url", + fmt.Sprintf("http://localhost:%s/query", r.port), + "--graphql-ws-url", + fmt.Sprintf("ws://localhost:%s/query", r.port), + r.appModulePath, + r.appClassName, + strconv.FormatUint(uint64(session.ID), 10), + ) + cmd.SetEnv("PYTHONUNBUFFERED", "1") + cmd.SetEnv("PATH", os.Getenv("PATH")) + r.wrapAppOutput(cmd.StdoutPipe, "stdout") + r.wrapAppOutput(cmd.StderrPipe, "stderr") + + if err := cmd.Start(); err != nil { + slog.Debug("could not start app", slog.String("error", err.Error())) + r.output.ErrorStartingApp(err) + + return nil + } + r.output.StartedApp() + + return cmd +} + +func (r *appRunner) wrapAppOutput(pipeFunc func() (io.ReadCloser, error), streamName string) { + if reader, err := pipeFunc(); err != nil { + r.output.ErrorGettingAppOutputStream(streamName) + } else { + scanner := bufio.NewScanner(reader) + go func() { + scanner.Split(bufio.ScanLines) + for scanner.Scan() { + r.output.PrintAppLogLine(scanner.Text()) + } + }() + } +} + +func (r *appRunner) signalExit() { + r.exit <- struct{}{} +} diff --git a/cli/appdevsession/command.go b/cli/appdevsession/command.go new file mode 100644 index 00000000..5daa68cf --- /dev/null +++ b/cli/appdevsession/command.go @@ -0,0 +1,66 @@ +package appdevsession + +import ( + "fmt" + "io" + "log/slog" + "os/exec" +) + +type commandExecutor interface { + // Create a command that runs the named command, with the provided arguments. + Create(name string, args ...string) command +} + +type command interface { + // Kill the command + Kill() error + // Start the command + Start() error + // Set an environment variable for the command + SetEnv(string, string) + // Returns a reader for the commands standard output. + StdoutPipe() (io.ReadCloser, error) + // Returns a reader for the commands standard error. + StderrPipe() (io.ReadCloser, error) + // Runs the command, and returns its combined output (both standard output and standard error). + Output() ([]byte, error) +} + +type execCommandExecutor struct{} + +func (e *execCommandExecutor) Create(name string, args ...string) command { + slog.Debug("creating command", slog.String("name", name), slog.Any("args", args)) + cmd := &execCommand{cmd: *exec.Command(name, args...)} + + return cmd +} + +type execCommand struct { + cmd exec.Cmd +} + +func (e *execCommand) Start() error { + slog.Debug("starting command", slog.String("path", e.cmd.Path), slog.Any("args", e.cmd.Args)) + return e.cmd.Start() +} + +func (e *execCommand) Kill() error { + return e.cmd.Process.Kill() +} + +func (e *execCommand) SetEnv(key string, value string) { + e.cmd.Env = append(e.cmd.Env, fmt.Sprintf("%s=%s", key, value)) +} + +func (e *execCommand) StdoutPipe() (io.ReadCloser, error) { + return e.cmd.StdoutPipe() +} + +func (e *execCommand) StderrPipe() (io.ReadCloser, error) { + return e.cmd.StderrPipe() +} + +func (e *execCommand) Output() ([]byte, error) { + return e.cmd.CombinedOutput() +} diff --git a/cli/appdevsession/filewatch.go b/cli/appdevsession/filewatch.go new file mode 100644 index 00000000..9b4789c7 --- /dev/null +++ b/cli/appdevsession/filewatch.go @@ -0,0 +1,115 @@ +package appdevsession + +import ( + "log/slog" + "time" + + "github.com/fsnotify/fsnotify" +) + +type clock interface { + Now() time.Time + Since(time.Time) time.Duration +} + +type timeclock struct{} + +func (c *timeclock) Now() time.Time { + return time.Now() +} + +func (c *timeclock) Since(t time.Time) time.Duration { + return time.Since(t) +} + +type fileWatcherFactory interface { + // Create a FileWatcher + Create() (FileWatcher, error) +} + +type FSNotifyFileWatcherFactory struct{} + +func (f *FSNotifyFileWatcherFactory) Create() (FileWatcher, error) { + if watcher, err := fsnotify.NewBufferedWatcher(1); err != nil { + return nil, err + } else { + return &FSNotifyWatcher{watcher: watcher}, nil + } +} + +type FileWatcher interface { + // Close the file watcher + Close() error + // Add a file to the file watcher + Add(name string) error + // Get a channel of file events noticed by the FileWatcher + GetEvents() chan fsnotify.Event + // Get a channel of errors for the FileWatcher + GetErrors() chan error +} + +type FSNotifyWatcher struct { + watcher *fsnotify.Watcher +} + +func (w *FSNotifyWatcher) Close() error { + return w.watcher.Close() +} + +func (w *FSNotifyWatcher) Add(name string) error { + return w.watcher.Add(name) +} + +func (w *FSNotifyWatcher) GetEvents() chan fsnotify.Event { + return w.watcher.Events +} + +func (w *FSNotifyWatcher) GetErrors() chan error { + return w.watcher.Errors +} + +// Watch the given path for file changes, returning a channel to which is sent +// the file names of updated files. +// +// Updates happening within minInterval time of the last update are ignored. +func WatchAppChanges(path string, watcherFactory fileWatcherFactory, clock clock, minInterval time.Duration) (chan string, error) { + updates := make(chan string) + + watcher, err := watcherFactory.Create() + if err != nil { + return nil, err + } + + err = watcher.Add(path) + if err != nil { + watcher.Close() + return nil, err + } + + go func() { + defer close(updates) + defer watcher.Close() + lastUpdate := clock.Now() + for { + select { + case event, ok := <-watcher.GetEvents(): + if !ok { + return + } + elapsed := clock.Since(lastUpdate) + + if event.Has(fsnotify.Write) && elapsed > minInterval { + lastUpdate = clock.Now() + updates <- event.Name + } + case err, ok := <-watcher.GetErrors(): + if !ok { + return + } + slog.Warn("error watching app code", slog.Any("error", err)) + } + } + }() + + return updates, nil +} diff --git a/cli/appdevsession/filewatch_test.go b/cli/appdevsession/filewatch_test.go new file mode 100644 index 00000000..e5c87ca9 --- /dev/null +++ b/cli/appdevsession/filewatch_test.go @@ -0,0 +1,33 @@ +package appdevsession + +import ( + "os" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestWatchToolChanges(t *testing.T) { + t.Run("sends message on file write", func(t *testing.T) { + dir := t.TempDir() + filepath := dir + "/file.txt" + + err := os.WriteFile(filepath, []byte("content before update\n"), 0o700) + require.NoError(t, err) + + changes, err := WatchAppChanges(filepath, &FSNotifyFileWatcherFactory{}, &timeclock{}, time.Second*0) + require.NoError(t, err) + + //nolint:errcheck + go os.WriteFile(filepath, []byte("content after update 5\n"), 0o700) + + select { + case changedFile := <-changes: + assert.Equal(t, filepath, changedFile) + case <-time.After(time.Second * 4): + assert.FailNow(t, "timed out waiting for file update") + } + }) +} diff --git a/cli/appdevsession/session.go b/cli/appdevsession/session.go new file mode 100644 index 00000000..add27caa --- /dev/null +++ b/cli/appdevsession/session.go @@ -0,0 +1,141 @@ +package appdevsession + +import ( + "log/slog" + "net/http" + "os" + "os/signal" + "syscall" + "time" + + "numerous/cli/appdev" + "numerous/cli/assets" + "numerous/cli/server" +) + +type devSession struct { + executor commandExecutor + fileWatcherFactory fileWatcherFactory + clock clock + appSessions appdev.AppSessionRepository + appSessionService appdev.AppSessionService + port string + pythonInterpeterPath string + appModulePath string + appClassName string + exit chan struct{} + server *http.Server + minUpdateInterval time.Duration + output appdev.Output +} + +func CreateAndRunDevSession(pythonInterpreterPath string, modulePath string, className string, port string) { + appSessions := appdev.InMemoryAppSessionRepository{} + output := appdev.NewLipglossOutput(modulePath, className) + session := devSession{ + executor: &execCommandExecutor{}, + fileWatcherFactory: &FSNotifyFileWatcherFactory{}, + clock: &timeclock{}, + appSessions: &appSessions, + appSessionService: appdev.NewAppSessionService(&appSessions), + port: port, + pythonInterpeterPath: pythonInterpreterPath, + appModulePath: modulePath, + appClassName: className, + exit: make(chan struct{}, 1), + minUpdateInterval: time.Second, + output: &output, + } + session.run() +} + +func (d *devSession) run() { + slog.Debug("running session", slog.Any("session", d)) + d.output.StartingApp(d.port) + go d.startServer() + d.setupSystemSignal() + if err := d.validateAppExists(); err != nil { + d.output.AppModuleNotFound(err) + os.Exit(1) + } + + appChanges, err := WatchAppChanges(d.appModulePath, d.fileWatcherFactory, d.clock, d.minUpdateInterval) + if err != nil { + d.output.ErrorWatchingAppFiles(err) + os.Exit(1) + } + + go d.handleAppChanges(appChanges) + + d.awaitExit() +} + +func (d *devSession) handleAppChanges(appChanges chan string) { + run := appRunner{ + executor: d.executor, + appSessions: d.appSessions, + appSessionService: d.appSessionService, + port: d.port, + pythonInterpeterPath: d.pythonInterpeterPath, + appModulePath: d.appModulePath, + appClassName: d.appClassName, + exit: d.exit, + output: d.output, + } + run.Run() + + for { + if _, ok := <-appChanges; !ok { + break + } + + d.output.FileUpdatedRestartingApp() + run.Run() + } +} + +func (d *devSession) signalExit() { + d.exit <- struct{}{} +} + +func (d *devSession) startServer() { + if d.server != nil { + panic("can only run server once per session") + } + registers := []server.HandlerRegister{assets.SPAMRegister} + d.server = server.CreateServer(server.ServerOptions{ + HTTPPort: d.port, + AppSessions: d.appSessions, + AppSessionService: d.appSessionService, + Registers: registers, + GQLPath: "/query", + PlaygroundPath: "/playground", + }) + + d.server.ListenAndServe() //nolint:errcheck +} + +func (d *devSession) validateAppExists() error { + _, err := os.Stat(d.appModulePath) + return err +} + +func (d *devSession) setupSystemSignal() { + systemExitSignal := make(chan os.Signal, 1) + go func() { + signal.Notify(systemExitSignal, syscall.SIGINT, syscall.SIGTERM) + <-systemExitSignal + d.signalExit() + }() +} + +func (d *devSession) awaitExit() { + <-d.exit + d.output.Stopping() + if d.server != nil { + if err := d.server.Close(); err != nil { + slog.Debug("error closing server", slog.String("error", err.Error())) + } + d.server = nil + } +} diff --git a/cli/appdevsession/session_test.go b/cli/appdevsession/session_test.go new file mode 100644 index 00000000..933cd792 --- /dev/null +++ b/cli/appdevsession/session_test.go @@ -0,0 +1,259 @@ +package appdevsession + +import ( + "bytes" + "database/sql" + "io" + "os" + "testing" + "time" + + "numerous/cli/appdev" + + "github.com/fsnotify/fsnotify" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" + "gorm.io/gorm" +) + +type mockCommandExecutor struct{ mock.Mock } + +func (e *mockCommandExecutor) Create(name string, args ...string) command { + var callArgs []interface{} + callArgs = append(callArgs, name) + for _, a := range args { + callArgs = append(callArgs, a) + } + + mockArgs := e.Called(callArgs...) + + return mockArgs.Get(0).(command) +} + +type mockCommand struct { + mock.Mock + name string +} + +func (e *mockCommand) Kill() error { + args := e.Called() + return args.Error(0) +} + +func (e *mockCommand) Start() error { + args := e.Called() + return args.Error(0) +} + +func (e *mockCommand) SetEnv(key string, value string) { + e.Called() +} + +func (e *mockCommand) StdoutPipe() (io.ReadCloser, error) { + args := e.Called() + return args.Get(0).(io.ReadCloser), args.Error(1) +} + +func (e *mockCommand) StderrPipe() (io.ReadCloser, error) { + args := e.Called() + return args.Get(0).(io.ReadCloser), args.Error(1) +} + +func (e *mockCommand) Output() ([]byte, error) { + args := e.Called() + return args.Get(0).([]byte), args.Error(1) +} + +type MockFileWatcherFactory struct{ mock.Mock } + +func (f *MockFileWatcherFactory) Create() (FileWatcher, error) { + args := f.Called() + return args.Get(0).(FileWatcher), args.Error(1) +} + +type mockFileWatcher struct{ mock.Mock } + +func (w *mockFileWatcher) Close() error { + args := w.Called() + return args.Error(0) +} + +func (w *mockFileWatcher) Add(name string) error { + args := w.Called(name) + return args.Error(0) +} + +func (w *mockFileWatcher) GetEvents() chan fsnotify.Event { + args := w.Called() + return args.Get(0).(chan fsnotify.Event) +} + +func (w *mockFileWatcher) GetErrors() chan error { + args := w.Called() + return args.Get(0).(chan error) +} + +type mockClock struct{ mock.Mock } + +func (c *mockClock) Now() time.Time { + args := c.Called() + return args.Get(0).(time.Time) +} + +func (c *mockClock) Since(t time.Time) time.Duration { + args := c.Called(t) + return args.Get(0).(time.Duration) +} + +func TestRunDevSession(t *testing.T) { + t.Run("calls expected commands", func(t *testing.T) { + appFile, err := os.CreateTemp("", "*-app.py") + require.NoError(t, err) + appFileName := appFile.Name() + appClassName := "App" + + readCmd := mockCommand{} + runCmd := mockCommand{} + executor := mockCommandExecutor{} + sessions := appdev.NewMockAppSessionRepository() + fileWatcher := &mockFileWatcher{} + fileWatcher.On("Add", mock.Anything).Return(nil) + fileWatcher.On("Close").Return(nil) + fileWatcher.On("GetEvents").Return(make(chan fsnotify.Event), nil) + fileWatcher.On("GetErrors").Return(make(chan error), nil) + + fileWatcherFactory := &MockFileWatcherFactory{} + fileWatcherFactory.On("Create").Return(fileWatcher, nil) + session := devSession{ + executor: &executor, + fileWatcherFactory: fileWatcherFactory, + clock: &timeclock{}, + appSessions: sessions, + appSessionService: appdev.NewAppSessionService(sessions), + port: "7001", + appModulePath: appFile.Name(), + appClassName: "App", + pythonInterpeterPath: "python", + exit: make(chan struct{}), + output: &appdev.FmtOutput{}, + } + + output := `{"app": {"title": "app", "elements": [{"name": "text", "type": "string", "label": "Text", "default": "default"}]}}` + readCmd.On("Output").Return([]byte(output), nil) + runCmd.On("SetEnv", mock.Anything).Return() + runCmd.On("StdoutPipe", mock.Anything).Return(io.NopCloser(bytes.NewBuffer(nil)), nil) + runCmd.On("StderrPipe", mock.Anything).Return(io.NopCloser(bytes.NewBuffer(nil)), nil) + runCmd.On("Start").Return(nil) + executor.On("Create", "python", "-m", "numerous", "read", appFileName, appClassName).Return(&readCmd, nil) + executor.On("Create", "python", "-m", "numerous", "run", "--graphql-url", "http://localhost:7001/query", "--graphql-ws-url", "ws://localhost:7001/query", appFileName, appClassName, "0").Return(&runCmd, nil).Run(func(args mock.Arguments) { + session.signalExit() + }) + + session.run() + + executor.AssertExpectations(t) + readCmd.AssertExpectations(t) + runCmd.AssertExpectations(t) + }) + + t.Run("updates session and restarts app when file is updated", func(t *testing.T) { + appFile, err := os.CreateTemp("", "*-app.py") + require.NoError(t, err) + appFileName := appFile.Name() + appClassName := "App" + fileEvents := make(chan fsnotify.Event) + + initialReadCmd := mockCommand{name: "initial read"} + initialRunCmd := mockCommand{name: "initial run"} + updateReadCmd := mockCommand{name: "updated read"} + updateRunCmd := mockCommand{name: "updated run"} + executor := mockCommandExecutor{} + sessions := appdev.NewMockAppSessionRepository() + fileWatcher := &mockFileWatcher{} + fileWatcher.On("Add", mock.Anything).Return(nil) + fileWatcher.On("Close").Return(nil) + fileWatcher.On("GetEvents").Return(fileEvents, nil) + fileWatcher.On("GetErrors").Return(make(chan error), nil) + mockClock := mockClock{} + + fileWatcherFactory := &MockFileWatcherFactory{} + fileWatcherFactory.On("Create").Return(fileWatcher, nil) + session := devSession{ + executor: &executor, + fileWatcherFactory: fileWatcherFactory, + clock: &mockClock, + appSessions: sessions, + appSessionService: appdev.NewAppSessionService(sessions), + port: "7001", + appModulePath: appFile.Name(), + appClassName: "App", + pythonInterpeterPath: "python", + exit: make(chan struct{}), + minUpdateInterval: time.Second, + output: &appdev.FmtOutput{}, + } + + initialDef := ` + { + "app": { + "title": "app", + "elements": [{"name": "text", "type": "string", "label": "Text", "default": "default"}] + } + }` + initialReadCmd.On("Output").Return([]byte(initialDef), nil) + initialRunCmd.On("SetEnv", mock.Anything).Return() + initialRunCmd.On("StdoutPipe", mock.Anything).Return(io.NopCloser(bytes.NewBuffer(nil)), nil) + initialRunCmd.On("StderrPipe", mock.Anything).Return(io.NopCloser(bytes.NewBuffer(nil)), nil) + initialRunCmd.On("Start").Return(nil) + initialRunCmd.On("Kill").Return(nil) + + updatedDef := ` + { + "app": { + "title": "app", + "elements": [{"name": "number", "type": "number", "label": "Number", "default": 12.34}] + } + }` + updateReadCmd.On("Output").Return([]byte(updatedDef), nil) + updateRunCmd.On("SetEnv", mock.Anything).Return() + updateRunCmd.On("StdoutPipe", mock.Anything).Return(io.NopCloser(bytes.NewBuffer(nil)), nil) + updateRunCmd.On("StderrPipe", mock.Anything).Return(io.NopCloser(bytes.NewBuffer(nil)), nil) + updateRunCmd.On("Start").Return(nil) + + mockClock.On("Now", mock.Anything).Return(time.Time{}) + mockClock.On("Since", mock.Anything).Return(2 * session.minUpdateInterval) + + executor.On("Create", "python", "-m", "numerous", "read", appFileName, appClassName).Return(&initialReadCmd, nil).Once() + executor.On("Create", "python", "-m", "numerous", "read", appFileName, appClassName).Return(&updateReadCmd, nil).Once() + executor.On("Create", "python", "-m", "numerous", "run", "--graphql-url", "http://localhost:7001/query", "--graphql-ws-url", "ws://localhost:7001/query", appFileName, appClassName, "0"). + Return(&initialRunCmd, nil). + Once(). + Run(func(args mock.Arguments) { + println("Creating a run command first time!") + fileEvents <- fsnotify.Event{Name: appFileName, Op: fsnotify.Write} + }) + executor.On("Create", "python", "-m", "numerous", "run", "--graphql-url", "http://localhost:7001/query", "--graphql-ws-url", "ws://localhost:7001/query", appFileName, appClassName, "0"). + Return(&updateRunCmd, nil). + Once(). + Run(func(args mock.Arguments) { + println("Creating a run command second time!") + session.signalExit() + }) + + session.run() + close(fileEvents) + + expectedElements := []appdev.AppSessionElement{ + {Model: gorm.Model{ID: 1}, Name: "number", Label: "Number", Type: "number", NumberValue: sql.NullFloat64{Valid: true, Float64: 12.34}, Elements: []appdev.AppSessionElement{}}, + } + if appSession, err := sessions.Read(0); assert.NoError(t, err) { + assert.Equal(t, expectedElements, appSession.Elements) + } + executor.AssertExpectations(t) + initialReadCmd.AssertExpectations(t) + initialRunCmd.AssertExpectations(t) + updateReadCmd.AssertExpectations(t) + updateRunCmd.AssertExpectations(t) + }) +} diff --git a/cli/assets/assets.go b/cli/assets/assets.go new file mode 100644 index 00000000..d70094a9 --- /dev/null +++ b/cli/assets/assets.go @@ -0,0 +1,65 @@ +package assets + +import ( + "embed" + "io" + "io/fs" + "log" + "log/slog" + "net/http" + "os" +) + +//nolint:typecheck +//go:embed spa/** +var spaFS embed.FS + +//go:embed spa/index.html +var spaIndex []byte + +type IndexHandler struct{} + +func (i *IndexHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + w.Header().Add("Content-Type", "text/html") + w.WriteHeader(http.StatusOK) + if _, err := w.Write(spaIndex); err != nil { + slog.Info("error serving SPA index", slog.Any("error", err)) + } +} + +func SPAMRegister(mux *http.ServeMux) { + subFS, subErr := fs.Sub(spaFS, "spa") + if subErr != nil { + log.Fatalf("Could create sub filesystem: %s", subFS) + } + + httpFs := http.FS(subFS) + fileServer := http.FileServer(httpFs) + mux.Handle("/assets/", fileServer) + mux.Handle("/vite.svg", fileServer) + mux.Handle("/", &IndexHandler{}) +} + +//go:embed images/placeholder_tool_cover.png +var image embed.FS + +func CopyToolPlaceholderCover(destPath string) error { + srcFile, err := image.Open("images/placeholder_tool_cover.png") + if err != nil { + return err + } + defer srcFile.Close() + + destFile, err := os.Create(destPath) + if err != nil { + return err + } + defer destFile.Close() + + _, err = io.Copy(destFile, srcFile) + if err != nil { + return err + } + + return nil +} diff --git a/cli/assets/images/placeholder_tool_cover.png b/cli/assets/images/placeholder_tool_cover.png new file mode 100644 index 00000000..d86fbc92 Binary files /dev/null and b/cli/assets/images/placeholder_tool_cover.png differ diff --git a/cli/assets/spa/assets/em-fave-jwADWkv5.ico b/cli/assets/spa/assets/em-fave-jwADWkv5.ico new file mode 100644 index 00000000..c3d95ef7 Binary files /dev/null and b/cli/assets/spa/assets/em-fave-jwADWkv5.ico differ diff --git a/cli/assets/spa/assets/index-Bd3b9qkg.js b/cli/assets/spa/assets/index-Bd3b9qkg.js new file mode 100644 index 00000000..dbc7fdf4 --- /dev/null +++ b/cli/assets/spa/assets/index-Bd3b9qkg.js @@ -0,0 +1,797 @@ +var A8=Object.defineProperty;var F8=(e,t,n)=>t in e?A8(e,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):e[t]=n;var j8=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var Qr=(e,t,n)=>(F8(e,typeof t!="symbol"?t+"":t,n),n);var fpe=j8((Mpe,rb)=>{(function(){try{var e=typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{},t=new Error().stack;t&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[t]="e437091c-7d43-4b33-8525-217c7b1a7269",e._sentryDebugIdIdentifier="sentry-dbid-e437091c-7d43-4b33-8525-217c7b1a7269")}catch{}})();function B3(e,t){for(var n=0;nr[o]})}}}return Object.freeze(Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}))}var L8=typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};L8.SENTRY_RELEASE={id:"1461dfc03e902fb267f0ccaad4cb3c1357d692ca"};(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const o of document.querySelectorAll('link[rel="modulepreload"]'))r(o);new MutationObserver(o=>{for(const i of o)if(i.type==="childList")for(const s of i.addedNodes)s.tagName==="LINK"&&s.rel==="modulepreload"&&r(s)}).observe(document,{childList:!0,subtree:!0});function n(o){const i={};return o.integrity&&(i.integrity=o.integrity),o.referrerPolicy&&(i.referrerPolicy=o.referrerPolicy),o.crossOrigin==="use-credentials"?i.credentials="include":o.crossOrigin==="anonymous"?i.credentials="omit":i.credentials="same-origin",i}function r(o){if(o.ep)return;o.ep=!0;const i=n(o);fetch(o.href,i)}})();var Nd=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};function kl(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var H3={exports:{}},Tp={},U3={exports:{}},ye={};/** + * @license React + * react.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var Gu=Symbol.for("react.element"),V8=Symbol.for("react.portal"),z8=Symbol.for("react.fragment"),B8=Symbol.for("react.strict_mode"),H8=Symbol.for("react.profiler"),U8=Symbol.for("react.provider"),W8=Symbol.for("react.context"),G8=Symbol.for("react.forward_ref"),q8=Symbol.for("react.suspense"),K8=Symbol.for("react.memo"),Y8=Symbol.for("react.lazy"),Ox=Symbol.iterator;function Q8(e){return e===null||typeof e!="object"?null:(e=Ox&&e[Ox]||e["@@iterator"],typeof e=="function"?e:null)}var W3={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},G3=Object.assign,q3={};function Tl(e,t,n){this.props=e,this.context=t,this.refs=q3,this.updater=n||W3}Tl.prototype.isReactComponent={};Tl.prototype.setState=function(e,t){if(typeof e!="object"&&typeof e!="function"&&e!=null)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")};Tl.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")};function K3(){}K3.prototype=Tl.prototype;function ob(e,t,n){this.props=e,this.context=t,this.refs=q3,this.updater=n||W3}var ib=ob.prototype=new K3;ib.constructor=ob;G3(ib,Tl.prototype);ib.isPureReactComponent=!0;var Nx=Array.isArray,Y3=Object.prototype.hasOwnProperty,sb={current:null},Q3={key:!0,ref:!0,__self:!0,__source:!0};function X3(e,t,n){var r,o={},i=null,s=null;if(t!=null)for(r in t.ref!==void 0&&(s=t.ref),t.key!==void 0&&(i=""+t.key),t)Y3.call(t,r)&&!Q3.hasOwnProperty(r)&&(o[r]=t[r]);var a=arguments.length-2;if(a===1)o.children=n;else if(1d9(e,r,n))}function f9(e,t,n=250,r,o,i,s){if(!i.exception||!i.exception.values||!s||!vo(s.originalException,Error))return;const a=i.exception.values.length>0?i.exception.values[i.exception.values.length-1]:void 0;a&&(i.exception.values=h9(vy(e,t,o,s.originalException,r,i.exception.values,a,0),n))}function vy(e,t,n,r,o,i,s,a){if(i.length>=n+1)return i;let l=[...i];if(vo(r[o],Error)){Fx(s,a);const c=e(t,r[o]),u=l.length;jx(c,o,u,a),l=vy(e,t,n,r[o],o,[c,...l],c,u)}return Array.isArray(r.errors)&&r.errors.forEach((c,u)=>{if(vo(c,Error)){Fx(s,a);const d=e(t,c),f=l.length;jx(d,`errors[${u}]`,f,a),l=vy(e,t,n,c,o,[d,...l],d,f)}}),l}function Fx(e,t){e.mechanism=e.mechanism||{type:"generic",handled:!0},e.mechanism={...e.mechanism,...e.type==="AggregateError"&&{is_exception_group:!0},exception_id:t}}function jx(e,t,n,r){e.mechanism=e.mechanism||{type:"generic",handled:!0},e.mechanism={...e.mechanism,type:"chained",source:t,exception_id:n,parent_id:r}}function h9(e,t){return e.map(n=>(n.value&&(n.value=Da(n.value,t)),n))}function Dd(e){return e&&e.Math==Math?e:void 0}const we=typeof globalThis=="object"&&Dd(globalThis)||typeof window=="object"&&Dd(window)||typeof self=="object"&&Dd(self)||typeof global=="object"&&Dd(global)||function(){return this}()||{};function fb(){return we}function rT(e,t,n){const r=n||we,o=r.__SENTRY__=r.__SENTRY__||{};return o[e]||(o[e]=t())}const Aa=fb(),p9=80;function bi(e,t={}){if(!e)return"";try{let n=e;const r=5,o=[];let i=0,s=0;const a=" > ",l=a.length;let c;const u=Array.isArray(t)?t:t.keyAttrs,d=!Array.isArray(t)&&t.maxStringLength||p9;for(;n&&i++1&&s+o.length*l+c.length>=d));)o.push(c),s+=c.length,n=n.parentNode;return o.reverse().join(a)}catch{return""}}function m9(e,t){const n=e,r=[];let o,i,s,a,l;if(!n||!n.tagName)return"";if(Aa.HTMLElement&&n instanceof HTMLElement&&n.dataset&&n.dataset.sentryComponent)return n.dataset.sentryComponent;r.push(n.tagName.toLowerCase());const c=t&&t.length?t.filter(d=>n.getAttribute(d)).map(d=>[d,n.getAttribute(d)]):null;if(c&&c.length)c.forEach(d=>{r.push(`[${d[0]}="${d[1]}"]`)});else if(n.id&&r.push(`#${n.id}`),o=n.className,o&&Vr(o))for(i=o.split(/\s+/),l=0;l"u"||__SENTRY_DEBUG__,v9="Sentry Logger ",yy=["debug","info","warn","error","log","assert","trace"],gh={};function vs(e){if(!("console"in we))return e();const t=we.console,n={},r=Object.keys(gh);r.forEach(o=>{const i=gh[o];n[o]=t[o],t[o]=i});try{return e()}finally{r.forEach(o=>{t[o]=n[o]})}}function y9(){let e=!1;const t={enable:()=>{e=!0},disable:()=>{e=!1},isEnabled:()=>e};return $l?yy.forEach(n=>{t[n]=(...r)=>{e&&vs(()=>{we.console[n](`${v9}[${n}]:`,...r)})}}):yy.forEach(n=>{t[n]=()=>{}}),t}const j=y9(),b9=/^(?:(\w+):)\/\/(?:(\w+)(?::(\w+)?)?@)([\w.-]+)(?::(\d+))?\/(.+)/;function w9(e){return e==="http"||e==="https"}function Pl(e,t=!1){const{host:n,path:r,pass:o,port:i,projectId:s,protocol:a,publicKey:l}=e;return`${a}://${l}${t&&o?`:${o}`:""}@${n}${i?`:${i}`:""}/${r&&`${r}/`}${s}`}function S9(e){const t=b9.exec(e);if(!t){vs(()=>{console.error(`Invalid Sentry Dsn: ${e}`)});return}const[n,r,o="",i,s="",a]=t.slice(1);let l="",c=a;const u=c.split("/");if(u.length>1&&(l=u.slice(0,-1).join("/"),c=u.pop()),c){const d=c.match(/^\d+/);d&&(c=d[0])}return sT({host:i,pass:o,path:l,projectId:c,port:s,protocol:n,publicKey:r})}function sT(e){return{protocol:e.protocol,publicKey:e.publicKey||"",pass:e.pass||"",host:e.host,port:e.port||"",path:e.path||"",projectId:e.projectId}}function x9(e){if(!$l)return!0;const{port:t,projectId:n,protocol:r}=e;return["protocol","publicKey","host","projectId"].find(s=>e[s]?!1:(j.error(`Invalid Sentry Dsn: ${s} missing`),!0))?!1:n.match(/^\d+$/)?w9(r)?t&&isNaN(parseInt(t,10))?(j.error(`Invalid Sentry Dsn: Invalid port ${t}`),!1):!0:(j.error(`Invalid Sentry Dsn: Invalid protocol ${r}`),!1):(j.error(`Invalid Sentry Dsn: Invalid projectId ${n}`),!1)}function aT(e){const t=typeof e=="string"?S9(e):sT(e);if(!(!t||!x9(t)))return t}class Ar extends Error{constructor(t,n="warn"){super(t),this.message=t,this.name=new.target.prototype.constructor.name,Object.setPrototypeOf(this,new.target.prototype),this.logLevel=n}}function Et(e,t,n){if(!(t in e))return;const r=e[t],o=n(r);typeof o=="function"&&lT(o,r),e[t]=o}function ys(e,t,n){try{Object.defineProperty(e,t,{value:n,writable:!0,configurable:!0})}catch{$l&&j.log(`Failed to add non-enumerable property "${t}" to object`,e)}}function lT(e,t){try{const n=t.prototype||{};e.prototype=t.prototype=n,ys(e,"__sentry_original__",t)}catch{}}function hb(e){return e.__sentry_original__}function _9(e){return Object.keys(e).map(t=>`${encodeURIComponent(t)}=${encodeURIComponent(e[t])}`).join("&")}function cT(e){if(lb(e))return{message:e.message,name:e.name,stack:e.stack,...Vx(e)};if(Rp(e)){const t={type:e.type,target:Lx(e.target),currentTarget:Lx(e.currentTarget),...Vx(e)};return typeof CustomEvent<"u"&&vo(e,CustomEvent)&&(t.detail=e.detail),t}else return e}function Lx(e){try{return l9(e)?bi(e):Object.prototype.toString.call(e)}catch{return""}}function Vx(e){if(typeof e=="object"&&e!==null){const t={};for(const n in e)Object.prototype.hasOwnProperty.call(e,n)&&(t[n]=e[n]);return t}else return{}}function E9(e,t=40){const n=Object.keys(cT(e));if(n.sort(),!n.length)return"[object has no keys]";if(n[0].length>=t)return Da(n[0],t);for(let r=n.length;r>0;r--){const o=n.slice(0,r).join(", ");if(!(o.length>t))return r===n.length?o:Da(o,t)}return""}function Zt(e){return by(e,new Map)}function by(e,t){if(C9(e)){const n=t.get(e);if(n!==void 0)return n;const r={};t.set(e,r);for(const o of Object.keys(e))typeof e[o]<"u"&&(r[o]=by(e[o],t));return r}if(Array.isArray(e)){const n=t.get(e);if(n!==void 0)return n;const r=[];return t.set(e,r),e.forEach(o=>{r.push(by(o,t))}),r}return e}function C9(e){if(!Ja(e))return!1;try{const t=Object.getPrototypeOf(e).constructor.name;return!t||t==="Object"}catch{return!0}}const uT=50,zx=/\(error: (.*)\)/,Bx=/captureMessage|captureException/;function dT(...e){const t=e.sort((n,r)=>n[0]-r[0]).map(n=>n[1]);return(n,r=0)=>{const o=[],i=n.split(` +`);for(let s=r;s1024)continue;const l=zx.test(a)?a.replace(zx,"$1"):a;if(!l.match(/\S*Error: /)){for(const c of t){const u=c(l);if(u){o.push(u);break}}if(o.length>=uT)break}}return T9(o)}}function k9(e){return Array.isArray(e)?dT(...e):e}function T9(e){if(!e.length)return[];const t=Array.from(e);return/sentryWrapped/.test(t[t.length-1].function||"")&&t.pop(),t.reverse(),Bx.test(t[t.length-1].function||"")&&(t.pop(),Bx.test(t[t.length-1].function||"")&&t.pop()),t.slice(0,uT).map(n=>({...n,filename:n.filename||t[t.length-1].filename,function:n.function||"?"}))}const yg="";function yo(e){try{return!e||typeof e!="function"?yg:e.name||yg}catch{return yg}}const jf={},Hx={};function $s(e,t){jf[e]=jf[e]||[],jf[e].push(t)}function Ps(e,t){Hx[e]||(t(),Hx[e]=!0)}function fr(e,t){const n=e&&jf[e];if(n)for(const r of n)try{r(t)}catch(o){$l&&j.error(`Error while triggering instrumentation handler. +Type: ${e} +Name: ${yo(r)} +Error:`,o)}}function R9(e){const t="console";$s(t,e),Ps(t,I9)}function I9(){"console"in we&&yy.forEach(function(e){e in we.console&&Et(we.console,e,function(t){return gh[e]=t,function(...n){fr("console",{args:n,level:e});const o=gh[e];o&&o.apply(we.console,n)}})})}function ot(){const e=we,t=e.crypto||e.msCrypto;let n=()=>Math.random()*16;try{if(t&&t.randomUUID)return t.randomUUID().replace(/-/g,"");t&&t.getRandomValues&&(n=()=>{const r=new Uint8Array(1);return t.getRandomValues(r),r[0]})}catch{}return("10000000100040008000"+1e11).replace(/[018]/g,r=>(r^(n()&15)>>r/4).toString(16))}function fT(e){return e.exception&&e.exception.values?e.exception.values[0]:void 0}function Zo(e){const{message:t,event_id:n}=e;if(t)return t;const r=fT(e);return r?r.type&&r.value?`${r.type}: ${r.value}`:r.type||r.value||n||"":n||""}function wy(e,t,n){const r=e.exception=e.exception||{},o=r.values=r.values||[],i=o[0]=o[0]||{};i.value||(i.value=t||""),i.type||(i.type=n||"Error")}function iu(e,t){const n=fT(e);if(!n)return;const r={type:"generic",handled:!0},o=n.mechanism;if(n.mechanism={...r,...o,...t},t&&"data"in t){const i={...o&&o.data,...t.data};n.mechanism.data=i}}function Ux(e){if(e&&e.__sentry_captured__)return!0;try{ys(e,"__sentry_captured__",!0)}catch{}return!1}function hT(e){return Array.isArray(e)?e:[e]}const ta=we,$9=1e3;let Wx,Sy,xy;function pT(e){const t="dom";$s(t,e),Ps(t,P9)}function P9(){if(!ta.document)return;const e=fr.bind(null,"dom"),t=Gx(e,!0);ta.document.addEventListener("click",t,!1),ta.document.addEventListener("keypress",t,!1),["EventTarget","Node"].forEach(n=>{const r=ta[n]&&ta[n].prototype;!r||!r.hasOwnProperty||!r.hasOwnProperty("addEventListener")||(Et(r,"addEventListener",function(o){return function(i,s,a){if(i==="click"||i=="keypress")try{const l=this,c=l.__sentry_instrumentation_handlers__=l.__sentry_instrumentation_handlers__||{},u=c[i]=c[i]||{refCount:0};if(!u.handler){const d=Gx(e);u.handler=d,o.call(this,i,d,a)}u.refCount++}catch{}return o.call(this,i,s,a)}}),Et(r,"removeEventListener",function(o){return function(i,s,a){if(i==="click"||i=="keypress")try{const l=this,c=l.__sentry_instrumentation_handlers__||{},u=c[i];u&&(u.refCount--,u.refCount<=0&&(o.call(this,i,u.handler,a),u.handler=void 0,delete c[i]),Object.keys(c).length===0&&delete l.__sentry_instrumentation_handlers__)}catch{}return o.call(this,i,s,a)}}))})}function O9(e){if(e.type!==Sy)return!1;try{if(!e.target||e.target._sentryId!==xy)return!1}catch{}return!0}function N9(e,t){return e!=="keypress"?!1:!t||!t.tagName?!0:!(t.tagName==="INPUT"||t.tagName==="TEXTAREA"||t.isContentEditable)}function Gx(e,t=!1){return n=>{if(!n||n._sentryCaptured)return;const r=M9(n);if(N9(n.type,r))return;ys(n,"_sentryCaptured",!0),r&&!r._sentryId&&ys(r,"_sentryId",ot());const o=n.type==="keypress"?"input":n.type;O9(n)||(e({event:n,name:o,global:t}),Sy=n.type,xy=r?r._sentryId:void 0),clearTimeout(Wx),Wx=ta.setTimeout(()=>{xy=void 0,Sy=void 0},$9)}}function M9(e){try{return e.target}catch{return null}}const _y=fb();function mT(){if(!("fetch"in _y))return!1;try{return new Headers,new Request("http://www.example.com"),new Response,!0}catch{return!1}}function Ey(e){return e&&/^function fetch\(\)\s+\{\s+\[native code\]\s+\}$/.test(e.toString())}function D9(){if(typeof EdgeRuntime=="string")return!0;if(!mT())return!1;if(Ey(_y.fetch))return!0;let e=!1;const t=_y.document;if(t&&typeof t.createElement=="function")try{const n=t.createElement("iframe");n.hidden=!0,t.head.appendChild(n),n.contentWindow&&n.contentWindow.fetch&&(e=Ey(n.contentWindow.fetch)),t.head.removeChild(n)}catch(n){$l&&j.warn("Could not create sandbox iframe for pure fetch check, bailing to window.fetch: ",n)}return e}function pb(e){const t="fetch";$s(t,e),Ps(t,A9)}function A9(){D9()&&Et(we,"fetch",function(e){return function(...t){const{method:n,url:r}=F9(t),o={args:t,fetchData:{method:n,url:r},startTimestamp:Date.now()};return fr("fetch",{...o}),e.apply(we,t).then(i=>{const s={...o,endTimestamp:Date.now(),response:i};return fr("fetch",s),i},i=>{const s={...o,endTimestamp:Date.now(),error:i};throw fr("fetch",s),i})}})}function Cy(e,t){return!!e&&typeof e=="object"&&!!e[t]}function qx(e){return typeof e=="string"?e:e?Cy(e,"url")?e.url:e.toString?e.toString():"":""}function F9(e){if(e.length===0)return{method:"GET",url:""};if(e.length===2){const[n,r]=e;return{url:qx(n),method:Cy(r,"method")?String(r.method).toUpperCase():"GET"}}const t=e[0];return{url:qx(t),method:Cy(t,"method")?String(t.method).toUpperCase():"GET"}}let Ad=null;function gT(e){const t="error";$s(t,e),Ps(t,j9)}function j9(){Ad=we.onerror,we.onerror=function(e,t,n,r,o){return fr("error",{column:r,error:o,line:n,msg:e,url:t}),Ad&&!Ad.__SENTRY_LOADER__?Ad.apply(this,arguments):!1},we.onerror.__SENTRY_INSTRUMENTED__=!0}let Fd=null;function vT(e){const t="unhandledrejection";$s(t,e),Ps(t,L9)}function L9(){Fd=we.onunhandledrejection,we.onunhandledrejection=function(e){return fr("unhandledrejection",e),Fd&&!Fd.__SENTRY_LOADER__?Fd.apply(this,arguments):!0},we.onunhandledrejection.__SENTRY_INSTRUMENTED__=!0}const jd=fb();function V9(){const e=jd.chrome,t=e&&e.app&&e.app.runtime,n="history"in jd&&!!jd.history.pushState&&!!jd.history.replaceState;return!t&&n}const Zl=we;let Ld;function $p(e){const t="history";$s(t,e),Ps(t,z9)}function z9(){if(!V9())return;const e=Zl.onpopstate;Zl.onpopstate=function(...n){const r=Zl.location.href,o=Ld;if(Ld=r,fr("history",{from:o,to:r}),e)try{return e.apply(this,n)}catch{}};function t(n){return function(...r){const o=r.length>2?r[2]:void 0;if(o){const i=Ld,s=String(o);Ld=s,fr("history",{from:i,to:s})}return n.apply(this,r)}}Et(Zl.history,"pushState",t),Et(Zl.history,"replaceState",t)}const B9=we,ti="__sentry_xhr_v3__";function mb(e){const t="xhr";$s(t,e),Ps(t,H9)}function H9(){if(!B9.XMLHttpRequest)return;const e=XMLHttpRequest.prototype;Et(e,"open",function(t){return function(...n){const r=Date.now(),o=Vr(n[0])?n[0].toUpperCase():void 0,i=U9(n[1]);if(!o||!i)return t.apply(this,n);this[ti]={method:o,url:i,request_headers:{}},o==="POST"&&i.match(/sentry_key/)&&(this.__sentry_own_request__=!0);const s=()=>{const a=this[ti];if(a&&this.readyState===4){try{a.status_code=this.status}catch{}const l={args:[o,i],endTimestamp:Date.now(),startTimestamp:r,xhr:this};fr("xhr",l)}};return"onreadystatechange"in this&&typeof this.onreadystatechange=="function"?Et(this,"onreadystatechange",function(a){return function(...l){return s(),a.apply(this,l)}}):this.addEventListener("readystatechange",s),Et(this,"setRequestHeader",function(a){return function(...l){const[c,u]=l,d=this[ti];return d&&Vr(c)&&Vr(u)&&(d.request_headers[c.toLowerCase()]=u),a.apply(this,l)}}),t.apply(this,n)}}),Et(e,"send",function(t){return function(...n){const r=this[ti];if(!r)return t.apply(this,n);n[0]!==void 0&&(r.body=n[0]);const o={args:[r.method,r.url],startTimestamp:Date.now(),xhr:this};return fr("xhr",o),t.apply(this,n)}})}function U9(e){if(Vr(e))return e;try{return e.toString()}catch{}}function W9(){return typeof __SENTRY_BROWSER_BUNDLE__<"u"&&!!__SENTRY_BROWSER_BUNDLE__}function G9(){return"npm"}function q9(){return!W9()&&Object.prototype.toString.call(typeof process<"u"?process:0)==="[object process]"}function ky(){return typeof window<"u"&&(!q9()||K9())}function K9(){return we.process!==void 0&&we.process.type==="renderer"}function Y9(){const e=typeof WeakSet=="function",t=e?new WeakSet:[];function n(o){if(e)return t.has(o)?!0:(t.add(o),!1);for(let i=0;in?yT(e,t-1,n):r}function Ty(e,t,n=1/0,r=1/0,o=Y9()){const[i,s]=o;if(t==null||["number","boolean","string"].includes(typeof t)&&!tT(t))return t;const a=Q9(e,t);if(!a.startsWith("[object "))return a;if(t.__sentry_skip_normalization__)return t;const l=typeof t.__sentry_override_normalization_depth__=="number"?t.__sentry_override_normalization_depth__:n;if(l===0)return a.replace("object ","");if(i(t))return"[Circular ~]";const c=t;if(c&&typeof c.toJSON=="function")try{const h=c.toJSON();return Ty("",h,l-1,r,o)}catch{}const u=Array.isArray(t)?[]:{};let d=0;const f=cT(t);for(const h in f){if(!Object.prototype.hasOwnProperty.call(f,h))continue;if(d>=r){u[h]="[MaxProperties ~]";break}const m=f[h];u[h]=Ty(h,m,l-1,r,o),d++}return s(t),u}function Q9(e,t){try{if(e==="domain"&&t&&typeof t=="object"&&t._events)return"[Domain]";if(e==="domainEmitter")return"[DomainEmitter]";if(typeof global<"u"&&t===global)return"[Global]";if(typeof window<"u"&&t===window)return"[Window]";if(typeof document<"u"&&t===document)return"[Document]";if(nT(t))return"[VueViewModel]";if(u9(t))return"[SyntheticEvent]";if(typeof t=="number"&&t!==t)return"[NaN]";if(typeof t=="function")return`[Function: ${yo(t)}]`;if(typeof t=="symbol")return`[${String(t)}]`;if(typeof t=="bigint")return`[BigInt: ${String(t)}]`;const n=X9(t);return/^HTML(\w*)Element$/.test(n)?`[HTMLElement: ${n}]`:`[object ${n}]`}catch(n){return`**non-serializable** (${n})`}}function X9(e){const t=Object.getPrototypeOf(e);return t?t.constructor.name:"null prototype"}function Z9(e){return~-encodeURI(e).split(/%..|./).length}function J9(e){return Z9(JSON.stringify(e))}var to;(function(e){e[e.PENDING=0]="PENDING";const n=1;e[e.RESOLVED=n]="RESOLVED";const r=2;e[e.REJECTED=r]="REJECTED"})(to||(to={}));function el(e){return new wn(t=>{t(e)})}function gb(e){return new wn((t,n)=>{n(e)})}class wn{constructor(t){wn.prototype.__init.call(this),wn.prototype.__init2.call(this),wn.prototype.__init3.call(this),wn.prototype.__init4.call(this),this._state=to.PENDING,this._handlers=[];try{t(this._resolve,this._reject)}catch(n){this._reject(n)}}then(t,n){return new wn((r,o)=>{this._handlers.push([!1,i=>{if(!t)r(i);else try{r(t(i))}catch(s){o(s)}},i=>{if(!n)o(i);else try{r(n(i))}catch(s){o(s)}}]),this._executeHandlers()})}catch(t){return this.then(n=>n,t)}finally(t){return new wn((n,r)=>{let o,i;return this.then(s=>{i=!1,o=s,t&&t()},s=>{i=!0,o=s,t&&t()}).then(()=>{if(i){r(o);return}n(o)})})}__init(){this._resolve=t=>{this._setResult(to.RESOLVED,t)}}__init2(){this._reject=t=>{this._setResult(to.REJECTED,t)}}__init3(){this._setResult=(t,n)=>{if(this._state===to.PENDING){if(Ip(n)){n.then(this._resolve,this._reject);return}this._state=t,this._value=n,this._executeHandlers()}}}__init4(){this._executeHandlers=()=>{if(this._state===to.PENDING)return;const t=this._handlers.slice();this._handlers=[],t.forEach(n=>{n[0]||(this._state===to.RESOLVED&&n[1](this._value),this._state===to.REJECTED&&n[2](this._value),n[0]=!0)})}}}function eM(e){const t=[];function n(){return e===void 0||t.lengthr(a)).then(null,()=>r(a).then(null,()=>{})),a}function i(s){return new wn((a,l)=>{let c=t.length;if(!c)return a(!0);const u=setTimeout(()=>{s&&s>0&&a(!1)},s);t.forEach(d=>{el(d).then(()=>{--c||(clearTimeout(u),a(!0))},l)})})}return{$:t,add:o,drain:i}}function Lf(e){if(!e)return{};const t=e.match(/^(([^:/?#]+):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/);if(!t)return{};const n=t[6]||"",r=t[8]||"";return{host:t[4],path:t[5],protocol:t[2],search:n,hash:r,relative:t[5]+n+r}}const tM=["fatal","error","warning","log","info","debug"];function nM(e){return e==="warn"?"warning":tM.includes(e)?e:"log"}const bT=1e3;function qu(){return Date.now()/bT}function rM(){const{performance:e}=we;if(!e||!e.now)return qu;const t=Date.now()-e.now(),n=e.timeOrigin==null?t:e.timeOrigin;return()=>(n+e.now())/bT}const Ku=rM(),kn=(()=>{const{performance:e}=we;if(!e||!e.now)return;const t=3600*1e3,n=e.now(),r=Date.now(),o=e.timeOrigin?Math.abs(e.timeOrigin+n-r):t,i=o{const i=Kx(o);for(const s of Object.keys(i))r[s]=i[s];return r},{});else{if(!e)return;t=Kx(e)}const n=Object.entries(t).reduce((r,[o,i])=>{if(o.match(oM)){const s=o.slice(wT.length);r[s]=i}return r},{});if(Object.keys(n).length>0)return n}function ST(e){if(!e)return;const t=Object.entries(e).reduce((n,[r,o])=>(o&&(n[`${wT}${r}`]=o),n),{});return aM(t)}function Kx(e){return e.split(",").map(t=>t.split("=").map(n=>decodeURIComponent(n.trim()))).reduce((t,[n,r])=>(t[n]=r,t),{})}function aM(e){if(Object.keys(e).length!==0)return Object.entries(e).reduce((t,[n,r],o)=>{const i=`${encodeURIComponent(n)}=${encodeURIComponent(r)}`,s=o===0?i:`${t},${i}`;return s.length>iM?($l&&j.warn(`Not adding key: ${n} with val: ${r} to baggage header due to exceeding baggage size limits.`),t):s},"")}const lM=new RegExp("^[ \\t]*([0-9a-f]{32})?-?([0-9a-f]{16})?-?([01])?[ \\t]*$");function cM(e){if(!e)return;const t=e.match(lM);if(!t)return;let n;return t[3]==="1"?n=!0:t[3]==="0"&&(n=!1),{traceId:t[1],parentSampled:n,parentSpanId:t[2]}}function uM(e,t){const n=cM(e),r=sM(t),{traceId:o,parentSpanId:i,parentSampled:s}=n||{};return n?{traceId:o||ot(),parentSpanId:i||ot().substring(16),spanId:ot().substring(16),sampled:s,dsc:r||{}}:{traceId:o||ot(),spanId:ot().substring(16)}}function vb(e=ot(),t=ot().substring(16),n){let r="";return n!==void 0&&(r=n?"-1":"-0"),`${e}-${t}${r}`}function Ai(e,t=[]){return[e,t]}function dM(e,t){const[n,r]=e;return[n,[...r,t]]}function Yx(e,t){const n=e[1];for(const r of n){const o=r[0].type;if(t(r,o))return!0}return!1}function Iy(e,t){return(t||new TextEncoder).encode(e)}function fM(e,t){const[n,r]=e;let o=JSON.stringify(n);function i(s){typeof o=="string"?o=typeof s=="string"?o+s:[Iy(o,t),s]:o.push(typeof s=="string"?Iy(s,t):s)}for(const s of r){const[a,l]=s;if(i(` +${JSON.stringify(a)} +`),typeof l=="string"||l instanceof Uint8Array)i(l);else{let c;try{c=JSON.stringify(l)}catch{c=JSON.stringify(Or(l))}i(c)}}return typeof o=="string"?o:hM(o)}function hM(e){const t=e.reduce((o,i)=>o+i.length,0),n=new Uint8Array(t);let r=0;for(const o of e)n.set(o,r),r+=o.length;return n}function pM(e,t){const n=typeof e.data=="string"?Iy(e.data,t):e.data;return[Zt({type:"attachment",length:n.length,filename:e.filename,content_type:e.contentType,attachment_type:e.attachmentType}),n]}const mM={session:"session",sessions:"session",attachment:"attachment",transaction:"transaction",event:"error",client_report:"internal",user_report:"default",profile:"profile",replay_event:"replay",replay_recording:"replay",check_in:"monitor",feedback:"feedback",span:"span",statsd:"unknown"};function Qx(e){return mM[e]}function yb(e){if(!e||!e.sdk)return;const{name:t,version:n}=e.sdk;return{name:t,version:n}}function xT(e,t,n,r){const o=e.sdkProcessingMetadata&&e.sdkProcessingMetadata.dynamicSamplingContext;return{event_id:e.event_id,sent_at:new Date().toISOString(),...t&&{sdk:t},...!!n&&r&&{dsn:Pl(r)},...o&&{trace:Zt({...o})}}}function gM(e,t,n){const r=[{type:"client_report"},{timestamp:n||qu(),discarded_events:e}];return Ai(t?{dsn:t}:{},[r])}const vM=60*1e3;function yM(e,t=Date.now()){const n=parseInt(`${e}`,10);if(!isNaN(n))return n*1e3;const r=Date.parse(`${e}`);return isNaN(r)?vM:r-t}function bM(e,t){return e[t]||e.all||0}function _T(e,t,n=Date.now()){return bM(e,t)>n}function ET(e,{statusCode:t,headers:n},r=Date.now()){const o={...e},i=n&&n["x-sentry-rate-limits"],s=n&&n["retry-after"];if(i)for(const a of i.trim().split(",")){const[l,c]=a.split(":",2),u=parseInt(l,10),d=(isNaN(u)?60:u)*1e3;if(!c)o.all=r+d;else for(const f of c.split(";"))o[f]=r+d}else s?o.all=r+yM(s,r):t===429&&(o.all=r+60*1e3);return o}function wM(e,t){return e??t()}function bg(e){let t,n=e[0],r=1;for(;rn.call(t,...s)),t=void 0)}return n}const J=typeof __SENTRY_DEBUG__>"u"||__SENTRY_DEBUG__,Pp="production";function bb(){return rT("globalEventProcessors",()=>[])}function SM(e){bb().push(e)}function vh(e,t,n,r=0){return new wn((o,i)=>{const s=e[r];if(t===null||typeof s!="function")o(t);else{const a=s({...t},n);J&&s.id&&a===null&&j.log(`Event processor "${s.id}" dropped event`),Ip(a)?a.then(l=>vh(e,l,n,r+1).then(o)).then(null,i):vh(e,a,n,r+1).then(o).then(null,i)}})}function CT(e){const t=Ku(),n={sid:ot(),init:!0,timestamp:t,started:t,duration:0,status:"ok",errors:0,ignoreDuration:!1,toJSON:()=>xM(n)};return e&&bs(n,e),n}function bs(e,t={}){if(t.user&&(!e.ipAddress&&t.user.ip_address&&(e.ipAddress=t.user.ip_address),!e.did&&!t.did&&(e.did=t.user.id||t.user.email||t.user.username)),e.timestamp=t.timestamp||Ku(),t.abnormal_mechanism&&(e.abnormal_mechanism=t.abnormal_mechanism),t.ignoreDuration&&(e.ignoreDuration=t.ignoreDuration),t.sid&&(e.sid=t.sid.length===32?t.sid:ot()),t.init!==void 0&&(e.init=t.init),!e.did&&t.did&&(e.did=`${t.did}`),typeof t.started=="number"&&(e.started=t.started),e.ignoreDuration)e.duration=void 0;else if(typeof t.duration=="number")e.duration=t.duration;else{const n=e.timestamp-e.started;e.duration=n>=0?n:0}t.release&&(e.release=t.release),t.environment&&(e.environment=t.environment),!e.ipAddress&&t.ipAddress&&(e.ipAddress=t.ipAddress),!e.userAgent&&t.userAgent&&(e.userAgent=t.userAgent),typeof t.errors=="number"&&(e.errors=t.errors),t.status&&(e.status=t.status)}function kT(e,t){let n={};t?n={status:t}:e.status==="ok"&&(n={status:"exited"}),bs(e,n)}function xM(e){return Zt({sid:`${e.sid}`,init:e.init,started:new Date(e.started*1e3).toISOString(),timestamp:new Date(e.timestamp*1e3).toISOString(),status:e.status,errors:e.errors,did:typeof e.did=="number"||typeof e.did=="string"?`${e.did}`:void 0,duration:e.duration,abnormal_mechanism:e.abnormal_mechanism,attrs:{release:e.release,environment:e.environment,ip_address:e.ipAddress,user_agent:e.userAgent}})}const _M=0,TT=1;function wb(e){const{spanId:t,traceId:n}=e.spanContext(),{data:r,op:o,parent_span_id:i,status:s,tags:a,origin:l}=pt(e);return Zt({data:r,op:o,parent_span_id:i,span_id:t,status:s,tags:a,trace_id:n,origin:l})}function Op(e){const{traceId:t,spanId:n}=e.spanContext(),r=Sb(e);return vb(t,n,r)}function Np(e){return typeof e=="number"?Xx(e):Array.isArray(e)?e[0]+e[1]/1e9:e instanceof Date?Xx(e.getTime()):Ku()}function Xx(e){return e>9999999999?e/1e3:e}function pt(e){return EM(e)?e.getSpanJSON():typeof e.toJSON=="function"?e.toJSON():{}}function EM(e){return typeof e.getSpanJSON=="function"}function Sb(e){const{traceFlags:t}=e.spanContext();return!!(t&TT)}function xb(e,t,n,r,o,i){const{normalizeDepth:s=3,normalizeMaxBreadth:a=1e3}=e,l={...t,event_id:t.event_id||n.event_id||ot(),timestamp:t.timestamp||qu()},c=n.integrations||e.integrations.map(S=>S.name);CM(l,e),RM(l,c),t.type===void 0&&kM(l,e.stackParser);const u=$M(r,n.captureContext);n.mechanism&&iu(l,n.mechanism);const d=o&&o.getEventProcessors?o.getEventProcessors():[],f=HM().getScopeData();if(i){const S=i.getScopeData();t_(f,S)}if(u){const S=u.getScopeData();t_(f,S)}const h=[...n.attachments||[],...f.attachments];h.length&&(n.attachments=h),PT(l,f);const m=[...d,...bb(),...f.eventProcessors];return vh(m,l,n).then(S=>(S&&TM(S),typeof s=="number"&&s>0?IM(S,s,a):S))}function CM(e,t){const{environment:n,release:r,dist:o,maxValueLength:i=250}=t;"environment"in e||(e.environment="environment"in t?n:Pp),e.release===void 0&&r!==void 0&&(e.release=r),e.dist===void 0&&o!==void 0&&(e.dist=o),e.message&&(e.message=Da(e.message,i));const s=e.exception&&e.exception.values&&e.exception.values[0];s&&s.value&&(s.value=Da(s.value,i));const a=e.request;a&&a.url&&(a.url=Da(a.url,i))}const Zx=new WeakMap;function kM(e,t){const n=we._sentryDebugIds;if(!n)return;let r;const o=Zx.get(t);o?r=o:(r=new Map,Zx.set(t,r));const i=Object.keys(n).reduce((s,a)=>{let l;const c=r.get(a);c?l=c:(l=t(a),r.set(a,l));for(let u=l.length-1;u>=0;u--){const d=l[u];if(d.filename){s[d.filename]=n[a];break}}return s},{});try{e.exception.values.forEach(s=>{s.stacktrace.frames.forEach(a=>{a.filename&&(a.debug_id=i[a.filename])})})}catch{}}function TM(e){const t={};try{e.exception.values.forEach(r=>{r.stacktrace.frames.forEach(o=>{o.debug_id&&(o.abs_path?t[o.abs_path]=o.debug_id:o.filename&&(t[o.filename]=o.debug_id),delete o.debug_id)})})}catch{}if(Object.keys(t).length===0)return;e.debug_meta=e.debug_meta||{},e.debug_meta.images=e.debug_meta.images||[];const n=e.debug_meta.images;Object.keys(t).forEach(r=>{n.push({type:"sourcemap",code_file:r,debug_id:t[r]})})}function RM(e,t){t.length>0&&(e.sdk=e.sdk||{},e.sdk.integrations=[...e.sdk.integrations||[],...t])}function IM(e,t,n){if(!e)return null;const r={...e,...e.breadcrumbs&&{breadcrumbs:e.breadcrumbs.map(o=>({...o,...o.data&&{data:Or(o.data,t,n)}}))},...e.user&&{user:Or(e.user,t,n)},...e.contexts&&{contexts:Or(e.contexts,t,n)},...e.extra&&{extra:Or(e.extra,t,n)}};return e.contexts&&e.contexts.trace&&r.contexts&&(r.contexts.trace=e.contexts.trace,e.contexts.trace.data&&(r.contexts.trace.data=Or(e.contexts.trace.data,t,n))),e.spans&&(r.spans=e.spans.map(o=>{const i=pt(o).data;return i&&(o.data=Or(i,t,n)),o})),r}function $M(e,t){if(!t)return e;const n=e?e.clone():new fo;return n.update(t),n}function PM(e){if(e)return OM(e)?{captureContext:e}:MM(e)?{captureContext:e}:e}function OM(e){return e instanceof fo||typeof e=="function"}const NM=["user","level","extra","contexts","tags","fingerprint","requestSession","propagationContext"];function MM(e){return Object.keys(e).some(t=>NM.includes(t))}function Ol(e,t){return Mt().captureException(e,PM(t))}function RT(e,t){return Mt().captureEvent(e,t)}function wi(e,t){Mt().addBreadcrumb(e,t)}function DM(e,t){Mt().setContext(e,t)}function AM(e){Mt().setUser(e)}function _b(...e){const t=Mt();if(e.length===2){const[n,r]=e;return n?t.withScope(()=>(t.getStackTop().scope=n,r(n))):t.withScope(r)}return t.withScope(e[0])}function ke(){return Mt().getClient()}function pn(){return Mt().getScope()}function Jx(e){const t=ke(),n=$o(),r=pn(),{release:o,environment:i=Pp}=t&&t.getOptions()||{},{userAgent:s}=we.navigator||{},a=CT({release:o,environment:i,user:r.getUser()||n.getUser(),...s&&{userAgent:s},...e}),l=n.getSession();return l&&l.status==="ok"&&bs(l,{status:"exited"}),IT(),n.setSession(a),r.setSession(a),a}function IT(){const e=$o(),t=pn(),n=t.getSession()||e.getSession();n&&kT(n),$T(),e.setSession(),t.setSession()}function $T(){const e=$o(),t=pn(),n=ke(),r=t.getSession()||e.getSession();r&&n&&n.captureSession&&n.captureSession(r)}function e_(e=!1){if(e){IT();return}$T()}function yh(e){return e.transaction}function Mp(e,t,n){const r=t.getOptions(),{publicKey:o}=t.getDsn()||{},{segment:i}=n&&n.getUser()||{},s=Zt({environment:r.environment||Pp,release:r.release,user_segment:i,public_key:o,trace_id:e});return t.emit&&t.emit("createDsc",s),s}function tl(e){const t=ke();if(!t)return{};const n=Mp(pt(e).trace_id||"",t,pn()),r=yh(e);if(!r)return n;const o=r&&r._frozenDynamicSamplingContext;if(o)return o;const{sampleRate:i,source:s}=r.metadata;i!=null&&(n.sample_rate=`${i}`);const a=pt(r);return s&&s!=="url"&&(n.transaction=a.description),n.sampled=String(Sb(r)),t.emit&&t.emit("createDsc",n),n}function PT(e,t){const{fingerprint:n,span:r,breadcrumbs:o,sdkProcessingMetadata:i}=t;FM(e,t),r&&VM(e,r),zM(e,n),jM(e,o),LM(e,i)}function t_(e,t){const{extra:n,tags:r,user:o,contexts:i,level:s,sdkProcessingMetadata:a,breadcrumbs:l,fingerprint:c,eventProcessors:u,attachments:d,propagationContext:f,transactionName:h,span:m}=t;Jl(e,"extra",n),Jl(e,"tags",r),Jl(e,"user",o),Jl(e,"contexts",i),Jl(e,"sdkProcessingMetadata",a),s&&(e.level=s),h&&(e.transactionName=h),m&&(e.span=m),l.length&&(e.breadcrumbs=[...e.breadcrumbs,...l]),c.length&&(e.fingerprint=[...e.fingerprint,...c]),u.length&&(e.eventProcessors=[...e.eventProcessors,...u]),d.length&&(e.attachments=[...e.attachments,...d]),e.propagationContext={...e.propagationContext,...f}}function Jl(e,t,n){if(n&&Object.keys(n).length){e[t]={...e[t]};for(const r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[t][r]=n[r])}}function FM(e,t){const{extra:n,tags:r,user:o,contexts:i,level:s,transactionName:a}=t,l=Zt(n);l&&Object.keys(l).length&&(e.extra={...l,...e.extra});const c=Zt(r);c&&Object.keys(c).length&&(e.tags={...c,...e.tags});const u=Zt(o);u&&Object.keys(u).length&&(e.user={...u,...e.user});const d=Zt(i);d&&Object.keys(d).length&&(e.contexts={...d,...e.contexts}),s&&(e.level=s),a&&(e.transaction=a)}function jM(e,t){const n=[...e.breadcrumbs||[],...t];e.breadcrumbs=n.length?n:void 0}function LM(e,t){e.sdkProcessingMetadata={...e.sdkProcessingMetadata,...t}}function VM(e,t){e.contexts={trace:wb(t),...e.contexts};const n=yh(t);if(n){e.sdkProcessingMetadata={dynamicSamplingContext:tl(t),...e.sdkProcessingMetadata};const r=pt(n).description;r&&(e.tags={transaction:r,...e.tags})}}function zM(e,t){e.fingerprint=e.fingerprint?hT(e.fingerprint):[],t&&(e.fingerprint=e.fingerprint.concat(t)),e.fingerprint&&!e.fingerprint.length&&delete e.fingerprint}const BM=100;let wg;class fo{constructor(){this._notifyingListeners=!1,this._scopeListeners=[],this._eventProcessors=[],this._breadcrumbs=[],this._attachments=[],this._user={},this._tags={},this._extra={},this._contexts={},this._sdkProcessingMetadata={},this._propagationContext=n_()}static clone(t){return t?t.clone():new fo}clone(){const t=new fo;return t._breadcrumbs=[...this._breadcrumbs],t._tags={...this._tags},t._extra={...this._extra},t._contexts={...this._contexts},t._user=this._user,t._level=this._level,t._span=this._span,t._session=this._session,t._transactionName=this._transactionName,t._fingerprint=this._fingerprint,t._eventProcessors=[...this._eventProcessors],t._requestSession=this._requestSession,t._attachments=[...this._attachments],t._sdkProcessingMetadata={...this._sdkProcessingMetadata},t._propagationContext={...this._propagationContext},t._client=this._client,t}setClient(t){this._client=t}getClient(){return this._client}addScopeListener(t){this._scopeListeners.push(t)}addEventProcessor(t){return this._eventProcessors.push(t),this}setUser(t){return this._user=t||{email:void 0,id:void 0,ip_address:void 0,segment:void 0,username:void 0},this._session&&bs(this._session,{user:t}),this._notifyScopeListeners(),this}getUser(){return this._user}getRequestSession(){return this._requestSession}setRequestSession(t){return this._requestSession=t,this}setTags(t){return this._tags={...this._tags,...t},this._notifyScopeListeners(),this}setTag(t,n){return this._tags={...this._tags,[t]:n},this._notifyScopeListeners(),this}setExtras(t){return this._extra={...this._extra,...t},this._notifyScopeListeners(),this}setExtra(t,n){return this._extra={...this._extra,[t]:n},this._notifyScopeListeners(),this}setFingerprint(t){return this._fingerprint=t,this._notifyScopeListeners(),this}setLevel(t){return this._level=t,this._notifyScopeListeners(),this}setTransactionName(t){return this._transactionName=t,this._notifyScopeListeners(),this}setContext(t,n){return n===null?delete this._contexts[t]:this._contexts[t]=n,this._notifyScopeListeners(),this}setSpan(t){return this._span=t,this._notifyScopeListeners(),this}getSpan(){return this._span}getTransaction(){const t=this._span;return t&&t.transaction}setSession(t){return t?this._session=t:delete this._session,this._notifyScopeListeners(),this}getSession(){return this._session}update(t){if(!t)return this;const n=typeof t=="function"?t(this):t;if(n instanceof fo){const r=n.getScopeData();this._tags={...this._tags,...r.tags},this._extra={...this._extra,...r.extra},this._contexts={...this._contexts,...r.contexts},r.user&&Object.keys(r.user).length&&(this._user=r.user),r.level&&(this._level=r.level),r.fingerprint.length&&(this._fingerprint=r.fingerprint),n.getRequestSession()&&(this._requestSession=n.getRequestSession()),r.propagationContext&&(this._propagationContext=r.propagationContext)}else if(Ja(n)){const r=t;this._tags={...this._tags,...r.tags},this._extra={...this._extra,...r.extra},this._contexts={...this._contexts,...r.contexts},r.user&&(this._user=r.user),r.level&&(this._level=r.level),r.fingerprint&&(this._fingerprint=r.fingerprint),r.requestSession&&(this._requestSession=r.requestSession),r.propagationContext&&(this._propagationContext=r.propagationContext)}return this}clear(){return this._breadcrumbs=[],this._tags={},this._extra={},this._user={},this._contexts={},this._level=void 0,this._transactionName=void 0,this._fingerprint=void 0,this._requestSession=void 0,this._span=void 0,this._session=void 0,this._notifyScopeListeners(),this._attachments=[],this._propagationContext=n_(),this}addBreadcrumb(t,n){const r=typeof n=="number"?n:BM;if(r<=0)return this;const o={timestamp:qu(),...t},i=this._breadcrumbs;return i.push(o),this._breadcrumbs=i.length>r?i.slice(-r):i,this._notifyScopeListeners(),this}getLastBreadcrumb(){return this._breadcrumbs[this._breadcrumbs.length-1]}clearBreadcrumbs(){return this._breadcrumbs=[],this._notifyScopeListeners(),this}addAttachment(t){return this._attachments.push(t),this}getAttachments(){return this.getScopeData().attachments}clearAttachments(){return this._attachments=[],this}getScopeData(){const{_breadcrumbs:t,_attachments:n,_contexts:r,_tags:o,_extra:i,_user:s,_level:a,_fingerprint:l,_eventProcessors:c,_propagationContext:u,_sdkProcessingMetadata:d,_transactionName:f,_span:h}=this;return{breadcrumbs:t,attachments:n,contexts:r,tags:o,extra:i,user:s,level:a,fingerprint:l||[],eventProcessors:c,propagationContext:u,sdkProcessingMetadata:d,transactionName:f,span:h}}applyToEvent(t,n={},r=[]){PT(t,this.getScopeData());const o=[...r,...bb(),...this._eventProcessors];return vh(o,t,n)}setSDKProcessingMetadata(t){return this._sdkProcessingMetadata={...this._sdkProcessingMetadata,...t},this}setPropagationContext(t){return this._propagationContext=t,this}getPropagationContext(){return this._propagationContext}captureException(t,n){const r=n&&n.event_id?n.event_id:ot();if(!this._client)return j.warn("No client configured on scope - will not capture exception!"),r;const o=new Error("Sentry syntheticException");return this._client.captureException(t,{originalException:t,syntheticException:o,...n,event_id:r},this),r}captureMessage(t,n,r){const o=r&&r.event_id?r.event_id:ot();if(!this._client)return j.warn("No client configured on scope - will not capture message!"),o;const i=new Error(t);return this._client.captureMessage(t,n,{originalException:t,syntheticException:i,...r,event_id:o},this),o}captureEvent(t,n){const r=n&&n.event_id?n.event_id:ot();return this._client?(this._client.captureEvent(t,{...n,event_id:r},this),r):(j.warn("No client configured on scope - will not capture event!"),r)}_notifyScopeListeners(){this._notifyingListeners||(this._notifyingListeners=!0,this._scopeListeners.forEach(t=>{t(this)}),this._notifyingListeners=!1)}}function HM(){return wg||(wg=new fo),wg}function n_(){return{traceId:ot(),spanId:ot().substring(16)}}const $y="7.105.0",OT=parseFloat($y),UM=100;class NT{constructor(t,n,r,o=OT){this._version=o;let i;n?i=n:(i=new fo,i.setClient(t));let s;r?s=r:(s=new fo,s.setClient(t)),this._stack=[{scope:i}],t&&this.bindClient(t),this._isolationScope=s}isOlderThan(t){return this._version(this.popScope(),o),o=>{throw this.popScope(),o}):(this.popScope(),r)}getClient(){return this.getStackTop().client}getScope(){return this.getStackTop().scope}getIsolationScope(){return this._isolationScope}getStack(){return this._stack}getStackTop(){return this._stack[this._stack.length-1]}captureException(t,n){const r=this._lastEventId=n&&n.event_id?n.event_id:ot(),o=new Error("Sentry syntheticException");return this.getScope().captureException(t,{originalException:t,syntheticException:o,...n,event_id:r}),r}captureMessage(t,n,r){const o=this._lastEventId=r&&r.event_id?r.event_id:ot(),i=new Error(t);return this.getScope().captureMessage(t,n,{originalException:t,syntheticException:i,...r,event_id:o}),o}captureEvent(t,n){const r=n&&n.event_id?n.event_id:ot();return t.type||(this._lastEventId=r),this.getScope().captureEvent(t,{...n,event_id:r}),r}lastEventId(){return this._lastEventId}addBreadcrumb(t,n){const{scope:r,client:o}=this.getStackTop();if(!o)return;const{beforeBreadcrumb:i=null,maxBreadcrumbs:s=UM}=o.getOptions&&o.getOptions()||{};if(s<=0)return;const l={timestamp:qu(),...t},c=i?vs(()=>i(l,n)):l;c!==null&&(o.emit&&o.emit("beforeAddBreadcrumb",c,n),r.addBreadcrumb(c,s))}setUser(t){this.getScope().setUser(t),this.getIsolationScope().setUser(t)}setTags(t){this.getScope().setTags(t),this.getIsolationScope().setTags(t)}setExtras(t){this.getScope().setExtras(t),this.getIsolationScope().setExtras(t)}setTag(t,n){this.getScope().setTag(t,n),this.getIsolationScope().setTag(t,n)}setExtra(t,n){this.getScope().setExtra(t,n),this.getIsolationScope().setExtra(t,n)}setContext(t,n){this.getScope().setContext(t,n),this.getIsolationScope().setContext(t,n)}configureScope(t){const{scope:n,client:r}=this.getStackTop();r&&t(n)}run(t){const n=r_(this);try{t(this)}finally{r_(n)}}getIntegration(t){const n=this.getClient();if(!n)return null;try{return n.getIntegration(t)}catch{return J&&j.warn(`Cannot retrieve integration ${t.id} from the current Hub`),null}}startTransaction(t,n){const r=this._callExtensionMethod("startTransaction",t,n);return J&&!r&&(this.getClient()?j.warn(`Tracing extension 'startTransaction' has not been added. Call 'addTracingExtensions' before calling 'init': +Sentry.addTracingExtensions(); +Sentry.init({...}); +`):j.warn("Tracing extension 'startTransaction' is missing. You should 'init' the SDK before calling 'startTransaction'")),r}traceHeaders(){return this._callExtensionMethod("traceHeaders")}captureSession(t=!1){if(t)return this.endSession();this._sendSessionUpdate()}endSession(){const n=this.getStackTop().scope,r=n.getSession();r&&kT(r),this._sendSessionUpdate(),n.setSession()}startSession(t){const{scope:n,client:r}=this.getStackTop(),{release:o,environment:i=Pp}=r&&r.getOptions()||{},{userAgent:s}=we.navigator||{},a=CT({release:o,environment:i,user:n.getUser(),...s&&{userAgent:s},...t}),l=n.getSession&&n.getSession();return l&&l.status==="ok"&&bs(l,{status:"exited"}),this.endSession(),n.setSession(a),a}shouldSendDefaultPii(){const t=this.getClient(),n=t&&t.getOptions();return!!(n&&n.sendDefaultPii)}_sendSessionUpdate(){const{scope:t,client:n}=this.getStackTop(),r=t.getSession();r&&n&&n.captureSession&&n.captureSession(r)}_callExtensionMethod(t,...n){const o=Yu().__SENTRY__;if(o&&o.extensions&&typeof o.extensions[t]=="function")return o.extensions[t].apply(this,n);J&&j.warn(`Extension method ${t} couldn't be found, doing nothing.`)}}function Yu(){return we.__SENTRY__=we.__SENTRY__||{extensions:{},hub:void 0},we}function r_(e){const t=Yu(),n=Py(t);return MT(t,e),n}function Mt(){const e=Yu();if(e.__SENTRY__&&e.__SENTRY__.acs){const t=e.__SENTRY__.acs.getCurrentHub();if(t)return t}return WM(e)}function $o(){return Mt().getIsolationScope()}function WM(e=Yu()){return(!GM(e)||Py(e).isOlderThan(OT))&&MT(e,new NT),Py(e)}function GM(e){return!!(e&&e.__SENTRY__&&e.__SENTRY__.hub)}function Py(e){return rT("hub",()=>new NT,e)}function MT(e,t){if(!e)return!1;const n=e.__SENTRY__=e.__SENTRY__||{};return n.hub=t,!0}function Os(e){return(e||Mt()).getScope().getTransaction()}let o_=!1;function qM(){o_||(o_=!0,gT(Oy),vT(Oy))}function Oy(){const e=Os();if(e){const t="internal_error";J&&j.log(`[Tracing] Transaction: ${t} -> Global error occured`),e.setStatus(t)}}Oy.tag="sentry_tracingErrorCallback";var i_;(function(e){const t="ok";e.Ok=t;const n="deadline_exceeded";e.DeadlineExceeded=n;const r="unauthenticated";e.Unauthenticated=r;const o="permission_denied";e.PermissionDenied=o;const i="not_found";e.NotFound=i;const s="resource_exhausted";e.ResourceExhausted=s;const a="invalid_argument";e.InvalidArgument=a;const l="unimplemented";e.Unimplemented=l;const c="unavailable";e.Unavailable=c;const u="internal_error";e.InternalError=u;const d="unknown_error";e.UnknownError=d;const f="cancelled";e.Cancelled=f;const h="already_exists";e.AlreadyExists=h;const m="failed_precondition";e.FailedPrecondition=m;const v="aborted";e.Aborted=v;const S="out_of_range";e.OutOfRange=S;const y="data_loss";e.DataLoss=y})(i_||(i_={}));function KM(e){if(e<400&&e>=100)return"ok";if(e>=400&&e<500)switch(e){case 401:return"unauthenticated";case 403:return"permission_denied";case 404:return"not_found";case 409:return"already_exists";case 413:return"failed_precondition";case 429:return"resource_exhausted";default:return"invalid_argument"}if(e>=500&&e<600)switch(e){case 501:return"unimplemented";case 503:return"unavailable";case 504:return"deadline_exceeded";default:return"internal_error"}return"unknown_error"}function Eb(e,t){e.setTag("http.status_code",String(t)),e.setData("http.response.status_code",t);const n=KM(t);n!=="unknown_error"&&e.setStatus(n)}function Nl(e){if(typeof __SENTRY_TRACING__=="boolean"&&!__SENTRY_TRACING__)return!1;const t=ke(),n=e||t&&t.getOptions();return!!n&&(n.enableTracing||"tracesSampleRate"in n||"tracesSampler"in n)}function DT(e){if(!Nl())return;const t=QM(e),n=Mt(),r=e.scope?e.scope.getSpan():Cb();if(e.onlyIfParent&&!r)return;const s=(e.scope||pn()).clone();return YM(n,{parentSpan:r,spanContext:t,forceTransaction:e.forceTransaction,scope:s})}function Cb(){return pn().getSpan()}function YM(e,{parentSpan:t,spanContext:n,forceTransaction:r,scope:o}){if(!Nl())return;const i=$o();let s;if(t&&!r)s=t.startChild(n);else if(t){const a=tl(t),{traceId:l,spanId:c}=t.spanContext(),u=Sb(t);s=e.startTransaction({traceId:l,parentSpanId:c,parentSampled:u,...n,metadata:{dynamicSamplingContext:a,...n.metadata}})}else{const{traceId:a,dsc:l,parentSpanId:c,sampled:u}={...i.getPropagationContext(),...o.getPropagationContext()};s=e.startTransaction({traceId:a,parentSpanId:c,parentSampled:u,...n,metadata:{dynamicSamplingContext:l,...n.metadata}})}return o.setSpan(s),XM(s,o,i),s}function QM(e){if(e.startTime){const t={...e};return t.startTimestamp=Np(e.startTime),delete t.startTime,t}return e}const AT="_sentryScope",FT="_sentryIsolationScope";function XM(e,t,n){e&&(ys(e,FT,n),ys(e,AT,t))}function ZM(e){return{scope:e[AT],isolationScope:e[FT]}}const ho="sentry.source",aa="sentry.sample_rate",Vd="sentry.op",la="sentry.origin",JM="profile_id";class jT{constructor(t=1e3){this._maxlen=t,this.spans=[]}add(t){this.spans.length>this._maxlen?t.spanRecorder=void 0:this.spans.push(t)}}class Dp{constructor(t={}){this._traceId=t.traceId||ot(),this._spanId=t.spanId||ot().substring(16),this._startTime=t.startTimestamp||Ku(),this.tags=t.tags?{...t.tags}:{},this.data=t.data?{...t.data}:{},this.instrumenter=t.instrumenter||"sentry",this._attributes={},this.setAttributes({[la]:t.origin||"manual",[Vd]:t.op,...t.attributes}),this._name=t.name||t.description,t.parentSpanId&&(this._parentSpanId=t.parentSpanId),"sampled"in t&&(this._sampled=t.sampled),t.status&&(this._status=t.status),t.endTimestamp&&(this._endTime=t.endTimestamp),t.exclusiveTime&&(this._exclusiveTime=t.exclusiveTime),this._measurements=t.measurements?{...t.measurements}:{}}get name(){return this._name||""}set name(t){this.updateName(t)}get description(){return this._name}set description(t){this._name=t}get traceId(){return this._traceId}set traceId(t){this._traceId=t}get spanId(){return this._spanId}set spanId(t){this._spanId=t}set parentSpanId(t){this._parentSpanId=t}get parentSpanId(){return this._parentSpanId}get sampled(){return this._sampled}set sampled(t){this._sampled=t}get attributes(){return this._attributes}set attributes(t){this._attributes=t}get startTimestamp(){return this._startTime}set startTimestamp(t){this._startTime=t}get endTimestamp(){return this._endTime}set endTimestamp(t){this._endTime=t}get status(){return this._status}set status(t){this._status=t}get op(){return this._attributes[Vd]}set op(t){this.setAttribute(Vd,t)}get origin(){return this._attributes[la]}set origin(t){this.setAttribute(la,t)}spanContext(){const{_spanId:t,_traceId:n,_sampled:r}=this;return{spanId:t,traceId:n,traceFlags:r?TT:_M}}startChild(t){const n=new Dp({...t,parentSpanId:this._spanId,sampled:this._sampled,traceId:this._traceId});n.spanRecorder=this.spanRecorder,n.spanRecorder&&n.spanRecorder.add(n);const r=yh(this);if(n.transaction=r,J&&r){const o=t&&t.op||"< unknown op >",i=pt(n).description||"< unknown name >",s=r.spanContext().spanId,a=`[Tracing] Starting '${o}' span on transaction '${i}' (${s}).`;j.log(a),this._logMessage=a}return n}setTag(t,n){return this.tags={...this.tags,[t]:n},this}setData(t,n){return this.data={...this.data,[t]:n},this}setAttribute(t,n){n===void 0?delete this._attributes[t]:this._attributes[t]=n}setAttributes(t){Object.keys(t).forEach(n=>this.setAttribute(n,t[n]))}setStatus(t){return this._status=t,this}setHttpStatus(t){return Eb(this,t),this}setName(t){this.updateName(t)}updateName(t){return this._name=t,this}isSuccess(){return this._status==="ok"}finish(t){return this.end(t)}end(t){if(this._endTime)return;const n=yh(this);if(J&&n&&n.spanContext().spanId!==this._spanId){const r=this._logMessage;r&&j.log(r.replace("Starting","Finishing"))}this._endTime=Np(t)}toTraceparent(){return Op(this)}toContext(){return Zt({data:this._getData(),description:this._name,endTimestamp:this._endTime,op:this.op,parentSpanId:this._parentSpanId,sampled:this._sampled,spanId:this._spanId,startTimestamp:this._startTime,status:this._status,tags:this.tags,traceId:this._traceId})}updateWithContext(t){return this.data=t.data||{},this._name=t.name||t.description,this._endTime=t.endTimestamp,this.op=t.op,this._parentSpanId=t.parentSpanId,this._sampled=t.sampled,this._spanId=t.spanId||this._spanId,this._startTime=t.startTimestamp||this._startTime,this._status=t.status,this.tags=t.tags||{},this._traceId=t.traceId||this._traceId,this}getTraceContext(){return wb(this)}getSpanJSON(){return Zt({data:this._getData(),description:this._name,op:this._attributes[Vd],parent_span_id:this._parentSpanId,span_id:this._spanId,start_timestamp:this._startTime,status:this._status,tags:Object.keys(this.tags).length>0?this.tags:void 0,timestamp:this._endTime,trace_id:this._traceId,origin:this._attributes[la],_metrics_summary:void 0,profile_id:this._attributes[JM],exclusive_time:this._exclusiveTime,measurements:Object.keys(this._measurements).length>0?this._measurements:void 0})}isRecording(){return!this._endTime&&!!this._sampled}toJSON(){return this.getSpanJSON()}_getData(){const{data:t,_attributes:n}=this,r=Object.keys(t).length>0,o=Object.keys(n).length>0;if(!(!r&&!o))return r&&o?{...t,...n}:r?t:n}}class LT extends Dp{constructor(t,n){super(t),this._contexts={},this._hub=n||Mt(),this._name=t.name||"",this._metadata={...t.metadata},this._trimEnd=t.trimEnd,this.transaction=this;const r=this._metadata.dynamicSamplingContext;r&&(this._frozenDynamicSamplingContext={...r})}get name(){return this._name}set name(t){this.setName(t)}get metadata(){return{source:"custom",spanMetadata:{},...this._metadata,...this._attributes[ho]&&{source:this._attributes[ho]},...this._attributes[aa]&&{sampleRate:this._attributes[aa]}}}set metadata(t){this._metadata=t}setName(t,n="custom"){this._name=t,this.setAttribute(ho,n)}updateName(t){return this._name=t,this}initSpanRecorder(t=1e3){this.spanRecorder||(this.spanRecorder=new jT(t)),this.spanRecorder.add(this)}setContext(t,n){n===null?delete this._contexts[t]:this._contexts[t]=n}setMeasurement(t,n,r=""){this._measurements[t]={value:n,unit:r}}setMetadata(t){this._metadata={...this._metadata,...t}}end(t){const n=Np(t),r=this._finishTransaction(n);if(r)return this._hub.captureEvent(r)}toContext(){const t=super.toContext();return Zt({...t,name:this._name,trimEnd:this._trimEnd})}updateWithContext(t){return super.updateWithContext(t),this._name=t.name||"",this._trimEnd=t.trimEnd,this}getDynamicSamplingContext(){return tl(this)}setHub(t){this._hub=t}getProfileId(){if(this._contexts!==void 0&&this._contexts.profile!==void 0)return this._contexts.profile.profile_id}_finishTransaction(t){if(this._endTime!==void 0)return;this._name||(J&&j.warn("Transaction has no name, falling back to ``."),this._name=""),super.end(t);const n=this._hub.getClient();if(n&&n.emit&&n.emit("finishTransaction",this),this._sampled!==!0){J&&j.log("[Tracing] Discarding transaction because its trace was not chosen to be sampled."),n&&n.recordDroppedEvent("sample_rate","transaction");return}const r=this.spanRecorder?this.spanRecorder.spans.filter(u=>u!==this&&pt(u).timestamp):[];if(this._trimEnd&&r.length>0){const u=r.map(d=>pt(d).timestamp).filter(Boolean);this._endTime=u.reduce((d,f)=>d>f?d:f)}const{scope:o,isolationScope:i}=ZM(this),{metadata:s}=this,{source:a}=s,l={contexts:{...this._contexts,trace:wb(this)},spans:r,start_timestamp:this._startTime,tags:this.tags,timestamp:this._endTime,transaction:this._name,type:"transaction",sdkProcessingMetadata:{...s,capturedSpanScope:o,capturedSpanIsolationScope:i,...Zt({dynamicSamplingContext:tl(this)})},_metrics_summary:void 0,...a&&{transaction_info:{source:a}}};return Object.keys(this._measurements).length>0&&(J&&j.log("[Measurements] Adding measurements to transaction",JSON.stringify(this._measurements,void 0,2)),l.measurements=this._measurements),J&&j.log(`[Tracing] Finishing ${this.op} transaction: ${this._name}.`),l}}const Vf={idleTimeout:1e3,finalTimeout:3e4,heartbeatInterval:5e3},eD="finishReason",Us=["heartbeatFailed","idleTimeout","documentHidden","finalTimeout","externalFinish","cancelled"];class tD extends jT{constructor(t,n,r,o){super(o),this._pushActivity=t,this._popActivity=n,this.transactionSpanId=r}add(t){if(t.spanContext().spanId!==this.transactionSpanId){const n=t.end;t.end=(...r)=>(this._popActivity(t.spanContext().spanId),n.apply(t,r)),pt(t).timestamp===void 0&&this._pushActivity(t.spanContext().spanId)}super.add(t)}}class nD extends LT{constructor(t,n,r=Vf.idleTimeout,o=Vf.finalTimeout,i=Vf.heartbeatInterval,s=!1,a=!1){super(t,n),this._idleHub=n,this._idleTimeout=r,this._finalTimeout=o,this._heartbeatInterval=i,this._onScope=s,this.activities={},this._heartbeatCounter=0,this._finished=!1,this._idleTimeoutCanceledPermanently=!1,this._beforeFinishCallbacks=[],this._finishReason=Us[4],this._autoFinishAllowed=!a,s&&(J&&j.log(`Setting idle transaction on scope. Span ID: ${this.spanContext().spanId}`),n.getScope().setSpan(this)),a||this._restartIdleTimeout(),setTimeout(()=>{this._finished||(this.setStatus("deadline_exceeded"),this._finishReason=Us[3],this.end())},this._finalTimeout)}end(t){const n=Np(t);if(this._finished=!0,this.activities={},this.op==="ui.action.click"&&this.setAttribute(eD,this._finishReason),this.spanRecorder){J&&j.log("[Tracing] finishing IdleTransaction",new Date(n*1e3).toISOString(),this.op);for(const r of this._beforeFinishCallbacks)r(this,n);this.spanRecorder.spans=this.spanRecorder.spans.filter(r=>{if(r.spanContext().spanId===this.spanContext().spanId)return!0;pt(r).timestamp||(r.setStatus("cancelled"),r.end(n),J&&j.log("[Tracing] cancelling span since transaction ended early",JSON.stringify(r,void 0,2)));const{start_timestamp:o,timestamp:i}=pt(r),s=o&&o{this._finished||this._pushActivity(o)},r=o=>{this._finished||this._popActivity(o)};this.spanRecorder=new tD(n,r,this.spanContext().spanId,t),J&&j.log("Starting heartbeat"),this._pingHeartbeat()}this.spanRecorder.add(this)}cancelIdleTimeout(t,{restartOnChildSpanChange:n}={restartOnChildSpanChange:!0}){this._idleTimeoutCanceledPermanently=n===!1,this._idleTimeoutID&&(clearTimeout(this._idleTimeoutID),this._idleTimeoutID=void 0,Object.keys(this.activities).length===0&&this._idleTimeoutCanceledPermanently&&(this._finishReason=Us[5],this.end(t)))}setFinishReason(t){this._finishReason=t}sendAutoFinishSignal(){this._autoFinishAllowed||(J&&j.log("[Tracing] Received finish signal for idle transaction."),this._restartIdleTimeout(),this._autoFinishAllowed=!0)}_restartIdleTimeout(t){this.cancelIdleTimeout(),this._idleTimeoutID=setTimeout(()=>{!this._finished&&Object.keys(this.activities).length===0&&(this._finishReason=Us[1],this.end(t))},this._idleTimeout)}_pushActivity(t){this.cancelIdleTimeout(void 0,{restartOnChildSpanChange:!this._idleTimeoutCanceledPermanently}),J&&j.log(`[Tracing] pushActivity: ${t}`),this.activities[t]=!0,J&&j.log("[Tracing] new activities count",Object.keys(this.activities).length)}_popActivity(t){if(this.activities[t]&&(J&&j.log(`[Tracing] popActivity ${t}`),delete this.activities[t],J&&j.log("[Tracing] new activities count",Object.keys(this.activities).length)),Object.keys(this.activities).length===0){const n=Ku();this._idleTimeoutCanceledPermanently?this._autoFinishAllowed&&(this._finishReason=Us[5],this.end(n)):this._restartIdleTimeout(n+this._idleTimeout/1e3)}}_beat(){if(this._finished)return;const t=Object.keys(this.activities).join("");t===this._prevHeartbeatString?this._heartbeatCounter++:this._heartbeatCounter=1,this._prevHeartbeatString=t,this._heartbeatCounter>=3?this._autoFinishAllowed&&(J&&j.log("[Tracing] Transaction finished because of no change for 3 heart beats"),this.setStatus("deadline_exceeded"),this._finishReason=Us[0],this.end()):this._pingHeartbeat()}_pingHeartbeat(){J&&j.log(`pinging Heartbeat -> current counter: ${this._heartbeatCounter}`),setTimeout(()=>{this._beat()},this._heartbeatInterval)}}function VT(e,t,n){if(!Nl(t))return e.sampled=!1,e;if(e.sampled!==void 0)return e.setAttribute(aa,Number(e.sampled)),e;let r;return typeof t.tracesSampler=="function"?(r=t.tracesSampler(n),e.setAttribute(aa,Number(r))):n.parentSampled!==void 0?r=n.parentSampled:typeof t.tracesSampleRate<"u"?(r=t.tracesSampleRate,e.setAttribute(aa,Number(r))):(r=1,e.setAttribute(aa,r)),zT(r)?r?(e.sampled=Math.random()1?(J&&j.warn(`[Tracing] Given sample rate is invalid. Sample rate must be between 0 and 1. Got ${e}.`),!1):!0}function rD(){const t=this.getScope().getSpan();return t?{"sentry-trace":Op(t)}:{}}function oD(e,t){const n=this.getClient(),r=n&&n.getOptions()||{},o=r.instrumenter||"sentry",i=e.instrumenter||"sentry";o!==i&&(J&&j.error(`A transaction was started with instrumenter=\`${i}\`, but the SDK is configured with the \`${o}\` instrumenter. +The transaction will not be sampled. Please use the ${o} instrumentation to start transactions.`),e.sampled=!1);let s=new LT(e,this);return s=VT(s,r,{name:e.name,parentSampled:e.parentSampled,transactionContext:e,attributes:{...e.data,...e.attributes},...t}),s.isRecording()&&s.initSpanRecorder(r._experiments&&r._experiments.maxSpans),n&&n.emit&&n.emit("startTransaction",s),s}function BT(e,t,n,r,o,i,s,a=!1){const l=e.getClient(),c=l&&l.getOptions()||{};let u=new nD(t,e,n,r,s,o,a);return u=VT(u,c,{name:t.name,parentSampled:t.parentSampled,transactionContext:t,attributes:{...t.data,...t.attributes},...i}),u.isRecording()&&u.initSpanRecorder(c._experiments&&c._experiments.maxSpans),l&&l.emit&&l.emit("startTransaction",u),u}function iD(){const e=Yu();e.__SENTRY__&&(e.__SENTRY__.extensions=e.__SENTRY__.extensions||{},e.__SENTRY__.extensions.startTransaction||(e.__SENTRY__.extensions.startTransaction=oD),e.__SENTRY__.extensions.traceHeaders||(e.__SENTRY__.extensions.traceHeaders=rD),qM())}function sD(e,t,n){const r=Os();r&&r.setMeasurement(e,t,n)}function aD(e,t){return t&&(e.sdk=e.sdk||{},e.sdk.name=e.sdk.name||t.name,e.sdk.version=e.sdk.version||t.version,e.sdk.integrations=[...e.sdk.integrations||[],...t.integrations||[]],e.sdk.packages=[...e.sdk.packages||[],...t.packages||[]]),e}function lD(e,t,n,r){const o=yb(n),i={sent_at:new Date().toISOString(),...o&&{sdk:o},...!!r&&t&&{dsn:Pl(t)}},s="aggregates"in e?[{type:"sessions"},e]:[{type:"session"},e.toJSON()];return Ai(i,[s])}function HT(e,t,n,r){const o=yb(n),i=e.type&&e.type!=="replay_event"?e.type:"event";aD(e,n&&n.sdk);const s=xT(e,o,r,t);return delete e.sdkProcessingMetadata,Ai(s,[[{type:i},e]])}const cD="7";function UT(e){const t=e.protocol?`${e.protocol}:`:"",n=e.port?`:${e.port}`:"";return`${t}//${e.host}${n}${e.path?`/${e.path}`:""}/api/`}function uD(e){return`${UT(e)}${e.projectId}/envelope/`}function dD(e,t){return _9({sentry_key:e.publicKey,sentry_version:cD,...t&&{sentry_client:`${t.name}/${t.version}`}})}function fD(e,t={}){const n=typeof t=="string"?t:t.tunnel,r=typeof t=="string"||!t._metadata?void 0:t._metadata.sdk;return n||`${uD(e)}?${dD(e,r)}`}function hD(e,t){const n=aT(e);if(!n)return"";const r=`${UT(n)}embed/error-page/`;let o=`dsn=${Pl(n)}`;for(const i in t)if(i!=="dsn"&&i!=="onClose")if(i==="user"){const s=t.user;if(!s)continue;s.name&&(o+=`&name=${encodeURIComponent(s.name)}`),s.email&&(o+=`&email=${encodeURIComponent(s.email)}`)}else o+=`&${encodeURIComponent(i)}=${encodeURIComponent(t[i])}`;return`${r}?${o}`}const s_=[];function pD(e){const t={};return e.forEach(n=>{const{name:r}=n,o=t[r];o&&!o.isDefaultInstance&&n.isDefaultInstance||(t[r]=n)}),Object.keys(t).map(n=>t[n])}function mD(e){const t=e.defaultIntegrations||[],n=e.integrations;t.forEach(s=>{s.isDefaultInstance=!0});let r;Array.isArray(n)?r=[...t,...n]:typeof n=="function"?r=hT(n(t)):r=t;const o=pD(r),i=vD(o,s=>s.name==="Debug");if(i!==-1){const[s]=o.splice(i,1);o.push(s)}return o}function gD(e,t){const n={};return t.forEach(r=>{r&&WT(e,r,n)}),n}function a_(e,t){for(const n of t)n&&n.afterAllSetup&&n.afterAllSetup(e)}function WT(e,t,n){if(n[t.name]){J&&j.log(`Integration skipped because it was already installed: ${t.name}`);return}if(n[t.name]=t,s_.indexOf(t.name)===-1&&(t.setupOnce(SM,Mt),s_.push(t.name)),t.setup&&typeof t.setup=="function"&&t.setup(e),e.on&&typeof t.preprocessEvent=="function"){const r=t.preprocessEvent.bind(t);e.on("preprocessEvent",(o,i)=>r(o,i,e))}if(e.addEventProcessor&&typeof t.processEvent=="function"){const r=t.processEvent.bind(t),o=Object.assign((i,s)=>r(i,s,e),{id:t.name});e.addEventProcessor(o)}J&&j.log(`Integration installed: ${t.name}`)}function vD(e,t){for(let n=0;n0?`|#${r.map(([i,s])=>`${i}:${s}`).join(",")}`:"";t+=`${n.name}@${n.unit}:${n.metric}|${n.metricType}${o}|T${n.timestamp} +`}return t}function bD(e,t,n,r){const o={sent_at:new Date().toISOString()};n&&n.sdk&&(o.sdk={name:n.sdk.name,version:n.sdk.version}),r&&t&&(o.dsn=Pl(t));const i=wD(e);return Ai(o,[i])}function wD(e){const t=yD(e);return[{type:"statsd",length:t.length},t]}const l_="Not capturing exception because it's already been captured.";class SD{constructor(t){if(this._options=t,this._integrations={},this._integrationsInitialized=!1,this._numProcessing=0,this._outcomes={},this._hooks={},this._eventProcessors=[],t.dsn?this._dsn=aT(t.dsn):J&&j.warn("No DSN provided, client will not send events."),this._dsn){const n=fD(this._dsn,t);this._transport=t.transport({recordDroppedEvent:this.recordDroppedEvent.bind(this),...t.transportOptions,url:n})}}captureException(t,n,r){if(Ux(t)){J&&j.log(l_);return}let o=n&&n.event_id;return this._process(this.eventFromException(t,n).then(i=>this._captureEvent(i,n,r)).then(i=>{o=i})),o}captureMessage(t,n,r,o){let i=r&&r.event_id;const s=ub(t)?t:String(t),a=db(t)?this.eventFromMessage(s,n,r):this.eventFromException(t,r);return this._process(a.then(l=>this._captureEvent(l,r,o)).then(l=>{i=l})),i}captureEvent(t,n,r){if(n&&n.originalException&&Ux(n.originalException)){J&&j.log(l_);return}let o=n&&n.event_id;const s=(t.sdkProcessingMetadata||{}).capturedSpanScope;return this._process(this._captureEvent(t,n,s||r).then(a=>{o=a})),o}captureSession(t){typeof t.release!="string"?J&&j.warn("Discarded session because of missing or non-string release"):(this.sendSession(t),bs(t,{init:!1}))}getDsn(){return this._dsn}getOptions(){return this._options}getSdkMetadata(){return this._options._metadata}getTransport(){return this._transport}flush(t){const n=this._transport;return n?(this.metricsAggregator&&this.metricsAggregator.flush(),this._isClientDoneProcessing(t).then(r=>n.flush(t).then(o=>r&&o))):el(!0)}close(t){return this.flush(t).then(n=>(this.getOptions().enabled=!1,this.metricsAggregator&&this.metricsAggregator.close(),n))}getEventProcessors(){return this._eventProcessors}addEventProcessor(t){this._eventProcessors.push(t)}setupIntegrations(t){(t&&!this._integrationsInitialized||this._isEnabled()&&!this._integrationsInitialized)&&this._setupIntegrations()}init(){this._isEnabled()&&this._setupIntegrations()}getIntegrationById(t){return this.getIntegrationByName(t)}getIntegrationByName(t){return this._integrations[t]}getIntegration(t){try{return this._integrations[t.id]||null}catch{return J&&j.warn(`Cannot retrieve integration ${t.id} from the current Client`),null}}addIntegration(t){const n=this._integrations[t.name];WT(this,t,this._integrations),n||a_(this,[t])}sendEvent(t,n={}){this.emit("beforeSendEvent",t,n);let r=HT(t,this._dsn,this._options._metadata,this._options.tunnel);for(const i of n.attachments||[])r=dM(r,pM(i,this._options.transportOptions&&this._options.transportOptions.textEncoder));const o=this._sendEnvelope(r);o&&o.then(i=>this.emit("afterSendEvent",t,i),null)}sendSession(t){const n=lD(t,this._dsn,this._options._metadata,this._options.tunnel);this._sendEnvelope(n)}recordDroppedEvent(t,n,r){if(this._options.sendClientReports){const o=`${t}:${n}`;J&&j.log(`Adding outcome: "${o}"`),this._outcomes[o]=this._outcomes[o]+1||1}}captureAggregateMetrics(t){J&&j.log(`Flushing aggregated metrics, number of metrics: ${t.length}`);const n=bD(t,this._dsn,this._options._metadata,this._options.tunnel);this._sendEnvelope(n)}on(t,n){this._hooks[t]||(this._hooks[t]=[]),this._hooks[t].push(n)}emit(t,...n){this._hooks[t]&&this._hooks[t].forEach(r=>r(...n))}_setupIntegrations(){const{integrations:t}=this._options;this._integrations=gD(this,t),a_(this,t),this._integrationsInitialized=!0}_updateSessionFromEvent(t,n){let r=!1,o=!1;const i=n.exception&&n.exception.values;if(i){o=!0;for(const l of i){const c=l.mechanism;if(c&&c.handled===!1){r=!0;break}}}const s=t.status==="ok";(s&&t.errors===0||s&&r)&&(bs(t,{...r&&{status:"crashed"},errors:t.errors||Number(o||r)}),this.captureSession(t))}_isClientDoneProcessing(t){return new wn(n=>{let r=0;const o=1,i=setInterval(()=>{this._numProcessing==0?(clearInterval(i),n(!0)):(r+=o,t&&r>=t&&(clearInterval(i),n(!1)))},o)})}_isEnabled(){return this.getOptions().enabled!==!1&&this._transport!==void 0}_prepareEvent(t,n,r,o=$o()){const i=this.getOptions(),s=Object.keys(this._integrations);return!n.integrations&&s.length>0&&(n.integrations=s),this.emit("preprocessEvent",t,n),xb(i,t,n,r,this,o).then(a=>{if(a===null)return a;const l={...o.getPropagationContext(),...r?r.getPropagationContext():void 0};if(!(a.contexts&&a.contexts.trace)&&l){const{traceId:u,spanId:d,parentSpanId:f,dsc:h}=l;a.contexts={trace:{trace_id:u,span_id:d,parent_span_id:f},...a.contexts};const m=h||Mp(u,this,r);a.sdkProcessingMetadata={dynamicSamplingContext:m,...a.sdkProcessingMetadata}}return a})}_captureEvent(t,n={},r){return this._processEvent(t,n,r).then(o=>o.event_id,o=>{if(J){const i=o;i.logLevel==="log"?j.log(i.message):j.warn(i)}})}_processEvent(t,n,r){const o=this.getOptions(),{sampleRate:i}=o,s=qT(t),a=GT(t),l=t.type||"error",c=`before send for type \`${l}\``;if(a&&typeof i=="number"&&Math.random()>i)return this.recordDroppedEvent("sample_rate","error",t),gb(new Ar(`Discarding event because it's not included in the random sample (sampling rate = ${i})`,"log"));const u=l==="replay_event"?"replay":l,f=(t.sdkProcessingMetadata||{}).capturedSpanIsolationScope;return this._prepareEvent(t,n,r,f).then(h=>{if(h===null)throw this.recordDroppedEvent("event_processor",u,t),new Ar("An event processor returned `null`, will not send event.","log");if(n.data&&n.data.__sentry__===!0)return h;const v=_D(o,h,n);return xD(v,c)}).then(h=>{if(h===null)throw this.recordDroppedEvent("before_send",u,t),new Ar(`${c} returned \`null\`, will not send event.`,"log");const m=r&&r.getSession();!s&&m&&this._updateSessionFromEvent(m,h);const v=h.transaction_info;if(s&&v&&h.transaction!==t.transaction){const S="custom";h.transaction_info={...v,source:S}}return this.sendEvent(h,n),h}).then(null,h=>{throw h instanceof Ar?h:(this.captureException(h,{data:{__sentry__:!0},originalException:h}),new Ar(`Event processing pipeline threw an error, original event will not be sent. Details have been sent as a new event. +Reason: ${h}`))})}_process(t){this._numProcessing++,t.then(n=>(this._numProcessing--,n),n=>(this._numProcessing--,n))}_sendEnvelope(t){if(this.emit("beforeEnvelope",t),this._isEnabled()&&this._transport)return this._transport.send(t).then(null,n=>{J&&j.error("Error while sending event:",n)});J&&j.error("Transport disabled")}_clearOutcomes(){const t=this._outcomes;return this._outcomes={},Object.keys(t).map(n=>{const[r,o]=n.split(":");return{reason:r,category:o,quantity:t[n]}})}}function xD(e,t){const n=`${t} must return \`null\` or a valid event.`;if(Ip(e))return e.then(r=>{if(!Ja(r)&&r!==null)throw new Ar(n);return r},r=>{throw new Ar(`${t} rejected with ${r}`)});if(!Ja(e)&&e!==null)throw new Ar(n);return e}function _D(e,t,n){const{beforeSend:r,beforeSendTransaction:o}=e;return GT(t)&&r?r(t,n):qT(t)&&o?o(t,n):t}function GT(e){return e.type===void 0}function qT(e){return e.type==="transaction"}function ED(e){const t=ke();!t||!t.addEventProcessor||t.addEventProcessor(e)}function CD(e,t){t.debug===!0&&(J?j.enable():vs(()=>{console.warn("[Sentry] Cannot initialize SDK with `debug` option using a non-debug bundle.")})),pn().update(t.initialScope);const r=new e(t);kD(r),TD(r)}function kD(e){const n=Mt().getStackTop();n.client=e,n.scope.setClient(e)}function TD(e){e.init?e.init():e.setupIntegrations&&e.setupIntegrations()}const RD=30;function KT(e,t,n=eM(e.bufferSize||RD)){let r={};const o=s=>n.drain(s);function i(s){const a=[];if(Yx(s,(d,f)=>{const h=Qx(f);if(_T(r,h)){const m=c_(d,f);e.recordDroppedEvent("ratelimit_backoff",h,m)}else a.push(d)}),a.length===0)return el();const l=Ai(s[0],a),c=d=>{Yx(l,(f,h)=>{const m=c_(f,h);e.recordDroppedEvent(d,Qx(h),m)})},u=()=>t({body:fM(l,e.textEncoder)}).then(d=>(d.statusCode!==void 0&&(d.statusCode<200||d.statusCode>=300)&&J&&j.warn(`Sentry responded with status code ${d.statusCode} to sent event.`),r=ET(r,d),d),d=>{throw c("network_error"),d});return n.add(u).then(d=>d,d=>{if(d instanceof Ar)return J&&j.error("Skipped sending event because buffer is full."),c("queue_overflow"),el();throw d})}return i.__sentry__baseTransport__=!0,{send:i,flush:o}}function c_(e,t){if(!(t!=="event"&&t!=="transaction"))return Array.isArray(e)?e[1]:void 0}function ID(e){const t={sent_at:new Date().toISOString()},n=e.map($D);return Ai(t,n)}function $D(e){return[{type:"span"},e]}function PD(e,t){const n=t&&MD(t)?t.getClient():t,r=n&&n.getDsn(),o=n&&n.getOptions().tunnel;return ND(e,r)||OD(e,o)}function OD(e,t){return t?u_(e)===u_(t):!1}function ND(e,t){return t?e.includes(t.host):!1}function u_(e){return e[e.length-1]==="/"?e.slice(0,-1):e}function MD(e){return e.getClient!==void 0}function YT(e,t,n=[t],r="npm"){const o=e._metadata||{};o.sdk||(o.sdk={name:`sentry.javascript.${t}`,packages:n.map(i=>({name:`${r}:@sentry/${i}`,version:$y})),version:$y}),e._metadata=o}const DD=[/^Script error\.?$/,/^Javascript error: Script error\.? on line 0$/],AD=[/^.*\/healthcheck$/,/^.*\/healthy$/,/^.*\/live$/,/^.*\/ready$/,/^.*\/heartbeat$/,/^.*\/health$/,/^.*\/healthz$/],QT="InboundFilters",FD=(e={})=>({name:QT,setupOnce(){},processEvent(t,n,r){const o=r.getOptions(),i=jD(e,o);return LD(t,i)?null:t}}),XT=FD;Fi(QT,XT);function jD(e={},t={}){return{allowUrls:[...e.allowUrls||[],...t.allowUrls||[]],denyUrls:[...e.denyUrls||[],...t.denyUrls||[]],ignoreErrors:[...e.ignoreErrors||[],...t.ignoreErrors||[],...e.disableErrorDefaults?[]:DD],ignoreTransactions:[...e.ignoreTransactions||[],...t.ignoreTransactions||[],...e.disableTransactionDefaults?[]:AD],ignoreInternal:e.ignoreInternal!==void 0?e.ignoreInternal:!0}}function LD(e,t){return t.ignoreInternal&&WD(e)?(J&&j.warn(`Event dropped due to being internal Sentry Error. +Event: ${Zo(e)}`),!0):VD(e,t.ignoreErrors)?(J&&j.warn(`Event dropped due to being matched by \`ignoreErrors\` option. +Event: ${Zo(e)}`),!0):zD(e,t.ignoreTransactions)?(J&&j.warn(`Event dropped due to being matched by \`ignoreTransactions\` option. +Event: ${Zo(e)}`),!0):BD(e,t.denyUrls)?(J&&j.warn(`Event dropped due to being matched by \`denyUrls\` option. +Event: ${Zo(e)}. +Url: ${bh(e)}`),!0):HD(e,t.allowUrls)?!1:(J&&j.warn(`Event dropped due to not being matched by \`allowUrls\` option. +Event: ${Zo(e)}. +Url: ${bh(e)}`),!0)}function VD(e,t){return e.type||!t||!t.length?!1:UD(e).some(n=>Il(n,t))}function zD(e,t){if(e.type!=="transaction"||!t||!t.length)return!1;const n=e.transaction;return n?Il(n,t):!1}function BD(e,t){if(!t||!t.length)return!1;const n=bh(e);return n?Il(n,t):!1}function HD(e,t){if(!t||!t.length)return!0;const n=bh(e);return n?Il(n,t):!0}function UD(e){const t=[];e.message&&t.push(e.message);let n;try{n=e.exception.values[e.exception.values.length-1]}catch{}return n&&n.value&&(t.push(n.value),n.type&&t.push(`${n.type}: ${n.value}`)),J&&t.length===0&&j.error(`Could not extract message for event ${Zo(e)}`),t}function WD(e){try{return e.exception.values[0].type==="SentryError"}catch{}return!1}function GD(e=[]){for(let t=e.length-1;t>=0;t--){const n=e[t];if(n&&n.filename!==""&&n.filename!=="[native code]")return n.filename||null}return null}function bh(e){try{let t;try{t=e.exception.values[0].stacktrace.frames}catch{}return t?GD(t):null}catch{return J&&j.error(`Cannot extract url for event ${Zo(e)}`),null}}let d_;const ZT="FunctionToString",f_=new WeakMap,qD=()=>({name:ZT,setupOnce(){d_=Function.prototype.toString;try{Function.prototype.toString=function(...e){const t=hb(this),n=f_.has(ke())&&t!==void 0?t:this;return d_.apply(n,e)}}catch{}},setup(e){f_.set(e,!0)}}),JT=qD;Fi(ZT,JT);const Xe=typeof __SENTRY_DEBUG__>"u"||__SENTRY_DEBUG__,Se=we;function KD(){Se&&Se.document?Se.document.addEventListener("visibilitychange",()=>{const e=Os();if(Se.document.hidden&&e){const t="cancelled",{op:n,status:r}=pt(e);Xe&&j.log(`[Tracing] Transaction: ${t} -> since tab moved to the background, op: ${n}`),r||e.setStatus(t),e.setTag("visibilitychange","document.hidden"),e.end()}}):Xe&&j.warn("[Tracing] Could not set up background tab detection due to lack of global document")}const Ap=(e,t,n)=>{let r,o;return i=>{t.value>=0&&(i||n)&&(o=t.value-(r||0),(o||r===void 0)&&(r=t.value,t.delta=o,e(t)))}},YD=()=>`v3-${Date.now()}-${Math.floor(Math.random()*(9e12-1))+1e12}`,QD=()=>{const e=Se.performance.timing,t=Se.performance.navigation.type,n={entryType:"navigation",startTime:0,type:t==2?"back_forward":t===1?"reload":"navigate"};for(const r in e)r!=="navigationStart"&&r!=="toJSON"&&(n[r]=Math.max(e[r]-e.navigationStart,0));return n},e5=()=>Se.__WEB_VITALS_POLYFILL__?Se.performance&&(performance.getEntriesByType&&performance.getEntriesByType("navigation")[0]||QD()):Se.performance&&performance.getEntriesByType&&performance.getEntriesByType("navigation")[0],t5=()=>{const e=e5();return e&&e.activationStart||0},Fp=(e,t)=>{const n=e5();let r="navigate";return n&&(Se.document.prerendering||t5()>0?r="prerender":r=n.type.replace(/_/g,"-")),{name:e,value:typeof t>"u"?-1:t,rating:"good",delta:0,entries:[],id:YD(),navigationType:r}},Ml=(e,t,n)=>{try{if(PerformanceObserver.supportedEntryTypes.includes(e)){const r=new PerformanceObserver(o=>{t(o.getEntries())});return r.observe(Object.assign({type:e,buffered:!0},n||{})),r}}catch{}},Qu=(e,t)=>{const n=r=>{(r.type==="pagehide"||Se.document.visibilityState==="hidden")&&(e(r),t&&(removeEventListener("visibilitychange",n,!0),removeEventListener("pagehide",n,!0)))};addEventListener("visibilitychange",n,!0),addEventListener("pagehide",n,!0)},XD=e=>{const t=Fp("CLS",0);let n,r=0,o=[];const i=a=>{a.forEach(l=>{if(!l.hadRecentInput){const c=o[0],u=o[o.length-1];r&&o.length!==0&&l.startTime-u.startTime<1e3&&l.startTime-c.startTime<5e3?(r+=l.value,o.push(l)):(r=l.value,o=[l]),r>t.value&&(t.value=r,t.entries=o,n&&n())}})},s=Ml("layout-shift",i);if(s){n=Ap(e,t);const a=()=>{i(s.takeRecords()),n(!0)};return Qu(a),a}};let zf=-1;const ZD=()=>Se.document.visibilityState==="hidden"&&!Se.document.prerendering?0:1/0,JD=()=>{Qu(({timeStamp:e})=>{zf=e},!0)},kb=()=>(zf<0&&(zf=ZD(),JD()),{get firstHiddenTime(){return zf}}),eA=e=>{const t=kb(),n=Fp("FID");let r;const o=a=>{a.startTime{a.forEach(o)},s=Ml("first-input",i);r=Ap(e,n),s&&Qu(()=>{i(s.takeRecords()),s.disconnect()},!0)};let n5=0,Sg=1/0,zd=0;const tA=e=>{e.forEach(t=>{t.interactionId&&(Sg=Math.min(Sg,t.interactionId),zd=Math.max(zd,t.interactionId),n5=zd?(zd-Sg)/7+1:0)})};let Ny;const nA=()=>Ny?n5:performance.interactionCount||0,rA=()=>{"interactionCount"in performance||Ny||(Ny=Ml("event",tA,{type:"event",buffered:!0,durationThreshold:0}))},r5=()=>nA(),h_=10,io=[],xg={},p_=e=>{const t=io[io.length-1],n=xg[e.interactionId];if(n||io.lengtht.latency){if(n)n.entries.push(e),n.latency=Math.max(n.latency,e.duration);else{const r={id:e.interactionId,latency:e.duration,entries:[e]};xg[r.id]=r,io.push(r)}io.sort((r,o)=>o.latency-r.latency),io.splice(h_).forEach(r=>{delete xg[r.id]})}},oA=()=>{const e=Math.min(io.length-1,Math.floor(r5()/50));return io[e]},iA=(e,t)=>{t=t||{},rA();const n=Fp("INP");let r;const o=s=>{s.forEach(l=>{l.interactionId&&p_(l),l.entryType==="first-input"&&!io.some(u=>u.entries.some(d=>l.duration===d.duration&&l.startTime===d.startTime))&&p_(l)});const a=oA();a&&a.latency!==n.value&&(n.value=a.latency,n.entries=a.entries,r())},i=Ml("event",o,{durationThreshold:t.durationThreshold||40});r=Ap(e,n,t.reportAllChanges),i&&(i.observe({type:"first-input",buffered:!0}),Qu(()=>{o(i.takeRecords()),n.value<0&&r5()>0&&(n.value=0,n.entries=[]),r(!0)}))},m_={},sA=e=>{const t=kb(),n=Fp("LCP");let r;const o=s=>{const a=s[s.length-1];if(a){const l=Math.max(a.startTime-t5(),0);l{m_[n.id]||(o(i.takeRecords()),i.disconnect(),m_[n.id]=!0,r(!0))};return["keydown","click"].forEach(a=>{addEventListener(a,s,{once:!0,capture:!0})}),Qu(s,!0),s}},Nc={},wh={};let o5,i5,s5,a5;function aA(e,t=!1){return jp("cls",e,uA,o5,t)}function l5(e,t=!1){return jp("lcp",e,fA,s5,t)}function lA(e){return jp("fid",e,dA,i5)}function cA(e){return jp("inp",e,hA,a5)}function Xu(e,t){return c5(e,t),wh[e]||(pA(e),wh[e]=!0),u5(e,t)}function Zu(e,t){const n=Nc[e];if(!(!n||!n.length))for(const r of n)try{r(t)}catch(o){Xe&&j.error(`Error while triggering instrumentation handler. +Type: ${e} +Name: ${yo(r)} +Error:`,o)}}function uA(){return XD(e=>{Zu("cls",{metric:e}),o5=e})}function dA(){return eA(e=>{Zu("fid",{metric:e}),i5=e})}function fA(){return sA(e=>{Zu("lcp",{metric:e}),s5=e})}function hA(){return iA(e=>{Zu("inp",{metric:e}),a5=e})}function jp(e,t,n,r,o=!1){c5(e,t);let i;return wh[e]||(i=n(),wh[e]=!0),r&&t({metric:r}),u5(e,t,o?i:void 0)}function pA(e){const t={};e==="event"&&(t.durationThreshold=0),Ml(e,n=>{Zu(e,{entries:n})},t)}function c5(e,t){Nc[e]=Nc[e]||[],Nc[e].push(t)}function u5(e,t,n){return()=>{n&&n();const r=Nc[e];if(!r)return;const o=r.indexOf(t);o!==-1&&r.splice(o,1)}}function _g(e){return typeof e=="number"&&isFinite(e)}function nl(e,{startTimestamp:t,...n}){return t&&e.startTimestamp>t&&(e.startTimestamp=t),e.startChild({startTimestamp:t,...n})}const mA=2147483647;function dt(e){return e/1e3}function Tb(){return Se&&Se.addEventListener&&Se.performance}let g_=0,at={},$r,Mc;function gA(){const e=Tb();if(e&&kn){e.mark&&Se.performance.mark("sentry-tracing-init");const t=xA(),n=wA(),r=SA();return()=>{t(),n(),r()}}return()=>{}}function vA(){Xu("longtask",({entries:e})=>{for(const t of e){const n=Os();if(!n)return;const r=dt(kn+t.startTime),o=dt(t.duration);n.startChild({description:"Main UI thread blocked",op:"ui.long-task",origin:"auto.ui.browser.metrics",startTimestamp:r,endTimestamp:r+o})}})}function yA(){Xu("event",({entries:e})=>{for(const t of e){const n=Os();if(!n)return;if(t.name==="click"){const r=dt(kn+t.startTime),o=dt(t.duration),i={description:bi(t.target),op:`ui.interaction.${t.name}`,origin:"auto.ui.browser.metrics",startTimestamp:r,endTimestamp:r+o},s=iT(t.target);s&&(i.attributes={"ui.component_name":s}),n.startChild(i)}}})}function bA(e){if(Tb()&&kn){const n=_A(e);return()=>{n()}}return()=>{}}function wA(){return aA(({metric:e})=>{const t=e.entries[e.entries.length-1];t&&(Xe&&j.log("[Measurements] Adding CLS"),at.cls={value:e.value,unit:""},Mc=t)},!0)}function SA(){return l5(({metric:e})=>{const t=e.entries[e.entries.length-1];t&&(Xe&&j.log("[Measurements] Adding LCP"),at.lcp={value:e.value,unit:"millisecond"},$r=t)},!0)}function xA(){return lA(({metric:e})=>{const t=e.entries[e.entries.length-1];if(!t)return;const n=dt(kn),r=dt(t.startTime);Xe&&j.log("[Measurements] Adding FID"),at.fid={value:e.value,unit:"millisecond"},at["mark.fid"]={value:n+r,unit:"second"}})}function _A(e){return cA(({metric:t})=>{const n=t.entries.find(S=>S.name==="click"),r=ke();if(!n||!r)return;const o=r.getOptions(),i=dt(kn+n.startTime),s=dt(t.value),{routeName:a,parentContext:l,activeTransaction:c,user:u,replayId:d}=n.interactionId!==void 0?e[n.interactionId]:{routeName:void 0,parentContext:void 0,activeTransaction:void 0,user:void 0,replayId:void 0},f=u!==void 0?u.email||u.id||u.ip_address:void 0,h=c!==void 0?c.getProfileId():void 0,m=new Dp({startTimestamp:i,endTimestamp:i+s,op:"ui.interaction.click",name:bi(n.target),attributes:{release:o.release,environment:o.environment,transaction:a,...f!==void 0&&f!==""?{user:f}:{},...h!==void 0?{profile_id:h}:{},...d!==void 0?{replay_id:d}:{}},exclusiveTime:t.value,measurements:{inp:{value:t.value,unit:"millisecond"}}}),v=OA(l,o);if(v&&Math.random(){Xe&&j.error("Error while sending interaction:",b)});return}})}function EA(e){const t=Tb();if(!t||!Se.performance.getEntries||!kn)return;Xe&&j.log("[Tracing] Adding & adjusting spans using Performance API");const n=dt(kn),r=t.getEntries();let o,i;const{op:s,start_timestamp:a}=pt(e);if(r.slice(g_).forEach(l=>{const c=dt(l.startTime),u=dt(l.duration);if(!(e.op==="navigation"&&a&&n+c{if(!at[c]||!a||n>=a)return;const u=at[c].value,d=n+dt(u),f=Math.abs((d-a)*1e3),h=f-u;Xe&&j.log(`[Measurements] Normalized ${c} from ${u} to ${f} (${h})`),at[c].value=f});const l=at["mark.fid"];l&&at.fid&&(nl(e,{description:"first input delay",endTimestamp:l.value+dt(at.fid.value),op:"ui.action",origin:"auto.ui.browser.metrics",startTimestamp:l.value}),delete at["mark.fid"]),"fcp"in at||delete at.cls,Object.keys(at).forEach(c=>{sD(c,at[c].value,at[c].unit)}),$A(e)}$r=void 0,Mc=void 0,at={}}function CA(e,t,n,r,o){const i=o+n,s=i+r;return nl(e,{description:t.name,endTimestamp:s,op:t.entryType,origin:"auto.resource.browser.metrics",startTimestamp:i}),i}function kA(e,t,n){["unloadEvent","redirect","domContentLoadedEvent","loadEvent","connect"].forEach(r=>{Bd(e,t,r,n)}),Bd(e,t,"secureConnection",n,"TLS/SSL","connectEnd"),Bd(e,t,"fetch",n,"cache","domainLookupStart"),Bd(e,t,"domainLookup",n,"DNS"),TA(e,t,n)}function Bd(e,t,n,r,o,i){const s=i?t[i]:t[`${n}End`],a=t[`${n}Start`];!a||!s||nl(e,{op:"browser",origin:"auto.browser.browser.metrics",description:o||n,startTimestamp:r+dt(a),endTimestamp:r+dt(s)})}function TA(e,t,n){t.responseEnd&&(nl(e,{op:"browser",origin:"auto.browser.browser.metrics",description:"request",startTimestamp:n+dt(t.requestStart),endTimestamp:n+dt(t.responseEnd)}),nl(e,{op:"browser",origin:"auto.browser.browser.metrics",description:"response",startTimestamp:n+dt(t.responseStart),endTimestamp:n+dt(t.responseEnd)}))}function RA(e,t,n,r,o,i){if(t.initiatorType==="xmlhttprequest"||t.initiatorType==="fetch")return;const s=Lf(n),a={};Eg(a,t,"transferSize","http.response_transfer_size"),Eg(a,t,"encodedBodySize","http.response_content_length"),Eg(a,t,"decodedBodySize","http.decoded_response_content_length"),"renderBlockingStatus"in t&&(a["resource.render_blocking_status"]=t.renderBlockingStatus),s.protocol&&(a["url.scheme"]=s.protocol.split(":").pop()),s.host&&(a["server.address"]=s.host),a["url.same_origin"]=n.includes(Se.location.origin);const l=i+r,c=l+o;nl(e,{description:n.replace(Se.location.origin,""),endTimestamp:c,op:t.initiatorType?`resource.${t.initiatorType}`:"resource.other",origin:"auto.resource.browser.metrics",startTimestamp:l,data:a})}function IA(e){const t=Se.navigator;if(!t)return;const n=t.connection;n&&(n.effectiveType&&e.setTag("effectiveConnectionType",n.effectiveType),n.type&&e.setTag("connectionType",n.type),_g(n.rtt)&&(at["connection.rtt"]={value:n.rtt,unit:"millisecond"})),_g(t.deviceMemory)&&e.setTag("deviceMemory",`${t.deviceMemory} GB`),_g(t.hardwareConcurrency)&&e.setTag("hardwareConcurrency",String(t.hardwareConcurrency))}function $A(e){$r&&(Xe&&j.log("[Measurements] Adding LCP Data"),$r.element&&e.setTag("lcp.element",bi($r.element)),$r.id&&e.setTag("lcp.id",$r.id),$r.url&&e.setTag("lcp.url",$r.url.trim().slice(0,200)),e.setTag("lcp.size",$r.size)),Mc&&Mc.sources&&(Xe&&j.log("[Measurements] Adding CLS Data"),Mc.sources.forEach((t,n)=>e.setTag(`cls.source.${n+1}`,bi(t.node))))}function Eg(e,t,n,r){const o=t[n];o!=null&&o0&&f.setAttribute("http.response_content_length",m)}}else e.error&&f.setStatus("internal_error");f.end(),delete r[d]}return}const s=pn(),a=ke(),{method:l,url:c}=e.fetchData,u=i?DT({name:`${l} ${c}`,onlyIfParent:!0,attributes:{url:c,type:"fetch","http.method":l,[la]:o},op:"http.client"}):void 0;if(u&&(e.fetchData.__span=u.spanContext().spanId,r[u.spanContext().spanId]=u),n(e.fetchData.url)&&a){const d=e.args[0];e.args[1]=e.args[1]||{};const f=e.args[1];f.headers=MA(d,a,s,f,u)}return u}function MA(e,t,n,r,o){const i=o||n.getSpan(),s=$o(),{traceId:a,spanId:l,sampled:c,dsc:u}={...s.getPropagationContext(),...n.getPropagationContext()},d=i?Op(i):vb(a,l,c),f=ST(u||(i?tl(i):Mp(a,t,n))),h=r.headers||(typeof Request<"u"&&vo(e,Request)?e.headers:void 0);if(h)if(typeof Headers<"u"&&vo(h,Headers)){const m=new Headers(h);return m.append("sentry-trace",d),f&&m.append(Ry,f),m}else if(Array.isArray(h)){const m=[...h,["sentry-trace",d]];return f&&m.push([Ry,f]),m}else{const m="baggage"in h?h.baggage:void 0,v=[];return Array.isArray(m)?v.push(...m):m&&v.push(m),f&&v.push(f),{...h,"sentry-trace":d,baggage:v.length>0?v.join(","):void 0}}else return{"sentry-trace":d,baggage:f}}const My=["localhost",/^\/(?!\/)/],Dy={traceFetch:!0,traceXHR:!0,enableHTTPTimings:!0,tracingOrigins:My,tracePropagationTargets:My};function DA(e){const{traceFetch:t,traceXHR:n,tracePropagationTargets:r,tracingOrigins:o,shouldCreateSpanForRequest:i,enableHTTPTimings:s}={traceFetch:Dy.traceFetch,traceXHR:Dy.traceXHR,...e},a=typeof i=="function"?i:u=>!0,l=u=>LA(u,r||o),c={};t&&pb(u=>{const d=NA(u,a,l,c);s&&d&&v_(d)}),n&&mb(u=>{const d=VA(u,a,l,c);s&&d&&v_(d)})}function AA(e){return e.entryType==="resource"&&"initiatorType"in e&&typeof e.nextHopProtocol=="string"&&(e.initiatorType==="fetch"||e.initiatorType==="xmlhttprequest")}function v_(e){const{url:t}=pt(e).data||{};if(!t||typeof t!="string")return;const n=Xu("resource",({entries:r})=>{r.forEach(o=>{AA(o)&&o.name.endsWith(t)&&(jA(o).forEach(s=>e.setAttribute(...s)),setTimeout(n))})})}function FA(e){let t="unknown",n="unknown",r="";for(const o of e){if(o==="/"){[t,n]=e.split("/");break}if(!isNaN(Number(o))){t=r==="h"?"http":r,n=e.split(r)[1];break}r+=o}return r===e&&(t=r),{name:t,version:n}}function Rr(e=0){return((kn||performance.timeOrigin)+e)/1e3}function jA(e){const{name:t,version:n}=FA(e.nextHopProtocol),r=[];return r.push(["network.protocol.version",n],["network.protocol.name",t]),kn?[...r,["http.request.redirect_start",Rr(e.redirectStart)],["http.request.fetch_start",Rr(e.fetchStart)],["http.request.domain_lookup_start",Rr(e.domainLookupStart)],["http.request.domain_lookup_end",Rr(e.domainLookupEnd)],["http.request.connect_start",Rr(e.connectStart)],["http.request.secure_connection_start",Rr(e.secureConnectionStart)],["http.request.connection_end",Rr(e.connectEnd)],["http.request.request_start",Rr(e.requestStart)],["http.request.response_start",Rr(e.responseStart)],["http.request.response_end",Rr(e.responseEnd)]]:r}function LA(e,t){return Il(e,t||My)}function VA(e,t,n,r){const o=e.xhr,i=o&&o[ti];if(!Nl()||!o||o.__sentry_own_request__||!i)return;const s=t(i.url);if(e.endTimestamp&&s){const d=o.__sentry_xhr_span_id__;if(!d)return;const f=r[d];f&&i.status_code!==void 0&&(Eb(f,i.status_code),f.end(),delete r[d]);return}const a=pn(),l=$o(),c=s?DT({name:`${i.method} ${i.url}`,onlyIfParent:!0,attributes:{type:"xhr","http.method":i.method,url:i.url,[la]:"auto.http.browser"},op:"http.client"}):void 0;c&&(o.__sentry_xhr_span_id__=c.spanContext().spanId,r[o.__sentry_xhr_span_id__]=c);const u=ke();if(o.setRequestHeader&&n(i.url)&&u){const{traceId:d,spanId:f,sampled:h,dsc:m}={...l.getPropagationContext(),...a.getPropagationContext()},v=c?Op(c):vb(d,f,h),S=ST(m||(c?tl(c):Mp(d,u,a)));zA(o,v,S)}return c}function zA(e,t,n){try{e.setRequestHeader("sentry-trace",t),n&&e.setRequestHeader(Ry,n)}catch{}}const BA="BrowserTracing",HA={...Vf,instrumentNavigation:!0,instrumentPageLoad:!0,markBackgroundSpan:!0,enableLongTask:!0,enableInp:!1,_experiments:{},...Dy},UA=(e={})=>{const t=Xe?!!(e.tracePropagationTargets||e.tracingOrigins):!1;iD(),!e.tracePropagationTargets&&e.tracingOrigins&&(e.tracePropagationTargets=e.tracingOrigins);const n={...HA,...e},r=gA(),o={};n.enableInp&&bA(o),n.enableLongTask&&vA(),n._experiments.enableInteractions&&yA();const i={name:void 0,context:void 0};function s(a){const l=Mt(),{beforeStartSpan:c,idleTimeout:u,finalTimeout:d,heartbeatInterval:f}=n,h=a.op==="pageload";let m;if(h){const b=h?y_("sentry-trace"):"",w=h?y_("baggage"):void 0,{traceId:x,dsc:_,parentSpanId:E,sampled:C}=uM(b,w);m={traceId:x,parentSpanId:E,parentSampled:C,...a,metadata:{...a.metadata,dynamicSamplingContext:_},trimEnd:!0}}else m={trimEnd:!0,...a};const v=c?c(m):m;v.metadata=v.name!==m.name?{...v.metadata,source:"custom"}:v.metadata,i.name=v.name,i.context=v,v.sampled===!1&&Xe&&j.log(`[Tracing] Will not send ${v.op} transaction because of beforeNavigate.`),Xe&&j.log(`[Tracing] Starting ${v.op} transaction on scope`);const{location:S}=Se,y=BT(l,v,u,d,!0,{location:S},f,h);return h&&Se.document&&(Se.document.addEventListener("readystatechange",()=>{["interactive","complete"].includes(Se.document.readyState)&&y.sendAutoFinishSignal()}),["interactive","complete"].includes(Se.document.readyState)&&y.sendAutoFinishSignal()),y.registerBeforeFinishCallback(b=>{r(),EA(b)}),y}return{name:BA,setupOnce:()=>{},afterAllSetup(a){const l=a.getOptions(),{markBackgroundSpan:c,traceFetch:u,traceXHR:d,shouldCreateSpanForRequest:f,enableHTTPTimings:h,_experiments:m}=n,v=l&&l.tracePropagationTargets,S=v||n.tracePropagationTargets;Xe&&t&&v&&j.warn("[Tracing] The `tracePropagationTargets` option was set in the BrowserTracing integration and top level `Sentry.init`. The top level `Sentry.init` value is being used.");let y,b=Se.location&&Se.location.href;if(a.on&&(a.on("startNavigationSpan",w=>{y&&(Xe&&j.log(`[Tracing] Finishing current transaction with op: ${pt(y).op}`),y.end()),y=s({op:"navigation",...w})}),a.on("startPageLoadSpan",w=>{y&&(Xe&&j.log(`[Tracing] Finishing current transaction with op: ${pt(y).op}`),y.end()),y=s({op:"pageload",...w})})),n.instrumentPageLoad&&a.emit&&Se.location){const w={name:Se.location.pathname,startTimestamp:kn?kn/1e3:void 0,origin:"auto.pageload.browser",attributes:{[ho]:"url"}};WA(a,w)}n.instrumentNavigation&&a.emit&&Se.location&&$p(({to:w,from:x})=>{if(x===void 0&&b&&b.indexOf(w)!==-1){b=void 0;return}if(x!==w){b=void 0;const _={name:Se.location.pathname,origin:"auto.navigation.browser",attributes:{[ho]:"url"}};GA(a,_)}}),c&&KD(),m.enableInteractions&&qA(n,i),n.enableInp&&QA(o,i),DA({traceFetch:u,traceXHR:d,tracePropagationTargets:S,shouldCreateSpanForRequest:f,enableHTTPTimings:h})},options:n}};function WA(e,t){if(!e.emit)return;e.emit("startPageLoadSpan",t);const n=Cb();return(n&&pt(n).op)==="pageload"?n:void 0}function GA(e,t){if(!e.emit)return;e.emit("startNavigationSpan",t);const n=Cb();return(n&&pt(n).op)==="navigation"?n:void 0}function y_(e){const t=g9(`meta[name=${e}]`);return t?t.getAttribute("content"):void 0}function qA(e,t){let n;const r=()=>{const{idleTimeout:o,finalTimeout:i,heartbeatInterval:s}=e,a="ui.action.click",l=Os();if(l&&l.op&&["navigation","pageload"].includes(l.op)){Xe&&j.warn(`[Tracing] Did not create ${a} transaction because a pageload or navigation transaction is in progress.`);return}if(n&&(n.setFinishReason("interactionInterrupted"),n.end(),n=void 0),!t.name){Xe&&j.warn(`[Tracing] Did not create ${a} transaction because _latestRouteName is missing.`);return}const{location:c}=Se,u={name:t.name,op:a,trimEnd:!0,data:{[ho]:t.context?XA(t.context):"url"}};n=BT(Mt(),u,o,i,!0,{location:c},s)};["click"].forEach(o=>{addEventListener(o,r,{once:!1,capture:!0})})}function KA(e){return"duration"in e}const YA=10;function QA(e,t){Xu("event",({entries:n})=>{const r=ke(),o=r!==void 0&&r.getIntegrationByName!==void 0?r.getIntegrationByName("Replay"):void 0,i=o!==void 0?o.getReplayId():void 0,s=Os(),a=pn(),l=a!==void 0?a.getUser():void 0;for(const c of n)if(KA(c)){const u=c.duration,d=Object.keys(e),f=d.length>0?d.reduce((h,m)=>e[h].duratione[f].duration){const h=c.interactionId,m=t.name,v=t.context;h&&m&&v&&(f&&Object.keys(e).length>=YA&&delete e[f],e[h]={routeName:m,duration:u,parentContext:v,user:l,activeTransaction:s,replayId:i})}}})}function XA(e){const t=e.attributes&&e.attributes[ho],n=e.data&&e.data[ho],r=e.metadata&&e.metadata.source;return t||n||r}const Ee=we;let Ay=0;function d5(){return Ay>0}function ZA(){Ay++,setTimeout(()=>{Ay--})}function rl(e,t={},n){if(typeof e!="function")return e;try{const o=e.__sentry_wrapped__;if(o)return o;if(hb(e))return e}catch{return e}const r=function(){const o=Array.prototype.slice.call(arguments);try{n&&typeof n=="function"&&n.apply(this,arguments);const i=o.map(s=>rl(s,t));return e.apply(this,i)}catch(i){throw ZA(),_b(s=>{s.addEventProcessor(a=>(t.mechanism&&(wy(a,void 0,void 0),iu(a,t.mechanism)),a.extra={...a.extra,arguments:o},a)),Ol(i)}),i}};try{for(const o in e)Object.prototype.hasOwnProperty.call(e,o)&&(r[o]=e[o])}catch{}lT(r,e),ys(e,"__sentry_wrapped__",r);try{Object.getOwnPropertyDescriptor(r,"name").configurable&&Object.defineProperty(r,"name",{get(){return e.name}})}catch{}return r}const Vn=typeof __SENTRY_DEBUG__>"u"||__SENTRY_DEBUG__;function f5(e,t){const n=Rb(e,t),r={type:t&&t.name,value:nF(t)};return n.length&&(r.stacktrace={frames:n}),r.type===void 0&&r.value===""&&(r.value="Unrecoverable error caught"),r}function JA(e,t,n,r){const o=ke(),i=o&&o.getOptions().normalizeDepth,s={exception:{values:[{type:Rp(t)?t.constructor.name:r?"UnhandledRejection":"Error",value:iF(t,{isUnhandledRejection:r})}]},extra:{__serialized__:yT(t,i)}};if(n){const a=Rb(e,n);a.length&&(s.exception.values[0].stacktrace={frames:a})}return s}function Cg(e,t){return{exception:{values:[f5(e,t)]}}}function Rb(e,t){const n=t.stacktrace||t.stack||"",r=tF(t);try{return e(n,r)}catch{}return[]}const eF=/Minified React error #\d+;/i;function tF(e){if(e){if(typeof e.framesToPop=="number")return e.framesToPop;if(eF.test(e.message))return 1}return 0}function nF(e){const t=e&&e.message;return t?t.error&&typeof t.error.message=="string"?t.error.message:t:"No error message"}function rF(e,t,n,r){const o=n&&n.syntheticException||void 0,i=Ib(e,t,o,r);return iu(i),i.level="error",n&&n.event_id&&(i.event_id=n.event_id),el(i)}function oF(e,t,n="info",r,o){const i=r&&r.syntheticException||void 0,s=Fy(e,t,i,o);return s.level=n,r&&r.event_id&&(s.event_id=r.event_id),el(s)}function Ib(e,t,n,r,o){let i;if(cb(t)&&t.error)return Cg(e,t.error);if(Dx(t)||a9(t)){const s=t;if("stack"in t)i=Cg(e,t);else{const a=s.name||(Dx(s)?"DOMError":"DOMException"),l=s.message?`${a}: ${s.message}`:a;i=Fy(e,l,n,r),wy(i,l)}return"code"in s&&(i.tags={...i.tags,"DOMException.code":`${s.code}`}),i}return lb(t)?Cg(e,t):Ja(t)||Rp(t)?(i=JA(e,t,n,o),iu(i,{synthetic:!0}),i):(i=Fy(e,t,n,r),wy(i,`${t}`,void 0),iu(i,{synthetic:!0}),i)}function Fy(e,t,n,r){const o={};if(r&&n){const i=Rb(e,n);i.length&&(o.exception={values:[{value:t,stacktrace:{frames:i}}]})}if(ub(t)){const{__sentry_template_string__:i,__sentry_template_values__:s}=t;return o.logentry={message:i,params:s},o}return o.message=t,o}function iF(e,{isUnhandledRejection:t}){const n=E9(e),r=t?"promise rejection":"exception";return cb(e)?`Event \`ErrorEvent\` captured as ${r} with message \`${e.message}\``:Rp(e)?`Event \`${sF(e)}\` (type=${e.type}) captured as ${r}`:`Object captured as ${r} with keys: ${n}`}function sF(e){try{const t=Object.getPrototypeOf(e);return t?t.constructor.name:void 0}catch{}}function aF(e,{metadata:t,tunnel:n,dsn:r}){const o={event_id:e.event_id,sent_at:new Date().toISOString(),...t&&t.sdk&&{sdk:{name:t.sdk.name,version:t.sdk.version}},...!!n&&!!r&&{dsn:Pl(r)}},i=lF(e);return Ai(o,[i])}function lF(e){return[{type:"user_report"},e]}class cF extends SD{constructor(t){const n=Ee.SENTRY_SDK_SOURCE||G9();YT(t,"browser",["browser"],n),super(t),t.sendClientReports&&Ee.document&&Ee.document.addEventListener("visibilitychange",()=>{Ee.document.visibilityState==="hidden"&&this._flushOutcomes()})}eventFromException(t,n){return rF(this._options.stackParser,t,n,this._options.attachStacktrace)}eventFromMessage(t,n="info",r){return oF(this._options.stackParser,t,n,r,this._options.attachStacktrace)}captureUserFeedback(t){if(!this._isEnabled()){Vn&&j.warn("SDK not enabled, will not capture user feedback.");return}const n=aF(t,{metadata:this.getSdkMetadata(),dsn:this.getDsn(),tunnel:this.getOptions().tunnel});this._sendEnvelope(n)}_prepareEvent(t,n,r){return t.platform=t.platform||"javascript",super._prepareEvent(t,n,r)}_flushOutcomes(){const t=this._clearOutcomes();if(t.length===0){Vn&&j.log("No outcomes to send");return}if(!this._dsn){Vn&&j.log("No dsn provided, will not send outcomes");return}Vn&&j.log("Sending outcomes:",t);const n=gM(t,this._options.tunnel&&Pl(this._dsn));this._sendEnvelope(n)}}let kc;function uF(){if(kc)return kc;if(Ey(Ee.fetch))return kc=Ee.fetch.bind(Ee);const e=Ee.document;let t=Ee.fetch;if(e&&typeof e.createElement=="function")try{const n=e.createElement("iframe");n.hidden=!0,e.head.appendChild(n);const r=n.contentWindow;r&&r.fetch&&(t=r.fetch),e.head.removeChild(n)}catch(n){Vn&&j.warn("Could not create sandbox iframe for pure fetch check, bailing to window.fetch: ",n)}return kc=t.bind(Ee)}function dF(){kc=void 0}function fF(e,t=uF()){let n=0,r=0;function o(i){const s=i.body.length;n+=s,r++;const a={body:i.body,method:"POST",referrerPolicy:"origin",headers:e.headers,keepalive:n<=6e4&&r<15,...e.fetchOptions};try{return t(e.url,a).then(l=>(n-=s,r--,{statusCode:l.status,headers:{"x-sentry-rate-limits":l.headers.get("X-Sentry-Rate-Limits"),"retry-after":l.headers.get("Retry-After")}}))}catch(l){return dF(),n-=s,r--,gb(l)}}return KT(e,o)}const hF=4;function pF(e){function t(n){return new wn((r,o)=>{const i=new XMLHttpRequest;i.onerror=o,i.onreadystatechange=()=>{i.readyState===hF&&r({statusCode:i.status,headers:{"x-sentry-rate-limits":i.getResponseHeader("X-Sentry-Rate-Limits"),"retry-after":i.getResponseHeader("Retry-After")}})},i.open("POST",e.url);for(const s in e.headers)Object.prototype.hasOwnProperty.call(e.headers,s)&&i.setRequestHeader(s,e.headers[s]);i.send(n.body)})}return KT(e,t)}const Lp="?",mF=30,gF=40,vF=50;function $b(e,t,n,r){const o={filename:e,function:t,in_app:!0};return n!==void 0&&(o.lineno=n),r!==void 0&&(o.colno=r),o}const yF=/^\s*at (?:(.+?\)(?: \[.+\])?|.*?) ?\((?:address at )?)?(?:async )?((?:|[-a-z]+:|.*bundle|\/)?.*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i,bF=/\((\S*)(?::(\d+))(?::(\d+))\)/,wF=e=>{const t=yF.exec(e);if(t){if(t[2]&&t[2].indexOf("eval")===0){const i=bF.exec(t[2]);i&&(t[2]=i[1],t[3]=i[2],t[4]=i[3])}const[r,o]=h5(t[1]||Lp,t[2]);return $b(o,r,t[3]?+t[3]:void 0,t[4]?+t[4]:void 0)}},SF=[mF,wF],xF=/^\s*(.*?)(?:\((.*?)\))?(?:^|@)?((?:[-a-z]+)?:\/.*?|\[native code\]|[^@]*(?:bundle|\d+\.js)|\/[\w\-. /=]+)(?::(\d+))?(?::(\d+))?\s*$/i,_F=/(\S+) line (\d+)(?: > eval line \d+)* > eval/i,EF=e=>{const t=xF.exec(e);if(t){if(t[3]&&t[3].indexOf(" > eval")>-1){const i=_F.exec(t[3]);i&&(t[1]=t[1]||"eval",t[3]=i[1],t[4]=i[2],t[5]="")}let r=t[3],o=t[1]||Lp;return[o,r]=h5(o,r),$b(r,o,t[4]?+t[4]:void 0,t[5]?+t[5]:void 0)}},CF=[vF,EF],kF=/^\s*at (?:((?:\[object object\])?.+) )?\(?((?:[-a-z]+):.*?):(\d+)(?::(\d+))?\)?\s*$/i,TF=e=>{const t=kF.exec(e);return t?$b(t[2],t[1]||Lp,+t[3],t[4]?+t[4]:void 0):void 0},RF=[gF,TF],IF=[SF,CF,RF],$F=dT(...IF),h5=(e,t)=>{const n=e.indexOf("safari-extension")!==-1,r=e.indexOf("safari-web-extension")!==-1;return n||r?[e.indexOf("@")!==-1?e.split("@")[0]:Lp,n?`safari-extension:${t}`:`safari-web-extension:${t}`]:[e,t]},Hd=1024,p5="Breadcrumbs",PF=(e={})=>{const t={console:!0,dom:!0,fetch:!0,history:!0,sentry:!0,xhr:!0,...e};return{name:p5,setupOnce(){},setup(n){t.console&&R9(MF(n)),t.dom&&pT(NF(n,t.dom)),t.xhr&&mb(DF(n)),t.fetch&&pb(AF(n)),t.history&&$p(FF(n)),t.sentry&&n.on&&n.on("beforeSendEvent",OF(n))}}},m5=PF;Fi(p5,m5);function OF(e){return function(n){ke()===e&&wi({category:`sentry.${n.type==="transaction"?"transaction":"event"}`,event_id:n.event_id,level:n.level,message:Zo(n)},{event:n})}}function NF(e,t){return function(r){if(ke()!==e)return;let o,i,s=typeof t=="object"?t.serializeAttribute:void 0,a=typeof t=="object"&&typeof t.maxStringLength=="number"?t.maxStringLength:void 0;a&&a>Hd&&(Vn&&j.warn(`\`dom.maxStringLength\` cannot exceed ${Hd}, but a value of ${a} was configured. Sentry will use ${Hd} instead.`),a=Hd),typeof s=="string"&&(s=[s]);try{const c=r.event,u=jF(c)?c.target:c;o=bi(u,{keyAttrs:s,maxStringLength:a}),i=iT(u)}catch{o=""}if(o.length===0)return;const l={category:`ui.${r.name}`,message:o};i&&(l.data={"ui.component_name":i}),wi(l,{event:r.event,name:r.name,global:r.global})}}function MF(e){return function(n){if(ke()!==e)return;const r={category:"console",data:{arguments:n.args,logger:"console"},level:nM(n.level),message:Ax(n.args," ")};if(n.level==="assert")if(n.args[0]===!1)r.message=`Assertion failed: ${Ax(n.args.slice(1)," ")||"console.assert"}`,r.data.arguments=n.args.slice(1);else return;wi(r,{input:n.args,level:n.level})}}function DF(e){return function(n){if(ke()!==e)return;const{startTimestamp:r,endTimestamp:o}=n,i=n.xhr[ti];if(!r||!o||!i)return;const{method:s,url:a,status_code:l,body:c}=i,u={method:s,url:a,status_code:l},d={xhr:n.xhr,input:c,startTimestamp:r,endTimestamp:o};wi({category:"xhr",data:u,type:"http"},d)}}function AF(e){return function(n){if(ke()!==e)return;const{startTimestamp:r,endTimestamp:o}=n;if(o&&!(n.fetchData.url.match(/sentry_key/)&&n.fetchData.method==="POST"))if(n.error){const i=n.fetchData,s={data:n.error,input:n.args,startTimestamp:r,endTimestamp:o};wi({category:"fetch",data:i,level:"error",type:"http"},s)}else{const i=n.response,s={...n.fetchData,status_code:i&&i.status},a={input:n.args,response:i,startTimestamp:r,endTimestamp:o};wi({category:"fetch",data:s,type:"http"},a)}}}function FF(e){return function(n){if(ke()!==e)return;let r=n.from,o=n.to;const i=Lf(Ee.location.href);let s=r?Lf(r):void 0;const a=Lf(o);(!s||!s.path)&&(s=i),i.protocol===a.protocol&&i.host===a.host&&(o=a.relative),i.protocol===s.protocol&&i.host===s.host&&(r=s.relative),wi({category:"navigation",data:{from:r,to:o}})}}function jF(e){return!!e&&!!e.target}const g5="Dedupe",LF=()=>{let e;return{name:g5,setupOnce(){},processEvent(t){if(t.type)return t;try{if(VF(t,e))return Vn&&j.warn("Event dropped due to being a duplicate of previously captured event."),null}catch{}return e=t}}},v5=LF;Fi(g5,v5);function VF(e,t){return t?!!(zF(e,t)||BF(e,t)):!1}function zF(e,t){const n=e.message,r=t.message;return!(!n&&!r||n&&!r||!n&&r||n!==r||!b5(e,t)||!y5(e,t))}function BF(e,t){const n=b_(t),r=b_(e);return!(!n||!r||n.type!==r.type||n.value!==r.value||!b5(e,t)||!y5(e,t))}function y5(e,t){let n=w_(e),r=w_(t);if(!n&&!r)return!0;if(n&&!r||!n&&r||(n=n,r=r,r.length!==n.length))return!1;for(let o=0;o{const t={onerror:!0,onunhandledrejection:!0,...e};return{name:w5,setupOnce(){Error.stackTraceLimit=50},setup(n){t.onerror&&(UF(n),S_("onerror")),t.onunhandledrejection&&(WF(n),S_("onunhandledrejection"))}}},S5=HF;Fi(w5,S5);function UF(e){gT(t=>{const{stackParser:n,attachStacktrace:r}=_5();if(ke()!==e||d5())return;const{msg:o,url:i,line:s,column:a,error:l}=t,c=l===void 0&&Vr(o)?KF(o,i,s,a):x5(Ib(n,l||o,void 0,r,!1),i,s,a);c.level="error",RT(c,{originalException:l,mechanism:{handled:!1,type:"onerror"}})})}function WF(e){vT(t=>{const{stackParser:n,attachStacktrace:r}=_5();if(ke()!==e||d5())return;const o=GF(t),i=db(o)?qF(o):Ib(n,o,void 0,r,!0);i.level="error",RT(i,{originalException:o,mechanism:{handled:!1,type:"onunhandledrejection"}})})}function GF(e){if(db(e))return e;const t=e;try{if("reason"in t)return t.reason;if("detail"in t&&"reason"in t.detail)return t.detail.reason}catch{}return e}function qF(e){return{exception:{values:[{type:"UnhandledRejection",value:`Non-Error promise rejection captured with value: ${String(e)}`}]}}}function KF(e,t,n,r){const o=/^(?:[Uu]ncaught (?:exception: )?)?(?:((?:Eval|Internal|Range|Reference|Syntax|Type|URI|)Error): )?(.*)$/i;let i=cb(e)?e.message:e,s="Error";const a=i.match(o);return a&&(s=a[1],i=a[2]),x5({exception:{values:[{type:s,value:i}]}},t,n,r)}function x5(e,t,n,r){const o=e.exception=e.exception||{},i=o.values=o.values||[],s=i[0]=i[0]||{},a=s.stacktrace=s.stacktrace||{},l=a.frames=a.frames||[],c=isNaN(parseInt(r,10))?void 0:r,u=isNaN(parseInt(n,10))?void 0:n,d=Vr(t)&&t.length>0?t:oT();return l.length===0&&l.push({colno:c,filename:d,function:"?",in_app:!0,lineno:u}),e}function S_(e){Vn&&j.log(`Global Handler attached: ${e}`)}function _5(){const e=ke();return e&&e.getOptions()||{stackParser:()=>[],attachStacktrace:!1}}const E5="HttpContext",YF=()=>({name:E5,setupOnce(){},preprocessEvent(e){if(!Ee.navigator&&!Ee.location&&!Ee.document)return;const t=e.request&&e.request.url||Ee.location&&Ee.location.href,{referrer:n}=Ee.document||{},{userAgent:r}=Ee.navigator||{},o={...e.request&&e.request.headers,...n&&{Referer:n},...r&&{"User-Agent":r}},i={...e.request,...t&&{url:t},headers:o};e.request=i}}),C5=YF;Fi(E5,C5);const QF="cause",XF=5,k5="LinkedErrors",ZF=(e={})=>{const t=e.limit||XF,n=e.key||QF;return{name:k5,setupOnce(){},preprocessEvent(r,o,i){const s=i.getOptions();f9(f5,s.stackParser,s.maxValueLength,n,t,r,o)}}},T5=ZF;Fi(k5,T5);const JF=["EventTarget","Window","Node","ApplicationCache","AudioTrackList","BroadcastChannel","ChannelMergerNode","CryptoOperation","EventSource","FileReader","HTMLUnknownElement","IDBDatabase","IDBRequest","IDBTransaction","KeyOperation","MediaController","MessagePort","ModalWindow","Notification","SVGElementInstance","Screen","SharedWorker","TextTrack","TextTrackCue","TextTrackList","WebSocket","WebSocketWorker","Worker","XMLHttpRequest","XMLHttpRequestEventTarget","XMLHttpRequestUpload"],R5="TryCatch",ej=(e={})=>{const t={XMLHttpRequest:!0,eventTarget:!0,requestAnimationFrame:!0,setInterval:!0,setTimeout:!0,...e};return{name:R5,setupOnce(){t.setTimeout&&Et(Ee,"setTimeout",x_),t.setInterval&&Et(Ee,"setInterval",x_),t.requestAnimationFrame&&Et(Ee,"requestAnimationFrame",tj),t.XMLHttpRequest&&"XMLHttpRequest"in Ee&&Et(XMLHttpRequest.prototype,"send",nj);const n=t.eventTarget;n&&(Array.isArray(n)?n:JF).forEach(rj)}}},I5=ej;Fi(R5,I5);function x_(e){return function(...t){const n=t[0];return t[0]=rl(n,{mechanism:{data:{function:yo(e)},handled:!1,type:"instrument"}}),e.apply(this,t)}}function tj(e){return function(t){return e.apply(this,[rl(t,{mechanism:{data:{function:"requestAnimationFrame",handler:yo(e)},handled:!1,type:"instrument"}})])}}function nj(e){return function(...t){const n=this;return["onload","onerror","onprogress","onreadystatechange"].forEach(o=>{o in n&&typeof n[o]=="function"&&Et(n,o,function(i){const s={mechanism:{data:{function:o,handler:yo(i)},handled:!1,type:"instrument"}},a=hb(i);return a&&(s.mechanism.data.handler=yo(a)),rl(i,s)})}),e.apply(this,t)}}function rj(e){const t=Ee,n=t[e]&&t[e].prototype;!n||!n.hasOwnProperty||!n.hasOwnProperty("addEventListener")||(Et(n,"addEventListener",function(r){return function(o,i,s){try{typeof i.handleEvent=="function"&&(i.handleEvent=rl(i.handleEvent,{mechanism:{data:{function:"handleEvent",handler:yo(i),target:e},handled:!1,type:"instrument"}}))}catch{}return r.apply(this,[o,rl(i,{mechanism:{data:{function:"addEventListener",handler:yo(i),target:e},handled:!1,type:"instrument"}}),s])}}),Et(n,"removeEventListener",function(r){return function(o,i,s){const a=i;try{const l=a&&a.__sentry_wrapped__;l&&r.call(this,o,l,s)}catch{}return r.call(this,o,a,s)}}))}const oj=[XT(),JT(),I5(),m5(),S5(),T5(),v5(),C5()];function ij(e){return[...oj]}function sj(e={}){e.defaultIntegrations===void 0&&(e.defaultIntegrations=ij()),e.release===void 0&&(typeof __SENTRY_RELEASE__=="string"&&(e.release=__SENTRY_RELEASE__),Ee.SENTRY_RELEASE&&Ee.SENTRY_RELEASE.id&&(e.release=Ee.SENTRY_RELEASE.id)),e.autoSessionTracking===void 0&&(e.autoSessionTracking=!0),e.sendClientReports===void 0&&(e.sendClientReports=!0);const t={...e,stackParser:k9(e.stackParser||$F),integrations:mD(e),transport:e.transport||(mT()?fF:pF)};CD(cF,t),e.autoSessionTracking&&aj()}const __=(e={},t=Mt())=>{if(!Ee.document){Vn&&j.error("Global document not defined in showReportDialog call");return}const{client:n,scope:r}=t.getStackTop(),o=e.dsn||n&&n.getDsn();if(!o){Vn&&j.error("DSN not configured for showReportDialog call");return}r&&(e.user={...r.getUser(),...e.user}),e.eventId||(e.eventId=t.lastEventId());const i=Ee.document.createElement("script");i.async=!0,i.crossOrigin="anonymous",i.src=hD(o,e),e.onLoad&&(i.onload=e.onLoad);const{onClose:s}=e;if(s){const l=c=>{if(c.data==="__sentry_reportdialog_closed__")try{s()}finally{Ee.removeEventListener("message",l)}};Ee.addEventListener("message",l)}const a=Ee.document.head||Ee.document.body;a?a.appendChild(i):Vn&&j.error("Not injecting report dialog. No injection point found in HTML")};function aj(){if(typeof Ee.document>"u"){Vn&&j.warn("Session tracking in non-browser environment with @sentry/browser is not supported.");return}Jx({ignoreDuration:!0}),e_(),$p(({from:e,to:t})=>{e!==void 0&&e!==t&&(Jx({ignoreDuration:!0}),e_())})}const Le=we,Pb="sentryReplaySession",lj="replay_event",Ob="Unable to send Replay",cj=3e5,uj=9e5,dj=5e3,fj=5500,hj=6e4,pj=5e3,mj=3,E_=15e4,Ud=5e3,gj=3e3,vj=300,Nb=2e7,yj=4999,bj=15e3,C_=36e5;function wj(e,t){return e??t()}function Sh(e){let t,n=e[0],r=1;for(;rn.call(t,...s)),t=void 0)}return n}var yt;(function(e){e[e.Document=0]="Document",e[e.DocumentType=1]="DocumentType",e[e.Element=2]="Element",e[e.Text=3]="Text",e[e.CDATA=4]="CDATA",e[e.Comment=5]="Comment"})(yt||(yt={}));function Sj(e){return e.nodeType===e.ELEMENT_NODE}function Dc(e){const t=Sh([e,"optionalAccess",n=>n.host]);return Sh([t,"optionalAccess",n=>n.shadowRoot])===e}function Ac(e){return Object.prototype.toString.call(e)==="[object ShadowRoot]"}function xj(e){return e.includes(" background-clip: text;")&&!e.includes(" -webkit-background-clip: text;")&&(e=e.replace(" background-clip: text;"," -webkit-background-clip: text; background-clip: text;")),e}function _j(e){const{cssText:t}=e;if(t.split('"').length<3)return t;const n=["@import",`url(${JSON.stringify(e.href)})`];return e.layerName===""?n.push("layer"):e.layerName&&n.push(`layer(${e.layerName})`),e.supportsText&&n.push(`supports(${e.supportsText})`),e.media.length&&n.push(e.media.mediaText),n.join(" ")+";"}function xh(e){try{const t=e.rules||e.cssRules;return t?xj(Array.from(t,$5).join("")):null}catch{return null}}function $5(e){let t;if(Cj(e))try{t=xh(e.styleSheet)||_j(e)}catch{}else if(kj(e)&&e.selectorText.includes(":"))return Ej(e.cssText);return t||e.cssText}function Ej(e){const t=/(\[(?:[\w-]+)[^\\])(:(?:[\w-]+)\])/gm;return e.replace(t,"$1\\$2")}function Cj(e){return"styleSheet"in e}function kj(e){return"selectorText"in e}class P5{constructor(){this.idNodeMap=new Map,this.nodeMetaMap=new WeakMap}getId(t){if(!t)return-1;const n=Sh([this,"access",r=>r.getMeta,"call",r=>r(t),"optionalAccess",r=>r.id]);return wj(n,()=>-1)}getNode(t){return this.idNodeMap.get(t)||null}getIds(){return Array.from(this.idNodeMap.keys())}getMeta(t){return this.nodeMetaMap.get(t)||null}removeNodeFromMap(t){const n=this.getId(t);this.idNodeMap.delete(n),t.childNodes&&t.childNodes.forEach(r=>this.removeNodeFromMap(r))}has(t){return this.idNodeMap.has(t)}hasNode(t){return this.nodeMetaMap.has(t)}add(t,n){const r=n.id;this.idNodeMap.set(r,t),this.nodeMetaMap.set(t,n)}replace(t,n){const r=this.getNode(t);if(r){const o=this.nodeMetaMap.get(r);o&&this.nodeMetaMap.set(n,o)}this.idNodeMap.set(t,n)}reset(){this.idNodeMap=new Map,this.nodeMetaMap=new WeakMap}}function Tj(){return new P5}function Vp({maskInputOptions:e,tagName:t,type:n}){return t==="OPTION"&&(t="SELECT"),!!(e[t.toLowerCase()]||n&&e[n]||n==="password"||t==="INPUT"&&!n&&e.text)}function su({isMasked:e,element:t,value:n,maskInputFn:r}){let o=n||"";return e?(r&&(o=r(o,t)),"*".repeat(o.length)):o}function ol(e){return e.toLowerCase()}function jy(e){return e.toUpperCase()}const k_="__rrweb_original__";function Rj(e){const t=e.getContext("2d");if(!t)return!0;const n=50;for(let r=0;rl!==0))return!1}return!0}function Mb(e){const t=e.type;return e.hasAttribute("data-rr-is-password")?"password":t?ol(t):null}function _h(e,t,n){return t==="INPUT"&&(n==="radio"||n==="checkbox")?e.getAttribute("value")||"":e.value}let Ij=1;const $j=new RegExp("[^a-z0-9-_:]"),au=-2;function Db(){return Ij++}function Pj(e){if(e instanceof HTMLFormElement)return"form";const t=ol(e.tagName);return $j.test(t)?"div":t}function Oj(e){let t="";return e.indexOf("//")>-1?t=e.split("/").slice(0,3).join("/"):t=e.split("/")[0],t=t.split("?")[0],t}let Ws,T_;const Nj=/url\((?:(')([^']*)'|(")(.*?)"|([^)]*))\)/gm,Mj=/^(?:[a-z+]+:)?\/\//i,Dj=/^www\..*/i,Aj=/^(data:)([^,]*),(.*)/i;function Eh(e,t){return(e||"").replace(Nj,(n,r,o,i,s,a)=>{const l=o||s||a,c=r||i||"";if(!l)return n;if(Mj.test(l)||Dj.test(l))return`url(${c}${l}${c})`;if(Aj.test(l))return`url(${c}${l}${c})`;if(l[0]==="/")return`url(${c}${Oj(t)+l}${c})`;const u=t.split("/"),d=l.split("/");u.pop();for(const f of d)f!=="."&&(f===".."?u.pop():u.push(f));return`url(${c}${u.join("/")}${c})`})}const Fj=/^[^ \t\n\r\u000c]+/,jj=/^[, \t\n\r\u000c]+/;function Lj(e,t){if(t.trim()==="")return t;let n=0;function r(i){let s;const a=i.exec(t.substring(n));return a?(s=a[0],n+=s.length,s):""}const o=[];for(;r(jj),!(n>=t.length);){let i=r(Fj);if(i.slice(-1)===",")i=ca(e,i.substring(0,i.length-1)),o.push(i);else{let s="";i=ca(e,i);let a=!1;for(;;){const l=t.charAt(n);if(l===""){o.push((i+s).trim());break}else if(a)l===")"&&(a=!1);else if(l===","){n+=1,o.push((i+s).trim());break}else l==="("&&(a=!0);s+=l,n+=1}}}return o.join(", ")}function ca(e,t){if(!t||t.trim()==="")return t;const n=e.createElement("a");return n.href=t,n.href}function Vj(e){return!!(e.tagName==="svg"||e.ownerSVGElement)}function Ab(){const e=document.createElement("a");return e.href="",e.href}function O5(e,t,n,r,o,i){return r&&(n==="src"||n==="href"&&!(t==="use"&&r[0]==="#")||n==="xlink:href"&&r[0]!=="#"||n==="background"&&(t==="table"||t==="td"||t==="th")?ca(e,r):n==="srcset"?Lj(e,r):n==="style"?Eh(r,Ab()):t==="object"&&n==="data"?ca(e,r):typeof i=="function"?i(n,r,o):r)}function N5(e,t,n){return(e==="video"||e==="audio")&&t==="autoplay"}function zj(e,t,n,r){try{if(r&&e.matches(r))return!1;if(typeof t=="string"){if(e.classList.contains(t))return!0}else for(let o=e.classList.length;o--;){const i=e.classList[o];if(t.test(i))return!0}if(n)return e.matches(n)}catch{}return!1}function Bj(e,t){for(let n=e.classList.length;n--;){const r=e.classList[n];if(t.test(r))return!0}return!1}function is(e,t,n=1/0,r=0){return!e||e.nodeType!==e.ELEMENT_NODE||r>n?-1:t(e)?r:is(e.parentNode,t,n,r+1)}function ua(e,t){return n=>{const r=n;if(r===null)return!1;try{if(e){if(typeof e=="string"){if(r.matches(`.${e}`))return!0}else if(Bj(r,e))return!0}return!!(t&&r.matches(t))}catch{return!1}}}function il(e,t,n,r,o,i){try{const s=e.nodeType===e.ELEMENT_NODE?e:e.parentElement;if(s===null)return!1;if(s.tagName==="INPUT"){const c=s.getAttribute("autocomplete");if(["current-password","new-password","cc-number","cc-exp","cc-exp-month","cc-exp-year","cc-csc"].includes(c))return!0}let a=-1,l=-1;if(i){if(l=is(s,ua(r,o)),l<0)return!0;a=is(s,ua(t,n),l>=0?l:1/0)}else{if(a=is(s,ua(t,n)),a<0)return!1;l=is(s,ua(r,o),a>=0?a:1/0)}return a>=0?l>=0?a<=l:!0:l>=0?!1:!!i}catch{}return!!i}function Hj(e,t,n){const r=e.contentWindow;if(!r)return;let o=!1,i;try{i=r.document.readyState}catch{return}if(i!=="complete"){const a=setTimeout(()=>{o||(t(),o=!0)},n);e.addEventListener("load",()=>{clearTimeout(a),o=!0,t()});return}const s="about:blank";if(r.location.href!==s||e.src===s||e.src==="")return setTimeout(t,0),e.addEventListener("load",t);e.addEventListener("load",t)}function Uj(e,t,n){let r=!1,o;try{o=e.sheet}catch{return}if(o)return;const i=setTimeout(()=>{r||(t(),r=!0)},n);e.addEventListener("load",()=>{clearTimeout(i),r=!0,t()})}function Wj(e,t){const{doc:n,mirror:r,blockClass:o,blockSelector:i,unblockSelector:s,maskAllText:a,maskAttributeFn:l,maskTextClass:c,unmaskTextClass:u,maskTextSelector:d,unmaskTextSelector:f,inlineStylesheet:h,maskInputOptions:m={},maskTextFn:v,maskInputFn:S,dataURLOptions:y={},inlineImages:b,recordCanvas:w,keepIframeSrcFn:x,newlyAddedElement:_=!1}=t,E=Gj(n,r);switch(e.nodeType){case e.DOCUMENT_NODE:return e.compatMode!=="CSS1Compat"?{type:yt.Document,childNodes:[],compatMode:e.compatMode}:{type:yt.Document,childNodes:[]};case e.DOCUMENT_TYPE_NODE:return{type:yt.DocumentType,name:e.name,publicId:e.publicId,systemId:e.systemId,rootId:E};case e.ELEMENT_NODE:return Kj(e,{doc:n,blockClass:o,blockSelector:i,unblockSelector:s,inlineStylesheet:h,maskAttributeFn:l,maskInputOptions:m,maskInputFn:S,dataURLOptions:y,inlineImages:b,recordCanvas:w,keepIframeSrcFn:x,newlyAddedElement:_,rootId:E,maskAllText:a,maskTextClass:c,unmaskTextClass:u,maskTextSelector:d,unmaskTextSelector:f});case e.TEXT_NODE:return qj(e,{maskAllText:a,maskTextClass:c,unmaskTextClass:u,maskTextSelector:d,unmaskTextSelector:f,maskTextFn:v,maskInputOptions:m,maskInputFn:S,rootId:E});case e.CDATA_SECTION_NODE:return{type:yt.CDATA,textContent:"",rootId:E};case e.COMMENT_NODE:return{type:yt.Comment,textContent:e.textContent||"",rootId:E};default:return!1}}function Gj(e,t){if(!t.hasNode(e))return;const n=t.getId(e);return n===1?void 0:n}function qj(e,t){const{maskAllText:n,maskTextClass:r,unmaskTextClass:o,maskTextSelector:i,unmaskTextSelector:s,maskTextFn:a,maskInputOptions:l,maskInputFn:c,rootId:u}=t,d=e.parentNode&&e.parentNode.tagName;let f=e.textContent;const h=d==="STYLE"?!0:void 0,m=d==="SCRIPT"?!0:void 0,v=d==="TEXTAREA"?!0:void 0;if(h&&f){try{e.nextSibling||e.previousSibling||Sh([e,"access",y=>y.parentNode,"access",y=>y.sheet,"optionalAccess",y=>y.cssRules])&&(f=xh(e.parentNode.sheet))}catch(y){console.warn(`Cannot get CSS styles from text's parentNode. Error: ${y}`,e)}f=Eh(f,Ab())}m&&(f="SCRIPT_PLACEHOLDER");const S=il(e,r,i,o,s,n);if(!h&&!m&&!v&&f&&S&&(f=a?a(f):f.replace(/[\S]/g,"*")),v&&f&&(l.textarea||S)&&(f=c?c(f,e.parentNode):f.replace(/[\S]/g,"*")),d==="OPTION"&&f){const y=Vp({type:null,tagName:d,maskInputOptions:l});f=su({isMasked:il(e,r,i,o,s,y),element:e,value:f,maskInputFn:c})}return{type:yt.Text,textContent:f||"",isStyle:h,rootId:u}}function Kj(e,t){const{doc:n,blockClass:r,blockSelector:o,unblockSelector:i,inlineStylesheet:s,maskInputOptions:a={},maskAttributeFn:l,maskInputFn:c,dataURLOptions:u={},inlineImages:d,recordCanvas:f,keepIframeSrcFn:h,newlyAddedElement:m=!1,rootId:v,maskAllText:S,maskTextClass:y,unmaskTextClass:b,maskTextSelector:w,unmaskTextSelector:x}=t,_=zj(e,r,o,i),E=Pj(e);let C={};const k=e.attributes.length;for(let R=0;RO.href===e.href);let D=null;R&&(D=xh(R)),D&&(delete C.rel,delete C.href,C._cssText=Eh(D,R.href))}if(E==="style"&&e.sheet&&!(e.innerText||e.textContent||"").trim().length){const R=xh(e.sheet);R&&(C._cssText=Eh(R,Ab()))}if(E==="input"||E==="textarea"||E==="select"||E==="option"){const R=e,D=Mb(R),O=_h(R,jy(E),D),H=R.checked;if(D!=="submit"&&D!=="button"&&O){const N=il(R,y,w,b,x,Vp({type:D,tagName:jy(E),maskInputOptions:a}));C.value=su({isMasked:N,element:R,value:O,maskInputFn:c})}H&&(C.checked=H)}if(E==="option"&&(e.selected&&!a.select?C.selected=!0:delete C.selected),E==="canvas"&&f){if(e.__context==="2d")Rj(e)||(C.rr_dataURL=e.toDataURL(u.type,u.quality));else if(!("__context"in e)){const R=e.toDataURL(u.type,u.quality),D=document.createElement("canvas");D.width=e.width,D.height=e.height;const O=D.toDataURL(u.type,u.quality);R!==O&&(C.rr_dataURL=R)}}if(E==="img"&&d){Ws||(Ws=n.createElement("canvas"),T_=Ws.getContext("2d"));const R=e,D=R.crossOrigin;R.crossOrigin="anonymous";const O=()=>{R.removeEventListener("load",O);try{Ws.width=R.naturalWidth,Ws.height=R.naturalHeight,T_.drawImage(R,0,0),C.rr_dataURL=Ws.toDataURL(u.type,u.quality)}catch(H){console.warn(`Cannot inline img src=${R.currentSrc}! Error: ${H}`)}D?C.crossOrigin=D:R.removeAttribute("crossorigin")};R.complete&&R.naturalWidth!==0?O():R.addEventListener("load",O)}if((E==="audio"||E==="video")&&(C.rr_mediaState=e.paused?"paused":"played",C.rr_mediaCurrentTime=e.currentTime),m||(e.scrollLeft&&(C.rr_scrollLeft=e.scrollLeft),e.scrollTop&&(C.rr_scrollTop=e.scrollTop)),_){const{width:R,height:D}=e.getBoundingClientRect();C={class:C.class,rr_width:`${R}px`,rr_height:`${D}px`}}E==="iframe"&&!h(C.src)&&(e.contentDocument||(C.rr_src=C.src),delete C.src);let T;try{customElements.get(E)&&(T=!0)}catch{}return{type:yt.Element,tagName:E,attributes:C,childNodes:[],isSVG:Vj(e)||void 0,needBlock:_,rootId:v,isCustom:T}}function je(e){return e==null?"":e.toLowerCase()}function Yj(e,t){if(t.comment&&e.type===yt.Comment)return!0;if(e.type===yt.Element){if(t.script&&(e.tagName==="script"||e.tagName==="link"&&(e.attributes.rel==="preload"||e.attributes.rel==="modulepreload")&&e.attributes.as==="script"||e.tagName==="link"&&e.attributes.rel==="prefetch"&&typeof e.attributes.href=="string"&&e.attributes.href.endsWith(".js")))return!0;if(t.headFavicon&&(e.tagName==="link"&&e.attributes.rel==="shortcut icon"||e.tagName==="meta"&&(je(e.attributes.name).match(/^msapplication-tile(image|color)$/)||je(e.attributes.name)==="application-name"||je(e.attributes.rel)==="icon"||je(e.attributes.rel)==="apple-touch-icon"||je(e.attributes.rel)==="shortcut icon")))return!0;if(e.tagName==="meta"){if(t.headMetaDescKeywords&&je(e.attributes.name).match(/^description|keywords$/))return!0;if(t.headMetaSocial&&(je(e.attributes.property).match(/^(og|twitter|fb):/)||je(e.attributes.name).match(/^(og|twitter):/)||je(e.attributes.name)==="pinterest"))return!0;if(t.headMetaRobots&&(je(e.attributes.name)==="robots"||je(e.attributes.name)==="googlebot"||je(e.attributes.name)==="bingbot"))return!0;if(t.headMetaHttpEquiv&&e.attributes["http-equiv"]!==void 0)return!0;if(t.headMetaAuthorship&&(je(e.attributes.name)==="author"||je(e.attributes.name)==="generator"||je(e.attributes.name)==="framework"||je(e.attributes.name)==="publisher"||je(e.attributes.name)==="progid"||je(e.attributes.property).match(/^article:/)||je(e.attributes.property).match(/^product:/)))return!0;if(t.headMetaVerification&&(je(e.attributes.name)==="google-site-verification"||je(e.attributes.name)==="yandex-verification"||je(e.attributes.name)==="csrf-token"||je(e.attributes.name)==="p:domain_verify"||je(e.attributes.name)==="verify-v1"||je(e.attributes.name)==="verification"||je(e.attributes.name)==="shopify-checkout-api-token"))return!0}}return!1}function da(e,t){const{doc:n,mirror:r,blockClass:o,blockSelector:i,unblockSelector:s,maskAllText:a,maskTextClass:l,unmaskTextClass:c,maskTextSelector:u,unmaskTextSelector:d,skipChild:f=!1,inlineStylesheet:h=!0,maskInputOptions:m={},maskAttributeFn:v,maskTextFn:S,maskInputFn:y,slimDOMOptions:b,dataURLOptions:w={},inlineImages:x=!1,recordCanvas:_=!1,onSerialize:E,onIframeLoad:C,iframeLoadTimeout:k=5e3,onStylesheetLoad:T,stylesheetLoadTimeout:R=5e3,keepIframeSrcFn:D=()=>!1,newlyAddedElement:O=!1}=t;let{preserveWhiteSpace:H=!0}=t;const N=Wj(e,{doc:n,mirror:r,blockClass:o,blockSelector:i,maskAllText:a,unblockSelector:s,maskTextClass:l,unmaskTextClass:c,maskTextSelector:u,unmaskTextSelector:d,inlineStylesheet:h,maskInputOptions:m,maskAttributeFn:v,maskTextFn:S,maskInputFn:y,dataURLOptions:w,inlineImages:x,recordCanvas:_,keepIframeSrcFn:D,newlyAddedElement:O});if(!N)return console.warn(e,"not serialized"),null;let A;r.hasNode(e)?A=r.getId(e):Yj(N,b)||!H&&N.type===yt.Text&&!N.isStyle&&!N.textContent.replace(/^\s+|\s+$/gm,"").length?A=au:A=Db();const F=Object.assign(N,{id:A});if(r.add(e,F),A===au)return null;E&&E(e);let P=!f;if(F.type===yt.Element){P=P&&!F.needBlock,delete F.needBlock;const $=e.shadowRoot;$&&Ac($)&&(F.isShadowHost=!0)}if((F.type===yt.Document||F.type===yt.Element)&&P){b.headWhitespace&&F.type===yt.Element&&F.tagName==="head"&&(H=!1);const $={doc:n,mirror:r,blockClass:o,blockSelector:i,maskAllText:a,unblockSelector:s,maskTextClass:l,unmaskTextClass:c,maskTextSelector:u,unmaskTextSelector:d,skipChild:f,inlineStylesheet:h,maskInputOptions:m,maskAttributeFn:v,maskTextFn:S,maskInputFn:y,slimDOMOptions:b,dataURLOptions:w,inlineImages:x,recordCanvas:_,preserveWhiteSpace:H,onSerialize:E,onIframeLoad:C,iframeLoadTimeout:k,onStylesheetLoad:T,stylesheetLoadTimeout:R,keepIframeSrcFn:D};for(const I of Array.from(e.childNodes)){const z=da(I,$);z&&F.childNodes.push(z)}if(Sj(e)&&e.shadowRoot)for(const I of Array.from(e.shadowRoot.childNodes)){const z=da(I,$);z&&(Ac(e.shadowRoot)&&(z.isShadow=!0),F.childNodes.push(z))}}return e.parentNode&&Dc(e.parentNode)&&Ac(e.parentNode)&&(F.isShadow=!0),F.type===yt.Element&&F.tagName==="iframe"&&Hj(e,()=>{const $=e.contentDocument;if($&&C){const I=da($,{doc:$,mirror:r,blockClass:o,blockSelector:i,unblockSelector:s,maskAllText:a,maskTextClass:l,unmaskTextClass:c,maskTextSelector:u,unmaskTextSelector:d,skipChild:!1,inlineStylesheet:h,maskInputOptions:m,maskAttributeFn:v,maskTextFn:S,maskInputFn:y,slimDOMOptions:b,dataURLOptions:w,inlineImages:x,recordCanvas:_,preserveWhiteSpace:H,onSerialize:E,onIframeLoad:C,iframeLoadTimeout:k,onStylesheetLoad:T,stylesheetLoadTimeout:R,keepIframeSrcFn:D});I&&C(e,I)}},k),F.type===yt.Element&&F.tagName==="link"&&F.attributes.rel==="stylesheet"&&Uj(e,()=>{if(T){const $=da(e,{doc:n,mirror:r,blockClass:o,blockSelector:i,unblockSelector:s,maskAllText:a,maskTextClass:l,unmaskTextClass:c,maskTextSelector:u,unmaskTextSelector:d,skipChild:!1,inlineStylesheet:h,maskInputOptions:m,maskAttributeFn:v,maskTextFn:S,maskInputFn:y,slimDOMOptions:b,dataURLOptions:w,inlineImages:x,recordCanvas:_,preserveWhiteSpace:H,onSerialize:E,onIframeLoad:C,iframeLoadTimeout:k,onStylesheetLoad:T,stylesheetLoadTimeout:R,keepIframeSrcFn:D});$&&T(e,$)}},R),F}function Qj(e,t){const{mirror:n=new P5,blockClass:r="rr-block",blockSelector:o=null,unblockSelector:i=null,maskAllText:s=!1,maskTextClass:a="rr-mask",unmaskTextClass:l=null,maskTextSelector:c=null,unmaskTextSelector:u=null,inlineStylesheet:d=!0,inlineImages:f=!1,recordCanvas:h=!1,maskAllInputs:m=!1,maskAttributeFn:v,maskTextFn:S,maskInputFn:y,slimDOM:b=!1,dataURLOptions:w,preserveWhiteSpace:x,onSerialize:_,onIframeLoad:E,iframeLoadTimeout:C,onStylesheetLoad:k,stylesheetLoadTimeout:T,keepIframeSrcFn:R=()=>!1}=t||{};return da(e,{doc:e,mirror:n,blockClass:r,blockSelector:o,unblockSelector:i,maskAllText:s,maskTextClass:a,unmaskTextClass:l,maskTextSelector:c,unmaskTextSelector:u,skipChild:!1,inlineStylesheet:d,maskInputOptions:m===!0?{color:!0,date:!0,"datetime-local":!0,email:!0,month:!0,number:!0,range:!0,search:!0,tel:!0,text:!0,time:!0,url:!0,week:!0,textarea:!0,select:!0}:m===!1?{}:m,maskAttributeFn:v,maskTextFn:S,maskInputFn:y,slimDOMOptions:b===!0||b==="all"?{script:!0,comment:!0,headFavicon:!0,headWhitespace:!0,headMetaDescKeywords:b==="all",headMetaSocial:!0,headMetaRobots:!0,headMetaHttpEquiv:!0,headMetaAuthorship:!0,headMetaVerification:!0}:b===!1?{}:b,dataURLOptions:w,inlineImages:f,recordCanvas:h,preserveWhiteSpace:x,onSerialize:_,onIframeLoad:E,iframeLoadTimeout:C,onStylesheetLoad:k,stylesheetLoadTimeout:T,keepIframeSrcFn:R,newlyAddedElement:!1})}function Bo(e){let t,n=e[0],r=1;for(;rn.call(t,...s)),t=void 0)}return n}function Xt(e,t,n=document){const r={capture:!0,passive:!0};return n.addEventListener(e,t,r),()=>n.removeEventListener(e,t,r)}const na=`Please stop import mirror directly. Instead of that,\r +now you can use replayer.getMirror() to access the mirror instance of a replayer,\r +or you can use record.mirror to access the mirror instance during recording.`;let R_={map:{},getId(){return console.error(na),-1},getNode(){return console.error(na),null},removeNodeFromMap(){console.error(na)},has(){return console.error(na),!1},reset(){console.error(na)}};typeof window<"u"&&window.Proxy&&window.Reflect&&(R_=new Proxy(R_,{get(e,t,n){return t==="map"&&console.error(na),Reflect.get(e,t,n)}}));function lu(e,t,n={}){let r=null,o=0;return function(...i){const s=Date.now();!o&&n.leading===!1&&(o=s);const a=t-(s-o),l=this;a<=0||a>t?(r&&(clearTimeout(r),r=null),o=s,e.apply(l,i)):!r&&n.trailing!==!1&&(r=setTimeout(()=>{o=n.leading===!1?0:Date.now(),r=null,e.apply(l,i)},a))}}function M5(e,t,n,r,o=window){const i=o.Object.getOwnPropertyDescriptor(e,t);return o.Object.defineProperty(e,t,r?n:{set(s){setTimeout(()=>{n.set.call(this,s)},0),i&&i.set&&i.set.call(this,s)}}),()=>M5(e,t,i||{},!0)}function Fb(e,t,n){try{if(!(t in e))return()=>{};const r=e[t],o=n(r);return typeof o=="function"&&(o.prototype=o.prototype||{},Object.defineProperties(o,{__rrweb_original__:{enumerable:!1,value:r}})),e[t]=o,()=>{e[t]=r}}catch{return()=>{}}}let Ch=Date.now;/[1-9][0-9]{12}/.test(Date.now().toString())||(Ch=()=>new Date().getTime());function D5(e){const t=e.document;return{left:t.scrollingElement?t.scrollingElement.scrollLeft:e.pageXOffset!==void 0?e.pageXOffset:Bo([t,"optionalAccess",n=>n.documentElement,"access",n=>n.scrollLeft])||Bo([t,"optionalAccess",n=>n.body,"optionalAccess",n=>n.parentElement,"optionalAccess",n=>n.scrollLeft])||Bo([t,"optionalAccess",n=>n.body,"optionalAccess",n=>n.scrollLeft])||0,top:t.scrollingElement?t.scrollingElement.scrollTop:e.pageYOffset!==void 0?e.pageYOffset:Bo([t,"optionalAccess",n=>n.documentElement,"access",n=>n.scrollTop])||Bo([t,"optionalAccess",n=>n.body,"optionalAccess",n=>n.parentElement,"optionalAccess",n=>n.scrollTop])||Bo([t,"optionalAccess",n=>n.body,"optionalAccess",n=>n.scrollTop])||0}}function A5(){return window.innerHeight||document.documentElement&&document.documentElement.clientHeight||document.body&&document.body.clientHeight}function F5(){return window.innerWidth||document.documentElement&&document.documentElement.clientWidth||document.body&&document.body.clientWidth}function cr(e,t,n,r,o){if(!e)return!1;const i=e.nodeType===e.ELEMENT_NODE?e:e.parentElement;if(!i)return!1;const s=ua(t,n);if(!o){const c=r&&i.matches(r);return s(i)&&!c}const a=is(i,s);let l=-1;return a<0?!1:(r&&(l=is(i,ua(null,r))),a>-1&&l<0?!0:a{let n=t[0];if(!(0 in t))throw new TypeError("1 argument is required");do if(this===n)return!0;while(n=n&&n.parentNode);return!1})}function L5(e,t){return!!(e.nodeName==="IFRAME"&&t.getMeta(e))}function V5(e,t){return!!(e.nodeName==="LINK"&&e.nodeType===e.ELEMENT_NODE&&e.getAttribute&&e.getAttribute("rel")==="stylesheet"&&t.getMeta(e))}function Vy(e){return!!Bo([e,"optionalAccess",t=>t.shadowRoot])}class Jj{constructor(){this.id=1,this.styleIDMap=new WeakMap,this.idStyleMap=new Map}getId(t){return wM(this.styleIDMap.get(t),()=>-1)}has(t){return this.styleIDMap.has(t)}add(t,n){if(this.has(t))return this.getId(t);let r;return n===void 0?r=this.id++:r=n,this.styleIDMap.set(t,r),this.idStyleMap.set(r,t),r}getStyle(t){return this.idStyleMap.get(t)||null}reset(){this.styleIDMap=new WeakMap,this.idStyleMap=new Map,this.id=1}generateId(){return this.id++}}function z5(e){let t=null;return Bo([e,"access",n=>n.getRootNode,"optionalCall",n=>n(),"optionalAccess",n=>n.nodeType])===Node.DOCUMENT_FRAGMENT_NODE&&e.getRootNode().host&&(t=e.getRootNode().host),t}function eL(e){let t=e,n;for(;n=z5(t);)t=n;return t}function tL(e){const t=e.ownerDocument;if(!t)return!1;const n=eL(e);return t.contains(n)}function B5(e){const t=e.ownerDocument;return t?t.contains(e)||tL(e):!1}let Tg;function nL(){if(Tg)return Tg;const e=window.document;let t=window.requestAnimationFrame;if(e&&typeof e.createElement=="function")try{const n=e.createElement("iframe");n.hidden=!0,e.head.appendChild(n);const r=n.contentWindow;r&&r.requestAnimationFrame&&(t=r.requestAnimationFrame),e.head.removeChild(n)}catch{}return Tg=t.bind(window)}function rL(...e){return nL()(...e)}var fe=(e=>(e[e.DomContentLoaded=0]="DomContentLoaded",e[e.Load=1]="Load",e[e.FullSnapshot=2]="FullSnapshot",e[e.IncrementalSnapshot=3]="IncrementalSnapshot",e[e.Meta=4]="Meta",e[e.Custom=5]="Custom",e[e.Plugin=6]="Plugin",e))(fe||{}),he=(e=>(e[e.Mutation=0]="Mutation",e[e.MouseMove=1]="MouseMove",e[e.MouseInteraction=2]="MouseInteraction",e[e.Scroll=3]="Scroll",e[e.ViewportResize=4]="ViewportResize",e[e.Input=5]="Input",e[e.TouchMove=6]="TouchMove",e[e.MediaInteraction=7]="MediaInteraction",e[e.StyleSheetRule=8]="StyleSheetRule",e[e.CanvasMutation=9]="CanvasMutation",e[e.Font=10]="Font",e[e.Log=11]="Log",e[e.Drag=12]="Drag",e[e.StyleDeclaration=13]="StyleDeclaration",e[e.Selection=14]="Selection",e[e.AdoptedStyleSheet=15]="AdoptedStyleSheet",e[e.CustomElement=16]="CustomElement",e))(he||{}),qt=(e=>(e[e.MouseUp=0]="MouseUp",e[e.MouseDown=1]="MouseDown",e[e.Click=2]="Click",e[e.ContextMenu=3]="ContextMenu",e[e.DblClick=4]="DblClick",e[e.Focus=5]="Focus",e[e.Blur=6]="Blur",e[e.TouchStart=7]="TouchStart",e[e.TouchMove_Departed=8]="TouchMove_Departed",e[e.TouchEnd=9]="TouchEnd",e[e.TouchCancel=10]="TouchCancel",e))(qt||{}),Jr=(e=>(e[e.Mouse=0]="Mouse",e[e.Pen=1]="Pen",e[e.Touch=2]="Touch",e))(Jr||{});function oL(e){let t,n=e[0],r=1;for(;rn.call(t,...s)),t=void 0)}return n}function I_(e){return"__ln"in e}class iL{constructor(){this.length=0,this.head=null,this.tail=null}get(t){if(t>=this.length)throw new Error("Position outside of list range");let n=this.head;for(let r=0;ro.next])||null;return n}addNode(t){const n={value:t,previous:null,next:null};if(t.__ln=n,t.previousSibling&&I_(t.previousSibling)){const r=t.previousSibling.__ln.next;n.next=r,n.previous=t.previousSibling.__ln,t.previousSibling.__ln.next=n,r&&(r.previous=n)}else if(t.nextSibling&&I_(t.nextSibling)&&t.nextSibling.__ln.previous){const r=t.nextSibling.__ln.previous;n.previous=r,n.next=t.nextSibling.__ln,t.nextSibling.__ln.previous=n,r&&(r.next=n)}else this.head&&(this.head.previous=n),n.next=this.head,this.head=n;n.next===null&&(this.tail=n),this.length++}removeNode(t){const n=t.__ln;this.head&&(n.previous?(n.previous.next=n.next,n.next?n.next.previous=n.previous:this.tail=n.previous):(this.head=n.next,this.head?this.head.previous=null:this.tail=null),t.__ln&&delete t.__ln,this.length--)}}const $_=(e,t)=>`${e}@${t}`;class sL{constructor(){this.frozen=!1,this.locked=!1,this.texts=[],this.attributes=[],this.removes=[],this.mapRemoves=[],this.movedMap={},this.addedSet=new Set,this.movedSet=new Set,this.droppedSet=new Set,this.processMutations=t=>{t.forEach(this.processMutation),this.emit()},this.emit=()=>{if(this.frozen||this.locked)return;const t=[],n=new Set,r=new iL,o=l=>{let c=l,u=au;for(;u===au;)c=c&&c.nextSibling,u=c&&this.mirror.getId(c);return u},i=l=>{if(!l.parentNode||!B5(l))return;const c=Dc(l.parentNode)?this.mirror.getId(z5(l)):this.mirror.getId(l.parentNode),u=o(l);if(c===-1||u===-1)return r.addNode(l);const d=da(l,{doc:this.doc,mirror:this.mirror,blockClass:this.blockClass,blockSelector:this.blockSelector,maskAllText:this.maskAllText,unblockSelector:this.unblockSelector,maskTextClass:this.maskTextClass,unmaskTextClass:this.unmaskTextClass,maskTextSelector:this.maskTextSelector,unmaskTextSelector:this.unmaskTextSelector,skipChild:!0,newlyAddedElement:!0,inlineStylesheet:this.inlineStylesheet,maskInputOptions:this.maskInputOptions,maskAttributeFn:this.maskAttributeFn,maskTextFn:this.maskTextFn,maskInputFn:this.maskInputFn,slimDOMOptions:this.slimDOMOptions,dataURLOptions:this.dataURLOptions,recordCanvas:this.recordCanvas,inlineImages:this.inlineImages,onSerialize:f=>{L5(f,this.mirror)&&this.iframeManager.addIframe(f),V5(f,this.mirror)&&this.stylesheetManager.trackLinkElement(f),Vy(l)&&this.shadowDomManager.addShadowRoot(l.shadowRoot,this.doc)},onIframeLoad:(f,h)=>{this.iframeManager.attachIframe(f,h),this.shadowDomManager.observeAttachShadow(f)},onStylesheetLoad:(f,h)=>{this.stylesheetManager.attachLinkElement(f,h)}});d&&(t.push({parentId:c,nextId:u,node:d}),n.add(d.id))};for(;this.mapRemoves.length;)this.mirror.removeNodeFromMap(this.mapRemoves.shift());for(const l of this.movedSet)P_(this.removes,l,this.mirror)&&!this.movedSet.has(l.parentNode)||i(l);for(const l of this.addedSet)!O_(this.droppedSet,l)&&!P_(this.removes,l,this.mirror)||O_(this.movedSet,l)?i(l):this.droppedSet.add(l);let s=null;for(;r.length;){let l=null;if(s){const c=this.mirror.getId(s.value.parentNode),u=o(s.value);c!==-1&&u!==-1&&(l=s)}if(!l){let c=r.tail;for(;c;){const u=c;if(c=c.previous,u){const d=this.mirror.getId(u.value.parentNode);if(o(u.value)===-1)continue;if(d!==-1){l=u;break}else{const h=u.value;if(h.parentNode&&h.parentNode.nodeType===Node.DOCUMENT_FRAGMENT_NODE){const m=h.parentNode.host;if(this.mirror.getId(m)!==-1){l=u;break}}}}}}if(!l){for(;r.head;)r.removeNode(r.head.value);break}s=l.previous,r.removeNode(l.value),i(l.value)}const a={texts:this.texts.map(l=>({id:this.mirror.getId(l.node),value:l.value})).filter(l=>!n.has(l.id)).filter(l=>this.mirror.has(l.id)),attributes:this.attributes.map(l=>{const{attributes:c}=l;if(typeof c.style=="string"){const u=JSON.stringify(l.styleDiff),d=JSON.stringify(l._unchangedStyles);u.length!n.has(l.id)).filter(l=>this.mirror.has(l.id)),removes:this.removes,adds:t};!a.texts.length&&!a.attributes.length&&!a.removes.length&&!a.adds.length||(this.texts=[],this.attributes=[],this.removes=[],this.addedSet=new Set,this.movedSet=new Set,this.droppedSet=new Set,this.movedMap={},this.mutationCb(a))},this.processMutation=t=>{if(kg(t.target,this.mirror))return;let n;try{n=document.implementation.createHTMLDocument()}catch{n=this.doc}switch(t.type){case"characterData":{const r=t.target.textContent;!cr(t.target,this.blockClass,this.blockSelector,this.unblockSelector,!1)&&r!==t.oldValue&&this.texts.push({value:il(t.target,this.maskTextClass,this.maskTextSelector,this.unmaskTextClass,this.unmaskTextSelector,this.maskAllText)&&r?this.maskTextFn?this.maskTextFn(r):r.replace(/[\S]/g,"*"):r,node:t.target});break}case"attributes":{const r=t.target;let o=t.attributeName,i=t.target.getAttribute(o);if(o==="value"){const a=Mb(r),l=r.tagName;i=_h(r,l,a);const c=Vp({maskInputOptions:this.maskInputOptions,tagName:l,type:a}),u=il(t.target,this.maskTextClass,this.maskTextSelector,this.unmaskTextClass,this.unmaskTextSelector,c);i=su({isMasked:u,element:r,value:i,maskInputFn:this.maskInputFn})}if(cr(t.target,this.blockClass,this.blockSelector,this.unblockSelector,!1)||i===t.oldValue)return;let s=this.attributes.find(a=>a.node===t.target);if(r.tagName==="IFRAME"&&o==="src"&&!this.keepIframeSrcFn(i))if(!r.contentDocument)o="rr_src";else return;if(s||(s={node:t.target,attributes:{},styleDiff:{},_unchangedStyles:{}},this.attributes.push(s)),o==="type"&&r.tagName==="INPUT"&&(t.oldValue||"").toLowerCase()==="password"&&r.setAttribute("data-rr-is-password","true"),!N5(r.tagName,o)&&(s.attributes[o]=O5(this.doc,ol(r.tagName),ol(o),i,r,this.maskAttributeFn),o==="style")){const a=n.createElement("span");t.oldValue&&a.setAttribute("style",t.oldValue);for(const l of Array.from(r.style)){const c=r.style.getPropertyValue(l),u=r.style.getPropertyPriority(l);c!==a.style.getPropertyValue(l)||u!==a.style.getPropertyPriority(l)?u===""?s.styleDiff[l]=c:s.styleDiff[l]=[c,u]:s._unchangedStyles[l]=[c,u]}for(const l of Array.from(a.style))r.style.getPropertyValue(l)===""&&(s.styleDiff[l]=!1)}break}case"childList":{if(cr(t.target,this.blockClass,this.blockSelector,this.unblockSelector,!0))return;t.addedNodes.forEach(r=>this.genAdds(r,t.target)),t.removedNodes.forEach(r=>{const o=this.mirror.getId(r),i=Dc(t.target)?this.mirror.getId(t.target.host):this.mirror.getId(t.target);cr(t.target,this.blockClass,this.blockSelector,this.unblockSelector,!1)||kg(r,this.mirror)||!Xj(r,this.mirror)||(this.addedSet.has(r)?(zy(this.addedSet,r),this.droppedSet.add(r)):this.addedSet.has(t.target)&&o===-1||j5(t.target,this.mirror)||(this.movedSet.has(r)&&this.movedMap[$_(o,i)]?zy(this.movedSet,r):this.removes.push({parentId:i,id:o,isShadow:Dc(t.target)&&Ac(t.target)?!0:void 0})),this.mapRemoves.push(r))});break}}},this.genAdds=(t,n)=>{if(!this.processedNodeManager.inOtherBuffer(t,this)&&!(this.addedSet.has(t)||this.movedSet.has(t))){if(this.mirror.hasNode(t)){if(kg(t,this.mirror))return;this.movedSet.add(t);let r=null;n&&this.mirror.hasNode(n)&&(r=this.mirror.getId(n)),r&&r!==-1&&(this.movedMap[$_(this.mirror.getId(t),r)]=!0)}else this.addedSet.add(t),this.droppedSet.delete(t);cr(t,this.blockClass,this.blockSelector,this.unblockSelector,!1)||(t.childNodes.forEach(r=>this.genAdds(r)),Vy(t)&&t.shadowRoot.childNodes.forEach(r=>{this.processedNodeManager.add(r,this),this.genAdds(r,t)}))}}}init(t){["mutationCb","blockClass","blockSelector","unblockSelector","maskAllText","maskTextClass","unmaskTextClass","maskTextSelector","unmaskTextSelector","inlineStylesheet","maskInputOptions","maskAttributeFn","maskTextFn","maskInputFn","keepIframeSrcFn","recordCanvas","inlineImages","slimDOMOptions","dataURLOptions","doc","mirror","iframeManager","stylesheetManager","shadowDomManager","canvasManager","processedNodeManager"].forEach(n=>{this[n]=t[n]})}freeze(){this.frozen=!0,this.canvasManager.freeze()}unfreeze(){this.frozen=!1,this.canvasManager.unfreeze(),this.emit()}isFrozen(){return this.frozen}lock(){this.locked=!0,this.canvasManager.lock()}unlock(){this.locked=!1,this.canvasManager.unlock(),this.emit()}reset(){this.shadowDomManager.reset(),this.canvasManager.reset()}}function zy(e,t){e.delete(t),t.childNodes.forEach(n=>zy(e,n))}function P_(e,t,n){return e.length===0?!1:H5(e,t,n)}function H5(e,t,n){const{parentNode:r}=t;if(!r)return!1;const o=n.getId(r);return e.some(i=>i.id===o)?!0:H5(e,r,n)}function O_(e,t){return e.size===0?!1:U5(e,t)}function U5(e,t){const{parentNode:n}=t;return n?e.has(n)?!0:U5(e,n):!1}let Fc;function aL(e){Fc=e}function lL(){Fc=void 0}const xe=e=>Fc?(...n)=>{try{return e(...n)}catch(r){if(Fc&&Fc(r)===!0)return()=>{};throw r}}:e;function Nr(e){let t,n=e[0],r=1;for(;rn.call(t,...s)),t=void 0)}return n}const fa=[];function Ju(e){try{if("composedPath"in e){const t=e.composedPath();if(t.length)return t[0]}else if("path"in e&&e.path.length)return e.path[0]}catch{}return e&&e.target}function W5(e,t){const n=new sL;fa.push(n),n.init(e);let r=window.MutationObserver||window.__rrMutationObserver;const o=Nr([window,"optionalAccess",s=>s.Zone,"optionalAccess",s=>s.__symbol__,"optionalCall",s=>s("MutationObserver")]);o&&window[o]&&(r=window[o]);const i=new r(xe(s=>{e.onMutation&&e.onMutation(s)===!1||n.processMutations.bind(n)(s)}));return i.observe(t,{attributes:!0,attributeOldValue:!0,characterData:!0,characterDataOldValue:!0,childList:!0,subtree:!0}),i}function cL({mousemoveCb:e,sampling:t,doc:n,mirror:r}){if(t.mousemove===!1)return()=>{};const o=typeof t.mousemove=="number"?t.mousemove:50,i=typeof t.mousemoveCallback=="number"?t.mousemoveCallback:500;let s=[],a;const l=lu(xe(d=>{const f=Date.now()-a;e(s.map(h=>(h.timeOffset-=f,h)),d),s=[],a=null}),i),c=xe(lu(xe(d=>{const f=Ju(d),{clientX:h,clientY:m}=Ly(d)?d.changedTouches[0]:d;a||(a=Ch()),s.push({x:h,y:m,id:r.getId(f),timeOffset:Ch()-a}),l(typeof DragEvent<"u"&&d instanceof DragEvent?he.Drag:d instanceof MouseEvent?he.MouseMove:he.TouchMove)}),o,{trailing:!1})),u=[Xt("mousemove",c,n),Xt("touchmove",c,n),Xt("drag",c,n)];return xe(()=>{u.forEach(d=>d())})}function uL({mouseInteractionCb:e,doc:t,mirror:n,blockClass:r,blockSelector:o,unblockSelector:i,sampling:s}){if(s.mouseInteraction===!1)return()=>{};const a=s.mouseInteraction===!0||s.mouseInteraction===void 0?{}:s.mouseInteraction,l=[];let c=null;const u=d=>f=>{const h=Ju(f);if(cr(h,r,o,i,!0))return;let m=null,v=d;if("pointerType"in f){switch(f.pointerType){case"mouse":m=Jr.Mouse;break;case"touch":m=Jr.Touch;break;case"pen":m=Jr.Pen;break}m===Jr.Touch?qt[d]===qt.MouseDown?v="TouchStart":qt[d]===qt.MouseUp&&(v="TouchEnd"):Jr.Pen}else Ly(f)&&(m=Jr.Touch);m!==null?(c=m,(v.startsWith("Touch")&&m===Jr.Touch||v.startsWith("Mouse")&&m===Jr.Mouse)&&(m=null)):qt[d]===qt.Click&&(m=c,c=null);const S=Ly(f)?f.changedTouches[0]:f;if(!S)return;const y=n.getId(h),{clientX:b,clientY:w}=S;xe(e)({type:qt[v],id:y,x:b,y:w,...m!==null&&{pointerType:m}})};return Object.keys(qt).filter(d=>Number.isNaN(Number(d))&&!d.endsWith("_Departed")&&a[d]!==!1).forEach(d=>{let f=ol(d);const h=u(d);if(window.PointerEvent)switch(qt[d]){case qt.MouseDown:case qt.MouseUp:f=f.replace("mouse","pointer");break;case qt.TouchStart:case qt.TouchEnd:return}l.push(Xt(f,h,t))}),xe(()=>{l.forEach(d=>d())})}function G5({scrollCb:e,doc:t,mirror:n,blockClass:r,blockSelector:o,unblockSelector:i,sampling:s}){const a=xe(lu(xe(l=>{const c=Ju(l);if(!c||cr(c,r,o,i,!0))return;const u=n.getId(c);if(c===t&&t.defaultView){const d=D5(t.defaultView);e({id:u,x:d.left,y:d.top})}else e({id:u,x:c.scrollLeft,y:c.scrollTop})}),s.scroll||100));return Xt("scroll",a,t)}function dL({viewportResizeCb:e},{win:t}){let n=-1,r=-1;const o=xe(lu(xe(()=>{const i=A5(),s=F5();(n!==i||r!==s)&&(e({width:Number(s),height:Number(i)}),n=i,r=s)}),200));return Xt("resize",o,t)}const fL=["INPUT","TEXTAREA","SELECT"],N_=new WeakMap;function hL({inputCb:e,doc:t,mirror:n,blockClass:r,blockSelector:o,unblockSelector:i,ignoreClass:s,ignoreSelector:a,maskInputOptions:l,maskInputFn:c,sampling:u,userTriggeredOnInput:d,maskTextClass:f,unmaskTextClass:h,maskTextSelector:m,unmaskTextSelector:v}){function S(C){let k=Ju(C);const T=C.isTrusted,R=k&&jy(k.tagName);if(R==="OPTION"&&(k=k.parentElement),!k||!R||fL.indexOf(R)<0||cr(k,r,o,i,!0))return;const D=k;if(D.classList.contains(s)||a&&D.matches(a))return;const O=Mb(k);let H=_h(D,R,O),N=!1;const A=Vp({maskInputOptions:l,tagName:R,type:O}),F=il(k,f,m,h,v,A);(O==="radio"||O==="checkbox")&&(N=k.checked),H=su({isMasked:F,element:k,value:H,maskInputFn:c}),y(k,d?{text:H,isChecked:N,userTriggered:T}:{text:H,isChecked:N});const P=k.name;O==="radio"&&P&&N&&t.querySelectorAll(`input[type="radio"][name="${P}"]`).forEach($=>{if($!==k){const I=su({isMasked:F,element:$,value:_h($,R,O),maskInputFn:c});y($,d?{text:I,isChecked:!N,userTriggered:!1}:{text:I,isChecked:!N})}})}function y(C,k){const T=N_.get(C);if(!T||T.text!==k.text||T.isChecked!==k.isChecked){N_.set(C,k);const R=n.getId(C);xe(e)({...k,id:R})}}const w=(u.input==="last"?["change"]:["input","change"]).map(C=>Xt(C,xe(S),t)),x=t.defaultView;if(!x)return()=>{w.forEach(C=>C())};const _=x.Object.getOwnPropertyDescriptor(x.HTMLInputElement.prototype,"value"),E=[[x.HTMLInputElement.prototype,"value"],[x.HTMLInputElement.prototype,"checked"],[x.HTMLSelectElement.prototype,"value"],[x.HTMLTextAreaElement.prototype,"value"],[x.HTMLSelectElement.prototype,"selectedIndex"],[x.HTMLOptionElement.prototype,"selected"]];return _&&_.set&&w.push(...E.map(C=>M5(C[0],C[1],{set(){xe(S)({target:this,isTrusted:!1})}},!1,x))),xe(()=>{w.forEach(C=>C())})}function kh(e){const t=[];function n(r,o){if(Wd("CSSGroupingRule")&&r.parentRule instanceof CSSGroupingRule||Wd("CSSMediaRule")&&r.parentRule instanceof CSSMediaRule||Wd("CSSSupportsRule")&&r.parentRule instanceof CSSSupportsRule||Wd("CSSConditionRule")&&r.parentRule instanceof CSSConditionRule){const s=Array.from(r.parentRule.cssRules).indexOf(r);o.unshift(s)}else if(r.parentStyleSheet){const s=Array.from(r.parentStyleSheet.cssRules).indexOf(r);o.unshift(s)}return o}return n(e,t)}function Ho(e,t,n){let r,o;return e?(e.ownerNode?r=t.getId(e.ownerNode):o=n.getId(e),{styleId:o,id:r}):{}}function pL({styleSheetRuleCb:e,mirror:t,stylesheetManager:n},{win:r}){if(!r.CSSStyleSheet||!r.CSSStyleSheet.prototype)return()=>{};const o=r.CSSStyleSheet.prototype.insertRule;r.CSSStyleSheet.prototype.insertRule=new Proxy(o,{apply:xe((u,d,f)=>{const[h,m]=f,{id:v,styleId:S}=Ho(d,t,n.styleMirror);return(v&&v!==-1||S&&S!==-1)&&e({id:v,styleId:S,adds:[{rule:h,index:m}]}),u.apply(d,f)})});const i=r.CSSStyleSheet.prototype.deleteRule;r.CSSStyleSheet.prototype.deleteRule=new Proxy(i,{apply:xe((u,d,f)=>{const[h]=f,{id:m,styleId:v}=Ho(d,t,n.styleMirror);return(m&&m!==-1||v&&v!==-1)&&e({id:m,styleId:v,removes:[{index:h}]}),u.apply(d,f)})});let s;r.CSSStyleSheet.prototype.replace&&(s=r.CSSStyleSheet.prototype.replace,r.CSSStyleSheet.prototype.replace=new Proxy(s,{apply:xe((u,d,f)=>{const[h]=f,{id:m,styleId:v}=Ho(d,t,n.styleMirror);return(m&&m!==-1||v&&v!==-1)&&e({id:m,styleId:v,replace:h}),u.apply(d,f)})}));let a;r.CSSStyleSheet.prototype.replaceSync&&(a=r.CSSStyleSheet.prototype.replaceSync,r.CSSStyleSheet.prototype.replaceSync=new Proxy(a,{apply:xe((u,d,f)=>{const[h]=f,{id:m,styleId:v}=Ho(d,t,n.styleMirror);return(m&&m!==-1||v&&v!==-1)&&e({id:m,styleId:v,replaceSync:h}),u.apply(d,f)})}));const l={};Gd("CSSGroupingRule")?l.CSSGroupingRule=r.CSSGroupingRule:(Gd("CSSMediaRule")&&(l.CSSMediaRule=r.CSSMediaRule),Gd("CSSConditionRule")&&(l.CSSConditionRule=r.CSSConditionRule),Gd("CSSSupportsRule")&&(l.CSSSupportsRule=r.CSSSupportsRule));const c={};return Object.entries(l).forEach(([u,d])=>{c[u]={insertRule:d.prototype.insertRule,deleteRule:d.prototype.deleteRule},d.prototype.insertRule=new Proxy(c[u].insertRule,{apply:xe((f,h,m)=>{const[v,S]=m,{id:y,styleId:b}=Ho(h.parentStyleSheet,t,n.styleMirror);return(y&&y!==-1||b&&b!==-1)&&e({id:y,styleId:b,adds:[{rule:v,index:[...kh(h),S||0]}]}),f.apply(h,m)})}),d.prototype.deleteRule=new Proxy(c[u].deleteRule,{apply:xe((f,h,m)=>{const[v]=m,{id:S,styleId:y}=Ho(h.parentStyleSheet,t,n.styleMirror);return(S&&S!==-1||y&&y!==-1)&&e({id:S,styleId:y,removes:[{index:[...kh(h),v]}]}),f.apply(h,m)})})}),xe(()=>{r.CSSStyleSheet.prototype.insertRule=o,r.CSSStyleSheet.prototype.deleteRule=i,s&&(r.CSSStyleSheet.prototype.replace=s),a&&(r.CSSStyleSheet.prototype.replaceSync=a),Object.entries(l).forEach(([u,d])=>{d.prototype.insertRule=c[u].insertRule,d.prototype.deleteRule=c[u].deleteRule})})}function q5({mirror:e,stylesheetManager:t},n){let r=null;n.nodeName==="#document"?r=e.getId(n):r=e.getId(n.host);const o=n.nodeName==="#document"?Nr([n,"access",s=>s.defaultView,"optionalAccess",s=>s.Document]):Nr([n,"access",s=>s.ownerDocument,"optionalAccess",s=>s.defaultView,"optionalAccess",s=>s.ShadowRoot]),i=Nr([o,"optionalAccess",s=>s.prototype])?Object.getOwnPropertyDescriptor(Nr([o,"optionalAccess",s=>s.prototype]),"adoptedStyleSheets"):void 0;return r===null||r===-1||!o||!i?()=>{}:(Object.defineProperty(n,"adoptedStyleSheets",{configurable:i.configurable,enumerable:i.enumerable,get(){return Nr([i,"access",s=>s.get,"optionalAccess",s=>s.call,"call",s=>s(this)])},set(s){const a=Nr([i,"access",l=>l.set,"optionalAccess",l=>l.call,"call",l=>l(this,s)]);if(r!==null&&r!==-1)try{t.adoptStyleSheets(s,r)}catch{}return a}}),xe(()=>{Object.defineProperty(n,"adoptedStyleSheets",{configurable:i.configurable,enumerable:i.enumerable,get:i.get,set:i.set})}))}function mL({styleDeclarationCb:e,mirror:t,ignoreCSSAttributes:n,stylesheetManager:r},{win:o}){const i=o.CSSStyleDeclaration.prototype.setProperty;o.CSSStyleDeclaration.prototype.setProperty=new Proxy(i,{apply:xe((a,l,c)=>{const[u,d,f]=c;if(n.has(u))return i.apply(l,[u,d,f]);const{id:h,styleId:m}=Ho(Nr([l,"access",v=>v.parentRule,"optionalAccess",v=>v.parentStyleSheet]),t,r.styleMirror);return(h&&h!==-1||m&&m!==-1)&&e({id:h,styleId:m,set:{property:u,value:d,priority:f},index:kh(l.parentRule)}),a.apply(l,c)})});const s=o.CSSStyleDeclaration.prototype.removeProperty;return o.CSSStyleDeclaration.prototype.removeProperty=new Proxy(s,{apply:xe((a,l,c)=>{const[u]=c;if(n.has(u))return s.apply(l,[u]);const{id:d,styleId:f}=Ho(Nr([l,"access",h=>h.parentRule,"optionalAccess",h=>h.parentStyleSheet]),t,r.styleMirror);return(d&&d!==-1||f&&f!==-1)&&e({id:d,styleId:f,remove:{property:u},index:kh(l.parentRule)}),a.apply(l,c)})}),xe(()=>{o.CSSStyleDeclaration.prototype.setProperty=i,o.CSSStyleDeclaration.prototype.removeProperty=s})}function gL({mediaInteractionCb:e,blockClass:t,blockSelector:n,unblockSelector:r,mirror:o,sampling:i,doc:s}){const a=xe(c=>lu(xe(u=>{const d=Ju(u);if(!d||cr(d,t,n,r,!0))return;const{currentTime:f,volume:h,muted:m,playbackRate:v}=d;e({type:c,id:o.getId(d),currentTime:f,volume:h,muted:m,playbackRate:v})}),i.media||500)),l=[Xt("play",a(0),s),Xt("pause",a(1),s),Xt("seeked",a(2),s),Xt("volumechange",a(3),s),Xt("ratechange",a(4),s)];return xe(()=>{l.forEach(c=>c())})}function vL({fontCb:e,doc:t}){const n=t.defaultView;if(!n)return()=>{};const r=[],o=new WeakMap,i=n.FontFace;n.FontFace=function(l,c,u){const d=new i(l,c,u);return o.set(d,{family:l,buffer:typeof c!="string",descriptors:u,fontSource:typeof c=="string"?c:JSON.stringify(Array.from(new Uint8Array(c)))}),d};const s=Fb(t.fonts,"add",function(a){return function(l){return setTimeout(xe(()=>{const c=o.get(l);c&&(e(c),o.delete(l))}),0),a.apply(this,[l])}});return r.push(()=>{n.FontFace=i}),r.push(s),xe(()=>{r.forEach(a=>a())})}function yL(e){const{doc:t,mirror:n,blockClass:r,blockSelector:o,unblockSelector:i,selectionCb:s}=e;let a=!0;const l=xe(()=>{const c=t.getSelection();if(!c||a&&Nr([c,"optionalAccess",f=>f.isCollapsed]))return;a=c.isCollapsed||!1;const u=[],d=c.rangeCount||0;for(let f=0;f{}:Fb(n.customElements,"define",function(o){return function(i,s,a){try{t({define:{name:i}})}catch{}return o.apply(this,[i,s,a])}})}function wL(e,t={}){const n=e.doc.defaultView;if(!n)return()=>{};const r=W5(e,e.doc),o=cL(e),i=uL(e),s=G5(e),a=dL(e,{win:n}),l=hL(e),c=gL(e),u=pL(e,{win:n}),d=q5(e,e.doc),f=mL(e,{win:n}),h=e.collectFonts?vL(e):()=>{},m=yL(e),v=bL(e),S=[];for(const y of e.plugins)S.push(y.observer(y.callback,n,y.options));return xe(()=>{fa.forEach(y=>y.reset()),r.disconnect(),o(),i(),s(),a(),l(),c(),u(),d(),f(),h(),m(),v(),S.forEach(y=>y())})}function Wd(e){return typeof window[e]<"u"}function Gd(e){return!!(typeof window[e]<"u"&&window[e].prototype&&"insertRule"in window[e].prototype&&"deleteRule"in window[e].prototype)}class By{constructor(t){this.generateIdFn=t,this.iframeIdToRemoteIdMap=new WeakMap,this.iframeRemoteIdToIdMap=new WeakMap}getId(t,n,r,o){const i=r||this.getIdToRemoteIdMap(t),s=o||this.getRemoteIdToIdMap(t);let a=i.get(n);return a||(a=this.generateIdFn(),i.set(n,a),s.set(a,n)),a}getIds(t,n){const r=this.getIdToRemoteIdMap(t),o=this.getRemoteIdToIdMap(t);return n.map(i=>this.getId(t,i,r,o))}getRemoteId(t,n,r){const o=r||this.getRemoteIdToIdMap(t);if(typeof n!="number")return n;const i=o.get(n);return i||-1}getRemoteIds(t,n){const r=this.getRemoteIdToIdMap(t);return n.map(o=>this.getRemoteId(t,o,r))}reset(t){if(!t){this.iframeIdToRemoteIdMap=new WeakMap,this.iframeRemoteIdToIdMap=new WeakMap;return}this.iframeIdToRemoteIdMap.delete(t),this.iframeRemoteIdToIdMap.delete(t)}getIdToRemoteIdMap(t){let n=this.iframeIdToRemoteIdMap.get(t);return n||(n=new Map,this.iframeIdToRemoteIdMap.set(t,n)),n}getRemoteIdToIdMap(t){let n=this.iframeRemoteIdToIdMap.get(t);return n||(n=new Map,this.iframeRemoteIdToIdMap.set(t,n)),n}}function M_(e){let t,n=e[0],r=1;for(;rn.call(t,...s)),t=void 0)}return n}class SL{constructor(){this.crossOriginIframeMirror=new By(Db),this.crossOriginIframeRootIdMap=new WeakMap}addIframe(){}addLoadListener(){}attachIframe(){}}class xL{constructor(t){this.iframes=new WeakMap,this.crossOriginIframeMap=new WeakMap,this.crossOriginIframeMirror=new By(Db),this.crossOriginIframeRootIdMap=new WeakMap,this.mutationCb=t.mutationCb,this.wrappedEmit=t.wrappedEmit,this.stylesheetManager=t.stylesheetManager,this.recordCrossOriginIframes=t.recordCrossOriginIframes,this.crossOriginIframeStyleMirror=new By(this.stylesheetManager.styleMirror.generateId.bind(this.stylesheetManager.styleMirror)),this.mirror=t.mirror,this.recordCrossOriginIframes&&window.addEventListener("message",this.handleMessage.bind(this))}addIframe(t){this.iframes.set(t,!0),t.contentWindow&&this.crossOriginIframeMap.set(t.contentWindow,t)}addLoadListener(t){this.loadListener=t}attachIframe(t,n){this.mutationCb({adds:[{parentId:this.mirror.getId(t),nextId:null,node:n}],removes:[],texts:[],attributes:[],isAttachIframe:!0}),M_([this,"access",r=>r.loadListener,"optionalCall",r=>r(t)]),t.contentDocument&&t.contentDocument.adoptedStyleSheets&&t.contentDocument.adoptedStyleSheets.length>0&&this.stylesheetManager.adoptStyleSheets(t.contentDocument.adoptedStyleSheets,this.mirror.getId(t.contentDocument))}handleMessage(t){const n=t;if(n.data.type!=="rrweb"||n.origin!==n.data.origin||!t.source)return;const o=this.crossOriginIframeMap.get(t.source);if(!o)return;const i=this.transformCrossOriginEvent(o,n.data.event);i&&this.wrappedEmit(i,n.data.isCheckout)}transformCrossOriginEvent(t,n){switch(n.type){case fe.FullSnapshot:{this.crossOriginIframeMirror.reset(t),this.crossOriginIframeStyleMirror.reset(t),this.replaceIdOnNode(n.data.node,t);const r=n.data.node.id;return this.crossOriginIframeRootIdMap.set(t,r),this.patchRootIdOnNode(n.data.node,r),{timestamp:n.timestamp,type:fe.IncrementalSnapshot,data:{source:he.Mutation,adds:[{parentId:this.mirror.getId(t),nextId:null,node:n.data.node}],removes:[],texts:[],attributes:[],isAttachIframe:!0}}}case fe.Meta:case fe.Load:case fe.DomContentLoaded:return!1;case fe.Plugin:return n;case fe.Custom:return this.replaceIds(n.data.payload,t,["id","parentId","previousId","nextId"]),n;case fe.IncrementalSnapshot:switch(n.data.source){case he.Mutation:return n.data.adds.forEach(r=>{this.replaceIds(r,t,["parentId","nextId","previousId"]),this.replaceIdOnNode(r.node,t);const o=this.crossOriginIframeRootIdMap.get(t);o&&this.patchRootIdOnNode(r.node,o)}),n.data.removes.forEach(r=>{this.replaceIds(r,t,["parentId","id"])}),n.data.attributes.forEach(r=>{this.replaceIds(r,t,["id"])}),n.data.texts.forEach(r=>{this.replaceIds(r,t,["id"])}),n;case he.Drag:case he.TouchMove:case he.MouseMove:return n.data.positions.forEach(r=>{this.replaceIds(r,t,["id"])}),n;case he.ViewportResize:return!1;case he.MediaInteraction:case he.MouseInteraction:case he.Scroll:case he.CanvasMutation:case he.Input:return this.replaceIds(n.data,t,["id"]),n;case he.StyleSheetRule:case he.StyleDeclaration:return this.replaceIds(n.data,t,["id"]),this.replaceStyleIds(n.data,t,["styleId"]),n;case he.Font:return n;case he.Selection:return n.data.ranges.forEach(r=>{this.replaceIds(r,t,["start","end"])}),n;case he.AdoptedStyleSheet:return this.replaceIds(n.data,t,["id"]),this.replaceStyleIds(n.data,t,["styleIds"]),M_([n,"access",r=>r.data,"access",r=>r.styles,"optionalAccess",r=>r.forEach,"call",r=>r(o=>{this.replaceStyleIds(o,t,["styleId"])})]),n}}return!1}replace(t,n,r,o){for(const i of o)!Array.isArray(n[i])&&typeof n[i]!="number"||(Array.isArray(n[i])?n[i]=t.getIds(r,n[i]):n[i]=t.getId(r,n[i]));return n}replaceIds(t,n,r){return this.replace(this.crossOriginIframeMirror,t,n,r)}replaceStyleIds(t,n,r){return this.replace(this.crossOriginIframeStyleMirror,t,n,r)}replaceIdOnNode(t,n){this.replaceIds(t,n,["id","rootId"]),"childNodes"in t&&t.childNodes.forEach(r=>{this.replaceIdOnNode(r,n)})}patchRootIdOnNode(t,n){t.type!==yt.Document&&!t.rootId&&(t.rootId=n),"childNodes"in t&&t.childNodes.forEach(r=>{this.patchRootIdOnNode(r,n)})}}class _L{init(){}addShadowRoot(){}observeAttachShadow(){}reset(){}}class EL{constructor(t){this.shadowDoms=new WeakSet,this.restoreHandlers=[],this.mutationCb=t.mutationCb,this.scrollCb=t.scrollCb,this.bypassOptions=t.bypassOptions,this.mirror=t.mirror,this.init()}init(){this.reset(),this.patchAttachShadow(Element,document)}addShadowRoot(t,n){if(!Ac(t)||this.shadowDoms.has(t))return;this.shadowDoms.add(t);const r=W5({...this.bypassOptions,doc:n,mutationCb:this.mutationCb,mirror:this.mirror,shadowDomManager:this},t);this.restoreHandlers.push(()=>r.disconnect()),this.restoreHandlers.push(G5({...this.bypassOptions,scrollCb:this.scrollCb,doc:t,mirror:this.mirror})),setTimeout(()=>{t.adoptedStyleSheets&&t.adoptedStyleSheets.length>0&&this.bypassOptions.stylesheetManager.adoptStyleSheets(t.adoptedStyleSheets,this.mirror.getId(t.host)),this.restoreHandlers.push(q5({mirror:this.mirror,stylesheetManager:this.bypassOptions.stylesheetManager},t))},0)}observeAttachShadow(t){!t.contentWindow||!t.contentDocument||this.patchAttachShadow(t.contentWindow.Element,t.contentDocument)}patchAttachShadow(t,n){const r=this;this.restoreHandlers.push(Fb(t.prototype,"attachShadow",function(o){return function(i){const s=o.call(this,i);return this.shadowRoot&&B5(this)&&r.addShadowRoot(this.shadowRoot,n),s}}))}reset(){this.restoreHandlers.forEach(t=>{try{t()}catch{}}),this.restoreHandlers=[],this.shadowDoms=new WeakSet}}class D_{reset(){}freeze(){}unfreeze(){}lock(){}unlock(){}snapshot(){}}class CL{constructor(t){this.trackedLinkElements=new WeakSet,this.styleMirror=new Jj,this.mutationCb=t.mutationCb,this.adoptedStyleSheetCb=t.adoptedStyleSheetCb}attachLinkElement(t,n){"_cssText"in n.attributes&&this.mutationCb({adds:[],removes:[],texts:[],attributes:[{id:n.id,attributes:n.attributes}]}),this.trackLinkElement(t)}trackLinkElement(t){this.trackedLinkElements.has(t)||(this.trackedLinkElements.add(t),this.trackStylesheetInLinkElement(t))}adoptStyleSheets(t,n){if(t.length===0)return;const r={id:n,styleIds:[]},o=[];for(const i of t){let s;this.styleMirror.has(i)?s=this.styleMirror.getId(i):(s=this.styleMirror.add(i),o.push({styleId:s,rules:Array.from(i.rules||CSSRule,(a,l)=>({rule:$5(a),index:l}))})),r.styleIds.push(s)}o.length>0&&(r.styles=o),this.adoptedStyleSheetCb(r)}reset(){this.styleMirror.reset(),this.trackedLinkElements=new WeakSet}trackStylesheetInLinkElement(t){}}class kL{constructor(){this.nodeMap=new WeakMap,this.loop=!0,this.periodicallyClear()}periodicallyClear(){rL(()=>{this.clear(),this.loop&&this.periodicallyClear()})}inOtherBuffer(t,n){const r=this.nodeMap.get(t);return r&&Array.from(r).some(o=>o!==n)}add(t,n){this.nodeMap.set(t,(this.nodeMap.get(t)||new Set).add(n))}clear(){this.nodeMap=new WeakMap}destroy(){this.loop=!1}}function mt(e){const t=e;return t.timestamp=Ch(),t}let Th;const nr=Tj();function ii(e={}){const{emit:t,checkoutEveryNms:n,checkoutEveryNth:r,blockClass:o="rr-block",blockSelector:i=null,unblockSelector:s=null,ignoreClass:a="rr-ignore",ignoreSelector:l=null,maskAllText:c=!1,maskTextClass:u="rr-mask",unmaskTextClass:d=null,maskTextSelector:f=null,unmaskTextSelector:h=null,inlineStylesheet:m=!0,maskAllInputs:v,maskInputOptions:S,slimDOMOptions:y,maskAttributeFn:b,maskInputFn:w,maskTextFn:x,packFn:_,sampling:E={},dataURLOptions:C={},mousemoveWait:k,recordCanvas:T=!1,recordCrossOriginIframes:R=!1,recordAfter:D=e.recordAfter==="DOMContentLoaded"?e.recordAfter:"load",userTriggeredOnInput:O=!1,collectFonts:H=!1,inlineImages:N=!1,plugins:A,keepIframeSrcFn:F=()=>!1,ignoreCSSAttributes:P=new Set([]),errorHandler:$,onMutation:I,getCanvasManager:z}=e;aL($);const V=R?window.parent===window:!0;let G=!1;if(!V)try{window.parent.document&&(G=!1)}catch{G=!0}if(V&&!t)throw new Error("emit function is required");k!==void 0&&E.mousemove===void 0&&(E.mousemove=k),nr.reset();const ie=v===!0?{color:!0,date:!0,"datetime-local":!0,email:!0,month:!0,number:!0,range:!0,search:!0,tel:!0,text:!0,time:!0,url:!0,week:!0,textarea:!0,select:!0,radio:!0,checkbox:!0}:S!==void 0?S:{},te=y===!0||y==="all"?{script:!0,comment:!0,headFavicon:!0,headWhitespace:!0,headMetaSocial:!0,headMetaRobots:!0,headMetaHttpEquiv:!0,headMetaVerification:!0,headMetaAuthorship:y==="all",headMetaDescKeywords:y==="all"}:y||{};Zj();let pe,X=0;const B=le=>{for(const gn of A||[])gn.eventProcessor&&(le=gn.eventProcessor(le));return _&&!G&&(le=_(le)),le},K=(le,gn)=>{if(bg([fa,"access",me=>me[0],"optionalAccess",me=>me.isFrozen,"call",me=>me()])&&le.type!==fe.FullSnapshot&&!(le.type===fe.IncrementalSnapshot&&le.data.source===he.Mutation)&&fa.forEach(me=>me.unfreeze()),V)bg([t,"optionalCall",me=>me(B(le),gn)]);else if(G){const me={type:"rrweb",event:B(le),origin:window.location.origin,isCheckout:gn};window.parent.postMessage(me,"*")}if(le.type===fe.FullSnapshot)pe=le,X=0;else if(le.type===fe.IncrementalSnapshot){if(le.data.source===he.Mutation&&le.data.isAttachIframe)return;X++;const me=r&&X>=r,Jn=n&&le.timestamp-pe.timestamp>n;(me||Jn)&&Xl(!0)}},se=le=>{K(mt({type:fe.IncrementalSnapshot,data:{source:he.Mutation,...le}}))},ae=le=>K(mt({type:fe.IncrementalSnapshot,data:{source:he.Scroll,...le}})),ue=le=>K(mt({type:fe.IncrementalSnapshot,data:{source:he.CanvasMutation,...le}})),be=le=>K(mt({type:fe.IncrementalSnapshot,data:{source:he.AdoptedStyleSheet,...le}})),Ie=new CL({mutationCb:se,adoptedStyleSheetCb:be}),Ae=typeof __RRWEB_EXCLUDE_IFRAME__=="boolean"&&__RRWEB_EXCLUDE_IFRAME__?new SL:new xL({mirror:nr,mutationCb:se,stylesheetManager:Ie,recordCrossOriginIframes:R,wrappedEmit:K});for(const le of A||[])le.getMirror&&le.getMirror({nodeMirror:nr,crossOriginIframeMirror:Ae.crossOriginIframeMirror,crossOriginIframeStyleMirror:Ae.crossOriginIframeStyleMirror});const Gt=new kL,Yr=RL(z,{mirror:nr,win:window,mutationCb:le=>K(mt({type:fe.IncrementalSnapshot,data:{source:he.CanvasMutation,...le}})),recordCanvas:T,blockClass:o,blockSelector:i,unblockSelector:s,sampling:E.canvas,dataURLOptions:C,errorHandler:$}),Tr=typeof __RRWEB_EXCLUDE_SHADOW_DOM__=="boolean"&&__RRWEB_EXCLUDE_SHADOW_DOM__?new _L:new EL({mutationCb:se,scrollCb:ae,bypassOptions:{onMutation:I,blockClass:o,blockSelector:i,unblockSelector:s,maskAllText:c,maskTextClass:u,unmaskTextClass:d,maskTextSelector:f,unmaskTextSelector:h,inlineStylesheet:m,maskInputOptions:ie,dataURLOptions:C,maskAttributeFn:b,maskTextFn:x,maskInputFn:w,recordCanvas:T,inlineImages:N,sampling:E,slimDOMOptions:te,iframeManager:Ae,stylesheetManager:Ie,canvasManager:Yr,keepIframeSrcFn:F,processedNodeManager:Gt},mirror:nr}),Xl=(le=!1)=>{K(mt({type:fe.Meta,data:{href:window.location.href,width:F5(),height:A5()}}),le),Ie.reset(),Tr.init(),fa.forEach(me=>me.lock());const gn=Qj(document,{mirror:nr,blockClass:o,blockSelector:i,unblockSelector:s,maskAllText:c,maskTextClass:u,unmaskTextClass:d,maskTextSelector:f,unmaskTextSelector:h,inlineStylesheet:m,maskAllInputs:ie,maskAttributeFn:b,maskInputFn:w,maskTextFn:x,slimDOM:te,dataURLOptions:C,recordCanvas:T,inlineImages:N,onSerialize:me=>{L5(me,nr)&&Ae.addIframe(me),V5(me,nr)&&Ie.trackLinkElement(me),Vy(me)&&Tr.addShadowRoot(me.shadowRoot,document)},onIframeLoad:(me,Jn)=>{Ae.attachIframe(me,Jn),Tr.observeAttachShadow(me)},onStylesheetLoad:(me,Jn)=>{Ie.attachLinkElement(me,Jn)},keepIframeSrcFn:F});if(!gn)return console.warn("Failed to snapshot the document");K(mt({type:fe.FullSnapshot,data:{node:gn,initialOffset:D5(window)}})),fa.forEach(me=>me.unlock()),document.adoptedStyleSheets&&document.adoptedStyleSheets.length>0&&Ie.adoptStyleSheets(document.adoptedStyleSheets,nr.getId(document))};Th=Xl;try{const le=[],gn=Jn=>xe(wL)({onMutation:I,mutationCb:se,mousemoveCb:($e,Wi)=>K(mt({type:fe.IncrementalSnapshot,data:{source:Wi,positions:$e}})),mouseInteractionCb:$e=>K(mt({type:fe.IncrementalSnapshot,data:{source:he.MouseInteraction,...$e}})),scrollCb:ae,viewportResizeCb:$e=>K(mt({type:fe.IncrementalSnapshot,data:{source:he.ViewportResize,...$e}})),inputCb:$e=>K(mt({type:fe.IncrementalSnapshot,data:{source:he.Input,...$e}})),mediaInteractionCb:$e=>K(mt({type:fe.IncrementalSnapshot,data:{source:he.MediaInteraction,...$e}})),styleSheetRuleCb:$e=>K(mt({type:fe.IncrementalSnapshot,data:{source:he.StyleSheetRule,...$e}})),styleDeclarationCb:$e=>K(mt({type:fe.IncrementalSnapshot,data:{source:he.StyleDeclaration,...$e}})),canvasMutationCb:ue,fontCb:$e=>K(mt({type:fe.IncrementalSnapshot,data:{source:he.Font,...$e}})),selectionCb:$e=>{K(mt({type:fe.IncrementalSnapshot,data:{source:he.Selection,...$e}}))},customElementCb:$e=>{K(mt({type:fe.IncrementalSnapshot,data:{source:he.CustomElement,...$e}}))},blockClass:o,ignoreClass:a,ignoreSelector:l,maskAllText:c,maskTextClass:u,unmaskTextClass:d,maskTextSelector:f,unmaskTextSelector:h,maskInputOptions:ie,inlineStylesheet:m,sampling:E,recordCanvas:T,inlineImages:N,userTriggeredOnInput:O,collectFonts:H,doc:Jn,maskAttributeFn:b,maskInputFn:w,maskTextFn:x,keepIframeSrcFn:F,blockSelector:i,unblockSelector:s,slimDOMOptions:te,dataURLOptions:C,mirror:nr,iframeManager:Ae,stylesheetManager:Ie,shadowDomManager:Tr,processedNodeManager:Gt,canvasManager:Yr,ignoreCSSAttributes:P,plugins:bg([A,"optionalAccess",$e=>$e.filter,"call",$e=>$e(Wi=>Wi.observer),"optionalAccess",$e=>$e.map,"call",$e=>$e(Wi=>({observer:Wi.observer,options:Wi.options,callback:D8=>K(mt({type:fe.Plugin,data:{plugin:Wi.name,payload:D8}}))}))])||[]},{});Ae.addLoadListener(Jn=>{try{le.push(gn(Jn.contentDocument))}catch($e){console.warn($e)}});const me=()=>{Xl(),le.push(gn(document))};return document.readyState==="interactive"||document.readyState==="complete"?me():(le.push(Xt("DOMContentLoaded",()=>{K(mt({type:fe.DomContentLoaded,data:{}})),D==="DOMContentLoaded"&&me()})),le.push(Xt("load",()=>{K(mt({type:fe.Load,data:{}})),D==="load"&&me()},window))),()=>{le.forEach(Jn=>Jn()),Gt.destroy(),Th=void 0,lL()}}catch(le){console.warn(le)}}function TL(e){if(!Th)throw new Error("please take full snapshot after start recording");Th(e)}ii.mirror=nr;ii.takeFullSnapshot=TL;function RL(e,t){try{return e?e(t):new D_}catch{return console.warn("Unable to initialize CanvasManager"),new D_}}const IL=3,$L=5;function jb(e){return e>9999999999?e:e*1e3}function Rg(e){return e>9999999999?e/1e3:e}function ed(e,t){t.category!=="sentry.transaction"&&(["ui.click","ui.input"].includes(t.category)?e.triggerUserActivity():e.checkAndHandleExpiredSession(),e.addUpdate(()=>(e.throttledAddEvent({type:fe.Custom,timestamp:(t.timestamp||0)*1e3,data:{tag:"breadcrumb",payload:Or(t,10,1e3)}}),t.category==="console")))}const PL="button,a";function K5(e){return e.closest(PL)||e}function Y5(e){const t=Q5(e);return!t||!(t instanceof Element)?t:K5(t)}function Q5(e){return OL(e)?e.target:e}function OL(e){return typeof e=="object"&&!!e&&"target"in e}let Uo;function NL(e){return Uo||(Uo=[],ML()),Uo.push(e),()=>{const t=Uo?Uo.indexOf(e):-1;t>-1&&Uo.splice(t,1)}}function ML(){Et(Le,"open",function(e){return function(...t){if(Uo)try{Uo.forEach(n=>n())}catch{}return e.apply(Le,t)}})}function DL(e,t,n){e.handleClick(t,n)}class AL{constructor(t,n,r=ed){this._lastMutation=0,this._lastScroll=0,this._clicks=[],this._timeout=n.timeout/1e3,this._threshold=n.threshold/1e3,this._scollTimeout=n.scrollTimeout/1e3,this._replay=t,this._ignoreSelector=n.ignoreSelector,this._addBreadcrumbEvent=r}addListeners(){const t=NL(()=>{this._lastMutation=A_()});this._teardown=()=>{t(),this._clicks=[],this._lastMutation=0,this._lastScroll=0}}removeListeners(){this._teardown&&this._teardown(),this._checkClickTimeout&&clearTimeout(this._checkClickTimeout)}handleClick(t,n){if(jL(n,this._ignoreSelector)||!LL(t))return;const r={timestamp:Rg(t.timestamp),clickBreadcrumb:t,clickCount:0,node:n};this._clicks.some(o=>o.node===r.node&&Math.abs(o.timestamp-r.timestamp)<1)||(this._clicks.push(r),this._clicks.length===1&&this._scheduleCheckClicks())}registerMutation(t=Date.now()){this._lastMutation=Rg(t)}registerScroll(t=Date.now()){this._lastScroll=Rg(t)}registerClick(t){const n=K5(t);this._handleMultiClick(n)}_handleMultiClick(t){this._getClicks(t).forEach(n=>{n.clickCount++})}_getClicks(t){return this._clicks.filter(n=>n.node===t)}_checkClicks(){const t=[],n=A_();this._clicks.forEach(r=>{!r.mutationAfter&&this._lastMutation&&(r.mutationAfter=r.timestamp<=this._lastMutation?this._lastMutation-r.timestamp:void 0),!r.scrollAfter&&this._lastScroll&&(r.scrollAfter=r.timestamp<=this._lastScroll?this._lastScroll-r.timestamp:void 0),r.timestamp+this._timeout<=n&&t.push(r)});for(const r of t){const o=this._clicks.indexOf(r);o>-1&&(this._generateBreadcrumbs(r),this._clicks.splice(o,1))}this._clicks.length&&this._scheduleCheckClicks()}_generateBreadcrumbs(t){const n=this._replay,r=t.scrollAfter&&t.scrollAfter<=this._scollTimeout,o=t.mutationAfter&&t.mutationAfter<=this._threshold,i=!r&&!o,{clickCount:s,clickBreadcrumb:a}=t;if(i){const l=Math.min(t.mutationAfter||this._timeout,this._timeout)*1e3,c=l1){const l={type:"default",message:a.message,timestamp:a.timestamp,category:"ui.multiClick",data:{...a.data,url:Le.location.href,route:n.getCurrentRoute(),clickCount:s,metric:!0}};this._addBreadcrumbEvent(n,l)}}_scheduleCheckClicks(){this._checkClickTimeout&&clearTimeout(this._checkClickTimeout),this._checkClickTimeout=setTimeout(()=>this._checkClicks(),1e3)}}const FL=["A","BUTTON","INPUT"];function jL(e,t){return!!(!FL.includes(e.tagName)||e.tagName==="INPUT"&&!["submit","button"].includes(e.getAttribute("type")||"")||e.tagName==="A"&&(e.hasAttribute("download")||e.hasAttribute("target")&&e.getAttribute("target")!=="_self")||t&&e.matches(t))}function LL(e){return!!(e.data&&typeof e.data.nodeId=="number"&&e.timestamp)}function A_(){return Date.now()/1e3}function VL(e,t){try{if(!zL(t))return;const{source:n}=t.data;if(n===he.Mutation&&e.registerMutation(t.timestamp),n===he.Scroll&&e.registerScroll(t.timestamp),BL(t)){const{type:r,id:o}=t.data,i=ii.mirror.getNode(o);i instanceof HTMLElement&&r===qt.Click&&e.registerClick(i)}}catch{}}function zL(e){return e.type===IL}function BL(e){return e.data.source===he.MouseInteraction}function jr(e){return{timestamp:Date.now()/1e3,type:"default",...e}}var Rh;(function(e){e[e.Document=0]="Document",e[e.DocumentType=1]="DocumentType",e[e.Element=2]="Element",e[e.Text=3]="Text",e[e.CDATA=4]="CDATA",e[e.Comment=5]="Comment"})(Rh||(Rh={}));const HL=new Set(["id","class","aria-label","role","name","alt","title","data-test-id","data-testid","disabled","aria-disabled","data-sentry-component"]);function UL(e){const t={};for(const n in e)if(HL.has(n)){let r=n;(n==="data-testid"||n==="data-test-id")&&(r="testId"),t[r]=e[n]}return t}const WL=e=>t=>{if(!e.isEnabled())return;const n=GL(t);if(!n)return;const r=t.name==="click",o=r?t.event:void 0;r&&e.clickDetector&&o&&o.target&&!o.altKey&&!o.metaKey&&!o.ctrlKey&&!o.shiftKey&&DL(e.clickDetector,n,Y5(t.event)),ed(e,n)};function X5(e,t){const n=ii.mirror.getId(e),r=n&&ii.mirror.getNode(n),o=r&&ii.mirror.getMeta(r),i=o&&KL(o)?o:null;return{message:t,data:i?{nodeId:n,node:{id:n,tagName:i.tagName,textContent:Array.from(i.childNodes).map(s=>s.type===Rh.Text&&s.textContent).filter(Boolean).map(s=>s.trim()).join(""),attributes:UL(i.attributes)}}:{}}}function GL(e){const{target:t,message:n}=qL(e);return jr({category:`ui.${e.name}`,...X5(t,n)})}function qL(e){const t=e.name==="click";let n,r=null;try{r=t?Y5(e.event):Q5(e.event),n=bi(r,{maxStringLength:200})||""}catch{n=""}return{target:r,message:n}}function KL(e){return e.type===Rh.Element}function YL(e,t){if(!e.isEnabled())return;e.updateUserActivity();const n=QL(t);n&&ed(e,n)}function QL(e){const{metaKey:t,shiftKey:n,ctrlKey:r,altKey:o,key:i,target:s}=e;if(!s||XL(s)||!i)return null;const a=t||r||o,l=i.length===1;if(!a&&l)return null;const c=bi(s,{maxStringLength:200})||"",u=X5(s,c);return jr({category:"ui.keyDown",message:c,data:{...u.data,metaKey:t,shiftKey:n,ctrlKey:r,altKey:o,key:i}})}function XL(e){return e.tagName==="INPUT"||e.tagName==="TEXTAREA"||e.isContentEditable}const F_={resource:nV,paint:eV,navigation:tV};function ZL(e){return e.map(JL).filter(Boolean)}function JL(e){return F_[e.entryType]?F_[e.entryType](e):null}function sl(e){return((kn||Le.performance.timeOrigin)+e)/1e3}function eV(e){const{duration:t,entryType:n,name:r,startTime:o}=e,i=sl(o);return{type:n,name:r,start:i,end:i+t,data:void 0}}function tV(e){const{entryType:t,name:n,decodedBodySize:r,duration:o,domComplete:i,encodedBodySize:s,domContentLoadedEventStart:a,domContentLoadedEventEnd:l,domInteractive:c,loadEventStart:u,loadEventEnd:d,redirectCount:f,startTime:h,transferSize:m,type:v}=e;return o===0?null:{type:`${t}.${v}`,start:sl(h),end:sl(i),name:n,data:{size:m,decodedBodySize:r,encodedBodySize:s,duration:o,domInteractive:c,domContentLoadedEventStart:a,domContentLoadedEventEnd:l,loadEventStart:u,loadEventEnd:d,domComplete:i,redirectCount:f}}}function nV(e){const{entryType:t,initiatorType:n,name:r,responseEnd:o,startTime:i,decodedBodySize:s,encodedBodySize:a,responseStatus:l,transferSize:c}=e;return["fetch","xmlhttprequest"].includes(n)?null:{type:`${t}.${n}`,start:sl(i),end:sl(o),name:r,data:{size:c,statusCode:l,decodedBodySize:s,encodedBodySize:a}}}function rV(e){const t=e.entries,n=t[t.length-1],r=n?n.element:void 0,o=e.value,i=sl(o);return{type:"largest-contentful-paint",name:"largest-contentful-paint",start:i,end:i,data:{value:o,size:o,nodeId:r?ii.mirror.getId(r):void 0}}}function oV(e){function t(o){e.performanceEntries.includes(o)||e.performanceEntries.push(o)}function n({entries:o}){o.forEach(t)}const r=[];return["navigation","paint","resource"].forEach(o=>{r.push(Xu(o,n))}),r.push(l5(({metric:o})=>{e.replayPerformanceEntries.push(rV(o))})),()=>{r.forEach(o=>o())}}const Fe=typeof __SENTRY_DEBUG__>"u"||__SENTRY_DEBUG__,iV='var t=Uint8Array,n=Uint16Array,r=Int32Array,e=new t([0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0,0]),i=new t([0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,0,0]),a=new t([16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15]),s=function(t,e){for(var i=new n(31),a=0;a<31;++a)i[a]=e+=1<>1|(21845&c)<<1;v=(61680&(v=(52428&v)>>2|(13107&v)<<2))>>4|(3855&v)<<4,u[c]=((65280&v)>>8|(255&v)<<8)>>1}var d=function(t,r,e){for(var i=t.length,a=0,s=new n(r);a>h]=l}else for(o=new n(i),a=0;a>15-t[a]);return o},g=new t(288);for(c=0;c<144;++c)g[c]=8;for(c=144;c<256;++c)g[c]=9;for(c=256;c<280;++c)g[c]=7;for(c=280;c<288;++c)g[c]=8;var w=new t(32);for(c=0;c<32;++c)w[c]=5;var p=d(g,9,0),y=d(w,5,0),m=function(t){return(t+7)/8|0},b=function(n,r,e){return(null==r||r<0)&&(r=0),(null==e||e>n.length)&&(e=n.length),new t(n.subarray(r,e))},M=["unexpected EOF","invalid block type","invalid length/literal","invalid distance","stream finished","no stream handler",,"no callback","invalid UTF-8 data","extra field too long","date not in range 1980-2099","filename too long","stream finishing","invalid zip data"],E=function(t,n,r){var e=new Error(n||M[t]);if(e.code=t,Error.captureStackTrace&&Error.captureStackTrace(e,E),!r)throw e;return e},z=function(t,n,r){r<<=7&n;var e=n/8|0;t[e]|=r,t[e+1]|=r>>8},A=function(t,n,r){r<<=7&n;var e=n/8|0;t[e]|=r,t[e+1]|=r>>8,t[e+2]|=r>>16},_=function(r,e){for(var i=[],a=0;ad&&(d=o[a].s);var g=new n(d+1),w=x(i[c-1],g,0);if(w>e){a=0;var p=0,y=w-e,m=1<e))break;p+=m-(1<>=y;p>0;){var M=o[a].s;g[M]=0&&p;--a){var E=o[a].s;g[E]==e&&(--g[E],++p)}w=e}return{t:new t(g),l:w}},x=function(t,n,r){return-1==t.s?Math.max(x(t.l,n,r+1),x(t.r,n,r+1)):n[t.s]=r},D=function(t){for(var r=t.length;r&&!t[--r];);for(var e=new n(++r),i=0,a=t[0],s=1,o=function(t){e[i++]=t},f=1;f<=r;++f)if(t[f]==a&&f!=r)++s;else{if(!a&&s>2){for(;s>138;s-=138)o(32754);s>2&&(o(s>10?s-11<<5|28690:s-3<<5|12305),s=0)}else if(s>3){for(o(a),--s;s>6;s-=6)o(8304);s>2&&(o(s-3<<5|8208),s=0)}for(;s--;)o(a);s=1,a=t[f]}return{c:e.subarray(0,i),n:r}},T=function(t,n){for(var r=0,e=0;e>8,t[i+2]=255^t[i],t[i+3]=255^t[i+1];for(var a=0;a4&&!H[a[K-1]];--K);var N,P,Q,R,V=v+5<<3,W=T(f,g)+T(h,w)+l,X=T(f,M)+T(h,C)+l+14+3*K+T(q,H)+2*q[16]+3*q[17]+7*q[18];if(c>=0&&V<=W&&V<=X)return k(r,m,t.subarray(c,c+v));if(z(r,m,1+(X15&&(z(r,m,tt[B]>>5&127),m+=tt[B]>>12)}}}else N=p,P=g,Q=y,R=w;for(B=0;B255){A(r,m,N[(nt=rt>>18&31)+257]),m+=P[nt+257],nt>7&&(z(r,m,rt>>23&31),m+=e[nt]);var et=31&rt;A(r,m,Q[et]),m+=R[et],et>3&&(A(r,m,rt>>5&8191),m+=i[et])}else A(r,m,N[rt]),m+=P[rt]}return A(r,m,N[256]),m+P[256]},U=new r([65540,131080,131088,131104,262176,1048704,1048832,2114560,2117632]),F=new t(0),I=function(){for(var t=new Int32Array(256),n=0;n<256;++n){for(var r=n,e=9;--e;)r=(1&r&&-306674912)^r>>>1;t[n]=r}return t}(),S=function(){var t=1,n=0;return{p:function(r){for(var e=t,i=n,a=0|r.length,s=0;s!=a;){for(var o=Math.min(s+2655,a);s>16),i=(65535&i)+15*(i>>16)}t=e,n=i},d:function(){return(255&(t%=65521))<<24|(65280&t)<<8|(255&(n%=65521))<<8|n>>8}}},L=function(a,s,o,f,u){if(!u&&(u={l:1},s.dictionary)){var c=s.dictionary.subarray(-32768),v=new t(c.length+a.length);v.set(c),v.set(a,c.length),a=v,u.w=c.length}return function(a,s,o,f,u,c){var v=c.z||a.length,d=new t(f+v+5*(1+Math.ceil(v/7e3))+u),g=d.subarray(f,d.length-u),w=c.l,p=7&(c.r||0);if(s){p&&(g[0]=c.r>>3);for(var y=U[s-1],M=y>>13,E=8191&y,z=(1<7e3||q>24576)&&(N>423||!w)){p=C(a,g,0,F,I,S,O,q,G,j-G,p),q=L=O=0,G=j;for(var P=0;P<286;++P)I[P]=0;for(P=0;P<30;++P)S[P]=0}var Q=2,R=0,V=E,W=J-K&32767;if(N>2&&H==T(j-W))for(var X=Math.min(M,N)-1,Y=Math.min(32767,j),Z=Math.min(258,N);W<=Y&&--V&&J!=K;){if(a[j+Q]==a[j+Q-W]){for(var $=0;$Q){if(Q=$,R=W,$>X)break;var tt=Math.min(W,$-2),nt=0;for(P=0;Pnt&&(nt=et,K=rt)}}}W+=(J=K)-(K=A[J])&32767}if(R){F[q++]=268435456|h[Q]<<18|l[R];var it=31&h[Q],at=31&l[R];O+=e[it]+i[at],++I[257+it],++S[at],B=j+Q,++L}else F[q++]=a[j],++I[a[j]]}}for(j=Math.max(j,B);j=v&&(g[p/8|0]=w,st=v),p=k(g,p+1,a.subarray(j,st))}c.i=v}return b(d,0,f+m(p)+u)}(a,null==s.level?6:s.level,null==s.mem?Math.ceil(1.5*Math.max(8,Math.min(13,Math.log(a.length)))):12+s.mem,o,f,u)},O=function(t,n,r){for(;r;++n)t[n]=r,r>>>=8},j=function(){function n(n,r){if("function"==typeof n&&(r=n,n={}),this.ondata=r,this.o=n||{},this.s={l:0,i:32768,w:32768,z:32768},this.b=new t(98304),this.o.dictionary){var e=this.o.dictionary.subarray(-32768);this.b.set(e,32768-e.length),this.s.i=32768-e.length}}return n.prototype.p=function(t,n){this.ondata(L(t,this.o,0,0,this.s),n)},n.prototype.push=function(n,r){this.ondata||E(5),this.s.l&&E(4);var e=n.length+this.s.z;if(e>this.b.length){if(e>2*this.b.length-32768){var i=new t(-32768&e);i.set(this.b.subarray(0,this.s.z)),this.b=i}var a=this.b.length-this.s.z;a&&(this.b.set(n.subarray(0,a),this.s.z),this.s.z=this.b.length,this.p(this.b,!1)),this.b.set(this.b.subarray(-32768)),this.b.set(n.subarray(a),32768),this.s.z=n.length-a+32768,this.s.i=32766,this.s.w=32768}else this.b.set(n,this.s.z),this.s.z+=n.length;this.s.l=1&r,(this.s.z>this.s.w+8191||r)&&(this.p(this.b,r||!1),this.s.w=this.s.i,this.s.i-=2)},n}();function q(t,n){n||(n={});var r=function(){var t=-1;return{p:function(n){for(var r=t,e=0;e>>8;t=r},d:function(){return~t}}}(),e=t.length;r.p(t);var i,a=L(t,n,10+((i=n).filename?i.filename.length+1:0),8),s=a.length;return function(t,n){var r=n.filename;if(t[0]=31,t[1]=139,t[2]=8,t[8]=n.level<2?4:9==n.level?2:0,t[9]=3,0!=n.mtime&&O(t,4,Math.floor(new Date(n.mtime||Date.now())/1e3)),r){t[3]=8;for(var e=0;e<=r.length;++e)t[e+10]=r.charCodeAt(e)}}(a,n),O(a,s-8,r.d()),O(a,s-4,e),a}var B=function(){function t(t,n){this.c=S(),this.v=1,j.call(this,t,n)}return t.prototype.push=function(t,n){this.c.p(t),j.prototype.push.call(this,t,n)},t.prototype.p=function(t,n){var r=L(t,this.o,this.v&&(this.o.dictionary?6:2),n&&4,this.s);this.v&&(function(t,n){var r=n.level,e=0==r?0:r<6?1:9==r?3:2;if(t[0]=120,t[1]=e<<6|(n.dictionary&&32),t[1]|=31-(t[0]<<8|t[1])%31,n.dictionary){var i=S();i.p(n.dictionary),O(t,2,i.d())}}(r,this.o),this.v=0),n&&O(r,r.length-4,this.c.d()),this.ondata(r,n)},t}(),G="undefined"!=typeof TextEncoder&&new TextEncoder,H="undefined"!=typeof TextDecoder&&new TextDecoder;try{H.decode(F,{stream:!0})}catch(t){}var J=function(){function t(t){this.ondata=t}return t.prototype.push=function(t,n){this.ondata||E(5),this.d&&E(4),this.ondata(K(t),this.d=n||!1)},t}();function K(n,r){if(r){for(var e=new t(n.length),i=0;i>1)),o=0,f=function(t){s[o++]=t};for(i=0;is.length){var h=new t(o+8+(a-i<<1));h.set(s),s=h}var l=n.charCodeAt(i);l<128||r?f(l):l<2048?(f(192|l>>6),f(128|63&l)):l>55295&&l<57344?(f(240|(l=65536+(1047552&l)|1023&n.charCodeAt(++i))>>18),f(128|l>>12&63),f(128|l>>6&63),f(128|63&l)):(f(224|l>>12),f(128|l>>6&63),f(128|63&l))}return b(s,0,o)}const N=new class{constructor(){this._init()}clear(){this._init()}addEvent(t){if(!t)throw new Error("Adding invalid event");const n=this._hasEvents?",":"";this.stream.push(n+t),this._hasEvents=!0}finish(){this.stream.push("]",!0);const t=function(t){let n=0;for(let r=0,e=t.length;r{this._deflatedData.push(t)},this.stream=new J(((t,n)=>{this.deflate.push(t,n)})),this.stream.push("[")}},P={clear:()=>{N.clear()},addEvent:t=>N.addEvent(t),finish:()=>N.finish(),compress:t=>function(t){return q(K(t))}(t)};addEventListener("message",(function(t){const n=t.data.method,r=t.data.id,e=t.data.arg;if(n in P&&"function"==typeof P[n])try{const t=P[n](e);postMessage({id:r,method:n,success:!0,response:t})}catch(t){postMessage({id:r,method:n,success:!1,response:t.message}),console.error(t)}})),postMessage({id:void 0,method:"init",success:!0,response:void 0});';function sV(){const e=new Blob([iV]);return URL.createObjectURL(e)}function Qt(e,t){Fe&&(j.info(e),t&&Z5(e))}function Fa(e,t){Fe&&(j.info(e),t&&setTimeout(()=>{Z5(e)},0))}function Z5(e){wi({category:"console",data:{logger:"replay"},level:"info",message:e},{level:"info"})}class Lb extends Error{constructor(){super(`Event buffer exceeded maximum size of ${Nb}.`)}}class J5{constructor(){this.events=[],this._totalSize=0,this.hasCheckout=!1}get hasEvents(){return this.events.length>0}get type(){return"sync"}destroy(){this.events=[]}async addEvent(t){const n=JSON.stringify(t).length;if(this._totalSize+=n,this._totalSize>Nb)throw new Lb;this.events.push(t)}finish(){return new Promise(t=>{const n=this.events;this.clear(),t(JSON.stringify(n))})}clear(){this.events=[],this._totalSize=0,this.hasCheckout=!1}getEarliestTimestamp(){const t=this.events.map(n=>n.timestamp).sort()[0];return t?jb(t):null}}class aV{constructor(t){this._worker=t,this._id=0}ensureReady(){return this._ensureReadyPromise?this._ensureReadyPromise:(this._ensureReadyPromise=new Promise((t,n)=>{this._worker.addEventListener("message",({data:r})=>{r.success?t():n()},{once:!0}),this._worker.addEventListener("error",r=>{n(r)},{once:!0})}),this._ensureReadyPromise)}destroy(){Qt("[Replay] Destroying compression worker"),this._worker.terminate()}postMessage(t,n){const r=this._getAndIncrementId();return new Promise((o,i)=>{const s=({data:a})=>{const l=a;if(l.method===t&&l.id===r){if(this._worker.removeEventListener("message",s),!l.success){Fe&&j.error("[Replay]",l.response),i(new Error("Error in compression worker"));return}o(l.response)}};this._worker.addEventListener("message",s),this._worker.postMessage({id:r,method:t,arg:n})})}_getAndIncrementId(){return this._id++}}class lV{constructor(t){this._worker=new aV(t),this._earliestTimestamp=null,this._totalSize=0,this.hasCheckout=!1}get hasEvents(){return!!this._earliestTimestamp}get type(){return"worker"}ensureReady(){return this._worker.ensureReady()}destroy(){this._worker.destroy()}addEvent(t){const n=jb(t.timestamp);(!this._earliestTimestamp||nNb?Promise.reject(new Lb):this._sendEventToWorker(r)}finish(){return this._finishRequest()}clear(){this._earliestTimestamp=null,this._totalSize=0,this.hasCheckout=!1,this._worker.postMessage("clear").then(null,t=>{Fe&&j.warn('[Replay] Sending "clear" message to worker failed',t)})}getEarliestTimestamp(){return this._earliestTimestamp}_sendEventToWorker(t){return this._worker.postMessage("addEvent",t)}async _finishRequest(){const t=await this._worker.postMessage("finish");return this._earliestTimestamp=null,this._totalSize=0,t}}class cV{constructor(t){this._fallback=new J5,this._compression=new lV(t),this._used=this._fallback,this._ensureWorkerIsLoadedPromise=this._ensureWorkerIsLoaded()}get type(){return this._used.type}get hasEvents(){return this._used.hasEvents}get hasCheckout(){return this._used.hasCheckout}set hasCheckout(t){this._used.hasCheckout=t}destroy(){this._fallback.destroy(),this._compression.destroy()}clear(){return this._used.clear()}getEarliestTimestamp(){return this._used.getEarliestTimestamp()}addEvent(t){return this._used.addEvent(t)}async finish(){return await this.ensureWorkerIsLoaded(),this._used.finish()}ensureWorkerIsLoaded(){return this._ensureWorkerIsLoadedPromise}async _ensureWorkerIsLoaded(){try{await this._compression.ensureReady()}catch{Qt("[Replay] Failed to load the compression worker, falling back to simple buffer");return}await this._switchToCompressionWorker()}async _switchToCompressionWorker(){const{events:t,hasCheckout:n}=this._fallback,r=[];for(const o of t)r.push(this._compression.addEvent(o));this._compression.hasCheckout=n,this._used=this._compression;try{await Promise.all(r)}catch(o){Fe&&j.warn("[Replay] Failed to add events when switching buffers.",o)}}}function uV({useCompression:e,workerUrl:t}){if(e&&window.Worker){const n=dV(t);if(n)return n}return Qt("[Replay] Using simple buffer"),new J5}function dV(e){try{const t=e||fV();if(!t)return;Qt(`[Replay] Using compression worker${e?` from ${e}`:""}`);const n=new Worker(t);return new cV(n)}catch{Qt("[Replay] Failed to create compression worker")}}function fV(){return typeof __SENTRY_EXCLUDE_REPLAY_WORKER__>"u"||!__SENTRY_EXCLUDE_REPLAY_WORKER__?sV():""}function Vb(){try{return"sessionStorage"in Le&&!!Le.sessionStorage}catch{return!1}}function hV(e){pV(),e.session=void 0}function pV(){if(Vb())try{Le.sessionStorage.removeItem(Pb)}catch{}}function eR(e){return e===void 0?!1:Math.random()e.getContext().initialTimestamp+e.getOptions().maxReplayDuration?(Qt(`[Replay] Skipping event with timestamp ${n} because it is after maxReplayDuration`,e.getOptions()._experiments.traceInternals),!1):!0}function bV(e,t){try{if(typeof t=="function"&&vV(e))return t(e)}catch(n){return Fe&&j.error("[Replay] An error occured in the `beforeAddRecordingEvent` callback, skipping the event...",n),null}return e}function Hb(e){return!e.type}function Uy(e){return e.type==="transaction"}function wV(e){return e.type==="replay_event"}function L_(e){return e.type==="feedback"}function sR(e){const t=_V();return(n,r)=>{if(!e.isEnabled()||!Hb(n)&&!Uy(n))return;const o=r&&r.statusCode;if(!(t&&(!o||o<200||o>=300))){if(Uy(n)){SV(e,n);return}xV(e,n)}}}function SV(e,t){const n=e.getContext();t.contexts&&t.contexts.trace&&t.contexts.trace.trace_id&&n.traceIds.size<100&&n.traceIds.add(t.contexts.trace.trace_id)}function xV(e,t){const n=e.getContext();if(t.event_id&&n.errorIds.size<100&&n.errorIds.add(t.event_id),e.recordingMode!=="buffer"||!t.tags||!t.tags.replayId)return;const{beforeErrorSampling:r}=e.getOptions();typeof r=="function"&&!r(t)||setTimeout(()=>{e.sendBufferedReplayOrFlush()})}function _V(){const e=ke();if(!e)return!1;const t=e.getTransport();return t&&t.send.__sentry__baseTransport__||!1}function EV(e){return t=>{!e.isEnabled()||!Hb(t)||CV(e,t)}}function CV(e,t){const n=t.exception&&t.exception.values&&t.exception.values[0].value;if(typeof n=="string"&&(n.match(/reactjs\.org\/docs\/error-decoder\.html\?invariant=(418|419|422|423|425)/)||n.match(/(does not match server-rendered HTML|Hydration failed because)/i))){const r=jr({category:"replay.hydrate-error"});ed(e,r)}}function kV(e,t){return e.type||!e.exception||!e.exception.values||!e.exception.values.length?!1:!!(t.originalException&&t.originalException.__rrweb__)}function TV(e,t){e.triggerUserActivity(),e.addUpdate(()=>t.timestamp?(e.throttledAddEvent({type:fe.Custom,timestamp:t.timestamp*1e3,data:{tag:"breadcrumb",payload:{timestamp:t.timestamp,type:"default",category:"sentry.feedback",data:{feedbackId:t.event_id}}}}),!1):!0)}function RV(e,t){return e.recordingMode!=="buffer"||t.message===Ob||!t.exception||t.type?!1:eR(e.getOptions().errorSampleRate)}function IV(e,t=!1){const n=t?sR(e):void 0;return Object.assign((r,o)=>e.isEnabled()?wV(r)?(delete r.breadcrumbs,r):!Hb(r)&&!Uy(r)&&!L_(r)||!e.checkAndHandleExpiredSession()?r:L_(r)?(e.flush(),r.contexts.feedback.replay_id=e.getSessionId(),TV(e,r),r):kV(r,o)&&!e.getOptions()._experiments.captureExceptions?(Fe&&j.log("[Replay] Ignoring error from rrweb internals",r),null):((RV(e,r)||e.recordingMode==="session")&&(r.tags={...r.tags,replayId:e.getSessionId()}),n&&n(r,{statusCode:200}),r):r,{id:"Replay"})}function zp(e,t){return t.map(({type:n,start:r,end:o,name:i,data:s})=>{const a=e.throttledAddEvent({type:fe.Custom,timestamp:r,data:{tag:"performanceSpan",payload:{op:n,description:i,startTimestamp:r,endTimestamp:o,data:s}}});return typeof a=="string"?Promise.resolve(null):a})}function $V(e){const{from:t,to:n}=e,r=Date.now()/1e3;return{type:"navigation.push",start:r,end:r,name:n,data:{previous:t}}}function PV(e){return t=>{if(!e.isEnabled())return;const n=$V(t);n!==null&&(e.getContext().urls.push(n.name),e.triggerUserActivity(),e.addUpdate(()=>(zp(e,[n]),!1)))}}function OV(e,t){return Fe&&e.getOptions()._experiments.traceInternals?!1:PD(t,ke())}function Bp(e,t){e.isEnabled()&&t!==null&&(OV(e,t.name)||e.addUpdate(()=>(zp(e,[t]),!0)))}function NV(e){const{startTimestamp:t,endTimestamp:n,fetchData:r,response:o}=e;if(!n)return null;const{method:i,url:s}=r;return{type:"resource.fetch",start:t/1e3,end:n/1e3,name:s,data:{method:i,statusCode:o?o.status:void 0}}}function MV(e){return t=>{if(!e.isEnabled())return;const n=NV(t);Bp(e,n)}}function DV(e){const{startTimestamp:t,endTimestamp:n,xhr:r}=e,o=r[ti];if(!t||!n||!o)return null;const{method:i,url:s,status_code:a}=o;return s===void 0?null:{type:"resource.xhr",name:s,start:t/1e3,end:n/1e3,data:{method:i,statusCode:a}}}function AV(e){return t=>{if(!e.isEnabled())return;const n=DV(t);Bp(e,n)}}function Hp(e,t){if(e)try{if(typeof e=="string")return t.encode(e).length;if(e instanceof URLSearchParams)return t.encode(e.toString()).length;if(e instanceof FormData){const n=uR(e);return t.encode(n).length}if(e instanceof Blob)return e.size;if(e instanceof ArrayBuffer)return e.byteLength}catch{}}function aR(e){if(!e)return;const t=parseInt(e,10);return isNaN(t)?void 0:t}function lR(e){try{if(typeof e=="string")return[e];if(e instanceof URLSearchParams)return[e.toString()];if(e instanceof FormData)return[uR(e)];if(!e)return[void 0]}catch{return Fe&&j.warn("[Replay] Failed to serialize body",e),[void 0,"BODY_PARSE_ERROR"]}return Fe&&j.info("[Replay] Skipping network body because of body type",e),[void 0,"UNPARSEABLE_BODY_TYPE"]}function Ih(e,t){if(!e)return{headers:{},size:void 0,_meta:{warnings:[t]}};const n={...e._meta},r=n.warnings||[];return n.warnings=[...r,t],e._meta=n,e}function cR(e,t){if(!t)return null;const{startTimestamp:n,endTimestamp:r,url:o,method:i,statusCode:s,request:a,response:l}=t;return{type:e,start:n/1e3,end:r/1e3,name:o,data:Zt({method:i,statusCode:s,request:a,response:l})}}function cu(e){return{headers:{},size:e,_meta:{warnings:["URL_SKIPPED"]}}}function si(e,t,n){if(!t&&Object.keys(e).length===0)return;if(!t)return{headers:e};if(!n)return{headers:e,size:t};const r={headers:e,size:t},{body:o,warnings:i}=FV(n);return r.body=o,i&&i.length>0&&(r._meta={warnings:i}),r}function Wy(e,t){return Object.keys(e).reduce((n,r)=>{const o=r.toLowerCase();return t.includes(o)&&e[r]&&(n[o]=e[r]),n},{})}function uR(e){return new URLSearchParams(e).toString()}function FV(e){if(!e||typeof e!="string")return{body:e};const t=e.length>E_,n=jV(e);if(t){const r=e.slice(0,E_);return n?{body:r,warnings:["MAYBE_JSON_TRUNCATED"]}:{body:`${r}…`,warnings:["TEXT_TRUNCATED"]}}if(n)try{return{body:JSON.parse(e)}}catch{}return{body:e}}function jV(e){const t=e[0],n=e[e.length-1];return t==="["&&n==="]"||t==="{"&&n==="}"}function $h(e,t){const n=LV(e);return Il(n,t)}function LV(e,t=Le.document.baseURI){if(e.startsWith("http://")||e.startsWith("https://")||e.startsWith(Le.location.origin))return e;const n=new URL(e,t);if(n.origin!==new URL(t).origin)return e;const r=n.href;return!e.endsWith("/")&&r.endsWith("/")?r.slice(0,-1):r}async function VV(e,t,n){try{const r=await BV(e,t,n),o=cR("resource.fetch",r);Bp(n.replay,o)}catch(r){Fe&&j.error("[Replay] Failed to capture fetch breadcrumb",r)}}function zV(e,t,n){const{input:r,response:o}=t,i=r?dR(r):void 0,s=Hp(i,n.textEncoder),a=o?aR(o.headers.get("content-length")):void 0;s!==void 0&&(e.data.request_body_size=s),a!==void 0&&(e.data.response_body_size=a)}async function BV(e,t,n){const r=Date.now(),{startTimestamp:o=r,endTimestamp:i=r}=t,{url:s,method:a,status_code:l=0,request_body_size:c,response_body_size:u}=e.data,d=$h(s,n.networkDetailAllowUrls)&&!$h(s,n.networkDetailDenyUrls),f=d?HV(n,t.input,c):cu(c),h=await UV(d,n,t.response,u);return{startTimestamp:o,endTimestamp:i,url:s,method:a,statusCode:l,request:f,response:h}}function HV({networkCaptureBodies:e,networkRequestHeaders:t},n,r){const o=n?qV(n,t):{};if(!e)return si(o,r,void 0);const i=dR(n),[s,a]=lR(i),l=si(o,r,s);return a?Ih(l,a):l}async function UV(e,{networkCaptureBodies:t,textEncoder:n,networkResponseHeaders:r},o,i){if(!e&&i!==void 0)return cu(i);const s=o?fR(o.headers,r):{};if(!o||!t&&i!==void 0)return si(s,i,void 0);const[a,l]=await GV(o),c=WV(a,{networkCaptureBodies:t,textEncoder:n,responseBodySize:i,captureDetails:e,headers:s});return l?Ih(c,l):c}function WV(e,{networkCaptureBodies:t,textEncoder:n,responseBodySize:r,captureDetails:o,headers:i}){try{const s=e&&e.length&&r===void 0?Hp(e,n):r;return o?t?si(i,s,e):si(i,s,void 0):cu(s)}catch(s){return Fe&&j.warn("[Replay] Failed to serialize response body",s),si(i,r,void 0)}}async function GV(e){const t=KV(e);if(!t)return[void 0,"BODY_PARSE_ERROR"];try{return[await YV(t)]}catch(n){return Fe&&j.warn("[Replay] Failed to get text body from response",n),[void 0,"BODY_PARSE_ERROR"]}}function dR(e=[]){if(!(e.length!==2||typeof e[1]!="object"))return e[1].body}function fR(e,t){const n={};return t.forEach(r=>{e.get(r)&&(n[r]=e.get(r))}),n}function qV(e,t){return e.length===1&&typeof e[0]!="string"?V_(e[0],t):e.length===2?V_(e[1],t):{}}function V_(e,t){if(!e)return{};const n=e.headers;return n?n instanceof Headers?fR(n,t):Array.isArray(n)?{}:Wy(n,t):{}}function KV(e){try{return e.clone()}catch(t){Fe&&j.warn("[Replay] Failed to clone response body",t)}}function YV(e){return new Promise((t,n)=>{const r=setTimeout(()=>n(new Error("Timeout while trying to read response body")),500);QV(e).then(o=>t(o),o=>n(o)).finally(()=>clearTimeout(r))})}async function QV(e){return await e.text()}async function XV(e,t,n){try{const r=JV(e,t,n),o=cR("resource.xhr",r);Bp(n.replay,o)}catch(r){Fe&&j.error("[Replay] Failed to capture xhr breadcrumb",r)}}function ZV(e,t,n){const{xhr:r,input:o}=t;if(!r)return;const i=Hp(o,n.textEncoder),s=r.getResponseHeader("content-length")?aR(r.getResponseHeader("content-length")):rz(r.response,r.responseType,n.textEncoder);i!==void 0&&(e.data.request_body_size=i),s!==void 0&&(e.data.response_body_size=s)}function JV(e,t,n){const r=Date.now(),{startTimestamp:o=r,endTimestamp:i=r,input:s,xhr:a}=t,{url:l,method:c,status_code:u=0,request_body_size:d,response_body_size:f}=e.data;if(!l)return null;if(!a||!$h(l,n.networkDetailAllowUrls)||$h(l,n.networkDetailDenyUrls)){const E=cu(d),C=cu(f);return{startTimestamp:o,endTimestamp:i,url:l,method:c,statusCode:u,request:E,response:C}}const h=a[ti],m=h?Wy(h.request_headers,n.networkRequestHeaders):{},v=Wy(ez(a),n.networkResponseHeaders),[S,y]=n.networkCaptureBodies?lR(s):[void 0],[b,w]=n.networkCaptureBodies?tz(a):[void 0],x=si(m,d,S),_=si(v,f,b);return{startTimestamp:o,endTimestamp:i,url:l,method:c,statusCode:u,request:y?Ih(x,y):x,response:w?Ih(_,w):_}}function ez(e){const t=e.getAllResponseHeaders();return t?t.split(`\r +`).reduce((n,r)=>{const[o,i]=r.split(": ");return n[o.toLowerCase()]=i,n},{}):{}}function tz(e){const t=[];try{return[e.responseText]}catch(n){t.push(n)}try{return nz(e.response,e.responseType)}catch(n){t.push(n)}return Fe&&j.warn("[Replay] Failed to get xhr response body",...t),[void 0]}function nz(e,t){try{if(typeof e=="string")return[e];if(e instanceof Document)return[e.body.outerHTML];if(t==="json"&&e&&typeof e=="object")return[JSON.stringify(e)];if(!e)return[void 0]}catch{return Fe&&j.warn("[Replay] Failed to serialize body",e),[void 0,"BODY_PARSE_ERROR"]}return Fe&&j.info("[Replay] Skipping network body because of body type",e),[void 0,"UNPARSEABLE_BODY_TYPE"]}function rz(e,t,n){try{const r=t==="json"&&e&&typeof e=="object"?JSON.stringify(e):e;return Hp(r,n)}catch{return}}function oz(e){const t=ke();try{const n=new TextEncoder,{networkDetailAllowUrls:r,networkDetailDenyUrls:o,networkCaptureBodies:i,networkRequestHeaders:s,networkResponseHeaders:a}=e.getOptions(),l={replay:e,textEncoder:n,networkDetailAllowUrls:r,networkDetailDenyUrls:o,networkCaptureBodies:i,networkRequestHeaders:s,networkResponseHeaders:a};t&&t.on?t.on("beforeAddBreadcrumb",(c,u)=>iz(l,c,u)):(pb(MV(e)),mb(AV(e)))}catch{}}function iz(e,t,n){if(t.data)try{sz(t)&&lz(n)&&(ZV(t,n,e),XV(t,n,e)),az(t)&&cz(n)&&(zV(t,n,e),VV(t,n,e))}catch{Fe&&j.warn("Error when enriching network breadcrumb")}}function sz(e){return e.category==="xhr"}function az(e){return e.category==="fetch"}function lz(e){return e&&e.xhr}function cz(e){return e&&e.response}let z_=null;function uz(e){return!!e.category}const dz=e=>t=>{if(!e.isEnabled())return;const n=fz(t);n&&ed(e,n)};function fz(e){const t=e.getLastBreadcrumb&&e.getLastBreadcrumb();return z_===t||!t||(z_=t,!uz(t)||["fetch","xhr","sentry.event","sentry.transaction"].includes(t.category)||t.category.startsWith("ui."))?null:t.category==="console"?hz(t):jr(t)}function hz(e){const t=e.data&&e.data.arguments;if(!Array.isArray(t)||t.length===0)return jr(e);let n=!1;const r=t.map(o=>{if(!o)return o;if(typeof o=="string")return o.length>Ud?(n=!0,`${o.slice(0,Ud)}…`):o;if(typeof o=="object")try{const i=Or(o,7);return JSON.stringify(i).length>Ud?(n=!0,`${JSON.stringify(i,null,2).slice(0,Ud)}…`):i}catch{}return o});return jr({...e,data:{...e.data,arguments:r,...n?{_meta:{warnings:["CONSOLE_ARG_TRUNCATED"]}}:{}}})}function pz(e){const t=pn(),n=ke();t.addScopeListener(dz(e)),pT(WL(e)),$p(PV(e)),oz(e);const r=IV(e,!B_(n));n&&n.addEventProcessor?n.addEventProcessor(r):ED(r),B_(n)&&(n.on("beforeSendEvent",EV(e)),n.on("afterSendEvent",sR(e)),n.on("createDsc",o=>{const i=e.getSessionId();i&&e.isEnabled()&&e.recordingMode==="session"&&e.checkAndHandleExpiredSession()&&(o.replay_id=i)}),n.on("startTransaction",o=>{e.lastTransaction=o}),n.on("finishTransaction",o=>{e.lastTransaction=o}),n.on("beforeSendFeedback",(o,i)=>{const s=e.getSessionId();i&&i.includeReplay&&e.isEnabled()&&s&&o.contexts&&o.contexts.feedback&&(o.contexts.feedback.replay_id=s)}))}function B_(e){return!!(e&&e.on)}async function mz(e){try{return Promise.all(zp(e,[gz(Le.performance.memory)]))}catch{return[]}}function gz(e){const{jsHeapSizeLimit:t,totalJSHeapSize:n,usedJSHeapSize:r}=e,o=Date.now()/1e3;return{type:"memory",name:"memory",start:o,end:o,data:{memory:{jsHeapSizeLimit:t,totalJSHeapSize:n,usedJSHeapSize:r}}}}function vz(e,t,n){let r,o,i;const s=n&&n.maxWait?Math.max(n.maxWait,t):0;function a(){return l(),r=e(),r}function l(){o!==void 0&&clearTimeout(o),i!==void 0&&clearTimeout(i),o=i=void 0}function c(){return o!==void 0||i!==void 0?a():r}function u(){return o&&clearTimeout(o),o=setTimeout(a,t),s&&i===void 0&&(i=setTimeout(a,s)),r}return u.cancel=l,u.flush=c,u}function yz(e){let t=!1;return(n,r)=>{if(!e.checkAndHandleExpiredSession()){Fe&&j.warn("[Replay] Received replay event after session expired.");return}const o=r||!t;t=!0,e.clickDetector&&VL(e.clickDetector,n),e.addUpdate(()=>{if(e.recordingMode==="buffer"&&o&&e.setInitialState(),!Bb(e,n,o))return!0;if(!o)return!1;if(wz(e,o),e.session&&e.session.previousSessionId)return!0;if(e.recordingMode==="buffer"&&e.session&&e.eventBuffer){const i=e.eventBuffer.getEarliestTimestamp();i&&(Qt(`[Replay] Updating session start time to earliest event in buffer to ${new Date(i)}`,e.getOptions()._experiments.traceInternals),e.session.started=i,e.getOptions().stickySession&&zb(e.session))}return e.recordingMode==="session"&&e.flush(),!0})}}function bz(e){const t=e.getOptions();return{type:fe.Custom,timestamp:Date.now(),data:{tag:"options",payload:{shouldRecordCanvas:e.isRecordingCanvas(),sessionSampleRate:t.sessionSampleRate,errorSampleRate:t.errorSampleRate,useCompressionOption:t.useCompression,blockAllMedia:t.blockAllMedia,maskAllText:t.maskAllText,maskAllInputs:t.maskAllInputs,useCompression:e.eventBuffer?e.eventBuffer.type==="worker":!1,networkDetailHasUrls:t.networkDetailAllowUrls.length>0,networkCaptureBodies:t.networkCaptureBodies,networkRequestHasHeaders:t.networkRequestHeaders.length>0,networkResponseHasHeaders:t.networkResponseHeaders.length>0}}}}function wz(e,t){!t||!e.session||e.session.segmentId!==0||Bb(e,bz(e),!1)}function Sz(e,t,n,r){return Ai(xT(e,yb(e),r,n),[[{type:"replay_event"},e],[{type:"replay_recording",length:typeof t=="string"?new TextEncoder().encode(t).length:t.length},t]])}function xz({recordingData:e,headers:t}){let n;const r=`${JSON.stringify(t)} +`;if(typeof e=="string")n=`${r}${e}`;else{const i=new TextEncoder().encode(r);n=new Uint8Array(i.length+e.length),n.set(i),n.set(e,i.length)}return n}async function _z({client:e,scope:t,replayId:n,event:r}){const o=typeof e._integrations=="object"&&e._integrations!==null&&!Array.isArray(e._integrations)?Object.keys(e._integrations):void 0,i={event_id:n,integrations:o};e.emit&&e.emit("preprocessEvent",r,i);const s=await xb(e.getOptions(),r,i,t,e,$o());if(!s)return null;s.platform=s.platform||"javascript";const a=e.getSdkMetadata&&e.getSdkMetadata(),{name:l,version:c}=a&&a.sdk||{};return s.sdk={...s.sdk,name:l||"sentry.javascript.unknown",version:c||"0.0.0"},s}async function Ez({recordingData:e,replayId:t,segmentId:n,eventContext:r,timestamp:o,session:i}){const s=xz({recordingData:e,headers:{segment_id:n}}),{urls:a,errorIds:l,traceIds:c,initialTimestamp:u}=r,d=ke(),f=pn(),h=d&&d.getTransport(),m=d&&d.getDsn();if(!d||!h||!m||!i.sampled)return;const v={type:lj,replay_start_timestamp:u/1e3,timestamp:o/1e3,error_ids:l,trace_ids:c,urls:a,replay_id:t,segment_id:n,replay_type:i.sampled},S=await _z({scope:f,client:d,replayId:t,event:v});if(!S){d.recordDroppedEvent("event_processor","replay",v),Qt("An event processor returned `null`, will not send event.");return}delete S.sdkProcessingMetadata;const y=Sz(S,s,m,d.getOptions().tunnel);let b;try{b=await h.send(y)}catch(x){const _=new Error(Ob);try{_.cause=x}catch{}throw _}if(!b)return b;if(typeof b.statusCode=="number"&&(b.statusCode<200||b.statusCode>=300))throw new hR(b.statusCode);const w=ET({},b);if(_T(w,"replay"))throw new pR(w);return b}class hR extends Error{constructor(t){super(`Transport returned status code ${t}`)}}class pR extends Error{constructor(t){super("Rate limit hit"),this.rateLimits=t}}async function mR(e,t={count:0,interval:pj}){const{recordingData:n,options:r}=e;if(n.length)try{return await Ez(e),!0}catch(o){if(o instanceof hR||o instanceof pR)throw o;if(DM("Replays",{_retryCount:t.count}),Fe&&r._experiments&&r._experiments.captureExceptions&&Ol(o),t.count>=mj){const i=new Error(`${Ob} - max retries exceeded`);try{i.cause=o}catch{}throw i}return t.interval*=++t.count,new Promise((i,s)=>{setTimeout(async()=>{try{await mR(e,t),i(!0)}catch(a){s(a)}},t.interval)})}}const gR="__THROTTLED",Cz="__SKIPPED";function kz(e,t,n){const r=new Map,o=a=>{const l=a-n;r.forEach((c,u)=>{u[...r.values()].reduce((a,l)=>a+l,0);let s=!1;return(...a)=>{const l=Math.floor(Date.now()/1e3);if(o(l),i()>=t){const u=s;return s=!0,u?Cz:gR}s=!1;const c=r.get(l)||0;return r.set(l,c+1),e(...a)}}class Wo{constructor({options:t,recordingOptions:n}){Wo.prototype.__init.call(this),Wo.prototype.__init2.call(this),Wo.prototype.__init3.call(this),Wo.prototype.__init4.call(this),Wo.prototype.__init5.call(this),Wo.prototype.__init6.call(this),this.eventBuffer=null,this.performanceEntries=[],this.replayPerformanceEntries=[],this.recordingMode="session",this.timeouts={sessionIdlePause:cj,sessionIdleExpire:uj},this._lastActivity=Date.now(),this._isEnabled=!1,this._isPaused=!1,this._hasInitializedCoreListeners=!1,this._context={errorIds:new Set,traceIds:new Set,urls:[],initialTimestamp:Date.now(),initialUrl:""},this._recordingOptions=n,this._options=t,this._debouncedFlush=vz(()=>this._flush(),this._options.flushMinDelay,{maxWait:this._options.flushMaxDelay}),this._throttledAddEvent=kz((s,a)=>yV(this,s,a),300,5);const{slowClickTimeout:r,slowClickIgnoreSelectors:o}=this.getOptions(),i=r?{threshold:Math.min(gj,r),timeout:r,scrollTimeout:vj,ignoreSelector:o?o.join(","):""}:void 0;i&&(this.clickDetector=new AL(this,i))}getContext(){return this._context}isEnabled(){return this._isEnabled}isPaused(){return this._isPaused}isRecordingCanvas(){return!!this._canvas}getOptions(){return this._options}initializeSampling(t){const{errorSampleRate:n,sessionSampleRate:r}=this._options;if(!(n<=0&&r<=0)){if(this._initializeSessionForSampling(t),!this.session){this._handleException(new Error("Unable to initialize and create session"));return}this.session.sampled!==!1&&(this.recordingMode=this.session.sampled==="buffer"&&this.session.segmentId===0?"buffer":"session",Fa(`[Replay] Starting replay in ${this.recordingMode} mode`,this._options._experiments.traceInternals),this._initializeRecording())}}start(){if(this._isEnabled&&this.recordingMode==="session")throw new Error("Replay recording is already in progress");if(this._isEnabled&&this.recordingMode==="buffer")throw new Error("Replay buffering is in progress, call `flush()` to save the replay");Fa("[Replay] Starting replay in session mode",this._options._experiments.traceInternals);const t=Ig({maxReplayDuration:this._options.maxReplayDuration,sessionIdleExpire:this.timeouts.sessionIdleExpire,traceInternals:this._options._experiments.traceInternals},{stickySession:this._options.stickySession,sessionSampleRate:1,allowBuffering:!1});this.session=t,this._initializeRecording()}startBuffering(){if(this._isEnabled)throw new Error("Replay recording is already in progress");Fa("[Replay] Starting replay in buffer mode",this._options._experiments.traceInternals);const t=Ig({sessionIdleExpire:this.timeouts.sessionIdleExpire,maxReplayDuration:this._options.maxReplayDuration,traceInternals:this._options._experiments.traceInternals},{stickySession:this._options.stickySession,sessionSampleRate:0,allowBuffering:!0});this.session=t,this.recordingMode="buffer",this._initializeRecording()}startRecording(){try{const t=this._canvas;this._stopRecording=ii({...this._recordingOptions,...this.recordingMode==="buffer"&&{checkoutEveryNms:hj},emit:yz(this),onMutation:this._onMutationHandler,...t?{recordCanvas:t.recordCanvas,getCanvasManager:t.getCanvasManager,sampling:t.sampling,dataURLOptions:t.dataURLOptions}:{}})}catch(t){this._handleException(t)}}stopRecording(){try{return this._stopRecording&&(this._stopRecording(),this._stopRecording=void 0),!0}catch(t){return this._handleException(t),!1}}async stop({forceFlush:t=!1,reason:n}={}){if(this._isEnabled){this._isEnabled=!1;try{Qt(`[Replay] Stopping Replay${n?` triggered by ${n}`:""}`,this._options._experiments.traceInternals),this._removeListeners(),this.stopRecording(),this._debouncedFlush.cancel(),t&&await this._flush({force:!0}),this.eventBuffer&&this.eventBuffer.destroy(),this.eventBuffer=null,hV(this)}catch(r){this._handleException(r)}}}pause(){this._isPaused||(this._isPaused=!0,this.stopRecording(),Qt("[Replay] Pausing replay",this._options._experiments.traceInternals))}resume(){!this._isPaused||!this._checkSession()||(this._isPaused=!1,this.startRecording(),Qt("[Replay] Resuming replay",this._options._experiments.traceInternals))}async sendBufferedReplayOrFlush({continueRecording:t=!0}={}){if(this.recordingMode==="session")return this.flushImmediate();const n=Date.now();Qt("[Replay] Converting buffer to session",this._options._experiments.traceInternals),await this.flushImmediate();const r=this.stopRecording();!t||!r||this.recordingMode!=="session"&&(this.recordingMode="session",this.session&&(this._updateUserActivity(n),this._updateSessionActivity(n),this._maybeSaveSession()),this.startRecording())}addUpdate(t){const n=t();this.recordingMode!=="buffer"&&n!==!0&&this._debouncedFlush()}triggerUserActivity(){if(this._updateUserActivity(),!this._stopRecording){if(!this._checkSession())return;this.resume();return}this.checkAndHandleExpiredSession(),this._updateSessionActivity()}updateUserActivity(){this._updateUserActivity(),this._updateSessionActivity()}conditionalFlush(){return this.recordingMode==="buffer"?Promise.resolve():this.flushImmediate()}flush(){return this._debouncedFlush()}flushImmediate(){return this._debouncedFlush(),this._debouncedFlush.flush()}cancelFlush(){this._debouncedFlush.cancel()}getSessionId(){return this.session&&this.session.id}checkAndHandleExpiredSession(){if(this._lastActivity&&Hy(this._lastActivity,this.timeouts.sessionIdlePause)&&this.session&&this.session.sampled==="session"){this.pause();return}return!!this._checkSession()}setInitialState(){const t=`${Le.location.pathname}${Le.location.hash}${Le.location.search}`,n=`${Le.location.origin}${t}`;this.performanceEntries=[],this.replayPerformanceEntries=[],this._clearContext(),this._context.initialUrl=n,this._context.initialTimestamp=Date.now(),this._context.urls.push(n)}throttledAddEvent(t,n){const r=this._throttledAddEvent(t,n);if(r===gR){const o=jr({category:"replay.throttled"});this.addUpdate(()=>!Bb(this,{type:$L,timestamp:o.timestamp||0,data:{tag:"breadcrumb",payload:o,metric:!0}}))}return r}getCurrentRoute(){const t=this.lastTransaction||pn().getTransaction(),r=(t&&pt(t).data||{})[ho];if(!(!t||!r||!["route","custom"].includes(r)))return pt(t).description}_initializeRecording(){this.setInitialState(),this._updateSessionActivity(),this.eventBuffer=uV({useCompression:this._options.useCompression,workerUrl:this._options.workerUrl}),this._removeListeners(),this._addListeners(),this._isEnabled=!0,this._isPaused=!1,this.startRecording()}_handleException(t){Fe&&j.error("[Replay]",t),Fe&&this._options._experiments&&this._options._experiments.captureExceptions&&Ol(t)}_initializeSessionForSampling(t){const n=this._options.errorSampleRate>0,r=Ig({sessionIdleExpire:this.timeouts.sessionIdleExpire,maxReplayDuration:this._options.maxReplayDuration,traceInternals:this._options._experiments.traceInternals,previousSessionId:t},{stickySession:this._options.stickySession,sessionSampleRate:this._options.sessionSampleRate,allowBuffering:n});this.session=r}_checkSession(){if(!this.session)return!1;const t=this.session;return rR(t,{sessionIdleExpire:this.timeouts.sessionIdleExpire,maxReplayDuration:this._options.maxReplayDuration})?(this._refreshSession(t),!1):!0}async _refreshSession(t){this._isEnabled&&(await this.stop({reason:"refresh session"}),this.initializeSampling(t.id))}_addListeners(){try{Le.document.addEventListener("visibilitychange",this._handleVisibilityChange),Le.addEventListener("blur",this._handleWindowBlur),Le.addEventListener("focus",this._handleWindowFocus),Le.addEventListener("keydown",this._handleKeyboardEvent),this.clickDetector&&this.clickDetector.addListeners(),this._hasInitializedCoreListeners||(pz(this),this._hasInitializedCoreListeners=!0)}catch(t){this._handleException(t)}this._performanceCleanupCallback=oV(this)}_removeListeners(){try{Le.document.removeEventListener("visibilitychange",this._handleVisibilityChange),Le.removeEventListener("blur",this._handleWindowBlur),Le.removeEventListener("focus",this._handleWindowFocus),Le.removeEventListener("keydown",this._handleKeyboardEvent),this.clickDetector&&this.clickDetector.removeListeners(),this._performanceCleanupCallback&&this._performanceCleanupCallback()}catch(t){this._handleException(t)}}__init(){this._handleVisibilityChange=()=>{Le.document.visibilityState==="visible"?this._doChangeToForegroundTasks():this._doChangeToBackgroundTasks()}}__init2(){this._handleWindowBlur=()=>{const t=jr({category:"ui.blur"});this._doChangeToBackgroundTasks(t)}}__init3(){this._handleWindowFocus=()=>{const t=jr({category:"ui.focus"});this._doChangeToForegroundTasks(t)}}__init4(){this._handleKeyboardEvent=t=>{YL(this,t)}}_doChangeToBackgroundTasks(t){!this.session||nR(this.session,{maxReplayDuration:this._options.maxReplayDuration,sessionIdleExpire:this.timeouts.sessionIdleExpire})||(t&&this._createCustomBreadcrumb(t),this.conditionalFlush())}_doChangeToForegroundTasks(t){if(!this.session)return;if(!this.checkAndHandleExpiredSession()){Qt("[Replay] Document has become active, but session has expired");return}t&&this._createCustomBreadcrumb(t)}_updateUserActivity(t=Date.now()){this._lastActivity=t}_updateSessionActivity(t=Date.now()){this.session&&(this.session.lastActivity=t,this._maybeSaveSession())}_createCustomBreadcrumb(t){this.addUpdate(()=>{this.throttledAddEvent({type:fe.Custom,timestamp:t.timestamp||0,data:{tag:"breadcrumb",payload:t}})})}_addPerformanceEntries(){const t=ZL(this.performanceEntries).concat(this.replayPerformanceEntries);return this.performanceEntries=[],this.replayPerformanceEntries=[],Promise.all(zp(this,t))}_clearContext(){this._context.errorIds.clear(),this._context.traceIds.clear(),this._context.urls=[]}_updateInitialTimestampFromEventBuffer(){const{session:t,eventBuffer:n}=this;if(!t||!n||t.segmentId)return;const r=n.getEarliestTimestamp();r&&rthis._options.maxReplayDuration+3e4)throw new Error("Session is too long, not sending replay");const r=this._popEventContext(),o=this.session.segmentId++;this._maybeSaveSession();const i=await this.eventBuffer.finish();await mR({replayId:t,recordingData:i,segmentId:o,eventContext:r,session:this.session,options:this.getOptions(),timestamp:n})}catch(n){this._handleException(n),this.stop({reason:"sendReplay"});const r=ke();r&&r.recordDroppedEvent("send_error","replay")}}__init5(){this._flush=async({force:t=!1}={})=>{if(!this._isEnabled&&!t)return;if(!this.checkAndHandleExpiredSession()){Fe&&j.error("[Replay] Attempting to finish replay event after session expired.");return}if(!this.session)return;const n=this.session.started,o=Date.now()-n;this._debouncedFlush.cancel();const i=othis._options.maxReplayDuration+5e3;if(i||s){Qt(`[Replay] Session duration (${Math.floor(o/1e3)}s) is too ${i?"short":"long"}, not sending replay.`,this._options._experiments.traceInternals),i&&this._debouncedFlush();return}const a=this.eventBuffer;if(a&&this.session.segmentId===0&&!a.hasCheckout&&Qt("[Replay] Flushing initial segment without checkout.",this._options._experiments.traceInternals),!this._flushLock){this._flushLock=this._runFlush(),await this._flushLock,this._flushLock=void 0;return}try{await this._flushLock}catch(l){Fe&&j.error(l)}finally{this._debouncedFlush()}}}_maybeSaveSession(){this.session&&this._options.stickySession&&zb(this.session)}__init6(){this._onMutationHandler=t=>{const n=t.length,r=this._options.mutationLimit,o=this._options.mutationBreadcrumbLimit,i=r&&n>r;if(n>o||i){const s=jr({category:"replay.mutations",data:{count:n,limit:i}});this._createCustomBreadcrumb(s)}return i?(this.stop({reason:"mutationLimit",forceFlush:this.recordingMode==="session"}),!1):!0}}}function ec(e,t,n,r){const o=typeof r=="string"?r.split(","):[],i=[...e,...o,...t];return typeof n<"u"&&(typeof n=="string"&&i.push(`.${n}`),vs(()=>{console.warn("[Replay] You are using a deprecated configuration item for privacy. Read the documentation on how to use the new privacy configuration.")})),i.join(",")}function Tz({mask:e,unmask:t,block:n,unblock:r,ignore:o,blockClass:i,blockSelector:s,maskTextClass:a,maskTextSelector:l,ignoreClass:c}){const u=['base[href="/"]'],d=ec(e,[".sentry-mask","[data-sentry-mask]"],a,l),f=ec(t,[".sentry-unmask","[data-sentry-unmask]"]),h={maskTextSelector:d,unmaskTextSelector:f,blockSelector:ec(n,[".sentry-block","[data-sentry-block]",...u],i,s),unblockSelector:ec(r,[".sentry-unblock","[data-sentry-unblock]"]),ignoreSelector:ec(o,[".sentry-ignore","[data-sentry-ignore]",'input[type="file"]'],c)};return i instanceof RegExp&&(h.blockClass=i),a instanceof RegExp&&(h.maskTextClass=a),h}function Rz({el:e,key:t,maskAttributes:n,maskAllText:r,privacyOptions:o,value:i}){return!r||o.unmaskTextSelector&&e.matches(o.unmaskTextSelector)?i:n.includes(t)||t==="value"&&e.tagName==="INPUT"&&["submit","button"].includes(e.getAttribute("type")||"")?i.replace(/[\S]/g,"*"):i}const H_='img,image,svg,video,object,picture,embed,map,audio,link[rel="icon"],link[rel="apple-touch-icon"]',Iz=["content-length","content-type","accept"];let U_=!1;const $z=e=>new Up(e);class Up{static __initStatic(){this.id="Replay"}constructor({flushMinDelay:t=dj,flushMaxDelay:n=fj,minReplayDuration:r=yj,maxReplayDuration:o=C_,stickySession:i=!0,useCompression:s=!0,workerUrl:a,_experiments:l={},sessionSampleRate:c,errorSampleRate:u,maskAllText:d=!0,maskAllInputs:f=!0,blockAllMedia:h=!0,mutationBreadcrumbLimit:m=750,mutationLimit:v=1e4,slowClickTimeout:S=7e3,slowClickIgnoreSelectors:y=[],networkDetailAllowUrls:b=[],networkDetailDenyUrls:w=[],networkCaptureBodies:x=!0,networkRequestHeaders:_=[],networkResponseHeaders:E=[],mask:C=[],maskAttributes:k=["title","placeholder"],unmask:T=[],block:R=[],unblock:D=[],ignore:O=[],maskFn:H,beforeAddRecordingEvent:N,beforeErrorSampling:A,blockClass:F,blockSelector:P,maskInputOptions:$,maskTextClass:I,maskTextSelector:z,ignoreClass:V}={}){this.name=Up.id;const G=Tz({mask:C,unmask:T,block:R,unblock:D,ignore:O,blockClass:F,blockSelector:P,maskTextClass:I,maskTextSelector:z,ignoreClass:V});if(this._recordingOptions={maskAllInputs:f,maskAllText:d,maskInputOptions:{...$||{},password:!0},maskTextFn:H,maskInputFn:H,maskAttributeFn:(ie,te,pe)=>Rz({maskAttributes:k,maskAllText:d,privacyOptions:G,key:ie,value:te,el:pe}),...G,slimDOMOptions:"all",inlineStylesheet:!0,inlineImages:!1,collectFonts:!0,errorHandler:ie=>{try{ie.__rrweb__=!0}catch{}}},this._initialOptions={flushMinDelay:t,flushMaxDelay:n,minReplayDuration:Math.min(r,bj),maxReplayDuration:Math.min(o,C_),stickySession:i,sessionSampleRate:c,errorSampleRate:u,useCompression:s,workerUrl:a,blockAllMedia:h,maskAllInputs:f,maskAllText:d,mutationBreadcrumbLimit:m,mutationLimit:v,slowClickTimeout:S,slowClickIgnoreSelectors:y,networkDetailAllowUrls:b,networkDetailDenyUrls:w,networkCaptureBodies:x,networkRequestHeaders:W_(_),networkResponseHeaders:W_(E),beforeAddRecordingEvent:N,beforeErrorSampling:A,_experiments:l},typeof c=="number"&&(console.warn(`[Replay] You are passing \`sessionSampleRate\` to the Replay integration. +This option is deprecated and will be removed soon. +Instead, configure \`replaysSessionSampleRate\` directly in the SDK init options, e.g.: +Sentry.init({ replaysSessionSampleRate: ${c} })`),this._initialOptions.sessionSampleRate=c),typeof u=="number"&&(console.warn(`[Replay] You are passing \`errorSampleRate\` to the Replay integration. +This option is deprecated and will be removed soon. +Instead, configure \`replaysOnErrorSampleRate\` directly in the SDK init options, e.g.: +Sentry.init({ replaysOnErrorSampleRate: ${u} })`),this._initialOptions.errorSampleRate=u),this._initialOptions.blockAllMedia&&(this._recordingOptions.blockSelector=this._recordingOptions.blockSelector?`${this._recordingOptions.blockSelector},${H_}`:H_),this._isInitialized&&ky())throw new Error("Multiple Sentry Session Replay instances are not supported");this._isInitialized=!0}get _isInitialized(){return U_}set _isInitialized(t){U_=t}setupOnce(){ky()&&(this._setup(),setTimeout(()=>this._initialize()))}start(){this._replay&&this._replay.start()}startBuffering(){this._replay&&this._replay.startBuffering()}stop(){return this._replay?this._replay.stop({forceFlush:this._replay.recordingMode==="session"}):Promise.resolve()}flush(t){return!this._replay||!this._replay.isEnabled()?Promise.resolve():this._replay.sendBufferedReplayOrFlush(t)}getReplayId(){if(!(!this._replay||!this._replay.isEnabled()))return this._replay.getSessionId()}_initialize(){this._replay&&(this._maybeLoadFromReplayCanvasIntegration(),this._replay.initializeSampling())}_setup(){const t=Pz(this._initialOptions);this._replay=new Wo({options:t,recordingOptions:this._recordingOptions})}_maybeLoadFromReplayCanvasIntegration(){try{const n=ke().getIntegrationByName("ReplayCanvas");if(!n)return;this._replay._canvas=n.getOptions()}catch{}}}Up.__initStatic();function Pz(e){const t=ke(),n=t&&t.getOptions(),r={sessionSampleRate:0,errorSampleRate:0,...Zt(e)};return n?(e.sessionSampleRate==null&&e.errorSampleRate==null&&n.replaysSessionSampleRate==null&&n.replaysOnErrorSampleRate==null&&vs(()=>{console.warn("Replay is disabled because neither `replaysSessionSampleRate` nor `replaysOnErrorSampleRate` are set.")}),typeof n.replaysSessionSampleRate=="number"&&(r.sessionSampleRate=n.replaysSessionSampleRate),typeof n.replaysOnErrorSampleRate=="number"&&(r.errorSampleRate=n.replaysOnErrorSampleRate),r):(vs(()=>{console.warn("SDK client is not available.")}),r)}function W_(e){return[...Iz,...e.map(t=>t.toLowerCase())]}const Ns=we,$g="#ffffff",G_="inherit",Pg="rgba(108, 95, 199, 1)",q_={fontFamily:"system-ui, 'Helvetica Neue', Arial, sans-serif",fontSize:"14px",background:$g,backgroundHover:"#f6f6f7",foreground:"#2b2233",border:"1.5px solid rgba(41, 35, 47, 0.13)",borderRadius:"12px",boxShadow:"0px 4px 24px 0px rgba(43, 34, 51, 0.12)",success:"#268d75",error:"#df3338",submitBackground:"rgba(88, 74, 192, 1)",submitBackgroundHover:Pg,submitBorder:Pg,submitOutlineFocus:"#29232f",submitForeground:$g,submitForegroundHover:$g,cancelBackground:"transparent",cancelBackgroundHover:"var(--background-hover)",cancelBorder:"var(--border)",cancelOutlineFocus:"var(--input-outline-focus)",cancelForeground:"var(--foreground)",cancelForegroundHover:"var(--foreground)",inputBackground:G_,inputForeground:G_,inputBorder:"var(--border)",inputOutlineFocus:Pg,formBorderRadius:"20px",formContentBorderRadius:"6px"},K_={light:q_,dark:{...q_,background:"#29232f",backgroundHover:"#352f3b",foreground:"#ebe6ef",border:"1.5px solid rgba(235, 230, 239, 0.15)",success:"#2da98c",error:"#f55459"}},Oz="Report a Bug",Nz="Cancel",Mz="Send Bug Report",Dz="Report a Bug",Az="your.email@example.org",Fz="Email",jz="What's the bug? What did you expect?",Lz="Description",Vz="Your Name",zz="Name",Bz="Thank you for your report!",vR="widget",yR="api";async function Hz({client:e,scope:t,event:n}){const r={};e.emit&&e.emit("preprocessEvent",n,r);const o=await xb(e.getOptions(),n,r,t,e,$o());return o===null?(e.recordDroppedEvent("event_processor","feedback",n),null):(o.platform=o.platform||"javascript",o)}async function Uz({feedback:{message:e,email:t,name:n,source:r,url:o}},{includeReplay:i=!0}={}){const s=ke(),a=s&&s.getTransport(),l=s&&s.getDsn();if(!s||!a||!l)return;const c={contexts:{feedback:{contact_email:t,name:n,message:e,url:o,source:r}},type:"feedback"};return _b(async u=>{u.clearBreadcrumbs(),[yR,vR].includes(String(r))&&u.setLevel("info");const d=await Hz({scope:u,client:s,event:c});if(!d)return;s.emit&&s.emit("beforeSendFeedback",d,{includeReplay:!!i});const f=HT(d,l,s.getOptions()._metadata,s.getOptions().tunnel);let h;try{h=await a.send(f)}catch(m){const v=new Error("Unable to send Feedback");try{v.cause=m}catch{}throw v}if(h){if(typeof h.statusCode=="number"&&(h.statusCode<200||h.statusCode>=300))throw new Error("Unable to send Feedback");return h}})}function bR({name:e,email:t,message:n,source:r=yR,url:o=oT()},i={}){if(!n)throw new Error("Unable to submit feedback with empty message");return Uz({feedback:{name:e,email:t,message:n,url:o,source:r}},i)}const ns=typeof __SENTRY_DEBUG__>"u"||__SENTRY_DEBUG__;function Y_(e,t){return{...e,...t,themeDark:{...e.themeDark,...t.themeDark},themeLight:{...e.themeLight,...t.themeLight}}}function Wz(e){const t=e.createElement("style");return t.textContent=` +.widget__actor { + line-height: 25px; + + display: flex; + align-items: center; + gap: 8px; + + border-radius: var(--border-radius); + cursor: pointer; + font-size: 14px; + font-weight: 600; + padding: 12px 16px; + text-decoration: none; + z-index: 9000; + + color: var(--foreground); + background-color: var(--background); + border: var(--border); + box-shadow: var(--box-shadow); + opacity: 1; + transition: opacity 0.1s ease-in-out; +} + +.widget__actor:hover { + background-color: var(--background-hover); +} + +.widget__actor svg { + width: 16px; + height: 16px; +} + +.widget__actor--hidden { + opacity: 0; + pointer-events: none; + visibility: hidden; +} + +.widget__actor__text { +} + +.feedback-icon path { + fill: var(--foreground); +} +`,t}function Gz(e){const t=e.createElement("style");return t.textContent=` +.dialog { + line-height: 25px; + background-color: rgba(0, 0, 0, 0.05); + border: none; + position: fixed; + inset: 0; + z-index: 10000; + width: 100vw; + height: 100vh; + display: flex; + align-items: center; + justify-content: center; + opacity: 1; + transition: opacity 0.2s ease-in-out; +} + +.dialog:not([open]) { + opacity: 0; + pointer-events: none; + visibility: hidden; +} +.dialog:not([open]) .dialog__content { + transform: translate(0, -16px) scale(0.98); +} + +.dialog__content { + position: fixed; + left: var(--left); + right: var(--right); + bottom: var(--bottom); + top: var(--top); + + border: var(--border); + border-radius: var(--form-border-radius); + background-color: var(--background); + color: var(--foreground); + + width: 320px; + max-width: 100%; + max-height: calc(100% - 2rem); + display: flex; + flex-direction: column; + box-shadow: var(--box-shadow); + transition: transform 0.2s ease-in-out; + transform: translate(0, 0) scale(1); +} + +.dialog__header { + display: flex; + align-items: center; + justify-content: space-between; + font-size: 20px; + font-weight: 600; + padding: 24px 24px 0 24px; + margin: 0; + margin-bottom: 16px; +} + +.brand-link { + display: inline-flex; +} + +.error { + color: var(--error); + margin-bottom: 16px; +} + +.form { + display: grid; + overflow: auto; + flex-direction: column; + gap: 16px; + padding: 0 24px 24px; +} + +.form__error-container { + color: var(--error); +} + +.form__error-container--hidden { + display: none; +} + +.form__label { + display: flex; + flex-direction: column; + gap: 4px; + margin: 0px; +} + +.form__label__text { + display: grid; + gap: 4px; + align-items: center; + grid-auto-flow: column; + grid-auto-columns: max-content; +} + +.form__label__text--required { + font-size: 0.85em; +} + +.form__input { + font-family: inherit; + line-height: inherit; + background-color: var(--input-background); + box-sizing: border-box; + border: var(--input-border); + border-radius: var(--form-content-border-radius); + color: var(--input-foreground); + font-size: 14px; + font-weight: 500; + padding: 6px 12px; +} + +.form__input:focus-visible { + outline: 1px auto var(--input-outline-focus); +} + +.form__input--textarea { + font-family: inherit; + resize: vertical; +} + +.btn-group { + display: grid; + gap: 8px; + margin-top: 8px; +} + +.btn { + line-height: inherit; + border: var(--cancel-border); + border-radius: var(--form-content-border-radius); + cursor: pointer; + font-size: 14px; + font-weight: 600; + padding: 6px 16px; +} +.btn[disabled] { + opacity: 0.6; + pointer-events: none; +} + +.btn--primary { + background-color: var(--submit-background); + border-color: var(--submit-border); + color: var(--submit-foreground); +} +.btn--primary:hover { + background-color: var(--submit-background-hover); + color: var(--submit-foreground-hover); +} +.btn--primary:focus-visible { + outline: 1px auto var(--submit-outline-focus); +} + +.btn--default { + background-color: var(--cancel-background); + color: var(--cancel-foreground); + font-weight: 500; +} +.btn--default:hover { + background-color: var(--cancel-background-hover); + color: var(--cancel-foreground-hover); +} +.btn--default:focus-visible { + outline: 1px auto var(--cancel-outline-focus); +} + +.success-message { + background-color: var(--background); + border: var(--border); + border-radius: var(--border-radius); + box-shadow: var(--box-shadow); + font-weight: 600; + color: var(--success); + padding: 12px 24px; + line-height: 25px; + display: grid; + align-items: center; + grid-auto-flow: column; + gap: 6px; + cursor: default; +} + +.success-icon path { + fill: var(--success); +} +`,t}function Q_(e){return` + --background: ${e.background}; + --background-hover: ${e.backgroundHover}; + --foreground: ${e.foreground}; + --error: ${e.error}; + --success: ${e.success}; + --border: ${e.border}; + --border-radius: ${e.borderRadius}; + --box-shadow: ${e.boxShadow}; + + --submit-background: ${e.submitBackground}; + --submit-background-hover: ${e.submitBackgroundHover}; + --submit-border: ${e.submitBorder}; + --submit-outline-focus: ${e.submitOutlineFocus}; + --submit-foreground: ${e.submitForeground}; + --submit-foreground-hover: ${e.submitForegroundHover}; + + --cancel-background: ${e.cancelBackground}; + --cancel-background-hover: ${e.cancelBackgroundHover}; + --cancel-border: ${e.cancelBorder}; + --cancel-outline-focus: ${e.cancelOutlineFocus}; + --cancel-foreground: ${e.cancelForeground}; + --cancel-foreground-hover: ${e.cancelForegroundHover}; + + --input-background: ${e.inputBackground}; + --input-foreground: ${e.inputForeground}; + --input-border: ${e.inputBorder}; + --input-outline-focus: ${e.inputOutlineFocus}; + + --form-border-radius: ${e.formBorderRadius}; + --form-content-border-radius: ${e.formContentBorderRadius}; + `}function qz(e,t,n){const r=e.createElement("style");return r.textContent=` +:host { + --bottom: 1rem; + --right: 1rem; + --top: auto; + --left: auto; + --z-index: 100000; + --font-family: ${n.light.fontFamily}; + --font-size: ${n.light.fontSize}; + + position: fixed; + left: var(--left); + right: var(--right); + bottom: var(--bottom); + top: var(--top); + z-index: var(--z-index); + + font-family: var(--font-family); + font-size: var(--font-size); + + ${Q_(t==="dark"?n.dark:n.light)} +} + +${t==="system"?` +@media (prefers-color-scheme: dark) { + :host { + ${Q_(n.dark)} + } +}`:""} +}`,r}function Kz({id:e,colorScheme:t,themeDark:n,themeLight:r}){try{const o=Ns.document,i=o.createElement("div");i.id=e;const s=i.attachShadow({mode:"open"});return s.appendChild(qz(o,t,{dark:n,light:r})),s.appendChild(Gz(o)),{shadow:s,host:i}}catch{throw j.warn("[Feedback] Browser does not support shadow DOM API"),new Error("Browser does not support shadow DOM API.")}}async function Yz(e,t,n){if(!e)return;const r=()=>{e&&e.showError("There was a problem submitting feedback, please wait and try again.")};e.hideError();try{return await bR({...t,source:vR},n)}catch(o){ns&&j.error(o),r()}}function Sn(e,t){return Object.entries(t).forEach(([n,r])=>{e.setAttributeNS(null,n,r)}),e}const Gs=20,Qz="http://www.w3.org/2000/svg";function Xz(){const e=a=>Ns.document.createElementNS(Qz,a),t=Sn(e("svg"),{class:"feedback-icon",width:`${Gs}`,height:`${Gs}`,viewBox:`0 0 ${Gs} ${Gs}`,fill:"none"}),n=Sn(e("g"),{clipPath:"url(#clip0_57_80)"}),r=Sn(e("path"),{"fill-rule":"evenodd","clip-rule":"evenodd",d:"M15.6622 15H12.3997C12.2129 14.9959 12.031 14.9396 11.8747 14.8375L8.04965 12.2H7.49956V19.1C7.4875 19.3348 7.3888 19.5568 7.22256 19.723C7.05632 19.8892 6.83435 19.9879 6.59956 20H2.04956C1.80193 19.9968 1.56535 19.8969 1.39023 19.7218C1.21511 19.5467 1.1153 19.3101 1.11206 19.0625V12.2H0.949652C0.824431 12.2017 0.700142 12.1783 0.584123 12.1311C0.468104 12.084 0.362708 12.014 0.274155 11.9255C0.185602 11.8369 0.115689 11.7315 0.0685419 11.6155C0.0213952 11.4995 -0.00202913 11.3752 -0.00034808 11.25V3.75C-0.00900498 3.62067 0.0092504 3.49095 0.0532651 3.36904C0.0972798 3.24712 0.166097 3.13566 0.255372 3.04168C0.344646 2.94771 0.452437 2.87327 0.571937 2.82307C0.691437 2.77286 0.82005 2.74798 0.949652 2.75H8.04965L11.8747 0.1625C12.031 0.0603649 12.2129 0.00407221 12.3997 0H15.6622C15.9098 0.00323746 16.1464 0.103049 16.3215 0.278167C16.4966 0.453286 16.5964 0.689866 16.5997 0.9375V3.25269C17.3969 3.42959 18.1345 3.83026 18.7211 4.41679C19.5322 5.22788 19.9878 6.32796 19.9878 7.47502C19.9878 8.62209 19.5322 9.72217 18.7211 10.5333C18.1345 11.1198 17.3969 11.5205 16.5997 11.6974V14.0125C16.6047 14.1393 16.5842 14.2659 16.5395 14.3847C16.4948 14.5035 16.4268 14.6121 16.3394 14.7042C16.252 14.7962 16.147 14.8698 16.0307 14.9206C15.9144 14.9714 15.7891 14.9984 15.6622 15ZM1.89695 10.325H1.88715V4.625H8.33715C8.52423 4.62301 8.70666 4.56654 8.86215 4.4625L12.6872 1.875H14.7247V13.125H12.6872L8.86215 10.4875C8.70666 10.3835 8.52423 10.327 8.33715 10.325H2.20217C2.15205 10.3167 2.10102 10.3125 2.04956 10.3125C1.9981 10.3125 1.94708 10.3167 1.89695 10.325ZM2.98706 12.2V18.1625H5.66206V12.2H2.98706ZM16.5997 9.93612V5.01393C16.6536 5.02355 16.7072 5.03495 16.7605 5.04814C17.1202 5.13709 17.4556 5.30487 17.7425 5.53934C18.0293 5.77381 18.2605 6.06912 18.4192 6.40389C18.578 6.73866 18.6603 7.10452 18.6603 7.47502C18.6603 7.84552 18.578 8.21139 18.4192 8.54616C18.2605 8.88093 18.0293 9.17624 17.7425 9.41071C17.4556 9.64518 17.1202 9.81296 16.7605 9.90191C16.7072 9.91509 16.6536 9.9265 16.5997 9.93612Z"});t.appendChild(n).appendChild(r);const o=e("defs"),i=Sn(e("clipPath"),{id:"clip0_57_80"}),s=Sn(e("rect"),{width:`${Gs}`,height:`${Gs}`,fill:"white"});return i.appendChild(s),o.appendChild(i),t.appendChild(o).appendChild(i).appendChild(s),{get el(){return t}}}function We(e,t,...n){const o=Ns.document.createElement(e);t&&Object.entries(t).forEach(([i,s])=>{i==="className"&&typeof s=="string"?o.setAttribute("class",s):typeof s=="boolean"&&s?o.setAttribute(i,""):typeof s=="string"?o.setAttribute(i,s):i.startsWith("on")&&typeof s=="function"&&o.addEventListener(i.substring(2).toLowerCase(),s)});for(const i of n)wR(o,i);return o}function wR(e,t){const n=Ns.document;if(!(typeof t>"u"||t===null))if(Array.isArray(t))for(const r of t)wR(e,r);else t===!1||(typeof t=="string"?e.appendChild(n.createTextNode(t)):t instanceof Node?e.appendChild(t):e.appendChild(n.createTextNode(String(t))))}function Zz({buttonLabel:e,onClick:t}){function n(o){t&&t(o)}const r=We("button",{type:"button",className:"widget__actor","aria-label":e,"aria-hidden":"false"},Xz().el,e?We("span",{className:"widget__actor__text"},e):null);return r.addEventListener("click",n),{get el(){return r},show:()=>{r.classList.remove("widget__actor--hidden"),r.setAttribute("aria-hidden","false")},hide:()=>{r.classList.add("widget__actor--hidden"),r.setAttribute("aria-hidden","true")}}}function Jz({label:e}){return{el:We("button",{type:"submit",className:"btn btn--primary","aria-label":e},e)}}function Og(e,t){const n=e.get(t);return typeof n=="string"?n.trim():""}function eB({nameLabel:e,namePlaceholder:t,emailLabel:n,emailPlaceholder:r,messageLabel:o,messagePlaceholder:i,cancelButtonLabel:s,submitButtonLabel:a,showName:l,showEmail:c,isNameRequired:u,isEmailRequired:d,defaultName:f,defaultEmail:h,onCancel:m,onSubmit:v}){const{el:S}=Jz({label:a});function y(R){if(R.preventDefault(),R.target instanceof HTMLFormElement)try{if(v){const D=new FormData(R.target),O={name:Og(D,"name"),email:Og(D,"email"),message:Og(D,"message")};v(O)}}catch{}}const b=We("div",{className:"form__error-container form__error-container--hidden","aria-hidden":"true"});function w(R){b.textContent=R,b.classList.remove("form__error-container--hidden"),b.setAttribute("aria-hidden","false")}function x(){b.textContent="",b.classList.add("form__error-container--hidden"),b.setAttribute("aria-hidden","true")}const _=We("input",{id:"name",type:l?"text":"hidden","aria-hidden":l?"false":"true",name:"name",required:u,className:"form__input",placeholder:t,value:f}),E=We("input",{id:"email",type:c?"text":"hidden","aria-hidden":c?"false":"true",name:"email",required:d,className:"form__input",placeholder:r,value:h}),C=We("textarea",{id:"message",autoFocus:"true",rows:"5",name:"message",required:!0,className:"form__input form__input--textarea",placeholder:i}),k=We("button",{type:"button",className:"btn btn--default","aria-label":s,onClick:R=>{m&&m(R)}},s),T=We("form",{className:"form",onSubmit:y},[b,l&&We("label",{htmlFor:"name",className:"form__label"},[We("span",{className:"form__label__text"},e,u&&We("span",{className:"form__label__text--required"}," (required)")),_]),!l&&_,c&&We("label",{htmlFor:"email",className:"form__label"},[We("span",{className:"form__label__text"},n,d&&We("span",{className:"form__label__text--required"}," (required)")),E]),!c&&E,We("label",{htmlFor:"message",className:"form__label"},[We("span",{className:"form__label__text"},o,We("span",{className:"form__label__text--required"}," (required)")),C]),We("div",{className:"btn-group"},[S,k])]);return{get el(){return T},showError:w,hideError:x}}const tB="http://www.w3.org/2000/svg";function nB({colorScheme:e}){const t=s=>Ns.document.createElementNS(tB,s),n=Sn(t("svg"),{class:"sentry-logo",width:"32",height:"30",viewBox:"0 0 72 66",fill:"none"}),r=Sn(t("path"),{transform:"translate(11, 11)",d:"M29,2.26a4.67,4.67,0,0,0-8,0L14.42,13.53A32.21,32.21,0,0,1,32.17,40.19H27.55A27.68,27.68,0,0,0,12.09,17.47L6,28a15.92,15.92,0,0,1,9.23,12.17H4.62A.76.76,0,0,1,4,39.06l2.94-5a10.74,10.74,0,0,0-3.36-1.9l-2.91,5a4.54,4.54,0,0,0,1.69,6.24A4.66,4.66,0,0,0,4.62,44H19.15a19.4,19.4,0,0,0-8-17.31l2.31-4A23.87,23.87,0,0,1,23.76,44H36.07a35.88,35.88,0,0,0-16.41-31.8l4.67-8a.77.77,0,0,1,1.05-.27c.53.29,20.29,34.77,20.66,35.17a.76.76,0,0,1-.68,1.13H40.6q.09,1.91,0,3.81h4.78A4.59,4.59,0,0,0,50,39.43a4.49,4.49,0,0,0-.62-2.28Z"});n.append(r);const o=t("defs"),i=t("style");return i.textContent=` + path { + fill: ${e==="dark"?"#fff":"#362d59"}; + }`,e==="system"&&(i.textContent+=` + @media (prefers-color-scheme: dark) { + path: { + fill: '#fff'; + } + } + `),o.append(i),n.append(o),{get el(){return n}}}function rB({formTitle:e,showBranding:t,showName:n,showEmail:r,isNameRequired:o,isEmailRequired:i,colorScheme:s,defaultName:a,defaultEmail:l,onClosed:c,onCancel:u,onSubmit:d,...f}){let h=null;function m(){v(),c&&c()}function v(){h&&(h.open=!1)}function S(){h&&(h.open=!0)}function y(){return h&&h.open===!0||!1}const{el:b,showError:w,hideError:x}=eB({showEmail:r,showName:n,isEmailRequired:i,isNameRequired:o,defaultName:a,defaultEmail:l,onSubmit:d,onCancel:u,...f});return h=We("dialog",{className:"dialog",open:!0,onClick:m},We("div",{className:"dialog__content",onClick:_=>{_.stopPropagation()}},We("h2",{className:"dialog__header"},e,t&&We("a",{className:"brand-link",target:"_blank",href:"https://sentry.io/welcome/",title:"Powered by Sentry",rel:"noopener noreferrer"},nB({colorScheme:s}).el)),b)),{get el(){return h},showError:w,hideError:x,open:S,close:v,checkIsOpen:y}}const qd=16,X_=17,oB="http://www.w3.org/2000/svg";function iB(){const e=l=>Ns.document.createElementNS(oB,l),t=Sn(e("svg"),{class:"success-icon",width:`${qd}`,height:`${X_}`,viewBox:`0 0 ${qd} ${X_}`,fill:"none"}),n=Sn(e("g"),{clipPath:"url(#clip0_57_156)"}),r=Sn(e("path"),{"fill-rule":"evenodd","clip-rule":"evenodd",d:"M3.55544 15.1518C4.87103 16.0308 6.41775 16.5 8 16.5C10.1217 16.5 12.1566 15.6571 13.6569 14.1569C15.1571 12.6566 16 10.6217 16 8.5C16 6.91775 15.5308 5.37103 14.6518 4.05544C13.7727 2.73985 12.5233 1.71447 11.0615 1.10897C9.59966 0.503466 7.99113 0.34504 6.43928 0.653721C4.88743 0.962403 3.46197 1.72433 2.34315 2.84315C1.22433 3.96197 0.462403 5.38743 0.153721 6.93928C-0.15496 8.49113 0.00346625 10.0997 0.608967 11.5615C1.21447 13.0233 2.23985 14.2727 3.55544 15.1518ZM4.40546 3.1204C5.46945 2.40946 6.72036 2.03 8 2.03C9.71595 2.03 11.3616 2.71166 12.575 3.92502C13.7883 5.13838 14.47 6.78405 14.47 8.5C14.47 9.77965 14.0905 11.0306 13.3796 12.0945C12.6687 13.1585 11.6582 13.9878 10.476 14.4775C9.29373 14.9672 7.99283 15.0953 6.73777 14.8457C5.48271 14.596 4.32987 13.9798 3.42502 13.075C2.52018 12.1701 1.90397 11.0173 1.65432 9.76224C1.40468 8.50718 1.5328 7.20628 2.0225 6.02404C2.5122 4.8418 3.34148 3.83133 4.40546 3.1204Z"}),o=Sn(e("path"),{d:"M6.68775 12.4297C6.78586 12.4745 6.89218 12.4984 7 12.5C7.11275 12.4955 7.22315 12.4664 7.32337 12.4145C7.4236 12.3627 7.51121 12.2894 7.58 12.2L12 5.63999C12.0848 5.47724 12.1071 5.28902 12.0625 5.11098C12.0178 4.93294 11.9095 4.77744 11.7579 4.67392C11.6064 4.57041 11.4221 4.52608 11.24 4.54931C11.0579 4.57254 10.8907 4.66173 10.77 4.79999L6.88 10.57L5.13 8.56999C5.06508 8.49566 4.98613 8.43488 4.89768 8.39111C4.80922 8.34735 4.713 8.32148 4.61453 8.31498C4.51605 8.30847 4.41727 8.32147 4.32382 8.35322C4.23038 8.38497 4.14413 8.43484 4.07 8.49999C3.92511 8.63217 3.83692 8.81523 3.82387 9.01092C3.81083 9.2066 3.87393 9.39976 4 9.54999L6.43 12.24C6.50187 12.3204 6.58964 12.385 6.68775 12.4297Z"});t.appendChild(n).append(o,r);const i=e("defs"),s=Sn(e("clipPath"),{id:"clip0_57_156"}),a=Sn(e("rect"),{width:`${qd}`,height:`${qd}`,fill:"white",transform:"translate(0 0.5)"});return s.appendChild(a),i.appendChild(s),t.appendChild(i).appendChild(s).appendChild(a),{get el(){return t}}}function sB({message:e,onRemove:t}){function n(){r&&(r.remove(),t&&t())}const r=We("div",{className:"success-message",onClick:n},iB().el,e);return{el:r,remove:n}}function Z_({shadow:e,options:{shouldCreateActor:t=!0,...n},attachTo:r}){let o,i,s=!1;function a(){if(e)try{const y=sB({message:n.successMessageText,onRemove:()=>{b&&clearTimeout(b),u()}});if(!y.el)throw new Error("Unable to show success message");e.appendChild(y.el);const b=setTimeout(()=>{y&&y.remove()},5e3)}catch(y){j.error(y)}}async function l(y){if(!i)return;const b=[];if(n.isNameRequired&&!y.name&&b.push(n.nameLabel),n.isEmailRequired&&!y.email&&b.push(n.emailLabel),y.message||b.push(n.messageLabel),b.length>0){i.showError(`Please enter in the following required fields: ${b.join(", ")}`);return}if(!await Yz(i,y)){n.onSubmitError&&n.onSubmitError();return}v(),a(),n.onSubmitSuccess&&n.onSubmitSuccess()}function c(){const y=ke(),b=y&&y.getIntegrationByName&&y.getIntegrationByName("Replay");b&&b.flush().catch(w=>{ns&&j.error(w)})}function u(){o&&o.show()}function d(){o&&o.hide()}function f(){o&&o.el&&o.el.remove()}function h(){try{if(i){i.open(),s=!0,n.onFormOpen&&n.onFormOpen(),c();return}const y=n.useSentryUser,b=pn(),w=b&&b.getUser();if(i=rB({colorScheme:n.colorScheme,showBranding:n.showBranding,showName:n.showName||n.isNameRequired,showEmail:n.showEmail||n.isEmailRequired,isNameRequired:n.isNameRequired,isEmailRequired:n.isEmailRequired,formTitle:n.formTitle,cancelButtonLabel:n.cancelButtonLabel,submitButtonLabel:n.submitButtonLabel,emailLabel:n.emailLabel,emailPlaceholder:n.emailPlaceholder,messageLabel:n.messageLabel,messagePlaceholder:n.messagePlaceholder,nameLabel:n.nameLabel,namePlaceholder:n.namePlaceholder,defaultName:y&&w&&w[y.name]||"",defaultEmail:y&&w&&w[y.email]||"",onClosed:()=>{u(),s=!1,n.onFormClose&&n.onFormClose()},onCancel:()=>{m(),u()},onSubmit:l}),!i.el)throw new Error("Unable to open Feedback dialog");e.appendChild(i.el),d(),n.onFormOpen&&n.onFormOpen(),c()}catch(y){j.error(y)}}function m(){i&&(i.close(),s=!1,n.onFormClose&&n.onFormClose())}function v(){if(i){m();const y=i.el;y&&y.remove(),i=void 0}}function S(){s||h(),d()}return r?r.addEventListener("click",S):t&&(o=Zz({buttonLabel:n.buttonLabel,onClick:S}),o.el&&e.appendChild(o.el)),{get actor(){return o},get dialog(){return i},showActor:u,hideActor:d,removeActor:f,openDialog:h,closeDialog:m,removeDialog:v}}const Kd=Ns.document,aB=e=>new SR(e);let SR=class xR{static __initStatic(){this.id="Feedback"}constructor({autoInject:t=!0,id:n="sentry-feedback",isEmailRequired:r=!1,isNameRequired:o=!1,showBranding:i=!0,showEmail:s=!0,showName:a=!0,useSentryUser:l={email:"email",name:"username"},themeDark:c,themeLight:u,colorScheme:d="system",buttonLabel:f=Oz,cancelButtonLabel:h=Nz,submitButtonLabel:m=Mz,formTitle:v=Dz,emailPlaceholder:S=Az,emailLabel:y=Fz,messagePlaceholder:b=jz,messageLabel:w=Lz,namePlaceholder:x=Vz,nameLabel:_=zz,successMessageText:E=Bz,onFormClose:C,onFormOpen:k,onSubmitError:T,onSubmitSuccess:R}={}){this.name=xR.id,this._host=null,this._shadow=null,this._widget=null,this._widgets=new Set,this._hasInsertedActorStyles=!1,this.options={autoInject:t,showBranding:i,id:n,isEmailRequired:r,isNameRequired:o,showEmail:s,showName:a,useSentryUser:l,colorScheme:d,themeDark:{...K_.dark,...c},themeLight:{...K_.light,...u},buttonLabel:f,cancelButtonLabel:h,submitButtonLabel:m,formTitle:v,emailLabel:y,emailPlaceholder:S,messageLabel:w,messagePlaceholder:b,nameLabel:_,namePlaceholder:x,successMessageText:E,onFormClose:C,onFormOpen:k,onSubmitError:T,onSubmitSuccess:R}}setupOnce(){if(ky())try{this._cleanupWidgetIfExists();const{autoInject:t}=this.options;if(!t)return;this._createWidget(this.options)}catch(t){ns&&j.error(t)}}openDialog(){this._widget||this._createWidget({...this.options,shouldCreateActor:!1}),this._widget&&this._widget.openDialog()}closeDialog(){this._widget&&this._widget.closeDialog()}attachTo(t,n){try{const r=Y_(this.options,n||{});return this._ensureShadowHost(r,({shadow:o})=>{const i=typeof t=="string"?Kd.querySelector(t):typeof t.addEventListener=="function"?t:null;if(!i)return ns&&j.error("[Feedback] Unable to attach to target element"),null;const s=Z_({shadow:o,options:r,attachTo:i});return this._widgets.add(s),this._widget||(this._widget=s),s})}catch(r){return ns&&j.error(r),null}}createWidget(t){try{return this._createWidget(Y_(this.options,t||{}))}catch(n){return ns&&j.error(n),null}}removeWidget(t){if(!t)return!1;try{if(this._widgets.has(t))return t.removeActor(),t.removeDialog(),this._widgets.delete(t),this._widget===t&&(this._widget=null),!0}catch(n){ns&&j.error(n)}return!1}getWidget(){return this._widget}remove(){this._host&&this._host.remove(),this._initialize()}_initialize(){this._host=null,this._shadow=null,this._widget=null,this._widgets=new Set,this._hasInsertedActorStyles=!1}_cleanupWidgetIfExists(){this._host&&this.remove();const t=Kd.querySelector(`#${this.options.id}`);t&&t.remove()}_createWidget(t){return this._ensureShadowHost(t,({shadow:n})=>{const r=Z_({shadow:n,options:t});return!this._hasInsertedActorStyles&&r.actor&&(n.appendChild(Wz(Kd)),this._hasInsertedActorStyles=!0),this._widgets.add(r),this._widget||(this._widget=r),r})}_ensureShadowHost(t,n){let r=!1;if(!this._shadow||!this._host){const{id:i,colorScheme:s,themeLight:a,themeDark:l}=t,{shadow:c,host:u}=Kz({id:i,colorScheme:s,themeLight:a,themeDark:l});this._shadow=c,this._host=u,r=!0}this._host.dataset.sentryFeedbackColorscheme=t.colorScheme;const o=n({shadow:this._shadow,host:this._host});return r&&Kd.body.appendChild(this._host),o}};SR.__initStatic();function lB(e){const t={...e};YT(t,"react"),sj(t)}var _R={exports:{}},Ne={};/** @license React v16.13.1 + * react-is.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var kt=typeof Symbol=="function"&&Symbol.for,Ub=kt?Symbol.for("react.element"):60103,Wb=kt?Symbol.for("react.portal"):60106,Wp=kt?Symbol.for("react.fragment"):60107,Gp=kt?Symbol.for("react.strict_mode"):60108,qp=kt?Symbol.for("react.profiler"):60114,Kp=kt?Symbol.for("react.provider"):60109,Yp=kt?Symbol.for("react.context"):60110,Gb=kt?Symbol.for("react.async_mode"):60111,Qp=kt?Symbol.for("react.concurrent_mode"):60111,Xp=kt?Symbol.for("react.forward_ref"):60112,Zp=kt?Symbol.for("react.suspense"):60113,cB=kt?Symbol.for("react.suspense_list"):60120,Jp=kt?Symbol.for("react.memo"):60115,em=kt?Symbol.for("react.lazy"):60116,uB=kt?Symbol.for("react.block"):60121,dB=kt?Symbol.for("react.fundamental"):60117,fB=kt?Symbol.for("react.responder"):60118,hB=kt?Symbol.for("react.scope"):60119;function Pn(e){if(typeof e=="object"&&e!==null){var t=e.$$typeof;switch(t){case Ub:switch(e=e.type,e){case Gb:case Qp:case Wp:case qp:case Gp:case Zp:return e;default:switch(e=e&&e.$$typeof,e){case Yp:case Xp:case em:case Jp:case Kp:return e;default:return t}}case Wb:return t}}}function ER(e){return Pn(e)===Qp}Ne.AsyncMode=Gb;Ne.ConcurrentMode=Qp;Ne.ContextConsumer=Yp;Ne.ContextProvider=Kp;Ne.Element=Ub;Ne.ForwardRef=Xp;Ne.Fragment=Wp;Ne.Lazy=em;Ne.Memo=Jp;Ne.Portal=Wb;Ne.Profiler=qp;Ne.StrictMode=Gp;Ne.Suspense=Zp;Ne.isAsyncMode=function(e){return ER(e)||Pn(e)===Gb};Ne.isConcurrentMode=ER;Ne.isContextConsumer=function(e){return Pn(e)===Yp};Ne.isContextProvider=function(e){return Pn(e)===Kp};Ne.isElement=function(e){return typeof e=="object"&&e!==null&&e.$$typeof===Ub};Ne.isForwardRef=function(e){return Pn(e)===Xp};Ne.isFragment=function(e){return Pn(e)===Wp};Ne.isLazy=function(e){return Pn(e)===em};Ne.isMemo=function(e){return Pn(e)===Jp};Ne.isPortal=function(e){return Pn(e)===Wb};Ne.isProfiler=function(e){return Pn(e)===qp};Ne.isStrictMode=function(e){return Pn(e)===Gp};Ne.isSuspense=function(e){return Pn(e)===Zp};Ne.isValidElementType=function(e){return typeof e=="string"||typeof e=="function"||e===Wp||e===Qp||e===qp||e===Gp||e===Zp||e===cB||typeof e=="object"&&e!==null&&(e.$$typeof===em||e.$$typeof===Jp||e.$$typeof===Kp||e.$$typeof===Yp||e.$$typeof===Xp||e.$$typeof===dB||e.$$typeof===fB||e.$$typeof===hB||e.$$typeof===uB)};Ne.typeOf=Pn;_R.exports=Ne;var pB=_R.exports,CR=pB,mB={$$typeof:!0,render:!0,defaultProps:!0,displayName:!0,propTypes:!0},gB={$$typeof:!0,compare:!0,defaultProps:!0,displayName:!0,propTypes:!0,type:!0},kR={};kR[CR.ForwardRef]=mB;kR[CR.Memo]=gB;const vB=typeof __SENTRY_DEBUG__>"u"||__SENTRY_DEBUG__;function yB(e){const t=e.match(/^([^.]+)/);return t!==null&&parseInt(t[0])>=17}const J_={componentStack:null,error:null,eventId:null};function bB(e,t){const n=new WeakMap;function r(o,i){if(!n.has(o)){if(o.cause)return n.set(o,!0),r(o.cause,i);o.cause=i}}r(e,t)}class qb extends p.Component{constructor(t){super(t),qb.prototype.__init.call(this),this.state=J_,this._openFallbackReportDialog=!0;const n=ke();n&&n.on&&t.showDialog&&(this._openFallbackReportDialog=!1,n.on("afterSendEvent",r=>{!r.type&&r.event_id===this._lastEventId&&__({...t.dialogOptions,eventId:this._lastEventId})}))}componentDidCatch(t,{componentStack:n}){const{beforeCapture:r,onError:o,showDialog:i,dialogOptions:s}=this.props;_b(a=>{if(yB(p.version)&&lb(t)){const c=new Error(t.message);c.name=`React ErrorBoundary ${t.name}`,c.stack=n,bB(t,c)}r&&r(a,t,n);const l=Ol(t,{captureContext:{contexts:{react:{componentStack:n}}},mechanism:{handled:!1}});o&&o(t,n,l),i&&(this._lastEventId=l,this._openFallbackReportDialog&&__({...s,eventId:l})),this.setState({error:t,componentStack:n,eventId:l})})}componentDidMount(){const{onMount:t}=this.props;t&&t()}componentWillUnmount(){const{error:t,componentStack:n,eventId:r}=this.state,{onUnmount:o}=this.props;o&&o(t,n,r)}__init(){this.resetErrorBoundary=()=>{const{onReset:t}=this.props,{error:n,componentStack:r,eventId:o}=this.state;t&&t(n,r,o),this.setState(J_)}}render(){const{fallback:t,children:n}=this.props,r=this.state;if(r.error){let o;return typeof t=="function"?o=t({error:r.error,componentStack:r.componentStack,resetError:this.resetErrorBoundary,eventId:r.eventId}):o=t,p.isValidElement(o)?o:(t&&vB&&j.warn("fallback did not produce a valid ReactElement"),null)}return typeof n=="function"?n():n}}var Gy={},TR={exports:{}},On={},RR={exports:{}},IR={};/** + * @license React + * scheduler.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */(function(e){function t($,I){var z=$.length;$.push(I);e:for(;0>>1,G=$[V];if(0>>1;Vo(pe,z))Xo(B,pe)?($[V]=B,$[X]=z,V=X):($[V]=pe,$[te]=z,V=te);else if(Xo(B,z))$[V]=B,$[X]=z,V=X;else break e}}return I}function o($,I){var z=$.sortIndex-I.sortIndex;return z!==0?z:$.id-I.id}if(typeof performance=="object"&&typeof performance.now=="function"){var i=performance;e.unstable_now=function(){return i.now()}}else{var s=Date,a=s.now();e.unstable_now=function(){return s.now()-a}}var l=[],c=[],u=1,d=null,f=3,h=!1,m=!1,v=!1,S=typeof setTimeout=="function"?setTimeout:null,y=typeof clearTimeout=="function"?clearTimeout:null,b=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function w($){for(var I=n(c);I!==null;){if(I.callback===null)r(c);else if(I.startTime<=$)r(c),I.sortIndex=I.expirationTime,t(l,I);else break;I=n(c)}}function x($){if(v=!1,w($),!m)if(n(l)!==null)m=!0,F(_);else{var I=n(c);I!==null&&P(x,I.startTime-$)}}function _($,I){m=!1,v&&(v=!1,y(k),k=-1),h=!0;var z=f;try{for(w(I),d=n(l);d!==null&&(!(d.expirationTime>I)||$&&!D());){var V=d.callback;if(typeof V=="function"){d.callback=null,f=d.priorityLevel;var G=V(d.expirationTime<=I);I=e.unstable_now(),typeof G=="function"?d.callback=G:d===n(l)&&r(l),w(I)}else r(l);d=n(l)}if(d!==null)var ie=!0;else{var te=n(c);te!==null&&P(x,te.startTime-I),ie=!1}return ie}finally{d=null,f=z,h=!1}}var E=!1,C=null,k=-1,T=5,R=-1;function D(){return!(e.unstable_now()-R$||125<$?console.error("forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported"):T=0<$?Math.floor(1e3/$):5},e.unstable_getCurrentPriorityLevel=function(){return f},e.unstable_getFirstCallbackNode=function(){return n(l)},e.unstable_next=function($){switch(f){case 1:case 2:case 3:var I=3;break;default:I=f}var z=f;f=I;try{return $()}finally{f=z}},e.unstable_pauseExecution=function(){},e.unstable_requestPaint=function(){},e.unstable_runWithPriority=function($,I){switch($){case 1:case 2:case 3:case 4:case 5:break;default:$=3}var z=f;f=$;try{return I()}finally{f=z}},e.unstable_scheduleCallback=function($,I,z){var V=e.unstable_now();switch(typeof z=="object"&&z!==null?(z=z.delay,z=typeof z=="number"&&0V?($.sortIndex=z,t(c,$),n(l)===null&&$===n(c)&&(v?(y(k),k=-1):v=!0,P(x,z-V))):($.sortIndex=G,t(l,$),m||h||(m=!0,F(_))),$},e.unstable_shouldYield=D,e.unstable_wrapCallback=function($){var I=f;return function(){var z=f;f=I;try{return $.apply(this,arguments)}finally{f=z}}}})(IR);RR.exports=IR;var wB=RR.exports;/** + * @license React + * react-dom.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var $R=p,Tn=wB;function U(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),qy=Object.prototype.hasOwnProperty,SB=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,e2={},t2={};function xB(e){return qy.call(t2,e)?!0:qy.call(e2,e)?!1:SB.test(e)?t2[e]=!0:(e2[e]=!0,!1)}function _B(e,t,n,r){if(n!==null&&n.type===0)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return r?!1:n!==null?!n.acceptsBooleans:(e=e.toLowerCase().slice(0,5),e!=="data-"&&e!=="aria-");default:return!1}}function EB(e,t,n,r){if(t===null||typeof t>"u"||_B(e,t,n,r))return!0;if(r)return!1;if(n!==null)switch(n.type){case 3:return!t;case 4:return t===!1;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}function rn(e,t,n,r,o,i,s){this.acceptsBooleans=t===2||t===3||t===4,this.attributeName=r,this.attributeNamespace=o,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=i,this.removeEmptyString=s}var Nt={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){Nt[e]=new rn(e,0,!1,e,null,!1,!1)});[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var t=e[0];Nt[t]=new rn(t,1,!1,e[1],null,!1,!1)});["contentEditable","draggable","spellCheck","value"].forEach(function(e){Nt[e]=new rn(e,2,!1,e.toLowerCase(),null,!1,!1)});["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){Nt[e]=new rn(e,2,!1,e,null,!1,!1)});"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(e){Nt[e]=new rn(e,3,!1,e.toLowerCase(),null,!1,!1)});["checked","multiple","muted","selected"].forEach(function(e){Nt[e]=new rn(e,3,!0,e,null,!1,!1)});["capture","download"].forEach(function(e){Nt[e]=new rn(e,4,!1,e,null,!1,!1)});["cols","rows","size","span"].forEach(function(e){Nt[e]=new rn(e,6,!1,e,null,!1,!1)});["rowSpan","start"].forEach(function(e){Nt[e]=new rn(e,5,!1,e.toLowerCase(),null,!1,!1)});var Kb=/[\-:]([a-z])/g;function Yb(e){return e[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(e){var t=e.replace(Kb,Yb);Nt[t]=new rn(t,1,!1,e,null,!1,!1)});"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var t=e.replace(Kb,Yb);Nt[t]=new rn(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)});["xml:base","xml:lang","xml:space"].forEach(function(e){var t=e.replace(Kb,Yb);Nt[t]=new rn(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)});["tabIndex","crossOrigin"].forEach(function(e){Nt[e]=new rn(e,1,!1,e.toLowerCase(),null,!1,!1)});Nt.xlinkHref=new rn("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1);["src","href","action","formAction"].forEach(function(e){Nt[e]=new rn(e,1,!1,e.toLowerCase(),null,!0,!0)});function Qb(e,t,n,r){var o=Nt.hasOwnProperty(t)?Nt[t]:null;(o!==null?o.type!==0:r||!(2a||o[s]!==i[a]){var l=` +`+o[s].replace(" at new "," at ");return e.displayName&&l.includes("")&&(l=l.replace("",e.displayName)),l}while(1<=s&&0<=a);break}}}finally{Mg=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?Tc(e):""}function CB(e){switch(e.tag){case 5:return Tc(e.type);case 16:return Tc("Lazy");case 13:return Tc("Suspense");case 19:return Tc("SuspenseList");case 0:case 2:case 15:return e=Dg(e.type,!1),e;case 11:return e=Dg(e.type.render,!1),e;case 1:return e=Dg(e.type,!0),e;default:return""}}function Xy(e){if(e==null)return null;if(typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case pa:return"Fragment";case ha:return"Portal";case Ky:return"Profiler";case Xb:return"StrictMode";case Yy:return"Suspense";case Qy:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case NR:return(e.displayName||"Context")+".Consumer";case OR:return(e._context.displayName||"Context")+".Provider";case Zb:var t=e.render;return e=e.displayName,e||(e=t.displayName||t.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case Jb:return t=e.displayName||null,t!==null?t:Xy(e.type)||"Memo";case Go:t=e._payload,e=e._init;try{return Xy(e(t))}catch{}}return null}function kB(e){var t=e.type;switch(e.tag){case 24:return"Cache";case 9:return(t.displayName||"Context")+".Consumer";case 10:return(t._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=t.render,e=e.displayName||e.name||"",t.displayName||(e!==""?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return t;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return Xy(t);case 8:return t===Xb?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof t=="function")return t.displayName||t.name||null;if(typeof t=="string")return t}return null}function Si(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function DR(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(t==="checkbox"||t==="radio")}function TB(e){var t=DR(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),r=""+e[t];if(!e.hasOwnProperty(t)&&typeof n<"u"&&typeof n.get=="function"&&typeof n.set=="function"){var o=n.get,i=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return o.call(this)},set:function(s){r=""+s,i.call(this,s)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return r},setValue:function(s){r=""+s},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}function Qd(e){e._valueTracker||(e._valueTracker=TB(e))}function AR(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r="";return e&&(r=DR(e)?e.checked?"true":"false":e.value),e=r,e!==n?(t.setValue(e),!0):!1}function Ph(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}function Zy(e,t){var n=t.checked;return tt({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:n??e._wrapperState.initialChecked})}function r2(e,t){var n=t.defaultValue==null?"":t.defaultValue,r=t.checked!=null?t.checked:t.defaultChecked;n=Si(t.value!=null?t.value:n),e._wrapperState={initialChecked:r,initialValue:n,controlled:t.type==="checkbox"||t.type==="radio"?t.checked!=null:t.value!=null}}function FR(e,t){t=t.checked,t!=null&&Qb(e,"checked",t,!1)}function Jy(e,t){FR(e,t);var n=Si(t.value),r=t.type;if(n!=null)r==="number"?(n===0&&e.value===""||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if(r==="submit"||r==="reset"){e.removeAttribute("value");return}t.hasOwnProperty("value")?e0(e,t.type,n):t.hasOwnProperty("defaultValue")&&e0(e,t.type,Si(t.defaultValue)),t.checked==null&&t.defaultChecked!=null&&(e.defaultChecked=!!t.defaultChecked)}function o2(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var r=t.type;if(!(r!=="submit"&&r!=="reset"||t.value!==void 0&&t.value!==null))return;t=""+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}n=e.name,n!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,n!==""&&(e.name=n)}function e0(e,t,n){(t!=="number"||Ph(e.ownerDocument)!==e)&&(n==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}var Rc=Array.isArray;function ja(e,t,n,r){if(e=e.options,t){t={};for(var o=0;o"+t.valueOf().toString()+"",t=Xd.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}});function du(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&n.nodeType===3){n.nodeValue=t;return}}e.textContent=t}var jc={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},RB=["Webkit","ms","Moz","O"];Object.keys(jc).forEach(function(e){RB.forEach(function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),jc[t]=jc[e]})});function zR(e,t,n){return t==null||typeof t=="boolean"||t===""?"":n||typeof t!="number"||t===0||jc.hasOwnProperty(e)&&jc[e]?(""+t).trim():t+"px"}function BR(e,t){e=e.style;for(var n in t)if(t.hasOwnProperty(n)){var r=n.indexOf("--")===0,o=zR(n,t[n],r);n==="float"&&(n="cssFloat"),r?e.setProperty(n,o):e[n]=o}}var IB=tt({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function r0(e,t){if(t){if(IB[e]&&(t.children!=null||t.dangerouslySetInnerHTML!=null))throw Error(U(137,e));if(t.dangerouslySetInnerHTML!=null){if(t.children!=null)throw Error(U(60));if(typeof t.dangerouslySetInnerHTML!="object"||!("__html"in t.dangerouslySetInnerHTML))throw Error(U(61))}if(t.style!=null&&typeof t.style!="object")throw Error(U(62))}}function o0(e,t){if(e.indexOf("-")===-1)return typeof t.is=="string";switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var i0=null;function ew(e){return e=e.target||e.srcElement||window,e.correspondingUseElement&&(e=e.correspondingUseElement),e.nodeType===3?e.parentNode:e}var s0=null,La=null,Va=null;function a2(e){if(e=rd(e)){if(typeof s0!="function")throw Error(U(280));var t=e.stateNode;t&&(t=im(t),s0(e.stateNode,e.type,t))}}function HR(e){La?Va?Va.push(e):Va=[e]:La=e}function UR(){if(La){var e=La,t=Va;if(Va=La=null,a2(e),t)for(e=0;e>>=0,e===0?32:31-(VB(e)/zB|0)|0}var Zd=64,Jd=4194304;function Ic(e){switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return e&4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return e&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return e}}function Dh(e,t){var n=e.pendingLanes;if(n===0)return 0;var r=0,o=e.suspendedLanes,i=e.pingedLanes,s=n&268435455;if(s!==0){var a=s&~o;a!==0?r=Ic(a):(i&=s,i!==0&&(r=Ic(i)))}else s=n&~o,s!==0?r=Ic(s):i!==0&&(r=Ic(i));if(r===0)return 0;if(t!==0&&t!==r&&!(t&o)&&(o=r&-r,i=t&-t,o>=i||o===16&&(i&4194240)!==0))return t;if(r&4&&(r|=n&16),t=e.entangledLanes,t!==0)for(e=e.entanglements,t&=r;0n;n++)t.push(e);return t}function td(e,t,n){e.pendingLanes|=t,t!==536870912&&(e.suspendedLanes=0,e.pingedLanes=0),e=e.eventTimes,t=31-hr(t),e[t]=n}function WB(e,t){var n=e.pendingLanes&~t;e.pendingLanes=t,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=t,e.mutableReadLanes&=t,e.entangledLanes&=t,t=e.entanglements;var r=e.eventTimes;for(e=e.expirationTimes;0=Vc),g2=" ",v2=!1;function u4(e,t){switch(e){case"keyup":return bH.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function d4(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var ma=!1;function SH(e,t){switch(e){case"compositionend":return d4(t);case"keypress":return t.which!==32?null:(v2=!0,g2);case"textInput":return e=t.data,e===g2&&v2?null:e;default:return null}}function xH(e,t){if(ma)return e==="compositionend"||!lw&&u4(e,t)?(e=l4(),Hf=iw=ni=null,ma=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=r}e:{for(;n;){if(n.nextSibling){n=n.nextSibling;break e}n=n.parentNode}n=void 0}n=S2(n)}}function m4(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?m4(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function g4(){for(var e=window,t=Ph();t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href=="string"}catch{n=!1}if(n)e=t.contentWindow;else break;t=Ph(e.document)}return t}function cw(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}function PH(e){var t=g4(),n=e.focusedElem,r=e.selectionRange;if(t!==n&&n&&n.ownerDocument&&m4(n.ownerDocument.documentElement,n)){if(r!==null&&cw(n)){if(t=r.start,e=r.end,e===void 0&&(e=t),"selectionStart"in n)n.selectionStart=t,n.selectionEnd=Math.min(e,n.value.length);else if(e=(t=n.ownerDocument||document)&&t.defaultView||window,e.getSelection){e=e.getSelection();var o=n.textContent.length,i=Math.min(r.start,o);r=r.end===void 0?i:Math.min(r.end,o),!e.extend&&i>r&&(o=r,r=i,i=o),o=x2(n,i);var s=x2(n,r);o&&s&&(e.rangeCount!==1||e.anchorNode!==o.node||e.anchorOffset!==o.offset||e.focusNode!==s.node||e.focusOffset!==s.offset)&&(t=t.createRange(),t.setStart(o.node,o.offset),e.removeAllRanges(),i>r?(e.addRange(t),e.extend(s.node,s.offset)):(t.setEnd(s.node,s.offset),e.addRange(t)))}}for(t=[],e=n;e=e.parentNode;)e.nodeType===1&&t.push({element:e,left:e.scrollLeft,top:e.scrollTop});for(typeof n.focus=="function"&&n.focus(),n=0;n=document.documentMode,ga=null,f0=null,Bc=null,h0=!1;function _2(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;h0||ga==null||ga!==Ph(r)||(r=ga,"selectionStart"in r&&cw(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),Bc&&vu(Bc,r)||(Bc=r,r=jh(f0,"onSelect"),0ba||(e.current=b0[ba],b0[ba]=null,ba--)}function Ve(e,t){ba++,b0[ba]=e.current,e.current=t}var xi={},Ht=Li(xi),un=Li(!1),ws=xi;function ll(e,t){var n=e.type.contextTypes;if(!n)return xi;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===t)return r.__reactInternalMemoizedMaskedChildContext;var o={},i;for(i in n)o[i]=t[i];return r&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=o),o}function dn(e){return e=e.childContextTypes,e!=null}function Vh(){He(un),He(Ht)}function $2(e,t,n){if(Ht.current!==xi)throw Error(U(168));Ve(Ht,t),Ve(un,n)}function C4(e,t,n){var r=e.stateNode;if(t=t.childContextTypes,typeof r.getChildContext!="function")return n;r=r.getChildContext();for(var o in r)if(!(o in t))throw Error(U(108,kB(e)||"Unknown",o));return tt({},n,r)}function zh(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||xi,ws=Ht.current,Ve(Ht,e),Ve(un,un.current),!0}function P2(e,t,n){var r=e.stateNode;if(!r)throw Error(U(169));n?(e=C4(e,t,ws),r.__reactInternalMemoizedMergedChildContext=e,He(un),He(Ht),Ve(Ht,e)):He(un),Ve(un,n)}var so=null,sm=!1,Yg=!1;function k4(e){so===null?so=[e]:so.push(e)}function HH(e){sm=!0,k4(e)}function Vi(){if(!Yg&&so!==null){Yg=!0;var e=0,t=Oe;try{var n=so;for(Oe=1;e>=s,o-=s,lo=1<<32-hr(t)+o|n<k?(T=C,C=null):T=C.sibling;var R=f(y,C,w[k],x);if(R===null){C===null&&(C=T);break}e&&C&&R.alternate===null&&t(y,C),b=i(R,b,k),E===null?_=R:E.sibling=R,E=R,C=T}if(k===w.length)return n(y,C),qe&&qi(y,k),_;if(C===null){for(;kk?(T=C,C=null):T=C.sibling;var D=f(y,C,R.value,x);if(D===null){C===null&&(C=T);break}e&&C&&D.alternate===null&&t(y,C),b=i(D,b,k),E===null?_=D:E.sibling=D,E=D,C=T}if(R.done)return n(y,C),qe&&qi(y,k),_;if(C===null){for(;!R.done;k++,R=w.next())R=d(y,R.value,x),R!==null&&(b=i(R,b,k),E===null?_=R:E.sibling=R,E=R);return qe&&qi(y,k),_}for(C=r(y,C);!R.done;k++,R=w.next())R=h(C,y,k,R.value,x),R!==null&&(e&&R.alternate!==null&&C.delete(R.key===null?k:R.key),b=i(R,b,k),E===null?_=R:E.sibling=R,E=R);return e&&C.forEach(function(O){return t(y,O)}),qe&&qi(y,k),_}function S(y,b,w,x){if(typeof w=="object"&&w!==null&&w.type===pa&&w.key===null&&(w=w.props.children),typeof w=="object"&&w!==null){switch(w.$$typeof){case Yd:e:{for(var _=w.key,E=b;E!==null;){if(E.key===_){if(_=w.type,_===pa){if(E.tag===7){n(y,E.sibling),b=o(E,w.props.children),b.return=y,y=b;break e}}else if(E.elementType===_||typeof _=="object"&&_!==null&&_.$$typeof===Go&&j2(_)===E.type){n(y,E.sibling),b=o(E,w.props),b.ref=sc(y,E,w),b.return=y,y=b;break e}n(y,E);break}else t(y,E);E=E.sibling}w.type===pa?(b=ps(w.props.children,y.mode,x,w.key),b.return=y,y=b):(x=Xf(w.type,w.key,w.props,null,y.mode,x),x.ref=sc(y,b,w),x.return=y,y=x)}return s(y);case ha:e:{for(E=w.key;b!==null;){if(b.key===E)if(b.tag===4&&b.stateNode.containerInfo===w.containerInfo&&b.stateNode.implementation===w.implementation){n(y,b.sibling),b=o(b,w.children||[]),b.return=y,y=b;break e}else{n(y,b);break}else t(y,b);b=b.sibling}b=rv(w,y.mode,x),b.return=y,y=b}return s(y);case Go:return E=w._init,S(y,b,E(w._payload),x)}if(Rc(w))return m(y,b,w,x);if(tc(w))return v(y,b,w,x);af(y,w)}return typeof w=="string"&&w!==""||typeof w=="number"?(w=""+w,b!==null&&b.tag===6?(n(y,b.sibling),b=o(b,w),b.return=y,y=b):(n(y,b),b=nv(w,y.mode,x),b.return=y,y=b),s(y)):n(y,b)}return S}var ul=M4(!0),D4=M4(!1),od={},Br=Li(od),Su=Li(od),xu=Li(od);function ls(e){if(e===od)throw Error(U(174));return e}function yw(e,t){switch(Ve(xu,t),Ve(Su,e),Ve(Br,od),e=t.nodeType,e){case 9:case 11:t=(t=t.documentElement)?t.namespaceURI:n0(null,"");break;default:e=e===8?t.parentNode:t,t=e.namespaceURI||null,e=e.tagName,t=n0(t,e)}He(Br),Ve(Br,t)}function dl(){He(Br),He(Su),He(xu)}function A4(e){ls(xu.current);var t=ls(Br.current),n=n0(t,e.type);t!==n&&(Ve(Su,e),Ve(Br,n))}function bw(e){Su.current===e&&(He(Br),He(Su))}var Qe=Li(0);function qh(e){for(var t=e;t!==null;){if(t.tag===13){var n=t.memoizedState;if(n!==null&&(n=n.dehydrated,n===null||n.data==="$?"||n.data==="$!"))return t}else if(t.tag===19&&t.memoizedProps.revealOrder!==void 0){if(t.flags&128)return t}else if(t.child!==null){t.child.return=t,t=t.child;continue}if(t===e)break;for(;t.sibling===null;){if(t.return===null||t.return===e)return null;t=t.return}t.sibling.return=t.return,t=t.sibling}return null}var Qg=[];function ww(){for(var e=0;en?n:4,e(!0);var r=Xg.transition;Xg.transition={};try{e(!1),t()}finally{Oe=n,Xg.transition=r}}function Z4(){return Gn().memoizedState}function qH(e,t,n){var r=hi(e);if(n={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null},J4(e))eI(t,n);else if(n=$4(e,t,n,r),n!==null){var o=Jt();pr(n,e,r,o),tI(n,t,r)}}function KH(e,t,n){var r=hi(e),o={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null};if(J4(e))eI(t,o);else{var i=e.alternate;if(e.lanes===0&&(i===null||i.lanes===0)&&(i=t.lastRenderedReducer,i!==null))try{var s=t.lastRenderedState,a=i(s,n);if(o.hasEagerState=!0,o.eagerState=a,xr(a,s)){var l=t.interleaved;l===null?(o.next=o,gw(t)):(o.next=l.next,l.next=o),t.interleaved=o;return}}catch{}finally{}n=$4(e,t,o,r),n!==null&&(o=Jt(),pr(n,e,r,o),tI(n,t,r))}}function J4(e){var t=e.alternate;return e===et||t!==null&&t===et}function eI(e,t){Hc=Kh=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function tI(e,t,n){if(n&4194240){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,nw(e,n)}}var Yh={readContext:Wn,useCallback:At,useContext:At,useEffect:At,useImperativeHandle:At,useInsertionEffect:At,useLayoutEffect:At,useMemo:At,useReducer:At,useRef:At,useState:At,useDebugValue:At,useDeferredValue:At,useTransition:At,useMutableSource:At,useSyncExternalStore:At,useId:At,unstable_isNewReconciler:!1},YH={readContext:Wn,useCallback:function(e,t){return Pr().memoizedState=[e,t===void 0?null:t],e},useContext:Wn,useEffect:V2,useImperativeHandle:function(e,t,n){return n=n!=null?n.concat([e]):null,qf(4194308,4,q4.bind(null,t,e),n)},useLayoutEffect:function(e,t){return qf(4194308,4,e,t)},useInsertionEffect:function(e,t){return qf(4,2,e,t)},useMemo:function(e,t){var n=Pr();return t=t===void 0?null:t,e=e(),n.memoizedState=[e,t],e},useReducer:function(e,t,n){var r=Pr();return t=n!==void 0?n(t):t,r.memoizedState=r.baseState=t,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:t},r.queue=e,e=e.dispatch=qH.bind(null,et,e),[r.memoizedState,e]},useRef:function(e){var t=Pr();return e={current:e},t.memoizedState=e},useState:L2,useDebugValue:Cw,useDeferredValue:function(e){return Pr().memoizedState=e},useTransition:function(){var e=L2(!1),t=e[0];return e=GH.bind(null,e[1]),Pr().memoizedState=e,[t,e]},useMutableSource:function(){},useSyncExternalStore:function(e,t,n){var r=et,o=Pr();if(qe){if(n===void 0)throw Error(U(407));n=n()}else{if(n=t(),Ct===null)throw Error(U(349));xs&30||L4(r,t,n)}o.memoizedState=n;var i={value:n,getSnapshot:t};return o.queue=i,V2(z4.bind(null,r,i,e),[e]),r.flags|=2048,Cu(9,V4.bind(null,r,i,n,t),void 0,null),n},useId:function(){var e=Pr(),t=Ct.identifierPrefix;if(qe){var n=co,r=lo;n=(r&~(1<<32-hr(r)-1)).toString(32)+n,t=":"+t+"R"+n,n=_u++,0<\/script>",e=e.removeChild(e.firstChild)):typeof r.is=="string"?e=s.createElement(n,{is:r.is}):(e=s.createElement(n),n==="select"&&(s=e,r.multiple?s.multiple=!0:r.size&&(s.size=r.size))):e=s.createElementNS(e,n),e[Fr]=t,e[wu]=r,uI(e,t,!1,!1),t.stateNode=e;e:{switch(s=o0(n,r),n){case"dialog":Be("cancel",e),Be("close",e),o=r;break;case"iframe":case"object":case"embed":Be("load",e),o=r;break;case"video":case"audio":for(o=0;o<$c.length;o++)Be($c[o],e);o=r;break;case"source":Be("error",e),o=r;break;case"img":case"image":case"link":Be("error",e),Be("load",e),o=r;break;case"details":Be("toggle",e),o=r;break;case"input":r2(e,r),o=Zy(e,r),Be("invalid",e);break;case"option":o=r;break;case"select":e._wrapperState={wasMultiple:!!r.multiple},o=tt({},r,{value:void 0}),Be("invalid",e);break;case"textarea":i2(e,r),o=t0(e,r),Be("invalid",e);break;default:o=r}r0(n,o),a=o;for(i in a)if(a.hasOwnProperty(i)){var l=a[i];i==="style"?BR(e,l):i==="dangerouslySetInnerHTML"?(l=l?l.__html:void 0,l!=null&&VR(e,l)):i==="children"?typeof l=="string"?(n!=="textarea"||l!=="")&&du(e,l):typeof l=="number"&&du(e,""+l):i!=="suppressContentEditableWarning"&&i!=="suppressHydrationWarning"&&i!=="autoFocus"&&(uu.hasOwnProperty(i)?l!=null&&i==="onScroll"&&Be("scroll",e):l!=null&&Qb(e,i,l,s))}switch(n){case"input":Qd(e),o2(e,r,!1);break;case"textarea":Qd(e),s2(e);break;case"option":r.value!=null&&e.setAttribute("value",""+Si(r.value));break;case"select":e.multiple=!!r.multiple,i=r.value,i!=null?ja(e,!!r.multiple,i,!1):r.defaultValue!=null&&ja(e,!!r.multiple,r.defaultValue,!0);break;default:typeof o.onClick=="function"&&(e.onclick=Lh)}switch(n){case"button":case"input":case"select":case"textarea":r=!!r.autoFocus;break e;case"img":r=!0;break e;default:r=!1}}r&&(t.flags|=4)}t.ref!==null&&(t.flags|=512,t.flags|=2097152)}return Ft(t),null;case 6:if(e&&t.stateNode!=null)fI(e,t,e.memoizedProps,r);else{if(typeof r!="string"&&t.stateNode===null)throw Error(U(166));if(n=ls(xu.current),ls(Br.current),sf(t)){if(r=t.stateNode,n=t.memoizedProps,r[Fr]=t,(i=r.nodeValue!==n)&&(e=En,e!==null))switch(e.tag){case 3:of(r.nodeValue,n,(e.mode&1)!==0);break;case 5:e.memoizedProps.suppressHydrationWarning!==!0&&of(r.nodeValue,n,(e.mode&1)!==0)}i&&(t.flags|=4)}else r=(n.nodeType===9?n:n.ownerDocument).createTextNode(r),r[Fr]=t,t.stateNode=r}return Ft(t),null;case 13:if(He(Qe),r=t.memoizedState,e===null||e.memoizedState!==null&&e.memoizedState.dehydrated!==null){if(qe&&_n!==null&&t.mode&1&&!(t.flags&128))I4(),cl(),t.flags|=98560,i=!1;else if(i=sf(t),r!==null&&r.dehydrated!==null){if(e===null){if(!i)throw Error(U(318));if(i=t.memoizedState,i=i!==null?i.dehydrated:null,!i)throw Error(U(317));i[Fr]=t}else cl(),!(t.flags&128)&&(t.memoizedState=null),t.flags|=4;Ft(t),i=!1}else ar!==null&&(j0(ar),ar=null),i=!0;if(!i)return t.flags&65536?t:null}return t.flags&128?(t.lanes=n,t):(r=r!==null,r!==(e!==null&&e.memoizedState!==null)&&r&&(t.child.flags|=8192,t.mode&1&&(e===null||Qe.current&1?bt===0&&(bt=3):Ow())),t.updateQueue!==null&&(t.flags|=4),Ft(t),null);case 4:return dl(),$0(e,t),e===null&&yu(t.stateNode.containerInfo),Ft(t),null;case 10:return mw(t.type._context),Ft(t),null;case 17:return dn(t.type)&&Vh(),Ft(t),null;case 19:if(He(Qe),i=t.memoizedState,i===null)return Ft(t),null;if(r=(t.flags&128)!==0,s=i.rendering,s===null)if(r)ac(i,!1);else{if(bt!==0||e!==null&&e.flags&128)for(e=t.child;e!==null;){if(s=qh(e),s!==null){for(t.flags|=128,ac(i,!1),r=s.updateQueue,r!==null&&(t.updateQueue=r,t.flags|=4),t.subtreeFlags=0,r=n,n=t.child;n!==null;)i=n,e=r,i.flags&=14680066,s=i.alternate,s===null?(i.childLanes=0,i.lanes=e,i.child=null,i.subtreeFlags=0,i.memoizedProps=null,i.memoizedState=null,i.updateQueue=null,i.dependencies=null,i.stateNode=null):(i.childLanes=s.childLanes,i.lanes=s.lanes,i.child=s.child,i.subtreeFlags=0,i.deletions=null,i.memoizedProps=s.memoizedProps,i.memoizedState=s.memoizedState,i.updateQueue=s.updateQueue,i.type=s.type,e=s.dependencies,i.dependencies=e===null?null:{lanes:e.lanes,firstContext:e.firstContext}),n=n.sibling;return Ve(Qe,Qe.current&1|2),t.child}e=e.sibling}i.tail!==null&&ft()>hl&&(t.flags|=128,r=!0,ac(i,!1),t.lanes=4194304)}else{if(!r)if(e=qh(s),e!==null){if(t.flags|=128,r=!0,n=e.updateQueue,n!==null&&(t.updateQueue=n,t.flags|=4),ac(i,!0),i.tail===null&&i.tailMode==="hidden"&&!s.alternate&&!qe)return Ft(t),null}else 2*ft()-i.renderingStartTime>hl&&n!==1073741824&&(t.flags|=128,r=!0,ac(i,!1),t.lanes=4194304);i.isBackwards?(s.sibling=t.child,t.child=s):(n=i.last,n!==null?n.sibling=s:t.child=s,i.last=s)}return i.tail!==null?(t=i.tail,i.rendering=t,i.tail=t.sibling,i.renderingStartTime=ft(),t.sibling=null,n=Qe.current,Ve(Qe,r?n&1|2:n&1),t):(Ft(t),null);case 22:case 23:return Pw(),r=t.memoizedState!==null,e!==null&&e.memoizedState!==null!==r&&(t.flags|=8192),r&&t.mode&1?yn&1073741824&&(Ft(t),t.subtreeFlags&6&&(t.flags|=8192)):Ft(t),null;case 24:return null;case 25:return null}throw Error(U(156,t.tag))}function rU(e,t){switch(dw(t),t.tag){case 1:return dn(t.type)&&Vh(),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return dl(),He(un),He(Ht),ww(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 5:return bw(t),null;case 13:if(He(Qe),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(U(340));cl()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return He(Qe),null;case 4:return dl(),null;case 10:return mw(t.type._context),null;case 22:case 23:return Pw(),null;case 24:return null;default:return null}}var cf=!1,zt=!1,oU=typeof WeakSet=="function"?WeakSet:Set,Y=null;function _a(e,t){var n=e.ref;if(n!==null)if(typeof n=="function")try{n(null)}catch(r){nt(e,t,r)}else n.current=null}function P0(e,t,n){try{n()}catch(r){nt(e,t,r)}}var Y2=!1;function iU(e,t){if(p0=Ah,e=g4(),cw(e)){if("selectionStart"in e)var n={start:e.selectionStart,end:e.selectionEnd};else e:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var o=r.anchorOffset,i=r.focusNode;r=r.focusOffset;try{n.nodeType,i.nodeType}catch{n=null;break e}var s=0,a=-1,l=-1,c=0,u=0,d=e,f=null;t:for(;;){for(var h;d!==n||o!==0&&d.nodeType!==3||(a=s+o),d!==i||r!==0&&d.nodeType!==3||(l=s+r),d.nodeType===3&&(s+=d.nodeValue.length),(h=d.firstChild)!==null;)f=d,d=h;for(;;){if(d===e)break t;if(f===n&&++c===o&&(a=s),f===i&&++u===r&&(l=s),(h=d.nextSibling)!==null)break;d=f,f=d.parentNode}d=h}n=a===-1||l===-1?null:{start:a,end:l}}else n=null}n=n||{start:0,end:0}}else n=null;for(m0={focusedElem:e,selectionRange:n},Ah=!1,Y=t;Y!==null;)if(t=Y,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,Y=e;else for(;Y!==null;){t=Y;try{var m=t.alternate;if(t.flags&1024)switch(t.tag){case 0:case 11:case 15:break;case 1:if(m!==null){var v=m.memoizedProps,S=m.memoizedState,y=t.stateNode,b=y.getSnapshotBeforeUpdate(t.elementType===t.type?v:rr(t.type,v),S);y.__reactInternalSnapshotBeforeUpdate=b}break;case 3:var w=t.stateNode.containerInfo;w.nodeType===1?w.textContent="":w.nodeType===9&&w.documentElement&&w.removeChild(w.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(U(163))}}catch(x){nt(t,t.return,x)}if(e=t.sibling,e!==null){e.return=t.return,Y=e;break}Y=t.return}return m=Y2,Y2=!1,m}function Uc(e,t,n){var r=t.updateQueue;if(r=r!==null?r.lastEffect:null,r!==null){var o=r=r.next;do{if((o.tag&e)===e){var i=o.destroy;o.destroy=void 0,i!==void 0&&P0(t,n,i)}o=o.next}while(o!==r)}}function cm(e,t){if(t=t.updateQueue,t=t!==null?t.lastEffect:null,t!==null){var n=t=t.next;do{if((n.tag&e)===e){var r=n.create;n.destroy=r()}n=n.next}while(n!==t)}}function O0(e){var t=e.ref;if(t!==null){var n=e.stateNode;switch(e.tag){case 5:e=n;break;default:e=n}typeof t=="function"?t(e):t.current=e}}function hI(e){var t=e.alternate;t!==null&&(e.alternate=null,hI(t)),e.child=null,e.deletions=null,e.sibling=null,e.tag===5&&(t=e.stateNode,t!==null&&(delete t[Fr],delete t[wu],delete t[y0],delete t[zH],delete t[BH])),e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function pI(e){return e.tag===5||e.tag===3||e.tag===4}function Q2(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||pI(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function N0(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.nodeType===8?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(n.nodeType===8?(t=n.parentNode,t.insertBefore(e,n)):(t=n,t.appendChild(e)),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=Lh));else if(r!==4&&(e=e.child,e!==null))for(N0(e,t,n),e=e.sibling;e!==null;)N0(e,t,n),e=e.sibling}function M0(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(e=e.child,e!==null))for(M0(e,t,n),e=e.sibling;e!==null;)M0(e,t,n),e=e.sibling}var It=null,or=!1;function Mo(e,t,n){for(n=n.child;n!==null;)mI(e,t,n),n=n.sibling}function mI(e,t,n){if(zr&&typeof zr.onCommitFiberUnmount=="function")try{zr.onCommitFiberUnmount(tm,n)}catch{}switch(n.tag){case 5:zt||_a(n,t);case 6:var r=It,o=or;It=null,Mo(e,t,n),It=r,or=o,It!==null&&(or?(e=It,n=n.stateNode,e.nodeType===8?e.parentNode.removeChild(n):e.removeChild(n)):It.removeChild(n.stateNode));break;case 18:It!==null&&(or?(e=It,n=n.stateNode,e.nodeType===8?Kg(e.parentNode,n):e.nodeType===1&&Kg(e,n),mu(e)):Kg(It,n.stateNode));break;case 4:r=It,o=or,It=n.stateNode.containerInfo,or=!0,Mo(e,t,n),It=r,or=o;break;case 0:case 11:case 14:case 15:if(!zt&&(r=n.updateQueue,r!==null&&(r=r.lastEffect,r!==null))){o=r=r.next;do{var i=o,s=i.destroy;i=i.tag,s!==void 0&&(i&2||i&4)&&P0(n,t,s),o=o.next}while(o!==r)}Mo(e,t,n);break;case 1:if(!zt&&(_a(n,t),r=n.stateNode,typeof r.componentWillUnmount=="function"))try{r.props=n.memoizedProps,r.state=n.memoizedState,r.componentWillUnmount()}catch(a){nt(n,t,a)}Mo(e,t,n);break;case 21:Mo(e,t,n);break;case 22:n.mode&1?(zt=(r=zt)||n.memoizedState!==null,Mo(e,t,n),zt=r):Mo(e,t,n);break;default:Mo(e,t,n)}}function X2(e){var t=e.updateQueue;if(t!==null){e.updateQueue=null;var n=e.stateNode;n===null&&(n=e.stateNode=new oU),t.forEach(function(r){var o=pU.bind(null,e,r);n.has(r)||(n.add(r),r.then(o,o))})}}function er(e,t){var n=t.deletions;if(n!==null)for(var r=0;ro&&(o=s),r&=~i}if(r=o,r=ft()-r,r=(120>r?120:480>r?480:1080>r?1080:1920>r?1920:3e3>r?3e3:4320>r?4320:1960*aU(r/1960))-r,10e?16:e,ri===null)var r=!1;else{if(e=ri,ri=null,Zh=0,Ce&6)throw Error(U(331));var o=Ce;for(Ce|=4,Y=e.current;Y!==null;){var i=Y,s=i.child;if(Y.flags&16){var a=i.deletions;if(a!==null){for(var l=0;lft()-Iw?hs(e,0):Rw|=n),fn(e,t)}function _I(e,t){t===0&&(e.mode&1?(t=Jd,Jd<<=1,!(Jd&130023424)&&(Jd=4194304)):t=1);var n=Jt();e=So(e,t),e!==null&&(td(e,t,n),fn(e,n))}function hU(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),_I(e,n)}function pU(e,t){var n=0;switch(e.tag){case 13:var r=e.stateNode,o=e.memoizedState;o!==null&&(n=o.retryLane);break;case 19:r=e.stateNode;break;default:throw Error(U(314))}r!==null&&r.delete(t),_I(e,n)}var EI;EI=function(e,t,n){if(e!==null)if(e.memoizedProps!==t.pendingProps||un.current)cn=!0;else{if(!(e.lanes&n)&&!(t.flags&128))return cn=!1,tU(e,t,n);cn=!!(e.flags&131072)}else cn=!1,qe&&t.flags&1048576&&T4(t,Hh,t.index);switch(t.lanes=0,t.tag){case 2:var r=t.type;Kf(e,t),e=t.pendingProps;var o=ll(t,Ht.current);Ba(t,n),o=xw(null,t,r,e,o,n);var i=_w();return t.flags|=1,typeof o=="object"&&o!==null&&typeof o.render=="function"&&o.$$typeof===void 0?(t.tag=1,t.memoizedState=null,t.updateQueue=null,dn(r)?(i=!0,zh(t)):i=!1,t.memoizedState=o.state!==null&&o.state!==void 0?o.state:null,vw(t),o.updater=am,t.stateNode=o,o._reactInternals=t,E0(t,r,e,n),t=T0(null,t,r,!0,i,n)):(t.tag=0,qe&&i&&uw(t),Yt(null,t,o,n),t=t.child),t;case 16:r=t.elementType;e:{switch(Kf(e,t),e=t.pendingProps,o=r._init,r=o(r._payload),t.type=r,o=t.tag=gU(r),e=rr(r,e),o){case 0:t=k0(null,t,r,e,n);break e;case 1:t=G2(null,t,r,e,n);break e;case 11:t=U2(null,t,r,e,n);break e;case 14:t=W2(null,t,r,rr(r.type,e),n);break e}throw Error(U(306,r,""))}return t;case 0:return r=t.type,o=t.pendingProps,o=t.elementType===r?o:rr(r,o),k0(e,t,r,o,n);case 1:return r=t.type,o=t.pendingProps,o=t.elementType===r?o:rr(r,o),G2(e,t,r,o,n);case 3:e:{if(aI(t),e===null)throw Error(U(387));r=t.pendingProps,i=t.memoizedState,o=i.element,P4(e,t),Gh(t,r,null,n);var s=t.memoizedState;if(r=s.element,i.isDehydrated)if(i={element:r,isDehydrated:!1,cache:s.cache,pendingSuspenseBoundaries:s.pendingSuspenseBoundaries,transitions:s.transitions},t.updateQueue.baseState=i,t.memoizedState=i,t.flags&256){o=fl(Error(U(423)),t),t=q2(e,t,r,n,o);break e}else if(r!==o){o=fl(Error(U(424)),t),t=q2(e,t,r,n,o);break e}else for(_n=ui(t.stateNode.containerInfo.firstChild),En=t,qe=!0,ar=null,n=D4(t,null,r,n),t.child=n;n;)n.flags=n.flags&-3|4096,n=n.sibling;else{if(cl(),r===o){t=xo(e,t,n);break e}Yt(e,t,r,n)}t=t.child}return t;case 5:return A4(t),e===null&&S0(t),r=t.type,o=t.pendingProps,i=e!==null?e.memoizedProps:null,s=o.children,g0(r,o)?s=null:i!==null&&g0(r,i)&&(t.flags|=32),sI(e,t),Yt(e,t,s,n),t.child;case 6:return e===null&&S0(t),null;case 13:return lI(e,t,n);case 4:return yw(t,t.stateNode.containerInfo),r=t.pendingProps,e===null?t.child=ul(t,null,r,n):Yt(e,t,r,n),t.child;case 11:return r=t.type,o=t.pendingProps,o=t.elementType===r?o:rr(r,o),U2(e,t,r,o,n);case 7:return Yt(e,t,t.pendingProps,n),t.child;case 8:return Yt(e,t,t.pendingProps.children,n),t.child;case 12:return Yt(e,t,t.pendingProps.children,n),t.child;case 10:e:{if(r=t.type._context,o=t.pendingProps,i=t.memoizedProps,s=o.value,Ve(Uh,r._currentValue),r._currentValue=s,i!==null)if(xr(i.value,s)){if(i.children===o.children&&!un.current){t=xo(e,t,n);break e}}else for(i=t.child,i!==null&&(i.return=t);i!==null;){var a=i.dependencies;if(a!==null){s=i.child;for(var l=a.firstContext;l!==null;){if(l.context===r){if(i.tag===1){l=po(-1,n&-n),l.tag=2;var c=i.updateQueue;if(c!==null){c=c.shared;var u=c.pending;u===null?l.next=l:(l.next=u.next,u.next=l),c.pending=l}}i.lanes|=n,l=i.alternate,l!==null&&(l.lanes|=n),x0(i.return,n,t),a.lanes|=n;break}l=l.next}}else if(i.tag===10)s=i.type===t.type?null:i.child;else if(i.tag===18){if(s=i.return,s===null)throw Error(U(341));s.lanes|=n,a=s.alternate,a!==null&&(a.lanes|=n),x0(s,n,t),s=i.sibling}else s=i.child;if(s!==null)s.return=i;else for(s=i;s!==null;){if(s===t){s=null;break}if(i=s.sibling,i!==null){i.return=s.return,s=i;break}s=s.return}i=s}Yt(e,t,o.children,n),t=t.child}return t;case 9:return o=t.type,r=t.pendingProps.children,Ba(t,n),o=Wn(o),r=r(o),t.flags|=1,Yt(e,t,r,n),t.child;case 14:return r=t.type,o=rr(r,t.pendingProps),o=rr(r.type,o),W2(e,t,r,o,n);case 15:return oI(e,t,t.type,t.pendingProps,n);case 17:return r=t.type,o=t.pendingProps,o=t.elementType===r?o:rr(r,o),Kf(e,t),t.tag=1,dn(r)?(e=!0,zh(t)):e=!1,Ba(t,n),N4(t,r,o),E0(t,r,o,n),T0(null,t,r,!0,e,n);case 19:return cI(e,t,n);case 22:return iI(e,t,n)}throw Error(U(156,t.tag))};function CI(e,t){return XR(e,t)}function mU(e,t,n,r){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function zn(e,t,n,r){return new mU(e,t,n,r)}function Nw(e){return e=e.prototype,!(!e||!e.isReactComponent)}function gU(e){if(typeof e=="function")return Nw(e)?1:0;if(e!=null){if(e=e.$$typeof,e===Zb)return 11;if(e===Jb)return 14}return 2}function pi(e,t){var n=e.alternate;return n===null?(n=zn(e.tag,t,e.key,e.mode),n.elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.type=e.type,n.flags=0,n.subtreeFlags=0,n.deletions=null),n.flags=e.flags&14680064,n.childLanes=e.childLanes,n.lanes=e.lanes,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=t===null?null:{lanes:t.lanes,firstContext:t.firstContext},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}function Xf(e,t,n,r,o,i){var s=2;if(r=e,typeof e=="function")Nw(e)&&(s=1);else if(typeof e=="string")s=5;else e:switch(e){case pa:return ps(n.children,o,i,t);case Xb:s=8,o|=8;break;case Ky:return e=zn(12,n,t,o|2),e.elementType=Ky,e.lanes=i,e;case Yy:return e=zn(13,n,t,o),e.elementType=Yy,e.lanes=i,e;case Qy:return e=zn(19,n,t,o),e.elementType=Qy,e.lanes=i,e;case MR:return dm(n,o,i,t);default:if(typeof e=="object"&&e!==null)switch(e.$$typeof){case OR:s=10;break e;case NR:s=9;break e;case Zb:s=11;break e;case Jb:s=14;break e;case Go:s=16,r=null;break e}throw Error(U(130,e==null?e:typeof e,""))}return t=zn(s,n,t,o),t.elementType=e,t.type=r,t.lanes=i,t}function ps(e,t,n,r){return e=zn(7,e,r,t),e.lanes=n,e}function dm(e,t,n,r){return e=zn(22,e,r,t),e.elementType=MR,e.lanes=n,e.stateNode={isHidden:!1},e}function nv(e,t,n){return e=zn(6,e,null,t),e.lanes=n,e}function rv(e,t,n){return t=zn(4,e.children!==null?e.children:[],e.key,t),t.lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function vU(e,t,n,r,o){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=Fg(0),this.expirationTimes=Fg(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=Fg(0),this.identifierPrefix=r,this.onRecoverableError=o,this.mutableSourceEagerHydrationData=null}function Mw(e,t,n,r,o,i,s,a,l){return e=new vU(e,t,n,a,l),t===1?(t=1,i===!0&&(t|=8)):t=0,i=zn(3,null,null,t),e.current=i,i.stateNode=e,i.memoizedState={element:r,isDehydrated:n,cache:null,transitions:null,pendingSuspenseBoundaries:null},vw(i),e}function yU(e,t,n){var r=3"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(II)}catch(e){console.error(e)}}II(),TR.exports=On;var zi=TR.exports;const _U=kl(zi);var iE=zi;Gy.createRoot=iE.createRoot,Gy.hydrateRoot=iE.hydrateRoot;var EU=typeof Element<"u",CU=typeof Map=="function",kU=typeof Set=="function",TU=typeof ArrayBuffer=="function"&&!!ArrayBuffer.isView;function Zf(e,t){if(e===t)return!0;if(e&&t&&typeof e=="object"&&typeof t=="object"){if(e.constructor!==t.constructor)return!1;var n,r,o;if(Array.isArray(e)){if(n=e.length,n!=t.length)return!1;for(r=n;r--!==0;)if(!Zf(e[r],t[r]))return!1;return!0}var i;if(CU&&e instanceof Map&&t instanceof Map){if(e.size!==t.size)return!1;for(i=e.entries();!(r=i.next()).done;)if(!t.has(r.value[0]))return!1;for(i=e.entries();!(r=i.next()).done;)if(!Zf(r.value[1],t.get(r.value[0])))return!1;return!0}if(kU&&e instanceof Set&&t instanceof Set){if(e.size!==t.size)return!1;for(i=e.entries();!(r=i.next()).done;)if(!t.has(r.value[0]))return!1;return!0}if(TU&&ArrayBuffer.isView(e)&&ArrayBuffer.isView(t)){if(n=e.length,n!=t.length)return!1;for(r=n;r--!==0;)if(e[r]!==t[r])return!1;return!0}if(e.constructor===RegExp)return e.source===t.source&&e.flags===t.flags;if(e.valueOf!==Object.prototype.valueOf&&typeof e.valueOf=="function"&&typeof t.valueOf=="function")return e.valueOf()===t.valueOf();if(e.toString!==Object.prototype.toString&&typeof e.toString=="function"&&typeof t.toString=="function")return e.toString()===t.toString();if(o=Object.keys(e),n=o.length,n!==Object.keys(t).length)return!1;for(r=n;r--!==0;)if(!Object.prototype.hasOwnProperty.call(t,o[r]))return!1;if(EU&&e instanceof Element)return!1;for(r=n;r--!==0;)if(!((o[r]==="_owner"||o[r]==="__v"||o[r]==="__o")&&e.$$typeof)&&!Zf(e[o[r]],t[o[r]]))return!1;return!0}return e!==e&&t!==t}var RU=function(t,n){try{return Zf(t,n)}catch(r){if((r.message||"").match(/stack|recursion/i))return console.warn("react-fast-compare cannot handle circular refs"),!1;throw r}};const IU=kl(RU);var $U=function(e,t,n,r,o,i,s,a){if(!e){var l;if(t===void 0)l=new Error("Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.");else{var c=[n,r,o,i,s,a],u=0;l=new Error(t.replace(/%s/g,function(){return c[u++]})),l.name="Invariant Violation"}throw l.framesToPop=1,l}},PU=$U;const sE=kl(PU);var OU=function(t,n,r,o){var i=r?r.call(o,t,n):void 0;if(i!==void 0)return!!i;if(t===n)return!0;if(typeof t!="object"||!t||typeof n!="object"||!n)return!1;var s=Object.keys(t),a=Object.keys(n);if(s.length!==a.length)return!1;for(var l=Object.prototype.hasOwnProperty.bind(n),c=0;c(e.BASE="base",e.BODY="body",e.HEAD="head",e.HTML="html",e.LINK="link",e.META="meta",e.NOSCRIPT="noscript",e.SCRIPT="script",e.STYLE="style",e.TITLE="title",e.FRAGMENT="Symbol(react.fragment)",e))($I||{}),ov={link:{rel:["amphtml","canonical","alternate"]},script:{type:["application/ld+json"]},meta:{charset:"",name:["generator","robots","description"],property:["og:type","og:title","og:url","og:image","og:image:alt","og:description","twitter:url","twitter:title","twitter:description","twitter:image","twitter:image:alt","twitter:card","twitter:site"]}},aE=Object.values($I),jw={accesskey:"accessKey",charset:"charSet",class:"className",contenteditable:"contentEditable",contextmenu:"contextMenu","http-equiv":"httpEquiv",itemprop:"itemProp",tabindex:"tabIndex"},MU=Object.entries(jw).reduce((e,[t,n])=>(e[n]=t,e),{}),ur="data-rh",Ua={DEFAULT_TITLE:"defaultTitle",DEFER:"defer",ENCODE_SPECIAL_CHARACTERS:"encodeSpecialCharacters",ON_CHANGE_CLIENT_STATE:"onChangeClientState",TITLE_TEMPLATE:"titleTemplate",PRIORITIZE_SEO_TAGS:"prioritizeSeoTags"},Wa=(e,t)=>{for(let n=e.length-1;n>=0;n-=1){const r=e[n];if(Object.prototype.hasOwnProperty.call(r,t))return r[t]}return null},DU=e=>{let t=Wa(e,"title");const n=Wa(e,Ua.TITLE_TEMPLATE);if(Array.isArray(t)&&(t=t.join("")),n&&t)return n.replace(/%s/g,()=>t);const r=Wa(e,Ua.DEFAULT_TITLE);return t||r||void 0},AU=e=>Wa(e,Ua.ON_CHANGE_CLIENT_STATE)||(()=>{}),iv=(e,t)=>t.filter(n=>typeof n[e]<"u").map(n=>n[e]).reduce((n,r)=>({...n,...r}),{}),FU=(e,t)=>t.filter(n=>typeof n.base<"u").map(n=>n.base).reverse().reduce((n,r)=>{if(!n.length){const o=Object.keys(r);for(let i=0;iconsole&&typeof console.warn=="function"&&console.warn(e),cc=(e,t,n)=>{const r={};return n.filter(o=>Array.isArray(o[e])?!0:(typeof o[e]<"u"&&jU(`Helmet: ${e} should be of type "Array". Instead found type "${typeof o[e]}"`),!1)).map(o=>o[e]).reverse().reduce((o,i)=>{const s={};i.filter(l=>{let c;const u=Object.keys(l);for(let f=0;fo.push(l));const a=Object.keys(s);for(let l=0;l{if(Array.isArray(e)&&e.length){for(let n=0;n({baseTag:FU(["href"],e),bodyAttributes:iv("bodyAttributes",e),defer:Wa(e,Ua.DEFER),encode:Wa(e,Ua.ENCODE_SPECIAL_CHARACTERS),htmlAttributes:iv("htmlAttributes",e),linkTags:cc("link",["rel","href"],e),metaTags:cc("meta",["name","charset","http-equiv","property","itemprop"],e),noscriptTags:cc("noscript",["innerHTML"],e),onChangeClientState:AU(e),scriptTags:cc("script",["src","innerHTML"],e),styleTags:cc("style",["cssText"],e),title:DU(e),titleAttributes:iv("titleAttributes",e),prioritizeSeoTags:LU(e,Ua.PRIORITIZE_SEO_TAGS)}),PI=e=>Array.isArray(e)?e.join(""):e,zU=(e,t)=>{const n=Object.keys(e);for(let r=0;rArray.isArray(e)?e.reduce((n,r)=>(zU(r,t)?n.priority.push(r):n.default.push(r),n),{priority:[],default:[]}):{default:e,priority:[]},lE=(e,t)=>({...e,[t]:void 0}),BU=["noscript","script","style"],L0=(e,t=!0)=>t===!1?String(e):String(e).replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'"),OI=e=>Object.keys(e).reduce((t,n)=>{const r=typeof e[n]<"u"?`${n}="${e[n]}"`:`${n}`;return t?`${t} ${r}`:r},""),HU=(e,t,n,r)=>{const o=OI(n),i=PI(t);return o?`<${e} ${ur}="true" ${o}>${L0(i,r)}`:`<${e} ${ur}="true">${L0(i,r)}`},UU=(e,t,n=!0)=>t.reduce((r,o)=>{const i=o,s=Object.keys(i).filter(c=>!(c==="innerHTML"||c==="cssText")).reduce((c,u)=>{const d=typeof i[u]>"u"?u:`${u}="${L0(i[u],n)}"`;return c?`${c} ${d}`:d},""),a=i.innerHTML||i.cssText||"",l=BU.indexOf(e)===-1;return`${r}<${e} ${ur}="true" ${s}${l?"/>":`>${a}`}`},""),NI=(e,t={})=>Object.keys(e).reduce((n,r)=>{const o=jw[r];return n[o||r]=e[r],n},t),WU=(e,t,n)=>{const r={key:t,[ur]:!0},o=NI(n,r);return[Ge.createElement("title",o,t)]},Jf=(e,t)=>t.map((n,r)=>{const o={key:r,[ur]:!0};return Object.keys(n).forEach(i=>{const a=jw[i]||i;if(a==="innerHTML"||a==="cssText"){const l=n.innerHTML||n.cssText;o.dangerouslySetInnerHTML={__html:l}}else o[a]=n[i]}),Ge.createElement(e,o)}),An=(e,t,n=!0)=>{switch(e){case"title":return{toComponent:()=>WU(e,t.title,t.titleAttributes),toString:()=>HU(e,t.title,t.titleAttributes,n)};case"bodyAttributes":case"htmlAttributes":return{toComponent:()=>NI(t),toString:()=>OI(t)};default:return{toComponent:()=>Jf(e,t),toString:()=>UU(e,t,n)}}},GU=({metaTags:e,linkTags:t,scriptTags:n,encode:r})=>{const o=sv(e,ov.meta),i=sv(t,ov.link),s=sv(n,ov.script);return{priorityMethods:{toComponent:()=>[...Jf("meta",o.priority),...Jf("link",i.priority),...Jf("script",s.priority)],toString:()=>`${An("meta",o.priority,r)} ${An("link",i.priority,r)} ${An("script",s.priority,r)}`},metaTags:o.default,linkTags:i.default,scriptTags:s.default}},qU=e=>{const{baseTag:t,bodyAttributes:n,encode:r=!0,htmlAttributes:o,noscriptTags:i,styleTags:s,title:a="",titleAttributes:l,prioritizeSeoTags:c}=e;let{linkTags:u,metaTags:d,scriptTags:f}=e,h={toComponent:()=>{},toString:()=>""};return c&&({priorityMethods:h,linkTags:u,metaTags:d,scriptTags:f}=GU(e)),{priority:h,base:An("base",t,r),bodyAttributes:An("bodyAttributes",n,r),htmlAttributes:An("htmlAttributes",o,r),link:An("link",u,r),meta:An("meta",d,r),noscript:An("noscript",i,r),script:An("script",f,r),style:An("style",s,r),title:An("title",{title:a,titleAttributes:l},r)}},V0=qU,ff=[],MI=!!(typeof window<"u"&&window.document&&window.document.createElement),z0=class{constructor(e,t){Qr(this,"instances",[]);Qr(this,"canUseDOM",MI);Qr(this,"context");Qr(this,"value",{setHelmet:e=>{this.context.helmet=e},helmetInstances:{get:()=>this.canUseDOM?ff:this.instances,add:e=>{(this.canUseDOM?ff:this.instances).push(e)},remove:e=>{const t=(this.canUseDOM?ff:this.instances).indexOf(e);(this.canUseDOM?ff:this.instances).splice(t,1)}}});this.context=e,this.canUseDOM=t||!1,t||(e.helmet=V0({baseTag:[],bodyAttributes:{},encodeSpecialCharacters:!0,htmlAttributes:{},linkTags:[],metaTags:[],noscriptTags:[],scriptTags:[],styleTags:[],title:"",titleAttributes:{}}))}},KU={},DI=Ge.createContext(KU),Za,AI=(Za=class extends p.Component{constructor(n){super(n);Qr(this,"helmetData");this.helmetData=new z0(this.props.context||{},Za.canUseDOM)}render(){return Ge.createElement(DI.Provider,{value:this.helmetData.value},this.props.children)}},Qr(Za,"canUseDOM",MI),Za),Ks=(e,t)=>{const n=document.head||document.querySelector("head"),r=n.querySelectorAll(`${e}[${ur}]`),o=[].slice.call(r),i=[];let s;return t&&t.length&&t.forEach(a=>{const l=document.createElement(e);for(const c in a)if(Object.prototype.hasOwnProperty.call(a,c))if(c==="innerHTML")l.innerHTML=a.innerHTML;else if(c==="cssText")l.styleSheet?l.styleSheet.cssText=a.cssText:l.appendChild(document.createTextNode(a.cssText));else{const u=c,d=typeof a[u]>"u"?"":a[u];l.setAttribute(c,d)}l.setAttribute(ur,"true"),o.some((c,u)=>(s=u,l.isEqualNode(c)))?o.splice(s,1):i.push(l)}),o.forEach(a=>{var l;return(l=a.parentNode)==null?void 0:l.removeChild(a)}),i.forEach(a=>n.appendChild(a)),{oldTags:o,newTags:i}},B0=(e,t)=>{const n=document.getElementsByTagName(e)[0];if(!n)return;const r=n.getAttribute(ur),o=r?r.split(","):[],i=[...o],s=Object.keys(t);for(const a of s){const l=t[a]||"";n.getAttribute(a)!==l&&n.setAttribute(a,l),o.indexOf(a)===-1&&o.push(a);const c=i.indexOf(a);c!==-1&&i.splice(c,1)}for(let a=i.length-1;a>=0;a-=1)n.removeAttribute(i[a]);o.length===i.length?n.removeAttribute(ur):n.getAttribute(ur)!==s.join(",")&&n.setAttribute(ur,s.join(","))},YU=(e,t)=>{typeof e<"u"&&document.title!==e&&(document.title=PI(e)),B0("title",t)},cE=(e,t)=>{const{baseTag:n,bodyAttributes:r,htmlAttributes:o,linkTags:i,metaTags:s,noscriptTags:a,onChangeClientState:l,scriptTags:c,styleTags:u,title:d,titleAttributes:f}=e;B0("body",r),B0("html",o),YU(d,f);const h={baseTag:Ks("base",n),linkTags:Ks("link",i),metaTags:Ks("meta",s),noscriptTags:Ks("noscript",a),scriptTags:Ks("script",c),styleTags:Ks("style",u)},m={},v={};Object.keys(h).forEach(S=>{const{newTags:y,oldTags:b}=h[S];y.length&&(m[S]=y),b.length&&(v[S]=h[S].oldTags)}),t&&t(),l(e,m,v)},uc=null,QU=e=>{uc&&cancelAnimationFrame(uc),e.defer?uc=requestAnimationFrame(()=>{cE(e,()=>{uc=null})}):(cE(e),uc=null)},XU=QU,uE=class extends p.Component{constructor(){super(...arguments);Qr(this,"rendered",!1)}shouldComponentUpdate(t){return!NU(t,this.props)}componentDidUpdate(){this.emitChange()}componentWillUnmount(){const{helmetInstances:t}=this.props.context;t.remove(this),this.emitChange()}emitChange(){const{helmetInstances:t,setHelmet:n}=this.props.context;let r=null;const o=VU(t.get().map(i=>{const s={...i.props};return delete s.context,s}));AI.canUseDOM?XU(o):V0&&(r=V0(o)),n(r)}init(){if(this.rendered)return;this.rendered=!0;const{helmetInstances:t}=this.props.context;t.add(this),this.emitChange()}render(){return this.init(),null}},gy,ZU=(gy=class extends p.Component{shouldComponentUpdate(e){return!IU(lE(this.props,"helmetData"),lE(e,"helmetData"))}mapNestedChildrenToProps(e,t){if(!t)return null;switch(e.type){case"script":case"noscript":return{innerHTML:t};case"style":return{cssText:t};default:throw new Error(`<${e.type} /> elements are self-closing and can not contain children. Refer to our API for more information.`)}}flattenArrayTypeChildren(e,t,n,r){return{...t,[e.type]:[...t[e.type]||[],{...n,...this.mapNestedChildrenToProps(e,r)}]}}mapObjectTypeChildren(e,t,n,r){switch(e.type){case"title":return{...t,[e.type]:r,titleAttributes:{...n}};case"body":return{...t,bodyAttributes:{...n}};case"html":return{...t,htmlAttributes:{...n}};default:return{...t,[e.type]:{...n}}}}mapArrayTypeChildrenToProps(e,t){let n={...t};return Object.keys(e).forEach(r=>{n={...n,[r]:e[r]}}),n}warnOnInvalidChildren(e,t){return sE(aE.some(n=>e.type===n),typeof e.type=="function"?"You may be attempting to nest components within each other, which is not allowed. Refer to our API for more information.":`Only elements types ${aE.join(", ")} are allowed. Helmet does not support rendering <${e.type}> elements. Refer to our API for more information.`),sE(!t||typeof t=="string"||Array.isArray(t)&&!t.some(n=>typeof n!="string"),`Helmet expects a string as a child of <${e.type}>. Did you forget to wrap your children in braces? ( <${e.type}>{\`\`} ) Refer to our API for more information.`),!0}mapChildrenToProps(e,t){let n={};return Ge.Children.forEach(e,r=>{if(!r||!r.props)return;const{children:o,...i}=r.props,s=Object.keys(i).reduce((l,c)=>(l[MU[c]||c]=i[c],l),{});let{type:a}=r;switch(typeof a=="symbol"?a=a.toString():this.warnOnInvalidChildren(r,o),a){case"Symbol(react.fragment)":t=this.mapChildrenToProps(o,t);break;case"link":case"meta":case"noscript":case"script":case"style":n=this.flattenArrayTypeChildren(r,n,s,o);break;default:t=this.mapObjectTypeChildren(r,t,s,o);break}}),this.mapArrayTypeChildrenToProps(n,t)}render(){const{children:e,...t}=this.props;let n={...t},{helmetData:r}=t;if(e&&(n=this.mapChildrenToProps(e,n)),r&&!(r instanceof z0)){const o=r;r=new z0(o.context,!0),delete n.helmetData}return r?Ge.createElement(uE,{...n,context:r.value}):Ge.createElement(DI.Consumer,null,o=>Ge.createElement(uE,{...n,context:o}))}},Qr(gy,"defaultProps",{defer:!0,encodeSpecialCharacters:!0,prioritizeSeoTags:!1}),gy),H0=function(e,t){return H0=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(n,r){n.__proto__=r}||function(n,r){for(var o in r)Object.prototype.hasOwnProperty.call(r,o)&&(n[o]=r[o])},H0(e,t)};function JU(e,t){if(typeof t!="function"&&t!==null)throw new TypeError("Class extends value "+String(t)+" is not a constructor or null");H0(e,t);function n(){this.constructor=e}e.prototype=t===null?Object.create(t):(n.prototype=t.prototype,new n)}var wt=function(){return wt=Object.assign||function(t){for(var n,r=1,o=arguments.length;r0&&i[i.length-1])&&(c[0]===6||c[0]===2)){n=0;continue}if(c[0]===3&&(!i||c[1]>i[0]&&c[1]0&&m[m.length-1])||x[0]!==6&&x[0]!==2)){S=0;continue}if(x[0]===3&&(!m||x[1]>m[0]&&x[1]0?setTimeout(h,w):h(null)}}window.addEventListener("storage",y),u.addToWaiting(y);var b=setTimeout(y,Math.max(0,d-Date.now()))})];case 1:return f.sent(),[2]}})})},u.addToWaiting=function(d){this.removeFromWaiting(d),u.waiters!==void 0&&u.waiters.push(d)},u.removeFromWaiting=function(d){u.waiters!==void 0&&(u.waiters=u.waiters.filter(function(f){return f!==d}))},u.notifyWaiters=function(){u.waiters!==void 0&&u.waiters.slice().forEach(function(d){return d()})},u.prototype.releaseLock=function(d){return n(this,void 0,void 0,function(){return r(this,function(f){switch(f.label){case 0:return[4,this.releaseLock__private__(d)];case 1:return[2,f.sent()]}})})},u.prototype.releaseLock__private__=function(d){return n(this,void 0,void 0,function(){var f,h,m,v;return r(this,function(S){switch(S.label){case 0:return f=this.storageHandler===void 0?s:this.storageHandler,h=i+"-"+d,(m=f.getItemSync(h))===null?[2]:(v=JSON.parse(m)).id!==this.id?[3,2]:[4,Yi.default().lock(v.iat)];case 1:S.sent(),this.acquiredIatSet.delete(v.iat),f.removeItemSync(h),Yi.default().unlock(v.iat),u.notifyWaiters(),S.label=2;case 2:return[2]}})})},u.lockCorrector=function(d){for(var f=Date.now()-5e3,h=d,m=[],v=0;;){var S=h.keySync(v);if(S===null)break;m.push(S),v++}for(var y=!1,b=0;bDate.now();let bn=class U0 extends Error{constructor(t,n){super(n),this.error=t,this.error_description=n,Object.setPrototypeOf(this,U0.prototype)}static fromPayload({error:t,error_description:n}){return new U0(t,n)}},rW=class LI extends bn{constructor(t,n,r,o=null){super(t,n),this.state=r,this.appState=o,Object.setPrototypeOf(this,LI.prototype)}},W0=class VI extends bn{constructor(){super("timeout","Timeout"),Object.setPrototypeOf(this,VI.prototype)}},oW=class zI extends W0{constructor(t){super(),this.popup=t,Object.setPrototypeOf(this,zI.prototype)}},iW=class BI extends bn{constructor(t){super("cancelled","Popup closed"),this.popup=t,Object.setPrototypeOf(this,BI.prototype)}},sW=class HI extends bn{constructor(t,n,r){super(t,n),this.mfa_token=r,Object.setPrototypeOf(this,HI.prototype)}},UI=class WI extends bn{constructor(t,n){super("missing_refresh_token",`Missing Refresh Token (audience: '${dE(t,["default"])}', scope: '${dE(n)}')`),this.audience=t,this.scope=n,Object.setPrototypeOf(this,WI.prototype)}};function dE(e,t=[]){return e&&!t.includes(e)?e:""}const eh=()=>window.crypto,av=()=>{const e="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_~.";let t="";return Array.from(eh().getRandomValues(new Uint8Array(43))).forEach(n=>t+=e[n%e.length]),t},fE=e=>btoa(e),G0=e=>{var{clientId:t}=e,n=Mr(e,["clientId"]);return new URLSearchParams((r=>Object.keys(r).filter(o=>r[o]!==void 0).reduce((o,i)=>Object.assign(Object.assign({},o),{[i]:r[i]}),{}))(Object.assign({client_id:t},n))).toString()},hE=e=>(t=>decodeURIComponent(atob(t).split("").map(n=>"%"+("00"+n.charCodeAt(0).toString(16)).slice(-2)).join("")))(e.replace(/_/g,"/").replace(/-/g,"+")),aW=async(e,t)=>{const n=await fetch(e,t);return{ok:n.ok,json:await n.json()}},lW=async(e,t,n)=>{const r=new AbortController;let o;return t.signal=r.signal,Promise.race([aW(e,t),new Promise((i,s)=>{o=setTimeout(()=>{r.abort(),s(new Error("Timeout when executing 'fetch'"))},n)})]).finally(()=>{clearTimeout(o)})},cW=async(e,t,n,r,o,i,s)=>{return a={auth:{audience:t,scope:n},timeout:o,fetchUrl:e,fetchOptions:r,useFormData:s},l=i,new Promise(function(c,u){const d=new MessageChannel;d.port1.onmessage=function(f){f.data.error?u(new Error(f.data.error)):c(f.data),d.port1.close()},l.postMessage(a,[d.port2])});var a,l},uW=async(e,t,n,r,o,i,s=1e4)=>o?cW(e,t,n,r,s,o,i):lW(e,r,s);async function dW(e,t){var{baseUrl:n,timeout:r,audience:o,scope:i,auth0Client:s,useFormData:a}=e,l=Mr(e,["baseUrl","timeout","audience","scope","auth0Client","useFormData"]);const c=a?G0(l):JSON.stringify(l);return await async function(u,d,f,h,m,v,S){let y,b=null;for(let k=0;k<3;k++)try{y=await uW(u,f,h,m,v,S,d),b=null;break}catch(T){b=T}if(b)throw b;const w=y.json,{error:x,error_description:_}=w,E=Mr(w,["error","error_description"]),{ok:C}=y;if(!C){const k=_||`HTTP error. Unable to fetch ${u}`;throw x==="mfa_required"?new sW(x,k,E.mfa_token):x==="missing_refresh_token"?new UI(f,h):new bn(x||"request_error",k)}return E}(`${n}/oauth/token`,r,o||"default",i,{method:"POST",body:c,headers:{"Content-Type":a?"application/x-www-form-urlencoded":"application/json","Auth0-Client":btoa(JSON.stringify(s||FI))}},t,a)}const hf=(...e)=>{return(t=e.filter(Boolean).join(" ").trim().split(/\s+/),Array.from(new Set(t))).join(" ");var t};class Lr{constructor(t,n="@@auth0spajs@@",r){this.prefix=n,this.suffix=r,this.clientId=t.clientId,this.scope=t.scope,this.audience=t.audience}toKey(){return[this.prefix,this.clientId,this.audience,this.scope,this.suffix].filter(Boolean).join("::")}static fromKey(t){const[n,r,o,i]=t.split("::");return new Lr({clientId:r,scope:i,audience:o},n)}static fromCacheEntry(t){const{scope:n,audience:r,client_id:o}=t;return new Lr({scope:n,audience:r,clientId:o})}}let fW=class{set(t,n){localStorage.setItem(t,JSON.stringify(n))}get(t){const n=window.localStorage.getItem(t);if(n)try{return JSON.parse(n)}catch{return}}remove(t){localStorage.removeItem(t)}allKeys(){return Object.keys(window.localStorage).filter(t=>t.startsWith("@@auth0spajs@@"))}},GI=class{constructor(){this.enclosedCache=function(){let t={};return{set(n,r){t[n]=r},get(n){const r=t[n];if(r)return r},remove(n){delete t[n]},allKeys:()=>Object.keys(t)}}()}},hW=class{constructor(t,n,r){this.cache=t,this.keyManifest=n,this.nowProvider=r||jI}async setIdToken(t,n,r){var o;const i=this.getIdTokenCacheKey(t);await this.cache.set(i,{id_token:n,decodedToken:r}),await((o=this.keyManifest)===null||o===void 0?void 0:o.add(i))}async getIdToken(t){const n=await this.cache.get(this.getIdTokenCacheKey(t.clientId));if(!n&&t.scope&&t.audience){const r=await this.get(t);return!r||!r.id_token||!r.decodedToken?void 0:{id_token:r.id_token,decodedToken:r.decodedToken}}if(n)return{id_token:n.id_token,decodedToken:n.decodedToken}}async get(t,n=0){var r;let o=await this.cache.get(t.toKey());if(!o){const a=await this.getCacheKeys();if(!a)return;const l=this.matchExistingCacheKey(t,a);l&&(o=await this.cache.get(l))}if(!o)return;const i=await this.nowProvider(),s=Math.floor(i/1e3);return o.expiresAt-n!t||o.includes(t)).reduce(async(o,i)=>{await o,await this.cache.remove(i)},Promise.resolve()),await((n=this.keyManifest)===null||n===void 0?void 0:n.clear()))}async wrapCacheEntry(t){const n=await this.nowProvider();return{body:t,expiresAt:Math.floor(n/1e3)+t.expires_in}}async getCacheKeys(){var t;return this.keyManifest?(t=await this.keyManifest.get())===null||t===void 0?void 0:t.keys:this.cache.allKeys?this.cache.allKeys():void 0}getIdTokenCacheKey(t){return new Lr({clientId:t},"@@auth0spajs@@","@@user@@").toKey()}matchExistingCacheKey(t,n){return n.filter(r=>{var o;const i=Lr.fromKey(r),s=new Set(i.scope&&i.scope.split(" ")),a=((o=t.scope)===null||o===void 0?void 0:o.split(" "))||[],l=i.scope&&a.reduce((c,u)=>c&&s.has(u),!0);return i.prefix==="@@auth0spajs@@"&&i.clientId===t.clientId&&i.audience===t.audience&&l})[0]}};class pW{constructor(t,n,r){this.storage=t,this.clientId=n,this.cookieDomain=r,this.storageKey=`a0.spajs.txs.${this.clientId}`}create(t){this.storage.save(this.storageKey,t,{daysUntilExpire:1,cookieDomain:this.cookieDomain})}get(){return this.storage.get(this.storageKey)}remove(){this.storage.remove(this.storageKey,{cookieDomain:this.cookieDomain})}}const dc=e=>typeof e=="number",mW=["iss","aud","exp","nbf","iat","jti","azp","nonce","auth_time","at_hash","c_hash","acr","amr","sub_jwk","cnf","sip_from_tag","sip_date","sip_callid","sip_cseq_num","sip_via_branch","orig","dest","mky","events","toe","txn","rph","sid","vot","vtm"],gW=e=>{if(!e.id_token)throw new Error("ID token is required but missing");const t=(i=>{const s=i.split("."),[a,l,c]=s;if(s.length!==3||!a||!l||!c)throw new Error("ID token could not be decoded");const u=JSON.parse(hE(l)),d={__raw:i},f={};return Object.keys(u).forEach(h=>{d[h]=u[h],mW.includes(h)||(f[h]=u[h])}),{encoded:{header:a,payload:l,signature:c},header:JSON.parse(hE(a)),claims:d,user:f}})(e.id_token);if(!t.claims.iss)throw new Error("Issuer (iss) claim must be a string present in the ID token");if(t.claims.iss!==e.iss)throw new Error(`Issuer (iss) claim mismatch in the ID token; expected "${e.iss}", found "${t.claims.iss}"`);if(!t.user.sub)throw new Error("Subject (sub) claim must be a string present in the ID token");if(t.header.alg!=="RS256")throw new Error(`Signature algorithm of "${t.header.alg}" is not supported. Expected the ID token to be signed with "RS256".`);if(!t.claims.aud||typeof t.claims.aud!="string"&&!Array.isArray(t.claims.aud))throw new Error("Audience (aud) claim must be a string or array of strings present in the ID token");if(Array.isArray(t.claims.aud)){if(!t.claims.aud.includes(e.aud))throw new Error(`Audience (aud) claim mismatch in the ID token; expected "${e.aud}" but was not one of "${t.claims.aud.join(", ")}"`);if(t.claims.aud.length>1){if(!t.claims.azp)throw new Error("Authorized Party (azp) claim must be a string present in the ID token when Audience (aud) claim has multiple values");if(t.claims.azp!==e.aud)throw new Error(`Authorized Party (azp) claim mismatch in the ID token; expected "${e.aud}", found "${t.claims.azp}"`)}}else if(t.claims.aud!==e.aud)throw new Error(`Audience (aud) claim mismatch in the ID token; expected "${e.aud}" but found "${t.claims.aud}"`);if(e.nonce){if(!t.claims.nonce)throw new Error("Nonce (nonce) claim must be a string present in the ID token");if(t.claims.nonce!==e.nonce)throw new Error(`Nonce (nonce) claim mismatch in the ID token; expected "${e.nonce}", found "${t.claims.nonce}"`)}if(e.max_age&&!dc(t.claims.auth_time))throw new Error("Authentication Time (auth_time) claim must be a number present in the ID token when Max Age (max_age) is specified");if(t.claims.exp==null||!dc(t.claims.exp))throw new Error("Expiration Time (exp) claim must be a number present in the ID token");if(!dc(t.claims.iat))throw new Error("Issued At (iat) claim must be a number present in the ID token");const n=e.leeway||60,r=new Date(e.now||Date.now()),o=new Date(0);if(o.setUTCSeconds(t.claims.exp+n),r>o)throw new Error(`Expiration Time (exp) claim error in the ID token; current time (${r}) is after expiration time (${o})`);if(t.claims.nbf!=null&&dc(t.claims.nbf)){const i=new Date(0);if(i.setUTCSeconds(t.claims.nbf-n),ri)throw new Error(`Authentication Time (auth_time) claim in the ID token indicates that too much time has passed since the last end-user authentication. Current time (${r}) is after last auth at ${i}`)}if(e.organization){const i=e.organization.trim();if(i.startsWith("org_")){const s=i;if(!t.claims.org_id)throw new Error("Organization ID (org_id) claim must be a string present in the ID token");if(s!==t.claims.org_id)throw new Error(`Organization ID (org_id) claim mismatch in the ID token; expected "${s}", found "${t.claims.org_id}"`)}else{const s=i.toLowerCase();if(!t.claims.org_name)throw new Error("Organization Name (org_name) claim must be a string present in the ID token");if(s!==t.claims.org_name)throw new Error(`Organization Name (org_name) claim mismatch in the ID token; expected "${s}", found "${t.claims.org_name}"`)}}return t};var cs=Vw(function(e,t){var n=rs&&rs.__assign||function(){return n=Object.assign||function(l){for(var c,u=1,d=arguments.length;u"u")return;const t=sessionStorage.getItem(e);return t!=null?JSON.parse(t):void 0},save(e,t){sessionStorage.setItem(e,JSON.stringify(t))},remove(e){sessionStorage.removeItem(e)}};function wW(e,t,n){var r=t===void 0?null:t,o=function(l,c){var u=atob(l);if(c){for(var d=new Uint8Array(u.length),f=0,h=u.length;f0?await this.cache.set(this.manifestKey,{keys:[...r]}):await this.cache.remove(this.manifestKey)}}get(){return this.cache.get(this.manifestKey)}clear(){return this.cache.remove(this.manifestKey)}createManifestKeyFrom(t){return`@@auth0spajs@@::${t}`}}const _W={memory:()=>new GI().enclosedCache,localstorage:()=>new fW},vE=e=>_W[e],yE=e=>{const{openUrl:t,onRedirect:n}=e,r=Mr(e,["openUrl","onRedirect"]);return Object.assign(Object.assign({},r),{openUrl:t===!1||t?t:n})},uv=new tW;class EW{constructor(t){let n,r;if(this.userCache=new GI().enclosedCache,this.defaultOptions={authorizationParams:{scope:"openid profile email"},useRefreshTokensFallback:!1,useFormData:!0},this._releaseLockOnPageHide=async()=>{await uv.releaseLock("auth0.lock.getTokenSilently"),window.removeEventListener("pagehide",this._releaseLockOnPageHide)},this.options=Object.assign(Object.assign(Object.assign({},this.defaultOptions),t),{authorizationParams:Object.assign(Object.assign({},this.defaultOptions.authorizationParams),t.authorizationParams)}),typeof window<"u"&&(()=>{if(!eh())throw new Error("For security reasons, `window.crypto` is required to run `auth0-spa-js`.");if(eh().subtle===void 0)throw new Error(` + auth0-spa-js must run on a secure origin. See https://github.com/auth0/auth0-spa-js/blob/main/FAQ.md#why-do-i-get-auth0-spa-js-must-run-on-a-secure-origin for more information. + `)})(),t.cache&&t.cacheLocation&&console.warn("Both `cache` and `cacheLocation` options have been specified in the Auth0Client configuration; ignoring `cacheLocation` and using `cache`."),t.cache)r=t.cache;else{if(n=t.cacheLocation||"memory",!vE(n))throw new Error(`Invalid cache location "${n}"`);r=vE(n)()}this.httpTimeoutMs=t.httpTimeoutInSeconds?1e3*t.httpTimeoutInSeconds:1e4,this.cookieStorage=t.legacySameSiteCookie===!1?ra:yW,this.orgHintCookieName=`auth0.${this.options.clientId}.organization_hint`,this.isAuthenticatedCookieName=(s=>`auth0.${s}.is.authenticated`)(this.options.clientId),this.sessionCheckExpiryDays=t.sessionCheckExpiryDays||1;const o=t.useCookiesForTransactions?this.cookieStorage:bW;var i;this.scope=hf("openid",this.options.authorizationParams.scope,this.options.useRefreshTokens?"offline_access":""),this.transactionManager=new pW(o,this.options.clientId,this.options.cookieDomain),this.nowProvider=this.options.nowProvider||jI,this.cacheManager=new hW(r,r.allKeys?void 0:new xW(r,this.options.clientId),this.nowProvider),this.domainUrl=(i=this.options.domain,/^https?:\/\//.test(i)?i:`https://${i}`),this.tokenIssuer=((s,a)=>s?s.startsWith("https://")?s:`https://${s}/`:`${a}/`)(this.options.issuer,this.domainUrl),typeof window<"u"&&window.Worker&&this.options.useRefreshTokens&&n==="memory"&&(this.options.workerUrl?this.worker=new Worker(this.options.workerUrl):this.worker=new SW)}_url(t){const n=encodeURIComponent(btoa(JSON.stringify(this.options.auth0Client||FI)));return`${this.domainUrl}${t}&auth0Client=${n}`}_authorizeUrl(t){return this._url(`/authorize?${G0(t)}`)}async _verifyIdToken(t,n,r){const o=await this.nowProvider();return gW({iss:this.tokenIssuer,aud:this.options.clientId,id_token:t,nonce:n,organization:r,leeway:this.options.leeway,max_age:(i=this.options.authorizationParams.max_age,typeof i!="string"?i:parseInt(i,10)||void 0),now:o});var i}_processOrgHint(t){t?this.cookieStorage.save(this.orgHintCookieName,t,{daysUntilExpire:this.sessionCheckExpiryDays,cookieDomain:this.options.cookieDomain}):this.cookieStorage.remove(this.orgHintCookieName,{cookieDomain:this.options.cookieDomain})}async _prepareAuthorizeUrl(t,n,r){const o=fE(av()),i=fE(av()),s=av(),a=(u=>{const d=new Uint8Array(u);return(f=>{const h={"+":"-","/":"_","=":""};return f.replace(/[+/=]/g,m=>h[m])})(window.btoa(String.fromCharCode(...Array.from(d))))})(await(async u=>await eh().subtle.digest({name:"SHA-256"},new TextEncoder().encode(u)))(s)),l=((u,d,f,h,m,v,S,y)=>Object.assign(Object.assign(Object.assign({client_id:u.clientId},u.authorizationParams),f),{scope:hf(d,f.scope),response_type:"code",response_mode:y||"query",state:h,nonce:m,redirect_uri:S||u.authorizationParams.redirect_uri,code_challenge:v,code_challenge_method:"S256"}))(this.options,this.scope,t,o,i,a,t.redirect_uri||this.options.authorizationParams.redirect_uri||r,n==null?void 0:n.response_mode),c=this._authorizeUrl(l);return{nonce:i,code_verifier:s,scope:l.scope,audience:l.audience||"default",redirect_uri:l.redirect_uri,state:o,url:c}}async loginWithPopup(t,n){var r;if(t=t||{},!(n=n||{}).popup&&(n.popup=(a=>{const l=window.screenX+(window.innerWidth-400)/2,c=window.screenY+(window.innerHeight-600)/2;return window.open(a,"auth0:authorize:popup",`left=${l},top=${c},width=400,height=600,resizable,scrollbars=yes,status=1`)})(""),!n.popup))throw new Error("Unable to open a popup for loginWithPopup - window.open returned `null`");const o=await this._prepareAuthorizeUrl(t.authorizationParams||{},{response_mode:"web_message"},window.location.origin);n.popup.location.href=o.url;const i=await(a=>new Promise((l,c)=>{let u;const d=setInterval(()=>{a.popup&&a.popup.closed&&(clearInterval(d),clearTimeout(f),window.removeEventListener("message",u,!1),c(new iW(a.popup)))},1e3),f=setTimeout(()=>{clearInterval(d),c(new oW(a.popup)),window.removeEventListener("message",u,!1)},1e3*(a.timeoutInSeconds||60));u=function(h){if(h.data&&h.data.type==="authorization_response"){if(clearTimeout(f),clearInterval(d),window.removeEventListener("message",u,!1),a.popup.close(),h.data.response.error)return c(bn.fromPayload(h.data.response));l(h.data.response)}},window.addEventListener("message",u)}))(Object.assign(Object.assign({},n),{timeoutInSeconds:n.timeoutInSeconds||this.options.authorizeTimeoutInSeconds||60}));if(o.state!==i.state)throw new bn("state_mismatch","Invalid state");const s=((r=t.authorizationParams)===null||r===void 0?void 0:r.organization)||this.options.authorizationParams.organization;await this._requestToken({audience:o.audience,scope:o.scope,code_verifier:o.code_verifier,grant_type:"authorization_code",code:i.code,redirect_uri:o.redirect_uri},{nonceIn:o.nonce,organization:s})}async getUser(){var t;const n=await this._getIdTokenFromCache();return(t=n==null?void 0:n.decodedToken)===null||t===void 0?void 0:t.user}async getIdTokenClaims(){var t;const n=await this._getIdTokenFromCache();return(t=n==null?void 0:n.decodedToken)===null||t===void 0?void 0:t.claims}async loginWithRedirect(t={}){var n;const r=yE(t),{openUrl:o,fragment:i,appState:s}=r,a=Mr(r,["openUrl","fragment","appState"]),l=((n=a.authorizationParams)===null||n===void 0?void 0:n.organization)||this.options.authorizationParams.organization,c=await this._prepareAuthorizeUrl(a.authorizationParams||{}),{url:u}=c,d=Mr(c,["url"]);this.transactionManager.create(Object.assign(Object.assign(Object.assign({},d),{appState:s}),l&&{organization:l}));const f=i?`${u}#${i}`:u;o?await o(f):window.location.assign(f)}async handleRedirectCallback(t=window.location.href){const n=t.split("?").slice(1);if(n.length===0)throw new Error("There are no query params available for parsing.");const{state:r,code:o,error:i,error_description:s}=(d=>{d.indexOf("#")>-1&&(d=d.substring(0,d.indexOf("#")));const f=new URLSearchParams(d);return{state:f.get("state"),code:f.get("code")||void 0,error:f.get("error")||void 0,error_description:f.get("error_description")||void 0}})(n.join("")),a=this.transactionManager.get();if(!a)throw new bn("missing_transaction","Invalid state");if(this.transactionManager.remove(),i)throw new rW(i,s||i,r,a.appState);if(!a.code_verifier||a.state&&a.state!==r)throw new bn("state_mismatch","Invalid state");const l=a.organization,c=a.nonce,u=a.redirect_uri;return await this._requestToken(Object.assign({audience:a.audience,scope:a.scope,code_verifier:a.code_verifier,grant_type:"authorization_code",code:o},u?{redirect_uri:u}:{}),{nonceIn:c,organization:l}),{appState:a.appState}}async checkSession(t){if(!this.cookieStorage.get(this.isAuthenticatedCookieName)){if(!this.cookieStorage.get("auth0.is.authenticated"))return;this.cookieStorage.save(this.isAuthenticatedCookieName,!0,{daysUntilExpire:this.sessionCheckExpiryDays,cookieDomain:this.options.cookieDomain}),this.cookieStorage.remove("auth0.is.authenticated")}try{await this.getTokenSilently(t)}catch{}}async getTokenSilently(t={}){var n;const r=Object.assign(Object.assign({cacheMode:"on"},t),{authorizationParams:Object.assign(Object.assign(Object.assign({},this.options.authorizationParams),t.authorizationParams),{scope:hf(this.scope,(n=t.authorizationParams)===null||n===void 0?void 0:n.scope)})}),o=await((i,s)=>{let a=cv[s];return a||(a=i().finally(()=>{delete cv[s],a=null}),cv[s]=a),a})(()=>this._getTokenSilently(r),`${this.options.clientId}::${r.authorizationParams.audience}::${r.authorizationParams.scope}`);return t.detailedResponse?o:o==null?void 0:o.access_token}async _getTokenSilently(t){const{cacheMode:n}=t,r=Mr(t,["cacheMode"]);if(n!=="off"){const o=await this._getEntryFromCache({scope:r.authorizationParams.scope,audience:r.authorizationParams.audience||"default",clientId:this.options.clientId});if(o)return o}if(n!=="cache-only"){if(!await(async(o,i=3)=>{for(let s=0;suv.acquireLock("auth0.lock.getTokenSilently",5e3),10))throw new W0;try{if(window.addEventListener("pagehide",this._releaseLockOnPageHide),n!=="off"){const c=await this._getEntryFromCache({scope:r.authorizationParams.scope,audience:r.authorizationParams.audience||"default",clientId:this.options.clientId});if(c)return c}const o=this.options.useRefreshTokens?await this._getTokenUsingRefreshToken(r):await this._getTokenFromIFrame(r),{id_token:i,access_token:s,oauthTokenScope:a,expires_in:l}=o;return Object.assign(Object.assign({id_token:i,access_token:s},a?{scope:a}:null),{expires_in:l})}finally{await uv.releaseLock("auth0.lock.getTokenSilently"),window.removeEventListener("pagehide",this._releaseLockOnPageHide)}}}async getTokenWithPopup(t={},n={}){var r;const o=Object.assign(Object.assign({},t),{authorizationParams:Object.assign(Object.assign(Object.assign({},this.options.authorizationParams),t.authorizationParams),{scope:hf(this.scope,(r=t.authorizationParams)===null||r===void 0?void 0:r.scope)})});return n=Object.assign(Object.assign({},nW),n),await this.loginWithPopup(o,n),(await this.cacheManager.get(new Lr({scope:o.authorizationParams.scope,audience:o.authorizationParams.audience||"default",clientId:this.options.clientId}))).access_token}async isAuthenticated(){return!!await this.getUser()}_buildLogoutUrl(t){t.clientId!==null?t.clientId=t.clientId||this.options.clientId:delete t.clientId;const n=t.logoutParams||{},{federated:r}=n,o=Mr(n,["federated"]),i=r?"&federated":"";return this._url(`/v2/logout?${G0(Object.assign({clientId:t.clientId},o))}`)+i}async logout(t={}){const n=yE(t),{openUrl:r}=n,o=Mr(n,["openUrl"]);t.clientId===null?await this.cacheManager.clear():await this.cacheManager.clear(t.clientId||this.options.clientId),this.cookieStorage.remove(this.orgHintCookieName,{cookieDomain:this.options.cookieDomain}),this.cookieStorage.remove(this.isAuthenticatedCookieName,{cookieDomain:this.options.cookieDomain}),this.userCache.remove("@@user@@");const i=this._buildLogoutUrl(o);r?await r(i):r!==!1&&window.location.assign(i)}async _getTokenFromIFrame(t){const n=Object.assign(Object.assign({},t.authorizationParams),{prompt:"none"}),r=this.cookieStorage.get(this.orgHintCookieName);r&&!n.organization&&(n.organization=r);const{url:o,state:i,nonce:s,code_verifier:a,redirect_uri:l,scope:c,audience:u}=await this._prepareAuthorizeUrl(n,{response_mode:"web_message"},window.location.origin);try{if(window.crossOriginIsolated)throw new bn("login_required","The application is running in a Cross-Origin Isolated context, silently retrieving a token without refresh token is not possible.");const d=t.timeoutInSeconds||this.options.authorizeTimeoutInSeconds,f=await((m,v,S=60)=>new Promise((y,b)=>{const w=window.document.createElement("iframe");w.setAttribute("width","0"),w.setAttribute("height","0"),w.style.display="none";const x=()=>{window.document.body.contains(w)&&(window.document.body.removeChild(w),window.removeEventListener("message",_,!1))};let _;const E=setTimeout(()=>{b(new W0),x()},1e3*S);_=function(C){if(C.origin!=v||!C.data||C.data.type!=="authorization_response")return;const k=C.source;k&&k.close(),C.data.response.error?b(bn.fromPayload(C.data.response)):y(C.data.response),clearTimeout(E),window.removeEventListener("message",_,!1),setTimeout(x,2e3)},window.addEventListener("message",_,!1),window.document.body.appendChild(w),w.setAttribute("src",m)}))(o,this.domainUrl,d);if(i!==f.state)throw new bn("state_mismatch","Invalid state");const h=await this._requestToken(Object.assign(Object.assign({},t.authorizationParams),{code_verifier:a,code:f.code,grant_type:"authorization_code",redirect_uri:l,timeout:t.authorizationParams.timeout||this.httpTimeoutMs}),{nonceIn:s,organization:n.organization});return Object.assign(Object.assign({},h),{scope:c,oauthTokenScope:h.scope,audience:u})}catch(d){throw d.error==="login_required"&&this.logout({openUrl:!1}),d}}async _getTokenUsingRefreshToken(t){const n=await this.cacheManager.get(new Lr({scope:t.authorizationParams.scope,audience:t.authorizationParams.audience||"default",clientId:this.options.clientId}));if(!(n&&n.refresh_token||this.worker)){if(this.options.useRefreshTokensFallback)return await this._getTokenFromIFrame(t);throw new UI(t.authorizationParams.audience||"default",t.authorizationParams.scope)}const r=t.authorizationParams.redirect_uri||this.options.authorizationParams.redirect_uri||window.location.origin,o=typeof t.timeoutInSeconds=="number"?1e3*t.timeoutInSeconds:null;try{const i=await this._requestToken(Object.assign(Object.assign(Object.assign({},t.authorizationParams),{grant_type:"refresh_token",refresh_token:n&&n.refresh_token,redirect_uri:r}),o&&{timeout:o}));return Object.assign(Object.assign({},i),{scope:t.authorizationParams.scope,oauthTokenScope:i.scope,audience:t.authorizationParams.audience||"default"})}catch(i){if((i.message.indexOf("Missing Refresh Token")>-1||i.message&&i.message.indexOf("invalid refresh token")>-1)&&this.options.useRefreshTokensFallback)return await this._getTokenFromIFrame(t);throw i}}async _saveEntryInCache(t){const{id_token:n,decodedToken:r}=t,o=Mr(t,["id_token","decodedToken"]);this.userCache.set("@@user@@",{id_token:n,decodedToken:r}),await this.cacheManager.setIdToken(this.options.clientId,t.id_token,t.decodedToken),await this.cacheManager.set(o)}async _getIdTokenFromCache(){const t=this.options.authorizationParams.audience||"default",n=await this.cacheManager.getIdToken(new Lr({clientId:this.options.clientId,audience:t,scope:this.scope})),r=this.userCache.get("@@user@@");return n&&n.id_token===(r==null?void 0:r.id_token)?r:(this.userCache.set("@@user@@",n),n)}async _getEntryFromCache({scope:t,audience:n,clientId:r}){const o=await this.cacheManager.get(new Lr({scope:t,audience:n,clientId:r}),60);if(o&&o.access_token){const{access_token:i,oauthTokenScope:s,expires_in:a}=o,l=await this._getIdTokenFromCache();return l&&Object.assign(Object.assign({id_token:l.id_token,access_token:i},s?{scope:s}:null),{expires_in:a})}}async _requestToken(t,n){const{nonceIn:r,organization:o}=n||{},i=await dW(Object.assign({baseUrl:this.domainUrl,client_id:this.options.clientId,auth0Client:this.options.auth0Client,useFormData:this.options.useFormData,timeout:this.httpTimeoutMs},t),this.worker),s=await this._verifyIdToken(i.id_token,r,o);return await this._saveEntryInCache(Object.assign(Object.assign(Object.assign(Object.assign({},i),{decodedToken:s,scope:t.scope,audience:t.audience||"default"}),i.scope?{oauthTokenScope:i.scope}:null),{client_id:this.options.clientId})),this.cookieStorage.save(this.isAuthenticatedCookieName,!0,{daysUntilExpire:this.sessionCheckExpiryDays,cookieDomain:this.options.cookieDomain}),this._processOrgHint(o||s.claims.org_id),Object.assign(Object.assign({},i),{decodedToken:s})}}var YI={isAuthenticated:!1,isLoading:!0},Xr=function(){throw new Error("You forgot to wrap your component in .")},CW=wt(wt({},YI),{buildAuthorizeUrl:Xr,buildLogoutUrl:Xr,getAccessTokenSilently:Xr,getAccessTokenWithPopup:Xr,getIdTokenClaims:Xr,loginWithRedirect:Xr,loginWithPopup:Xr,logout:Xr,handleRedirectCallback:Xr}),QI=p.createContext(CW),bE=function(e){JU(t,e);function t(n,r){var o=e.call(this,r||n)||this;return o.error=n,o.error_description=r,Object.setPrototypeOf(o,t.prototype),o}return t}(Error),kW=/[?&]code=[^&]+/,TW=/[?&]state=[^&]+/,RW=/[?&]error=[^&]+/,IW=function(e){return e===void 0&&(e=window.location.search),(kW.test(e)||RW.test(e))&&TW.test(e)},XI=function(e){return function(t){return t instanceof Error?t:t!==null&&typeof t=="object"&&"error"in t&&typeof t.error=="string"?"error_description"in t&&typeof t.error_description=="string"?new bE(t.error,t.error_description):new bE(t.error):new Error(e)}},wE=XI("Login failed"),dv=XI("Get access token failed"),ZI=function(e){var t;e!=null&&e.redirectUri&&(console.warn("Using `redirectUri` has been deprecated, please use `authorizationParams.redirect_uri` instead as `redirectUri` will be no longer supported in a future version"),e.authorizationParams=e.authorizationParams||{},e.authorizationParams.redirect_uri=e.redirectUri,delete e.redirectUri),!((t=e==null?void 0:e.authorizationParams)===null||t===void 0)&&t.redirectUri&&(console.warn("Using `authorizationParams.redirectUri` has been deprecated, please use `authorizationParams.redirect_uri` instead as `authorizationParams.redirectUri` will be removed in a future version"),e.authorizationParams.redirect_uri=e.authorizationParams.redirectUri,delete e.authorizationParams.redirectUri)},$W=function(e,t){switch(t.type){case"LOGIN_POPUP_STARTED":return wt(wt({},e),{isLoading:!0});case"LOGIN_POPUP_COMPLETE":case"INITIALISED":return wt(wt({},e),{isAuthenticated:!!t.user,user:t.user,isLoading:!1,error:void 0});case"HANDLE_REDIRECT_COMPLETE":case"GET_ACCESS_TOKEN_COMPLETE":return e.user===t.user?e:wt(wt({},e),{isAuthenticated:!!t.user,user:t.user});case"LOGOUT":return wt(wt({},e),{isAuthenticated:!1,user:void 0});case"ERROR":return wt(wt({},e),{isLoading:!1,error:t.error})}},PW=function(e){return ZI(e),wt(wt({},e),{auth0Client:{name:"auth0-react",version:"2.2.4"}})},OW=function(e){window.history.replaceState({},document.title,(e==null?void 0:e.returnTo)||window.location.pathname)},NW=function(e){var t=e.children,n=e.skipRedirectCallback,r=e.onRedirectCallback,o=r===void 0?OW:r,i=e.context,s=i===void 0?QI:i,a=eW(e,["children","skipRedirectCallback","onRedirectCallback","context"]),l=p.useState(function(){return new EW(PW(a))})[0],c=p.useReducer($W,YI),u=c[0],d=c[1],f=p.useRef(!1);p.useEffect(function(){f.current||(f.current=!0,function(){return Ys(void 0,void 0,void 0,function(){var _,E,C;return Qs(this,function(k){switch(k.label){case 0:return k.trys.push([0,7,,8]),_=void 0,IW()&&!n?[4,l.handleRedirectCallback()]:[3,3];case 1:return E=k.sent().appState,[4,l.getUser()];case 2:return _=k.sent(),o(E,_),[3,6];case 3:return[4,l.checkSession()];case 4:return k.sent(),[4,l.getUser()];case 5:_=k.sent(),k.label=6;case 6:return d({type:"INITIALISED",user:_}),[3,8];case 7:return C=k.sent(),d({type:"ERROR",error:wE(C)}),[3,8];case 8:return[2]}})})}())},[l,o,n]);var h=p.useCallback(function(_){return ZI(_),l.loginWithRedirect(_)},[l]),m=p.useCallback(function(_,E){return Ys(void 0,void 0,void 0,function(){var C,k;return Qs(this,function(T){switch(T.label){case 0:d({type:"LOGIN_POPUP_STARTED"}),T.label=1;case 1:return T.trys.push([1,3,,4]),[4,l.loginWithPopup(_,E)];case 2:return T.sent(),[3,4];case 3:return C=T.sent(),d({type:"ERROR",error:wE(C)}),[2];case 4:return[4,l.getUser()];case 5:return k=T.sent(),d({type:"LOGIN_POPUP_COMPLETE",user:k}),[2]}})})},[l]),v=p.useCallback(function(_){return _===void 0&&(_={}),Ys(void 0,void 0,void 0,function(){return Qs(this,function(E){switch(E.label){case 0:return[4,l.logout(_)];case 1:return E.sent(),(_.openUrl||_.openUrl===!1)&&d({type:"LOGOUT"}),[2]}})})},[l]),S=p.useCallback(function(_){return Ys(void 0,void 0,void 0,function(){var E,C,k,T;return Qs(this,function(R){switch(R.label){case 0:return R.trys.push([0,2,3,5]),[4,l.getTokenSilently(_)];case 1:return E=R.sent(),[3,5];case 2:throw C=R.sent(),dv(C);case 3:return k=d,T={type:"GET_ACCESS_TOKEN_COMPLETE"},[4,l.getUser()];case 4:return k.apply(void 0,[(T.user=R.sent(),T)]),[7];case 5:return[2,E]}})})},[l]),y=p.useCallback(function(_,E){return Ys(void 0,void 0,void 0,function(){var C,k,T,R;return Qs(this,function(D){switch(D.label){case 0:return D.trys.push([0,2,3,5]),[4,l.getTokenWithPopup(_,E)];case 1:return C=D.sent(),[3,5];case 2:throw k=D.sent(),dv(k);case 3:return T=d,R={type:"GET_ACCESS_TOKEN_COMPLETE"},[4,l.getUser()];case 4:return T.apply(void 0,[(R.user=D.sent(),R)]),[7];case 5:return[2,C]}})})},[l]),b=p.useCallback(function(){return l.getIdTokenClaims()},[l]),w=p.useCallback(function(_){return Ys(void 0,void 0,void 0,function(){var E,C,k;return Qs(this,function(T){switch(T.label){case 0:return T.trys.push([0,2,3,5]),[4,l.handleRedirectCallback(_)];case 1:return[2,T.sent()];case 2:throw E=T.sent(),dv(E);case 3:return C=d,k={type:"HANDLE_REDIRECT_COMPLETE"},[4,l.getUser()];case 4:return C.apply(void 0,[(k.user=T.sent(),k)]),[7];case 5:return[2]}})})},[l]),x=p.useMemo(function(){return wt(wt({},u),{getAccessTokenSilently:S,getAccessTokenWithPopup:y,getIdTokenClaims:b,loginWithRedirect:h,loginWithPopup:m,logout:v,handleRedirectCallback:w})},[u,S,y,b,h,m,v,w]);return Ge.createElement(s.Provider,{value:x},t)},Bi=function(e){return e===void 0&&(e=QI),p.useContext(e)};const SE="pushstate",xE="popstate",JI="beforeunload",e6=e=>(e.preventDefault(),e.returnValue=""),MW=()=>{removeEventListener(JI,e6,{capture:!0})};function t6(e){let t=e.getLocation(),n=new Set,r=[];const o=()=>{t=e.getLocation(),n.forEach(s=>s())},i=async s=>{var a;if(typeof document<"u"&&r.length){for(let l of r)if(!await l()){(a=e.onBlocked)==null||a.call(e,o);return}}s()};return{get location(){return t},subscribe:s=>(n.add(s),()=>{n.delete(s)}),push:(s,a)=>{a=_E(a),i(()=>{e.pushState(s,a),o()})},replace:(s,a)=>{a=_E(a),i(()=>{e.replaceState(s,a),o()})},go:s=>{i(()=>{e.go(s)})},back:()=>{i(()=>{e.back()})},forward:()=>{i(()=>{e.forward()})},createHref:s=>e.createHref(s),block:s=>(r.push(s),r.length===1&&addEventListener(JI,e6,{capture:!0}),()=>{r=r.filter(a=>a!==s),r.length||MW()}),flush:()=>{var s;return(s=e.flush)==null?void 0:s.call(e)},destroy:()=>{var s;return(s=e.destroy)==null?void 0:s.call(e)},notify:o}}function _E(e){return e||(e={}),{...e,key:n6()}}function DW(e){const t=(e==null?void 0:e.window)??(typeof document<"u"?window:void 0),n=(e==null?void 0:e.createHref)??(y=>y),r=(e==null?void 0:e.parseLocation)??(()=>q0(`${t.location.pathname}${t.location.search}${t.location.hash}`,t.history.state));let o=r(),i;const s=()=>o;let a,l=!0,c;const u=y=>{l=!1,y(),l=!0},d=()=>{u(()=>{a&&(t.history[a.isPush?"pushState":"replaceState"](a.state,"",a.href),a=void 0,c=void 0,i=void 0)})},f=(y,b,w)=>{const x=n(b);c||(i=o),o=q0(b,w),a={href:x,state:w,isPush:(a==null?void 0:a.isPush)||y==="push"},c||(c=Promise.resolve().then(()=>d()))},h=()=>{o=r(),S.notify()};var m=t.history.pushState,v=t.history.replaceState;const S=t6({getLocation:s,pushState:(y,b)=>f("push",y,b),replaceState:(y,b)=>f("replace",y,b),back:()=>t.history.back(),forward:()=>t.history.forward(),go:y=>t.history.go(y),createHref:y=>n(y),flush:d,destroy:()=>{t.history.pushState=m,t.history.replaceState=v,t.removeEventListener(SE,h),t.removeEventListener(xE,h)},onBlocked:y=>{i&&o!==i&&(o=i,y())}});return t.addEventListener(SE,h),t.addEventListener(xE,h),t.history.pushState=function(){let y=m.apply(t.history,arguments);return l&&S.notify(),y},t.history.replaceState=function(){let y=v.apply(t.history,arguments);return l&&S.notify(),y},S}function AW(e={initialEntries:["/"]}){const t=e.initialEntries;let n=e.initialIndex??t.length-1,r={key:n6()};return t6({getLocation:()=>q0(t[n],r),pushState:(i,s)=>{r=s,t.push(i),n++},replaceState:(i,s)=>{r=s,t[n]=i},back:()=>{n--},forward:()=>{n=Math.min(n+1,t.length-1)},go:i=>{n=Math.min(Math.max(n+i,0),t.length-1)},createHref:i=>i})}function q0(e,t){let n=e.indexOf("#"),r=e.indexOf("?");return{href:e,pathname:e.substring(0,n>0?r>0?Math.min(n,r):n:r>0?r:e.length),hash:n>-1?e.substring(n):"",search:r>-1?e.slice(r,n===-1?void 0:n):"",state:t||{}}}function n6(){return(Math.random()+1).toString(36).substring(7)}var FW="Invariant failed";function Vt(e,t){if(!e)throw new Error(FW)}let fv=p.createContext(null);function r6(){return typeof document>"u"?fv:window.__TSR_ROUTER_CONTEXT__?window.__TSR_ROUTER_CONTEXT__:(window.__TSR_ROUTER_CONTEXT__=fv,fv)}function Dt(e){const t=p.useContext(r6());return e==null||e.warn,t}var o6={exports:{}},i6={},s6={exports:{}},a6={};/** + * @license React + * use-sync-external-store-shim.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var pl=p;function jW(e,t){return e===t&&(e!==0||1/e===1/t)||e!==e&&t!==t}var LW=typeof Object.is=="function"?Object.is:jW,VW=pl.useState,zW=pl.useEffect,BW=pl.useLayoutEffect,HW=pl.useDebugValue;function UW(e,t){var n=t(),r=VW({inst:{value:n,getSnapshot:t}}),o=r[0].inst,i=r[1];return BW(function(){o.value=n,o.getSnapshot=t,hv(o)&&i({inst:o})},[e,n,t]),zW(function(){return hv(o)&&i({inst:o}),e(function(){hv(o)&&i({inst:o})})},[e]),HW(n),n}function hv(e){var t=e.getSnapshot;e=e.value;try{var n=t();return!LW(e,n)}catch{return!0}}function WW(e,t){return t()}var GW=typeof window>"u"||typeof window.document>"u"||typeof window.document.createElement>"u"?WW:UW;a6.useSyncExternalStore=pl.useSyncExternalStore!==void 0?pl.useSyncExternalStore:GW;s6.exports=a6;var qW=s6.exports;/** + * @license React + * use-sync-external-store-shim/with-selector.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var gm=p,KW=qW;function YW(e,t){return e===t&&(e!==0||1/e===1/t)||e!==e&&t!==t}var QW=typeof Object.is=="function"?Object.is:YW,XW=KW.useSyncExternalStore,ZW=gm.useRef,JW=gm.useEffect,eG=gm.useMemo,tG=gm.useDebugValue;i6.useSyncExternalStoreWithSelector=function(e,t,n,r,o){var i=ZW(null);if(i.current===null){var s={hasValue:!1,value:null};i.current=s}else s=i.current;i=eG(function(){function l(h){if(!c){if(c=!0,u=h,h=r(h),o!==void 0&&s.hasValue){var m=s.value;if(o(m,h))return d=m}return d=h}if(m=d,QW(u,h))return m;var v=r(h);return o!==void 0&&o(m,v)?m:(u=h,d=v)}var c=!1,u,d,f=n===void 0?null:n;return[function(){return l(t())},f===null?void 0:function(){return l(f())}]},[t,n,r,o]);var a=XW(e,i[0],i[1]);return JW(function(){s.hasValue=!0,s.value=a},[a]),tG(a),a};o6.exports=i6;var nG=o6.exports,rG=class{constructor(e,t){this.listeners=new Set,this._batching=!1,this._flushing=0,this._nextPriority=null,this.subscribe=n=>{var o,i;this.listeners.add(n);const r=(i=(o=this.options)==null?void 0:o.onSubscribe)==null?void 0:i.call(o,n,this);return()=>{this.listeners.delete(n),r==null||r()}},this.setState=(n,r)=>{var s,a,l,c,u;const o=this.state;this.state=(s=this.options)!=null&&s.updateFn?this.options.updateFn(o)(n):n(o);const i=(r==null?void 0:r.priority)??((a=this.options)==null?void 0:a.defaultPriority)??"high";this._nextPriority===null?this._nextPriority=i:this._nextPriority==="high"?this._nextPriority=i:this._nextPriority=((l=this.options)==null?void 0:l.defaultPriority)??"high",(u=(c=this.options)==null?void 0:c.onUpdate)==null||u.call(c,{priority:this._nextPriority}),this._flush()},this._flush=()=>{if(this._batching)return;const n=++this._flushing;this.listeners.forEach(r=>{this._flushing===n&&r({priority:this._nextPriority??"high"})})},this.batch=n=>{if(this._batching)return n();this._batching=!0,n(),this._batching=!1,this._flush()},this.state=e,this.options=t}};function oG(e,t=n=>n){return nG.useSyncExternalStoreWithSelector(e.subscribe,()=>e.state,()=>e.state,t,iG)}function iG(e,t){if(Object.is(e,t))return!0;if(typeof e!="object"||e===null||typeof t!="object"||t===null)return!1;const n=Object.keys(e);if(n.length!==Object.keys(t).length)return!1;for(let r=0;rn?p.createElement(t,{error:n}):e.children})}class sG extends p.Component{constructor(){super(...arguments),this.state={error:null}}static getDerivedStateFromProps(t){var n;return{resetKey:(n=t.getResetKey)==null?void 0:n.call(t)}}static getDerivedStateFromError(t){return{error:t}}componentDidUpdate(t,n){n.error&&n.resetKey!==this.state.resetKey&&this.setState({error:null})}componentDidCatch(t){var n,r;this.props.onCatch?(r=(n=this.props).onCatch)==null||r.call(n,t):console.error(t)}render(){return this.props.children(this.state)}}function vm({error:e}){const[t,n]=p.useState(!1);return g.jsxs("div",{style:{padding:".5rem",maxWidth:"100%"},children:[g.jsxs("div",{style:{display:"flex",alignItems:"center",gap:".5rem"},children:[g.jsx("strong",{style:{fontSize:"1rem"},children:"Something went wrong!"}),g.jsx("button",{style:{appearance:"none",fontSize:".6em",border:"1px solid currentColor",padding:".1rem .2rem",fontWeight:"bold",borderRadius:".25rem"},onClick:()=>n(r=>!r),children:t?"Hide Error":"Show Error"})]}),g.jsx("div",{style:{height:".25rem"}}),t?g.jsx("div",{children:g.jsx("pre",{style:{fontSize:".7em",border:"1px solid red",borderRadius:".25rem",padding:".3rem",color:"red",overflow:"auto"},children:e.message?g.jsx("code",{children:e.message}):null})}):null]})}function Hn(e){const t=Dt({warn:(e==null?void 0:e.router)===void 0});return oG(((e==null?void 0:e.router)||t).__store,e==null?void 0:e.select)}const l6=typeof document>"u";function tp(e){return e[e.length-1]}function aG(e){return typeof e=="function"}function Ca(e,t){return aG(e)?e(t):e}function qc(e,t){return t.reduce((n,r)=>(n[r]=e[r],n),{})}function jo(e,t){if(e===t)return e;const n=t,r=CE(e)&&CE(n);if(r||np(e)&&np(n)){const o=r?e:Object.keys(e),i=o.length,s=r?n:Object.keys(n),a=s.length,l=r?[]:{};let c=0;for(let u=0;u"u")return!0;const n=t.prototype;return!(!EE(n)||!n.hasOwnProperty("isPrototypeOf"))}function EE(e){return Object.prototype.toString.call(e)==="[object Object]"}function CE(e){return Array.isArray(e)&&e.length===Object.keys(e).length}function Tu(e,t,n=!1){if(e===t)return!0;if(typeof e!=typeof t)return!1;if(np(e)&&np(t)){const r=Object.keys(e),o=Object.keys(t);return!n&&r.length!==o.length?!1:!o.some(i=>!(i in e)||!Tu(e[i],t[i],n))}return Array.isArray(e)&&Array.isArray(t)?!e.some((r,o)=>!Tu(r,t[o],n)):!1}const pv=typeof window<"u"?p.useLayoutEffect:p.useEffect;function lG(e){return e.replace(/\\/g,"\\\\").replace(/'/g,"\\'").replace(/"/g,'\\"')}function cG(e={}){if(e.isNotFound=!0,e.throw)throw e;return e}function ao(e){return!!(e!=null&&e.isNotFound)}function uG(e){const t=Hn({select:n=>`not-found-${n.location.pathname}-${n.status}`});return g.jsx(zw,{getResetKey:()=>t,onCatch:n=>{var r;if(ao(n))(r=e.onCatch)==null||r.call(e,n);else throw n},errorComponent:({error:n})=>{var r;return(r=e.fallback)==null?void 0:r.call(e,n)},children:e.children})}function dG(){return g.jsx("p",{children:"Not Found"})}function fG(e){if(e.isRedirect=!0,e.statusCode=e.statusCode||e.code||301,e.throw??!0)throw e;return e}function eo(e){return!!(e!=null&&e.isRedirect)}const ym=p.createContext(void 0);function kE(){const e=Dt(),t=Hn({select:n=>{var r;return(r=mr(n)[0])==null?void 0:r.id}});return g.jsx(ym.Provider,{value:t,children:g.jsx(zw,{getResetKey:()=>{var n;return(n=e.state.resolvedLocation.state)==null?void 0:n.key},errorComponent:vm,onCatch:n=>{console.error(n)},children:t?g.jsx(c6,{matchId:t}):null})})}function mv(e){return g.jsx(g.Fragment,{children:e.children})}function c6({matchId:e}){var t,n,r,o;const i=Dt(),s=Hn({select:v=>{var S;return(S=mr(v).find(y=>y.id===e))==null?void 0:S.routeId}});Vt(s);const a=i.routesById[s],l=a.options.pendingComponent??i.options.defaultPendingComponent,c=l?g.jsx(l,{}):null,u=a.options.errorComponent??i.options.defaultErrorComponent??vm,d=a.isRoot?a.options.notFoundComponent??((t=i.options.notFoundRoute)==null?void 0:t.options.component):a.options.notFoundComponent,f=a.options.wrapInSuspense??l??((n=a.options.component)==null?void 0:n.preload)??((r=a.options.pendingComponent)==null?void 0:r.preload)??((o=a.options.errorComponent)==null?void 0:o.preload)?p.Suspense:mv,h=u?zw:mv,m=d?uG:mv;return g.jsx(ym.Provider,{value:e,children:g.jsx(f,{fallback:c,children:g.jsx(h,{getResetKey:()=>{var v;return(v=i.state.resolvedLocation.state)==null?void 0:v.key},errorComponent:u,onCatch:v=>{if(ao(v))throw v;console.error(v)},children:g.jsx(m,{fallback:v=>{if(!d||v.routeId&&v.routeId!==s||!v.routeId&&!a.isRoot)throw v;return p.createElement(d,v)},children:g.jsx(hG,{matchId:e,pendingElement:c})})})})})}function hG({matchId:e,pendingElement:t}){var n,r;const o=Dt(),i=Hn({select:c=>{var u;return(u=mr(c).find(d=>d.id===e))==null?void 0:u.routeId}}),s=o.routesById[i],a=Hn({select:c=>qc(mr(c).find(u=>u.id===e),["status","error","showPending","loadPromise"])}),l=(s.options.errorComponent??o.options.defaultErrorComponent)||vm;if(a.status==="notFound"){let c;return TE(a.error)?c=(((n=o.options.errorSerializer)==null?void 0:n.deserialize)??RE)(a.error.data):c=a.error,Vt(ao(c)),u6(o,s,c)}if(a.status==="redirected")return Vt(eo(a.error)),null;if(a.status==="error"){if(l6)return g.jsx(l,{error:a.error,info:{componentStack:""}});throw TE(a.error)?(((r=o.options.errorSerializer)==null?void 0:r.deserialize)??RE)(a.error.data):a.error}if(a.status==="pending"){if(a.showPending)return t;throw a.loadPromise}if(a.status==="success"){let c=s.options.component??o.options.defaultComponent;return c?g.jsx(c,{}):g.jsx(id,{})}Vt(!1)}const id=p.memo(function(){const t=Dt(),n=p.useContext(ym),r=Hn({select:a=>{var l;return(l=mr(a).find(c=>c.id===n))==null?void 0:l.routeId}}),o=t.routesById[r],{parentGlobalNotFound:i}=Hn({select:a=>{const c=mr(a).find(u=>u.id===n);return Vt(c),{parentGlobalNotFound:c.globalNotFound}}}),s=Hn({select:a=>{var l;const c=mr(a),u=c.findIndex(d=>d.id===n);return(l=c[u+1])==null?void 0:l.id}});return i?u6(t,o,void 0):s?g.jsx(c6,{matchId:s}):null});function u6(e,t,n){return t.options.notFoundComponent?g.jsx(t.options.notFoundComponent,{data:n}):e.options.defaultNotFoundComponent?g.jsx(e.options.defaultNotFoundComponent,{data:n}):g.jsx(dG,{})}function mr(e){var t;return(t=e.pendingMatches)!=null&&t.some(n=>n.showPending)?e.pendingMatches:e.matches}function Wr(e){var t;const n=Dt(),r=p.useContext(ym),o=(t=mr(n.state).find(a=>a.id===r))==null?void 0:t.routeId,i=(()=>{const a=mr(n.state);return(e!=null&&e.from?a.find(c=>c.routeId===(e==null?void 0:e.from)):a.find(c=>c.id===r)).routeId})();return((e==null?void 0:e.strict)??!0)&&Vt(o==i),Hn({select:a=>{const l=mr(a).find(c=>e!=null&&e.from?(e==null?void 0:e.from)===c.routeId:c.id===r);return Vt(l,`Could not find ${e!=null&&e.from?`an active match from "${e.from}"`:"a nearest match!"}`),e!=null&&e.select?e.select(l):l}})}function d6(e){return Wr({...e,select:t=>typeof e.select=="function"?e.select(t==null?void 0:t.loaderDeps):t==null?void 0:t.loaderDeps})}function f6(e){return Wr({...e,select:t=>typeof e.select=="function"?e.select(t==null?void 0:t.loaderData):t==null?void 0:t.loaderData})}function TE(e){return!(typeof e=="object"&&e&&"data"in e)||!("__isServerError"in e&&e.__isServerError)||!(typeof e.data=="object"&&e.data)?!1:e.__isServerError===!0}function RE(e){if("name"in e&&"message"in e){const t=new Error(e.message);return t.name=e.name,t}return e.data}function mi(e){return bm(e.filter(Boolean).join("/"))}function bm(e){return e.replace(/\/{2,}/g,"/")}function Bw(e){return e==="/"?e:e.replace(/^\/{1,}/,"")}function th(e){return e==="/"?e:e.replace(/\/{1,}$/,"")}function pG(e){return th(Bw(e))}function mG(e,t,n){t=t.replace(new RegExp(`^${e}`),"/"),n=n.replace(new RegExp(`^${e}`),"/");let r=ml(t);const o=ml(n);o.forEach((s,a)=>{var l;if(s.value==="/")a?a===o.length-1&&r.push(s):r=[s];else if(s.value==="..")r.length>1&&((l=tp(r))==null?void 0:l.value)==="/"&&r.pop(),r.pop();else{if(s.value===".")return;r.push(s)}});const i=mi([e,...r.map(s=>s.value)]);return bm(i)}function ml(e){if(!e)return[];e=bm(e);const t=[];if(e.slice(0,1)==="/"&&(e=e.substring(1),t.push({type:"pathname",value:"/"})),!e)return t;const n=e.split("/").filter(Boolean);return t.push(...n.map(r=>r==="$"||r==="*"?{type:"wildcard",value:r}:r.charAt(0)==="$"?{type:"param",value:r}:{type:"pathname",value:r})),e.slice(-1)==="/"&&(e=e.substring(1),t.push({type:"pathname",value:"/"})),t}function gv({path:e,params:t,leaveWildcards:n,leaveParams:r}){const o=ml(e);return mi(o.map(i=>{if(i.type==="wildcard"){const s=t._splat;return n?`${i.value}${s??""}`:s}if(i.type==="param"){if(r){const s=t[i.value];return`${i.value}${s??""}`}return t[i.value.substring(1)]??"undefined"}return i.value}))}function vv(e,t,n){const r=gG(e,t,n);if(!(n.to&&!r))return r??{}}function IE(e,t){return e!="/"?t.replace(e,""):t}function gG(e,t,n){t=IE(e,t);const r=IE(e,`${n.to??"$"}`),o=ml(t),i=ml(r);t.startsWith("/")||o.unshift({type:"pathname",value:"/"}),r.startsWith("/")||i.unshift({type:"pathname",value:"/"});const s={};return(()=>{for(let l=0;l=o.length-1,f=l>=i.length-1;if(u){if(u.type==="wildcard"){if(c!=null&&c.value){const h=decodeURI(mi(o.slice(l).map(m=>m.value)));return s["*"]=h,s._splat=h,!0}return!1}if(u.type==="pathname"){if(u.value==="/"&&!(c!=null&&c.value))return!0;if(c){if(n.caseSensitive){if(u.value!==c.value)return!1}else if(u.value.toLowerCase()!==c.value.toLowerCase())return!1}}if(!c)return!1;if(u.type==="param"){if((c==null?void 0:c.value)==="/")return!1;c.value.charAt(0)!=="$"&&(s[u.value.substring(1)]=decodeURI(c.value))}}if(!d&&f)return s["**"]=mi(o.slice(l+1).map(h=>h.value)),!!n.fuzzy&&(u==null?void 0:u.value)!=="/"}return!0})()?s:void 0}function sd(e){return Hn({select:t=>{var n;const r=(n=tp(mr(t)))==null?void 0:n.params;return e!=null&&e.select?e.select(r):r}})}function h6(e){return Wr({...e,select:t=>e!=null&&e.select?e.select(t.search):t.search})}const Fn="__root__";function p6(e){return new vG({id:e})}class vG{constructor({id:t}){this.useMatch=n=>Wr({select:n==null?void 0:n.select,from:this.id}),this.useRouteContext=n=>Wr({from:this.id,select:r=>n!=null&&n.select?n.select(r.context):r.context}),this.useSearch=n=>h6({...n,from:this.id}),this.useParams=n=>sd({...n,from:this.id}),this.useLoaderDeps=n=>d6({...n,from:this.id,strict:!1}),this.useLoaderData=n=>f6({...n,from:this.id,strict:!1}),this.notFound=n=>cG({routeId:this.id,...n}),this.id=t}}let m6=class{constructor(t){this.init=n=>{var r,o;this.originalIndex=n.originalIndex;const i=this.options,s=!(i!=null&&i.path)&&!(i!=null&&i.id);this.parentRoute=(o=(r=this.options)==null?void 0:r.getParentRoute)==null?void 0:o.call(r),s?this.path=Fn:Vt(this.parentRoute);let a=s?Fn:i.path;a&&a!=="/"&&(a=Bw(a));const l=(i==null?void 0:i.id)||a;let c=s?Fn:mi([this.parentRoute.id===Fn?"":this.parentRoute.id,l]);a===Fn&&(a="/"),c!==Fn&&(c=mi(["/",c]));const u=c===Fn?"/":mi([this.parentRoute.fullPath,a]);this.path=a,this.id=c,this.fullPath=u,this.to=u},this.addChildren=n=>(this.children=n,this),this.updateLoader=n=>(Object.assign(this.options,n),this),this.update=n=>(Object.assign(this.options,n),this),this.lazy=n=>(this.lazyFn=n,this),this.useMatch=n=>Wr({...n,from:this.id}),this.useRouteContext=n=>Wr({...n,from:this.id,select:r=>n!=null&&n.select?n.select(r.context):r.context}),this.useSearch=n=>h6({...n,from:this.id}),this.useParams=n=>sd({...n,from:this.id}),this.useLoaderDeps=n=>d6({...n,from:this.id}),this.useLoaderData=n=>f6({...n,from:this.id}),this.options=t||{},this.isRoot=!(t!=null&&t.getParentRoute),Vt(!(t!=null&&t.id&&(t!=null&&t.path))),this.$$typeof=Symbol.for("react.memo")}};function yG(e){return new m6(e)}class bG extends m6{constructor(t){super(t)}}function wG(e){return new bG(e)}function SG(e,t){var n,r,o,i="";for(n in e)if((o=e[n])!==void 0)if(Array.isArray(o))for(r=0;r{t.substring(0,1)==="?"&&(t=t.substring(1));let n=xG(t);for(let r in n){const o=n[r];if(typeof o=="string")try{n[r]=e(o)}catch{}}return n}}function kG(e,t){function n(r){if(typeof r=="object"&&r!==null)try{return e(r)}catch{}else if(typeof r=="string"&&typeof t=="function")try{return t(r),e(r)}catch{}return r}return r=>{r={...r},r&&Object.keys(r).forEach(i=>{const s=r[i];typeof s>"u"||s===void 0?delete r[i]:r[i]=n(s)});const o=SG(r).toString();return o?`?${o}`:""}}const TG=p.useTransition||(()=>[!1,e=>{e()}]);function RG({router:e,...t}){e.update({...e.options,...t,context:{...e.options.context,...t==null?void 0:t.context}});const n=e.options.InnerWrap?g.jsx(e.options.InnerWrap,{children:g.jsx(kE,{})}):g.jsx(kE,{}),r=r6(),o=g.jsxs(r.Provider,{value:e,children:[n,g.jsx(IG,{})]});return e.options.Wrap?g.jsx(e.options.Wrap,{children:o}):o}function IG(){const e=Dt(),t=p.useRef({router:e,mounted:!1}),n=Hn({select:s=>qc(s,["isLoading","location","resolvedLocation","isTransitioning"])}),[r,o]=TG();e.startReactTransition=o,p.useEffect(()=>{r&&e.__store.setState(s=>({...s,isTransitioning:r}))},[r]);const i=()=>{(a=>{n.isTransitioning?a():o(()=>a())})(()=>{try{e.load()}catch(a){console.error(a)}})};return pv(()=>{const s=e.history.subscribe(()=>{e.latestLocation=e.parseLocation(e.latestLocation),e.state.location!==e.latestLocation&&i()}),a=e.buildLocation({to:e.latestLocation.pathname,search:!0,params:!0,hash:!0,state:!0});return n.location.href!==a.href&&e.commitLocation({...a,replace:!0}),()=>{s()}},[e.history]),pv(()=>{var s;if(p.useTransition?n.isTransitioning&&!r:!n.isLoading&&n.resolvedLocation!==n.location){if(e.emit({type:"onResolved",fromLocation:n.resolvedLocation,toLocation:n.location,pathChanged:n.location.href!==((s=n.resolvedLocation)==null?void 0:s.href)}),document.querySelector&&n.location.hash!==""){const a=document.getElementById(n.location.hash);a&&a.scrollIntoView()}e.__store.setState(a=>({...a,isTransitioning:!1,resolvedLocation:a.location}))}},[n.isTransitioning,r,n.isLoading,n.resolvedLocation,n.location]),pv(()=>{window.__TSR_DEHYDRATED__||t.current.router===e&&t.current.mounted||(t.current={router:e,mounted:!0},i())},[e]),null}function PE(e,t){return[...e.cachedMatches,...e.pendingMatches??[],...e.matches].find(n=>n.id===t)}const $G=["component","errorComponent","pendingComponent","notFoundComponent"];function PG(e){return new OG(e)}class OG{constructor(t){this.tempLocationKey=`${Math.round(Math.random()*1e7)}`,this.resetNextScroll=!0,this.navigateTimeout=null,this.latestLoadPromise=Promise.resolve(),this.subscribers=new Set,this.injectedHtml=[],this.startReactTransition=n=>n(),this.update=n=>{n.notFoundRoute&&console.warn("The notFoundRoute API is deprecated and will be removed in the next major version. See https://tanstack.com/router/v1/docs/guide/not-found-errors#migrating-from-notfoundroute for more info.");const r=this.options;this.options={...this.options,...n},(!this.basepath||n.basepath&&n.basepath!==r.basepath)&&(n.basepath===void 0||n.basepath===""||n.basepath==="/"?this.basepath="/":this.basepath=`/${pG(n.basepath)}`),(!this.history||this.options.history&&this.options.history!==this.history)&&(this.history=this.options.history??(typeof document<"u"?DW():AW({initialEntries:[this.options.basepath||"/"]})),this.latestLocation=this.parseLocation()),this.options.routeTree!==this.routeTree&&(this.routeTree=this.options.routeTree,this.buildRouteTree()),this.__store||(this.__store=new rG(DG(this.latestLocation),{onUpdate:()=>{this.__store.state={...this.state,status:this.state.isTransitioning||this.state.isLoading?"pending":"idle",cachedMatches:this.state.cachedMatches.filter(o=>!["redirected"].includes(o.status))}}}))},this.buildRouteTree=()=>{this.routesById={},this.routesByPath={};const n=this.options.notFoundRoute;n&&(n.init({originalIndex:99999999999}),this.routesById[n.id]=n);const r=i=>{i.forEach((s,a)=>{s.init({originalIndex:a});const l=this.routesById[s.id];if(Vt(!l,`Duplicate routes found with id: ${String(s.id)}`),this.routesById[s.id]=s,!s.isRoot&&s.path){const u=th(s.fullPath);(!this.routesByPath[u]||s.fullPath.endsWith("/"))&&(this.routesByPath[u]=s)}const c=s.children;c!=null&&c.length&&r(c)})};r([this.routeTree]);const o=[];Object.values(this.routesById).forEach((i,s)=>{var a;if(i.isRoot||!i.path)return;const l=Bw(i.fullPath),c=ml(l);for(;c.length>1&&((a=c[0])==null?void 0:a.value)==="/";)c.shift();const u=c.map(d=>d.value==="/"?.75:d.type==="param"?.5:d.type==="wildcard"?.25:1);o.push({child:i,trimmed:l,parsed:c,index:s,scores:u})}),this.flatRoutes=o.sort((i,s)=>{const a=Math.min(i.scores.length,s.scores.length);for(let l=0;ls.parsed[l].value?1:-1;return i.index-s.index}).map((i,s)=>(i.child.rank=s,i.child))},this.subscribe=(n,r)=>{const o={eventType:n,fn:r};return this.subscribers.add(o),()=>{this.subscribers.delete(o)}},this.emit=n=>{this.subscribers.forEach(r=>{r.eventType===n.type&&r.fn(n)})},this.checkLatest=n=>this.latestLoadPromise!==n?this.latestLoadPromise:void 0,this.parseLocation=n=>{const r=({pathname:a,search:l,hash:c,state:u})=>{const d=this.options.parseSearch(l),f=this.options.stringifySearch(d);return{pathname:a,searchStr:f,search:jo(n==null?void 0:n.search,d),hash:c.split("#").reverse()[0]??"",href:`${a}${f}${c}`,state:jo(n==null?void 0:n.state,u)}},o=r(this.history.location);let{__tempLocation:i,__tempKey:s}=o.state;if(i&&(!s||s===this.tempLocationKey)){const a=r(i);return a.state.key=o.state.key,delete a.state.__tempLocation,{...a,maskedLocation:o}}return o},this.resolvePathWithBase=(n,r)=>mG(this.basepath,n,bm(r)),this.matchRoutes=(n,r,o)=>{let i={},s=this.flatRoutes.find(h=>{const m=vv(this.basepath,th(n),{to:h.fullPath,caseSensitive:h.options.caseSensitive??this.options.caseSensitive,fuzzy:!0});return m?(i=m,!0):!1}),a=s||this.routesById[Fn],l=[a],c=!1;for((s?s.path!=="/"&&i["**"]:th(n))&&(this.options.notFoundRoute?l.push(this.options.notFoundRoute):c=!0);a!=null&&a.parentRoute;)a=a.parentRoute,a&&l.unshift(a);const u=(()=>{if(c){if(this.options.notFoundMode!=="root")for(let h=l.length-1;h>=0;h--){const m=l[h];if(m.children)return m.id}return Fn}})(),d=l.map(h=>{let m;if(h.options.parseParams)try{const v=h.options.parseParams(i);Object.assign(i,v)}catch(v){if(m=new MG(v.message,{cause:v}),o!=null&&o.throwOnError)throw m;return m}}),f=[];return l.forEach((h,m)=>{var v,S,y,b,w,x;const _=f[m-1],[E,C]=(()=>{const A=(_==null?void 0:_.search)??r;try{const F=typeof h.options.validateSearch=="object"?h.options.validateSearch.parse:h.options.validateSearch;let P=(F==null?void 0:F(A))??{};return[{...A,...P},void 0]}catch(F){const P=new NG(F.message,{cause:F});if(o!=null&&o.throwOnError)throw P;return[A,P]}})(),k=((S=(v=h.options).loaderDeps)==null?void 0:S.call(v,{search:E}))??"",T=k?JSON.stringify(k):"",R=gv({path:h.fullPath,params:i}),D=gv({path:h.id,params:i,leaveWildcards:!0})+T;let O=PE(this.state,D);const H=this.state.matches.find(A=>A.id===D)?"stay":"enter",N=O?{...O,cause:H,params:i}:{id:D,routeId:h.id,params:i,pathname:mi([this.basepath,R]),updatedAt:Date.now(),search:{},searchError:void 0,status:"pending",showPending:!1,isFetching:!1,error:void 0,paramsError:d[m],loadPromise:Promise.resolve(),routeContext:void 0,context:void 0,abortController:new AbortController,fetchCount:0,cause:H,loaderDeps:k,invalid:!1,preload:!1,links:(b=(y=h.options).links)==null?void 0:b.call(y),scripts:(x=(w=h.options).scripts)==null?void 0:x.call(w),staticData:h.options.staticData||{}};o!=null&&o.preload||(N.globalNotFound=u===h.id),N.search=jo(N.search,E),N.searchError=C,f.push(N)}),f},this.cancelMatch=n=>{},this.cancelMatches=()=>{var n;(n=this.state.pendingMatches)==null||n.forEach(r=>{this.cancelMatch(r.id)})},this.buildLocation=n=>{const r=(i={},s)=>{var a,l,c;const u=this.state.pendingMatches||this.state.matches,d=((a=u[u.length-1])==null?void 0:a.search)||this.latestLocation.search,f=this.matchRoutes(this.latestLocation.pathname,d),h=s==null?void 0:s.filter(O=>f==null?void 0:f.find(H=>H.routeId===O.routeId)),m=this.looseRoutesById[(l=tp(f))==null?void 0:l.routeId];let v=i.to?this.resolvePathWithBase(i.from??this.latestLocation.pathname,`${i.to}`):this.resolvePathWithBase(m==null?void 0:m.fullPath,m==null?void 0:m.fullPath);const S={...(c=tp(f))==null?void 0:c.params};let y=(i.params??!0)===!0?S:{...S,...Ca(i.params,S)};Object.keys(y).length>0&&(s==null||s.map(O=>this.looseRoutesById[O.routeId].options.stringifyParams).filter(Boolean).forEach(O=>{y={...y,...O(y)}})),v=gv({path:v,params:y??{},leaveWildcards:!1,leaveParams:n.leaveParams});const b=(h==null?void 0:h.map(O=>this.looseRoutesById[O.routeId].options.preSearchFilters??[]).flat().filter(Boolean))??[],w=(h==null?void 0:h.map(O=>this.looseRoutesById[O.routeId].options.postSearchFilters??[]).flat().filter(Boolean))??[],x=b!=null&&b.length?b==null?void 0:b.reduce((O,H)=>H(O),d):d,_=i.search===!0?x:i.search?Ca(i.search,x)??{}:b!=null&&b.length?x:{},E=w!=null&&w.length?w.reduce((O,H)=>H(O),_):_,C=jo(d,E),k=this.options.stringifySearch(C),T=i.hash===!0?this.latestLocation.hash:i.hash?Ca(i.hash,this.latestLocation.hash):void 0,R=T?`#${T}`:"";let D=i.state===!0?this.latestLocation.state:i.state?Ca(i.state,this.latestLocation.state):{};return D=jo(this.latestLocation.state,D),{pathname:v,search:C,searchStr:k,state:D,hash:T??"",href:`${v}${k}${R}`,unmaskOnReload:i.unmaskOnReload}},o=(i={},s)=>{var a;let l=r(i),c=s?r(s):void 0;if(!c){let m={},v=(a=this.options.routeMasks)==null?void 0:a.find(S=>{const y=vv(this.basepath,l.pathname,{to:S.from,caseSensitive:!1,fuzzy:!1});return y?(m=y,!0):!1});v&&(s={...qc(n,["from"]),...v,params:m},c=r(s))}const u=this.matchRoutes(l.pathname,l.search),d=c?this.matchRoutes(c.pathname,c.search):void 0,f=c?r(s,d):void 0,h=r(i,u);return f&&(h.maskedLocation=f),h};return n.mask?o(n,{...qc(n,["from"]),...n.mask}):o(n)},this.commitLocation=async({startTransition:n,...r})=>{if(this.navigateTimeout&&clearTimeout(this.navigateTimeout),!(this.latestLocation.href===r.href)){let{maskedLocation:i,...s}=r;i&&(s={...i,state:{...i.state,__tempKey:void 0,__tempLocation:{...s,search:s.searchStr,state:{...s.state,__tempKey:void 0,__tempLocation:void 0,key:void 0}}}},(s.unmaskOnReload??this.options.unmaskOnReload??!1)&&(s.state.__tempKey=this.tempLocationKey));const a=()=>{this.history[r.replace?"replace":"push"](s.href,s.state)};n??!0?this.startReactTransition(a):a()}return this.resetNextScroll=r.resetScroll??!0,this.latestLoadPromise},this.buildAndCommitLocation=({replace:n,resetScroll:r,startTransition:o,...i}={})=>{const s=this.buildLocation(i);return this.commitLocation({...s,startTransition:o,replace:n,resetScroll:r})},this.navigate=({from:n,to:r,...o})=>{const i=String(r);let s;try{new URL(`${i}`),s=!0}catch{}return Vt(!s),this.buildAndCommitLocation({...o,from:n,to:r})},this.loadMatches=async({checkLatest:n,location:r,matches:o,preload:i})=>{var s,a;let l,c;const u=(m,v)=>{var S;const y=(S=this.state.pendingMatches)==null?void 0:S.find(x=>x.id===m.id),b=this.state.matches.find(x=>x.id===m.id),w=y?"pendingMatches":b?"matches":"cachedMatches";this.__store.setState(x=>{var _,E;return{...x,[w]:v!=null&&v.remove?(_=x[w])==null?void 0:_.filter(C=>C.id!==m.id):(E=x[w])==null?void 0:E.map(C=>C.id===m.id?m:C)}})},d=(m,v)=>{throw m={...m,status:eo(v)?"redirected":ao(v)?"notFound":"error",isFetching:!1,error:v},u(m),v.routeId||(v.routeId=m.routeId),v};for(let[m,v]of o.entries()){const S=o[m-1],y=this.looseRoutesById[v.routeId],b=new AbortController,w=(x,_)=>{var E,C;x.routerCode=_,c=c??m,(eo(x)||ao(x))&&d(v,x);try{(C=(E=y.options).onError)==null||C.call(E,x)}catch(k){x=k,(eo(x)||ao(x))&&d(v,k)}o[m]=v={...v,error:x,status:"error",updatedAt:Date.now(),abortController:new AbortController}};v.paramsError&&w(v.paramsError,"PARSE_PARAMS"),v.searchError&&w(v.searchError,"VALIDATE_SEARCH");try{const x=(S==null?void 0:S.context)??this.options.context??{},_=y.options.pendingMs??this.options.defaultPendingMs,E=typeof _=="number"&&_<=0?Promise.resolve():new Promise(T=>setTimeout(T,_)),C=await((a=(s=y.options).beforeLoad)==null?void 0:a.call(s,{search:v.search,abortController:b,params:v.params,preload:!!i,context:x,location:r,navigate:T=>this.navigate({...T,from:v.pathname}),buildLocation:this.buildLocation,cause:i?"preload":v.cause}))??{};(eo(C)||ao(C))&&w(C,"BEFORE_LOAD");const k={...x,...C};o[m]=v={...v,routeContext:jo(v.routeContext,C),context:jo(v.context,k),abortController:b,pendingPromise:E}}catch(x){w(x,"BEFORE_LOAD");break}}const f=o.slice(0,c),h=[];return f.forEach((m,v)=>{h.push(new Promise(async(S,y)=>{var b;const w=h[v-1],x=this.looseRoutesById[m.routeId],_=P=>{(eo(P)||ao(P))&&d(m,P)};let E;o[v]=m={...m,showPending:!1};let C=!1;const k=x.options.pendingMs??this.options.defaultPendingMs,T=x.options.pendingMinMs??this.options.defaultPendingMinMs,R={params:m.params,deps:m.loaderDeps,preload:!!i,parentMatchPromise:w,abortController:m.abortController,context:m.context,location:r,navigate:P=>this.navigate({...P,from:m.pathname}),cause:i?"preload":m.cause,route:x},D=async()=>{var P,$,I,z,V,G,ie,te,pe,X;try{if(m.isFetching)E=(P=PE(this.state,m.id))==null?void 0:P.loadPromise;else{o[v]=m={...m,isFetching:!0,fetchCount:m.fetchCount+1};const ae=(($=x.lazyFn)==null?void 0:$.call(x).then(Ie=>{Object.assign(x.options,Ie.options)}))||Promise.resolve(),ue=ae.then(()=>Promise.all($G.map(async Ie=>{const Ae=x.options[Ie];Ae!=null&&Ae.preload&&await Ae.preload()}))),be=(z=(I=x.options).loader)==null?void 0:z.call(I,R);E=Promise.all([ue,be,ae]).then(Ie=>Ie[1])}o[v]=m={...m,loadPromise:E},u(m);const B=await E;if(l=n())return await l;if(_(B),C&&T&&await new Promise(ae=>setTimeout(ae,T)),l=n())return await l;const[K,se]=await Promise.all([(G=(V=x.options).meta)==null?void 0:G.call(V,{params:m.params,loaderData:B}),(te=(ie=x.options).headers)==null?void 0:te.call(ie,{loaderData:B})]);o[v]=m={...m,error:void 0,status:"success",isFetching:!1,updatedAt:Date.now(),loaderData:B,loadPromise:void 0,meta:K,headers:se}}catch(B){if(l=n())return await l;_(B);try{(X=(pe=x.options).onError)==null||X.call(pe,B)}catch(K){B=K,_(K)}o[v]=m={...m,error:B,status:"error",isFetching:!1}}u(m)},O=Date.now()-m.updatedAt;let H=i?x.options.preloadStaleTime??this.options.defaultPreloadStaleTime??3e4:x.options.staleTime??this.options.defaultStaleTime??0,N;const A=x.options.shouldReload;if(N=typeof A=="function"?A(R):A,o[v]=m={...m,preload:!!i&&!this.state.matches.find(P=>P.id===m.id)},m.status==="success"&&(m.invalid||(N??O>H)))return(async()=>{try{await D()}catch(P){console.info("Background Fetching Error",P),eo(P)&&((this.state.pendingMatches||this.state.matches).find($=>$.id===m.id),_(P),Vt(!1))}})(),S();const F=!i&&typeof k=="number"&&(x.options.pendingComponent??this.options.defaultPendingComponent);if(m.status!=="success")try{F&&((b=m.pendingPromise)==null||b.then(async()=>{if(l=n())return l;C=!0,o[v]=m={...m,showPending:!0},u(m),S()})),await D()}catch(P){y(P)}S()}))}),await Promise.all(h),o},this.invalidate=()=>{const n=r=>({...r,invalid:!0});this.__store.setState(r=>{var o;return{...r,matches:r.matches.map(n),cachedMatches:r.cachedMatches.map(n),pendingMatches:(o=r.pendingMatches)==null?void 0:o.map(n)}}),this.load()},this.load=async()=>{const n=new Promise(async(r,o)=>{const i=this.latestLocation,s=this.state.resolvedLocation,a=s.href!==i.href;let l;this.cancelMatches(),this.emit({type:"onBeforeLoad",fromLocation:s,toLocation:i,pathChanged:a});let c;const u=this.state.matches;this.__store.batch(()=>{this.cleanCache(),c=this.matchRoutes(i.pathname,i.search,{debug:!0}),this.__store.setState(d=>({...d,isLoading:!0,location:i,pendingMatches:c,cachedMatches:d.cachedMatches.filter(f=>!c.find(h=>h.id===f.id))}))});try{let d,f;try{await this.loadMatches({matches:c,location:i,checkLatest:()=>this.checkLatest(n)})}catch(S){eo(S)?(d=this.resolveRedirect(S),l6||this.navigate({...d,replace:!0})):ao(S)&&(f=S,this.handleNotFound(c,S))}if(l=this.checkLatest(n))return l;const h=u.filter(S=>!c.find(y=>y.id===S.id)),m=c.filter(S=>!u.find(y=>y.id===S.id)),v=u.filter(S=>c.find(y=>y.id===S.id));this.__store.batch(()=>{this.__store.setState(S=>({...S,isLoading:!1,matches:S.pendingMatches,pendingMatches:void 0,cachedMatches:[...S.cachedMatches,...h.filter(y=>y.status!=="error")],statusCode:d!=null&&d.statusCode||f?404:S.matches.some(y=>y.status==="error")?500:200,redirect:d})),this.cleanCache()}),[[h,"onLeave"],[m,"onEnter"],[v,"onStay"]].forEach(([S,y])=>{S.forEach(b=>{var w,x;(x=(w=this.looseRoutesById[b.routeId].options)[y])==null||x.call(w,b)})}),this.emit({type:"onLoad",fromLocation:s,toLocation:i,pathChanged:a}),r()}catch(d){if(l=this.checkLatest(n))return l;console.log("Load Error",d),o(d)}});return this.latestLoadPromise=n,this.latestLoadPromise},this.resolveRedirect=n=>{let r=n;return r.href||(r.href=this.buildLocation(r).href),r},this.cleanCache=()=>{this.__store.setState(n=>({...n,cachedMatches:n.cachedMatches.filter(r=>{const o=this.looseRoutesById[r.routeId];if(!o.options.loader)return!1;const i=(r.preload?o.options.preloadGcTime??this.options.defaultPreloadGcTime:o.options.gcTime??this.options.defaultGcTime)??5*60*1e3;return r.status!=="error"&&Date.now()-r.updatedAt{var r;let o=this.buildLocation(n),i=this.matchRoutes(o.pathname,o.search,{throwOnError:!0,preload:!0});const s=Object.fromEntries((r=[...this.state.matches,...this.state.pendingMatches??[],...this.state.cachedMatches])==null?void 0:r.map(a=>[a.id,!0]));this.__store.batch(()=>{i.forEach(a=>{s[a.id]||this.__store.setState(l=>({...l,cachedMatches:[...l.cachedMatches,a]}))})});try{return i=await this.loadMatches({matches:i,location:o,preload:!0,checkLatest:()=>{}}),i}catch(a){if(eo(a))return await this.preloadRoute(a);console.error(a);return}},this.matchRoute=(n,r)=>{const o={...n,to:n.to?this.resolvePathWithBase(n.from||"",n.to):void 0,params:n.params||{},leaveParams:!0},i=this.buildLocation(o);if(r!=null&&r.pending&&this.state.status!=="pending")return!1;const s=r!=null&&r.pending?this.latestLocation:this.state.resolvedLocation;if(!s)return!1;const a=vv(this.basepath,s.pathname,{...r,to:i.pathname});return!a||n.params&&!Tu(a,n.params,!0)?!1:a&&((r==null?void 0:r.includeSearch)??!0)?Tu(s.search,i.search,!0)?a:!1:a},this.injectHtml=async n=>{this.injectedHtml.push(n)},this.registeredDeferredsIds=new Map,this.registeredDeferreds=new WeakMap,this.getDeferred=n=>{const r=this.registeredDeferredsIds.get(n);if(r)return this.registeredDeferreds.get(r)},this.dehydrateData=(n,r)=>{if(typeof document>"u"){const o=typeof n=="string"?n:JSON.stringify(n);return this.injectHtml(async()=>{const i=`__TSR_DEHYDRATED__${o}`,s=typeof r=="function"?await r():r;return` + + + +
+ + diff --git a/cli/auth/authenticator.go b/cli/auth/authenticator.go new file mode 100644 index 00000000..0f9ef27a --- /dev/null +++ b/cli/auth/authenticator.go @@ -0,0 +1,91 @@ +package auth + +import ( + "context" + "net/http" + "time" + + "numerous/cli/keyring" + + "github.com/pkg/browser" +) + +const ( + numerousAuth0Domain string = "numerous.eu.auth0.com" + numerousAuth0ClientID string = "h5U41HhtgJ5OXdIvzi2Aw7VNFQMoLzgF" +) + +var NumerousTenantAuthenticator = NewTenantAuthenticator(numerousAuth0Domain, numerousAuth0ClientID) + +type Authenticator interface { + GetDeviceCode(ctx context.Context, client *http.Client) (DeviceCodeState, error) + OpenURL(url string) error + WaitUntilUserLogsIn(ctx context.Context, client *http.Client, state DeviceCodeState) (Result, error) + StoreAccessToken(token string) error + StoreRefreshToken(token string) error + GetLoggedInUserFromKeyring() *User + RemoveLoggedInUserFromKeyring() error + RegenerateAccessToken(client *http.Client, refreshToken string) (string, error) + RevokeRefreshToken(client *http.Client, refreshToken string) error +} + +type TenantAuthenticator struct { + tenant string + credentials Credentials +} + +func NewTenantAuthenticator(tenant string, clientID string) *TenantAuthenticator { + baseURL := "https://" + tenant + return &TenantAuthenticator{ + tenant: tenant, + credentials: Credentials{ + ClientID: clientID, + Audience: baseURL + "/api/v2/", + DeviceCodeEndpoint: baseURL + "/oauth/device/code/", + OauthTokenEndpoint: baseURL + "/oauth/token/", + RevokeTokenEndpoint: baseURL + "/oauth/revoke/", + }, + } +} + +func (t *TenantAuthenticator) GetDeviceCode(ctx context.Context, client *http.Client) (DeviceCodeState, error) { + return getDeviceCodeState(ctx, client, t.credentials) +} + +func (*TenantAuthenticator) OpenURL(url string) error { + return browser.OpenURL(url) +} + +func (t *TenantAuthenticator) WaitUntilUserLogsIn(ctx context.Context, client *http.Client, state DeviceCodeState) (Result, error) { + ticker := time.NewTicker(state.IntervalDuration()) + return waitUntilUserLogsIn(ctx, client, ticker, state.DeviceCode, t.credentials) +} + +func (t *TenantAuthenticator) StoreAccessToken(token string) error { + return keyring.StoreAccessToken(t.tenant, token) +} + +func (t *TenantAuthenticator) StoreRefreshToken(token string) error { + return keyring.StoreRefreshToken(t.tenant, token) +} + +func (t *TenantAuthenticator) GetLoggedInUserFromKeyring() *User { + return getLoggedInUserFromKeyring(t.tenant) +} + +func (t *TenantAuthenticator) RegenerateAccessToken(client *http.Client, refreshToken string) (string, error) { + token, err := refreshAccessToken(client, refreshToken, t.credentials) + if err != nil { + return "", err + } + + return token.AccessToken, nil +} + +func (t *TenantAuthenticator) RevokeRefreshToken(client *http.Client, refreshToken string) error { + return revokeRefreshToken(client, refreshToken, t.credentials) +} + +func (t *TenantAuthenticator) RemoveLoggedInUserFromKeyring() error { + return keyring.DeleteTokens(t.tenant) +} diff --git a/cli/auth/credentials.go b/cli/auth/credentials.go new file mode 100644 index 00000000..f33212d8 --- /dev/null +++ b/cli/auth/credentials.go @@ -0,0 +1,10 @@ +package auth + +// Credentials is used to facilitate the login process. +type Credentials struct { + Audience string + ClientID string + DeviceCodeEndpoint string + OauthTokenEndpoint string + RevokeTokenEndpoint string +} diff --git a/cli/auth/device_code_state.go b/cli/auth/device_code_state.go new file mode 100644 index 00000000..5aa90862 --- /dev/null +++ b/cli/auth/device_code_state.go @@ -0,0 +1,75 @@ +package auth + +import ( + "context" + "encoding/json" + "fmt" + "io" + "net/http" + "net/url" + "strings" + "time" +) + +const waitThresholdInSeconds = 3 + +type DeviceCodeState struct { + DeviceCode string `json:"device_code"` + UserCode string `json:"user_code"` + VerificationURI string `json:"verification_uri_complete"` + ExpiresIn int `json:"expires_in"` + Interval int `json:"interval"` +} + +func (s *DeviceCodeState) IntervalDuration() time.Duration { + return time.Duration(s.Interval+waitThresholdInSeconds) * time.Second +} + +var scope = []string{"openid", "profile", "offline_access", "email"} + +func getDeviceCodeState(ctx context.Context, httpClient *http.Client, c Credentials) (DeviceCodeState, error) { + data := url.Values{ + "client_id": []string{c.ClientID}, + "scope": []string{strings.Join(scope, " ")}, + "audience": []string{c.Audience}, + } + + request, err := http.NewRequestWithContext( + ctx, + http.MethodPost, + c.DeviceCodeEndpoint, + strings.NewReader(data.Encode()), + ) + if err != nil { + return DeviceCodeState{}, fmt.Errorf("failed to create the request: %w", err) + } + + request.Header.Set("Content-Type", "application/x-www-form-urlencoded") + + response, err := httpClient.Do(request) + if err != nil { + return DeviceCodeState{}, fmt.Errorf("failed to send the request: %w", err) + } + defer func() { + _ = response.Body.Close() + }() + + if response.StatusCode != http.StatusOK { + bodyBytes, err := io.ReadAll(response.Body) + if err != nil { + return DeviceCodeState{}, fmt.Errorf( + "received a %d response and failed to read the response", + response.StatusCode, + ) + } + + return DeviceCodeState{}, fmt.Errorf("received a %d response: %s", response.StatusCode, bodyBytes) + } + + var state DeviceCodeState + if err = json.NewDecoder(response.Body).Decode(&state); err != nil { + return DeviceCodeState{}, fmt.Errorf("failed to decode the response: %w", err) + } + + return state, nil +} diff --git a/cli/auth/device_code_state_test.go b/cli/auth/device_code_state_test.go new file mode 100644 index 00000000..5916428b --- /dev/null +++ b/cli/auth/device_code_state_test.go @@ -0,0 +1,80 @@ +package auth + +import ( + "bytes" + "context" + "io" + "net/http" + "testing" + "time" + + "numerous/cli/test" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestGetDeviceCode(t *testing.T) { + testTenant := NewTenantAuthenticator("numerous-test.com", "test-client-id") + t.Run("successfully retrieve state from response", func(t *testing.T) { + transport := &test.TestTransport{ + WithResponse: &http.Response{ + StatusCode: http.StatusOK, + Body: io.NopCloser(bytes.NewReader([]byte(`{ + "device_code": "device-code-here", + "user_code": "user-code-here", + "verification_uri_complete": "verification-uri-here", + "expires_in": 1000, + "interval": 1 + }`))), + }, + } + client := &http.Client{Transport: transport} + + state, err := testTenant.GetDeviceCode(context.Background(), client) + + require.NoError(t, err) + assert.Equal(t, "device-code-here", state.DeviceCode) + assert.Equal(t, "user-code-here", state.UserCode) + assert.Equal(t, "verification-uri-here", state.VerificationURI) + assert.Equal(t, 1000, state.ExpiresIn) + assert.Equal(t, 1, state.Interval) + assert.Equal(t, time.Duration(4000000000), state.IntervalDuration()) + }) + + testCases := []struct { + name string + httpStatus int + response string + expect string + }{ + { + name: "handle HTTP status errors", + httpStatus: http.StatusNotFound, + response: "Test response return", + expect: "received a 404 response: Test response return", + }, + { + name: "handle bad JSON response", + httpStatus: http.StatusOK, + response: "foo", + expect: "failed to decode the response: invalid character 'o' in literal false (expecting 'a')", + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + transport := &test.TestTransport{ + WithResponse: &http.Response{ + StatusCode: testCase.httpStatus, + Body: io.NopCloser(bytes.NewReader([]byte(testCase.response))), + }, + } + client := &http.Client{Transport: transport} + + _, err := testTenant.GetDeviceCode(context.Background(), client) + + assert.EqualError(t, err, testCase.expect) + }) + } +} diff --git a/cli/auth/refresh_access_token.go b/cli/auth/refresh_access_token.go new file mode 100644 index 00000000..0d3c5cad --- /dev/null +++ b/cli/auth/refresh_access_token.go @@ -0,0 +1,46 @@ +package auth + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "net/url" +) + +type TokenResponse struct { + AccessToken string `json:"access_token"` + IDToken string `json:"id_token"` + TokenType string `json:"token_type"` + ExpiresIn int `json:"expires_in"` +} + +func refreshAccessToken(httpClient *http.Client, refreshToken string, cred Credentials) (TokenResponse, error) { + r, err := httpClient.PostForm(cred.OauthTokenEndpoint, url.Values{ + "grant_type": {"refresh_token"}, + "client_id": {cred.ClientID}, + "refresh_token": {refreshToken}, + }) + if err != nil { + return TokenResponse{}, fmt.Errorf("cannot get a new access token from the refresh token: %w", err) + } + + defer func() { + _ = r.Body.Close() + }() + + if r.StatusCode != http.StatusOK { + b, _ := io.ReadAll(r.Body) + bodyStr := string(b) + + return TokenResponse{}, fmt.Errorf("cannot get a new access token from the refresh token: %s", bodyStr) + } + + var res TokenResponse + err = json.NewDecoder(r.Body).Decode(&res) + if err != nil { + return TokenResponse{}, fmt.Errorf("cannot decode response: %w", err) + } + + return res, nil +} diff --git a/cli/auth/refresh_access_token_test.go b/cli/auth/refresh_access_token_test.go new file mode 100644 index 00000000..8c4fe662 --- /dev/null +++ b/cli/auth/refresh_access_token_test.go @@ -0,0 +1,106 @@ +package auth + +import ( + "bytes" + "io" + "net/http" + "testing" + + "numerous/cli/test" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestRefeshAccessToken(t *testing.T) { + testCredentials := Credentials{ + Audience: "https://test.com/api/v2/", + ClientID: "client-id", + DeviceCodeEndpoint: "https://test.com/oauth/device/code", + OauthTokenEndpoint: "https://test.com/token", + } + t.Run("happy path", func(t *testing.T) { + transport := &test.TestTransport{ + WithResponse: &http.Response{ + StatusCode: http.StatusOK, + Body: io.NopCloser(bytes.NewReader([]byte(`{ + "access_token": "access-token-here", + "id_token": "id-token-here", + "token_type": "token-type-here", + "expires_in": 1000 + }`))), + }, + } + + client := &http.Client{Transport: transport} + + actualResponse, err := refreshAccessToken(client, "refresh-token-here", testCredentials) + require.NoError(t, err) + + expectedResponse := TokenResponse{ + AccessToken: "access-token-here", + IDToken: "id-token-here", + TokenType: "token-type-here", + ExpiresIn: 1000, + } + + assert.Equal(t, expectedResponse, actualResponse) + + req := transport.Requests[0] + err = req.ParseForm() + if err != nil { + t.Fatal(err) + } + + assert.Equal(t, "https://test.com/token", req.URL.String()) + assert.Equal(t, "refresh_token", req.Form["grant_type"][0]) + assert.Equal(t, "client-id", req.Form["client_id"][0]) + assert.Equal(t, "refresh-token-here", req.Form["refresh_token"][0]) + }) + + t.Run("Fails if empty refreshToken", func(t *testing.T) { + client := &http.Client{Transport: &test.TestTransport{}} + response, err := refreshAccessToken(client, "", testCredentials) + + require.Error(t, err) + assert.Equal(t, TokenResponse{}, response) + }) + + t.Run("Fails if post request returns error", func(t *testing.T) { + client := &http.Client{Transport: &test.TestTransport{WithError: http.ErrHandlerTimeout}} + response, err := refreshAccessToken(client, "refresh-token-here", testCredentials) + + require.Error(t, err) + assert.Equal(t, TokenResponse{}, response) + }) + + t.Run("Fails if http status is not http.OK", func(t *testing.T) { + transport := &test.TestTransport{ + WithResponse: &http.Response{ + StatusCode: http.StatusBadRequest, + Body: io.NopCloser(bytes.NewReader([]byte("Bad request"))), + }, + } + client := &http.Client{Transport: transport} + + response, err := refreshAccessToken(client, "refresh-token-here", testCredentials) + + require.Error(t, err) + assert.Equal(t, TokenResponse{}, response) + }) + + t.Run("Fails if body can't be decoded", func(t *testing.T) { + transport := &test.TestTransport{ + WithResponse: &http.Response{ + StatusCode: http.StatusOK, + Body: io.NopCloser(bytes.NewReader([]byte("Bad response"))), + }, + } + client := &http.Client{Transport: transport} + + response, err := refreshAccessToken(client, "refresh-token-here", testCredentials) + + require.Error(t, err) + assert.Equal(t, TokenResponse{}, response) + }) +} diff --git a/cli/auth/revoke_refresh_token.go b/cli/auth/revoke_refresh_token.go new file mode 100644 index 00000000..cb423585 --- /dev/null +++ b/cli/auth/revoke_refresh_token.go @@ -0,0 +1,49 @@ +package auth + +import ( + "encoding/json" + "errors" + "net/http" + "net/url" +) + +var ( + ErrInvalidRequest = errors.New("invalid request") + ErrInvalidClient = errors.New("invalid client") + ErrUnexpected = errors.New("unexpected error") +) + +type revokeResponse struct { + Error string `json:"error,omitempty"` + ErrorDescription string `json:"error_description,omitempty"` +} + +func revokeRefreshToken(httpClient *http.Client, refreshToken string, cred Credentials) error { + r, err := httpClient.PostForm(cred.RevokeTokenEndpoint, url.Values{ + "client_id": {cred.ClientID}, + "token": {refreshToken}, + }) + if err != nil { + return err + } + defer r.Body.Close() + + if r.StatusCode == http.StatusOK { + return nil + } + + res := revokeResponse{} + err = json.NewDecoder(r.Body).Decode(&res) + if err != nil { + return err + } + + switch res.Error { + case "invalid_request": + return ErrInvalidRequest + case "invalid_client": + return ErrInvalidClient + default: + return ErrUnexpected + } +} diff --git a/cli/auth/revoke_refresh_token_test.go b/cli/auth/revoke_refresh_token_test.go new file mode 100644 index 00000000..dd615a53 --- /dev/null +++ b/cli/auth/revoke_refresh_token_test.go @@ -0,0 +1,72 @@ +package auth + +import ( + "bytes" + "io" + "net/http" + "testing" + + "numerous/cli/test" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestRevokeRefreshToken(t *testing.T) { + testTenant := NewTenantAuthenticator("numerous-test.com", "test-client-id") + t.Run("successfully revoke token", func(t *testing.T) { + transport := &test.TestTransport{ + WithResponse: &http.Response{ + StatusCode: http.StatusOK, + Body: io.NopCloser(bytes.NewReader([]byte(""))), + }, + } + client := &http.Client{Transport: transport} + + err := testTenant.RevokeRefreshToken(client, "some-token") + + require.NoError(t, err) + }) + + t.Run("handles invalid request", func(t *testing.T) { + transport := &test.TestTransport{ + WithResponse: &http.Response{ + StatusCode: http.StatusBadRequest, + Body: io.NopCloser(bytes.NewReader([]byte(`{"error":"invalid_request","error_description":"request was bad"}`))), + }, + } + client := &http.Client{Transport: transport} + + err := testTenant.RevokeRefreshToken(client, "some-token") + + assert.ErrorIs(t, err, ErrInvalidRequest) + }) + + t.Run("handles invalid client", func(t *testing.T) { + transport := &test.TestTransport{ + WithResponse: &http.Response{ + StatusCode: http.StatusUnauthorized, + Body: io.NopCloser(bytes.NewReader([]byte(`{"error":"invalid_client","error_description":"client was bad"}`))), + }, + } + client := &http.Client{Transport: transport} + + err := testTenant.RevokeRefreshToken(client, "some-token") + + assert.ErrorIs(t, err, ErrInvalidClient) + }) + + t.Run("handles unexpected error", func(t *testing.T) { + transport := &test.TestTransport{ + WithResponse: &http.Response{ + StatusCode: http.StatusBadGateway, + Body: io.NopCloser(bytes.NewReader([]byte(`{"error":"something","error_description":"something unexpected was bad"}`))), + }, + } + client := &http.Client{Transport: transport} + + err := testTenant.RevokeRefreshToken(client, "some-token") + + assert.ErrorIs(t, err, ErrUnexpected) + }) +} diff --git a/cli/auth/user.go b/cli/auth/user.go new file mode 100644 index 00000000..4c83ee71 --- /dev/null +++ b/cli/auth/user.go @@ -0,0 +1,88 @@ +package auth + +import ( + "errors" + "fmt" + "time" + + "numerous/cli/keyring" + + "github.com/lestrrat-go/jwx/jwt" +) + +var ( + // ErrUserNotLoggedIn is thrown when there is not Access or Refresh Token + ErrUserNotLoggedIn = errors.New("user is logged in") + ErrInvalidToken = errors.New("token is invalid") + ErrExpiredToken = errors.New("token is expired") +) + +type User struct { + AccessToken string + RefreshToken string + Tenant string +} + +func getLoggedInUserFromKeyring(tenant string) *User { + a, accessTokenErr := keyring.GetAccessToken(tenant) + r, refreshTokenErr := keyring.GetRefreshToken(tenant) + if accessTokenErr != nil || refreshTokenErr != nil { + return nil + } + + return &User{ + AccessToken: a, + RefreshToken: r, + Tenant: tenant, + } +} + +func (u *User) extractToken() (jwt.Token, error) { + token, err := jwt.ParseString(u.AccessToken) + if err != nil { + return nil, err + } + + return token, nil +} + +func (u *User) CheckAuthenticationStatus() error { + if u == nil || u.AccessToken == "" { + return ErrUserNotLoggedIn + } + + if token, err := u.extractToken(); err != nil { + return ErrInvalidToken + } else if err := validateToken(token, u.Tenant); err != nil { + return err + } + + return nil +} + +func (u *User) HasExpiredToken() bool { + token, _ := u.extractToken() + return tokenExpired(token) +} + +func validateToken(t jwt.Token, tenantName string) error { + err := jwt.Validate(t, jwt.WithIssuer(fmt.Sprintf("https://%s/", tenantName))) + switch err { + case jwt.ErrTokenExpired(): + return ErrExpiredToken + case jwt.ErrInvalidIssuedAt(): + return ErrInvalidToken + case nil: + return nil + default: + return err + } +} + +func tokenExpired(t jwt.Token) bool { + if t == nil { + return false + } + + return time.Now().After(t.Expiration()) +} diff --git a/cli/auth/user_test.go b/cli/auth/user_test.go new file mode 100644 index 00000000..e2bd5d1e --- /dev/null +++ b/cli/auth/user_test.go @@ -0,0 +1,114 @@ +package auth + +import ( + "fmt" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + goKeyring "github.com/zalando/go-keyring" + + "numerous/cli/keyring" + "numerous/cli/test" +) + +func TestUser(t *testing.T) { + const testTenant string = "numerous-test.eu.com" + testIssuer := fmt.Sprintf("https://%s/", testTenant) + t.Run("Can get logged in user, based on keyring", func(t *testing.T) { + goKeyring.MockInit() + expectedUser := User{ + AccessToken: "access-token", + RefreshToken: "refresh-token", + Tenant: testTenant, + } + storeTestTokens(t, testTenant, expectedUser.AccessToken, expectedUser.RefreshToken) + + actualUser := getLoggedInUserFromKeyring(testTenant) + + assert.Equal(t, expectedUser, *actualUser) + }) + + t.Run("Cannot get logged in user, if nothing is in keyring", func(t *testing.T) { + goKeyring.MockInit() + + actualUser := getLoggedInUserFromKeyring(testTenant) + + assert.Nil(t, actualUser) + }) + + t.Run("CheckAuthenticationStatus when user is logged in with wrong issuer returns error", func(t *testing.T) { + goKeyring.MockInit() + + accessToken := test.GenerateJWT(t, "https://bad-issuer.com/", time.Now().Add(time.Hour)) + storeTestTokens(t, testTenant, accessToken, "refresh-token") + + user := getLoggedInUserFromKeyring(testTenant) + actualError := user.CheckAuthenticationStatus() + + require.EqualError(t, actualError, "\"iss\" not satisfied: values do not match") + }) + + t.Run("CheckAuthenticationStatus with expired accessToken returns error", func(t *testing.T) { + goKeyring.MockInit() + + accessToken := test.GenerateJWT(t, testIssuer, time.Now().Add(-time.Hour)) + storeTestTokens(t, testTenant, accessToken, "refresh-token") + + user := getLoggedInUserFromKeyring(testTenant) + actualError := user.CheckAuthenticationStatus() + + require.EqualError(t, actualError, ErrExpiredToken.Error()) + }) + + t.Run("CheckAuthenticationStatus when user is logged in returns nil", func(t *testing.T) { + goKeyring.MockInit() + + accessToken := test.GenerateJWT(t, testIssuer, time.Now().Add(time.Hour)) + storeTestTokens(t, testTenant, accessToken, "refresh-token") + + user := getLoggedInUserFromKeyring(testTenant) + actualError := user.CheckAuthenticationStatus() + + require.NoError(t, actualError) + }) + + hasExpiredTestCases := []struct { + name string + expiration time.Time + expectedHasExpired bool + }{ + { + name: "User.HasExpired returns false when expiration of token is after current time", + expiration: time.Now().Add(2 * time.Hour), + expectedHasExpired: false, + }, + { + name: "User.HasExpired returns true when expiration of token is before current time", + expiration: time.Now().Add(-2 * time.Hour), + expectedHasExpired: true, + }, + } + for _, testCase := range hasExpiredTestCases { + t.Run(testCase.name, func(t *testing.T) { + goKeyring.MockInit() + + accessToken := test.GenerateJWT(t, testIssuer, testCase.expiration) + user := User{ + AccessToken: accessToken, + RefreshToken: "refresh-token", + } + + assert.Equal(t, testCase.expectedHasExpired, user.HasExpiredToken()) + }) + } +} + +func storeTestTokens(t *testing.T, tenant, accessToken, refreshToken string) { + t.Helper() + err := keyring.StoreAccessToken(tenant, accessToken) + require.NoError(t, err) + err = keyring.StoreRefreshToken(tenant, refreshToken) + require.NoError(t, err) +} diff --git a/cli/auth/wait_until_user_logs_in.go b/cli/auth/wait_until_user_logs_in.go new file mode 100644 index 00000000..3cef48a3 --- /dev/null +++ b/cli/auth/wait_until_user_logs_in.go @@ -0,0 +1,89 @@ +package auth + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "net/http" + "net/url" + "time" + + "github.com/lestrrat-go/jwx/jwt" +) + +type Result struct { + IDToken string + AccessToken string + RefreshToken string + ExpiresAt time.Time +} + +// waitUntilUserLogsIn waits until the user is logged in on the browser. +func waitUntilUserLogsIn(ctx context.Context, httpClient *http.Client, t *time.Ticker, deviceCode string, cred Credentials) (Result, error) { + for { + select { + case <-ctx.Done(): + return Result{}, ctx.Err() + case <-t.C: + data := url.Values{ + "client_id": []string{cred.ClientID}, + "grant_type": []string{"urn:ietf:params:oauth:grant-type:device_code"}, + "device_code": []string{deviceCode}, + } + r, err := httpClient.PostForm(cred.OauthTokenEndpoint, data) + if err != nil { + return Result{}, fmt.Errorf("cannot get device code: %w", err) + } + defer func() { + _ = r.Body.Close() + }() + + var res struct { + AccessToken string `json:"access_token"` + IDToken string `json:"id_token"` + RefreshToken string `json:"refresh_token"` + Scope string `json:"scope"` + ExpiresIn int64 `json:"expires_in"` + TokenType string `json:"token_type"` + Error *string `json:"error,omitempty"` + ErrorDescription string `json:"error_description,omitempty"` + } + + err = json.NewDecoder(r.Body).Decode(&res) + if err != nil { + return Result{}, fmt.Errorf("cannot decode response: %w", err) + } + + if res.Error != nil { + if *res.Error == "authorization_pending" { + continue + } + + return Result{}, errors.New(res.ErrorDescription) + } + + if err := validateAccessToken(res.AccessToken); err != nil { + return Result{}, err + } + + return Result{ + RefreshToken: res.RefreshToken, + AccessToken: res.AccessToken, + IDToken: res.IDToken, + ExpiresAt: time.Now().Add( + time.Duration(res.ExpiresIn) * time.Second, + ), + }, nil + } + } +} + +func validateAccessToken(accessToken string) error { + _, err := jwt.ParseString(accessToken) + if err != nil { + return err + } + + return nil +} diff --git a/cli/auth/wait_until_user_logs_in_test.go b/cli/auth/wait_until_user_logs_in_test.go new file mode 100644 index 00000000..03bc1337 --- /dev/null +++ b/cli/auth/wait_until_user_logs_in_test.go @@ -0,0 +1,117 @@ +package auth + +import ( + "bytes" + "context" + "fmt" + "io" + "net/http" + "testing" + "time" + + "numerous/cli/test" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" +) + +func TestWaitUntilUserLogsIn(t *testing.T) { + ticker := time.NewTicker(time.Millisecond) + deviceCode := "1234" + initialOauthTokenEndpoint := "https://test.com/token" + testCredentials := Credentials{ + Audience: "https://test.com/api/v2/", + ClientID: "client-id", + DeviceCodeEndpoint: "https://test.com/oauth/device/code", + OauthTokenEndpoint: initialOauthTokenEndpoint, + } + t.Run("successfully waits and handles response", func(t *testing.T) { + validToken := test.GenerateJWT(t, "https://test.com/", time.Now()) // d + tokenResponse := fmt.Sprintf(`{ + "access_token": "%s", + "id_token": "id-token-here", + "refresh_token": "refresh-token-here", + "scope": "scope-here", + "token_type": "token-type-here", + "expires_in": 1000 + }`, validToken) + + pendingResponse := `{ + "error": "authorization_pending", + "error_description": "still pending auth" + }` + + ts := test.MockTransport{} + ts.On("RoundTrip", mock.Anything).Once().Return( + &http.Response{ + StatusCode: http.StatusForbidden, + Body: io.NopCloser(bytes.NewReader([]byte(pendingResponse))), + }, + nil, + ) + ts.On("RoundTrip", mock.Anything).Return( + &http.Response{ + StatusCode: http.StatusOK, + Body: io.NopCloser(bytes.NewReader([]byte(tokenResponse))), + }, + nil, + ) + client := &http.Client{Transport: &ts} + + actualResult, err := waitUntilUserLogsIn(context.Background(), client, ticker, deviceCode, testCredentials) + + expectedResult := Result{ + AccessToken: validToken, + RefreshToken: "refresh-token-here", + IDToken: "id-token-here", + } + + require.NoError(t, err) + assert.Equal(t, expectedResult.AccessToken, actualResult.AccessToken) + assert.Equal(t, expectedResult.RefreshToken, actualResult.RefreshToken) + assert.Equal(t, expectedResult.IDToken, actualResult.IDToken) + }) + + testCases := []struct { + name string + httpStatus int + response string + expect string + }{ + { + name: "handle malformed JSON", + httpStatus: http.StatusOK, + response: "foo", + expect: "cannot decode response: invalid character 'o' in literal false (expecting 'a')", + }, + { + name: "should pass through authorization server errors", + httpStatus: http.StatusOK, + response: "{\"error\": \"slow_down\", \"error_description\": \"slow down!\"}", + expect: "slow down!", + }, + { + name: "should error if can't parse as JWT", + httpStatus: http.StatusOK, + response: "{\"access_token\": \"bad.token\"}", + expect: "failed to parse token: invalid character 'b' looking for beginning of value", + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + transport := &test.TestTransport{ + WithResponse: &http.Response{ + StatusCode: http.StatusOK, + Body: io.NopCloser(bytes.NewReader([]byte(testCase.response))), + }, + } + client := &http.Client{Transport: transport} + + _, err := waitUntilUserLogsIn(context.Background(), client, ticker, deviceCode, testCredentials) + + assert.EqualError(t, err, testCase.expect) + }) + } +} diff --git a/cli/cmd/delete/delete.go b/cli/cmd/delete/delete.go new file mode 100644 index 00000000..02ab4c99 --- /dev/null +++ b/cli/cmd/delete/delete.go @@ -0,0 +1,74 @@ +package deleteapp + +import ( + "errors" + "fmt" + "os" + + "numerous/cli/internal/gql" + "numerous/cli/internal/gql/app" + "numerous/cli/tool" + + "git.sr.ht/~emersion/gqlclient" + "github.com/spf13/cobra" +) + +var DeleteCmd = &cobra.Command{ + Use: "delete [app ID]", + Short: "Deletes the app and removes its associated resources", + Long: `Removes the app from the server and deletes any associated resources, such as docker images or containers. +This action cannot be undone.`, + Run: func(cmd *cobra.Command, args []string) { + err := deleteApp(gql.GetClient(), args) + if err != nil { + os.Exit(1) + } + }, +} + +func deleteApp(client *gqlclient.Client, args []string) error { + var appID string + var err error + + if len(args) == 1 { + appID = args[0] + } else { + appID, err = tool.ReadToolID(".") + if err == tool.ErrToolIDNotFound { + fmt.Println("Sorry, we could not recognize your app in the specified directory.", + "\nRun \"numerous init\" to initialize the app in Numerous.") + + return err + } else if err != nil { + fmt.Println("Whoops! An error occurred when reading the app ID. \n Please make sure you are in the correct directory and try again.") + fmt.Println("Error: ", err) + + return err + } + } + + if _, err := app.Query(appID, client); err != nil { + fmt.Println( + "Sorry, we could not find the app in our database. \nPlease, make sure that the App ID in the .tool_id.txt file is correct and try again.") + + return err + } + + if result, err := app.Delete(appID, client); err != nil { + fmt.Println("An error occurred while removing the app from Numerous. Please try again.") + fmt.Println("Error: ", err) + + return err + } else { + if result.ToolDelete.Typename == "ToolDeleteSuccess" { + fmt.Println("The app has been successfully removed from Numerous") + } else if result.ToolDelete.Typename == "ToolDeleteFailure" { + fmt.Println("An error occurred while removing the app from Numerous. Please try again.") + fmt.Println("Error: ", result.ToolDelete.Result) + + return errors.New(result.ToolDelete.Result) + } + + return nil + } +} diff --git a/cli/cmd/delete/delete_test.go b/cli/cmd/delete/delete_test.go new file mode 100644 index 00000000..f97a65ee --- /dev/null +++ b/cli/cmd/delete/delete_test.go @@ -0,0 +1,46 @@ +package deleteapp + +import ( + "testing" + + "numerous/cli/internal/gql/app" + "numerous/cli/test" + + "github.com/stretchr/testify/assert" +) + +func TestAppDelete(t *testing.T) { + t.Run("returns nil and successfully sends AppDelete mutations", func(t *testing.T) { + test.ChdirToTmpDirWithAppIDDocument(t, "id") + response, _ := test.DeleteSuccessQueryResult() + app := app.App{ + ID: "id", + SharedURL: "https://test.com/shared/some-hash", + PublicURL: "https://test.com/public/another-hash", + } + appQueryResponse := test.AppToQueryResult("tool", app) + c, transportMock := test.CreateMockGqlClient(appQueryResponse, response) + err := deleteApp(c, []string{}) + assert.NoError(t, err) + transportMock.AssertExpectations(t) + }) + t.Run("returns error if app does not exist", func(t *testing.T) { + test.ChdirToTmpDirWithAppIDDocument(t, "id") + appNotFoundResponse := `"record not found"` + response, _ := test.DeleteFailureQueryResult(appNotFoundResponse) + c, transportMock := test.CreateMockGqlClient(response) + + err := deleteApp(c, []string{}) + + assert.Error(t, err) + transportMock.AssertExpectations(t) + }) + + t.Run("returns error if app id document does not exists in the current directory", func(t *testing.T) { + c, transportMock := test.CreateMockGqlClient() + err := deleteApp(c, []string{}) + + assert.Error(t, err) + transportMock.AssertExpectations(t) + }) +} diff --git a/cli/cmd/dev/dev.go b/cli/cmd/dev/dev.go new file mode 100644 index 00000000..e77aff3e --- /dev/null +++ b/cli/cmd/dev/dev.go @@ -0,0 +1,73 @@ +package dev + +import ( + "errors" + "fmt" + "strings" + + "numerous/cli/appdevsession" + + "github.com/spf13/cobra" +) + +type AppLocation struct { + ModulePath string + ClassName string +} + +var ( + port string + pythonInterpreter string + appLocation AppLocation +) + +var DevCmd = &cobra.Command{ + Use: "dev MODULE:CLASS", + Run: dev, + Short: "Develop and run numerous app engine apps locally.", + Args: func(cmd *cobra.Command, args []string) error { + if len(args) == 0 { + return errors.New("an app module and class must be specified") + } else if len(args) > 1 { + return errors.New("too many arguments. only one app can be specified") + } + + parsedAppLocation, err := parseAppLocation(args[0]) + if err != nil { + return err + } + + appLocation = parsedAppLocation + + return nil + }, +} + +func parseAppLocation(s string) (AppLocation, error) { + var location AppLocation + parts := strings.Split(s, ":") + allowedNumberOfParts := 2 + if len(parts) != allowedNumberOfParts { + return location, fmt.Errorf("invalid app location '%s', there must be exactly 1 ':'", s) + } else { + location.ModulePath = parts[0] + location.ClassName = parts[1] + + return location, nil + } +} + +func dev(cmd *cobra.Command, args []string) { + appdevsession.CreateAndRunDevSession(pythonInterpreter, appLocation.ModulePath, appLocation.ClassName, port) +} + +func init() { + flags := DevCmd.Flags() + flags.StringVar(&port, "port", "7001", "The GraphQL Port") + flags.StringVar( + &pythonInterpreter, + "python", + "python", + "Path to the python interpreter, eg. \"python\", or \"./venv/bin/python\"", + ) +} diff --git a/cli/cmd/initialize/bootstrap_files.go b/cli/cmd/initialize/bootstrap_files.go new file mode 100644 index 00000000..aebaf021 --- /dev/null +++ b/cli/cmd/initialize/bootstrap_files.go @@ -0,0 +1,93 @@ +package initialize + +import ( + "bytes" + "fmt" + "io/fs" + "os" + "path/filepath" + + "numerous/cli/assets" + "numerous/cli/manifest" + "numerous/cli/tool" +) + +func bootstrapFiles(t tool.Tool, toolID string, basePath string) (err error) { + manifestToml, err := manifest.FromTool(t).ToToml() + if err != nil { + fmt.Println("Error encoding manifest file") + + return err + } + + println("bootstrapping files in", basePath) + + err = createToolIDFile(basePath, toolID) + if err != nil { + return err + } + if err = addToGitIgnore(basePath, "# added by numerous init\n"+tool.ToolIDFileName); err != nil { + return err + } + + if err = CreateAndWriteIfFileNotExist(filepath.Join(basePath, t.AppFile), t.Library.DefaultAppFile()); err != nil { + return err + } + + for _, path := range []string{t.RequirementsFile} { + if err = createFile(filepath.Join(basePath, path)); err != nil { + return err + } + } + if err := bootstrapRequirements(t, basePath); err != nil { + return err + } + if err = assets.CopyToolPlaceholderCover(filepath.Join(basePath, t.CoverImage)); err != nil { + return err + } + + if err = CreateAndWriteIfFileNotExist(filepath.Join(basePath, manifest.ManifestPath), manifestToml); err != nil { + return err + } + + return nil +} + +func bootstrapRequirements(t tool.Tool, basePath string) error { + requirementsPath := filepath.Join(basePath, t.RequirementsFile) + content, err := os.ReadFile(requirementsPath) + if err != nil { + return err + } + var filePermission fs.FileMode = 0o600 + file, err := os.OpenFile(requirementsPath, os.O_APPEND|os.O_WRONLY, filePermission) + if err != nil { + return err + } + defer file.Close() + + for _, requirement := range t.Library.Requirements { + if err := addRequirementToFile(file, content, requirement); err != nil { + return err + } + } + + return nil +} + +func addRequirementToFile(f *os.File, content []byte, requirement string) error { + if bytes.Contains(content, []byte(requirement)) { + return nil + } + + // If it comes after content without newline, add newline + if len(content) != 0 && !bytes.HasSuffix(content, []byte("\n")) { + requirement = "\n" + requirement + } + + if _, err := f.WriteString(requirement + "\n"); err != nil { + return err + } + + return nil +} diff --git a/cli/cmd/initialize/bootstrap_files_test.go b/cli/cmd/initialize/bootstrap_files_test.go new file mode 100644 index 00000000..b169c7b9 --- /dev/null +++ b/cli/cmd/initialize/bootstrap_files_test.go @@ -0,0 +1,212 @@ +package initialize + +import ( + "os" + "strings" + "testing" + + "numerous/cli/manifest" + "numerous/cli/tool" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +type filesNotReadError struct { + files []string +} + +func (f *filesNotReadError) Error() string { + return "Could not read the following files:" + "\n[\n" + strings.Join(f.files, ",\n") + "\n]\n" +} + +func allFilesExist(fileNames []string) error { + filesNotRead := []string{} + + for _, fileName := range fileNames { + _, err := os.Stat(fileName) + if err != nil { + filesNotRead = append(filesNotRead, fileName) + } + } + + if len(filesNotRead) == 0 { + return nil + } + + return &filesNotReadError{files: filesNotRead} +} + +func TestBootstrapAllFiles(t *testing.T) { + tempDir := t.TempDir() + require.NoError(t, os.Chdir(tempDir)) + lib, err := tool.GetLibraryByKey("streamlit") + require.NoError(t, err) + testTool := tool.Tool{ + Library: lib, + AppFile: "app.py", + RequirementsFile: "requirements.txt", + CoverImage: "cover_image.png", + } + expectedFiles := []string{ + ".gitignore", + manifest.ManifestFileName, + testTool.AppFile, + testTool.RequirementsFile, + testTool.CoverImage, + } + + err = bootstrapFiles(testTool, "some-id", tempDir) + + if assert.NoError(t, err) { + err = allFilesExist(expectedFiles) + assert.NoError(t, err) + } +} + +func TestBootstrapRequirementsFile(t *testing.T) { + var ( + dummyRequirementsWithoutNewLine = strings.Join([]string{"some", "different", "dependencies=2.0.0"}, "\n") + dummyRequirementsWithNewLine = dummyRequirementsWithoutNewLine + "\n" + ) + + testCases := []struct { + name string + library tool.Library + initialRequirements string + expectedRequirements string + }{ + { + name: "plotly-dash without initial requirements", + library: tool.LibraryPlotlyDash, + initialRequirements: "", + expectedRequirements: "dash\ngunicorn\n", + }, + { + name: "streamlit without initial requirements", + library: tool.LibraryStreamlit, + initialRequirements: "", + expectedRequirements: "streamlit\n", + }, + { + name: "marimo without initial requirements", + library: tool.LibraryMarimo, + initialRequirements: "", + expectedRequirements: "marimo\n", + }, + { + name: "numerous without initial requirements", + library: tool.LibraryNumerous, + initialRequirements: "", + expectedRequirements: "numerous\n", + }, + { + name: "marimo with initial requirements with newline appends at end", + library: tool.LibraryMarimo, + initialRequirements: dummyRequirementsWithNewLine, + expectedRequirements: dummyRequirementsWithNewLine + "marimo\n", + }, + { + name: "marimo with initial requirements without newline appends at end", + library: tool.LibraryMarimo, + initialRequirements: dummyRequirementsWithoutNewLine, + expectedRequirements: dummyRequirementsWithNewLine + "marimo\n", + }, + { + name: "marimo with initial requirements and library is part of requirements, nothing changes", + library: tool.LibraryMarimo, + initialRequirements: "marimo\n" + dummyRequirementsWithNewLine, + expectedRequirements: "marimo\n" + dummyRequirementsWithNewLine, + }, + } + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + tempDir := t.TempDir() + require.NoError(t, os.Chdir(tempDir)) + testTool := tool.Tool{ + Library: testCase.library, + AppFile: "app.py", + RequirementsFile: "requirements.txt", + CoverImage: "cover_image.png", + } + if testCase.initialRequirements != "" { + err := os.WriteFile(testTool.RequirementsFile, []byte(testCase.initialRequirements), 0o644) + require.NoError(t, err) + } + + err := bootstrapFiles(testTool, "some-id", tempDir) + + require.NoError(t, err) + actualRequirements, err := os.ReadFile(testTool.RequirementsFile) + require.NoError(t, err) + assert.Equal(t, testCase.expectedRequirements, string(actualRequirements)) + }) + } +} + +var expectedNumerousApp string = ` +from numerous import action, app, slider + + +@app +class MyApp: + count: float + step: float = slider(min_value=0, max_value=10) + + @action + def increment(self) -> None: + self.count += self.step + + +appdef = MyApp +` + +func TestBootstrapAppFile(t *testing.T) { + testCases := []struct { + name string + library tool.Library + expectedAppFile string + }{ + { + name: "numerous", + library: tool.LibraryNumerous, + expectedAppFile: expectedNumerousApp, + }, + { + name: "streamlit", + library: tool.LibraryStreamlit, + expectedAppFile: "", + }, + { + name: "dash", + library: tool.LibraryPlotlyDash, + expectedAppFile: "", + }, + { + name: "marimo", + library: tool.LibraryMarimo, + expectedAppFile: "", + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + require.NoError(t, os.Chdir(t.TempDir())) + testTool := tool.Tool{ + Library: testCase.library, + AppFile: "app.py", + RequirementsFile: "requirements.txt", + CoverImage: "cover_image.png", + } + tempDir, err := os.Getwd() + require.NoError(t, err) + + err = bootstrapFiles(testTool, "tool id", tempDir) + + require.NoError(t, err) + appContent, err := os.ReadFile("app.py") + require.NoError(t, err) + assert.Equal(t, testCase.expectedAppFile, string(appContent)) + }) + } +} diff --git a/cli/cmd/initialize/files.go b/cli/cmd/initialize/files.go new file mode 100644 index 00000000..c040ff59 --- /dev/null +++ b/cli/cmd/initialize/files.go @@ -0,0 +1,99 @@ +package initialize + +import ( + "errors" + "fmt" + "os" + "path/filepath" + + "numerous/cli/tool" +) + +// Creates file if it does not exists +func createFile(path string) error { + if _, err := os.Stat(path); errors.Is(err, os.ErrNotExist) { + // file does not exist, create it + file, err := os.Create(path) + if err != nil { + return err + } + defer file.Close() + } else if err != nil { + return err + } + + return nil +} + +func CreateAndWriteIfFileNotExist(path string, content string) error { + _, err := os.Stat(path) + if err == nil { + fmt.Printf("Skipping creation of app file: %s already exists\n", path) + return nil + } + + if !errors.Is(err, os.ErrNotExist) { + return err + } + + file, err := os.Create(path) + if err != nil { + return err + } + + defer file.Close() + + _, err = file.WriteString(content) + if err != nil { + fmt.Printf("Could not write to %s\n", path) + } + + return nil +} + +// Writes content to a specific path +func writeOrAppendFile(path string, content string) error { + file, err := os.OpenFile(path, os.O_APPEND|os.O_WRONLY, os.ModeAppend) + if err != nil { + fmt.Printf("Could not open '%s'\n", path) + return err + } + defer file.Close() + + fileStat, err := file.Stat() + if err != nil { + fmt.Printf("Could not determine file size of '%s'\n", path) + return err + } else if fileStat.Size() != 0 { + content = "\n" + content + } + + _, err = file.WriteString(content) + if err != nil { + fmt.Printf("Could not write to '%s'\n", path) + } + + return nil +} + +// Generates and creates file containing the tools id +func createToolIDFile(path string, id string) error { + toolFile := filepath.Join(path, tool.ToolIDFileName) + if err := createFile(toolFile); err != nil { + fmt.Printf("Error creating tool id file\nError: %s", err) + return err + } + + return writeOrAppendFile(toolFile, id) +} + +// Creates and adds the item to .gitignore +func addToGitIgnore(path string, toIgnore string) error { + gitignorePath := filepath.Join(path, ".gitignore") + if err := createFile(gitignorePath); err != nil { + fmt.Println("Error creating .gitignore") + return err + } + + return writeOrAppendFile(gitignorePath, toIgnore) +} diff --git a/cli/cmd/initialize/files_test.go b/cli/cmd/initialize/files_test.go new file mode 100644 index 00000000..e50fb4d6 --- /dev/null +++ b/cli/cmd/initialize/files_test.go @@ -0,0 +1,144 @@ +package initialize + +import ( + "os" + "path/filepath" + "testing" + + "numerous/cli/tool" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +const mockGitIgnore string = ` +some.txt +*.go +another.yaml` + +const expectedGitIgnore string = ` +some.txt +*.go +another.yaml +.tool_id.txt` + +func TestCreateToolIdFile(t *testing.T) { + testPath := t.TempDir() + err := os.Chdir(testPath) + require.NoError(t, err) + toolIDPath := filepath.Join(testPath, tool.ToolIDFileName) + toolID := "some-id" + + err = createToolIDFile(testPath, toolID) + + if assert.NoError(t, err) { + toolIDContent, err := os.ReadFile(toolIDPath) + if assert.NoError(t, err) { + actualID := string(toolIDContent) + assert.Equal(t, toolID, actualID) + } + } +} + +func TestAddToolIdFileToGitIgnore(t *testing.T) { + t.Run("Adds if .gitignore exists", func(t *testing.T) { + testPath := t.TempDir() + err := os.Chdir(testPath) + require.NoError(t, err) + gitignorePath := filepath.Join(testPath, ".gitignore") + + file, err := os.Create(gitignorePath) + require.NoError(t, err) + _, err = file.WriteString(mockGitIgnore) + require.NoError(t, err) + require.NoError(t, file.Close()) + + err = addToGitIgnore(testPath, tool.ToolIDFileName) + + if assert.NoError(t, err) { + fileContentInBytes, err := os.ReadFile(gitignorePath) + if assert.NoError(t, err) { + assert.Equal(t, expectedGitIgnore, string(fileContentInBytes)) + } + } + }) + + t.Run("Creates and adds if .gitignore does not exists", func(t *testing.T) { + testPath := t.TempDir() + err := os.Chdir(testPath) + require.NoError(t, err) + gitignorePath := filepath.Join(testPath, ".gitignore") + require.NoFileExists(t, gitignorePath) + + err = addToGitIgnore(testPath, tool.ToolIDFileName) + + if assert.NoError(t, err) { + fileContentInBytes, err := os.ReadFile(gitignorePath) + if assert.NoError(t, err) { + assert.Equal(t, tool.ToolIDFileName, string(fileContentInBytes)) + } + } + }) +} + +func TestWriteFiles(t *testing.T) { + expectedContent := "some text input" + + t.Run("Can write to existing file", func(t *testing.T) { + filePath := filepath.Join(t.TempDir(), "test_file.txt") + file, err := os.Create(filePath) + require.NoError(t, err) + require.NoError(t, file.Close()) + + err = writeOrAppendFile(filePath, expectedContent) + + if assert.NoError(t, err) { + actualContent, err := os.ReadFile(filePath) + if assert.NoError(t, err) { + assert.Equal(t, expectedContent, string(actualContent)) + } + } + }) + + t.Run("Returns error if file does not exist", func(t *testing.T) { + filePath := filepath.Join(t.TempDir(), "test_file.txt") + file, err := os.Create(filePath) + require.NoError(t, err) + require.NoError(t, file.Close()) + + err = writeOrAppendFile(filePath, expectedContent) + + assert.NoError(t, err) + }) +} + +func TestCreateFile(t *testing.T) { + t.Run("Can create file if it does not exist", func(t *testing.T) { + filePath := filepath.Join(t.TempDir(), "test_file.txt") + require.NoFileExists(t, filePath) + + err := createFile(filePath) + + if assert.NoError(t, err) { + assert.FileExists(t, filePath) + } + }) + + t.Run("Does nothing if file exists", func(t *testing.T) { + filePath := filepath.Join(t.TempDir(), "test_file.txt") + expectedContent := "some content" + f, err := os.Create(filePath) + require.NoError(t, err) + _, err = f.WriteString(expectedContent) + require.NoError(t, err) + + err = createFile(filePath) + + if assert.NoError(t, err) { + actualContent, err := os.ReadFile(filePath) + if assert.NoError(t, err) { + assert.Equal(t, expectedContent, string(actualContent)) + } + } + }) +} diff --git a/cli/cmd/initialize/get_python_version.go b/cli/cmd/initialize/get_python_version.go new file mode 100644 index 00000000..fc91774a --- /dev/null +++ b/cli/cmd/initialize/get_python_version.go @@ -0,0 +1,50 @@ +package initialize + +import ( + "errors" + "os/exec" + "regexp" +) + +var ( + ErrDetectPythonExecutable = errors.New("could not detect python executable") + ErrDetectPythonVersion = errors.New("could not detect python version") +) + +func getPythonVersion() (string, error) { + p, err := execPythonVersionCommand() + if err != nil { + return "", err + } + + version, err := extractPythonVersion(p) + if err != nil { + return "", err + } + + return version, nil +} + +func execPythonVersionCommand() ([]byte, error) { + pythonExes := []string{"python", "python3", "python3.9", "python3.10", "python3.11", "python3.12"} + + for _, pythonExe := range pythonExes { + if p, err := exec.Command(pythonExe, "-V").Output(); err == nil { + return p, nil + } + } + + return []byte{}, ErrDetectPythonExecutable +} + +func extractPythonVersion(p []byte) (string, error) { + verifyPythonOutput := regexp.MustCompile(`Python [\d]+.[\d]+\+?`) + if !verifyPythonOutput.Match(p) { + return "", ErrDetectPythonVersion + } + + getVersionRegex := regexp.MustCompile(`[\d]+.[\d]+`) + version := getVersionRegex.Find(p) + + return string(version), nil +} diff --git a/cli/cmd/initialize/get_python_version_test.go b/cli/cmd/initialize/get_python_version_test.go new file mode 100644 index 00000000..e5b8c7e5 --- /dev/null +++ b/cli/cmd/initialize/get_python_version_test.go @@ -0,0 +1,39 @@ +package initialize + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestExtractPythonVersion(t *testing.T) { + tests := []struct { + version string + expectedExtractedVersion string + }{ + { + version: "3.12.4", + expectedExtractedVersion: "3.12", + }, + { + version: "3.7.0", + expectedExtractedVersion: "3.7", + }, + { + version: "2.7", + expectedExtractedVersion: "2.7", + }, + { + version: "1.5.1p1", + expectedExtractedVersion: "1.5", + }, + } + for _, test := range tests { + t.Run("Can extract python version "+test.expectedExtractedVersion, func(t *testing.T) { + actualExtractedVersion, err := extractPythonVersion([]byte("Python " + test.version)) + require.NoError(t, err) + assert.Equalf(t, test.expectedExtractedVersion, actualExtractedVersion, test.expectedExtractedVersion+"=="+actualExtractedVersion) + }) + } +} diff --git a/cli/cmd/initialize/init.go b/cli/cmd/initialize/init.go new file mode 100644 index 00000000..99a0571b --- /dev/null +++ b/cli/cmd/initialize/init.go @@ -0,0 +1,149 @@ +package initialize + +import ( + "errors" + "fmt" + "log/slog" + "os" + "strings" + + "numerous/cli/cmd/initialize/wizard" + "numerous/cli/internal/gql" + "numerous/cli/internal/gql/app" + "numerous/cli/manifest" + "numerous/cli/tool" + + "github.com/spf13/cobra" +) + +var ( + appLibraryString string + newApp = tool.Tool{CoverImage: "app_cover.jpg"} + InitCmd = &cobra.Command{ + Use: "init [flags]", + Aliases: []string{"initialize"}, + Short: "Initialize a numerous project", + Long: `Helps the user bootstrap a python project as a numerous project.`, + Args: cobra.MaximumNArgs(1), + Run: runInit, + } +) + +func setupFlags(a *tool.Tool) { + InitCmd.Flags().StringVarP(&a.Name, "name", "n", "", "Name of the app") + InitCmd.Flags().StringVarP(&a.Description, "description", "d", "", "Description of your app") + InitCmd.Flags().StringVarP(&appLibraryString, "app-library", "t", "", "Library the app is made with") + InitCmd.Flags().StringVarP(&a.AppFile, "app-file", "f", "", "Path to that main file of the project") + InitCmd.Flags().StringVarP(&a.RequirementsFile, "requirements-file", "r", "", "Requirements file of the project") +} + +func runInit(cmd *cobra.Command, args []string) { + projectFolderPath, err := os.Getwd() + if err != nil { + slog.Info("An error occurred when trying to get the current user path during init process.", slog.String("error", err.Error())) + fmt.Println(err) + + return + } + + if len(args) != 0 { + projectFolderPath = pathArgumentHandler(args[0], projectFolderPath) + } + + if exist, _ := tool.ToolIDExistsInCurrentDir(&newApp, projectFolderPath); exist { + fmt.Printf("Error: An app is already initialized in '%s'\n", projectFolderPath) + fmt.Println("You can initialize an app in a folder by specifying a path in the command, like below:") + fmt.Println(" numerous init ./my-app-folder") + + return + } + + if err := validateAndSetAppLibrary(&newApp, appLibraryString); err != nil { + fmt.Println(err) + return + } + + setPython(&newApp) + + if continueBootstrap, err := wizard.RunInitAppWizard(projectFolderPath, &newApp); err != nil { + fmt.Println("Error running initialization wizard:", err) + return + } else if !continueBootstrap { + return + } + + // Initialize and boostrap project files + a, err := app.Create(newApp, gql.GetClient()) + if err != nil { + fmt.Printf("error creating app in the database.\n error: %s)", err) + return + } + + if err := bootstrapFiles(newApp, a.ID, projectFolderPath); err != nil { + fmt.Printf("error bootstrapping files.\n error: %s)", err) + return + } + + printSuccess(a) +} + +func pathArgumentHandler(providedPath string, currentPath string) string { + appPath := providedPath + if providedPath != "." { + pathBegin := string([]rune(providedPath)[0:2]) + if pathBegin == "./" || pathBegin == ".\\" { + appPath = strings.Replace(appPath, ".", currentPath, 1) + } else { + appPath = providedPath + } + } else { + appPath = currentPath + } + + return appPath +} + +func validateAndSetAppLibrary(a *tool.Tool, l string) error { + if l == "" { + return nil + } + lib, err := tool.GetLibraryByKey(l) + if err != nil { + return err + } + a.Library = lib + + return nil +} + +func setPython(a *tool.Tool) { + fallbackVersion := "3.11" + + if version, err := getPythonVersion(); errors.Is(err, ErrDetectPythonExecutable) { + fmt.Printf("Python interpeter not found, setting Python version to '%s' for the app.\n", fallbackVersion) + a.Python = fallbackVersion + } else if errors.Is(err, ErrDetectPythonVersion) { + fmt.Printf("Could not parse python version '%s', setting Python version to '%s' for the app.\n", version, fallbackVersion) + a.Python = fallbackVersion + } else { + a.Python = version + } +} + +func printSuccess(a app.App) { + fmt.Printf(` +The app has been initialized! +If you need to edit some of the information you have just entered +go to %s + +APP ID: +%s + +The APP ID is an access id to this app. +It exists in this project, but be sure to save it somewhere else in case you delete this folder and still want access. +`, manifest.ManifestFileName, a.ID) +} + +func init() { + setupFlags(&newApp) +} diff --git a/cli/cmd/initialize/init_test.go b/cli/cmd/initialize/init_test.go new file mode 100644 index 00000000..97287026 --- /dev/null +++ b/cli/cmd/initialize/init_test.go @@ -0,0 +1,28 @@ +package initialize + +import ( + "testing" + + "numerous/cli/tool" + + "github.com/stretchr/testify/assert" +) + +func TestValidateFlags(t *testing.T) { + t.Run("Validates if no library is set", func(t *testing.T) { + err := validateAndSetAppLibrary(&tool.Tool{}, "") + assert.NoError(t, err) + }) + + t.Run("Cannot validate unsupported library", func(t *testing.T) { + err := validateAndSetAppLibrary(&tool.Tool{}, "something") + assert.Error(t, err) + }) + + for _, lib := range []string{"plotly", "marimo", "streamlit"} { + t.Run("Validates "+lib, func(t *testing.T) { + err := validateAndSetAppLibrary(&tool.Tool{}, lib) + assert.NoError(t, err) + }) + } +} diff --git a/cli/cmd/initialize/wizard/file_question.go b/cli/cmd/initialize/wizard/file_question.go new file mode 100644 index 00000000..2584fbeb --- /dev/null +++ b/cli/cmd/initialize/wizard/file_question.go @@ -0,0 +1,56 @@ +package wizard + +import ( + "fmt" + "os" + "path/filepath" + + "github.com/AlecAivazis/survey/v2" +) + +func getFileQuestion(name, prompt, defaultPath, fileExtension string) *survey.Question { + return &survey.Question{ + Name: name, + Prompt: &survey.Input{ + Message: prompt, + Default: defaultPath, + Suggest: func(toComplete string) []string { + return suggestPath(toComplete, fileExtension) + }, + }, + Validate: func(ans interface{}) error { + return validatePath(ans, fileExtension) + }, + Transform: cleanPath, + } +} + +func suggestPath(toComplete string, fileExtension string) []string { + matches, _ := filepath.Glob(toComplete + "*") + var paths []string + for _, match := range matches { + f, _ := os.Stat(match) + if f.IsDir() { + paths = append(paths, match+string(os.PathSeparator)) + } else if filepath.Ext(match) == fileExtension { + paths = append(paths, match) + } + } + + return paths +} + +func validatePath(ans interface{}, fileExtension string) error { + if err := survey.Required(ans); err != nil { + return err + } + if filepath.Ext(fmt.Sprintf("%v", ans)) != fileExtension { + return fmt.Errorf("input must be a %s file", fileExtension) + } + + return nil +} + +func cleanPath(path interface{}) interface{} { + return filepath.Clean(fmt.Sprintf("%v", path)) +} diff --git a/cli/cmd/initialize/wizard/folder.go b/cli/cmd/initialize/wizard/folder.go new file mode 100644 index 00000000..b45c29aa --- /dev/null +++ b/cli/cmd/initialize/wizard/folder.go @@ -0,0 +1,73 @@ +package wizard + +import ( + "errors" + "fmt" + "os" + "path" + + "github.com/AlecAivazis/survey/v2" + "github.com/AlecAivazis/survey/v2/terminal" +) + +// allows dependency injection of the standard input for testing the survey +func UseOrCreateAppFolder(folderPath string, in terminal.FileReader) (bool, error) { + absPath, err := absPath(folderPath) + if err != nil { + return false, err + } + + if _, err := os.Stat(absPath); errors.Is(err, os.ErrNotExist) { + return createFolderSurvey(absPath, in) + } + + return confirmFolderSurvey(absPath, in) +} + +func createFolderSurvey(folderPath string, in terminal.FileReader) (bool, error) { + var confirm bool + + prompt := &survey.Confirm{ + Message: fmt.Sprintf("The selected folder '%s' does not exist. Create it? (default: yes)", folderPath), + Default: true, + } + + err := survey.AskOne(prompt, &confirm, func(options *survey.AskOptions) error { options.Stdio.In = in; return nil }) + if err != nil { + return false, err + } + + if confirm { + if err := os.MkdirAll(folderPath, os.ModePerm); err != nil { + return false, err + } + } + + return confirm, nil +} + +func confirmFolderSurvey(folderPath string, in terminal.FileReader) (bool, error) { + var confirm bool + + msg := fmt.Sprintf("Do you want to use the existing folder '%s' for your app? (default: yes)", folderPath) + prompt := &survey.Confirm{Message: msg, Default: true} + err := survey.AskOne(prompt, &confirm, func(options *survey.AskOptions) error { options.Stdio.In = in; return nil }) + if err != nil { + return false, err + } + + return confirm, nil +} + +func absPath(p string) (string, error) { + if path.IsAbs(p) { + return p, nil + } + + wd, err := os.Getwd() + if err != nil { + return "", err + } + + return path.Join(wd, p), nil +} diff --git a/cli/cmd/initialize/wizard/folder_test.go b/cli/cmd/initialize/wizard/folder_test.go new file mode 100644 index 00000000..557e4945 --- /dev/null +++ b/cli/cmd/initialize/wizard/folder_test.go @@ -0,0 +1,114 @@ +package wizard + +import ( + "io" + "os" + "syscall" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +type MockFileReader struct { + index int + returns []struct { + b []byte + err error + } +} + +func (f *MockFileReader) Read(p []byte) (n int, err error) { + if f.index > len(f.returns) { + return 0, io.EOF + } else { + ret := f.returns[f.index] + f.index++ + copy(p, ret.b) + + return len(ret.b), ret.err + } +} + +func (f *MockFileReader) Fd() uintptr { + return 0 +} + +func (f *MockFileReader) Reset() { + f.index = 0 +} + +func TestUseOrCreateAppFolder(t *testing.T) { + yesReader := MockFileReader{ + returns: []struct { + b []byte + err error + }{ + {b: []byte("\x1b[10;10R"), err: nil}, + {b: []byte("\x1b[10;10R"), err: nil}, + {b: []byte("y\n"), err: nil}, + {b: []byte(""), err: io.EOF}, + }, + } + + t.Run("Creates a folder structure when it doesn't exist", func(t *testing.T) { + yesReader.Reset() + filePathTest := t.TempDir() + "/test/folder" + + shouldContinue, err := UseOrCreateAppFolder(filePathTest, &yesReader) + + assert.True(t, shouldContinue) + require.NoError(t, err) + _, err = os.Stat(filePathTest) + require.NoError(t, err) + }) + + t.Run("Identify the current user folder structure", func(t *testing.T) { + yesReader.Reset() + filePathTest := t.TempDir() + + shouldContinue, err := UseOrCreateAppFolder(filePathTest, &yesReader) + + assert.True(t, shouldContinue) + require.NoError(t, err) + _, err = os.Stat(filePathTest) + require.NoError(t, err) + }) + + noReader := MockFileReader{ + returns: []struct { + b []byte + err error + }{ + {b: []byte("\x1b[10;10R"), err: nil}, + {b: []byte("\x1b[10;10R"), err: nil}, + {b: []byte("n\n"), err: nil}, + {b: []byte(""), err: io.EOF}, + }, + } + + t.Run("User cancels folder creation", func(t *testing.T) { + noReader.Reset() + nonExistingFolder := t.TempDir() + "/test/folder" + + shouldContinue, err := UseOrCreateAppFolder(nonExistingFolder, &noReader) + + assert.False(t, shouldContinue) + require.NoError(t, err) + _, err = os.Stat(nonExistingFolder) + os.IsNotExist(err) + assert.Equal(t, syscall.ENOENT, err.(*os.PathError).Err) + }) + + t.Run("User rejects existing folder", func(t *testing.T) { + noReader.Reset() + existingPath := t.TempDir() + _, err := os.Stat(existingPath) + require.NoError(t, err) + + shouldContinue, err := UseOrCreateAppFolder(existingPath, &noReader) + + assert.False(t, shouldContinue) + require.NoError(t, err) + }) +} diff --git a/cli/cmd/initialize/wizard/library_question.go b/cli/cmd/initialize/wizard/library_question.go new file mode 100644 index 00000000..7e219528 --- /dev/null +++ b/cli/cmd/initialize/wizard/library_question.go @@ -0,0 +1,22 @@ +package wizard + +import ( + "numerous/cli/tool" + + "github.com/AlecAivazis/survey/v2" +) + +func getLibraryQuestion(name, prompt string) *survey.Question { + libraryNames := []string{} + for _, lib := range tool.SupportedLibraries { + libraryNames = append(libraryNames, lib.Name) + } + + return &survey.Question{ + Name: name, + Prompt: &survey.Select{ + Message: prompt, + Options: libraryNames, + }, + } +} diff --git a/cli/cmd/initialize/wizard/survey_answers.go b/cli/cmd/initialize/wizard/survey_answers.go new file mode 100644 index 00000000..6e609878 --- /dev/null +++ b/cli/cmd/initialize/wizard/survey_answers.go @@ -0,0 +1,33 @@ +package wizard + +import ( + "strings" + + "numerous/cli/tool" +) + +type surveyAnswers struct { + Name string + Description string + LibraryName string + AppFile string + RequirementsFile string +} + +func (s surveyAnswers) appendAnswersToApp(a *tool.Tool) { + a.Name = s.Name + a.Description = s.Description + a.Library, _ = tool.GetLibraryByName(s.LibraryName) + a.AppFile = strings.Trim(s.AppFile, " ") + a.RequirementsFile = strings.Trim(s.RequirementsFile, " ") +} + +func fromApp(a *tool.Tool) *surveyAnswers { + return &surveyAnswers{ + Name: a.Name, + Description: a.Description, + LibraryName: a.Library.Name, + AppFile: a.AppFile, + RequirementsFile: a.RequirementsFile, + } +} diff --git a/cli/cmd/initialize/wizard/text_question.go b/cli/cmd/initialize/wizard/text_question.go new file mode 100644 index 00000000..46aa29ed --- /dev/null +++ b/cli/cmd/initialize/wizard/text_question.go @@ -0,0 +1,15 @@ +package wizard + +import "github.com/AlecAivazis/survey/v2" + +func getTextQuestion(name, prompt string, required bool) *survey.Question { + q := &survey.Question{ + Name: name, + Prompt: &survey.Input{Message: prompt}, + } + if required { + q.Validate = survey.Required + } + + return q +} diff --git a/cli/cmd/initialize/wizard/wizard.go b/cli/cmd/initialize/wizard/wizard.go new file mode 100644 index 00000000..191d98bf --- /dev/null +++ b/cli/cmd/initialize/wizard/wizard.go @@ -0,0 +1,67 @@ +package wizard + +import ( + "fmt" + "os" + + "numerous/cli/tool" + + "github.com/AlecAivazis/survey/v2" +) + +func RunInitAppWizard(projectFolderPath string, a *tool.Tool) (bool, error) { + questions := getQuestions(*a) + if len(questions) == 1 && questions[0].Name == "Description" { + return false, nil + } + + fmt.Println("Hi there, welcome to Numerous.") + fmt.Println("We're happy you're here!") + fmt.Println("Let's get started by entering basic information about your app.") + + continueWizard, err := UseOrCreateAppFolder(projectFolderPath, os.Stdin) + if err != nil { + return false, err + } else if !continueWizard { + return false, nil + } + + answers := fromApp(a) + if err := survey.Ask(questions, answers); err != nil { + return false, err + } + + answers.appendAnswersToApp(a) + + return true, nil +} + +func getQuestions(a tool.Tool) []*survey.Question { + q := []*survey.Question{} + + if a.Name == "" { + q = append(q, getTextQuestion("Name", + "Name your app:", + true)) + } + if a.Description == "" { + q = append(q, getTextQuestion("Description", + "Provide a short description for your app:", + false)) + } + if a.Library.Key == "" { + q = append(q, getLibraryQuestion("LibraryName", + "Select which app library you are using:")) + } + if a.AppFile == "" { + q = append(q, getFileQuestion("AppFile", + "Provide the path to your app:", "app.py", ".py")) + } + if a.RequirementsFile == "" { + q = append(q, getFileQuestion("RequirementsFile", + "Provide the path to your requirements file:", + "requirements.txt", ".txt")) + } + + return q +} diff --git a/cli/cmd/list/list.go b/cli/cmd/list/list.go new file mode 100644 index 00000000..276bf9e3 --- /dev/null +++ b/cli/cmd/list/list.go @@ -0,0 +1,41 @@ +package list + +import ( + "fmt" + "os" + + "numerous/cli/auth" + "numerous/cli/internal/gql" + "numerous/cli/internal/gql/app" + + "git.sr.ht/~emersion/gqlclient" + "github.com/spf13/cobra" +) + +var ListCmd = &cobra.Command{ + Use: "list", + Short: "List all your apps (login required)", + Run: func(cmd *cobra.Command, args []string) { + if err := list(auth.NumerousTenantAuthenticator, gql.GetClient()); err != nil { + fmt.Println("Error: ", err) + os.Exit(1) + } + }, +} + +func list(a auth.Authenticator, c *gqlclient.Client) error { + user := a.GetLoggedInUserFromKeyring() + if user == nil { + fmt.Printf("Command requires login.\n Use \"numerous login\" to login or sign up.\n") + return nil + } + apps, err := app.QueryList(c) + if err != nil { + fmt.Println(err) + return err + } + + fmt.Println(setupTable(apps)) + + return nil +} diff --git a/cli/cmd/list/list_test.go b/cli/cmd/list/list_test.go new file mode 100644 index 00000000..335519bf --- /dev/null +++ b/cli/cmd/list/list_test.go @@ -0,0 +1,76 @@ +package list + +import ( + "strconv" + "strings" + "testing" + "time" + + "numerous/cli/auth" + "numerous/cli/internal/gql/app" + "numerous/cli/test" + "numerous/cli/test/mocks" + + "github.com/stretchr/testify/assert" +) + +func TestList(t *testing.T) { + testUser := &auth.User{ + AccessToken: "access-token", + RefreshToken: "refresh-token", + Tenant: "numerous-testing.com", + } + + t.Run("Can list apps if user is signed in", func(t *testing.T) { + m := new(mocks.MockAuthenticator) + m.On("GetLoggedInUserFromKeyring").Return(testUser) + + appsAsStrings := []string{} + for i := 0; i < 3; i++ { + id := strconv.Itoa(i) + app := app.App{ + ID: id, + SharedURL: "https://test.com/shared/some-hash-" + id, + PublicURL: "https://test.com/public/other-hash-" + id, + Name: "Name " + id, + CreatedAt: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC), + } + appsAsStrings = append(appsAsStrings, test.AppToResponse(app)) + } + + response := `{ + "data": { + "tools": [` + strings.Join(appsAsStrings, ", ") + `] + } + }` + c, transportMock := test.CreateMockGqlClient(response) + + err := list(m, c) + + assert.NoError(t, err) + m.AssertExpectations(t) + transportMock.AssertExpectations(t) + }) + + t.Run("Does not query list if user is not signed in", func(t *testing.T) { + var u *auth.User + m := new(mocks.MockAuthenticator) + m.On("GetLoggedInUserFromKeyring").Return(u) + + c, transportMock := test.CreateMockGqlClient() + + err := list(m, c) + + assert.NoError(t, err) + m.AssertExpectations(t) + transportMock.AssertExpectations(t) + }) + + t.Run("returns empty if url is empty", func(t *testing.T) { + assert.Equal(t, "", getPublicEmoji("")) + }) + + t.Run("returns checkmark if url is not empty", func(t *testing.T) { + assert.Equal(t, "✅", getPublicEmoji("https://test.com/public/id")) + }) +} diff --git a/cli/cmd/list/table.go b/cli/cmd/list/table.go new file mode 100644 index 00000000..22c23b46 --- /dev/null +++ b/cli/cmd/list/table.go @@ -0,0 +1,64 @@ +package list + +import ( + "numerous/cli/internal/gql/app" + + "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/lipgloss/table" +) + +var ( + borderStyle = lipgloss.NewStyle(). + Foreground(lipgloss.Color("8")) + headerStyle = lipgloss.NewStyle(). + Border(lipgloss.NormalBorder(), false, false, true, false). + Foreground(lipgloss.Color("2")). + PaddingLeft(1). + PaddingRight(1) + rowStyle = lipgloss.NewStyle().Padding(0, 1) +) + +func setupTable(apps []app.App) *table.Table { + columns := []string{"ID", "Name", "Description", "Created At ", "Shareable URL", "Public App"} + publicAppColumnIdx := 5 + var rows [][]string + for _, a := range apps { + rows = append(rows, []string{ + a.ID, + a.Name, + a.Description, + a.CreatedAt.Local().Format("2006-Jan-02"), + a.SharedURL, + getPublicEmoji(a.PublicURL), + }) + } + t := table.New(). + Border(lipgloss.NormalBorder()). + BorderStyle(borderStyle). + BorderRow(true). + Headers(columns...). + Rows(rows...). + StyleFunc(func(row, col int) lipgloss.Style { + var style lipgloss.Style + if row == 0 { + style = headerStyle.Copy() + } else { + style = rowStyle.Copy() + } + if col == publicAppColumnIdx { + style = style.AlignHorizontal(lipgloss.Center) + } + + return style + }) + + return t +} + +func getPublicEmoji(publicURL string) string { + if publicURL != "" { + return "✅" + } + + return "" +} diff --git a/cli/cmd/log/log.go b/cli/cmd/log/log.go new file mode 100644 index 00000000..407166a5 --- /dev/null +++ b/cli/cmd/log/log.go @@ -0,0 +1,54 @@ +package log + +import ( + "fmt" + "log/slog" + "os" + "path/filepath" + + "numerous/cli/tool" + + "github.com/spf13/cobra" +) + +var LogCmd = &cobra.Command{ + Use: "log", + Short: "Display running application logs", + Long: `This command initiates the logging process, providing last hour of application logs for monitoring and troubleshooting purposes.`, + Args: cobra.MaximumNArgs(1), + Run: log, +} + +func log(cmd *cobra.Command, args []string) { + msg := "Now streaming log entries from the last hour and all new entries..." + fmt.Println(msg) + userDir, err := os.Getwd() + if err != nil { + slog.Info("An error occurred when trying to get the current user path with log command.", slog.String("error", err.Error())) + fmt.Println(err) + + return + } + if len(args) > 0 { + userDir = args[0] + } + + if err := os.Chdir(userDir); err != nil { + fmt.Printf("Could not access \"%s\"", userDir) + return + } + + appID, err := os.ReadFile(filepath.Join(userDir, tool.ToolIDFileName)) + if err != nil { + slog.Info("An error occurred when trying read tool id file.", slog.String("error", err.Error())) + fmt.Println(tool.ErrToolIDNotFound) + fmt.Println("Remember to be in the app directory or pass it as an argument to the numerous log command!") + + return + } + + err = getLogs(string(appID)) + if err != nil { + fmt.Println("Error listening for logs.", err) + } +} diff --git a/cli/cmd/log/log_events.go b/cli/cmd/log/log_events.go new file mode 100644 index 00000000..5bc908ae --- /dev/null +++ b/cli/cmd/log/log_events.go @@ -0,0 +1,96 @@ +package log + +import ( + "encoding/json" + "fmt" + "io" + "log/slog" + "os" + "time" + + "numerous/cli/internal/gql" + + "github.com/hasura/go-graphql-client" +) + +type LogEntry struct { + Time time.Time `json:"time,omitempty"` + Message string `json:"message,omitempty"` +} + +type LogsContainer struct { + Logs LogEntry `json:"logs"` +} + +type subscription struct { + LogMessage LogEntry `graphql:"logs(appId: $appId)"` +} + +func getClient() *graphql.SubscriptionClient { + var previousError error + client := gql.GetSubscriptionClient() + client = client.OnError(func(sc *graphql.SubscriptionClient, err error) error { + if previousError != nil { + fmt.Printf("Error occurred listening for deploy logs. This does not mean that you app will be unavailable.\nFirst error: %s\nSecond error: %s\n", previousError, err) + return err + } + fmt.Printf("Error occurred listening for deploy logs.\nError: %s\nRetrying...\n", err) + previousError = err + + return nil + }) + + return client +} + +func getLogs(appID string) error { + client := getClient() + defer client.Close() + err := logsSubscription(client, appID, true) + if err != nil { + return err + } + + if err := client.Run(); err != nil { + return err + } + + return err +} + +func logsSubscription(client *graphql.SubscriptionClient, appID string, verbose bool) error { + var sub subscription + out := os.Stdout + variables := map[string]any{"appId": graphql.ID(appID)} + + _, err := client.Subscribe(&sub, variables, func(dataValue []byte, err error) error { + if err != nil { + return err + } + var data LogsContainer + + if err := json.Unmarshal(dataValue, &data); err != nil { + return err + } + ProcessLogEntry(data, out, verbose) + + return nil + }) + + return err +} + +func ProcessLogEntry(entry LogsContainer, out io.Writer, verbose bool) { + if entry.Logs.Message != "" { + printVerbose(out, entry.Logs.Message, verbose) + } +} + +func printVerbose(out io.Writer, message string, verbose bool) { + if verbose { + _, err := out.Write([]byte(message + "\n")) + if err != nil { + slog.Error("Error writing message", err) + } + } +} diff --git a/cli/cmd/login/login.go b/cli/cmd/login/login.go new file mode 100644 index 00000000..bb3c24fa --- /dev/null +++ b/cli/cmd/login/login.go @@ -0,0 +1,86 @@ +package login + +import ( + "context" + "fmt" + "log" + "net/http" + "os" + + "numerous/cli/auth" + + "github.com/spf13/cobra" +) + +var LoginCmd = &cobra.Command{ + Use: "login", + Short: "Login in to Numerous", + Args: cobra.NoArgs, + Run: func(cmd *cobra.Command, args []string) { + user := auth.NumerousTenantAuthenticator.GetLoggedInUserFromKeyring() + if user == nil { + Login(auth.NumerousTenantAuthenticator, cmd.Context()) + } else { + fmt.Println("Great, you are already logged in!") + } + }, +} + +func Login(a auth.Authenticator, ctx context.Context) *auth.User { + state, err := a.GetDeviceCode(ctx, http.DefaultClient) + if err != nil { + log.Fatal(err) + } + + fmt.Printf("\n%s\n\n", "You are logging into Numerous. \nWhen you press Enter, a browser window will automatically open. \nPlease verify that the code in the browser matches the code below to complete authentication and click 'Confirm'.") + fmt.Println("Verification code: " + state.UserCode) + fmt.Println("Press Enter to continue...") + + if _, err = fmt.Scanln(); err != nil { + log.Fatal(err) + os.Exit(1) + } + + if err := a.OpenURL(state.VerificationURI); err != nil { + fmt.Printf("Whoops, we ran into an error opening the verification URL in your browser. \nPlease copy and paste the following URL into your browser: %s\n", state.VerificationURI) + } + + result, err := a.WaitUntilUserLogsIn(ctx, http.DefaultClient, state) + if err != nil { + log.Fatal(err) + } + + if err := a.StoreAccessToken(result.AccessToken); err != nil { + fmt.Printf("An error occurred while storing your access token. We could not log you in. %s\n", err) + os.Exit(1) + } + if err := a.StoreRefreshToken(result.RefreshToken); err != nil { + fmt.Printf("An error occurred while storing your refresh token to the keyring. %s\n", err) + fmt.Printf("You will need to login again when your access token expire.\n\n") + } + + fmt.Println("You are now logged in to Numerous!") + + return a.GetLoggedInUserFromKeyring() +} + +func RefreshAccessToken(user *auth.User, client *http.Client, a auth.Authenticator) error { + if err := user.CheckAuthenticationStatus(); err != auth.ErrExpiredToken { + if err != nil { + return err + } + + return nil + } + + newAccessToken, err := a.RegenerateAccessToken(client, user.RefreshToken) + if err != nil { + return err + } + if err := a.StoreAccessToken(newAccessToken); err != nil { + return err + } + user.AccessToken = newAccessToken + + return nil +} diff --git a/cli/cmd/login/login_test.go b/cli/cmd/login/login_test.go new file mode 100644 index 00000000..61c2b3ec --- /dev/null +++ b/cli/cmd/login/login_test.go @@ -0,0 +1,120 @@ +package login + +import ( + "context" + "fmt" + "net/http" + "testing" + "time" + + "numerous/cli/auth" + "numerous/cli/test" + "numerous/cli/test/mocks" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" + "github.com/stretchr/testify/require" +) + +var ( + testTenant = "test.domain.com" + testIssuer = fmt.Sprintf("https://%s/", testTenant) +) + +func TestLogin(t *testing.T) { + state := auth.DeviceCodeState{ + DeviceCode: "some-code", + UserCode: "some-long-user-code", + VerificationURI: "https://test.domain.com/device/code/some-code", + ExpiresIn: 8400, + Interval: 5, + } + result := auth.Result{ + IDToken: "some-id-token", + AccessToken: "some-access-token", + RefreshToken: "some-refresh-token", + ExpiresAt: time.Now().Add(time.Second * time.Duration(state.ExpiresIn)), + } + expectedUser := &auth.User{ + AccessToken: result.AccessToken, + RefreshToken: result.RefreshToken, + Tenant: testTenant, + } + + m := new(mocks.MockAuthenticator) + m.On("GetDeviceCode", mock.Anything, mock.Anything).Return(state, nil) + m.On("OpenURL", state.VerificationURI).Return(nil) + m.On("WaitUntilUserLogsIn", mock.Anything, mock.Anything, state).Return(result, nil) + m.On("StoreAccessToken", result.AccessToken).Return(nil) + m.On("StoreRefreshToken", result.RefreshToken).Return(nil) + m.On("GetLoggedInUserFromKeyring").Return(&auth.User{ + AccessToken: result.AccessToken, + RefreshToken: result.RefreshToken, + Tenant: testTenant, + }) + acutalUser := Login(m, context.Background()) + + m.AssertExpectations(t) + assert.Equal(t, expectedUser, acutalUser) +} + +func TestRefreshAccessToken(t *testing.T) { + t.Run("Refreshes access token if it has expired", func(t *testing.T) { + // Create test tokens + refreshToken := "refresh-token" + accessToken := test.GenerateJWT(t, testIssuer, time.Now().Add(-time.Hour)) + expectedNewAccessToken := test.GenerateJWT(t, testIssuer, time.Now().Add(time.Hour)) + + user := &auth.User{ + AccessToken: accessToken, + RefreshToken: refreshToken, + Tenant: testTenant, + } + + // Mock function from authenticator + client := &http.Client{} + m := new(mocks.MockAuthenticator) + m.On("RegenerateAccessToken", client, refreshToken).Return(expectedNewAccessToken, nil) + m.On("StoreAccessToken", expectedNewAccessToken).Return(nil) + + // Execute function we test + err := RefreshAccessToken(user, client, m) + require.NoError(t, err) + + assert.Equal(t, expectedNewAccessToken, user.AccessToken) + m.AssertExpectations(t) + }) + + t.Run("Does not refresh if user not logged in", func(t *testing.T) { + var user *auth.User + m := new(mocks.MockAuthenticator) + client := &http.Client{} + err := RefreshAccessToken(user, client, m) + + require.EqualError(t, err, auth.ErrUserNotLoggedIn.Error()) + m.AssertExpectations(t) + }) + + t.Run("Does not refresh if access token has not expired", func(t *testing.T) { + // Create test tokens + refreshToken := "refresh-token" + accessToken := test.GenerateJWT(t, testIssuer, time.Now().Add(time.Hour)) + + user := &auth.User{ + AccessToken: accessToken, + RefreshToken: refreshToken, + Tenant: testTenant, + } + + // Mock function from authenticator + client := &http.Client{} + m := new(mocks.MockAuthenticator) + + // Execute function we test + err := RefreshAccessToken(user, client, m) + require.NoError(t, err) + + assert.Equal(t, user.AccessToken, accessToken) + m.AssertExpectations(t) + }) +} diff --git a/cli/cmd/logout/logout.go b/cli/cmd/logout/logout.go new file mode 100644 index 00000000..b5e7e2e1 --- /dev/null +++ b/cli/cmd/logout/logout.go @@ -0,0 +1,39 @@ +package logout + +import ( + "fmt" + "net/http" + "os" + + "numerous/cli/auth" + + "github.com/spf13/cobra" +) + +var LogoutCmd = &cobra.Command{ + Use: "logout", + Short: "Logout of the Numerous CLI", + Run: func(cmd *cobra.Command, args []string) { + if err := logout(auth.NumerousTenantAuthenticator); err != nil { + fmt.Println("Error: ", err) + os.Exit(1) + } + }, +} + +func logout(a auth.Authenticator) error { + user := a.GetLoggedInUserFromKeyring() + if user == nil { + fmt.Println("You are not logged in.") + return nil + } + + _ = a.RevokeRefreshToken(http.DefaultClient, user.RefreshToken) + if err := a.RemoveLoggedInUserFromKeyring(); err != nil { + fmt.Println("A problem occurred when signing out") + return err + } + fmt.Println("Successfully logged out!") + + return nil +} diff --git a/cli/cmd/logout/logout_test.go b/cli/cmd/logout/logout_test.go new file mode 100644 index 00000000..9e10ef2c --- /dev/null +++ b/cli/cmd/logout/logout_test.go @@ -0,0 +1,68 @@ +package logout + +import ( + "errors" + "net/http" + "testing" + + "numerous/cli/auth" + "numerous/cli/test/mocks" + + "github.com/stretchr/testify/assert" +) + +func TestLogout(t *testing.T) { + testUser := &auth.User{ + AccessToken: "access-token", + RefreshToken: "refresh-token", + Tenant: "numerous-testing.com", + } + + t.Run("Can logout if user is signed in", func(t *testing.T) { + m := new(mocks.MockAuthenticator) + m.On("GetLoggedInUserFromKeyring").Return(testUser) + m.On("RevokeRefreshToken", http.DefaultClient, testUser.RefreshToken).Return(nil) + m.On("RemoveLoggedInUserFromKeyring").Return(nil) + + err := logout(m) + + assert.NoError(t, err) + m.AssertExpectations(t) + }) + + t.Run("Can logout, even if refresh token could not be revoked", func(t *testing.T) { + m := new(mocks.MockAuthenticator) + m.On("GetLoggedInUserFromKeyring").Return(testUser) + m.On("RevokeRefreshToken", http.DefaultClient, testUser.RefreshToken).Return(auth.ErrInvalidClient) + m.On("RemoveLoggedInUserFromKeyring").Return(nil) + + err := logout(m) + + assert.NoError(t, err) + m.AssertExpectations(t) + }) + + t.Run("Does not call any methods on Authenticator if user is not logged in", func(t *testing.T) { + var u *auth.User + m := new(mocks.MockAuthenticator) + m.On("GetLoggedInUserFromKeyring").Return(u) + + err := logout(m) + + assert.NoError(t, err) + m.AssertExpectations(t) + }) + + t.Run("Returns error if it cannot remove from keyring", func(t *testing.T) { + errCouldNotRemove := errors.New("could not remove") + m := new(mocks.MockAuthenticator) + m.On("GetLoggedInUserFromKeyring").Return(testUser) + m.On("RevokeRefreshToken", http.DefaultClient, testUser.RefreshToken).Return(nil) + m.On("RemoveLoggedInUserFromKeyring").Return(errCouldNotRemove) + + err := logout(m) + + assert.ErrorIs(t, err, errCouldNotRemove) + m.AssertExpectations(t) + }) +} diff --git a/cli/cmd/organization/create/organization_create.go b/cli/cmd/organization/create/organization_create.go new file mode 100644 index 00000000..60fe8139 --- /dev/null +++ b/cli/cmd/organization/create/organization_create.go @@ -0,0 +1,63 @@ +package create + +import ( + "errors" + "fmt" + "os" + + "numerous/cli/auth" + "numerous/cli/cmd/organization/create/wizard" + "numerous/cli/internal/gql" + + "numerous/cli/internal/gql/organization" + + "git.sr.ht/~emersion/gqlclient" + "github.com/spf13/cobra" +) + +var OrganizationCreateCmd = &cobra.Command{ + Use: "create", + Short: "Creates an organization (login required)", + Long: "The organization feature is a structured space to keep the apps that you work on with team members. Organizations help to arrange your apps, manage who has access to them, and simplify the workflow with your team.", + Run: func(cmd *cobra.Command, args []string) { + if err := organizationCreate(auth.NumerousTenantAuthenticator, gql.GetClient()); err != nil { + fmt.Println("Error: ", err) + os.Exit(1) + } + }, +} + +func organizationCreate(a auth.Authenticator, c *gqlclient.Client) error { + user := a.GetLoggedInUserFromKeyring() + if user == nil { + fmt.Printf("Command requires login.\nUse \"numerous login\" to login or sign up.\n") + return nil + } + + newOrganization := organization.Organization{} + +wizard: + for { + if err := wizard.RunOrganizationCreateWizard(&newOrganization.Name, *user); err != nil { + return err + } + + _organization, err := organization.Create(newOrganization.Name, c) + + switch { + case errors.Is(err, organization.ErrOrganizationNameInvalidCharacter): + fmt.Println("The input name contains invalid characters. Please choose another name or press ctrl + c to quit.") + case err != nil: + fmt.Println(err) + return err + default: + newOrganization = _organization + break wizard + } + } + + fmt.Println("\nThe organization has been created!") + fmt.Println(newOrganization.String()) + + return nil +} diff --git a/cli/cmd/organization/create/organization_create_test.go b/cli/cmd/organization/create/organization_create_test.go new file mode 100644 index 00000000..137075e5 --- /dev/null +++ b/cli/cmd/organization/create/organization_create_test.go @@ -0,0 +1,27 @@ +package create + +import ( + "testing" + + "numerous/cli/auth" + "numerous/cli/test" + "numerous/cli/test/mocks" + + "github.com/stretchr/testify/assert" +) + +func TestOrganizationCreate(t *testing.T) { + t.Run("does not create an organization if user is not signed in", func(t *testing.T) { + var u *auth.User + m := new(mocks.MockAuthenticator) + m.On("GetLoggedInUserFromKeyring").Return(u) + + c, transportMock := test.CreateMockGqlClient() + + err := organizationCreate(m, c) + + assert.NoError(t, err) + m.AssertExpectations(t) + transportMock.AssertExpectations(t) + }) +} diff --git a/cli/cmd/organization/create/wizard/wizard.go b/cli/cmd/organization/create/wizard/wizard.go new file mode 100644 index 00000000..8a3a0941 --- /dev/null +++ b/cli/cmd/organization/create/wizard/wizard.go @@ -0,0 +1,29 @@ +package wizard + +import ( + "numerous/cli/auth" + + "github.com/AlecAivazis/survey/v2" +) + +func RunOrganizationCreateWizard(name *string, user auth.User) error { + questions := []*survey.Question{ + { + Name: "Name", + Prompt: &survey.Input{ + Message: "Allowed inputs: a-z, A-Z, 0-9, \"-\", \" \"\nName of the organization:", + Default: "user's organization", + }, + Validate: survey.Required, + }, + } + + answers := struct{ Name string }{} + if err := survey.Ask(questions, &answers); err != nil { + return err + } + + *name = answers.Name + + return nil +} diff --git a/cli/cmd/organization/list/organization_list.go b/cli/cmd/organization/list/organization_list.go new file mode 100644 index 00000000..b88bfc26 --- /dev/null +++ b/cli/cmd/organization/list/organization_list.go @@ -0,0 +1,42 @@ +package list + +import ( + "fmt" + "os" + + "numerous/cli/auth" + "numerous/cli/internal/gql" + "numerous/cli/internal/gql/user" + + "git.sr.ht/~emersion/gqlclient" + "github.com/spf13/cobra" +) + +var OrganizationListCmd = &cobra.Command{ + Use: "list", + Short: "List all your organizations (login required)", + Run: func(cmd *cobra.Command, args []string) { + if err := list(auth.NumerousTenantAuthenticator, gql.GetClient()); err != nil { + fmt.Println("Error: ", err) + os.Exit(1) + } + }, +} + +func list(a auth.Authenticator, g *gqlclient.Client) error { + u := a.GetLoggedInUserFromKeyring() + if u == nil { + fmt.Printf("Command requires login.\n Use \"numerous login\" to login or sign up.\n") + return nil + } + + userResp, err := user.QueryUser(g) + if err != nil { + fmt.Println(err) + return err + } + + fmt.Println(setupTable(userResp.Memberships)) + + return nil +} diff --git a/cli/cmd/organization/list/organization_list_test.go b/cli/cmd/organization/list/organization_list_test.go new file mode 100644 index 00000000..20896001 --- /dev/null +++ b/cli/cmd/organization/list/organization_list_test.go @@ -0,0 +1,82 @@ +package list + +import ( + "fmt" + "strconv" + "strings" + "testing" + + "numerous/cli/auth" + "numerous/cli/internal/gql/organization" + "numerous/cli/test" + "numerous/cli/test/mocks" + + "github.com/stretchr/testify/assert" +) + +func TestList(t *testing.T) { + testUser := &auth.User{ + AccessToken: "access-token", + RefreshToken: "refresh-token", + Tenant: "numerous-testing.com", + } + + t.Run("can list organizations if user is signed in", func(t *testing.T) { + m := new(mocks.MockAuthenticator) + m.On("GetLoggedInUserFromKeyring").Return(testUser) + + organizationsAsStrings := []string{} + for i := 0; i < 3; i++ { + id := strconv.Itoa(i) + organization := organization.OrganizationMembership{ + Role: organization.Admin, + Organization: organization.Organization{ + ID: id, + Name: "Name " + id, + Slug: fmt.Sprintf("name-%s-slug", id), + }, + } + organizationsAsStrings = append(organizationsAsStrings, test.OrganizationMembershipToResponse(struct { + Role test.Role + Organization struct { + ID string + Name string + Slug string + } + }{ + Role: test.Role(organization.Role), + Organization: organization.Organization, + })) + } + + response := `{ + "data": { + "me": { + "fullName": "", + "memberships": [` + strings.Join(organizationsAsStrings, ", ") + `] + } + } + }` + c, transportMock := test.CreateMockGqlClient(response) + + err := list(m, c) + + assert.NoError(t, err) + m.AssertExpectations(t) + transportMock.AssertExpectations(t) + }) + + t.Run("does not query list if user is not signed in", func(t *testing.T) { + var u *auth.User + m := new(mocks.MockAuthenticator) + m.On("GetLoggedInUserFromKeyring").Return(u) + + c, transportMock := test.CreateMockGqlClient() + + err := list(m, c) + + assert.NoError(t, err) + m.AssertExpectations(t) + transportMock.AssertExpectations(t) + }) +} diff --git a/cli/cmd/organization/list/table.go b/cli/cmd/organization/list/table.go new file mode 100644 index 00000000..c0c8ab0f --- /dev/null +++ b/cli/cmd/organization/list/table.go @@ -0,0 +1,50 @@ +package list + +import ( + "numerous/cli/internal/gql/organization" + + "github.com/charmbracelet/lipgloss" + "github.com/charmbracelet/lipgloss/table" +) + +var ( + borderStyle = lipgloss.NewStyle(). + Foreground(lipgloss.Color("8")) + headerStyle = lipgloss.NewStyle(). + Border(lipgloss.NormalBorder(), false, false, true, false). + Foreground(lipgloss.Color("2")). + PaddingLeft(1). + PaddingRight(1) + rowStyle = lipgloss.NewStyle().Padding(0, 1) +) + +func setupTable(organizations []organization.OrganizationMembership) *table.Table { + columns := []string{"Name", "Slug", "Role"} + var rows [][]string + for _, o := range organizations { + rows = append(rows, []string{ + o.Organization.Name, + o.Organization.Slug, + string(o.Role), + }) + } + + t := table.New(). + Border(lipgloss.NormalBorder()). + BorderStyle(borderStyle). + BorderRow(true). + Headers(columns...). + Rows(rows...). + StyleFunc(func(row, col int) lipgloss.Style { + var style lipgloss.Style + if row == 0 { + style = headerStyle.Copy() + } else { + style = rowStyle.Copy() + } + + return style + }) + + return t +} diff --git a/cli/cmd/organization/organization.go b/cli/cmd/organization/organization.go new file mode 100644 index 00000000..db1906ab --- /dev/null +++ b/cli/cmd/organization/organization.go @@ -0,0 +1,21 @@ +package organization + +import ( + "os" + + "github.com/spf13/cobra" +) + +var OrganizationRootCmd = &cobra.Command{ + Use: "organization", + Args: func(cmd *cobra.Command, args []string) error { + if len(args) < 1 { + if err := cmd.Help(); err != nil { + return err + } + os.Exit(0) + } + + return nil + }, +} diff --git a/cli/cmd/publish/publish.go b/cli/cmd/publish/publish.go new file mode 100644 index 00000000..c1400c69 --- /dev/null +++ b/cli/cmd/publish/publish.go @@ -0,0 +1,61 @@ +package publish + +import ( + "fmt" + "os" + + "numerous/cli/internal/gql" + "numerous/cli/internal/gql/app" + "numerous/cli/tool" + + "git.sr.ht/~emersion/gqlclient" + "github.com/spf13/cobra" +) + +var PublishCmd = &cobra.Command{ + Use: "publish", + Short: "Publishes an app to the public app gallery", + Run: func(cmd *cobra.Command, args []string) { + err := publish(gql.GetClient()) + if err != nil { + os.Exit(1) + } + }, +} + +func publish(client *gqlclient.Client) error { + appID, err := tool.ReadToolID(".") + if err == tool.ErrToolIDNotFound { + fmt.Println("The current directory is not a numerous app", + "\nrun \"numerous init\" to initialize a numerous app in the current directory") + + return err + } else if err != nil { + fmt.Println("An error occurred reading the app ID") + fmt.Println("Error: ", err) + + return err + } + + if a, err := app.Query(appID, client); err != nil { + fmt.Println("The app could not be found in the database.") + return err + } else if a.PublicURL != "" { + fmt.Println("The app has already been published to the open app gallery!") + fmt.Printf("Access it here: %s\n", a.PublicURL) + + return nil + } + + if t, err := app.Publish(appID, client); err != nil { + fmt.Println("An error occurred when publishing the app") + fmt.Println("Error: ", err) + + return err + } else { + fmt.Println("The app has been published to the open app gallery!") + fmt.Printf("Access it here: %s\n", t.PublicURL) + + return nil + } +} diff --git a/cli/cmd/publish/publish_test.go b/cli/cmd/publish/publish_test.go new file mode 100644 index 00000000..ba7ef1fa --- /dev/null +++ b/cli/cmd/publish/publish_test.go @@ -0,0 +1,63 @@ +package publish + +import ( + "testing" + + "numerous/cli/internal/gql/app" + "numerous/cli/test" + + "github.com/stretchr/testify/assert" +) + +func TestAppPublish(t *testing.T) { + t.Run("returns nil and successfully sends AppPublish mutations", func(t *testing.T) { + test.ChdirToTmpDirWithAppIDDocument(t, "id") + app := app.App{ + ID: "id", + SharedURL: "https://test.com/shared/some-hash", + } + appQueryResponse := test.AppToQueryResult("tool", app) + app.PublicURL = "https://test.com/public/another-hash" + appPublishResponse := test.AppToQueryResult("toolPublish", app) + + c, transportMock := test.CreateMockGqlClient(appQueryResponse, appPublishResponse) + err := publish(c) + assert.NoError(t, err) + transportMock.AssertExpectations(t) + }) + + t.Run("returns error if app does not exist", func(t *testing.T) { + test.ChdirToTmpDirWithAppIDDocument(t, "id") + appNotFoundResponse := `{"errors":[{"message":"record not found","path":["tool"]}],"data":null}` + c, transportMock := test.CreateMockGqlClient(appNotFoundResponse) + + err := publish(c) + + assert.Error(t, err) + transportMock.AssertExpectations(t) + }) + + t.Run("returns error if app id document does not exists in the current directory", func(t *testing.T) { + c, transportMock := test.CreateMockGqlClient() + err := publish(c) + + assert.Error(t, err) + transportMock.AssertExpectations(t) + }) + + t.Run("return nil and does not send AppPublish mutation, if app is published", func(t *testing.T) { + test.ChdirToTmpDirWithAppIDDocument(t, "id") + app := app.App{ + ID: "id", + SharedURL: "https://test.com/shared/some-hash", + PublicURL: "https://test.com/public/another-hash", + } + appQueryResponse := test.AppToQueryResult("tool", app) + + c, transportMock := test.CreateMockGqlClient(appQueryResponse) + err := publish(c) + + assert.NoError(t, err) + transportMock.AssertExpectations(t) + }) +} diff --git a/cli/cmd/push/build_events.go b/cli/cmd/push/build_events.go new file mode 100644 index 00000000..95cebbe8 --- /dev/null +++ b/cli/cmd/push/build_events.go @@ -0,0 +1,146 @@ +package push + +import ( + "encoding/json" + "errors" + "fmt" + "io" + "log/slog" + "os" + "strings" + + "numerous/cli/internal/gql" + + "github.com/hasura/go-graphql-client" +) + +type BuildEvent struct { + Typename string `json:"__typename"` + Result string `json:"result"` +} + +type subscription struct { + BuildEvents BuildEvent `json:"buildEvents"` +} + +type BuildEventSuccess struct { + Result string `json:"result"` +} + +type BuildEventFailure struct { + Result string `json:"result"` +} + +type BuildEventInfo struct { + Result string `json:"result"` +} + +type subscription1 struct { + BuildEvents struct { + Typename string `graphql:"__typename"` + Success *BuildEventSuccess `graphql:"... on BuildEventSuccess"` + Failure *BuildEventFailure `graphql:"... on BuildEventFailure"` + Info *BuildEventInfo `graphql:"... on BuildEventInfo"` + } `graphql:"buildEvents(buildId: $buildId, appPath: $appPath)"` +} + +func getBuildEventLogs(buildID string, appPath string, verbose bool) error { + client := getClient() + defer client.Close() + + err := buildEventSubscription(client, buildID, appPath, verbose) + if err != nil { + return err + } + + if err := client.Run(); err != nil { + return err + } + + return err +} + +type BuildEventErrorDetail struct { + Message string `json:"message,omitempty"` + Error string `json:"error,omitempty"` +} + +type BuildEventMessage struct { + Status string `json:"status,omitempty"` + Message string `json:"stream,omitempty"` + Error BuildEventErrorDetail `json:"errorDetail,omitempty"` +} + +type subscriptionClient interface { + Subscribe(v interface{}, variables map[string]interface{}, handler func(message []byte, err error) error, options ...graphql.Option) (string, error) +} + +func buildEventSubscription(client subscriptionClient, buildID string, appPath string, verbose bool) error { + var sub subscription1 + var out io.Writer = os.Stdout + + variables := map[string]any{"buildId": graphql.ID(buildID), "appPath": graphql.String(appPath)} + _, err := client.Subscribe(&sub, variables, func(dataValue []byte, err error) error { + if err != nil { + return err + } + data := subscription{} + if err := json.Unmarshal([]byte(dataValue), &data); err != nil { + return err + } + if data.BuildEvents.Typename == "BuildEventInfo" { + for _, msg := range strings.Split(data.BuildEvents.Result, "\r\n") { + ProcessBuildEvent(msg, out, verbose) + } + } + + if data.BuildEvents.Typename == "BuildEventFailure" { + fmt.Fprintf(out, data.BuildEvents.Result) + return errors.New(data.BuildEvents.Result) + } + + return nil + }) + + return err +} + +func getClient() *graphql.SubscriptionClient { + var previousError error + + client := gql.GetSubscriptionClient() + client = client.OnError(func(sc *graphql.SubscriptionClient, err error) error { + if previousError != nil { + fmt.Printf("Error occurred listening for deploy logs. This does not mean that you app will be unavailable.\nFirst error: %s\nSecond error: %s\n", previousError, err) + return err + } + fmt.Printf("Error occurred listening for deploy logs.\nError: %s\nRetrying...\n", err) + previousError = err + + return nil + }) + + return client +} + +func ProcessBuildEvent(msg string, out io.Writer, verbose bool) { + var b BuildEventMessage + if err := json.Unmarshal([]byte(msg), &b); err != nil { + slog.Debug("error unmarshalling build event message", slog.Any("message", msg), slog.Any("error", err)) + return + } + + if b.Message != "" { + printVerbose(out, b.Message, verbose) + } + if b.Status != "" { + printVerbose(out, b.Status, verbose) + } +} + +// printVerbose filters away buildEventMessages that do not interest the average user +func printVerbose(out io.Writer, message string, verbose bool) { + if verbose { + fmt.Fprintf(out, " Build: %s\n", strings.TrimSpace(message)) + } +} diff --git a/cli/cmd/push/build_events_test.go b/cli/cmd/push/build_events_test.go new file mode 100644 index 00000000..a7e3e922 --- /dev/null +++ b/cli/cmd/push/build_events_test.go @@ -0,0 +1,41 @@ +package push + +import ( + "testing" + + "github.com/hasura/go-graphql-client" + "github.com/stretchr/testify/assert" +) + +type fakeSubscriptionEvent struct { + message []byte + err error +} + +type fakeSubscriptionClient struct { + events []fakeSubscriptionEvent +} + +func (sc *fakeSubscriptionClient) Subscribe(v interface{}, variables map[string]interface{}, handler func(message []byte, err error) error, options ...graphql.Option) (string, error) { + for _, ev := range sc.events { + if err := handler(ev.message, ev.err); err != nil { + return "", err + } + } + + return "", nil +} + +func TestBuildEvents(t *testing.T) { + client := fakeSubscriptionClient{ + events: []fakeSubscriptionEvent{ + { + message: []byte("{}"), + }, + }, + } + + err := buildEventSubscription(&client, "some build ID", "", false) + + assert.NoError(t, err) +} diff --git a/cli/cmd/push/deploy_events.go b/cli/cmd/push/deploy_events.go new file mode 100644 index 00000000..c647d1bc --- /dev/null +++ b/cli/cmd/push/deploy_events.go @@ -0,0 +1,89 @@ +package push + +import ( + "encoding/json" + "io" + "log/slog" + "os" + "strings" + + "github.com/hasura/go-graphql-client" +) + +type DeployEvent struct { + Typename string `json:"__typename"` + Result string `json:"result"` +} + +type subscription3 struct { + DeployEvents DeployEvent `json:"deployEvents"` +} + +type subscription2 struct { + DeployEvents struct { + Typename string `graphql:"__typename"` + Success *BuildEventSuccess `graphql:"... on BuildEventSuccess"` + Failure *BuildEventFailure `graphql:"... on BuildEventFailure"` + Info *BuildEventInfo `graphql:"... on BuildEventInfo"` + } `graphql:"deployEvents(toolID: $toolID)"` +} + +func getDeployEventLogs(toolID string) error { + client := getClient() + defer client.Close() + + err := deployEventSubscription(client, toolID, true) + if err != nil { + return err + } + + if err := client.Run(); err != nil { + return err + } + + return err +} + +func deployEventSubscription(client *graphql.SubscriptionClient, toolID string, verbose bool) error { + var sub subscription2 + var out io.Writer = os.Stdout + + variables := map[string]any{"toolID": graphql.ID(toolID)} + _, err := client.Subscribe(&sub, variables, func(dataValue []byte, err error) error { + if err != nil { + return err + } + data := subscription3{} + if err := json.Unmarshal([]byte(dataValue), &data); err != nil { + return err + } + if data.DeployEvents.Typename == "BuildEventInfo" { + for _, msg := range strings.Split(data.DeployEvents.Result, "\r\n") { + var b BuildEventMessage + + if err := json.Unmarshal([]byte(msg), &b); err != nil { + slog.Debug("error unmarshalling build event message", slog.Any("message", msg), slog.Any("error", err)) + continue + } + + if b.Message != "" { + printVerbose(out, b.Message, verbose) + } + } + } + + if data.DeployEvents.Typename == "BuildEventFailure" { + ProcessBuildEvent(data.DeployEvents.Result, out, true) + return nil + } + + if data.DeployEvents.Typename == "BuildEventSuccess" { + ProcessBuildEvent(data.DeployEvents.Result, out, true) + return nil + } + + return nil + }) + + return err +} diff --git a/cli/cmd/push/ignore.go b/cli/cmd/push/ignore.go new file mode 100644 index 00000000..faefcbc2 --- /dev/null +++ b/cli/cmd/push/ignore.go @@ -0,0 +1,139 @@ +package push + +import ( + "os" + "path" + "path/filepath" + "strings" +) + +const dblAsterisks = "**" + +// Match matches patterns in the same manner that gitignore does. +func Match(pattern, value string) bool { + // A blank line matches no files, so it can serve as a separator for readability. + if pattern == "" { + return false + } + + // Trailing spaces are ignored unless they are quoted with backslash ("\"). + pattern = strings.TrimSuffix(pattern, " ") + + // An optional prefix "!" which negates the pattern; any matching file + // excluded by a previous pattern will become included again. It is not + // possible to re-include a file if a parent directory of that file is excluded. + // Git doesn’t list excluded directories for performance reasons, so any patterns + // on contained files have no effect, no matter where they are defined. + // Put a backslash ("\") in front of the first "!" for patterns that begin + // with a literal "!", for example, "\!important!.txt". + negate := strings.HasPrefix(pattern, "!") + if negate { + pattern = strings.TrimPrefix(pattern, "!") + } + + // If the pattern ends with a slash, it is removed for the purpose of the + // following description, but it would only find a match with a directory. + // In other words, foo/ will match a directory foo and paths underneath it, + // but will not match a regular file or a symbolic link foo (this is consistent + // with the way how pathspec works in general in Git). + pattern = strings.TrimSuffix(pattern, string(os.PathSeparator)) + + // Two consecutive asterisks ("**") in patterns matched + // against full pathname may have special meaning: + if strings.Contains(pattern, dblAsterisks) { + result := evalDblAsterisk(pattern, value) + if negate { + result = !result + } + + return result + } + + if matchFolder(pattern, value) { + return true + } + + // Ensure match for global patterns like "*.py" and values like "folder/app.py" + if !strings.Contains(pattern, string(os.PathSeparator)) { + value = filepath.Base(value) + } + + // Otherwise, Git treats the pattern as a shell glob suitable for consumption by + // fnmatch(3) with the FNM_PATHNAME flag: wildcards in the pattern will not match + // a / in the pathname. For example, "Documentation/*.html" matches + // "Documentation/git.html" but not "Documentation/ppc/ppc.html" or + // "tools/perf/Documentation/perf.html". + + // A leading slash matches the beginning of the pathname. For example, "/*.c" matches "cat-file.c" but not "mozilla-sha1/sha1.c". + + matched, err := path.Match(pattern, value) + if err != nil { + // maybe log? + return false + } + + if negate { + return !matched + } + + return matched +} + +func evalDblAsterisk(pattern, value string) bool { + // A leading "**" followed by a slash means match in all directories. + // For example, "**/foo" matches file or directory "foo" anywhere, + // the same as pattern "foo". "**/foo/bar" matches file or directory + // "bar" anywhere that is directly under directory "foo". + if strings.HasPrefix(pattern, dblAsterisks) { + pattern = strings.TrimPrefix(pattern, dblAsterisks) + return strings.HasSuffix(value, pattern) + } + + // A trailing "/**" matches everything inside. For example, "abc/**" + // matches all files inside directory "abc", relative to the location + // of the .gitignore file, with infinite depth. + if strings.HasSuffix(pattern, dblAsterisks) { + pattern = strings.TrimSuffix(pattern, dblAsterisks) + return strings.HasPrefix(value, pattern) + } + + // A slash followed by two consecutive asterisks then a slash matches + // zero or more directories. For example, "a/**/b" matches "a/b", + // /"a/x/b", "a/x/y/b" and so on. + parts := strings.Split(pattern, dblAsterisks) + for i, part := range parts { + switch i { + case 0: + if !strings.HasPrefix(value, part) { + return false + } + case len(parts) - 1: // last part + part = strings.TrimPrefix(part, string(os.PathSeparator)) + return strings.HasSuffix(value, part) + default: + if !strings.Contains(value, part) { + return false + } + } + + // trim evaluated text + index := strings.Index(value, part) + len(part) + value = value[index:] + } + + // Other consecutive asterisks are considered invalid. + + return false +} + +func matchFolder(pattern, value string) bool { + for { + if !strings.Contains(value, string(os.PathSeparator)) { + return false + } + value = filepath.Dir(value) + if m, _ := filepath.Match(pattern, value); m { + return true + } + } +} diff --git a/cli/cmd/push/path_utils.go b/cli/cmd/push/path_utils.go new file mode 100644 index 00000000..6b3c380a --- /dev/null +++ b/cli/cmd/push/path_utils.go @@ -0,0 +1,26 @@ +package push + +import ( + "path/filepath" + "strings" +) + +func CheckAndReturnSubpath(basePath, subPath string) (bool, string, error) { + absBasePath, err := filepath.Abs(basePath) + if err != nil { + return false, "", err + } + absSubPath, err := filepath.Abs(subPath) + if err != nil { + return false, "", err + } + + appPath, err := filepath.Rel(absBasePath, absSubPath) + if err != nil { + return false, "", err + } + + isSub := !strings.HasPrefix(appPath, "..") && !strings.HasPrefix(appPath, string(filepath.Separator)) + + return isSub, appPath, nil +} diff --git a/cli/cmd/push/push.go b/cli/cmd/push/push.go new file mode 100644 index 00000000..376bdb83 --- /dev/null +++ b/cli/cmd/push/push.go @@ -0,0 +1,181 @@ +package push + +import ( + "fmt" + "io/fs" + "os" + "path/filepath" + "strings" + + "numerous/cli/internal/gql" + "numerous/cli/internal/gql/app" + "numerous/cli/manifest" + "numerous/cli/tool" + + "github.com/spf13/cobra" +) + +const zipFileName string = ".zipped_project.zip" + +var verbose bool + +var ( + carriageReturn = "\r" + greenColorEscapeANSI = "\033[32m" + resetColorEscapeANSI = "\033[0m" + unicodeCheckmark = "\u2713" + greenCheckmark = carriageReturn + greenColorEscapeANSI + unicodeCheckmark + resetColorEscapeANSI + unicodeHourglass = "\u29D6" +) + +const ( + ProjectArgLength = 1 + ProjectAndAppArgLength = 2 +) + +var PushCmd = &cobra.Command{ + Use: "push [project path] [app path]", + Short: "Pushes the app and returns a shareable URL (login required)", + Long: `Zip-compresses the tool project and pushes it to the numerous server, which +builds a docker image and runs it as a container. +A URL is generated which provides access to the tool, anyone with the URL can access the tool.`, + Run: push, +} + +func push(cmd *cobra.Command, args []string) { + appDir := "." + projectDir := "." + appPath := "" + + if len(args) == ProjectArgLength { + appDir = args[0] + projectDir = args[0] + } + + if len(args) == ProjectAndAppArgLength { + appDir = args[1] + projectDir = args[0] + result, rt, err := CheckAndReturnSubpath(projectDir, appDir) + if err != nil { + fmt.Printf("Error occurred validating app and project arguments:\n %s", err) + } + + if !result { + fmt.Printf("Error: Application path %s is not a subpath of project path %s", appDir, projectDir) + return + } + appPath = rt + } + + toolID, readToolErr := os.ReadFile(filepath.Join(appDir, tool.ToolIDFileName)) + m, readManifestErr := manifest.LoadManifest(filepath.Join(appDir, manifest.ManifestPath)) + if readToolErr != nil || readManifestErr != nil { + fmt.Println("The current directory is not a numerous app", + "\nrun \"numerous init\" to initialize a numerous app in the current directory") + + return + } + + if validated, err := m.ValidateApp(); err != nil { + fmt.Printf("An error occurred validating the app: %s", err) + os.Exit(1) + } else if !validated { + os.Exit(1) + } + + _, err := app.Query(string(toolID), gql.GetClient()) + if err != nil { + if strings.Contains(err.Error(), "record not found") { // TODO: replace strings-check with GraphQL error type, when GraphQL types exist. + fmt.Println("Sorry, we can't find that app ID in our database. Please make sure you have the correct app ID entered.", + "\nIf you have used the \"numerous delete\" command to delete your app, please delete your .app_id", + "\nfile and reinitialize your app using the \"numerous init\" command.") + + return + } + } + + if err := os.Chdir(projectDir); err != nil { + fmt.Printf("Could not access \"%s\"", projectDir) + return + } + + // Remove if zip already exist + if file, _ := os.Stat(zipFileName); file != nil { + os.Remove(zipFileName) + } + + if !verbose { + fmt.Print(unicodeHourglass + " Preparing upload...") + } + var filePermission fs.FileMode = 0o666 + zipFile, err := os.OpenFile(zipFileName, os.O_CREATE|os.O_RDWR, filePermission) + if err != nil { + fmt.Printf("Error preparing app.\nError: %s", err) + return + } + defer os.Remove(zipFileName) + + if err := ZipFolder(zipFile, m.Exclude); err != nil { + fmt.Printf("Error preparing app.\nError: %s", err) + return + } + zipFile.Close() + + fmt.Println(greenCheckmark + " Preparing upload...Done") + fmt.Print(unicodeHourglass + " Uploading app......") + + buildID, err := uploadZipFile(zipFileName, string(toolID)) + if err != nil { + fmt.Println("Sorry! An error occurred uploading your app") + + if strings.Contains(err.Error(), "server failure: failed to read file for key file") { + fmt.Println("The app folder is too large. The maximum size of an app folder is currently 256MB.") + fmt.Println("If you have large files, which are not needed for your app, consider adding them to the 'exclude' field in 'numerous.toml'") + } else { + fmt.Printf("Error in uploading app.\nError: %s", err) + } + + return + } + + fmt.Println(greenCheckmark + " Uploading app......Done") + + fmt.Print(unicodeHourglass + " Building app.......") + if verbose { // To allow nice printing of build messages from backend + fmt.Println() + } + + err = getBuildEventLogs(buildID, appPath, verbose) + if err != nil { + fmt.Printf("Error listening for build logs.\nError: %s", err) + return + } + + fmt.Println(greenCheckmark + " Building app.......Done") + fmt.Print(unicodeHourglass + " Deploying app......") + + err = stopJobs(string(toolID)) + if err != nil { + fmt.Printf("Error stopping previous jobs.\nError: %s", err) + return + } + + err = getDeployEventLogs(string(toolID)) + if err != nil { + fmt.Printf("Error listening for deploy logs.\nError: %s", err) + return + } + + fmt.Println(greenCheckmark + " Deploying app......Done") + + pushedTool, err := app.Query(string(toolID), gql.GetClient()) + if err != nil { + fmt.Printf("Error reading the app.\nError: %s\n", err) + return + } + fmt.Printf("\nShareable url: %s\n", pushedTool.SharedURL) +} + +func init() { + PushCmd.Flags().BoolVarP(&verbose, "verbose", "v", false, "Provide more verbose output of the push process") +} diff --git a/cli/cmd/push/push_test.go b/cli/cmd/push/push_test.go new file mode 100644 index 00000000..cbc440bd --- /dev/null +++ b/cli/cmd/push/push_test.go @@ -0,0 +1,65 @@ +package push + +import ( + "bytes" + "testing" + + "github.com/stretchr/testify/assert" +) + +var verbosePrintTestCases = []struct { + name string + expected string + verbose bool +}{ + {name: "Verbose flag is false", expected: " Build: Building app.......\n Build: ---> Using cache\n Build: ---> 5dee4a5dd2e0\n Build: Step 4/7 : RUN pip install -r /app/requirements.txt\n Build: \n Build: Step 1/7 : FROM python:3.11-slim\n Build: \n Build: ---> f8e98f0336d5\n Build: Step 2/7 : EXPOSE 80\n Build: \n Build: ---> Using cache\n Build: ---> 70cbb8104f4d\n Build: Step 3/7 : COPY ./requirements.txt /app/requirements.txt\n Build: \n Build: ---> Using cache\n Build: ---> dc49b771620c\n Build: Step 5/7 : COPY . /app\n Build: \n Build: ---> Using cache\n Build: ---> 5f020e3f851a\n Build: Step 6/7 : WORKDIR /app\n Build: \n Build: ---> Using cache\n Build: ---> 36a177af492a\n Build: Step 7/7 : CMD [\"streamlit\", \"run\", \"app.py\", \"--server.port\", \"80\"]\n Build: \n Build: ---> Using cache\n Build: ---> f5b4a0f5108b\n Build: Successfully built f5b4a0f5108b\n Build: Successfully tagged 00a66264-651b-43ec-b46d-a176a653657c:latest\n", verbose: true}, + {name: "Verbose flag is true", expected: "", verbose: false}, +} + +func TestPrintVerbose(t *testing.T) { + for _, test := range verbosePrintTestCases { + t.Run(test.name, func(t *testing.T) { + buildEventMessages := []string{ + "Building app.......", + "---> Using cache", + "---> 5dee4a5dd2e0", + "Step 4/7 : RUN pip install -r /app/requirements.txt", + "", + "Step 1/7 : FROM python:3.11-slim", + "", + "---> f8e98f0336d5", + "Step 2/7 : EXPOSE 80", + "", + "---> Using cache", + "---> 70cbb8104f4d", + "Step 3/7 : COPY ./requirements.txt /app/requirements.txt", + "", + "---> Using cache", + "---> dc49b771620c", + "Step 5/7 : COPY . /app", + "", + "---> Using cache", + "---> 5f020e3f851a", + "Step 6/7 : WORKDIR /app", + "", + "---> Using cache", + "---> 36a177af492a", + "Step 7/7 : CMD [\"streamlit\", \"run\", \"app.py\", \"--server.port\", \"80\"]", + "", + "---> Using cache", + "---> f5b4a0f5108b", + "Successfully built f5b4a0f5108b", + "Successfully tagged 00a66264-651b-43ec-b46d-a176a653657c:latest", + } + + out := new(bytes.Buffer) + + for _, elem := range buildEventMessages { + printVerbose(out, elem, test.verbose) + } + outContent := (*bytes.Buffer).String(out) + + assert.Equal(t, test.expected, outContent) + }) + } +} diff --git a/cli/cmd/push/send_file.go b/cli/cmd/push/send_file.go new file mode 100644 index 00000000..0512d528 --- /dev/null +++ b/cli/cmd/push/send_file.go @@ -0,0 +1,25 @@ +package push + +import ( + "io/fs" + "os" + + "numerous/cli/internal/gql" + "numerous/cli/internal/gql/build" +) + +func uploadZipFile(zipFilePath string, appID string) (string, error) { + var filePermission fs.FileMode = 0o666 + zipFile, err := os.OpenFile(zipFilePath, os.O_CREATE|os.O_RDWR, filePermission) + if err != nil { + return "", err + } + defer zipFile.Close() + + build, err := build.Push(zipFile, appID, gql.GetClient()) + if err != nil { + return "", err + } + + return build.BuildID, nil +} diff --git a/cli/cmd/push/stop_jobs.go b/cli/cmd/push/stop_jobs.go new file mode 100644 index 00000000..a5bb393b --- /dev/null +++ b/cli/cmd/push/stop_jobs.go @@ -0,0 +1,22 @@ +package push + +import ( + "numerous/cli/internal/gql" + "numerous/cli/internal/gql/jobs" +) + +func stopJobs(id string) error { + jobsByTool, err := jobs.JobsByTool(id, gql.GetClient()) + if err != nil { + return err + } + + for _, job := range jobsByTool { + _, err = jobs.JobStop(job.ID, gql.GetClient()) + if err != nil { + return err + } + } + + return nil +} diff --git a/cli/cmd/push/zip.go b/cli/cmd/push/zip.go new file mode 100644 index 00000000..c5a7a11c --- /dev/null +++ b/cli/cmd/push/zip.go @@ -0,0 +1,72 @@ +package push + +import ( + "archive/zip" + "io" + "os" + "path/filepath" +) + +// ZipFolder compresses the current directory into a zip-file. +// It returns an error if anything fails, else nil. +func ZipFolder(zipFile *os.File, exclude []string) error { + zipWriter := zip.NewWriter(zipFile) + defer zipWriter.Close() + + return filepath.Walk(".", func(path string, info os.FileInfo, err error) error { + if err != nil { + return err + } + + if shouldExclude(exclude, path) || info.Name() == zipFile.Name() { + return nil + } + + header, err := zip.FileInfoHeader(info) + if err != nil { + return err + } + + // Ensure the header name is a relative path to avoid file path disclosure. + relPath, err := filepath.Rel(".", path) + if err != nil { + return err + } + header.Name = relPath + + // Ensure folder names end with a slash to distinguish them in the zip. + if info.IsDir() { + header.Name += "/" + } + + writer, err := zipWriter.CreateHeader(header) + if err != nil { + return err + } + + // Only copy file content; directories are added as empty entries. + if !info.IsDir() { + file, err := os.Open(path) + if err != nil { + return err + } + defer file.Close() + + _, err = io.Copy(writer, file) + + return err // err could be nil or an actual error + } + + return nil + }) +} + +func shouldExclude(excludedPatterns []string, path string) bool { + for _, pattern := range excludedPatterns { + if Match(pattern, path) { + return true + } + } + + return false +} diff --git a/cli/cmd/push/zip_test.go b/cli/cmd/push/zip_test.go new file mode 100644 index 00000000..932aa4cf --- /dev/null +++ b/cli/cmd/push/zip_test.go @@ -0,0 +1,57 @@ +package push + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestShouldExclude(t *testing.T) { + tests := []struct { + excludePatterns []string + includedFiles []string + excludedFiles []string + }{ + { + excludePatterns: []string{"*.go"}, + excludedFiles: []string{"exclude_file.go", "included_folder/excluded_file.go"}, + includedFiles: []string{"included_file.py", "included_folder/included_file.py"}, + }, + { + excludePatterns: []string{"venv"}, + excludedFiles: []string{"venv/exclude_file.py", "venv/folder/excluded_file.py"}, + includedFiles: []string{"included_file.py", "included_folder/included_file.py"}, + }, + { + excludePatterns: []string{"*venv"}, + excludedFiles: []string{".venv/exclude_file.py", ".venv/folder/excluded_file.py", "venv/excluded_file.py"}, + includedFiles: []string{"included_file.py", "included_folder/included_file.py"}, + }, + { + excludePatterns: []string{"venv*"}, + excludedFiles: []string{"venv1/exclude_file.py", "venv1/folder/excluded_file.py", "venv/excluded_file.py"}, + includedFiles: []string{"included_file.py", "1venv/included_file.py"}, + }, + { + excludePatterns: []string{"venv"}, + excludedFiles: []string{"venv/exclude_file.py", "venv/folder/excluded_file.py"}, + includedFiles: []string{"included_file.py", "included_folder/included_file.py"}, + }, + { + excludePatterns: []string{"excluded_file.py"}, + excludedFiles: []string{"venv/excluded_file.py", "included_folder/excluded_file.py", "excluded_file.py"}, + includedFiles: []string{"included_file.py", "included_folder/included_file.py"}, + }, + } + for _, test := range tests { + t.Run(fmt.Sprintf("Testing pattern: %v", test.excludePatterns), func(t *testing.T) { + for _, path := range test.includedFiles { + assert.False(t, shouldExclude(test.excludePatterns, path), path) + } + for _, path := range test.excludedFiles { + assert.True(t, shouldExclude(test.excludePatterns, path), path) + } + }) + } +} diff --git a/cli/cmd/report/report.go b/cli/cmd/report/report.go new file mode 100644 index 00000000..22ddd40c --- /dev/null +++ b/cli/cmd/report/report.go @@ -0,0 +1,58 @@ +package report + +import ( + "errors" + "fmt" + "os/exec" + "runtime" + + "github.com/spf13/cobra" +) + +const numerousReportURL = "https://numerous.com" + +var ReportCmd = &cobra.Command{ + Use: "report", + Short: "Opens numerous report and feedback page.", + Args: cobra.NoArgs, + Run: func(cmd *cobra.Command, args []string) { + if err := openURL(numerousReportURL); err != nil { + fmt.Println("Error:", err) + } + }, +} + +func openURL(url string) error { + cmd, args, err := setCmdByOS() + if err != nil { + return err + } + fmt.Println("Opening the report page in your default browser.") + args = append(args, url) + + return exec.Command(cmd, args...).Start() +} + +func setCmdByOS() (string, []string, error) { + switch runtime.GOOS { + case "windows": + return "cmd", []string{"/c", "start"}, nil + case "darwin": + return "open", nil, nil + case "freebsd", "openbsd", "netbsd": + return "xdg-open", nil, nil + case "linux": + out, err := exec.Command("sh", "-c", "grep -i Microsoft /proc/version").Output() + if err != nil { + fmt.Println("Error:", err) + return "", nil, err + } + if string(out) != "" { + return "sensible-browser", nil, nil + } else { + return "xdg-open", nil, nil + } + default: + return "", nil, errors.New("it wasn't possible to identify your OS") + } +} diff --git a/cli/cmd/root.go b/cli/cmd/root.go new file mode 100644 index 00000000..0c8a40d9 --- /dev/null +++ b/cli/cmd/root.go @@ -0,0 +1,132 @@ +package cmd + +import ( + "errors" + "fmt" + "log/slog" + "net/http" + "os" + "runtime" + + "numerous/cli/auth" + deleteapp "numerous/cli/cmd/delete" + "numerous/cli/cmd/dev" + "numerous/cli/cmd/initialize" + "numerous/cli/cmd/list" + "numerous/cli/cmd/log" + "numerous/cli/cmd/login" + "numerous/cli/cmd/logout" + "numerous/cli/cmd/organization" + createorganization "numerous/cli/cmd/organization/create" + listorganization "numerous/cli/cmd/organization/list" + "numerous/cli/cmd/publish" + "numerous/cli/cmd/push" + "numerous/cli/cmd/report" + "numerous/cli/cmd/unpublish" + "numerous/cli/logging" + + "github.com/spf13/cobra" +) + +// TODO: add lipgloss lib here instead of using bash and unicode hardcoded! Check cli/appdev/output +const ( + resetPrompt = "\033[0m" + cyanBold = "\033[1;36m" + raiseHandEmoji = "\U0000270B" + shootingStarEmoji = "\U0001F320" +) + +var ( + logLevel logging.Level = logging.LevelError + rootCmd = &cobra.Command{ + Use: "numerous", + Long: "\n ~~~ \n" + + " --- ~~~~~~~ \n" + + " ° ------- ~~~~~~~~~~ \n" + + " °°°° ----------- ~~~~~~~~~\n" + + " °°°°°°° ----------- ~~~~~~~~ _ _ \n" + + " °°°°°°°°°° ------- ~~~~~~~~ | \\ | | \n" + + " °°°°°°°°°°°°° ----- ~~~~~~~ | \\| |_ _ _ __ ___ ___ _ __ ___ _ _ ___\n" + + " °°°°°°°°°°°°° ----- ~~~~~~~ | . ` | | | | '_ ` _ \\ / _ \\ '__/ _ \\| | | / __|\n" + + " °°°°°°°°°°°°° ----- ~~~~ | |\\ | |_| | | | | | | __/ | | (_) | |_| \\__ \\\n" + + " °°°°°°°°°°°°° ---- ~~ |_| \\_|\\__,_|_| |_| |_|\\___|_| \\___/ \\__,_|___/\n" + + " °°°°°°°°°° --\n" + + " °°°°°°°° \n" + + " °°°°° \n" + + " °° \n" + + "", + SilenceUsage: true, + PersistentPreRunE: func(cmd *cobra.Command, args []string) error { + if commandRequiresAuthentication(cmd.CommandPath()) { + user := auth.NumerousTenantAuthenticator.GetLoggedInUserFromKeyring() + if user.CheckAuthenticationStatus() == auth.ErrUserNotLoggedIn { + if runtime.GOOS == "windows" { + fmt.Printf("\"%s\" can only be used when logged in.\n", cmd.CommandPath()) + fmt.Println("Use \"numerous login\" to enable this command.") + } else { + fmt.Printf("The use of %s%s%s command can only be done when logged in %s\n", cyanBold, cmd.CommandPath(), resetPrompt, raiseHandEmoji) + fmt.Printf("To enable it, please first proceed with %snumerous login%s %s\n", cyanBold, resetPrompt, shootingStarEmoji) + } + + return errors.New("not authorized") + } + if err := login.RefreshAccessToken(user, http.DefaultClient, auth.NumerousTenantAuthenticator); err != nil { + return err + } + } + + return nil + }, + } +) + +func commandRequiresAuthentication(invokedCommandName string) bool { + commandsWithAuthRequired := []string{ + "numerous list", + "numerous push", + "numerous log", + "numerous organization create", + "numerous organization list", + } + + for _, cmd := range commandsWithAuthRequired { + if cmd == invokedCommandName { + return true + } + } + + return false +} + +func bindCommands() { + rootCmd.AddCommand(initialize.InitCmd) + rootCmd.AddCommand(push.PushCmd) + rootCmd.AddCommand(log.LogCmd) + rootCmd.AddCommand(deleteapp.DeleteCmd) + rootCmd.AddCommand(login.LoginCmd) + rootCmd.AddCommand(logout.LogoutCmd) + rootCmd.AddCommand(dev.DevCmd) + rootCmd.AddCommand(publish.PublishCmd) + rootCmd.AddCommand(unpublish.UnpublishCmd) + rootCmd.AddCommand(list.ListCmd) + rootCmd.AddCommand(report.ReportCmd) + rootCmd.AddCommand(organization.OrganizationRootCmd) + organization.OrganizationRootCmd.AddCommand(createorganization.OrganizationCreateCmd) + organization.OrganizationRootCmd.AddCommand(listorganization.OrganizationListCmd) +} + +func Execute() { + err := rootCmd.Execute() + // fmt.Println(auth.NumerousTenantAuthenticator.GetLoggedInUserFromKeyring().AccessToken) + if err != nil { + os.Exit(1) + } +} + +func init() { + rootCmd.PersistentFlags().VarP(&logLevel, "log-level", "l", "The log level, one of \"debug\", \"info\", \"warning\", or \"error\". Defaults to \"error\".") + bindCommands() + cobra.OnInitialize(func() { + slog.SetDefault(slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: logLevel.ToSlogLevel()}))) + }) +} diff --git a/cli/cmd/unpublish/unpublish.go b/cli/cmd/unpublish/unpublish.go new file mode 100644 index 00000000..586978aa --- /dev/null +++ b/cli/cmd/unpublish/unpublish.go @@ -0,0 +1,58 @@ +package unpublish + +import ( + "fmt" + "os" + + "numerous/cli/internal/gql" + "numerous/cli/internal/gql/app" + "numerous/cli/tool" + + "git.sr.ht/~emersion/gqlclient" + "github.com/spf13/cobra" +) + +var UnpublishCmd = &cobra.Command{ + Use: "unpublish", + Short: "Removes a published app from the public app gallery", + Run: func(cmd *cobra.Command, args []string) { + err := unpublish(gql.GetClient()) + if err != nil { + os.Exit(1) + } + }, +} + +func unpublish(client *gqlclient.Client) error { + appID, err := tool.ReadToolID(".") + if err == tool.ErrToolIDNotFound { + fmt.Println("The current directory is not a numerous app", + "\nrun \"numerous init\" to initialize a numerous app in the current directory") + + return err + } else if err != nil { + fmt.Println("An error occurred reading the app ID") + fmt.Println("Error: ", err) + + return err + } + + if a, err := app.Query(appID, client); err != nil { + fmt.Println("The app could not be found in the database.") + return err + } else if a.PublicURL == "" { + fmt.Println("The app is currently not published to the public app gallery!") + return nil + } + + if _, err := app.Unpublish(appID, client); err != nil { + fmt.Println("An error occurred when unpublishing the app") + fmt.Println("Error: ", err) + + return err + } else { + fmt.Println("The app has been removed from the public app gallery!") + + return nil + } +} diff --git a/cli/cmd/unpublish/unpublish_test.go b/cli/cmd/unpublish/unpublish_test.go new file mode 100644 index 00000000..9fd36f0e --- /dev/null +++ b/cli/cmd/unpublish/unpublish_test.go @@ -0,0 +1,64 @@ +package unpublish + +import ( + "testing" + + "numerous/cli/internal/gql/app" + "numerous/cli/test" + + "github.com/stretchr/testify/assert" +) + +func TestAppPublish(t *testing.T) { + t.Run("returns nil and successfully sends AppUnpublish mutations", func(t *testing.T) { + test.ChdirToTmpDirWithAppIDDocument(t, "id") + app := app.App{ + ID: "id", + SharedURL: "https://test.com/shared/some-hash", + PublicURL: "https://test.com/public/another-hash", + } + appQueryResponse := test.AppToQueryResult("tool", app) + test.AppToQueryResult("ad", app) + app.PublicURL = "" + appUnpublishResponse := test.AppToQueryResult("toolUnpublish", app) + + c, transportMock := test.CreateMockGqlClient(appQueryResponse, appUnpublishResponse) + err := unpublish(c) + assert.NoError(t, err) + transportMock.AssertExpectations(t) + }) + + t.Run("returns error if app does not exist", func(t *testing.T) { + test.ChdirToTmpDirWithAppIDDocument(t, "id") + appNotFoundResponse := `{"errors":[{"message":"record not found","path":["tool"]}],"data":null}` + c, transportMock := test.CreateMockGqlClient(appNotFoundResponse) + + err := unpublish(c) + + assert.Error(t, err) + transportMock.AssertExpectations(t) + }) + + t.Run("returns error if app id document does not exists in the current directory", func(t *testing.T) { + c, transportMock := test.CreateMockGqlClient() + err := unpublish(c) + + assert.Error(t, err) + transportMock.AssertExpectations(t) + }) + + t.Run("return nil and does not send AppUnpublish mutation, if app is not published", func(t *testing.T) { + test.ChdirToTmpDirWithAppIDDocument(t, "id") + app := app.App{ + ID: "id", + SharedURL: "https://test.com/shared/some-hash", + } + appQueryResponse := test.AppToQueryResult("tool", app) + + c, transportMock := test.CreateMockGqlClient(appQueryResponse) + err := unpublish(c) + + assert.NoError(t, err) + transportMock.AssertExpectations(t) + }) +} diff --git a/cli/go.mod b/cli/go.mod new file mode 100644 index 00000000..9e2bf743 --- /dev/null +++ b/cli/go.mod @@ -0,0 +1,65 @@ +module numerous/cli + +go 1.21 + +require ( + git.sr.ht/~emersion/gqlclient v0.0.0-20230820050442-8873fe0204b9 + github.com/99designs/gqlgen v0.17.45 + github.com/AlecAivazis/survey/v2 v2.3.7 + github.com/BurntSushi/toml v1.3.2 + github.com/charmbracelet/lipgloss v0.10.0 + github.com/fsnotify/fsnotify v1.7.0 + github.com/google/uuid v1.6.0 + github.com/gorilla/websocket v1.5.1 + github.com/hasura/go-graphql-client v0.11.0 + github.com/lestrrat-go/jwx v1.2.28 + github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c + github.com/rs/cors v1.10.1 + github.com/spf13/cobra v1.8.0 + github.com/stretchr/testify v1.9.0 + github.com/vektah/gqlparser/v2 v2.5.11 + github.com/zalando/go-keyring v0.2.3 + gorm.io/gorm v1.25.6 +) + +require ( + github.com/agnivade/levenshtein v1.1.1 // indirect + github.com/alessio/shellescape v1.4.1 // indirect + github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect + github.com/danieljoos/wincred v1.2.0 // indirect + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 // indirect + github.com/goccy/go-json v0.10.2 // indirect + github.com/godbus/dbus/v5 v5.1.0 // indirect + github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect + github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect + github.com/lestrrat-go/backoff/v2 v2.0.8 // indirect + github.com/lestrrat-go/blackmagic v1.0.2 // indirect + github.com/lestrrat-go/httpcc v1.0.1 // indirect + github.com/lestrrat-go/iter v1.0.2 // indirect + github.com/lestrrat-go/option v1.0.1 // indirect + github.com/lucasb-eyer/go-colorful v1.2.0 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect + github.com/mitchellh/mapstructure v1.5.0 // indirect + github.com/muesli/reflow v0.3.0 // indirect + github.com/muesli/termenv v0.15.2 // indirect + github.com/pkg/errors v0.9.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + github.com/rivo/uniseg v0.4.7 // indirect + github.com/sosodev/duration v1.2.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/stretchr/objx v0.5.2 // indirect + golang.org/x/crypto v0.21.0 // indirect + golang.org/x/net v0.22.0 // indirect + golang.org/x/sys v0.18.0 // indirect + golang.org/x/term v0.18.0 // indirect + golang.org/x/text v0.14.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + nhooyr.io/websocket v1.8.10 // indirect +) diff --git a/cli/go.sum b/cli/go.sum new file mode 100644 index 00000000..f0bc01d3 --- /dev/null +++ b/cli/go.sum @@ -0,0 +1,201 @@ +git.sr.ht/~emersion/gqlclient v0.0.0-20230820050442-8873fe0204b9 h1:QNwHP6WknvS7X6MEFxCpefQb1QJMqgIIt+vn/PVoMMg= +git.sr.ht/~emersion/gqlclient v0.0.0-20230820050442-8873fe0204b9/go.mod h1:kvl/JK0Z3VRmtbBxdOJR4ydyXVouUIcFIXgv4H6rVAY= +github.com/99designs/gqlgen v0.17.45 h1:bH0AH67vIJo8JKNKPJP+pOPpQhZeuVRQLf53dKIpDik= +github.com/99designs/gqlgen v0.17.45/go.mod h1:Bas0XQ+Jiu/Xm5E33jC8sES3G+iC2esHBMXcq0fUPs0= +github.com/AlecAivazis/survey/v2 v2.3.7 h1:6I/u8FvytdGsgonrYsVn2t8t4QiRnh6QSTqkkhIiSjQ= +github.com/AlecAivazis/survey/v2 v2.3.7/go.mod h1:xUTIdE4KCOIjsBAE1JYsUPoCqYdZ1reCfTwbto0Fduo= +github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8= +github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2 h1:+vx7roKuyA63nhn5WAunQHLTznkw5W8b1Xc0dNjp83s= +github.com/Netflix/go-expect v0.0.0-20220104043353-73e0943537d2/go.mod h1:HBCaDeC1lPdgDeDbhX8XFpy1jqjK0IBG8W5K+xYqA0w= +github.com/PuerkitoBio/goquery v1.9.1 h1:mTL6XjbJTZdpfL+Gwl5U2h1l9yEkJjhmlTeV9VPW7UI= +github.com/PuerkitoBio/goquery v1.9.1/go.mod h1:cW1n6TmIMDoORQU5IU/P1T3tGFunOeXEpGP2WHRwkbY= +github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8= +github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo= +github.com/agnivade/levenshtein v1.1.1 h1:QY8M92nrzkmr798gCo3kmMyqXFzdQVpxLlGPRBij0P8= +github.com/agnivade/levenshtein v1.1.1/go.mod h1:veldBMzWxcCG2ZvUTKD2kJNRdCk5hVbJomOvKkmgYbo= +github.com/alessio/shellescape v1.4.1 h1:V7yhSDDn8LP4lc4jS8pFkt0zCnzVJlG5JXy9BVKJUX0= +github.com/alessio/shellescape v1.4.1/go.mod h1:PZAiSCk0LJaZkiCSkPv8qIobYglO3FPpyFjDCtHLS30= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= +github.com/andybalholm/cascadia v1.3.2 h1:3Xi6Dw5lHF15JtdcmAHD3i1+T8plmv7BQ/nsViSLyss= +github.com/andybalholm/cascadia v1.3.2/go.mod h1:7gtRlve5FxPPgIgX36uWBX58OdBsSS6lUvCFb+h7KvU= +github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0 h1:jfIu9sQUG6Ig+0+Ap1h4unLjW6YQJpKZVmUzxsD4E/Q= +github.com/arbovm/levenshtein v0.0.0-20160628152529-48b4e1c0c4d0/go.mod h1:t2tdKJDJF9BV14lnkjHmOQgcvEKgtqs5a1N3LNdJhGE= +github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= +github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= +github.com/charmbracelet/lipgloss v0.10.0 h1:KWeXFSexGcfahHX+54URiZGkBFazf70JNMtwg/AFW3s= +github.com/charmbracelet/lipgloss v0.10.0/go.mod h1:Wig9DSfvANsxqkRsqj6x87irdy123SR4dOXlKa91ciE= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/creack/pty v1.1.17 h1:QeVUsEDNrLBW4tMgZHvxy18sKtr6VI492kBhUfhDJNI= +github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= +github.com/danieljoos/wincred v1.2.0 h1:ozqKHaLK0W/ii4KVbbvluM91W2H3Sh0BncbUNPS7jLE= +github.com/danieljoos/wincred v1.2.0/go.mod h1:FzQLLMKBFdvu+osBrnFODiv32YGwCfx0SkRa/eYHgec= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/decred/dcrd/crypto/blake256 v1.0.1/go.mod h1:2OfgNZ5wDpcsFmHmCK5gZTPcCXqlm2ArzUIkw9czNJo= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0 h1:8UrgZ3GkP4i/CLijOJx79Yu+etlyjdBU4sfcs2WYQMs= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.2.0/go.mod h1:v57UDF4pDQJcEfFUCRop3lJL149eHGSe9Jvczhzjo/0= +github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48 h1:fRzb/w+pyskVMQ+UbP35JkH8yB7MYb4q/qhBarqZE6g= +github.com/dgryski/trifles v0.0.0-20200323201526-dd97f9abfb48/go.mod h1:if7Fbed8SFyPtHLHbg49SI7NAdJiC5WIA09pe59rfAA= +github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= +github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= +github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= +github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= +github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk= +github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= +github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= +github.com/graph-gophers/graphql-go v1.5.0 h1:fDqblo50TEpD0LY7RXk/LFVYEVqo3+tXMNMPSVXA1yc= +github.com/graph-gophers/graphql-go v1.5.0/go.mod h1:YtmJZDLbF1YYNrlNAuiO5zAStUWc3XZT07iGsVqe1Os= +github.com/graph-gophers/graphql-transport-ws v0.0.2 h1:DbmSkbIGzj8SvHei6n8Mh9eLQin8PtA8xY9eCzjRpvo= +github.com/graph-gophers/graphql-transport-ws v0.0.2/go.mod h1:5BVKvFzOd2BalVIBFfnfmHjpJi/MZ5rOj8G55mXvZ8g= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= +github.com/hasura/go-graphql-client v0.11.0 h1:EFEkpMZlkq5gLZj9oiI6TnHCOHV1oErxOroMc5qUHQI= +github.com/hasura/go-graphql-client v0.11.0/go.mod h1:eNNnmHAp6NgwKZ4xRbZEfywxr07qk34Y0QhbPsYIfhw= +github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog= +github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= +github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= +github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= +github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= +github.com/lestrrat-go/backoff/v2 v2.0.8 h1:oNb5E5isby2kiro9AgdHLv5N5tint1AnDVVf2E2un5A= +github.com/lestrrat-go/backoff/v2 v2.0.8/go.mod h1:rHP/q/r9aT27n24JQLa7JhSQZCKBBOiM/uP402WwN8Y= +github.com/lestrrat-go/blackmagic v1.0.2 h1:Cg2gVSc9h7sz9NOByczrbUvLopQmXrfFx//N+AkAr5k= +github.com/lestrrat-go/blackmagic v1.0.2/go.mod h1:UrEqBzIR2U6CnzVyUtfM6oZNMt/7O7Vohk2J0OGSAtU= +github.com/lestrrat-go/httpcc v1.0.1 h1:ydWCStUeJLkpYyjLDHihupbn2tYmZ7m22BGkcvZZrIE= +github.com/lestrrat-go/httpcc v1.0.1/go.mod h1:qiltp3Mt56+55GPVCbTdM9MlqhvzyuL6W/NMDA8vA5E= +github.com/lestrrat-go/iter v1.0.2 h1:gMXo1q4c2pHmC3dn8LzRhJfP1ceCbgSiT9lUydIzltI= +github.com/lestrrat-go/iter v1.0.2/go.mod h1:Momfcq3AnRlRjI5b5O8/G5/BvpzrhoFTZcn06fEOPt4= +github.com/lestrrat-go/jwx v1.2.28 h1:uadI6o0WpOVrBSf498tRXZIwPpEtLnR9CvqPFXeI5sA= +github.com/lestrrat-go/jwx v1.2.28/go.mod h1:nF+91HEMh/MYFVwKPl5HHsBGMPscqbQb+8IDQdIazP8= +github.com/lestrrat-go/option v1.0.0/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= +github.com/lestrrat-go/option v1.0.1 h1:oAzP2fvZGQKWkvHa1/SAcFolBEca1oN+mQ7eooNBEYU= +github.com/lestrrat-go/option v1.0.1/go.mod h1:5ZHFbivi4xwXxhxY9XHDe2FHo6/Z7WWmtT7T5nBBp3I= +github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= +github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4= +github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE= +github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= +github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s= +github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8= +github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo= +github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ= +github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rs/cors v1.10.1 h1:L0uuZVXIKlI1SShY2nhFfo44TYvDPQ1w4oFkUJNfhyo= +github.com/rs/cors v1.10.1/go.mod h1:XyqrcTp5zjWr1wsJ8PIRZssZ8b/WMcMf71DJnit4EMU= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8= +github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I= +github.com/sosodev/duration v1.2.0 h1:pqK/FLSjsAADWY74SyWDCjOcd5l7H8GSnnOGEB9A1Us= +github.com/sosodev/duration v1.2.0/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= +github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= +github.com/vektah/gqlparser/v2 v2.5.11 h1:JJxLtXIoN7+3x6MBdtIP59TP1RANnY7pXOaDnADQSf8= +github.com/vektah/gqlparser/v2 v2.5.11/go.mod h1:1rCcfwB2ekJofmluGWXMSEnPMZgbxzwj6FaZ/4OT8Cc= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +github.com/zalando/go-keyring v0.2.3 h1:v9CUu9phlABObO4LPWycf+zwMG7nlbb3t/B5wa97yms= +github.com/zalando/go-keyring v0.2.3/go.mod h1:HL4k+OXQfJUWaMnqyuSOc0drfGPX2b51Du6K+MRgZMk= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= +golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= +golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= +golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gorm.io/gorm v1.25.6 h1:V92+vVda1wEISSOMtodHVRcUIOPYa2tgQtyF+DfFx+A= +gorm.io/gorm v1.25.6/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8= +nhooyr.io/websocket v1.8.10 h1:mv4p+MnGrLDcPlBoWsvPP7XCzTYMXP9F9eIGoKbgx7Q= +nhooyr.io/websocket v1.8.10/go.mod h1:rN9OFWIUwuxg4fR5tELlYC04bXYowCP9GX47ivo2l+c= diff --git a/cli/gqlgen.yml b/cli/gqlgen.yml new file mode 100644 index 00000000..8c7e1b8e --- /dev/null +++ b/cli/gqlgen.yml @@ -0,0 +1,87 @@ +# Where are all the schema files located? globs are supported eg src/**/*.graphqls +schema: + - ../shared/schema.gql + +# Where should the generated server code go? +exec: + filename: graphql/generated.go + package: graphql + +# Uncomment to enable federation +# federation: +# filename: graphql/federation.go +# package: graph + +# Where should any generated models go? +model: + filename: graphql/model/models_gen.go + package: model + +# Where should the resolver implementations go? +resolver: + layout: follow-schema + dir: graphql + package: graphql + filename_template: "{name}.resolvers.go" + # Optional: turn on to not generate template comments above resolvers + # omit_template_comment: false + +# Optional: turn on use ` + "`" + `gqlgen:"fieldName"` + "`" + ` tags in your models +# struct_tag: json + +# Optional: turn on to use []Thing instead of []*Thing +# omit_slice_element_pointers: false + +# Optional: turn on to omit Is() methods to interface and unions +# omit_interface_checks : true + +# Optional: turn on to skip generation of ComplexityRoot struct content and Complexity function +# omit_complexity: false + +# Optional: turn on to not generate any file notice comments in generated files +# omit_gqlgen_file_notice: false + +# Optional: turn on to exclude the gqlgen version in the generated file notice. No effect if `omit_gqlgen_file_notice` is true. +# omit_gqlgen_version_in_file_notice: false + +# Optional: turn off to make struct-type struct fields not use pointers +# e.g. type Thing struct { FieldA OtherThing } instead of { FieldA *OtherThing } +# struct_fields_always_pointers: true + +# Optional: turn off to make resolvers return values instead of pointers for structs +# resolvers_always_return_pointers: true + +# Optional: turn on to return pointers instead of values in unmarshalInput +# return_pointers_in_unmarshalinput: false + +# Optional: wrap nullable input fields with Omittable +# nullable_input_omittable: true + +# Optional: set to speed up generation time by not performing a final validation pass. +# skip_validation: true + +# Optional: set to skip running `go mod tidy` when generating server code +# skip_mod_tidy: true + +# gqlgen will search for any type names in the schema in these go packages +# if they match it will use them, otherwise it will generate them. +autobind: +# - "numerous/cli/graphql/model" + +# This section declares type mapping between the GraphQL and go type systems +# +# The first line in each type will be used as defaults for resolver arguments and +# modelgen, the others will be allowed when binding to fields. Configure them to +# your liking +models: + ID: + model: + - github.com/99designs/gqlgen/graphql.ID + - github.com/99designs/gqlgen/graphql.Int + - github.com/99designs/gqlgen/graphql.Int64 + - github.com/99designs/gqlgen/graphql.Int32 + Int: + model: + - github.com/99designs/gqlgen/graphql.Int + - github.com/99designs/gqlgen/graphql.Int64 + - github.com/99designs/gqlgen/graphql.Int32 diff --git a/cli/graphql/convert.go b/cli/graphql/convert.go new file mode 100644 index 00000000..c4385045 --- /dev/null +++ b/cli/graphql/convert.go @@ -0,0 +1,219 @@ +package graphql + +import ( + "fmt" + "log/slog" + "strconv" + + "numerous/cli/appdev" + "numerous/cli/graphql/model" + + "github.com/google/uuid" +) + +func AppSessionFromDomain(session appdev.AppSession) *model.ToolSession { + s := &model.ToolSession{ + ID: convertID(session.ID), + Title: session.Title, + Name: session.Name, + AllElements: AppSessionElementsFromDomain(session), + IsActive: true, + ClientID: uuid.NewString(), + } + + return s +} + +func AppSessionElementsFromDomain(session appdev.AppSession) []model.Element { + var elements []model.Element + for _, domainElement := range session.Elements { + elem := AppSessionElementFromDomain(&session, domainElement) + elements = append(elements, elem) + } + + return elements +} + +func AppSessionElementFromDomain(session *appdev.AppSession, elem appdev.AppSessionElement) model.Element { + context := getGraphContext(session, elem) + if element, err := getElementFromDomain(elem, &context); err != nil { + slog.Error("Cannot retrieve element added from domain", slog.String("error", err.Error())) + return nil + } else { + return element + } +} + +func getGraphContext(session *appdev.AppSession, domainElement appdev.AppSessionElement) model.ElementGraphContext { + if !domainElement.ParentID.Valid { + return model.ElementGraphContext{} + } + + parentElement, err := session.GetElementByID(domainElement.ParentID.String) + if err != nil { + slog.Info("could not get graph parent, returning empty context", slog.Any("element", domainElement)) + return model.ElementGraphContext{} + } + + if parent, err := getGraphParent(session, *parentElement); err != nil { + slog.Info("error getting graph parent, returning empty context", slog.Any("element", domainElement), slog.Any("error", err)) + return model.ElementGraphContext{} + } else { + return model.ElementGraphContext{Parent: parent} + } +} + +func getGraphParent(session *appdev.AppSession, parentElement appdev.AppSessionElement) (model.ElementGraphParent, error) { + switch parentElement.Type { + case "container": + switch c := AppSessionElementFromDomain(session, parentElement).(type) { + case model.Container: + return &c, nil + default: + return nil, fmt.Errorf("invalid parent %#v", c) + } + default: + slog.Debug("invalid parent type for graph parent", slog.Any("session", session)) + return nil, fmt.Errorf("invalid parent type %s", parentElement.Type) + } +} + +func AppSessionEventFromDomain(session *appdev.AppSession, event appdev.AppSessionEvent) model.ToolSessionEvent { + switch { + case event.UpdatedElement != nil: + return getElementUpdateFromDomain(session, *event.UpdatedElement) + case event.TriggeredActionElement != nil: + return getElementActionTriggerFromDomain(session, event.TriggeredActionElement) + case event.AddedElement != nil: + return getElementAddedFromDomain(session, event.AddedElement) + case event.RemovedElement != nil: + return getElementRemovedFromDomain(session, event.RemovedElement) + default: + slog.Warn("Unsupported tool session event", slog.Any("event", event)) + return nil + } +} + +func getElementFromDomain(domainElement appdev.AppSessionElement, context *model.ElementGraphContext) (model.Element, error) { + switch domainElement.Type { + case "string": + return model.TextField{ + ID: convertID(domainElement.ID), + Name: domainElement.Name, + Label: domainElement.Label, + Value: domainElement.StringValue.String, + GraphContext: context, + }, nil + case "number": + return model.NumberField{ + ID: convertID(domainElement.ID), + Name: domainElement.Name, + Label: domainElement.Label, + Value: domainElement.NumberValue.Float64, + GraphContext: context, + }, nil + case "action": + return model.Button{ + ID: convertID(domainElement.ID), + Name: domainElement.Name, + Label: domainElement.Label, + GraphContext: context, + }, nil + case "container": + return model.Container{ + ID: convertID(domainElement.ID), + Name: domainElement.Name, + Label: domainElement.Label, + GraphContext: context, + }, nil + case "slider": + return model.SliderElement{ + ID: convertID(domainElement.ID), + Name: domainElement.Name, + Label: domainElement.Label, + GraphContext: context, + Value: domainElement.SliderValue.Float64, + MinValue: domainElement.SliderMinValue.Float64, + MaxValue: domainElement.SliderMaxValue.Float64, + }, nil + case "html": + return model.HTMLElement{ + ID: convertID(domainElement.ID), + Name: domainElement.Name, + Label: domainElement.Label, + GraphContext: context, + HTML: domainElement.HTMLValue.String, + }, nil + default: + slog.Debug("Invalid element type", slog.Any("type", domainElement.Type)) + return nil, fmt.Errorf("invalid element type %s", domainElement.Type) + } +} + +func getElementActionTriggerFromDomain(session *appdev.AppSession, actionTrigger *appdev.AppSessionElement) model.ToolSessionEvent { + context := getGraphContext(session, *actionTrigger) + return model.ToolSessionActionTriggered{ + Element: &model.Button{ + ID: convertID(actionTrigger.ID), + Label: actionTrigger.Label, + Name: actionTrigger.Name, + GraphContext: &context, + }, + } +} + +func getElementAddedFromDomain(session *appdev.AppSession, added *appdev.AppSessionElement) model.ToolSessionElementAdded { + context := getGraphContext(session, *added) + if element, err := getElementFromDomain(*added, &context); err != nil { + slog.Error("Cannot retrieve element added from domain", slog.String("error", err.Error())) + return model.ToolSessionElementAdded{ + Element: nil, + } + } else { + return model.ToolSessionElementAdded{ + Element: element, + } + } +} + +func getElementRemovedFromDomain(session *appdev.AppSession, removed *appdev.AppSessionElement) model.ToolSessionElementRemoved { + context := getGraphContext(session, *removed) + if element, err := getElementFromDomain(*removed, &context); err != nil { + slog.Error("Cannot retrieve element removed from domain", slog.String("error", err.Error())) + return model.ToolSessionElementRemoved{ + Element: nil, + } + } else { + return model.ToolSessionElementRemoved{ + Element: element, + } + } +} + +func getElementUpdateFromDomain(session *appdev.AppSession, update appdev.AppSessionElement) model.ToolSessionEvent { + context := getGraphContext(session, update) + if element, err := getElementFromDomain(update, &context); err != nil { + slog.Error("Cannot retrieve element update from domain", slog.String("error", err.Error())) + return model.ToolSessionElementUpdated{ + Element: nil, + } + } else { + return model.ToolSessionElementUpdated{ + Element: element, + } + } +} + +func ElementInputToDomain(elementInput model.ElementInput) appdev.AppSessionElementUpdate { + return appdev.AppSessionElementUpdate{ + ElementID: elementInput.ElementID, + StringValue: elementInput.TextValue, + NumberValue: elementInput.NumberValue, + HTMLValue: elementInput.HTMLValue, + SliderValue: elementInput.SliderValue, + } +} + +func convertID(id uint) string { + return strconv.FormatUint(uint64(id), 10) +} diff --git a/cli/graphql/generated.go b/cli/graphql/generated.go new file mode 100644 index 00000000..d4049cf7 --- /dev/null +++ b/cli/graphql/generated.go @@ -0,0 +1,15653 @@ +// Code generated by github.com/99designs/gqlgen, DO NOT EDIT. + +package graphql + +import ( + "bytes" + "context" + "errors" + "fmt" + "io" + "strconv" + "sync" + "sync/atomic" + "time" + + "numerous/cli/graphql/model" + + "github.com/99designs/gqlgen/graphql" + "github.com/99designs/gqlgen/graphql/introspection" + gqlparser "github.com/vektah/gqlparser/v2" + "github.com/vektah/gqlparser/v2/ast" +) + +// region ************************** generated!.gotpl ************************** + +// NewExecutableSchema creates an ExecutableSchema from the ResolverRoot interface. +func NewExecutableSchema(cfg Config) graphql.ExecutableSchema { + return &executableSchema{ + schema: cfg.Schema, + resolvers: cfg.Resolvers, + directives: cfg.Directives, + complexity: cfg.Complexity, + } +} + +type Config struct { + Schema *ast.Schema + Resolvers ResolverRoot + Directives DirectiveRoot + Complexity ComplexityRoot +} + +type ResolverRoot interface { + Mutation() MutationResolver + Query() QueryResolver + Subscription() SubscriptionResolver +} + +type DirectiveRoot struct { + CanAccessInvitation func(ctx context.Context, obj interface{}, next graphql.Resolver) (res interface{}, err error) + Client func(ctx context.Context, obj interface{}, next graphql.Resolver) (res interface{}, err error) + HasRole func(ctx context.Context, obj interface{}, next graphql.Resolver, role model.AuthRole) (res interface{}, err error) + TrackOperation func(ctx context.Context, obj interface{}, next graphql.Resolver, eventName string) (res interface{}, err error) +} + +type ComplexityRoot struct { + App struct { + CreatedAt func(childComplexity int) int + Description func(childComplexity int) int + ID func(childComplexity int) int + Name func(childComplexity int) int + PublicURL func(childComplexity int) int + SharedURL func(childComplexity int) int + User func(childComplexity int) int + } + + AppDeploy struct { + App func(childComplexity int) int + BuildID func(childComplexity int) int + } + + BuildEventFailure struct { + Result func(childComplexity int) int + } + + BuildEventInfo struct { + Result func(childComplexity int) int + } + + BuildEventSuccess struct { + Result func(childComplexity int) int + } + + Button struct { + GraphContext func(childComplexity int) int + ID func(childComplexity int) int + Label func(childComplexity int) int + Name func(childComplexity int) int + Value func(childComplexity int) int + } + + Container struct { + GraphContext func(childComplexity int) int + ID func(childComplexity int) int + Label func(childComplexity int) int + Name func(childComplexity int) int + } + + ElementGraphContext struct { + AffectedBy func(childComplexity int) int + Affects func(childComplexity int) int + Parent func(childComplexity int) int + } + + ElementList struct { + GraphContext func(childComplexity int) int + ID func(childComplexity int) int + Label func(childComplexity int) int + Name func(childComplexity int) int + } + + ElementSelect struct { + GraphContext func(childComplexity int) int + ID func(childComplexity int) int + Label func(childComplexity int) int + Name func(childComplexity int) int + SelectedOption func(childComplexity int) int + } + + HTMLElement struct { + GraphContext func(childComplexity int) int + HTML func(childComplexity int) int + ID func(childComplexity int) int + Label func(childComplexity int) int + Name func(childComplexity int) int + } + + InvalidEmail struct { + Email func(childComplexity int) int + } + + Job struct { + CreatedAt func(childComplexity int) int + ID func(childComplexity int) int + ProxyURL func(childComplexity int) int + Status func(childComplexity int) int + User func(childComplexity int) int + } + + LogMessage struct { + Message func(childComplexity int) int + Time func(childComplexity int) int + } + + Mutation struct { + BuildPush func(childComplexity int, file graphql.Upload, id string) int + ElementSelectionUpdate func(childComplexity int, clientID string, elementSelection model.ElementSelectInput) int + ElementTrigger func(childComplexity int, toolSessionID string, clientID string, actionElementID string) int + ElementUpdate func(childComplexity int, toolSessionID string, clientID string, element model.ElementInput) int + JobStart func(childComplexity int, toolHash string, hashType model.ToolHashType) int + JobStop func(childComplexity int, id string) int + ListElementAdd func(childComplexity int, clientID string, listElement *model.ListElementInput) int + ListElementRemove func(childComplexity int, clientID string, listItemID string) int + OrganizationAppDeploy func(childComplexity int, appID string, organizationSlug string, appArchive graphql.Upload) int + OrganizationCreate func(childComplexity int, input model.NewOrganization) int + OrganizationInvitationAccept func(childComplexity int, invitationID string) int + OrganizationInvitationCreate func(childComplexity int, organizationID string, input *model.OrganizationInvitationInput) int + OrganizationRename func(childComplexity int, organizationID string, name string) int + ToolCreate func(childComplexity int, input model.NewTool) int + ToolDelete func(childComplexity int, id string) int + ToolPublish func(childComplexity int, id string) int + ToolSessionCreate func(childComplexity int) int + ToolUnpublish func(childComplexity int, id string) int + } + + NumberField struct { + GraphContext func(childComplexity int) int + ID func(childComplexity int) int + Label func(childComplexity int) int + Name func(childComplexity int) int + Value func(childComplexity int) int + } + + Organization struct { + Apps func(childComplexity int) int + ID func(childComplexity int) int + Members func(childComplexity int) int + Name func(childComplexity int) int + Slug func(childComplexity int) int + } + + OrganizationInvitation struct { + Email func(childComplexity int) int + ID func(childComplexity int) int + InvitedAt func(childComplexity int) int + OrganizationName func(childComplexity int) int + Role func(childComplexity int) int + } + + OrganizationInvitationNotFound struct { + ID func(childComplexity int) int + } + + OrganizationMemberExists struct { + Email func(childComplexity int) int + } + + OrganizationMembership struct { + Organization func(childComplexity int) int + Role func(childComplexity int) int + } + + OrganizationNotFound struct { + ID func(childComplexity int) int + Slug func(childComplexity int) int + } + + OrganizationRenameFailure struct { + Result func(childComplexity int) int + } + + PublicTool struct { + Description func(childComplexity int) int + Developer func(childComplexity int) int + Name func(childComplexity int) int + PictureURL func(childComplexity int) int + PublicURL func(childComplexity int) int + } + + Query struct { + Job func(childComplexity int, id string) int + Jobs func(childComplexity int) int + JobsByTool func(childComplexity int, id string) int + Me func(childComplexity int) int + Organization func(childComplexity int, organizationSlug *string) int + OrganizationInvitation func(childComplexity int, invitationID string) int + PublicTools func(childComplexity int) int + Tool func(childComplexity int, id string) int + ToolSession func(childComplexity int, id string) int + Tools func(childComplexity int) int + } + + SliderElement struct { + GraphContext func(childComplexity int) int + ID func(childComplexity int) int + Label func(childComplexity int) int + MaxValue func(childComplexity int) int + MinValue func(childComplexity int) int + Name func(childComplexity int) int + Value func(childComplexity int) int + } + + StopJobPayload struct { + Message func(childComplexity int) int + } + + Subscription struct { + BuildEvents func(childComplexity int, buildID string, appPath *string) int + DeployEvents func(childComplexity int, toolID string) int + Logs func(childComplexity int, appID string) int + ToolSessionEvent func(childComplexity int, toolSessionID string, clientID string) int + } + + TextField struct { + GraphContext func(childComplexity int) int + ID func(childComplexity int) int + Label func(childComplexity int) int + Name func(childComplexity int) int + Value func(childComplexity int) int + } + + Tool struct { + CreatedAt func(childComplexity int) int + Description func(childComplexity int) int + ID func(childComplexity int) int + Name func(childComplexity int) int + PublicURL func(childComplexity int) int + SharedURL func(childComplexity int) int + User func(childComplexity int) int + } + + ToolDeleteFailure struct { + Result func(childComplexity int) int + } + + ToolDeleteSuccess struct { + Result func(childComplexity int) int + } + + ToolSession struct { + AllElements func(childComplexity int) int + ClientID func(childComplexity int) int + ID func(childComplexity int) int + IsActive func(childComplexity int) int + Name func(childComplexity int) int + Title func(childComplexity int) int + } + + ToolSessionActionTriggered struct { + Element func(childComplexity int) int + } + + ToolSessionElementAdded struct { + Element func(childComplexity int) int + } + + ToolSessionElementRemoved struct { + Element func(childComplexity int) int + } + + ToolSessionElementUpdated struct { + Element func(childComplexity int) int + } + + User struct { + FullName func(childComplexity int) int + Memberships func(childComplexity int) int + } + + BuildConfiguration struct { + BuildID func(childComplexity int) int + } +} + +type MutationResolver interface { + OrganizationCreate(ctx context.Context, input model.NewOrganization) (*model.Organization, error) + OrganizationRename(ctx context.Context, organizationID string, name string) (model.OrganizationRenameResult, error) + OrganizationInvitationCreate(ctx context.Context, organizationID string, input *model.OrganizationInvitationInput) (model.OrganizationInvitationCreateResult, error) + OrganizationInvitationAccept(ctx context.Context, invitationID string) (model.OrganizationInvitationAcceptResult, error) + ToolCreate(ctx context.Context, input model.NewTool) (*model.Tool, error) + ToolPublish(ctx context.Context, id string) (*model.Tool, error) + ToolUnpublish(ctx context.Context, id string) (*model.Tool, error) + ToolDelete(ctx context.Context, id string) (model.ToolDeleteResult, error) + OrganizationAppDeploy(ctx context.Context, appID string, organizationSlug string, appArchive graphql.Upload) (*model.AppDeploy, error) + JobStart(ctx context.Context, toolHash string, hashType model.ToolHashType) (*model.Job, error) + JobStop(ctx context.Context, id string) (*model.StopJobPayload, error) + ToolSessionCreate(ctx context.Context) (*model.ToolSession, error) + ElementUpdate(ctx context.Context, toolSessionID string, clientID string, element model.ElementInput) (model.Element, error) + ElementTrigger(ctx context.Context, toolSessionID string, clientID string, actionElementID string) (model.Element, error) + ElementSelectionUpdate(ctx context.Context, clientID string, elementSelection model.ElementSelectInput) (model.Element, error) + ListElementAdd(ctx context.Context, clientID string, listElement *model.ListElementInput) (model.Element, error) + ListElementRemove(ctx context.Context, clientID string, listItemID string) (model.Element, error) + BuildPush(ctx context.Context, file graphql.Upload, id string) (*model.BuildConfiguration, error) +} +type QueryResolver interface { + Me(ctx context.Context) (*model.User, error) + Organization(ctx context.Context, organizationSlug *string) (model.OrganizationQueryResult, error) + OrganizationInvitation(ctx context.Context, invitationID string) (model.OrganizationInvitationQueryResult, error) + PublicTools(ctx context.Context) ([]*model.PublicTool, error) + Tool(ctx context.Context, id string) (*model.Tool, error) + Tools(ctx context.Context) ([]*model.Tool, error) + Job(ctx context.Context, id string) (*model.Job, error) + JobsByTool(ctx context.Context, id string) ([]*model.Job, error) + Jobs(ctx context.Context) ([]*model.Job, error) + ToolSession(ctx context.Context, id string) (*model.ToolSession, error) +} +type SubscriptionResolver interface { + ToolSessionEvent(ctx context.Context, toolSessionID string, clientID string) (<-chan model.ToolSessionEvent, error) + BuildEvents(ctx context.Context, buildID string, appPath *string) (<-chan model.BuildEvent, error) + DeployEvents(ctx context.Context, toolID string) (<-chan model.BuildEvent, error) + Logs(ctx context.Context, appID string) (<-chan *model.LogMessage, error) +} + +type executableSchema struct { + schema *ast.Schema + resolvers ResolverRoot + directives DirectiveRoot + complexity ComplexityRoot +} + +func (e *executableSchema) Schema() *ast.Schema { + if e.schema != nil { + return e.schema + } + return parsedSchema +} + +func (e *executableSchema) Complexity(typeName, field string, childComplexity int, rawArgs map[string]interface{}) (int, bool) { + ec := executionContext{nil, e, 0, 0, nil} + _ = ec + switch typeName + "." + field { + + case "App.createdAt": + if e.complexity.App.CreatedAt == nil { + break + } + + return e.complexity.App.CreatedAt(childComplexity), true + + case "App.description": + if e.complexity.App.Description == nil { + break + } + + return e.complexity.App.Description(childComplexity), true + + case "App.id": + if e.complexity.App.ID == nil { + break + } + + return e.complexity.App.ID(childComplexity), true + + case "App.name": + if e.complexity.App.Name == nil { + break + } + + return e.complexity.App.Name(childComplexity), true + + case "App.publicUrl": + if e.complexity.App.PublicURL == nil { + break + } + + return e.complexity.App.PublicURL(childComplexity), true + + case "App.sharedUrl": + if e.complexity.App.SharedURL == nil { + break + } + + return e.complexity.App.SharedURL(childComplexity), true + + case "App.user": + if e.complexity.App.User == nil { + break + } + + return e.complexity.App.User(childComplexity), true + + case "AppDeploy.app": + if e.complexity.AppDeploy.App == nil { + break + } + + return e.complexity.AppDeploy.App(childComplexity), true + + case "AppDeploy.buildId": + if e.complexity.AppDeploy.BuildID == nil { + break + } + + return e.complexity.AppDeploy.BuildID(childComplexity), true + + case "BuildEventFailure.result": + if e.complexity.BuildEventFailure.Result == nil { + break + } + + return e.complexity.BuildEventFailure.Result(childComplexity), true + + case "BuildEventInfo.result": + if e.complexity.BuildEventInfo.Result == nil { + break + } + + return e.complexity.BuildEventInfo.Result(childComplexity), true + + case "BuildEventSuccess.result": + if e.complexity.BuildEventSuccess.Result == nil { + break + } + + return e.complexity.BuildEventSuccess.Result(childComplexity), true + + case "Button.graphContext": + if e.complexity.Button.GraphContext == nil { + break + } + + return e.complexity.Button.GraphContext(childComplexity), true + + case "Button.id": + if e.complexity.Button.ID == nil { + break + } + + return e.complexity.Button.ID(childComplexity), true + + case "Button.label": + if e.complexity.Button.Label == nil { + break + } + + return e.complexity.Button.Label(childComplexity), true + + case "Button.name": + if e.complexity.Button.Name == nil { + break + } + + return e.complexity.Button.Name(childComplexity), true + + case "Button.value": + if e.complexity.Button.Value == nil { + break + } + + return e.complexity.Button.Value(childComplexity), true + + case "Container.graphContext": + if e.complexity.Container.GraphContext == nil { + break + } + + return e.complexity.Container.GraphContext(childComplexity), true + + case "Container.id": + if e.complexity.Container.ID == nil { + break + } + + return e.complexity.Container.ID(childComplexity), true + + case "Container.label": + if e.complexity.Container.Label == nil { + break + } + + return e.complexity.Container.Label(childComplexity), true + + case "Container.name": + if e.complexity.Container.Name == nil { + break + } + + return e.complexity.Container.Name(childComplexity), true + + case "ElementGraphContext.affectedBy": + if e.complexity.ElementGraphContext.AffectedBy == nil { + break + } + + return e.complexity.ElementGraphContext.AffectedBy(childComplexity), true + + case "ElementGraphContext.affects": + if e.complexity.ElementGraphContext.Affects == nil { + break + } + + return e.complexity.ElementGraphContext.Affects(childComplexity), true + + case "ElementGraphContext.parent": + if e.complexity.ElementGraphContext.Parent == nil { + break + } + + return e.complexity.ElementGraphContext.Parent(childComplexity), true + + case "ElementList.graphContext": + if e.complexity.ElementList.GraphContext == nil { + break + } + + return e.complexity.ElementList.GraphContext(childComplexity), true + + case "ElementList.id": + if e.complexity.ElementList.ID == nil { + break + } + + return e.complexity.ElementList.ID(childComplexity), true + + case "ElementList.label": + if e.complexity.ElementList.Label == nil { + break + } + + return e.complexity.ElementList.Label(childComplexity), true + + case "ElementList.name": + if e.complexity.ElementList.Name == nil { + break + } + + return e.complexity.ElementList.Name(childComplexity), true + + case "ElementSelect.graphContext": + if e.complexity.ElementSelect.GraphContext == nil { + break + } + + return e.complexity.ElementSelect.GraphContext(childComplexity), true + + case "ElementSelect.id": + if e.complexity.ElementSelect.ID == nil { + break + } + + return e.complexity.ElementSelect.ID(childComplexity), true + + case "ElementSelect.label": + if e.complexity.ElementSelect.Label == nil { + break + } + + return e.complexity.ElementSelect.Label(childComplexity), true + + case "ElementSelect.name": + if e.complexity.ElementSelect.Name == nil { + break + } + + return e.complexity.ElementSelect.Name(childComplexity), true + + case "ElementSelect.selectedOption": + if e.complexity.ElementSelect.SelectedOption == nil { + break + } + + return e.complexity.ElementSelect.SelectedOption(childComplexity), true + + case "HTMLElement.graphContext": + if e.complexity.HTMLElement.GraphContext == nil { + break + } + + return e.complexity.HTMLElement.GraphContext(childComplexity), true + + case "HTMLElement.html": + if e.complexity.HTMLElement.HTML == nil { + break + } + + return e.complexity.HTMLElement.HTML(childComplexity), true + + case "HTMLElement.id": + if e.complexity.HTMLElement.ID == nil { + break + } + + return e.complexity.HTMLElement.ID(childComplexity), true + + case "HTMLElement.label": + if e.complexity.HTMLElement.Label == nil { + break + } + + return e.complexity.HTMLElement.Label(childComplexity), true + + case "HTMLElement.name": + if e.complexity.HTMLElement.Name == nil { + break + } + + return e.complexity.HTMLElement.Name(childComplexity), true + + case "InvalidEmail.email": + if e.complexity.InvalidEmail.Email == nil { + break + } + + return e.complexity.InvalidEmail.Email(childComplexity), true + + case "Job.createdAt": + if e.complexity.Job.CreatedAt == nil { + break + } + + return e.complexity.Job.CreatedAt(childComplexity), true + + case "Job.id": + if e.complexity.Job.ID == nil { + break + } + + return e.complexity.Job.ID(childComplexity), true + + case "Job.proxyUrl": + if e.complexity.Job.ProxyURL == nil { + break + } + + return e.complexity.Job.ProxyURL(childComplexity), true + + case "Job.status": + if e.complexity.Job.Status == nil { + break + } + + return e.complexity.Job.Status(childComplexity), true + + case "Job.user": + if e.complexity.Job.User == nil { + break + } + + return e.complexity.Job.User(childComplexity), true + + case "LogMessage.message": + if e.complexity.LogMessage.Message == nil { + break + } + + return e.complexity.LogMessage.Message(childComplexity), true + + case "LogMessage.time": + if e.complexity.LogMessage.Time == nil { + break + } + + return e.complexity.LogMessage.Time(childComplexity), true + + case "Mutation.buildPush": + if e.complexity.Mutation.BuildPush == nil { + break + } + + args, err := ec.field_Mutation_buildPush_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.BuildPush(childComplexity, args["file"].(graphql.Upload), args["id"].(string)), true + + case "Mutation.elementSelectionUpdate": + if e.complexity.Mutation.ElementSelectionUpdate == nil { + break + } + + args, err := ec.field_Mutation_elementSelectionUpdate_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.ElementSelectionUpdate(childComplexity, args["clientId"].(string), args["elementSelection"].(model.ElementSelectInput)), true + + case "Mutation.elementTrigger": + if e.complexity.Mutation.ElementTrigger == nil { + break + } + + args, err := ec.field_Mutation_elementTrigger_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.ElementTrigger(childComplexity, args["toolSessionId"].(string), args["clientId"].(string), args["actionElementId"].(string)), true + + case "Mutation.elementUpdate": + if e.complexity.Mutation.ElementUpdate == nil { + break + } + + args, err := ec.field_Mutation_elementUpdate_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.ElementUpdate(childComplexity, args["toolSessionId"].(string), args["clientId"].(string), args["element"].(model.ElementInput)), true + + case "Mutation.jobStart": + if e.complexity.Mutation.JobStart == nil { + break + } + + args, err := ec.field_Mutation_jobStart_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.JobStart(childComplexity, args["toolHash"].(string), args["hashType"].(model.ToolHashType)), true + + case "Mutation.jobStop": + if e.complexity.Mutation.JobStop == nil { + break + } + + args, err := ec.field_Mutation_jobStop_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.JobStop(childComplexity, args["id"].(string)), true + + case "Mutation.listElementAdd": + if e.complexity.Mutation.ListElementAdd == nil { + break + } + + args, err := ec.field_Mutation_listElementAdd_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.ListElementAdd(childComplexity, args["clientId"].(string), args["listElement"].(*model.ListElementInput)), true + + case "Mutation.listElementRemove": + if e.complexity.Mutation.ListElementRemove == nil { + break + } + + args, err := ec.field_Mutation_listElementRemove_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.ListElementRemove(childComplexity, args["clientId"].(string), args["listItemID"].(string)), true + + case "Mutation.organizationAppDeploy": + if e.complexity.Mutation.OrganizationAppDeploy == nil { + break + } + + args, err := ec.field_Mutation_organizationAppDeploy_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.OrganizationAppDeploy(childComplexity, args["appId"].(string), args["organizationSlug"].(string), args["appArchive"].(graphql.Upload)), true + + case "Mutation.organizationCreate": + if e.complexity.Mutation.OrganizationCreate == nil { + break + } + + args, err := ec.field_Mutation_organizationCreate_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.OrganizationCreate(childComplexity, args["input"].(model.NewOrganization)), true + + case "Mutation.organizationInvitationAccept": + if e.complexity.Mutation.OrganizationInvitationAccept == nil { + break + } + + args, err := ec.field_Mutation_organizationInvitationAccept_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.OrganizationInvitationAccept(childComplexity, args["invitationId"].(string)), true + + case "Mutation.organizationInvitationCreate": + if e.complexity.Mutation.OrganizationInvitationCreate == nil { + break + } + + args, err := ec.field_Mutation_organizationInvitationCreate_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.OrganizationInvitationCreate(childComplexity, args["organizationId"].(string), args["input"].(*model.OrganizationInvitationInput)), true + + case "Mutation.organizationRename": + if e.complexity.Mutation.OrganizationRename == nil { + break + } + + args, err := ec.field_Mutation_organizationRename_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.OrganizationRename(childComplexity, args["organizationId"].(string), args["name"].(string)), true + + case "Mutation.toolCreate": + if e.complexity.Mutation.ToolCreate == nil { + break + } + + args, err := ec.field_Mutation_toolCreate_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.ToolCreate(childComplexity, args["input"].(model.NewTool)), true + + case "Mutation.toolDelete": + if e.complexity.Mutation.ToolDelete == nil { + break + } + + args, err := ec.field_Mutation_toolDelete_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.ToolDelete(childComplexity, args["id"].(string)), true + + case "Mutation.toolPublish": + if e.complexity.Mutation.ToolPublish == nil { + break + } + + args, err := ec.field_Mutation_toolPublish_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.ToolPublish(childComplexity, args["id"].(string)), true + + case "Mutation.toolSessionCreate": + if e.complexity.Mutation.ToolSessionCreate == nil { + break + } + + return e.complexity.Mutation.ToolSessionCreate(childComplexity), true + + case "Mutation.toolUnpublish": + if e.complexity.Mutation.ToolUnpublish == nil { + break + } + + args, err := ec.field_Mutation_toolUnpublish_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Mutation.ToolUnpublish(childComplexity, args["id"].(string)), true + + case "NumberField.graphContext": + if e.complexity.NumberField.GraphContext == nil { + break + } + + return e.complexity.NumberField.GraphContext(childComplexity), true + + case "NumberField.id": + if e.complexity.NumberField.ID == nil { + break + } + + return e.complexity.NumberField.ID(childComplexity), true + + case "NumberField.label": + if e.complexity.NumberField.Label == nil { + break + } + + return e.complexity.NumberField.Label(childComplexity), true + + case "NumberField.name": + if e.complexity.NumberField.Name == nil { + break + } + + return e.complexity.NumberField.Name(childComplexity), true + + case "NumberField.value": + if e.complexity.NumberField.Value == nil { + break + } + + return e.complexity.NumberField.Value(childComplexity), true + + case "Organization.apps": + if e.complexity.Organization.Apps == nil { + break + } + + return e.complexity.Organization.Apps(childComplexity), true + + case "Organization.id": + if e.complexity.Organization.ID == nil { + break + } + + return e.complexity.Organization.ID(childComplexity), true + + case "Organization.members": + if e.complexity.Organization.Members == nil { + break + } + + return e.complexity.Organization.Members(childComplexity), true + + case "Organization.name": + if e.complexity.Organization.Name == nil { + break + } + + return e.complexity.Organization.Name(childComplexity), true + + case "Organization.slug": + if e.complexity.Organization.Slug == nil { + break + } + + return e.complexity.Organization.Slug(childComplexity), true + + case "OrganizationInvitation.email": + if e.complexity.OrganizationInvitation.Email == nil { + break + } + + return e.complexity.OrganizationInvitation.Email(childComplexity), true + + case "OrganizationInvitation.id": + if e.complexity.OrganizationInvitation.ID == nil { + break + } + + return e.complexity.OrganizationInvitation.ID(childComplexity), true + + case "OrganizationInvitation.invitedAt": + if e.complexity.OrganizationInvitation.InvitedAt == nil { + break + } + + return e.complexity.OrganizationInvitation.InvitedAt(childComplexity), true + + case "OrganizationInvitation.organizationName": + if e.complexity.OrganizationInvitation.OrganizationName == nil { + break + } + + return e.complexity.OrganizationInvitation.OrganizationName(childComplexity), true + + case "OrganizationInvitation.role": + if e.complexity.OrganizationInvitation.Role == nil { + break + } + + return e.complexity.OrganizationInvitation.Role(childComplexity), true + + case "OrganizationInvitationNotFound.id": + if e.complexity.OrganizationInvitationNotFound.ID == nil { + break + } + + return e.complexity.OrganizationInvitationNotFound.ID(childComplexity), true + + case "OrganizationMemberExists.email": + if e.complexity.OrganizationMemberExists.Email == nil { + break + } + + return e.complexity.OrganizationMemberExists.Email(childComplexity), true + + case "OrganizationMembership.organization": + if e.complexity.OrganizationMembership.Organization == nil { + break + } + + return e.complexity.OrganizationMembership.Organization(childComplexity), true + + case "OrganizationMembership.role": + if e.complexity.OrganizationMembership.Role == nil { + break + } + + return e.complexity.OrganizationMembership.Role(childComplexity), true + + case "OrganizationNotFound.id": + if e.complexity.OrganizationNotFound.ID == nil { + break + } + + return e.complexity.OrganizationNotFound.ID(childComplexity), true + + case "OrganizationNotFound.slug": + if e.complexity.OrganizationNotFound.Slug == nil { + break + } + + return e.complexity.OrganizationNotFound.Slug(childComplexity), true + + case "OrganizationRenameFailure.result": + if e.complexity.OrganizationRenameFailure.Result == nil { + break + } + + return e.complexity.OrganizationRenameFailure.Result(childComplexity), true + + case "PublicTool.description": + if e.complexity.PublicTool.Description == nil { + break + } + + return e.complexity.PublicTool.Description(childComplexity), true + + case "PublicTool.developer": + if e.complexity.PublicTool.Developer == nil { + break + } + + return e.complexity.PublicTool.Developer(childComplexity), true + + case "PublicTool.name": + if e.complexity.PublicTool.Name == nil { + break + } + + return e.complexity.PublicTool.Name(childComplexity), true + + case "PublicTool.pictureUrl": + if e.complexity.PublicTool.PictureURL == nil { + break + } + + return e.complexity.PublicTool.PictureURL(childComplexity), true + + case "PublicTool.publicUrl": + if e.complexity.PublicTool.PublicURL == nil { + break + } + + return e.complexity.PublicTool.PublicURL(childComplexity), true + + case "Query.job": + if e.complexity.Query.Job == nil { + break + } + + args, err := ec.field_Query_job_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Query.Job(childComplexity, args["id"].(string)), true + + case "Query.jobs": + if e.complexity.Query.Jobs == nil { + break + } + + return e.complexity.Query.Jobs(childComplexity), true + + case "Query.jobsByTool": + if e.complexity.Query.JobsByTool == nil { + break + } + + args, err := ec.field_Query_jobsByTool_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Query.JobsByTool(childComplexity, args["id"].(string)), true + + case "Query.me": + if e.complexity.Query.Me == nil { + break + } + + return e.complexity.Query.Me(childComplexity), true + + case "Query.organization": + if e.complexity.Query.Organization == nil { + break + } + + args, err := ec.field_Query_organization_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Query.Organization(childComplexity, args["organizationSlug"].(*string)), true + + case "Query.organizationInvitation": + if e.complexity.Query.OrganizationInvitation == nil { + break + } + + args, err := ec.field_Query_organizationInvitation_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Query.OrganizationInvitation(childComplexity, args["invitationId"].(string)), true + + case "Query.publicTools": + if e.complexity.Query.PublicTools == nil { + break + } + + return e.complexity.Query.PublicTools(childComplexity), true + + case "Query.tool": + if e.complexity.Query.Tool == nil { + break + } + + args, err := ec.field_Query_tool_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Query.Tool(childComplexity, args["id"].(string)), true + + case "Query.toolSession": + if e.complexity.Query.ToolSession == nil { + break + } + + args, err := ec.field_Query_toolSession_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Query.ToolSession(childComplexity, args["id"].(string)), true + + case "Query.tools": + if e.complexity.Query.Tools == nil { + break + } + + return e.complexity.Query.Tools(childComplexity), true + + case "SliderElement.graphContext": + if e.complexity.SliderElement.GraphContext == nil { + break + } + + return e.complexity.SliderElement.GraphContext(childComplexity), true + + case "SliderElement.id": + if e.complexity.SliderElement.ID == nil { + break + } + + return e.complexity.SliderElement.ID(childComplexity), true + + case "SliderElement.label": + if e.complexity.SliderElement.Label == nil { + break + } + + return e.complexity.SliderElement.Label(childComplexity), true + + case "SliderElement.maxValue": + if e.complexity.SliderElement.MaxValue == nil { + break + } + + return e.complexity.SliderElement.MaxValue(childComplexity), true + + case "SliderElement.minValue": + if e.complexity.SliderElement.MinValue == nil { + break + } + + return e.complexity.SliderElement.MinValue(childComplexity), true + + case "SliderElement.name": + if e.complexity.SliderElement.Name == nil { + break + } + + return e.complexity.SliderElement.Name(childComplexity), true + + case "SliderElement.value": + if e.complexity.SliderElement.Value == nil { + break + } + + return e.complexity.SliderElement.Value(childComplexity), true + + case "StopJobPayload.message": + if e.complexity.StopJobPayload.Message == nil { + break + } + + return e.complexity.StopJobPayload.Message(childComplexity), true + + case "Subscription.buildEvents": + if e.complexity.Subscription.BuildEvents == nil { + break + } + + args, err := ec.field_Subscription_buildEvents_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Subscription.BuildEvents(childComplexity, args["buildId"].(string), args["appPath"].(*string)), true + + case "Subscription.deployEvents": + if e.complexity.Subscription.DeployEvents == nil { + break + } + + args, err := ec.field_Subscription_deployEvents_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Subscription.DeployEvents(childComplexity, args["toolID"].(string)), true + + case "Subscription.logs": + if e.complexity.Subscription.Logs == nil { + break + } + + args, err := ec.field_Subscription_logs_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Subscription.Logs(childComplexity, args["appId"].(string)), true + + case "Subscription.toolSessionEvent": + if e.complexity.Subscription.ToolSessionEvent == nil { + break + } + + args, err := ec.field_Subscription_toolSessionEvent_args(context.TODO(), rawArgs) + if err != nil { + return 0, false + } + + return e.complexity.Subscription.ToolSessionEvent(childComplexity, args["toolSessionId"].(string), args["clientId"].(string)), true + + case "TextField.graphContext": + if e.complexity.TextField.GraphContext == nil { + break + } + + return e.complexity.TextField.GraphContext(childComplexity), true + + case "TextField.id": + if e.complexity.TextField.ID == nil { + break + } + + return e.complexity.TextField.ID(childComplexity), true + + case "TextField.label": + if e.complexity.TextField.Label == nil { + break + } + + return e.complexity.TextField.Label(childComplexity), true + + case "TextField.name": + if e.complexity.TextField.Name == nil { + break + } + + return e.complexity.TextField.Name(childComplexity), true + + case "TextField.value": + if e.complexity.TextField.Value == nil { + break + } + + return e.complexity.TextField.Value(childComplexity), true + + case "Tool.createdAt": + if e.complexity.Tool.CreatedAt == nil { + break + } + + return e.complexity.Tool.CreatedAt(childComplexity), true + + case "Tool.description": + if e.complexity.Tool.Description == nil { + break + } + + return e.complexity.Tool.Description(childComplexity), true + + case "Tool.id": + if e.complexity.Tool.ID == nil { + break + } + + return e.complexity.Tool.ID(childComplexity), true + + case "Tool.name": + if e.complexity.Tool.Name == nil { + break + } + + return e.complexity.Tool.Name(childComplexity), true + + case "Tool.publicUrl": + if e.complexity.Tool.PublicURL == nil { + break + } + + return e.complexity.Tool.PublicURL(childComplexity), true + + case "Tool.sharedUrl": + if e.complexity.Tool.SharedURL == nil { + break + } + + return e.complexity.Tool.SharedURL(childComplexity), true + + case "Tool.user": + if e.complexity.Tool.User == nil { + break + } + + return e.complexity.Tool.User(childComplexity), true + + case "ToolDeleteFailure.result": + if e.complexity.ToolDeleteFailure.Result == nil { + break + } + + return e.complexity.ToolDeleteFailure.Result(childComplexity), true + + case "ToolDeleteSuccess.result": + if e.complexity.ToolDeleteSuccess.Result == nil { + break + } + + return e.complexity.ToolDeleteSuccess.Result(childComplexity), true + + case "ToolSession.allElements": + if e.complexity.ToolSession.AllElements == nil { + break + } + + return e.complexity.ToolSession.AllElements(childComplexity), true + + case "ToolSession.clientID": + if e.complexity.ToolSession.ClientID == nil { + break + } + + return e.complexity.ToolSession.ClientID(childComplexity), true + + case "ToolSession.id": + if e.complexity.ToolSession.ID == nil { + break + } + + return e.complexity.ToolSession.ID(childComplexity), true + + case "ToolSession.isActive": + if e.complexity.ToolSession.IsActive == nil { + break + } + + return e.complexity.ToolSession.IsActive(childComplexity), true + + case "ToolSession.name": + if e.complexity.ToolSession.Name == nil { + break + } + + return e.complexity.ToolSession.Name(childComplexity), true + + case "ToolSession.title": + if e.complexity.ToolSession.Title == nil { + break + } + + return e.complexity.ToolSession.Title(childComplexity), true + + case "ToolSessionActionTriggered.element": + if e.complexity.ToolSessionActionTriggered.Element == nil { + break + } + + return e.complexity.ToolSessionActionTriggered.Element(childComplexity), true + + case "ToolSessionElementAdded.element": + if e.complexity.ToolSessionElementAdded.Element == nil { + break + } + + return e.complexity.ToolSessionElementAdded.Element(childComplexity), true + + case "ToolSessionElementRemoved.element": + if e.complexity.ToolSessionElementRemoved.Element == nil { + break + } + + return e.complexity.ToolSessionElementRemoved.Element(childComplexity), true + + case "ToolSessionElementUpdated.element": + if e.complexity.ToolSessionElementUpdated.Element == nil { + break + } + + return e.complexity.ToolSessionElementUpdated.Element(childComplexity), true + + case "User.fullName": + if e.complexity.User.FullName == nil { + break + } + + return e.complexity.User.FullName(childComplexity), true + + case "User.memberships": + if e.complexity.User.Memberships == nil { + break + } + + return e.complexity.User.Memberships(childComplexity), true + + case "buildConfiguration.buildId": + if e.complexity.BuildConfiguration.BuildID == nil { + break + } + + return e.complexity.BuildConfiguration.BuildID(childComplexity), true + + } + return 0, false +} + +func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { + rc := graphql.GetOperationContext(ctx) + ec := executionContext{rc, e, 0, 0, make(chan graphql.DeferredResult)} + inputUnmarshalMap := graphql.BuildUnmarshalerMap( + ec.unmarshalInputElementInput, + ec.unmarshalInputElementSelectInput, + ec.unmarshalInputListElementInput, + ec.unmarshalInputNewOrganization, + ec.unmarshalInputNewTool, + ec.unmarshalInputOrganizationInvitationInput, + ) + first := true + + switch rc.Operation.Operation { + case ast.Query: + return func(ctx context.Context) *graphql.Response { + var response graphql.Response + var data graphql.Marshaler + if first { + first = false + ctx = graphql.WithUnmarshalerMap(ctx, inputUnmarshalMap) + data = ec._queryMiddleware(ctx, rc.Operation, func(ctx context.Context) (interface{}, error) { + return ec._Query(ctx, rc.Operation.SelectionSet), nil + }) + } else { + if atomic.LoadInt32(&ec.pendingDeferred) > 0 { + result := <-ec.deferredResults + atomic.AddInt32(&ec.pendingDeferred, -1) + data = result.Result + response.Path = result.Path + response.Label = result.Label + response.Errors = result.Errors + } else { + return nil + } + } + var buf bytes.Buffer + data.MarshalGQL(&buf) + response.Data = buf.Bytes() + if atomic.LoadInt32(&ec.deferred) > 0 { + hasNext := atomic.LoadInt32(&ec.pendingDeferred) > 0 + response.HasNext = &hasNext + } + + return &response + } + case ast.Mutation: + return func(ctx context.Context) *graphql.Response { + if !first { + return nil + } + first = false + ctx = graphql.WithUnmarshalerMap(ctx, inputUnmarshalMap) + data := ec._Mutation(ctx, rc.Operation.SelectionSet) + var buf bytes.Buffer + data.MarshalGQL(&buf) + + return &graphql.Response{ + Data: buf.Bytes(), + } + } + case ast.Subscription: + next := ec._Subscription(ctx, rc.Operation.SelectionSet) + + var buf bytes.Buffer + return func(ctx context.Context) *graphql.Response { + buf.Reset() + data := next(ctx) + + if data == nil { + return nil + } + data.MarshalGQL(&buf) + + return &graphql.Response{ + Data: buf.Bytes(), + } + } + + default: + return graphql.OneShot(graphql.ErrorResponse(ctx, "unsupported GraphQL operation")) + } +} + +type executionContext struct { + *graphql.OperationContext + *executableSchema + deferred int32 + pendingDeferred int32 + deferredResults chan graphql.DeferredResult +} + +func (ec *executionContext) processDeferredGroup(dg graphql.DeferredGroup) { + atomic.AddInt32(&ec.pendingDeferred, 1) + go func() { + ctx := graphql.WithFreshResponseContext(dg.Context) + dg.FieldSet.Dispatch(ctx) + ds := graphql.DeferredResult{ + Path: dg.Path, + Label: dg.Label, + Result: dg.FieldSet, + Errors: graphql.GetErrors(ctx), + } + // null fields should bubble up + if dg.FieldSet.Invalids > 0 { + ds.Result = graphql.Null + } + ec.deferredResults <- ds + }() +} + +func (ec *executionContext) introspectSchema() (*introspection.Schema, error) { + if ec.DisableIntrospection { + return nil, errors.New("introspection disabled") + } + return introspection.WrapSchema(ec.Schema()), nil +} + +func (ec *executionContext) introspectType(name string) (*introspection.Type, error) { + if ec.DisableIntrospection { + return nil, errors.New("introspection disabled") + } + return introspection.WrapTypeFromDef(ec.Schema(), ec.Schema().Types[name]), nil +} + +var sources = []*ast.Source{ + {Name: "../../shared/schema.gql", Input: `scalar Time +scalar Upload + +directive @client on QUERY | FIELD +directive @trackOperation(eventName: String!) on FIELD_DEFINITION +directive @canAccessInvitation on FIELD_DEFINITION + +############################################################################### +### Auth +############################################################################### + +directive @hasRole(role: AuthRole!) on FIELD_DEFINITION + +enum AuthRole { + AUTHENTICATED + ADMIN + USER +} + +############################################################################### +### Auth end +############################################################################### + +############################################################################### +### User management +############################################################################### + +enum Role { + ADMIN + USER +} + +type OrganizationMembership { + organization: Organization! + role: Role! +} + +type User { + fullName: String! + memberships: [OrganizationMembership!]! +} + +type Query { + me: User! @hasRole(role: AUTHENTICATED) +} + +############################################################################### +### End of user management +############################################################################### + +############################################################################### +### Organization management +############################################################################### + +type Organization { + id: ID! + name: String! + slug: String! + apps: [App!]! + members: [OrganizationMembership!]! +} + +type OrganizationInvitation { + id: ID! + email: String! + organizationName: String! + invitedAt: Time! + role: Role! +} + +type InvalidEmail { + email: String! +} + +type OrganizationMemberExists { + email: String! +} + +input OrganizationInvitationInput { + role: Role! + email: String! +} + +input NewOrganization { + name: String! +} + +type OrganizationNotFound { + id: ID! + slug: String! +} + +type OrganizationRenameFailure { + result: String! +} + +union OrganizationRenameResult = + | Organization + | OrganizationNotFound + | OrganizationRenameFailure + +union OrganizationQueryResult = Organization | OrganizationNotFound + +type OrganizationInvitationNotFound { + id: ID! +} + +union OrganizationInvitationQueryResult = + | OrganizationInvitation + | OrganizationNotFound + | OrganizationInvitationNotFound + +union OrganizationInvitationCreateResult = + | OrganizationInvitation + | OrganizationNotFound + | InvalidEmail + | OrganizationMemberExists + +union OrganizationInvitationAcceptResult = Organization | OrganizationNotFound + +extend type Query { + organization(organizationSlug: ID): OrganizationQueryResult! + @hasRole(role: USER) + organizationInvitation(invitationId: ID!): OrganizationInvitationQueryResult + @canAccessInvitation +} +type Mutation { + organizationCreate(input: NewOrganization!): Organization! + @hasRole(role: AUTHENTICATED) + organizationRename( + organizationId: ID! + name: String! + ): OrganizationRenameResult! @hasRole(role: ADMIN) + organizationInvitationCreate( + organizationId: ID! + input: OrganizationInvitationInput + ): OrganizationInvitationCreateResult! @hasRole(role: ADMIN) + organizationInvitationAccept( + invitationId: ID! + ): OrganizationInvitationAcceptResult @canAccessInvitation +} + +############################################################################### +### End of organization management +############################################################################### + +############################################################################### +### Tool management +############################################################################### + +type Tool { + id: ID! + name: String! + description: String + user: User! + publicUrl: String + sharedUrl: String + createdAt: Time! +} + +type App { + id: ID! + name: String! + description: String + user: User! + publicUrl: String + sharedUrl: String + createdAt: Time! +} + +type PublicTool { + developer: User! + name: String! + description: String + pictureUrl: String + publicUrl: String! +} + +extend type Query { + publicTools: [PublicTool!] + tool(id: ID!): Tool! + tools: [Tool!]! @hasRole(role: AUTHENTICATED) +} + +input NewTool { + userId: ID! + manifest: String! +} + +type ToolDeleteSuccess { + result: String! +} + +type ToolDeleteFailure { + result: String! +} + +union ToolDeleteResult = ToolDeleteSuccess | ToolDeleteFailure + +type AppDeploy { + app: App! + buildId: ID! +} + +extend type Mutation { + toolCreate(input: NewTool!): Tool! @trackOperation(eventName: "App Create") + toolPublish(id: ID!): Tool! @trackOperation(eventName: "App Publish") + toolUnpublish(id: ID!): Tool! @trackOperation(eventName: "App Unpublish") + toolDelete(id: ID!): ToolDeleteResult! + @trackOperation(eventName: "App Delete") + organizationAppDeploy( + appId: ID! + organizationSlug: ID! + appArchive: Upload! + ): AppDeploy! @hasRole(role: USER) +} + +############################################################################### +### End of tool management +############################################################################### + +############################################################################### +### Job management +############################################################################### + +type Job { + id: ID! + status: String + proxyUrl: String + user: User! + createdAt: Time! +} + +type StopJobPayload { + message: String! +} + +enum ToolHashType { + public + shared +} + +extend type Query { + job(id: ID!): Job! + jobsByTool(id: ID!): [Job!]! + jobs: [Job!]! +} + +extend type Mutation { + jobStart(toolHash: ID!, hashType: ToolHashType!): Job! + @trackOperation(eventName: "App Use/Requested from Proxy") + jobStop(id: ID!): StopJobPayload! +} + +############################################################################### +### End of job management +############################################################################### + +############################################################################### +### Custom tool development +############################################################################### + +interface ElementGraphParent { + id: ID! +} + +type ElementGraphContext { + parent: ElementGraphParent + affectedBy: [Element]! + affects: [Element]! +} + +interface Element { + id: ID! + name: String! + label: String! + graphContext: ElementGraphContext! +} + +type Container implements Element & ElementGraphParent { + id: ID! + name: String! + label: String! + graphContext: ElementGraphContext! +} + +type SliderElement implements Element { + id: ID! + name: String! + label: String! + graphContext: ElementGraphContext! + value: Float! + minValue: Float! + maxValue: Float! +} + +type HTMLElement implements Element { + id: ID! + name: String! + label: String! + graphContext: ElementGraphContext! + html: String! +} + +type Button implements Element { + id: ID! + name: String! + label: String! + graphContext: ElementGraphContext! + value: String! +} + +type TextField implements Element { + id: ID! + name: String! + label: String! + graphContext: ElementGraphContext! + value: String! +} + +type NumberField implements Element { + id: ID! + name: String! + label: String! + graphContext: ElementGraphContext! + value: Float! +} + +type ElementList implements Element & ElementGraphParent { + id: ID! + name: String! + label: String! + graphContext: ElementGraphContext! +} + +type ElementSelect implements Element & ElementGraphParent { + id: ID! + name: String! + label: String! + graphContext: ElementGraphContext! + selectedOption: Element! +} + +type ToolSession { + id: ID! + name: String! + allElements: [Element!]! + isActive: Boolean! + clientID: String! + title: String! +} + +input ElementInput { + elementID: ID! + textValue: String + numberValue: Float + htmlValue: String + sliderValue: Float +} + +input ElementSelectInput { + selectElementID: ID! + selectedOptionID: ID! +} + +input ListElementInput { + listElementID: ID! +} + +extend type Query { + toolSession(id: ID!): ToolSession! +} + +extend type Mutation { + toolSessionCreate: ToolSession! + elementUpdate( + toolSessionId: ID! + clientId: ID! + element: ElementInput! + ): Element! + elementTrigger( + toolSessionId: ID! + clientId: ID! + actionElementId: ID! + ): Element! + elementSelectionUpdate( + clientId: ID! + elementSelection: ElementSelectInput! + ): Element! + listElementAdd(clientId: ID!, listElement: ListElementInput): Element! + listElementRemove(clientId: ID!, listItemID: ID!): Element! +} + +type ToolSessionElementAdded { + element: Element! +} + +type ToolSessionElementRemoved { + element: Element! +} + +type ToolSessionElementUpdated { + element: Element! +} + +type ToolSessionActionTriggered { + element: Button! +} + +union ToolSessionEvent = + | ToolSessionElementAdded + | ToolSessionElementRemoved + | ToolSessionElementUpdated + | ToolSessionActionTriggered + +type Subscription { + toolSessionEvent(toolSessionId: ID!, clientId: ID!): ToolSessionEvent! +} + +############################################################################### +### End of custom tool development +############################################################################### + +############################################################################### +### CLI Push command +############################################################################### + +type buildConfiguration { + buildId: ID! +} + +type BuildEventSuccess { + result: String! +} + +type BuildEventFailure { + result: String! +} + +type BuildEventInfo { + result: String! +} + +union BuildEvent = BuildEventSuccess | BuildEventFailure | BuildEventInfo + +extend type Mutation { + buildPush(file: Upload!, id: ID!): buildConfiguration! + @trackOperation(eventName: "App Push") +} + +extend type Subscription { + buildEvents(buildId: ID!, appPath: String): BuildEvent! +} + +extend type Subscription { + deployEvents(toolID: ID!): BuildEvent! +} + +############################################################################### +### End of CLI Push command +############################################################################### + +############################################################################### +### CLI Logs command +############################################################################### + +type LogMessage { + time: Time! + message: String! +} + +extend type Subscription { + logs(appId: ID!): LogMessage! +} + +############################################################################### +### End of CLI Push command +############################################################################### +`, BuiltIn: false}, +} +var parsedSchema = gqlparser.MustLoadSchema(sources...) + +// endregion ************************** generated!.gotpl ************************** + +// region ***************************** args.gotpl ***************************** + +func (ec *executionContext) dir_hasRole_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 model.AuthRole + if tmp, ok := rawArgs["role"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("role")) + arg0, err = ec.unmarshalNAuthRole2numerousᚋcliᚋgraphqlᚋmodelᚐAuthRole(ctx, tmp) + if err != nil { + return nil, err + } + } + args["role"] = arg0 + return args, nil +} + +func (ec *executionContext) dir_trackOperation_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["eventName"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("eventName")) + arg0, err = ec.unmarshalNString2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["eventName"] = arg0 + return args, nil +} + +func (ec *executionContext) field_Mutation_buildPush_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 graphql.Upload + if tmp, ok := rawArgs["file"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("file")) + arg0, err = ec.unmarshalNUpload2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚐUpload(ctx, tmp) + if err != nil { + return nil, err + } + } + args["file"] = arg0 + var arg1 string + if tmp, ok := rawArgs["id"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) + arg1, err = ec.unmarshalNID2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["id"] = arg1 + return args, nil +} + +func (ec *executionContext) field_Mutation_elementSelectionUpdate_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["clientId"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("clientId")) + arg0, err = ec.unmarshalNID2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["clientId"] = arg0 + var arg1 model.ElementSelectInput + if tmp, ok := rawArgs["elementSelection"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("elementSelection")) + arg1, err = ec.unmarshalNElementSelectInput2numerousᚋcliᚋgraphqlᚋmodelᚐElementSelectInput(ctx, tmp) + if err != nil { + return nil, err + } + } + args["elementSelection"] = arg1 + return args, nil +} + +func (ec *executionContext) field_Mutation_elementTrigger_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["toolSessionId"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("toolSessionId")) + arg0, err = ec.unmarshalNID2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["toolSessionId"] = arg0 + var arg1 string + if tmp, ok := rawArgs["clientId"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("clientId")) + arg1, err = ec.unmarshalNID2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["clientId"] = arg1 + var arg2 string + if tmp, ok := rawArgs["actionElementId"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("actionElementId")) + arg2, err = ec.unmarshalNID2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["actionElementId"] = arg2 + return args, nil +} + +func (ec *executionContext) field_Mutation_elementUpdate_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["toolSessionId"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("toolSessionId")) + arg0, err = ec.unmarshalNID2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["toolSessionId"] = arg0 + var arg1 string + if tmp, ok := rawArgs["clientId"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("clientId")) + arg1, err = ec.unmarshalNID2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["clientId"] = arg1 + var arg2 model.ElementInput + if tmp, ok := rawArgs["element"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("element")) + arg2, err = ec.unmarshalNElementInput2numerousᚋcliᚋgraphqlᚋmodelᚐElementInput(ctx, tmp) + if err != nil { + return nil, err + } + } + args["element"] = arg2 + return args, nil +} + +func (ec *executionContext) field_Mutation_jobStart_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["toolHash"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("toolHash")) + arg0, err = ec.unmarshalNID2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["toolHash"] = arg0 + var arg1 model.ToolHashType + if tmp, ok := rawArgs["hashType"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("hashType")) + arg1, err = ec.unmarshalNToolHashType2numerousᚋcliᚋgraphqlᚋmodelᚐToolHashType(ctx, tmp) + if err != nil { + return nil, err + } + } + args["hashType"] = arg1 + return args, nil +} + +func (ec *executionContext) field_Mutation_jobStop_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["id"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) + arg0, err = ec.unmarshalNID2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["id"] = arg0 + return args, nil +} + +func (ec *executionContext) field_Mutation_listElementAdd_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["clientId"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("clientId")) + arg0, err = ec.unmarshalNID2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["clientId"] = arg0 + var arg1 *model.ListElementInput + if tmp, ok := rawArgs["listElement"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("listElement")) + arg1, err = ec.unmarshalOListElementInput2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐListElementInput(ctx, tmp) + if err != nil { + return nil, err + } + } + args["listElement"] = arg1 + return args, nil +} + +func (ec *executionContext) field_Mutation_listElementRemove_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["clientId"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("clientId")) + arg0, err = ec.unmarshalNID2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["clientId"] = arg0 + var arg1 string + if tmp, ok := rawArgs["listItemID"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("listItemID")) + arg1, err = ec.unmarshalNID2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["listItemID"] = arg1 + return args, nil +} + +func (ec *executionContext) field_Mutation_organizationAppDeploy_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["appId"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("appId")) + arg0, err = ec.unmarshalNID2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["appId"] = arg0 + var arg1 string + if tmp, ok := rawArgs["organizationSlug"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("organizationSlug")) + arg1, err = ec.unmarshalNID2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["organizationSlug"] = arg1 + var arg2 graphql.Upload + if tmp, ok := rawArgs["appArchive"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("appArchive")) + arg2, err = ec.unmarshalNUpload2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚐUpload(ctx, tmp) + if err != nil { + return nil, err + } + } + args["appArchive"] = arg2 + return args, nil +} + +func (ec *executionContext) field_Mutation_organizationCreate_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 model.NewOrganization + if tmp, ok := rawArgs["input"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("input")) + arg0, err = ec.unmarshalNNewOrganization2numerousᚋcliᚋgraphqlᚋmodelᚐNewOrganization(ctx, tmp) + if err != nil { + return nil, err + } + } + args["input"] = arg0 + return args, nil +} + +func (ec *executionContext) field_Mutation_organizationInvitationAccept_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["invitationId"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("invitationId")) + arg0, err = ec.unmarshalNID2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["invitationId"] = arg0 + return args, nil +} + +func (ec *executionContext) field_Mutation_organizationInvitationCreate_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["organizationId"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("organizationId")) + arg0, err = ec.unmarshalNID2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["organizationId"] = arg0 + var arg1 *model.OrganizationInvitationInput + if tmp, ok := rawArgs["input"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("input")) + arg1, err = ec.unmarshalOOrganizationInvitationInput2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐOrganizationInvitationInput(ctx, tmp) + if err != nil { + return nil, err + } + } + args["input"] = arg1 + return args, nil +} + +func (ec *executionContext) field_Mutation_organizationRename_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["organizationId"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("organizationId")) + arg0, err = ec.unmarshalNID2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["organizationId"] = arg0 + var arg1 string + if tmp, ok := rawArgs["name"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) + arg1, err = ec.unmarshalNString2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["name"] = arg1 + return args, nil +} + +func (ec *executionContext) field_Mutation_toolCreate_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 model.NewTool + if tmp, ok := rawArgs["input"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("input")) + arg0, err = ec.unmarshalNNewTool2numerousᚋcliᚋgraphqlᚋmodelᚐNewTool(ctx, tmp) + if err != nil { + return nil, err + } + } + args["input"] = arg0 + return args, nil +} + +func (ec *executionContext) field_Mutation_toolDelete_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["id"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) + arg0, err = ec.unmarshalNID2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["id"] = arg0 + return args, nil +} + +func (ec *executionContext) field_Mutation_toolPublish_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["id"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) + arg0, err = ec.unmarshalNID2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["id"] = arg0 + return args, nil +} + +func (ec *executionContext) field_Mutation_toolUnpublish_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["id"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) + arg0, err = ec.unmarshalNID2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["id"] = arg0 + return args, nil +} + +func (ec *executionContext) field_Query___type_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["name"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) + arg0, err = ec.unmarshalNString2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["name"] = arg0 + return args, nil +} + +func (ec *executionContext) field_Query_job_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["id"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) + arg0, err = ec.unmarshalNID2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["id"] = arg0 + return args, nil +} + +func (ec *executionContext) field_Query_jobsByTool_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["id"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) + arg0, err = ec.unmarshalNID2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["id"] = arg0 + return args, nil +} + +func (ec *executionContext) field_Query_organizationInvitation_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["invitationId"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("invitationId")) + arg0, err = ec.unmarshalNID2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["invitationId"] = arg0 + return args, nil +} + +func (ec *executionContext) field_Query_organization_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 *string + if tmp, ok := rawArgs["organizationSlug"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("organizationSlug")) + arg0, err = ec.unmarshalOID2ᚖstring(ctx, tmp) + if err != nil { + return nil, err + } + } + args["organizationSlug"] = arg0 + return args, nil +} + +func (ec *executionContext) field_Query_toolSession_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["id"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) + arg0, err = ec.unmarshalNID2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["id"] = arg0 + return args, nil +} + +func (ec *executionContext) field_Query_tool_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["id"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("id")) + arg0, err = ec.unmarshalNID2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["id"] = arg0 + return args, nil +} + +func (ec *executionContext) field_Subscription_buildEvents_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["buildId"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("buildId")) + arg0, err = ec.unmarshalNID2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["buildId"] = arg0 + var arg1 *string + if tmp, ok := rawArgs["appPath"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("appPath")) + arg1, err = ec.unmarshalOString2ᚖstring(ctx, tmp) + if err != nil { + return nil, err + } + } + args["appPath"] = arg1 + return args, nil +} + +func (ec *executionContext) field_Subscription_deployEvents_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["toolID"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("toolID")) + arg0, err = ec.unmarshalNID2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["toolID"] = arg0 + return args, nil +} + +func (ec *executionContext) field_Subscription_logs_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["appId"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("appId")) + arg0, err = ec.unmarshalNID2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["appId"] = arg0 + return args, nil +} + +func (ec *executionContext) field_Subscription_toolSessionEvent_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 string + if tmp, ok := rawArgs["toolSessionId"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("toolSessionId")) + arg0, err = ec.unmarshalNID2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["toolSessionId"] = arg0 + var arg1 string + if tmp, ok := rawArgs["clientId"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("clientId")) + arg1, err = ec.unmarshalNID2string(ctx, tmp) + if err != nil { + return nil, err + } + } + args["clientId"] = arg1 + return args, nil +} + +func (ec *executionContext) field___Type_enumValues_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 bool + if tmp, ok := rawArgs["includeDeprecated"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("includeDeprecated")) + arg0, err = ec.unmarshalOBoolean2bool(ctx, tmp) + if err != nil { + return nil, err + } + } + args["includeDeprecated"] = arg0 + return args, nil +} + +func (ec *executionContext) field___Type_fields_args(ctx context.Context, rawArgs map[string]interface{}) (map[string]interface{}, error) { + var err error + args := map[string]interface{}{} + var arg0 bool + if tmp, ok := rawArgs["includeDeprecated"]; ok { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("includeDeprecated")) + arg0, err = ec.unmarshalOBoolean2bool(ctx, tmp) + if err != nil { + return nil, err + } + } + args["includeDeprecated"] = arg0 + return args, nil +} + +// endregion ***************************** args.gotpl ***************************** + +// region ************************** directives.gotpl ************************** + +func (ec *executionContext) _queryMiddleware(ctx context.Context, obj *ast.OperationDefinition, next func(ctx context.Context) (interface{}, error)) graphql.Marshaler { + for _, d := range obj.Directives { + switch d.Name { + case "client": + n := next + next = func(ctx context.Context) (interface{}, error) { + if ec.directives.Client == nil { + return nil, errors.New("directive client is not implemented") + } + return ec.directives.Client(ctx, obj, n) + } + } + } + tmp, err := next(ctx) + if err != nil { + ec.Error(ctx, err) + return graphql.Null + } + if data, ok := tmp.(graphql.Marshaler); ok { + return data + } + ec.Errorf(ctx, `unexpected type %T from directive, should be graphql.Marshaler`, tmp) + return graphql.Null +} + +func (ec *executionContext) _fieldMiddleware(ctx context.Context, obj interface{}, next graphql.Resolver) interface{} { + fc := graphql.GetFieldContext(ctx) + for _, d := range fc.Field.Directives { + switch d.Name { + case "client": + n := next + next = func(ctx context.Context) (interface{}, error) { + if ec.directives.Client == nil { + return nil, errors.New("directive client is not implemented") + } + return ec.directives.Client(ctx, obj, n) + } + } + } + res, err := ec.ResolverMiddleware(ctx, next) + if err != nil { + ec.Error(ctx, err) + return nil + } + return res +} + +// endregion ************************** directives.gotpl ************************** + +// region **************************** field.gotpl ***************************** + +func (ec *executionContext) _App_id(ctx context.Context, field graphql.CollectedField, obj *model.App) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_App_id(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ID, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNID2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_App_id(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "App", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type ID does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _App_name(ctx context.Context, field graphql.CollectedField, obj *model.App) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_App_name(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_App_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "App", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _App_description(ctx context.Context, field graphql.CollectedField, obj *model.App) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_App_description(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Description, nil + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_App_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "App", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _App_user(ctx context.Context, field graphql.CollectedField, obj *model.App) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_App_user(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.User, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.User) + fc.Result = res + return ec.marshalNUser2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐUser(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_App_user(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "App", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "fullName": + return ec.fieldContext_User_fullName(ctx, field) + case "memberships": + return ec.fieldContext_User_memberships(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type User", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _App_publicUrl(ctx context.Context, field graphql.CollectedField, obj *model.App) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_App_publicUrl(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.PublicURL, nil + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_App_publicUrl(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "App", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _App_sharedUrl(ctx context.Context, field graphql.CollectedField, obj *model.App) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_App_sharedUrl(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.SharedURL, nil + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_App_sharedUrl(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "App", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _App_createdAt(ctx context.Context, field graphql.CollectedField, obj *model.App) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_App_createdAt(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.CreatedAt, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(time.Time) + fc.Result = res + return ec.marshalNTime2timeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_App_createdAt(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "App", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Time does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _AppDeploy_app(ctx context.Context, field graphql.CollectedField, obj *model.AppDeploy) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_AppDeploy_app(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.App, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.App) + fc.Result = res + return ec.marshalNApp2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐApp(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_AppDeploy_app(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "AppDeploy", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_App_id(ctx, field) + case "name": + return ec.fieldContext_App_name(ctx, field) + case "description": + return ec.fieldContext_App_description(ctx, field) + case "user": + return ec.fieldContext_App_user(ctx, field) + case "publicUrl": + return ec.fieldContext_App_publicUrl(ctx, field) + case "sharedUrl": + return ec.fieldContext_App_sharedUrl(ctx, field) + case "createdAt": + return ec.fieldContext_App_createdAt(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type App", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _AppDeploy_buildId(ctx context.Context, field graphql.CollectedField, obj *model.AppDeploy) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_AppDeploy_buildId(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.BuildID, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNID2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_AppDeploy_buildId(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "AppDeploy", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type ID does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _BuildEventFailure_result(ctx context.Context, field graphql.CollectedField, obj *model.BuildEventFailure) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_BuildEventFailure_result(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Result, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_BuildEventFailure_result(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "BuildEventFailure", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _BuildEventInfo_result(ctx context.Context, field graphql.CollectedField, obj *model.BuildEventInfo) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_BuildEventInfo_result(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Result, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_BuildEventInfo_result(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "BuildEventInfo", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _BuildEventSuccess_result(ctx context.Context, field graphql.CollectedField, obj *model.BuildEventSuccess) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_BuildEventSuccess_result(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Result, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_BuildEventSuccess_result(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "BuildEventSuccess", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Button_id(ctx context.Context, field graphql.CollectedField, obj *model.Button) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Button_id(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ID, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNID2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Button_id(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Button", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type ID does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Button_name(ctx context.Context, field graphql.CollectedField, obj *model.Button) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Button_name(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Button_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Button", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Button_label(ctx context.Context, field graphql.CollectedField, obj *model.Button) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Button_label(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Label, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Button_label(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Button", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Button_graphContext(ctx context.Context, field graphql.CollectedField, obj *model.Button) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Button_graphContext(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.GraphContext, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.ElementGraphContext) + fc.Result = res + return ec.marshalNElementGraphContext2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐElementGraphContext(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Button_graphContext(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Button", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "parent": + return ec.fieldContext_ElementGraphContext_parent(ctx, field) + case "affectedBy": + return ec.fieldContext_ElementGraphContext_affectedBy(ctx, field) + case "affects": + return ec.fieldContext_ElementGraphContext_affects(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type ElementGraphContext", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _Button_value(ctx context.Context, field graphql.CollectedField, obj *model.Button) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Button_value(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Value, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Button_value(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Button", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Container_id(ctx context.Context, field graphql.CollectedField, obj *model.Container) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Container_id(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ID, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNID2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Container_id(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Container", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type ID does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Container_name(ctx context.Context, field graphql.CollectedField, obj *model.Container) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Container_name(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Container_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Container", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Container_label(ctx context.Context, field graphql.CollectedField, obj *model.Container) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Container_label(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Label, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Container_label(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Container", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Container_graphContext(ctx context.Context, field graphql.CollectedField, obj *model.Container) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Container_graphContext(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.GraphContext, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.ElementGraphContext) + fc.Result = res + return ec.marshalNElementGraphContext2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐElementGraphContext(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Container_graphContext(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Container", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "parent": + return ec.fieldContext_ElementGraphContext_parent(ctx, field) + case "affectedBy": + return ec.fieldContext_ElementGraphContext_affectedBy(ctx, field) + case "affects": + return ec.fieldContext_ElementGraphContext_affects(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type ElementGraphContext", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _ElementGraphContext_parent(ctx context.Context, field graphql.CollectedField, obj *model.ElementGraphContext) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ElementGraphContext_parent(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Parent, nil + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.(model.ElementGraphParent) + fc.Result = res + return ec.marshalOElementGraphParent2numerousᚋcliᚋgraphqlᚋmodelᚐElementGraphParent(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_ElementGraphContext_parent(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "ElementGraphContext", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("FieldContext.Child cannot be called on type INTERFACE") + }, + } + return fc, nil +} + +func (ec *executionContext) _ElementGraphContext_affectedBy(ctx context.Context, field graphql.CollectedField, obj *model.ElementGraphContext) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ElementGraphContext_affectedBy(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.AffectedBy, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]model.Element) + fc.Result = res + return ec.marshalNElement2ᚕnumerousᚋcliᚋgraphqlᚋmodelᚐElement(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_ElementGraphContext_affectedBy(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "ElementGraphContext", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("FieldContext.Child cannot be called on type INTERFACE") + }, + } + return fc, nil +} + +func (ec *executionContext) _ElementGraphContext_affects(ctx context.Context, field graphql.CollectedField, obj *model.ElementGraphContext) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ElementGraphContext_affects(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Affects, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]model.Element) + fc.Result = res + return ec.marshalNElement2ᚕnumerousᚋcliᚋgraphqlᚋmodelᚐElement(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_ElementGraphContext_affects(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "ElementGraphContext", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("FieldContext.Child cannot be called on type INTERFACE") + }, + } + return fc, nil +} + +func (ec *executionContext) _ElementList_id(ctx context.Context, field graphql.CollectedField, obj *model.ElementList) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ElementList_id(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ID, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNID2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_ElementList_id(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "ElementList", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type ID does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _ElementList_name(ctx context.Context, field graphql.CollectedField, obj *model.ElementList) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ElementList_name(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_ElementList_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "ElementList", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _ElementList_label(ctx context.Context, field graphql.CollectedField, obj *model.ElementList) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ElementList_label(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Label, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_ElementList_label(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "ElementList", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _ElementList_graphContext(ctx context.Context, field graphql.CollectedField, obj *model.ElementList) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ElementList_graphContext(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.GraphContext, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.ElementGraphContext) + fc.Result = res + return ec.marshalNElementGraphContext2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐElementGraphContext(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_ElementList_graphContext(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "ElementList", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "parent": + return ec.fieldContext_ElementGraphContext_parent(ctx, field) + case "affectedBy": + return ec.fieldContext_ElementGraphContext_affectedBy(ctx, field) + case "affects": + return ec.fieldContext_ElementGraphContext_affects(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type ElementGraphContext", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _ElementSelect_id(ctx context.Context, field graphql.CollectedField, obj *model.ElementSelect) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ElementSelect_id(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ID, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNID2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_ElementSelect_id(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "ElementSelect", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type ID does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _ElementSelect_name(ctx context.Context, field graphql.CollectedField, obj *model.ElementSelect) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ElementSelect_name(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_ElementSelect_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "ElementSelect", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _ElementSelect_label(ctx context.Context, field graphql.CollectedField, obj *model.ElementSelect) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ElementSelect_label(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Label, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_ElementSelect_label(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "ElementSelect", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _ElementSelect_graphContext(ctx context.Context, field graphql.CollectedField, obj *model.ElementSelect) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ElementSelect_graphContext(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.GraphContext, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.ElementGraphContext) + fc.Result = res + return ec.marshalNElementGraphContext2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐElementGraphContext(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_ElementSelect_graphContext(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "ElementSelect", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "parent": + return ec.fieldContext_ElementGraphContext_parent(ctx, field) + case "affectedBy": + return ec.fieldContext_ElementGraphContext_affectedBy(ctx, field) + case "affects": + return ec.fieldContext_ElementGraphContext_affects(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type ElementGraphContext", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _ElementSelect_selectedOption(ctx context.Context, field graphql.CollectedField, obj *model.ElementSelect) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ElementSelect_selectedOption(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.SelectedOption, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(model.Element) + fc.Result = res + return ec.marshalNElement2numerousᚋcliᚋgraphqlᚋmodelᚐElement(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_ElementSelect_selectedOption(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "ElementSelect", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("FieldContext.Child cannot be called on type INTERFACE") + }, + } + return fc, nil +} + +func (ec *executionContext) _HTMLElement_id(ctx context.Context, field graphql.CollectedField, obj *model.HTMLElement) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_HTMLElement_id(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ID, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNID2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_HTMLElement_id(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "HTMLElement", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type ID does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _HTMLElement_name(ctx context.Context, field graphql.CollectedField, obj *model.HTMLElement) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_HTMLElement_name(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_HTMLElement_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "HTMLElement", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _HTMLElement_label(ctx context.Context, field graphql.CollectedField, obj *model.HTMLElement) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_HTMLElement_label(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Label, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_HTMLElement_label(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "HTMLElement", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _HTMLElement_graphContext(ctx context.Context, field graphql.CollectedField, obj *model.HTMLElement) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_HTMLElement_graphContext(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.GraphContext, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.ElementGraphContext) + fc.Result = res + return ec.marshalNElementGraphContext2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐElementGraphContext(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_HTMLElement_graphContext(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "HTMLElement", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "parent": + return ec.fieldContext_ElementGraphContext_parent(ctx, field) + case "affectedBy": + return ec.fieldContext_ElementGraphContext_affectedBy(ctx, field) + case "affects": + return ec.fieldContext_ElementGraphContext_affects(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type ElementGraphContext", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _HTMLElement_html(ctx context.Context, field graphql.CollectedField, obj *model.HTMLElement) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_HTMLElement_html(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.HTML, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_HTMLElement_html(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "HTMLElement", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _InvalidEmail_email(ctx context.Context, field graphql.CollectedField, obj *model.InvalidEmail) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_InvalidEmail_email(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Email, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_InvalidEmail_email(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "InvalidEmail", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Job_id(ctx context.Context, field graphql.CollectedField, obj *model.Job) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Job_id(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ID, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNID2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Job_id(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Job", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type ID does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Job_status(ctx context.Context, field graphql.CollectedField, obj *model.Job) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Job_status(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Status, nil + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Job_status(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Job", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Job_proxyUrl(ctx context.Context, field graphql.CollectedField, obj *model.Job) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Job_proxyUrl(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ProxyURL, nil + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Job_proxyUrl(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Job", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Job_user(ctx context.Context, field graphql.CollectedField, obj *model.Job) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Job_user(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.User, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.User) + fc.Result = res + return ec.marshalNUser2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐUser(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Job_user(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Job", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "fullName": + return ec.fieldContext_User_fullName(ctx, field) + case "memberships": + return ec.fieldContext_User_memberships(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type User", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _Job_createdAt(ctx context.Context, field graphql.CollectedField, obj *model.Job) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Job_createdAt(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.CreatedAt, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(time.Time) + fc.Result = res + return ec.marshalNTime2timeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Job_createdAt(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Job", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Time does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _LogMessage_time(ctx context.Context, field graphql.CollectedField, obj *model.LogMessage) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_LogMessage_time(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Time, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(time.Time) + fc.Result = res + return ec.marshalNTime2timeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_LogMessage_time(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "LogMessage", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Time does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _LogMessage_message(ctx context.Context, field graphql.CollectedField, obj *model.LogMessage) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_LogMessage_message(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Message, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_LogMessage_message(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "LogMessage", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Mutation_organizationCreate(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_organizationCreate(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) { + directive0 := func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().OrganizationCreate(rctx, fc.Args["input"].(model.NewOrganization)) + } + directive1 := func(ctx context.Context) (interface{}, error) { + role, err := ec.unmarshalNAuthRole2numerousᚋcliᚋgraphqlᚋmodelᚐAuthRole(ctx, "AUTHENTICATED") + if err != nil { + return nil, err + } + if ec.directives.HasRole == nil { + return nil, errors.New("directive hasRole is not implemented") + } + return ec.directives.HasRole(ctx, nil, directive0, role) + } + + tmp, err := directive1(rctx) + if err != nil { + return nil, graphql.ErrorOnPath(ctx, err) + } + if tmp == nil { + return nil, nil + } + if data, ok := tmp.(*model.Organization); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be *numerous/cli/graphql/model.Organization`, tmp) + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.Organization) + fc.Result = res + return ec.marshalNOrganization2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐOrganization(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_organizationCreate(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_Organization_id(ctx, field) + case "name": + return ec.fieldContext_Organization_name(ctx, field) + case "slug": + return ec.fieldContext_Organization_slug(ctx, field) + case "apps": + return ec.fieldContext_Organization_apps(ctx, field) + case "members": + return ec.fieldContext_Organization_members(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Organization", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_organizationCreate_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Mutation_organizationRename(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_organizationRename(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) { + directive0 := func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().OrganizationRename(rctx, fc.Args["organizationId"].(string), fc.Args["name"].(string)) + } + directive1 := func(ctx context.Context) (interface{}, error) { + role, err := ec.unmarshalNAuthRole2numerousᚋcliᚋgraphqlᚋmodelᚐAuthRole(ctx, "ADMIN") + if err != nil { + return nil, err + } + if ec.directives.HasRole == nil { + return nil, errors.New("directive hasRole is not implemented") + } + return ec.directives.HasRole(ctx, nil, directive0, role) + } + + tmp, err := directive1(rctx) + if err != nil { + return nil, graphql.ErrorOnPath(ctx, err) + } + if tmp == nil { + return nil, nil + } + if data, ok := tmp.(model.OrganizationRenameResult); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be numerous/cli/graphql/model.OrganizationRenameResult`, tmp) + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(model.OrganizationRenameResult) + fc.Result = res + return ec.marshalNOrganizationRenameResult2numerousᚋcliᚋgraphqlᚋmodelᚐOrganizationRenameResult(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_organizationRename(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type OrganizationRenameResult does not have child fields") + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_organizationRename_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Mutation_organizationInvitationCreate(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_organizationInvitationCreate(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) { + directive0 := func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().OrganizationInvitationCreate(rctx, fc.Args["organizationId"].(string), fc.Args["input"].(*model.OrganizationInvitationInput)) + } + directive1 := func(ctx context.Context) (interface{}, error) { + role, err := ec.unmarshalNAuthRole2numerousᚋcliᚋgraphqlᚋmodelᚐAuthRole(ctx, "ADMIN") + if err != nil { + return nil, err + } + if ec.directives.HasRole == nil { + return nil, errors.New("directive hasRole is not implemented") + } + return ec.directives.HasRole(ctx, nil, directive0, role) + } + + tmp, err := directive1(rctx) + if err != nil { + return nil, graphql.ErrorOnPath(ctx, err) + } + if tmp == nil { + return nil, nil + } + if data, ok := tmp.(model.OrganizationInvitationCreateResult); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be numerous/cli/graphql/model.OrganizationInvitationCreateResult`, tmp) + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(model.OrganizationInvitationCreateResult) + fc.Result = res + return ec.marshalNOrganizationInvitationCreateResult2numerousᚋcliᚋgraphqlᚋmodelᚐOrganizationInvitationCreateResult(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_organizationInvitationCreate(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type OrganizationInvitationCreateResult does not have child fields") + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_organizationInvitationCreate_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Mutation_organizationInvitationAccept(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_organizationInvitationAccept(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) { + directive0 := func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().OrganizationInvitationAccept(rctx, fc.Args["invitationId"].(string)) + } + directive1 := func(ctx context.Context) (interface{}, error) { + if ec.directives.CanAccessInvitation == nil { + return nil, errors.New("directive canAccessInvitation is not implemented") + } + return ec.directives.CanAccessInvitation(ctx, nil, directive0) + } + + tmp, err := directive1(rctx) + if err != nil { + return nil, graphql.ErrorOnPath(ctx, err) + } + if tmp == nil { + return nil, nil + } + if data, ok := tmp.(model.OrganizationInvitationAcceptResult); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be numerous/cli/graphql/model.OrganizationInvitationAcceptResult`, tmp) + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.(model.OrganizationInvitationAcceptResult) + fc.Result = res + return ec.marshalOOrganizationInvitationAcceptResult2numerousᚋcliᚋgraphqlᚋmodelᚐOrganizationInvitationAcceptResult(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_organizationInvitationAccept(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type OrganizationInvitationAcceptResult does not have child fields") + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_organizationInvitationAccept_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Mutation_toolCreate(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_toolCreate(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) { + directive0 := func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().ToolCreate(rctx, fc.Args["input"].(model.NewTool)) + } + directive1 := func(ctx context.Context) (interface{}, error) { + eventName, err := ec.unmarshalNString2string(ctx, "App Create") + if err != nil { + return nil, err + } + if ec.directives.TrackOperation == nil { + return nil, errors.New("directive trackOperation is not implemented") + } + return ec.directives.TrackOperation(ctx, nil, directive0, eventName) + } + + tmp, err := directive1(rctx) + if err != nil { + return nil, graphql.ErrorOnPath(ctx, err) + } + if tmp == nil { + return nil, nil + } + if data, ok := tmp.(*model.Tool); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be *numerous/cli/graphql/model.Tool`, tmp) + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.Tool) + fc.Result = res + return ec.marshalNTool2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐTool(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_toolCreate(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_Tool_id(ctx, field) + case "name": + return ec.fieldContext_Tool_name(ctx, field) + case "description": + return ec.fieldContext_Tool_description(ctx, field) + case "user": + return ec.fieldContext_Tool_user(ctx, field) + case "publicUrl": + return ec.fieldContext_Tool_publicUrl(ctx, field) + case "sharedUrl": + return ec.fieldContext_Tool_sharedUrl(ctx, field) + case "createdAt": + return ec.fieldContext_Tool_createdAt(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Tool", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_toolCreate_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Mutation_toolPublish(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_toolPublish(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) { + directive0 := func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().ToolPublish(rctx, fc.Args["id"].(string)) + } + directive1 := func(ctx context.Context) (interface{}, error) { + eventName, err := ec.unmarshalNString2string(ctx, "App Publish") + if err != nil { + return nil, err + } + if ec.directives.TrackOperation == nil { + return nil, errors.New("directive trackOperation is not implemented") + } + return ec.directives.TrackOperation(ctx, nil, directive0, eventName) + } + + tmp, err := directive1(rctx) + if err != nil { + return nil, graphql.ErrorOnPath(ctx, err) + } + if tmp == nil { + return nil, nil + } + if data, ok := tmp.(*model.Tool); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be *numerous/cli/graphql/model.Tool`, tmp) + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.Tool) + fc.Result = res + return ec.marshalNTool2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐTool(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_toolPublish(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_Tool_id(ctx, field) + case "name": + return ec.fieldContext_Tool_name(ctx, field) + case "description": + return ec.fieldContext_Tool_description(ctx, field) + case "user": + return ec.fieldContext_Tool_user(ctx, field) + case "publicUrl": + return ec.fieldContext_Tool_publicUrl(ctx, field) + case "sharedUrl": + return ec.fieldContext_Tool_sharedUrl(ctx, field) + case "createdAt": + return ec.fieldContext_Tool_createdAt(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Tool", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_toolPublish_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Mutation_toolUnpublish(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_toolUnpublish(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) { + directive0 := func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().ToolUnpublish(rctx, fc.Args["id"].(string)) + } + directive1 := func(ctx context.Context) (interface{}, error) { + eventName, err := ec.unmarshalNString2string(ctx, "App Unpublish") + if err != nil { + return nil, err + } + if ec.directives.TrackOperation == nil { + return nil, errors.New("directive trackOperation is not implemented") + } + return ec.directives.TrackOperation(ctx, nil, directive0, eventName) + } + + tmp, err := directive1(rctx) + if err != nil { + return nil, graphql.ErrorOnPath(ctx, err) + } + if tmp == nil { + return nil, nil + } + if data, ok := tmp.(*model.Tool); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be *numerous/cli/graphql/model.Tool`, tmp) + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.Tool) + fc.Result = res + return ec.marshalNTool2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐTool(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_toolUnpublish(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_Tool_id(ctx, field) + case "name": + return ec.fieldContext_Tool_name(ctx, field) + case "description": + return ec.fieldContext_Tool_description(ctx, field) + case "user": + return ec.fieldContext_Tool_user(ctx, field) + case "publicUrl": + return ec.fieldContext_Tool_publicUrl(ctx, field) + case "sharedUrl": + return ec.fieldContext_Tool_sharedUrl(ctx, field) + case "createdAt": + return ec.fieldContext_Tool_createdAt(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Tool", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_toolUnpublish_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Mutation_toolDelete(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_toolDelete(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) { + directive0 := func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().ToolDelete(rctx, fc.Args["id"].(string)) + } + directive1 := func(ctx context.Context) (interface{}, error) { + eventName, err := ec.unmarshalNString2string(ctx, "App Delete") + if err != nil { + return nil, err + } + if ec.directives.TrackOperation == nil { + return nil, errors.New("directive trackOperation is not implemented") + } + return ec.directives.TrackOperation(ctx, nil, directive0, eventName) + } + + tmp, err := directive1(rctx) + if err != nil { + return nil, graphql.ErrorOnPath(ctx, err) + } + if tmp == nil { + return nil, nil + } + if data, ok := tmp.(model.ToolDeleteResult); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be numerous/cli/graphql/model.ToolDeleteResult`, tmp) + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(model.ToolDeleteResult) + fc.Result = res + return ec.marshalNToolDeleteResult2numerousᚋcliᚋgraphqlᚋmodelᚐToolDeleteResult(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_toolDelete(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type ToolDeleteResult does not have child fields") + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_toolDelete_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Mutation_organizationAppDeploy(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_organizationAppDeploy(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) { + directive0 := func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().OrganizationAppDeploy(rctx, fc.Args["appId"].(string), fc.Args["organizationSlug"].(string), fc.Args["appArchive"].(graphql.Upload)) + } + directive1 := func(ctx context.Context) (interface{}, error) { + role, err := ec.unmarshalNAuthRole2numerousᚋcliᚋgraphqlᚋmodelᚐAuthRole(ctx, "USER") + if err != nil { + return nil, err + } + if ec.directives.HasRole == nil { + return nil, errors.New("directive hasRole is not implemented") + } + return ec.directives.HasRole(ctx, nil, directive0, role) + } + + tmp, err := directive1(rctx) + if err != nil { + return nil, graphql.ErrorOnPath(ctx, err) + } + if tmp == nil { + return nil, nil + } + if data, ok := tmp.(*model.AppDeploy); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be *numerous/cli/graphql/model.AppDeploy`, tmp) + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.AppDeploy) + fc.Result = res + return ec.marshalNAppDeploy2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐAppDeploy(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_organizationAppDeploy(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "app": + return ec.fieldContext_AppDeploy_app(ctx, field) + case "buildId": + return ec.fieldContext_AppDeploy_buildId(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type AppDeploy", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_organizationAppDeploy_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Mutation_jobStart(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_jobStart(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) { + directive0 := func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().JobStart(rctx, fc.Args["toolHash"].(string), fc.Args["hashType"].(model.ToolHashType)) + } + directive1 := func(ctx context.Context) (interface{}, error) { + eventName, err := ec.unmarshalNString2string(ctx, "App Use/Requested from Proxy") + if err != nil { + return nil, err + } + if ec.directives.TrackOperation == nil { + return nil, errors.New("directive trackOperation is not implemented") + } + return ec.directives.TrackOperation(ctx, nil, directive0, eventName) + } + + tmp, err := directive1(rctx) + if err != nil { + return nil, graphql.ErrorOnPath(ctx, err) + } + if tmp == nil { + return nil, nil + } + if data, ok := tmp.(*model.Job); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be *numerous/cli/graphql/model.Job`, tmp) + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.Job) + fc.Result = res + return ec.marshalNJob2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐJob(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_jobStart(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_Job_id(ctx, field) + case "status": + return ec.fieldContext_Job_status(ctx, field) + case "proxyUrl": + return ec.fieldContext_Job_proxyUrl(ctx, field) + case "user": + return ec.fieldContext_Job_user(ctx, field) + case "createdAt": + return ec.fieldContext_Job_createdAt(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Job", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_jobStart_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Mutation_jobStop(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_jobStop(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().JobStop(rctx, fc.Args["id"].(string)) + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.StopJobPayload) + fc.Result = res + return ec.marshalNStopJobPayload2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐStopJobPayload(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_jobStop(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "message": + return ec.fieldContext_StopJobPayload_message(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type StopJobPayload", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_jobStop_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Mutation_toolSessionCreate(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_toolSessionCreate(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().ToolSessionCreate(rctx) + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.ToolSession) + fc.Result = res + return ec.marshalNToolSession2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐToolSession(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_toolSessionCreate(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_ToolSession_id(ctx, field) + case "name": + return ec.fieldContext_ToolSession_name(ctx, field) + case "allElements": + return ec.fieldContext_ToolSession_allElements(ctx, field) + case "isActive": + return ec.fieldContext_ToolSession_isActive(ctx, field) + case "clientID": + return ec.fieldContext_ToolSession_clientID(ctx, field) + case "title": + return ec.fieldContext_ToolSession_title(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type ToolSession", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _Mutation_elementUpdate(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_elementUpdate(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().ElementUpdate(rctx, fc.Args["toolSessionId"].(string), fc.Args["clientId"].(string), fc.Args["element"].(model.ElementInput)) + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(model.Element) + fc.Result = res + return ec.marshalNElement2numerousᚋcliᚋgraphqlᚋmodelᚐElement(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_elementUpdate(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("FieldContext.Child cannot be called on type INTERFACE") + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_elementUpdate_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Mutation_elementTrigger(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_elementTrigger(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().ElementTrigger(rctx, fc.Args["toolSessionId"].(string), fc.Args["clientId"].(string), fc.Args["actionElementId"].(string)) + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(model.Element) + fc.Result = res + return ec.marshalNElement2numerousᚋcliᚋgraphqlᚋmodelᚐElement(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_elementTrigger(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("FieldContext.Child cannot be called on type INTERFACE") + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_elementTrigger_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Mutation_elementSelectionUpdate(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_elementSelectionUpdate(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().ElementSelectionUpdate(rctx, fc.Args["clientId"].(string), fc.Args["elementSelection"].(model.ElementSelectInput)) + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(model.Element) + fc.Result = res + return ec.marshalNElement2numerousᚋcliᚋgraphqlᚋmodelᚐElement(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_elementSelectionUpdate(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("FieldContext.Child cannot be called on type INTERFACE") + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_elementSelectionUpdate_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Mutation_listElementAdd(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_listElementAdd(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().ListElementAdd(rctx, fc.Args["clientId"].(string), fc.Args["listElement"].(*model.ListElementInput)) + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(model.Element) + fc.Result = res + return ec.marshalNElement2numerousᚋcliᚋgraphqlᚋmodelᚐElement(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_listElementAdd(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("FieldContext.Child cannot be called on type INTERFACE") + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_listElementAdd_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Mutation_listElementRemove(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_listElementRemove(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().ListElementRemove(rctx, fc.Args["clientId"].(string), fc.Args["listItemID"].(string)) + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(model.Element) + fc.Result = res + return ec.marshalNElement2numerousᚋcliᚋgraphqlᚋmodelᚐElement(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_listElementRemove(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("FieldContext.Child cannot be called on type INTERFACE") + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_listElementRemove_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Mutation_buildPush(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Mutation_buildPush(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) { + directive0 := func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Mutation().BuildPush(rctx, fc.Args["file"].(graphql.Upload), fc.Args["id"].(string)) + } + directive1 := func(ctx context.Context) (interface{}, error) { + eventName, err := ec.unmarshalNString2string(ctx, "App Push") + if err != nil { + return nil, err + } + if ec.directives.TrackOperation == nil { + return nil, errors.New("directive trackOperation is not implemented") + } + return ec.directives.TrackOperation(ctx, nil, directive0, eventName) + } + + tmp, err := directive1(rctx) + if err != nil { + return nil, graphql.ErrorOnPath(ctx, err) + } + if tmp == nil { + return nil, nil + } + if data, ok := tmp.(*model.BuildConfiguration); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be *numerous/cli/graphql/model.BuildConfiguration`, tmp) + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.BuildConfiguration) + fc.Result = res + return ec.marshalNbuildConfiguration2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐBuildConfiguration(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Mutation_buildPush(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Mutation", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "buildId": + return ec.fieldContext_buildConfiguration_buildId(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type buildConfiguration", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Mutation_buildPush_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _NumberField_id(ctx context.Context, field graphql.CollectedField, obj *model.NumberField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_NumberField_id(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ID, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNID2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_NumberField_id(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "NumberField", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type ID does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _NumberField_name(ctx context.Context, field graphql.CollectedField, obj *model.NumberField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_NumberField_name(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_NumberField_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "NumberField", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _NumberField_label(ctx context.Context, field graphql.CollectedField, obj *model.NumberField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_NumberField_label(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Label, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_NumberField_label(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "NumberField", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _NumberField_graphContext(ctx context.Context, field graphql.CollectedField, obj *model.NumberField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_NumberField_graphContext(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.GraphContext, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.ElementGraphContext) + fc.Result = res + return ec.marshalNElementGraphContext2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐElementGraphContext(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_NumberField_graphContext(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "NumberField", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "parent": + return ec.fieldContext_ElementGraphContext_parent(ctx, field) + case "affectedBy": + return ec.fieldContext_ElementGraphContext_affectedBy(ctx, field) + case "affects": + return ec.fieldContext_ElementGraphContext_affects(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type ElementGraphContext", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _NumberField_value(ctx context.Context, field graphql.CollectedField, obj *model.NumberField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_NumberField_value(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Value, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(float64) + fc.Result = res + return ec.marshalNFloat2float64(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_NumberField_value(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "NumberField", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Float does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Organization_id(ctx context.Context, field graphql.CollectedField, obj *model.Organization) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Organization_id(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ID, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNID2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Organization_id(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Organization", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type ID does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Organization_name(ctx context.Context, field graphql.CollectedField, obj *model.Organization) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Organization_name(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Organization_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Organization", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Organization_slug(ctx context.Context, field graphql.CollectedField, obj *model.Organization) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Organization_slug(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Slug, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Organization_slug(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Organization", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Organization_apps(ctx context.Context, field graphql.CollectedField, obj *model.Organization) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Organization_apps(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Apps, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]*model.App) + fc.Result = res + return ec.marshalNApp2ᚕᚖnumerousᚋcliᚋgraphqlᚋmodelᚐAppᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Organization_apps(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Organization", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_App_id(ctx, field) + case "name": + return ec.fieldContext_App_name(ctx, field) + case "description": + return ec.fieldContext_App_description(ctx, field) + case "user": + return ec.fieldContext_App_user(ctx, field) + case "publicUrl": + return ec.fieldContext_App_publicUrl(ctx, field) + case "sharedUrl": + return ec.fieldContext_App_sharedUrl(ctx, field) + case "createdAt": + return ec.fieldContext_App_createdAt(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type App", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _Organization_members(ctx context.Context, field graphql.CollectedField, obj *model.Organization) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Organization_members(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Members, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]*model.OrganizationMembership) + fc.Result = res + return ec.marshalNOrganizationMembership2ᚕᚖnumerousᚋcliᚋgraphqlᚋmodelᚐOrganizationMembershipᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Organization_members(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Organization", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "organization": + return ec.fieldContext_OrganizationMembership_organization(ctx, field) + case "role": + return ec.fieldContext_OrganizationMembership_role(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type OrganizationMembership", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _OrganizationInvitation_id(ctx context.Context, field graphql.CollectedField, obj *model.OrganizationInvitation) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_OrganizationInvitation_id(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ID, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNID2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_OrganizationInvitation_id(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "OrganizationInvitation", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type ID does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _OrganizationInvitation_email(ctx context.Context, field graphql.CollectedField, obj *model.OrganizationInvitation) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_OrganizationInvitation_email(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Email, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_OrganizationInvitation_email(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "OrganizationInvitation", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _OrganizationInvitation_organizationName(ctx context.Context, field graphql.CollectedField, obj *model.OrganizationInvitation) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_OrganizationInvitation_organizationName(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.OrganizationName, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_OrganizationInvitation_organizationName(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "OrganizationInvitation", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _OrganizationInvitation_invitedAt(ctx context.Context, field graphql.CollectedField, obj *model.OrganizationInvitation) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_OrganizationInvitation_invitedAt(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.InvitedAt, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(time.Time) + fc.Result = res + return ec.marshalNTime2timeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_OrganizationInvitation_invitedAt(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "OrganizationInvitation", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Time does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _OrganizationInvitation_role(ctx context.Context, field graphql.CollectedField, obj *model.OrganizationInvitation) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_OrganizationInvitation_role(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Role, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(model.Role) + fc.Result = res + return ec.marshalNRole2numerousᚋcliᚋgraphqlᚋmodelᚐRole(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_OrganizationInvitation_role(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "OrganizationInvitation", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Role does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _OrganizationInvitationNotFound_id(ctx context.Context, field graphql.CollectedField, obj *model.OrganizationInvitationNotFound) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_OrganizationInvitationNotFound_id(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ID, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNID2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_OrganizationInvitationNotFound_id(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "OrganizationInvitationNotFound", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type ID does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _OrganizationMemberExists_email(ctx context.Context, field graphql.CollectedField, obj *model.OrganizationMemberExists) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_OrganizationMemberExists_email(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Email, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_OrganizationMemberExists_email(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "OrganizationMemberExists", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _OrganizationMembership_organization(ctx context.Context, field graphql.CollectedField, obj *model.OrganizationMembership) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_OrganizationMembership_organization(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Organization, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.Organization) + fc.Result = res + return ec.marshalNOrganization2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐOrganization(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_OrganizationMembership_organization(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "OrganizationMembership", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_Organization_id(ctx, field) + case "name": + return ec.fieldContext_Organization_name(ctx, field) + case "slug": + return ec.fieldContext_Organization_slug(ctx, field) + case "apps": + return ec.fieldContext_Organization_apps(ctx, field) + case "members": + return ec.fieldContext_Organization_members(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Organization", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _OrganizationMembership_role(ctx context.Context, field graphql.CollectedField, obj *model.OrganizationMembership) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_OrganizationMembership_role(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Role, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(model.Role) + fc.Result = res + return ec.marshalNRole2numerousᚋcliᚋgraphqlᚋmodelᚐRole(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_OrganizationMembership_role(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "OrganizationMembership", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Role does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _OrganizationNotFound_id(ctx context.Context, field graphql.CollectedField, obj *model.OrganizationNotFound) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_OrganizationNotFound_id(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ID, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNID2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_OrganizationNotFound_id(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "OrganizationNotFound", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type ID does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _OrganizationNotFound_slug(ctx context.Context, field graphql.CollectedField, obj *model.OrganizationNotFound) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_OrganizationNotFound_slug(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Slug, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_OrganizationNotFound_slug(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "OrganizationNotFound", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _OrganizationRenameFailure_result(ctx context.Context, field graphql.CollectedField, obj *model.OrganizationRenameFailure) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_OrganizationRenameFailure_result(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Result, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_OrganizationRenameFailure_result(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "OrganizationRenameFailure", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _PublicTool_developer(ctx context.Context, field graphql.CollectedField, obj *model.PublicTool) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_PublicTool_developer(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Developer, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.User) + fc.Result = res + return ec.marshalNUser2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐUser(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_PublicTool_developer(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "PublicTool", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "fullName": + return ec.fieldContext_User_fullName(ctx, field) + case "memberships": + return ec.fieldContext_User_memberships(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type User", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _PublicTool_name(ctx context.Context, field graphql.CollectedField, obj *model.PublicTool) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_PublicTool_name(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_PublicTool_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "PublicTool", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _PublicTool_description(ctx context.Context, field graphql.CollectedField, obj *model.PublicTool) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_PublicTool_description(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Description, nil + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_PublicTool_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "PublicTool", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _PublicTool_pictureUrl(ctx context.Context, field graphql.CollectedField, obj *model.PublicTool) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_PublicTool_pictureUrl(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.PictureURL, nil + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_PublicTool_pictureUrl(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "PublicTool", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _PublicTool_publicUrl(ctx context.Context, field graphql.CollectedField, obj *model.PublicTool) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_PublicTool_publicUrl(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.PublicURL, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_PublicTool_publicUrl(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "PublicTool", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Query_me(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_me(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) { + directive0 := func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().Me(rctx) + } + directive1 := func(ctx context.Context) (interface{}, error) { + role, err := ec.unmarshalNAuthRole2numerousᚋcliᚋgraphqlᚋmodelᚐAuthRole(ctx, "AUTHENTICATED") + if err != nil { + return nil, err + } + if ec.directives.HasRole == nil { + return nil, errors.New("directive hasRole is not implemented") + } + return ec.directives.HasRole(ctx, nil, directive0, role) + } + + tmp, err := directive1(rctx) + if err != nil { + return nil, graphql.ErrorOnPath(ctx, err) + } + if tmp == nil { + return nil, nil + } + if data, ok := tmp.(*model.User); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be *numerous/cli/graphql/model.User`, tmp) + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.User) + fc.Result = res + return ec.marshalNUser2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐUser(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query_me(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "fullName": + return ec.fieldContext_User_fullName(ctx, field) + case "memberships": + return ec.fieldContext_User_memberships(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type User", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _Query_organization(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_organization(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) { + directive0 := func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().Organization(rctx, fc.Args["organizationSlug"].(*string)) + } + directive1 := func(ctx context.Context) (interface{}, error) { + role, err := ec.unmarshalNAuthRole2numerousᚋcliᚋgraphqlᚋmodelᚐAuthRole(ctx, "USER") + if err != nil { + return nil, err + } + if ec.directives.HasRole == nil { + return nil, errors.New("directive hasRole is not implemented") + } + return ec.directives.HasRole(ctx, nil, directive0, role) + } + + tmp, err := directive1(rctx) + if err != nil { + return nil, graphql.ErrorOnPath(ctx, err) + } + if tmp == nil { + return nil, nil + } + if data, ok := tmp.(model.OrganizationQueryResult); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be numerous/cli/graphql/model.OrganizationQueryResult`, tmp) + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(model.OrganizationQueryResult) + fc.Result = res + return ec.marshalNOrganizationQueryResult2numerousᚋcliᚋgraphqlᚋmodelᚐOrganizationQueryResult(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query_organization(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type OrganizationQueryResult does not have child fields") + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_organization_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Query_organizationInvitation(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_organizationInvitation(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) { + directive0 := func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().OrganizationInvitation(rctx, fc.Args["invitationId"].(string)) + } + directive1 := func(ctx context.Context) (interface{}, error) { + if ec.directives.CanAccessInvitation == nil { + return nil, errors.New("directive canAccessInvitation is not implemented") + } + return ec.directives.CanAccessInvitation(ctx, nil, directive0) + } + + tmp, err := directive1(rctx) + if err != nil { + return nil, graphql.ErrorOnPath(ctx, err) + } + if tmp == nil { + return nil, nil + } + if data, ok := tmp.(model.OrganizationInvitationQueryResult); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be numerous/cli/graphql/model.OrganizationInvitationQueryResult`, tmp) + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.(model.OrganizationInvitationQueryResult) + fc.Result = res + return ec.marshalOOrganizationInvitationQueryResult2numerousᚋcliᚋgraphqlᚋmodelᚐOrganizationInvitationQueryResult(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query_organizationInvitation(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type OrganizationInvitationQueryResult does not have child fields") + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_organizationInvitation_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Query_publicTools(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_publicTools(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().PublicTools(rctx) + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]*model.PublicTool) + fc.Result = res + return ec.marshalOPublicTool2ᚕᚖnumerousᚋcliᚋgraphqlᚋmodelᚐPublicToolᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query_publicTools(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "developer": + return ec.fieldContext_PublicTool_developer(ctx, field) + case "name": + return ec.fieldContext_PublicTool_name(ctx, field) + case "description": + return ec.fieldContext_PublicTool_description(ctx, field) + case "pictureUrl": + return ec.fieldContext_PublicTool_pictureUrl(ctx, field) + case "publicUrl": + return ec.fieldContext_PublicTool_publicUrl(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type PublicTool", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _Query_tool(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_tool(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().Tool(rctx, fc.Args["id"].(string)) + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.Tool) + fc.Result = res + return ec.marshalNTool2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐTool(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query_tool(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_Tool_id(ctx, field) + case "name": + return ec.fieldContext_Tool_name(ctx, field) + case "description": + return ec.fieldContext_Tool_description(ctx, field) + case "user": + return ec.fieldContext_Tool_user(ctx, field) + case "publicUrl": + return ec.fieldContext_Tool_publicUrl(ctx, field) + case "sharedUrl": + return ec.fieldContext_Tool_sharedUrl(ctx, field) + case "createdAt": + return ec.fieldContext_Tool_createdAt(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Tool", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_tool_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Query_tools(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_tools(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) { + directive0 := func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().Tools(rctx) + } + directive1 := func(ctx context.Context) (interface{}, error) { + role, err := ec.unmarshalNAuthRole2numerousᚋcliᚋgraphqlᚋmodelᚐAuthRole(ctx, "AUTHENTICATED") + if err != nil { + return nil, err + } + if ec.directives.HasRole == nil { + return nil, errors.New("directive hasRole is not implemented") + } + return ec.directives.HasRole(ctx, nil, directive0, role) + } + + tmp, err := directive1(rctx) + if err != nil { + return nil, graphql.ErrorOnPath(ctx, err) + } + if tmp == nil { + return nil, nil + } + if data, ok := tmp.([]*model.Tool); ok { + return data, nil + } + return nil, fmt.Errorf(`unexpected type %T from directive, should be []*numerous/cli/graphql/model.Tool`, tmp) + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]*model.Tool) + fc.Result = res + return ec.marshalNTool2ᚕᚖnumerousᚋcliᚋgraphqlᚋmodelᚐToolᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query_tools(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_Tool_id(ctx, field) + case "name": + return ec.fieldContext_Tool_name(ctx, field) + case "description": + return ec.fieldContext_Tool_description(ctx, field) + case "user": + return ec.fieldContext_Tool_user(ctx, field) + case "publicUrl": + return ec.fieldContext_Tool_publicUrl(ctx, field) + case "sharedUrl": + return ec.fieldContext_Tool_sharedUrl(ctx, field) + case "createdAt": + return ec.fieldContext_Tool_createdAt(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Tool", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _Query_job(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_job(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().Job(rctx, fc.Args["id"].(string)) + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.Job) + fc.Result = res + return ec.marshalNJob2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐJob(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query_job(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_Job_id(ctx, field) + case "status": + return ec.fieldContext_Job_status(ctx, field) + case "proxyUrl": + return ec.fieldContext_Job_proxyUrl(ctx, field) + case "user": + return ec.fieldContext_Job_user(ctx, field) + case "createdAt": + return ec.fieldContext_Job_createdAt(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Job", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_job_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Query_jobsByTool(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_jobsByTool(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().JobsByTool(rctx, fc.Args["id"].(string)) + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]*model.Job) + fc.Result = res + return ec.marshalNJob2ᚕᚖnumerousᚋcliᚋgraphqlᚋmodelᚐJobᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query_jobsByTool(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_Job_id(ctx, field) + case "status": + return ec.fieldContext_Job_status(ctx, field) + case "proxyUrl": + return ec.fieldContext_Job_proxyUrl(ctx, field) + case "user": + return ec.fieldContext_Job_user(ctx, field) + case "createdAt": + return ec.fieldContext_Job_createdAt(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Job", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_jobsByTool_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Query_jobs(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_jobs(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().Jobs(rctx) + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]*model.Job) + fc.Result = res + return ec.marshalNJob2ᚕᚖnumerousᚋcliᚋgraphqlᚋmodelᚐJobᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query_jobs(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_Job_id(ctx, field) + case "status": + return ec.fieldContext_Job_status(ctx, field) + case "proxyUrl": + return ec.fieldContext_Job_proxyUrl(ctx, field) + case "user": + return ec.fieldContext_Job_user(ctx, field) + case "createdAt": + return ec.fieldContext_Job_createdAt(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Job", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _Query_toolSession(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query_toolSession(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Query().ToolSession(rctx, fc.Args["id"].(string)) + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.ToolSession) + fc.Result = res + return ec.marshalNToolSession2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐToolSession(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query_toolSession(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_ToolSession_id(ctx, field) + case "name": + return ec.fieldContext_ToolSession_name(ctx, field) + case "allElements": + return ec.fieldContext_ToolSession_allElements(ctx, field) + case "isActive": + return ec.fieldContext_ToolSession_isActive(ctx, field) + case "clientID": + return ec.fieldContext_ToolSession_clientID(ctx, field) + case "title": + return ec.fieldContext_ToolSession_title(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type ToolSession", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query_toolSession_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Query___type(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query___type(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.introspectType(fc.Args["name"].(string)) + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*introspection.Type) + fc.Result = res + return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query___type(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "kind": + return ec.fieldContext___Type_kind(ctx, field) + case "name": + return ec.fieldContext___Type_name(ctx, field) + case "description": + return ec.fieldContext___Type_description(ctx, field) + case "fields": + return ec.fieldContext___Type_fields(ctx, field) + case "interfaces": + return ec.fieldContext___Type_interfaces(ctx, field) + case "possibleTypes": + return ec.fieldContext___Type_possibleTypes(ctx, field) + case "enumValues": + return ec.fieldContext___Type_enumValues(ctx, field) + case "inputFields": + return ec.fieldContext___Type_inputFields(ctx, field) + case "ofType": + return ec.fieldContext___Type_ofType(ctx, field) + case "specifiedByURL": + return ec.fieldContext___Type_specifiedByURL(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Query___type_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Query___schema(ctx context.Context, field graphql.CollectedField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Query___schema(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.introspectSchema() + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*introspection.Schema) + fc.Result = res + return ec.marshalO__Schema2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐSchema(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Query___schema(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Query", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "description": + return ec.fieldContext___Schema_description(ctx, field) + case "types": + return ec.fieldContext___Schema_types(ctx, field) + case "queryType": + return ec.fieldContext___Schema_queryType(ctx, field) + case "mutationType": + return ec.fieldContext___Schema_mutationType(ctx, field) + case "subscriptionType": + return ec.fieldContext___Schema_subscriptionType(ctx, field) + case "directives": + return ec.fieldContext___Schema_directives(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type __Schema", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _SliderElement_id(ctx context.Context, field graphql.CollectedField, obj *model.SliderElement) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_SliderElement_id(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ID, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNID2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_SliderElement_id(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "SliderElement", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type ID does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _SliderElement_name(ctx context.Context, field graphql.CollectedField, obj *model.SliderElement) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_SliderElement_name(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_SliderElement_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "SliderElement", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _SliderElement_label(ctx context.Context, field graphql.CollectedField, obj *model.SliderElement) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_SliderElement_label(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Label, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_SliderElement_label(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "SliderElement", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _SliderElement_graphContext(ctx context.Context, field graphql.CollectedField, obj *model.SliderElement) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_SliderElement_graphContext(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.GraphContext, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.ElementGraphContext) + fc.Result = res + return ec.marshalNElementGraphContext2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐElementGraphContext(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_SliderElement_graphContext(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "SliderElement", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "parent": + return ec.fieldContext_ElementGraphContext_parent(ctx, field) + case "affectedBy": + return ec.fieldContext_ElementGraphContext_affectedBy(ctx, field) + case "affects": + return ec.fieldContext_ElementGraphContext_affects(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type ElementGraphContext", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _SliderElement_value(ctx context.Context, field graphql.CollectedField, obj *model.SliderElement) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_SliderElement_value(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Value, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(float64) + fc.Result = res + return ec.marshalNFloat2float64(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_SliderElement_value(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "SliderElement", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Float does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _SliderElement_minValue(ctx context.Context, field graphql.CollectedField, obj *model.SliderElement) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_SliderElement_minValue(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.MinValue, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(float64) + fc.Result = res + return ec.marshalNFloat2float64(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_SliderElement_minValue(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "SliderElement", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Float does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _SliderElement_maxValue(ctx context.Context, field graphql.CollectedField, obj *model.SliderElement) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_SliderElement_maxValue(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.MaxValue, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(float64) + fc.Result = res + return ec.marshalNFloat2float64(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_SliderElement_maxValue(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "SliderElement", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Float does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _StopJobPayload_message(ctx context.Context, field graphql.CollectedField, obj *model.StopJobPayload) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_StopJobPayload_message(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Message, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_StopJobPayload_message(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "StopJobPayload", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Subscription_toolSessionEvent(ctx context.Context, field graphql.CollectedField) (ret func(ctx context.Context) graphql.Marshaler) { + fc, err := ec.fieldContext_Subscription_toolSessionEvent(ctx, field) + if err != nil { + return nil + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + resTmp := ec._fieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Subscription().ToolSessionEvent(rctx, fc.Args["toolSessionId"].(string), fc.Args["clientId"].(string)) + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return nil + } + return func(ctx context.Context) graphql.Marshaler { + select { + case res, ok := <-resTmp.(<-chan model.ToolSessionEvent): + if !ok { + return nil + } + return graphql.WriterFunc(func(w io.Writer) { + w.Write([]byte{'{'}) + graphql.MarshalString(field.Alias).MarshalGQL(w) + w.Write([]byte{':'}) + ec.marshalNToolSessionEvent2numerousᚋcliᚋgraphqlᚋmodelᚐToolSessionEvent(ctx, field.Selections, res).MarshalGQL(w) + w.Write([]byte{'}'}) + }) + case <-ctx.Done(): + return nil + } + } +} + +func (ec *executionContext) fieldContext_Subscription_toolSessionEvent(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Subscription", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type ToolSessionEvent does not have child fields") + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Subscription_toolSessionEvent_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Subscription_buildEvents(ctx context.Context, field graphql.CollectedField) (ret func(ctx context.Context) graphql.Marshaler) { + fc, err := ec.fieldContext_Subscription_buildEvents(ctx, field) + if err != nil { + return nil + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + resTmp := ec._fieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Subscription().BuildEvents(rctx, fc.Args["buildId"].(string), fc.Args["appPath"].(*string)) + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return nil + } + return func(ctx context.Context) graphql.Marshaler { + select { + case res, ok := <-resTmp.(<-chan model.BuildEvent): + if !ok { + return nil + } + return graphql.WriterFunc(func(w io.Writer) { + w.Write([]byte{'{'}) + graphql.MarshalString(field.Alias).MarshalGQL(w) + w.Write([]byte{':'}) + ec.marshalNBuildEvent2numerousᚋcliᚋgraphqlᚋmodelᚐBuildEvent(ctx, field.Selections, res).MarshalGQL(w) + w.Write([]byte{'}'}) + }) + case <-ctx.Done(): + return nil + } + } +} + +func (ec *executionContext) fieldContext_Subscription_buildEvents(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Subscription", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type BuildEvent does not have child fields") + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Subscription_buildEvents_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Subscription_deployEvents(ctx context.Context, field graphql.CollectedField) (ret func(ctx context.Context) graphql.Marshaler) { + fc, err := ec.fieldContext_Subscription_deployEvents(ctx, field) + if err != nil { + return nil + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + resTmp := ec._fieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Subscription().DeployEvents(rctx, fc.Args["toolID"].(string)) + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return nil + } + return func(ctx context.Context) graphql.Marshaler { + select { + case res, ok := <-resTmp.(<-chan model.BuildEvent): + if !ok { + return nil + } + return graphql.WriterFunc(func(w io.Writer) { + w.Write([]byte{'{'}) + graphql.MarshalString(field.Alias).MarshalGQL(w) + w.Write([]byte{':'}) + ec.marshalNBuildEvent2numerousᚋcliᚋgraphqlᚋmodelᚐBuildEvent(ctx, field.Selections, res).MarshalGQL(w) + w.Write([]byte{'}'}) + }) + case <-ctx.Done(): + return nil + } + } +} + +func (ec *executionContext) fieldContext_Subscription_deployEvents(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Subscription", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type BuildEvent does not have child fields") + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Subscription_deployEvents_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _Subscription_logs(ctx context.Context, field graphql.CollectedField) (ret func(ctx context.Context) graphql.Marshaler) { + fc, err := ec.fieldContext_Subscription_logs(ctx, field) + if err != nil { + return nil + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + resTmp := ec._fieldMiddleware(ctx, nil, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return ec.resolvers.Subscription().Logs(rctx, fc.Args["appId"].(string)) + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return nil + } + return func(ctx context.Context) graphql.Marshaler { + select { + case res, ok := <-resTmp.(<-chan *model.LogMessage): + if !ok { + return nil + } + return graphql.WriterFunc(func(w io.Writer) { + w.Write([]byte{'{'}) + graphql.MarshalString(field.Alias).MarshalGQL(w) + w.Write([]byte{':'}) + ec.marshalNLogMessage2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐLogMessage(ctx, field.Selections, res).MarshalGQL(w) + w.Write([]byte{'}'}) + }) + case <-ctx.Done(): + return nil + } + } +} + +func (ec *executionContext) fieldContext_Subscription_logs(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Subscription", + Field: field, + IsMethod: true, + IsResolver: true, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "time": + return ec.fieldContext_LogMessage_time(ctx, field) + case "message": + return ec.fieldContext_LogMessage_message(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type LogMessage", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field_Subscription_logs_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) _TextField_id(ctx context.Context, field graphql.CollectedField, obj *model.TextField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_TextField_id(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ID, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNID2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_TextField_id(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "TextField", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type ID does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _TextField_name(ctx context.Context, field graphql.CollectedField, obj *model.TextField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_TextField_name(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_TextField_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "TextField", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _TextField_label(ctx context.Context, field graphql.CollectedField, obj *model.TextField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_TextField_label(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Label, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_TextField_label(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "TextField", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _TextField_graphContext(ctx context.Context, field graphql.CollectedField, obj *model.TextField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_TextField_graphContext(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.GraphContext, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.ElementGraphContext) + fc.Result = res + return ec.marshalNElementGraphContext2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐElementGraphContext(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_TextField_graphContext(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "TextField", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "parent": + return ec.fieldContext_ElementGraphContext_parent(ctx, field) + case "affectedBy": + return ec.fieldContext_ElementGraphContext_affectedBy(ctx, field) + case "affects": + return ec.fieldContext_ElementGraphContext_affects(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type ElementGraphContext", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _TextField_value(ctx context.Context, field graphql.CollectedField, obj *model.TextField) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_TextField_value(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Value, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_TextField_value(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "TextField", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Tool_id(ctx context.Context, field graphql.CollectedField, obj *model.Tool) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Tool_id(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ID, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNID2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Tool_id(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Tool", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type ID does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Tool_name(ctx context.Context, field graphql.CollectedField, obj *model.Tool) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Tool_name(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Tool_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Tool", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Tool_description(ctx context.Context, field graphql.CollectedField, obj *model.Tool) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Tool_description(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Description, nil + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Tool_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Tool", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Tool_user(ctx context.Context, field graphql.CollectedField, obj *model.Tool) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Tool_user(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.User, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.User) + fc.Result = res + return ec.marshalNUser2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐUser(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Tool_user(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Tool", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "fullName": + return ec.fieldContext_User_fullName(ctx, field) + case "memberships": + return ec.fieldContext_User_memberships(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type User", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _Tool_publicUrl(ctx context.Context, field graphql.CollectedField, obj *model.Tool) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Tool_publicUrl(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.PublicURL, nil + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Tool_publicUrl(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Tool", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Tool_sharedUrl(ctx context.Context, field graphql.CollectedField, obj *model.Tool) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Tool_sharedUrl(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.SharedURL, nil + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Tool_sharedUrl(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Tool", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _Tool_createdAt(ctx context.Context, field graphql.CollectedField, obj *model.Tool) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_Tool_createdAt(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.CreatedAt, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(time.Time) + fc.Result = res + return ec.marshalNTime2timeᚐTime(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_Tool_createdAt(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "Tool", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Time does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _ToolDeleteFailure_result(ctx context.Context, field graphql.CollectedField, obj *model.ToolDeleteFailure) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ToolDeleteFailure_result(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Result, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_ToolDeleteFailure_result(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "ToolDeleteFailure", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _ToolDeleteSuccess_result(ctx context.Context, field graphql.CollectedField, obj *model.ToolDeleteSuccess) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ToolDeleteSuccess_result(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Result, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_ToolDeleteSuccess_result(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "ToolDeleteSuccess", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _ToolSession_id(ctx context.Context, field graphql.CollectedField, obj *model.ToolSession) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ToolSession_id(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ID, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNID2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_ToolSession_id(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "ToolSession", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type ID does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _ToolSession_name(ctx context.Context, field graphql.CollectedField, obj *model.ToolSession) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ToolSession_name(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_ToolSession_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "ToolSession", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _ToolSession_allElements(ctx context.Context, field graphql.CollectedField, obj *model.ToolSession) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ToolSession_allElements(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.AllElements, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]model.Element) + fc.Result = res + return ec.marshalNElement2ᚕnumerousᚋcliᚋgraphqlᚋmodelᚐElementᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_ToolSession_allElements(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "ToolSession", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("FieldContext.Child cannot be called on type INTERFACE") + }, + } + return fc, nil +} + +func (ec *executionContext) _ToolSession_isActive(ctx context.Context, field graphql.CollectedField, obj *model.ToolSession) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ToolSession_isActive(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.IsActive, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(bool) + fc.Result = res + return ec.marshalNBoolean2bool(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_ToolSession_isActive(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "ToolSession", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Boolean does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _ToolSession_clientID(ctx context.Context, field graphql.CollectedField, obj *model.ToolSession) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ToolSession_clientID(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.ClientID, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_ToolSession_clientID(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "ToolSession", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _ToolSession_title(ctx context.Context, field graphql.CollectedField, obj *model.ToolSession) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ToolSession_title(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Title, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_ToolSession_title(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "ToolSession", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _ToolSessionActionTriggered_element(ctx context.Context, field graphql.CollectedField, obj *model.ToolSessionActionTriggered) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ToolSessionActionTriggered_element(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Element, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*model.Button) + fc.Result = res + return ec.marshalNButton2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐButton(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_ToolSessionActionTriggered_element(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "ToolSessionActionTriggered", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "id": + return ec.fieldContext_Button_id(ctx, field) + case "name": + return ec.fieldContext_Button_name(ctx, field) + case "label": + return ec.fieldContext_Button_label(ctx, field) + case "graphContext": + return ec.fieldContext_Button_graphContext(ctx, field) + case "value": + return ec.fieldContext_Button_value(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type Button", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) _ToolSessionElementAdded_element(ctx context.Context, field graphql.CollectedField, obj *model.ToolSessionElementAdded) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ToolSessionElementAdded_element(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Element, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(model.Element) + fc.Result = res + return ec.marshalNElement2numerousᚋcliᚋgraphqlᚋmodelᚐElement(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_ToolSessionElementAdded_element(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "ToolSessionElementAdded", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("FieldContext.Child cannot be called on type INTERFACE") + }, + } + return fc, nil +} + +func (ec *executionContext) _ToolSessionElementRemoved_element(ctx context.Context, field graphql.CollectedField, obj *model.ToolSessionElementRemoved) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ToolSessionElementRemoved_element(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Element, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(model.Element) + fc.Result = res + return ec.marshalNElement2numerousᚋcliᚋgraphqlᚋmodelᚐElement(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_ToolSessionElementRemoved_element(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "ToolSessionElementRemoved", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("FieldContext.Child cannot be called on type INTERFACE") + }, + } + return fc, nil +} + +func (ec *executionContext) _ToolSessionElementUpdated_element(ctx context.Context, field graphql.CollectedField, obj *model.ToolSessionElementUpdated) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_ToolSessionElementUpdated_element(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Element, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(model.Element) + fc.Result = res + return ec.marshalNElement2numerousᚋcliᚋgraphqlᚋmodelᚐElement(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_ToolSessionElementUpdated_element(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "ToolSessionElementUpdated", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("FieldContext.Child cannot be called on type INTERFACE") + }, + } + return fc, nil +} + +func (ec *executionContext) _User_fullName(ctx context.Context, field graphql.CollectedField, obj *model.User) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_User_fullName(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.FullName, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_User_fullName(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "User", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _User_memberships(ctx context.Context, field graphql.CollectedField, obj *model.User) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_User_memberships(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Memberships, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]*model.OrganizationMembership) + fc.Result = res + return ec.marshalNOrganizationMembership2ᚕᚖnumerousᚋcliᚋgraphqlᚋmodelᚐOrganizationMembershipᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_User_memberships(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "User", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "organization": + return ec.fieldContext_OrganizationMembership_organization(ctx, field) + case "role": + return ec.fieldContext_OrganizationMembership_role(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type OrganizationMembership", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) ___Directive_name(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Directive_name(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Directive_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Directive", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) ___Directive_description(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Directive_description(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Description(), nil + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Directive_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Directive", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) ___Directive_locations(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Directive_locations(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Locations, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]string) + fc.Result = res + return ec.marshalN__DirectiveLocation2ᚕstringᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Directive_locations(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Directive", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type __DirectiveLocation does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) ___Directive_args(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Directive_args(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Args, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]introspection.InputValue) + fc.Result = res + return ec.marshalN__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Directive_args(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Directive", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "name": + return ec.fieldContext___InputValue_name(ctx, field) + case "description": + return ec.fieldContext___InputValue_description(ctx, field) + case "type": + return ec.fieldContext___InputValue_type(ctx, field) + case "defaultValue": + return ec.fieldContext___InputValue_defaultValue(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type __InputValue", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) ___Directive_isRepeatable(ctx context.Context, field graphql.CollectedField, obj *introspection.Directive) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Directive_isRepeatable(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.IsRepeatable, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(bool) + fc.Result = res + return ec.marshalNBoolean2bool(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Directive_isRepeatable(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Directive", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Boolean does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) ___EnumValue_name(ctx context.Context, field graphql.CollectedField, obj *introspection.EnumValue) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___EnumValue_name(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___EnumValue_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__EnumValue", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) ___EnumValue_description(ctx context.Context, field graphql.CollectedField, obj *introspection.EnumValue) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___EnumValue_description(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Description(), nil + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___EnumValue_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__EnumValue", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) ___EnumValue_isDeprecated(ctx context.Context, field graphql.CollectedField, obj *introspection.EnumValue) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___EnumValue_isDeprecated(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.IsDeprecated(), nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(bool) + fc.Result = res + return ec.marshalNBoolean2bool(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___EnumValue_isDeprecated(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__EnumValue", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Boolean does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) ___EnumValue_deprecationReason(ctx context.Context, field graphql.CollectedField, obj *introspection.EnumValue) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___EnumValue_deprecationReason(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.DeprecationReason(), nil + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___EnumValue_deprecationReason(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__EnumValue", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) ___Field_name(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Field_name(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Field_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Field", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) ___Field_description(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Field_description(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Description(), nil + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Field_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Field", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) ___Field_args(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Field_args(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Args, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]introspection.InputValue) + fc.Result = res + return ec.marshalN__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Field_args(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Field", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "name": + return ec.fieldContext___InputValue_name(ctx, field) + case "description": + return ec.fieldContext___InputValue_description(ctx, field) + case "type": + return ec.fieldContext___InputValue_type(ctx, field) + case "defaultValue": + return ec.fieldContext___InputValue_defaultValue(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type __InputValue", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) ___Field_type(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Field_type(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Type, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*introspection.Type) + fc.Result = res + return ec.marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Field_type(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Field", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "kind": + return ec.fieldContext___Type_kind(ctx, field) + case "name": + return ec.fieldContext___Type_name(ctx, field) + case "description": + return ec.fieldContext___Type_description(ctx, field) + case "fields": + return ec.fieldContext___Type_fields(ctx, field) + case "interfaces": + return ec.fieldContext___Type_interfaces(ctx, field) + case "possibleTypes": + return ec.fieldContext___Type_possibleTypes(ctx, field) + case "enumValues": + return ec.fieldContext___Type_enumValues(ctx, field) + case "inputFields": + return ec.fieldContext___Type_inputFields(ctx, field) + case "ofType": + return ec.fieldContext___Type_ofType(ctx, field) + case "specifiedByURL": + return ec.fieldContext___Type_specifiedByURL(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) ___Field_isDeprecated(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Field_isDeprecated(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.IsDeprecated(), nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(bool) + fc.Result = res + return ec.marshalNBoolean2bool(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Field_isDeprecated(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Field", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type Boolean does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) ___Field_deprecationReason(ctx context.Context, field graphql.CollectedField, obj *introspection.Field) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Field_deprecationReason(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.DeprecationReason(), nil + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Field_deprecationReason(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Field", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) ___InputValue_name(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___InputValue_name(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNString2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___InputValue_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__InputValue", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) ___InputValue_description(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___InputValue_description(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Description(), nil + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___InputValue_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__InputValue", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) ___InputValue_type(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___InputValue_type(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Type, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*introspection.Type) + fc.Result = res + return ec.marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___InputValue_type(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__InputValue", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "kind": + return ec.fieldContext___Type_kind(ctx, field) + case "name": + return ec.fieldContext___Type_name(ctx, field) + case "description": + return ec.fieldContext___Type_description(ctx, field) + case "fields": + return ec.fieldContext___Type_fields(ctx, field) + case "interfaces": + return ec.fieldContext___Type_interfaces(ctx, field) + case "possibleTypes": + return ec.fieldContext___Type_possibleTypes(ctx, field) + case "enumValues": + return ec.fieldContext___Type_enumValues(ctx, field) + case "inputFields": + return ec.fieldContext___Type_inputFields(ctx, field) + case "ofType": + return ec.fieldContext___Type_ofType(ctx, field) + case "specifiedByURL": + return ec.fieldContext___Type_specifiedByURL(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) ___InputValue_defaultValue(ctx context.Context, field graphql.CollectedField, obj *introspection.InputValue) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___InputValue_defaultValue(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.DefaultValue, nil + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___InputValue_defaultValue(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__InputValue", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) ___Schema_description(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Schema_description(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Description(), nil + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Schema_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Schema", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) ___Schema_types(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Schema_types(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Types(), nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]introspection.Type) + fc.Result = res + return ec.marshalN__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Schema_types(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Schema", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "kind": + return ec.fieldContext___Type_kind(ctx, field) + case "name": + return ec.fieldContext___Type_name(ctx, field) + case "description": + return ec.fieldContext___Type_description(ctx, field) + case "fields": + return ec.fieldContext___Type_fields(ctx, field) + case "interfaces": + return ec.fieldContext___Type_interfaces(ctx, field) + case "possibleTypes": + return ec.fieldContext___Type_possibleTypes(ctx, field) + case "enumValues": + return ec.fieldContext___Type_enumValues(ctx, field) + case "inputFields": + return ec.fieldContext___Type_inputFields(ctx, field) + case "ofType": + return ec.fieldContext___Type_ofType(ctx, field) + case "specifiedByURL": + return ec.fieldContext___Type_specifiedByURL(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) ___Schema_queryType(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Schema_queryType(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.QueryType(), nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(*introspection.Type) + fc.Result = res + return ec.marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Schema_queryType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Schema", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "kind": + return ec.fieldContext___Type_kind(ctx, field) + case "name": + return ec.fieldContext___Type_name(ctx, field) + case "description": + return ec.fieldContext___Type_description(ctx, field) + case "fields": + return ec.fieldContext___Type_fields(ctx, field) + case "interfaces": + return ec.fieldContext___Type_interfaces(ctx, field) + case "possibleTypes": + return ec.fieldContext___Type_possibleTypes(ctx, field) + case "enumValues": + return ec.fieldContext___Type_enumValues(ctx, field) + case "inputFields": + return ec.fieldContext___Type_inputFields(ctx, field) + case "ofType": + return ec.fieldContext___Type_ofType(ctx, field) + case "specifiedByURL": + return ec.fieldContext___Type_specifiedByURL(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) ___Schema_mutationType(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Schema_mutationType(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.MutationType(), nil + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*introspection.Type) + fc.Result = res + return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Schema_mutationType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Schema", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "kind": + return ec.fieldContext___Type_kind(ctx, field) + case "name": + return ec.fieldContext___Type_name(ctx, field) + case "description": + return ec.fieldContext___Type_description(ctx, field) + case "fields": + return ec.fieldContext___Type_fields(ctx, field) + case "interfaces": + return ec.fieldContext___Type_interfaces(ctx, field) + case "possibleTypes": + return ec.fieldContext___Type_possibleTypes(ctx, field) + case "enumValues": + return ec.fieldContext___Type_enumValues(ctx, field) + case "inputFields": + return ec.fieldContext___Type_inputFields(ctx, field) + case "ofType": + return ec.fieldContext___Type_ofType(ctx, field) + case "specifiedByURL": + return ec.fieldContext___Type_specifiedByURL(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) ___Schema_subscriptionType(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Schema_subscriptionType(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.SubscriptionType(), nil + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*introspection.Type) + fc.Result = res + return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Schema_subscriptionType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Schema", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "kind": + return ec.fieldContext___Type_kind(ctx, field) + case "name": + return ec.fieldContext___Type_name(ctx, field) + case "description": + return ec.fieldContext___Type_description(ctx, field) + case "fields": + return ec.fieldContext___Type_fields(ctx, field) + case "interfaces": + return ec.fieldContext___Type_interfaces(ctx, field) + case "possibleTypes": + return ec.fieldContext___Type_possibleTypes(ctx, field) + case "enumValues": + return ec.fieldContext___Type_enumValues(ctx, field) + case "inputFields": + return ec.fieldContext___Type_inputFields(ctx, field) + case "ofType": + return ec.fieldContext___Type_ofType(ctx, field) + case "specifiedByURL": + return ec.fieldContext___Type_specifiedByURL(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) ___Schema_directives(ctx context.Context, field graphql.CollectedField, obj *introspection.Schema) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Schema_directives(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Directives(), nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.([]introspection.Directive) + fc.Result = res + return ec.marshalN__Directive2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirectiveᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Schema_directives(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Schema", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "name": + return ec.fieldContext___Directive_name(ctx, field) + case "description": + return ec.fieldContext___Directive_description(ctx, field) + case "locations": + return ec.fieldContext___Directive_locations(ctx, field) + case "args": + return ec.fieldContext___Directive_args(ctx, field) + case "isRepeatable": + return ec.fieldContext___Directive_isRepeatable(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type __Directive", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) ___Type_kind(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Type_kind(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Kind(), nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalN__TypeKind2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Type_kind(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Type", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type __TypeKind does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) ___Type_name(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Type_name(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Name(), nil + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Type_name(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Type", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) ___Type_description(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Type_description(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Description(), nil + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Type_description(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Type", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) ___Type_fields(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Type_fields(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Fields(fc.Args["includeDeprecated"].(bool)), nil + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]introspection.Field) + fc.Result = res + return ec.marshalO__Field2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐFieldᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Type_fields(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Type", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "name": + return ec.fieldContext___Field_name(ctx, field) + case "description": + return ec.fieldContext___Field_description(ctx, field) + case "args": + return ec.fieldContext___Field_args(ctx, field) + case "type": + return ec.fieldContext___Field_type(ctx, field) + case "isDeprecated": + return ec.fieldContext___Field_isDeprecated(ctx, field) + case "deprecationReason": + return ec.fieldContext___Field_deprecationReason(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type __Field", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field___Type_fields_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) ___Type_interfaces(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Type_interfaces(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.Interfaces(), nil + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]introspection.Type) + fc.Result = res + return ec.marshalO__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Type_interfaces(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Type", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "kind": + return ec.fieldContext___Type_kind(ctx, field) + case "name": + return ec.fieldContext___Type_name(ctx, field) + case "description": + return ec.fieldContext___Type_description(ctx, field) + case "fields": + return ec.fieldContext___Type_fields(ctx, field) + case "interfaces": + return ec.fieldContext___Type_interfaces(ctx, field) + case "possibleTypes": + return ec.fieldContext___Type_possibleTypes(ctx, field) + case "enumValues": + return ec.fieldContext___Type_enumValues(ctx, field) + case "inputFields": + return ec.fieldContext___Type_inputFields(ctx, field) + case "ofType": + return ec.fieldContext___Type_ofType(ctx, field) + case "specifiedByURL": + return ec.fieldContext___Type_specifiedByURL(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) ___Type_possibleTypes(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Type_possibleTypes(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.PossibleTypes(), nil + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]introspection.Type) + fc.Result = res + return ec.marshalO__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Type_possibleTypes(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Type", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "kind": + return ec.fieldContext___Type_kind(ctx, field) + case "name": + return ec.fieldContext___Type_name(ctx, field) + case "description": + return ec.fieldContext___Type_description(ctx, field) + case "fields": + return ec.fieldContext___Type_fields(ctx, field) + case "interfaces": + return ec.fieldContext___Type_interfaces(ctx, field) + case "possibleTypes": + return ec.fieldContext___Type_possibleTypes(ctx, field) + case "enumValues": + return ec.fieldContext___Type_enumValues(ctx, field) + case "inputFields": + return ec.fieldContext___Type_inputFields(ctx, field) + case "ofType": + return ec.fieldContext___Type_ofType(ctx, field) + case "specifiedByURL": + return ec.fieldContext___Type_specifiedByURL(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) ___Type_enumValues(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Type_enumValues(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.EnumValues(fc.Args["includeDeprecated"].(bool)), nil + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]introspection.EnumValue) + fc.Result = res + return ec.marshalO__EnumValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValueᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Type_enumValues(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Type", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "name": + return ec.fieldContext___EnumValue_name(ctx, field) + case "description": + return ec.fieldContext___EnumValue_description(ctx, field) + case "isDeprecated": + return ec.fieldContext___EnumValue_isDeprecated(ctx, field) + case "deprecationReason": + return ec.fieldContext___EnumValue_deprecationReason(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type __EnumValue", field.Name) + }, + } + defer func() { + if r := recover(); r != nil { + err = ec.Recover(ctx, r) + ec.Error(ctx, err) + } + }() + ctx = graphql.WithFieldContext(ctx, fc) + if fc.Args, err = ec.field___Type_enumValues_args(ctx, field.ArgumentMap(ec.Variables)); err != nil { + ec.Error(ctx, err) + return fc, err + } + return fc, nil +} + +func (ec *executionContext) ___Type_inputFields(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Type_inputFields(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.InputFields(), nil + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.([]introspection.InputValue) + fc.Result = res + return ec.marshalO__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Type_inputFields(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Type", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "name": + return ec.fieldContext___InputValue_name(ctx, field) + case "description": + return ec.fieldContext___InputValue_description(ctx, field) + case "type": + return ec.fieldContext___InputValue_type(ctx, field) + case "defaultValue": + return ec.fieldContext___InputValue_defaultValue(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type __InputValue", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) ___Type_ofType(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Type_ofType(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.OfType(), nil + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*introspection.Type) + fc.Result = res + return ec.marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Type_ofType(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Type", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + switch field.Name { + case "kind": + return ec.fieldContext___Type_kind(ctx, field) + case "name": + return ec.fieldContext___Type_name(ctx, field) + case "description": + return ec.fieldContext___Type_description(ctx, field) + case "fields": + return ec.fieldContext___Type_fields(ctx, field) + case "interfaces": + return ec.fieldContext___Type_interfaces(ctx, field) + case "possibleTypes": + return ec.fieldContext___Type_possibleTypes(ctx, field) + case "enumValues": + return ec.fieldContext___Type_enumValues(ctx, field) + case "inputFields": + return ec.fieldContext___Type_inputFields(ctx, field) + case "ofType": + return ec.fieldContext___Type_ofType(ctx, field) + case "specifiedByURL": + return ec.fieldContext___Type_specifiedByURL(ctx, field) + } + return nil, fmt.Errorf("no field named %q was found under type __Type", field.Name) + }, + } + return fc, nil +} + +func (ec *executionContext) ___Type_specifiedByURL(ctx context.Context, field graphql.CollectedField, obj *introspection.Type) (ret graphql.Marshaler) { + fc, err := ec.fieldContext___Type_specifiedByURL(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.SpecifiedByURL(), nil + }) + + if resTmp == nil { + return graphql.Null + } + res := resTmp.(*string) + fc.Result = res + return ec.marshalOString2ᚖstring(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext___Type_specifiedByURL(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "__Type", + Field: field, + IsMethod: true, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type String does not have child fields") + }, + } + return fc, nil +} + +func (ec *executionContext) _buildConfiguration_buildId(ctx context.Context, field graphql.CollectedField, obj *model.BuildConfiguration) (ret graphql.Marshaler) { + fc, err := ec.fieldContext_buildConfiguration_buildId(ctx, field) + if err != nil { + return graphql.Null + } + ctx = graphql.WithFieldContext(ctx, fc) + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = graphql.Null + } + }() + resTmp := ec._fieldMiddleware(ctx, obj, func(rctx context.Context) (interface{}, error) { + ctx = rctx // use context from middleware stack in children + return obj.BuildID, nil + }) + + if resTmp == nil { + if !graphql.HasFieldError(ctx, fc) { + ec.Errorf(ctx, "must not be null") + } + return graphql.Null + } + res := resTmp.(string) + fc.Result = res + return ec.marshalNID2string(ctx, field.Selections, res) +} + +func (ec *executionContext) fieldContext_buildConfiguration_buildId(ctx context.Context, field graphql.CollectedField) (fc *graphql.FieldContext, err error) { + fc = &graphql.FieldContext{ + Object: "buildConfiguration", + Field: field, + IsMethod: false, + IsResolver: false, + Child: func(ctx context.Context, field graphql.CollectedField) (*graphql.FieldContext, error) { + return nil, errors.New("field of type ID does not have child fields") + }, + } + return fc, nil +} + +// endregion **************************** field.gotpl ***************************** + +// region **************************** input.gotpl ***************************** + +func (ec *executionContext) unmarshalInputElementInput(ctx context.Context, obj interface{}) (model.ElementInput, error) { + var it model.ElementInput + asMap := map[string]interface{}{} + for k, v := range obj.(map[string]interface{}) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"elementID", "textValue", "numberValue", "htmlValue", "sliderValue"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "elementID": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("elementID")) + data, err := ec.unmarshalNID2string(ctx, v) + if err != nil { + return it, err + } + it.ElementID = data + case "textValue": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("textValue")) + data, err := ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + it.TextValue = data + case "numberValue": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("numberValue")) + data, err := ec.unmarshalOFloat2ᚖfloat64(ctx, v) + if err != nil { + return it, err + } + it.NumberValue = data + case "htmlValue": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("htmlValue")) + data, err := ec.unmarshalOString2ᚖstring(ctx, v) + if err != nil { + return it, err + } + it.HTMLValue = data + case "sliderValue": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("sliderValue")) + data, err := ec.unmarshalOFloat2ᚖfloat64(ctx, v) + if err != nil { + return it, err + } + it.SliderValue = data + } + } + + return it, nil +} + +func (ec *executionContext) unmarshalInputElementSelectInput(ctx context.Context, obj interface{}) (model.ElementSelectInput, error) { + var it model.ElementSelectInput + asMap := map[string]interface{}{} + for k, v := range obj.(map[string]interface{}) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"selectElementID", "selectedOptionID"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "selectElementID": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("selectElementID")) + data, err := ec.unmarshalNID2string(ctx, v) + if err != nil { + return it, err + } + it.SelectElementID = data + case "selectedOptionID": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("selectedOptionID")) + data, err := ec.unmarshalNID2string(ctx, v) + if err != nil { + return it, err + } + it.SelectedOptionID = data + } + } + + return it, nil +} + +func (ec *executionContext) unmarshalInputListElementInput(ctx context.Context, obj interface{}) (model.ListElementInput, error) { + var it model.ListElementInput + asMap := map[string]interface{}{} + for k, v := range obj.(map[string]interface{}) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"listElementID"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "listElementID": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("listElementID")) + data, err := ec.unmarshalNID2string(ctx, v) + if err != nil { + return it, err + } + it.ListElementID = data + } + } + + return it, nil +} + +func (ec *executionContext) unmarshalInputNewOrganization(ctx context.Context, obj interface{}) (model.NewOrganization, error) { + var it model.NewOrganization + asMap := map[string]interface{}{} + for k, v := range obj.(map[string]interface{}) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"name"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "name": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("name")) + data, err := ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err + } + it.Name = data + } + } + + return it, nil +} + +func (ec *executionContext) unmarshalInputNewTool(ctx context.Context, obj interface{}) (model.NewTool, error) { + var it model.NewTool + asMap := map[string]interface{}{} + for k, v := range obj.(map[string]interface{}) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"userId", "manifest"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "userId": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("userId")) + data, err := ec.unmarshalNID2string(ctx, v) + if err != nil { + return it, err + } + it.UserID = data + case "manifest": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("manifest")) + data, err := ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err + } + it.Manifest = data + } + } + + return it, nil +} + +func (ec *executionContext) unmarshalInputOrganizationInvitationInput(ctx context.Context, obj interface{}) (model.OrganizationInvitationInput, error) { + var it model.OrganizationInvitationInput + asMap := map[string]interface{}{} + for k, v := range obj.(map[string]interface{}) { + asMap[k] = v + } + + fieldsInOrder := [...]string{"role", "email"} + for _, k := range fieldsInOrder { + v, ok := asMap[k] + if !ok { + continue + } + switch k { + case "role": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("role")) + data, err := ec.unmarshalNRole2numerousᚋcliᚋgraphqlᚋmodelᚐRole(ctx, v) + if err != nil { + return it, err + } + it.Role = data + case "email": + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithField("email")) + data, err := ec.unmarshalNString2string(ctx, v) + if err != nil { + return it, err + } + it.Email = data + } + } + + return it, nil +} + +// endregion **************************** input.gotpl ***************************** + +// region ************************** interface.gotpl *************************** + +func (ec *executionContext) _BuildEvent(ctx context.Context, sel ast.SelectionSet, obj model.BuildEvent) graphql.Marshaler { + switch obj := (obj).(type) { + case nil: + return graphql.Null + case model.BuildEventSuccess: + return ec._BuildEventSuccess(ctx, sel, &obj) + case *model.BuildEventSuccess: + if obj == nil { + return graphql.Null + } + return ec._BuildEventSuccess(ctx, sel, obj) + case model.BuildEventFailure: + return ec._BuildEventFailure(ctx, sel, &obj) + case *model.BuildEventFailure: + if obj == nil { + return graphql.Null + } + return ec._BuildEventFailure(ctx, sel, obj) + case model.BuildEventInfo: + return ec._BuildEventInfo(ctx, sel, &obj) + case *model.BuildEventInfo: + if obj == nil { + return graphql.Null + } + return ec._BuildEventInfo(ctx, sel, obj) + default: + panic(fmt.Errorf("unexpected type %T", obj)) + } +} + +func (ec *executionContext) _Element(ctx context.Context, sel ast.SelectionSet, obj model.Element) graphql.Marshaler { + switch obj := (obj).(type) { + case nil: + return graphql.Null + case model.Container: + return ec._Container(ctx, sel, &obj) + case *model.Container: + if obj == nil { + return graphql.Null + } + return ec._Container(ctx, sel, obj) + case model.ElementList: + return ec._ElementList(ctx, sel, &obj) + case *model.ElementList: + if obj == nil { + return graphql.Null + } + return ec._ElementList(ctx, sel, obj) + case model.ElementSelect: + return ec._ElementSelect(ctx, sel, &obj) + case *model.ElementSelect: + if obj == nil { + return graphql.Null + } + return ec._ElementSelect(ctx, sel, obj) + case model.SliderElement: + return ec._SliderElement(ctx, sel, &obj) + case *model.SliderElement: + if obj == nil { + return graphql.Null + } + return ec._SliderElement(ctx, sel, obj) + case model.HTMLElement: + return ec._HTMLElement(ctx, sel, &obj) + case *model.HTMLElement: + if obj == nil { + return graphql.Null + } + return ec._HTMLElement(ctx, sel, obj) + case model.Button: + return ec._Button(ctx, sel, &obj) + case *model.Button: + if obj == nil { + return graphql.Null + } + return ec._Button(ctx, sel, obj) + case model.TextField: + return ec._TextField(ctx, sel, &obj) + case *model.TextField: + if obj == nil { + return graphql.Null + } + return ec._TextField(ctx, sel, obj) + case model.NumberField: + return ec._NumberField(ctx, sel, &obj) + case *model.NumberField: + if obj == nil { + return graphql.Null + } + return ec._NumberField(ctx, sel, obj) + default: + panic(fmt.Errorf("unexpected type %T", obj)) + } +} + +func (ec *executionContext) _ElementGraphParent(ctx context.Context, sel ast.SelectionSet, obj model.ElementGraphParent) graphql.Marshaler { + switch obj := (obj).(type) { + case nil: + return graphql.Null + case model.Container: + return ec._Container(ctx, sel, &obj) + case *model.Container: + if obj == nil { + return graphql.Null + } + return ec._Container(ctx, sel, obj) + case model.ElementList: + return ec._ElementList(ctx, sel, &obj) + case *model.ElementList: + if obj == nil { + return graphql.Null + } + return ec._ElementList(ctx, sel, obj) + case model.ElementSelect: + return ec._ElementSelect(ctx, sel, &obj) + case *model.ElementSelect: + if obj == nil { + return graphql.Null + } + return ec._ElementSelect(ctx, sel, obj) + default: + panic(fmt.Errorf("unexpected type %T", obj)) + } +} + +func (ec *executionContext) _OrganizationInvitationAcceptResult(ctx context.Context, sel ast.SelectionSet, obj model.OrganizationInvitationAcceptResult) graphql.Marshaler { + switch obj := (obj).(type) { + case nil: + return graphql.Null + case model.Organization: + return ec._Organization(ctx, sel, &obj) + case *model.Organization: + if obj == nil { + return graphql.Null + } + return ec._Organization(ctx, sel, obj) + case model.OrganizationNotFound: + return ec._OrganizationNotFound(ctx, sel, &obj) + case *model.OrganizationNotFound: + if obj == nil { + return graphql.Null + } + return ec._OrganizationNotFound(ctx, sel, obj) + default: + panic(fmt.Errorf("unexpected type %T", obj)) + } +} + +func (ec *executionContext) _OrganizationInvitationCreateResult(ctx context.Context, sel ast.SelectionSet, obj model.OrganizationInvitationCreateResult) graphql.Marshaler { + switch obj := (obj).(type) { + case nil: + return graphql.Null + case model.OrganizationInvitation: + return ec._OrganizationInvitation(ctx, sel, &obj) + case *model.OrganizationInvitation: + if obj == nil { + return graphql.Null + } + return ec._OrganizationInvitation(ctx, sel, obj) + case model.OrganizationNotFound: + return ec._OrganizationNotFound(ctx, sel, &obj) + case *model.OrganizationNotFound: + if obj == nil { + return graphql.Null + } + return ec._OrganizationNotFound(ctx, sel, obj) + case model.InvalidEmail: + return ec._InvalidEmail(ctx, sel, &obj) + case *model.InvalidEmail: + if obj == nil { + return graphql.Null + } + return ec._InvalidEmail(ctx, sel, obj) + case model.OrganizationMemberExists: + return ec._OrganizationMemberExists(ctx, sel, &obj) + case *model.OrganizationMemberExists: + if obj == nil { + return graphql.Null + } + return ec._OrganizationMemberExists(ctx, sel, obj) + default: + panic(fmt.Errorf("unexpected type %T", obj)) + } +} + +func (ec *executionContext) _OrganizationInvitationQueryResult(ctx context.Context, sel ast.SelectionSet, obj model.OrganizationInvitationQueryResult) graphql.Marshaler { + switch obj := (obj).(type) { + case nil: + return graphql.Null + case model.OrganizationInvitation: + return ec._OrganizationInvitation(ctx, sel, &obj) + case *model.OrganizationInvitation: + if obj == nil { + return graphql.Null + } + return ec._OrganizationInvitation(ctx, sel, obj) + case model.OrganizationNotFound: + return ec._OrganizationNotFound(ctx, sel, &obj) + case *model.OrganizationNotFound: + if obj == nil { + return graphql.Null + } + return ec._OrganizationNotFound(ctx, sel, obj) + case model.OrganizationInvitationNotFound: + return ec._OrganizationInvitationNotFound(ctx, sel, &obj) + case *model.OrganizationInvitationNotFound: + if obj == nil { + return graphql.Null + } + return ec._OrganizationInvitationNotFound(ctx, sel, obj) + default: + panic(fmt.Errorf("unexpected type %T", obj)) + } +} + +func (ec *executionContext) _OrganizationQueryResult(ctx context.Context, sel ast.SelectionSet, obj model.OrganizationQueryResult) graphql.Marshaler { + switch obj := (obj).(type) { + case nil: + return graphql.Null + case model.Organization: + return ec._Organization(ctx, sel, &obj) + case *model.Organization: + if obj == nil { + return graphql.Null + } + return ec._Organization(ctx, sel, obj) + case model.OrganizationNotFound: + return ec._OrganizationNotFound(ctx, sel, &obj) + case *model.OrganizationNotFound: + if obj == nil { + return graphql.Null + } + return ec._OrganizationNotFound(ctx, sel, obj) + default: + panic(fmt.Errorf("unexpected type %T", obj)) + } +} + +func (ec *executionContext) _OrganizationRenameResult(ctx context.Context, sel ast.SelectionSet, obj model.OrganizationRenameResult) graphql.Marshaler { + switch obj := (obj).(type) { + case nil: + return graphql.Null + case model.Organization: + return ec._Organization(ctx, sel, &obj) + case *model.Organization: + if obj == nil { + return graphql.Null + } + return ec._Organization(ctx, sel, obj) + case model.OrganizationNotFound: + return ec._OrganizationNotFound(ctx, sel, &obj) + case *model.OrganizationNotFound: + if obj == nil { + return graphql.Null + } + return ec._OrganizationNotFound(ctx, sel, obj) + case model.OrganizationRenameFailure: + return ec._OrganizationRenameFailure(ctx, sel, &obj) + case *model.OrganizationRenameFailure: + if obj == nil { + return graphql.Null + } + return ec._OrganizationRenameFailure(ctx, sel, obj) + default: + panic(fmt.Errorf("unexpected type %T", obj)) + } +} + +func (ec *executionContext) _ToolDeleteResult(ctx context.Context, sel ast.SelectionSet, obj model.ToolDeleteResult) graphql.Marshaler { + switch obj := (obj).(type) { + case nil: + return graphql.Null + case model.ToolDeleteSuccess: + return ec._ToolDeleteSuccess(ctx, sel, &obj) + case *model.ToolDeleteSuccess: + if obj == nil { + return graphql.Null + } + return ec._ToolDeleteSuccess(ctx, sel, obj) + case model.ToolDeleteFailure: + return ec._ToolDeleteFailure(ctx, sel, &obj) + case *model.ToolDeleteFailure: + if obj == nil { + return graphql.Null + } + return ec._ToolDeleteFailure(ctx, sel, obj) + default: + panic(fmt.Errorf("unexpected type %T", obj)) + } +} + +func (ec *executionContext) _ToolSessionEvent(ctx context.Context, sel ast.SelectionSet, obj model.ToolSessionEvent) graphql.Marshaler { + switch obj := (obj).(type) { + case nil: + return graphql.Null + case model.ToolSessionElementAdded: + return ec._ToolSessionElementAdded(ctx, sel, &obj) + case *model.ToolSessionElementAdded: + if obj == nil { + return graphql.Null + } + return ec._ToolSessionElementAdded(ctx, sel, obj) + case model.ToolSessionElementRemoved: + return ec._ToolSessionElementRemoved(ctx, sel, &obj) + case *model.ToolSessionElementRemoved: + if obj == nil { + return graphql.Null + } + return ec._ToolSessionElementRemoved(ctx, sel, obj) + case model.ToolSessionElementUpdated: + return ec._ToolSessionElementUpdated(ctx, sel, &obj) + case *model.ToolSessionElementUpdated: + if obj == nil { + return graphql.Null + } + return ec._ToolSessionElementUpdated(ctx, sel, obj) + case model.ToolSessionActionTriggered: + return ec._ToolSessionActionTriggered(ctx, sel, &obj) + case *model.ToolSessionActionTriggered: + if obj == nil { + return graphql.Null + } + return ec._ToolSessionActionTriggered(ctx, sel, obj) + default: + panic(fmt.Errorf("unexpected type %T", obj)) + } +} + +// endregion ************************** interface.gotpl *************************** + +// region **************************** object.gotpl **************************** + +var appImplementors = []string{"App"} + +func (ec *executionContext) _App(ctx context.Context, sel ast.SelectionSet, obj *model.App) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, appImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("App") + case "id": + out.Values[i] = ec._App_id(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "name": + out.Values[i] = ec._App_name(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "description": + out.Values[i] = ec._App_description(ctx, field, obj) + case "user": + out.Values[i] = ec._App_user(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "publicUrl": + out.Values[i] = ec._App_publicUrl(ctx, field, obj) + case "sharedUrl": + out.Values[i] = ec._App_sharedUrl(ctx, field, obj) + case "createdAt": + out.Values[i] = ec._App_createdAt(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var appDeployImplementors = []string{"AppDeploy"} + +func (ec *executionContext) _AppDeploy(ctx context.Context, sel ast.SelectionSet, obj *model.AppDeploy) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, appDeployImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("AppDeploy") + case "app": + out.Values[i] = ec._AppDeploy_app(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "buildId": + out.Values[i] = ec._AppDeploy_buildId(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var buildEventFailureImplementors = []string{"BuildEventFailure", "BuildEvent"} + +func (ec *executionContext) _BuildEventFailure(ctx context.Context, sel ast.SelectionSet, obj *model.BuildEventFailure) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, buildEventFailureImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("BuildEventFailure") + case "result": + out.Values[i] = ec._BuildEventFailure_result(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var buildEventInfoImplementors = []string{"BuildEventInfo", "BuildEvent"} + +func (ec *executionContext) _BuildEventInfo(ctx context.Context, sel ast.SelectionSet, obj *model.BuildEventInfo) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, buildEventInfoImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("BuildEventInfo") + case "result": + out.Values[i] = ec._BuildEventInfo_result(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var buildEventSuccessImplementors = []string{"BuildEventSuccess", "BuildEvent"} + +func (ec *executionContext) _BuildEventSuccess(ctx context.Context, sel ast.SelectionSet, obj *model.BuildEventSuccess) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, buildEventSuccessImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("BuildEventSuccess") + case "result": + out.Values[i] = ec._BuildEventSuccess_result(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var buttonImplementors = []string{"Button", "Element"} + +func (ec *executionContext) _Button(ctx context.Context, sel ast.SelectionSet, obj *model.Button) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, buttonImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("Button") + case "id": + out.Values[i] = ec._Button_id(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "name": + out.Values[i] = ec._Button_name(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "label": + out.Values[i] = ec._Button_label(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "graphContext": + out.Values[i] = ec._Button_graphContext(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "value": + out.Values[i] = ec._Button_value(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var containerImplementors = []string{"Container", "Element", "ElementGraphParent"} + +func (ec *executionContext) _Container(ctx context.Context, sel ast.SelectionSet, obj *model.Container) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, containerImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("Container") + case "id": + out.Values[i] = ec._Container_id(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "name": + out.Values[i] = ec._Container_name(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "label": + out.Values[i] = ec._Container_label(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "graphContext": + out.Values[i] = ec._Container_graphContext(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var elementGraphContextImplementors = []string{"ElementGraphContext"} + +func (ec *executionContext) _ElementGraphContext(ctx context.Context, sel ast.SelectionSet, obj *model.ElementGraphContext) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, elementGraphContextImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("ElementGraphContext") + case "parent": + out.Values[i] = ec._ElementGraphContext_parent(ctx, field, obj) + case "affectedBy": + out.Values[i] = ec._ElementGraphContext_affectedBy(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "affects": + out.Values[i] = ec._ElementGraphContext_affects(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var elementListImplementors = []string{"ElementList", "Element", "ElementGraphParent"} + +func (ec *executionContext) _ElementList(ctx context.Context, sel ast.SelectionSet, obj *model.ElementList) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, elementListImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("ElementList") + case "id": + out.Values[i] = ec._ElementList_id(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "name": + out.Values[i] = ec._ElementList_name(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "label": + out.Values[i] = ec._ElementList_label(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "graphContext": + out.Values[i] = ec._ElementList_graphContext(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var elementSelectImplementors = []string{"ElementSelect", "Element", "ElementGraphParent"} + +func (ec *executionContext) _ElementSelect(ctx context.Context, sel ast.SelectionSet, obj *model.ElementSelect) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, elementSelectImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("ElementSelect") + case "id": + out.Values[i] = ec._ElementSelect_id(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "name": + out.Values[i] = ec._ElementSelect_name(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "label": + out.Values[i] = ec._ElementSelect_label(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "graphContext": + out.Values[i] = ec._ElementSelect_graphContext(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "selectedOption": + out.Values[i] = ec._ElementSelect_selectedOption(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var hTMLElementImplementors = []string{"HTMLElement", "Element"} + +func (ec *executionContext) _HTMLElement(ctx context.Context, sel ast.SelectionSet, obj *model.HTMLElement) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, hTMLElementImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("HTMLElement") + case "id": + out.Values[i] = ec._HTMLElement_id(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "name": + out.Values[i] = ec._HTMLElement_name(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "label": + out.Values[i] = ec._HTMLElement_label(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "graphContext": + out.Values[i] = ec._HTMLElement_graphContext(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "html": + out.Values[i] = ec._HTMLElement_html(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var invalidEmailImplementors = []string{"InvalidEmail", "OrganizationInvitationCreateResult"} + +func (ec *executionContext) _InvalidEmail(ctx context.Context, sel ast.SelectionSet, obj *model.InvalidEmail) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, invalidEmailImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("InvalidEmail") + case "email": + out.Values[i] = ec._InvalidEmail_email(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var jobImplementors = []string{"Job"} + +func (ec *executionContext) _Job(ctx context.Context, sel ast.SelectionSet, obj *model.Job) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, jobImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("Job") + case "id": + out.Values[i] = ec._Job_id(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "status": + out.Values[i] = ec._Job_status(ctx, field, obj) + case "proxyUrl": + out.Values[i] = ec._Job_proxyUrl(ctx, field, obj) + case "user": + out.Values[i] = ec._Job_user(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "createdAt": + out.Values[i] = ec._Job_createdAt(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var logMessageImplementors = []string{"LogMessage"} + +func (ec *executionContext) _LogMessage(ctx context.Context, sel ast.SelectionSet, obj *model.LogMessage) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, logMessageImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("LogMessage") + case "time": + out.Values[i] = ec._LogMessage_time(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "message": + out.Values[i] = ec._LogMessage_message(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var mutationImplementors = []string{"Mutation"} + +func (ec *executionContext) _Mutation(ctx context.Context, sel ast.SelectionSet) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, mutationImplementors) + ctx = graphql.WithFieldContext(ctx, &graphql.FieldContext{ + Object: "Mutation", + }) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + innerCtx := graphql.WithRootFieldContext(ctx, &graphql.RootFieldContext{ + Object: field.Name, + Field: field, + }) + + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("Mutation") + case "organizationCreate": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_organizationCreate(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "organizationRename": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_organizationRename(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "organizationInvitationCreate": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_organizationInvitationCreate(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "organizationInvitationAccept": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_organizationInvitationAccept(ctx, field) + }) + case "toolCreate": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_toolCreate(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "toolPublish": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_toolPublish(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "toolUnpublish": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_toolUnpublish(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "toolDelete": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_toolDelete(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "organizationAppDeploy": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_organizationAppDeploy(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "jobStart": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_jobStart(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "jobStop": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_jobStop(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "toolSessionCreate": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_toolSessionCreate(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "elementUpdate": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_elementUpdate(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "elementTrigger": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_elementTrigger(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "elementSelectionUpdate": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_elementSelectionUpdate(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "listElementAdd": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_listElementAdd(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "listElementRemove": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_listElementRemove(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "buildPush": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Mutation_buildPush(ctx, field) + }) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var numberFieldImplementors = []string{"NumberField", "Element"} + +func (ec *executionContext) _NumberField(ctx context.Context, sel ast.SelectionSet, obj *model.NumberField) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, numberFieldImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("NumberField") + case "id": + out.Values[i] = ec._NumberField_id(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "name": + out.Values[i] = ec._NumberField_name(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "label": + out.Values[i] = ec._NumberField_label(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "graphContext": + out.Values[i] = ec._NumberField_graphContext(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "value": + out.Values[i] = ec._NumberField_value(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var organizationImplementors = []string{"Organization", "OrganizationRenameResult", "OrganizationQueryResult", "OrganizationInvitationAcceptResult"} + +func (ec *executionContext) _Organization(ctx context.Context, sel ast.SelectionSet, obj *model.Organization) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, organizationImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("Organization") + case "id": + out.Values[i] = ec._Organization_id(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "name": + out.Values[i] = ec._Organization_name(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "slug": + out.Values[i] = ec._Organization_slug(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "apps": + out.Values[i] = ec._Organization_apps(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "members": + out.Values[i] = ec._Organization_members(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var organizationInvitationImplementors = []string{"OrganizationInvitation", "OrganizationInvitationQueryResult", "OrganizationInvitationCreateResult"} + +func (ec *executionContext) _OrganizationInvitation(ctx context.Context, sel ast.SelectionSet, obj *model.OrganizationInvitation) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, organizationInvitationImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("OrganizationInvitation") + case "id": + out.Values[i] = ec._OrganizationInvitation_id(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "email": + out.Values[i] = ec._OrganizationInvitation_email(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "organizationName": + out.Values[i] = ec._OrganizationInvitation_organizationName(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "invitedAt": + out.Values[i] = ec._OrganizationInvitation_invitedAt(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "role": + out.Values[i] = ec._OrganizationInvitation_role(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var organizationInvitationNotFoundImplementors = []string{"OrganizationInvitationNotFound", "OrganizationInvitationQueryResult"} + +func (ec *executionContext) _OrganizationInvitationNotFound(ctx context.Context, sel ast.SelectionSet, obj *model.OrganizationInvitationNotFound) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, organizationInvitationNotFoundImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("OrganizationInvitationNotFound") + case "id": + out.Values[i] = ec._OrganizationInvitationNotFound_id(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var organizationMemberExistsImplementors = []string{"OrganizationMemberExists", "OrganizationInvitationCreateResult"} + +func (ec *executionContext) _OrganizationMemberExists(ctx context.Context, sel ast.SelectionSet, obj *model.OrganizationMemberExists) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, organizationMemberExistsImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("OrganizationMemberExists") + case "email": + out.Values[i] = ec._OrganizationMemberExists_email(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var organizationMembershipImplementors = []string{"OrganizationMembership"} + +func (ec *executionContext) _OrganizationMembership(ctx context.Context, sel ast.SelectionSet, obj *model.OrganizationMembership) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, organizationMembershipImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("OrganizationMembership") + case "organization": + out.Values[i] = ec._OrganizationMembership_organization(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "role": + out.Values[i] = ec._OrganizationMembership_role(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var organizationNotFoundImplementors = []string{"OrganizationNotFound", "OrganizationRenameResult", "OrganizationQueryResult", "OrganizationInvitationQueryResult", "OrganizationInvitationCreateResult", "OrganizationInvitationAcceptResult"} + +func (ec *executionContext) _OrganizationNotFound(ctx context.Context, sel ast.SelectionSet, obj *model.OrganizationNotFound) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, organizationNotFoundImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("OrganizationNotFound") + case "id": + out.Values[i] = ec._OrganizationNotFound_id(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "slug": + out.Values[i] = ec._OrganizationNotFound_slug(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var organizationRenameFailureImplementors = []string{"OrganizationRenameFailure", "OrganizationRenameResult"} + +func (ec *executionContext) _OrganizationRenameFailure(ctx context.Context, sel ast.SelectionSet, obj *model.OrganizationRenameFailure) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, organizationRenameFailureImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("OrganizationRenameFailure") + case "result": + out.Values[i] = ec._OrganizationRenameFailure_result(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var publicToolImplementors = []string{"PublicTool"} + +func (ec *executionContext) _PublicTool(ctx context.Context, sel ast.SelectionSet, obj *model.PublicTool) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, publicToolImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("PublicTool") + case "developer": + out.Values[i] = ec._PublicTool_developer(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "name": + out.Values[i] = ec._PublicTool_name(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "description": + out.Values[i] = ec._PublicTool_description(ctx, field, obj) + case "pictureUrl": + out.Values[i] = ec._PublicTool_pictureUrl(ctx, field, obj) + case "publicUrl": + out.Values[i] = ec._PublicTool_publicUrl(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var queryImplementors = []string{"Query"} + +func (ec *executionContext) _Query(ctx context.Context, sel ast.SelectionSet) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, queryImplementors) + ctx = graphql.WithFieldContext(ctx, &graphql.FieldContext{ + Object: "Query", + }) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + innerCtx := graphql.WithRootFieldContext(ctx, &graphql.RootFieldContext{ + Object: field.Name, + Field: field, + }) + + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("Query") + case "me": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_me(ctx, field) + if res == graphql.Null { + atomic.AddUint32(&fs.Invalids, 1) + } + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, + func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) + case "organization": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_organization(ctx, field) + if res == graphql.Null { + atomic.AddUint32(&fs.Invalids, 1) + } + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, + func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) + case "organizationInvitation": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_organizationInvitation(ctx, field) + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, + func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) + case "publicTools": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_publicTools(ctx, field) + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, + func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) + case "tool": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_tool(ctx, field) + if res == graphql.Null { + atomic.AddUint32(&fs.Invalids, 1) + } + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, + func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) + case "tools": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_tools(ctx, field) + if res == graphql.Null { + atomic.AddUint32(&fs.Invalids, 1) + } + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, + func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) + case "job": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_job(ctx, field) + if res == graphql.Null { + atomic.AddUint32(&fs.Invalids, 1) + } + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, + func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) + case "jobsByTool": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_jobsByTool(ctx, field) + if res == graphql.Null { + atomic.AddUint32(&fs.Invalids, 1) + } + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, + func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) + case "jobs": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_jobs(ctx, field) + if res == graphql.Null { + atomic.AddUint32(&fs.Invalids, 1) + } + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, + func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) + case "toolSession": + field := field + + innerFunc := func(ctx context.Context, fs *graphql.FieldSet) (res graphql.Marshaler) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + } + }() + res = ec._Query_toolSession(ctx, field) + if res == graphql.Null { + atomic.AddUint32(&fs.Invalids, 1) + } + return res + } + + rrm := func(ctx context.Context) graphql.Marshaler { + return ec.OperationContext.RootResolverMiddleware(ctx, + func(ctx context.Context) graphql.Marshaler { return innerFunc(ctx, out) }) + } + + out.Concurrently(i, func(ctx context.Context) graphql.Marshaler { return rrm(innerCtx) }) + case "__type": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Query___type(ctx, field) + }) + case "__schema": + out.Values[i] = ec.OperationContext.RootResolverMiddleware(innerCtx, func(ctx context.Context) (res graphql.Marshaler) { + return ec._Query___schema(ctx, field) + }) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var sliderElementImplementors = []string{"SliderElement", "Element"} + +func (ec *executionContext) _SliderElement(ctx context.Context, sel ast.SelectionSet, obj *model.SliderElement) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, sliderElementImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("SliderElement") + case "id": + out.Values[i] = ec._SliderElement_id(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "name": + out.Values[i] = ec._SliderElement_name(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "label": + out.Values[i] = ec._SliderElement_label(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "graphContext": + out.Values[i] = ec._SliderElement_graphContext(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "value": + out.Values[i] = ec._SliderElement_value(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "minValue": + out.Values[i] = ec._SliderElement_minValue(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "maxValue": + out.Values[i] = ec._SliderElement_maxValue(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var stopJobPayloadImplementors = []string{"StopJobPayload"} + +func (ec *executionContext) _StopJobPayload(ctx context.Context, sel ast.SelectionSet, obj *model.StopJobPayload) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, stopJobPayloadImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("StopJobPayload") + case "message": + out.Values[i] = ec._StopJobPayload_message(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var subscriptionImplementors = []string{"Subscription"} + +func (ec *executionContext) _Subscription(ctx context.Context, sel ast.SelectionSet) func(ctx context.Context) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, subscriptionImplementors) + ctx = graphql.WithFieldContext(ctx, &graphql.FieldContext{ + Object: "Subscription", + }) + if len(fields) != 1 { + ec.Errorf(ctx, "must subscribe to exactly one stream") + return nil + } + + switch fields[0].Name { + case "toolSessionEvent": + return ec._Subscription_toolSessionEvent(ctx, fields[0]) + case "buildEvents": + return ec._Subscription_buildEvents(ctx, fields[0]) + case "deployEvents": + return ec._Subscription_deployEvents(ctx, fields[0]) + case "logs": + return ec._Subscription_logs(ctx, fields[0]) + default: + panic("unknown field " + strconv.Quote(fields[0].Name)) + } +} + +var textFieldImplementors = []string{"TextField", "Element"} + +func (ec *executionContext) _TextField(ctx context.Context, sel ast.SelectionSet, obj *model.TextField) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, textFieldImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("TextField") + case "id": + out.Values[i] = ec._TextField_id(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "name": + out.Values[i] = ec._TextField_name(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "label": + out.Values[i] = ec._TextField_label(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "graphContext": + out.Values[i] = ec._TextField_graphContext(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "value": + out.Values[i] = ec._TextField_value(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var toolImplementors = []string{"Tool"} + +func (ec *executionContext) _Tool(ctx context.Context, sel ast.SelectionSet, obj *model.Tool) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, toolImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("Tool") + case "id": + out.Values[i] = ec._Tool_id(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "name": + out.Values[i] = ec._Tool_name(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "description": + out.Values[i] = ec._Tool_description(ctx, field, obj) + case "user": + out.Values[i] = ec._Tool_user(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "publicUrl": + out.Values[i] = ec._Tool_publicUrl(ctx, field, obj) + case "sharedUrl": + out.Values[i] = ec._Tool_sharedUrl(ctx, field, obj) + case "createdAt": + out.Values[i] = ec._Tool_createdAt(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var toolDeleteFailureImplementors = []string{"ToolDeleteFailure", "ToolDeleteResult"} + +func (ec *executionContext) _ToolDeleteFailure(ctx context.Context, sel ast.SelectionSet, obj *model.ToolDeleteFailure) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, toolDeleteFailureImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("ToolDeleteFailure") + case "result": + out.Values[i] = ec._ToolDeleteFailure_result(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var toolDeleteSuccessImplementors = []string{"ToolDeleteSuccess", "ToolDeleteResult"} + +func (ec *executionContext) _ToolDeleteSuccess(ctx context.Context, sel ast.SelectionSet, obj *model.ToolDeleteSuccess) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, toolDeleteSuccessImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("ToolDeleteSuccess") + case "result": + out.Values[i] = ec._ToolDeleteSuccess_result(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var toolSessionImplementors = []string{"ToolSession"} + +func (ec *executionContext) _ToolSession(ctx context.Context, sel ast.SelectionSet, obj *model.ToolSession) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, toolSessionImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("ToolSession") + case "id": + out.Values[i] = ec._ToolSession_id(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "name": + out.Values[i] = ec._ToolSession_name(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "allElements": + out.Values[i] = ec._ToolSession_allElements(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "isActive": + out.Values[i] = ec._ToolSession_isActive(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "clientID": + out.Values[i] = ec._ToolSession_clientID(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "title": + out.Values[i] = ec._ToolSession_title(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var toolSessionActionTriggeredImplementors = []string{"ToolSessionActionTriggered", "ToolSessionEvent"} + +func (ec *executionContext) _ToolSessionActionTriggered(ctx context.Context, sel ast.SelectionSet, obj *model.ToolSessionActionTriggered) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, toolSessionActionTriggeredImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("ToolSessionActionTriggered") + case "element": + out.Values[i] = ec._ToolSessionActionTriggered_element(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var toolSessionElementAddedImplementors = []string{"ToolSessionElementAdded", "ToolSessionEvent"} + +func (ec *executionContext) _ToolSessionElementAdded(ctx context.Context, sel ast.SelectionSet, obj *model.ToolSessionElementAdded) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, toolSessionElementAddedImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("ToolSessionElementAdded") + case "element": + out.Values[i] = ec._ToolSessionElementAdded_element(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var toolSessionElementRemovedImplementors = []string{"ToolSessionElementRemoved", "ToolSessionEvent"} + +func (ec *executionContext) _ToolSessionElementRemoved(ctx context.Context, sel ast.SelectionSet, obj *model.ToolSessionElementRemoved) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, toolSessionElementRemovedImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("ToolSessionElementRemoved") + case "element": + out.Values[i] = ec._ToolSessionElementRemoved_element(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var toolSessionElementUpdatedImplementors = []string{"ToolSessionElementUpdated", "ToolSessionEvent"} + +func (ec *executionContext) _ToolSessionElementUpdated(ctx context.Context, sel ast.SelectionSet, obj *model.ToolSessionElementUpdated) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, toolSessionElementUpdatedImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("ToolSessionElementUpdated") + case "element": + out.Values[i] = ec._ToolSessionElementUpdated_element(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var userImplementors = []string{"User"} + +func (ec *executionContext) _User(ctx context.Context, sel ast.SelectionSet, obj *model.User) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, userImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("User") + case "fullName": + out.Values[i] = ec._User_fullName(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "memberships": + out.Values[i] = ec._User_memberships(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var __DirectiveImplementors = []string{"__Directive"} + +func (ec *executionContext) ___Directive(ctx context.Context, sel ast.SelectionSet, obj *introspection.Directive) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, __DirectiveImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("__Directive") + case "name": + out.Values[i] = ec.___Directive_name(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "description": + out.Values[i] = ec.___Directive_description(ctx, field, obj) + case "locations": + out.Values[i] = ec.___Directive_locations(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "args": + out.Values[i] = ec.___Directive_args(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "isRepeatable": + out.Values[i] = ec.___Directive_isRepeatable(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var __EnumValueImplementors = []string{"__EnumValue"} + +func (ec *executionContext) ___EnumValue(ctx context.Context, sel ast.SelectionSet, obj *introspection.EnumValue) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, __EnumValueImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("__EnumValue") + case "name": + out.Values[i] = ec.___EnumValue_name(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "description": + out.Values[i] = ec.___EnumValue_description(ctx, field, obj) + case "isDeprecated": + out.Values[i] = ec.___EnumValue_isDeprecated(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "deprecationReason": + out.Values[i] = ec.___EnumValue_deprecationReason(ctx, field, obj) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var __FieldImplementors = []string{"__Field"} + +func (ec *executionContext) ___Field(ctx context.Context, sel ast.SelectionSet, obj *introspection.Field) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, __FieldImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("__Field") + case "name": + out.Values[i] = ec.___Field_name(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "description": + out.Values[i] = ec.___Field_description(ctx, field, obj) + case "args": + out.Values[i] = ec.___Field_args(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "type": + out.Values[i] = ec.___Field_type(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "isDeprecated": + out.Values[i] = ec.___Field_isDeprecated(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "deprecationReason": + out.Values[i] = ec.___Field_deprecationReason(ctx, field, obj) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var __InputValueImplementors = []string{"__InputValue"} + +func (ec *executionContext) ___InputValue(ctx context.Context, sel ast.SelectionSet, obj *introspection.InputValue) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, __InputValueImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("__InputValue") + case "name": + out.Values[i] = ec.___InputValue_name(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "description": + out.Values[i] = ec.___InputValue_description(ctx, field, obj) + case "type": + out.Values[i] = ec.___InputValue_type(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "defaultValue": + out.Values[i] = ec.___InputValue_defaultValue(ctx, field, obj) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var __SchemaImplementors = []string{"__Schema"} + +func (ec *executionContext) ___Schema(ctx context.Context, sel ast.SelectionSet, obj *introspection.Schema) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, __SchemaImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("__Schema") + case "description": + out.Values[i] = ec.___Schema_description(ctx, field, obj) + case "types": + out.Values[i] = ec.___Schema_types(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "queryType": + out.Values[i] = ec.___Schema_queryType(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "mutationType": + out.Values[i] = ec.___Schema_mutationType(ctx, field, obj) + case "subscriptionType": + out.Values[i] = ec.___Schema_subscriptionType(ctx, field, obj) + case "directives": + out.Values[i] = ec.___Schema_directives(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var __TypeImplementors = []string{"__Type"} + +func (ec *executionContext) ___Type(ctx context.Context, sel ast.SelectionSet, obj *introspection.Type) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, __TypeImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("__Type") + case "kind": + out.Values[i] = ec.___Type_kind(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + case "name": + out.Values[i] = ec.___Type_name(ctx, field, obj) + case "description": + out.Values[i] = ec.___Type_description(ctx, field, obj) + case "fields": + out.Values[i] = ec.___Type_fields(ctx, field, obj) + case "interfaces": + out.Values[i] = ec.___Type_interfaces(ctx, field, obj) + case "possibleTypes": + out.Values[i] = ec.___Type_possibleTypes(ctx, field, obj) + case "enumValues": + out.Values[i] = ec.___Type_enumValues(ctx, field, obj) + case "inputFields": + out.Values[i] = ec.___Type_inputFields(ctx, field, obj) + case "ofType": + out.Values[i] = ec.___Type_ofType(ctx, field, obj) + case "specifiedByURL": + out.Values[i] = ec.___Type_specifiedByURL(ctx, field, obj) + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +var buildConfigurationImplementors = []string{"buildConfiguration"} + +func (ec *executionContext) _buildConfiguration(ctx context.Context, sel ast.SelectionSet, obj *model.BuildConfiguration) graphql.Marshaler { + fields := graphql.CollectFields(ec.OperationContext, sel, buildConfigurationImplementors) + + out := graphql.NewFieldSet(fields) + deferred := make(map[string]*graphql.FieldSet) + for i, field := range fields { + switch field.Name { + case "__typename": + out.Values[i] = graphql.MarshalString("buildConfiguration") + case "buildId": + out.Values[i] = ec._buildConfiguration_buildId(ctx, field, obj) + if out.Values[i] == graphql.Null { + out.Invalids++ + } + default: + panic("unknown field " + strconv.Quote(field.Name)) + } + } + out.Dispatch(ctx) + if out.Invalids > 0 { + return graphql.Null + } + + atomic.AddInt32(&ec.deferred, int32(len(deferred))) + + for label, dfs := range deferred { + ec.processDeferredGroup(graphql.DeferredGroup{ + Label: label, + Path: graphql.GetPath(ctx), + FieldSet: dfs, + Context: ctx, + }) + } + + return out +} + +// endregion **************************** object.gotpl **************************** + +// region ***************************** type.gotpl ***************************** + +func (ec *executionContext) marshalNApp2ᚕᚖnumerousᚋcliᚋgraphqlᚋmodelᚐAppᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.App) graphql.Marshaler { + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNApp2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐApp(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalNApp2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐApp(ctx context.Context, sel ast.SelectionSet, v *model.App) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._App(ctx, sel, v) +} + +func (ec *executionContext) marshalNAppDeploy2numerousᚋcliᚋgraphqlᚋmodelᚐAppDeploy(ctx context.Context, sel ast.SelectionSet, v model.AppDeploy) graphql.Marshaler { + return ec._AppDeploy(ctx, sel, &v) +} + +func (ec *executionContext) marshalNAppDeploy2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐAppDeploy(ctx context.Context, sel ast.SelectionSet, v *model.AppDeploy) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._AppDeploy(ctx, sel, v) +} + +func (ec *executionContext) unmarshalNAuthRole2numerousᚋcliᚋgraphqlᚋmodelᚐAuthRole(ctx context.Context, v interface{}) (model.AuthRole, error) { + var res model.AuthRole + err := res.UnmarshalGQL(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNAuthRole2numerousᚋcliᚋgraphqlᚋmodelᚐAuthRole(ctx context.Context, sel ast.SelectionSet, v model.AuthRole) graphql.Marshaler { + return v +} + +func (ec *executionContext) unmarshalNBoolean2bool(ctx context.Context, v interface{}) (bool, error) { + res, err := graphql.UnmarshalBoolean(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNBoolean2bool(ctx context.Context, sel ast.SelectionSet, v bool) graphql.Marshaler { + res := graphql.MarshalBoolean(v) + if res == graphql.Null { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + } + return res +} + +func (ec *executionContext) marshalNBuildEvent2numerousᚋcliᚋgraphqlᚋmodelᚐBuildEvent(ctx context.Context, sel ast.SelectionSet, v model.BuildEvent) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._BuildEvent(ctx, sel, v) +} + +func (ec *executionContext) marshalNButton2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐButton(ctx context.Context, sel ast.SelectionSet, v *model.Button) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._Button(ctx, sel, v) +} + +func (ec *executionContext) marshalNElement2numerousᚋcliᚋgraphqlᚋmodelᚐElement(ctx context.Context, sel ast.SelectionSet, v model.Element) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._Element(ctx, sel, v) +} + +func (ec *executionContext) marshalNElement2ᚕnumerousᚋcliᚋgraphqlᚋmodelᚐElement(ctx context.Context, sel ast.SelectionSet, v []model.Element) graphql.Marshaler { + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalOElement2numerousᚋcliᚋgraphqlᚋmodelᚐElement(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + return ret +} + +func (ec *executionContext) marshalNElement2ᚕnumerousᚋcliᚋgraphqlᚋmodelᚐElementᚄ(ctx context.Context, sel ast.SelectionSet, v []model.Element) graphql.Marshaler { + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNElement2numerousᚋcliᚋgraphqlᚋmodelᚐElement(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalNElementGraphContext2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐElementGraphContext(ctx context.Context, sel ast.SelectionSet, v *model.ElementGraphContext) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._ElementGraphContext(ctx, sel, v) +} + +func (ec *executionContext) unmarshalNElementInput2numerousᚋcliᚋgraphqlᚋmodelᚐElementInput(ctx context.Context, v interface{}) (model.ElementInput, error) { + res, err := ec.unmarshalInputElementInput(ctx, v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) unmarshalNElementSelectInput2numerousᚋcliᚋgraphqlᚋmodelᚐElementSelectInput(ctx context.Context, v interface{}) (model.ElementSelectInput, error) { + res, err := ec.unmarshalInputElementSelectInput(ctx, v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) unmarshalNFloat2float64(ctx context.Context, v interface{}) (float64, error) { + res, err := graphql.UnmarshalFloatContext(ctx, v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNFloat2float64(ctx context.Context, sel ast.SelectionSet, v float64) graphql.Marshaler { + res := graphql.MarshalFloatContext(v) + if res == graphql.Null { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + } + return graphql.WrapContextMarshaler(ctx, res) +} + +func (ec *executionContext) unmarshalNID2string(ctx context.Context, v interface{}) (string, error) { + res, err := graphql.UnmarshalID(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNID2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { + res := graphql.MarshalID(v) + if res == graphql.Null { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + } + return res +} + +func (ec *executionContext) marshalNJob2numerousᚋcliᚋgraphqlᚋmodelᚐJob(ctx context.Context, sel ast.SelectionSet, v model.Job) graphql.Marshaler { + return ec._Job(ctx, sel, &v) +} + +func (ec *executionContext) marshalNJob2ᚕᚖnumerousᚋcliᚋgraphqlᚋmodelᚐJobᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.Job) graphql.Marshaler { + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNJob2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐJob(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalNJob2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐJob(ctx context.Context, sel ast.SelectionSet, v *model.Job) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._Job(ctx, sel, v) +} + +func (ec *executionContext) marshalNLogMessage2numerousᚋcliᚋgraphqlᚋmodelᚐLogMessage(ctx context.Context, sel ast.SelectionSet, v model.LogMessage) graphql.Marshaler { + return ec._LogMessage(ctx, sel, &v) +} + +func (ec *executionContext) marshalNLogMessage2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐLogMessage(ctx context.Context, sel ast.SelectionSet, v *model.LogMessage) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._LogMessage(ctx, sel, v) +} + +func (ec *executionContext) unmarshalNNewOrganization2numerousᚋcliᚋgraphqlᚋmodelᚐNewOrganization(ctx context.Context, v interface{}) (model.NewOrganization, error) { + res, err := ec.unmarshalInputNewOrganization(ctx, v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) unmarshalNNewTool2numerousᚋcliᚋgraphqlᚋmodelᚐNewTool(ctx context.Context, v interface{}) (model.NewTool, error) { + res, err := ec.unmarshalInputNewTool(ctx, v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNOrganization2numerousᚋcliᚋgraphqlᚋmodelᚐOrganization(ctx context.Context, sel ast.SelectionSet, v model.Organization) graphql.Marshaler { + return ec._Organization(ctx, sel, &v) +} + +func (ec *executionContext) marshalNOrganization2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐOrganization(ctx context.Context, sel ast.SelectionSet, v *model.Organization) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._Organization(ctx, sel, v) +} + +func (ec *executionContext) marshalNOrganizationInvitationCreateResult2numerousᚋcliᚋgraphqlᚋmodelᚐOrganizationInvitationCreateResult(ctx context.Context, sel ast.SelectionSet, v model.OrganizationInvitationCreateResult) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._OrganizationInvitationCreateResult(ctx, sel, v) +} + +func (ec *executionContext) marshalNOrganizationMembership2ᚕᚖnumerousᚋcliᚋgraphqlᚋmodelᚐOrganizationMembershipᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.OrganizationMembership) graphql.Marshaler { + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNOrganizationMembership2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐOrganizationMembership(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalNOrganizationMembership2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐOrganizationMembership(ctx context.Context, sel ast.SelectionSet, v *model.OrganizationMembership) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._OrganizationMembership(ctx, sel, v) +} + +func (ec *executionContext) marshalNOrganizationQueryResult2numerousᚋcliᚋgraphqlᚋmodelᚐOrganizationQueryResult(ctx context.Context, sel ast.SelectionSet, v model.OrganizationQueryResult) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._OrganizationQueryResult(ctx, sel, v) +} + +func (ec *executionContext) marshalNOrganizationRenameResult2numerousᚋcliᚋgraphqlᚋmodelᚐOrganizationRenameResult(ctx context.Context, sel ast.SelectionSet, v model.OrganizationRenameResult) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._OrganizationRenameResult(ctx, sel, v) +} + +func (ec *executionContext) marshalNPublicTool2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐPublicTool(ctx context.Context, sel ast.SelectionSet, v *model.PublicTool) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._PublicTool(ctx, sel, v) +} + +func (ec *executionContext) unmarshalNRole2numerousᚋcliᚋgraphqlᚋmodelᚐRole(ctx context.Context, v interface{}) (model.Role, error) { + var res model.Role + err := res.UnmarshalGQL(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNRole2numerousᚋcliᚋgraphqlᚋmodelᚐRole(ctx context.Context, sel ast.SelectionSet, v model.Role) graphql.Marshaler { + return v +} + +func (ec *executionContext) marshalNStopJobPayload2numerousᚋcliᚋgraphqlᚋmodelᚐStopJobPayload(ctx context.Context, sel ast.SelectionSet, v model.StopJobPayload) graphql.Marshaler { + return ec._StopJobPayload(ctx, sel, &v) +} + +func (ec *executionContext) marshalNStopJobPayload2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐStopJobPayload(ctx context.Context, sel ast.SelectionSet, v *model.StopJobPayload) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._StopJobPayload(ctx, sel, v) +} + +func (ec *executionContext) unmarshalNString2string(ctx context.Context, v interface{}) (string, error) { + res, err := graphql.UnmarshalString(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNString2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { + res := graphql.MarshalString(v) + if res == graphql.Null { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + } + return res +} + +func (ec *executionContext) unmarshalNTime2timeᚐTime(ctx context.Context, v interface{}) (time.Time, error) { + res, err := graphql.UnmarshalTime(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNTime2timeᚐTime(ctx context.Context, sel ast.SelectionSet, v time.Time) graphql.Marshaler { + res := graphql.MarshalTime(v) + if res == graphql.Null { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + } + return res +} + +func (ec *executionContext) marshalNTool2numerousᚋcliᚋgraphqlᚋmodelᚐTool(ctx context.Context, sel ast.SelectionSet, v model.Tool) graphql.Marshaler { + return ec._Tool(ctx, sel, &v) +} + +func (ec *executionContext) marshalNTool2ᚕᚖnumerousᚋcliᚋgraphqlᚋmodelᚐToolᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.Tool) graphql.Marshaler { + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNTool2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐTool(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalNTool2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐTool(ctx context.Context, sel ast.SelectionSet, v *model.Tool) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._Tool(ctx, sel, v) +} + +func (ec *executionContext) marshalNToolDeleteResult2numerousᚋcliᚋgraphqlᚋmodelᚐToolDeleteResult(ctx context.Context, sel ast.SelectionSet, v model.ToolDeleteResult) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._ToolDeleteResult(ctx, sel, v) +} + +func (ec *executionContext) unmarshalNToolHashType2numerousᚋcliᚋgraphqlᚋmodelᚐToolHashType(ctx context.Context, v interface{}) (model.ToolHashType, error) { + var res model.ToolHashType + err := res.UnmarshalGQL(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNToolHashType2numerousᚋcliᚋgraphqlᚋmodelᚐToolHashType(ctx context.Context, sel ast.SelectionSet, v model.ToolHashType) graphql.Marshaler { + return v +} + +func (ec *executionContext) marshalNToolSession2numerousᚋcliᚋgraphqlᚋmodelᚐToolSession(ctx context.Context, sel ast.SelectionSet, v model.ToolSession) graphql.Marshaler { + return ec._ToolSession(ctx, sel, &v) +} + +func (ec *executionContext) marshalNToolSession2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐToolSession(ctx context.Context, sel ast.SelectionSet, v *model.ToolSession) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._ToolSession(ctx, sel, v) +} + +func (ec *executionContext) marshalNToolSessionEvent2numerousᚋcliᚋgraphqlᚋmodelᚐToolSessionEvent(ctx context.Context, sel ast.SelectionSet, v model.ToolSessionEvent) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._ToolSessionEvent(ctx, sel, v) +} + +func (ec *executionContext) unmarshalNUpload2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚐUpload(ctx context.Context, v interface{}) (graphql.Upload, error) { + res, err := graphql.UnmarshalUpload(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalNUpload2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚐUpload(ctx context.Context, sel ast.SelectionSet, v graphql.Upload) graphql.Marshaler { + res := graphql.MarshalUpload(v) + if res == graphql.Null { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + } + return res +} + +func (ec *executionContext) marshalNUser2numerousᚋcliᚋgraphqlᚋmodelᚐUser(ctx context.Context, sel ast.SelectionSet, v model.User) graphql.Marshaler { + return ec._User(ctx, sel, &v) +} + +func (ec *executionContext) marshalNUser2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐUser(ctx context.Context, sel ast.SelectionSet, v *model.User) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._User(ctx, sel, v) +} + +func (ec *executionContext) marshalN__Directive2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirective(ctx context.Context, sel ast.SelectionSet, v introspection.Directive) graphql.Marshaler { + return ec.___Directive(ctx, sel, &v) +} + +func (ec *executionContext) marshalN__Directive2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirectiveᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.Directive) graphql.Marshaler { + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalN__Directive2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐDirective(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) unmarshalN__DirectiveLocation2string(ctx context.Context, v interface{}) (string, error) { + res, err := graphql.UnmarshalString(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalN__DirectiveLocation2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { + res := graphql.MarshalString(v) + if res == graphql.Null { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + } + return res +} + +func (ec *executionContext) unmarshalN__DirectiveLocation2ᚕstringᚄ(ctx context.Context, v interface{}) ([]string, error) { + var vSlice []interface{} + if v != nil { + vSlice = graphql.CoerceList(v) + } + var err error + res := make([]string, len(vSlice)) + for i := range vSlice { + ctx := graphql.WithPathContext(ctx, graphql.NewPathWithIndex(i)) + res[i], err = ec.unmarshalN__DirectiveLocation2string(ctx, vSlice[i]) + if err != nil { + return nil, err + } + } + return res, nil +} + +func (ec *executionContext) marshalN__DirectiveLocation2ᚕstringᚄ(ctx context.Context, sel ast.SelectionSet, v []string) graphql.Marshaler { + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalN__DirectiveLocation2string(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalN__EnumValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValue(ctx context.Context, sel ast.SelectionSet, v introspection.EnumValue) graphql.Marshaler { + return ec.___EnumValue(ctx, sel, &v) +} + +func (ec *executionContext) marshalN__Field2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐField(ctx context.Context, sel ast.SelectionSet, v introspection.Field) graphql.Marshaler { + return ec.___Field(ctx, sel, &v) +} + +func (ec *executionContext) marshalN__InputValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValue(ctx context.Context, sel ast.SelectionSet, v introspection.InputValue) graphql.Marshaler { + return ec.___InputValue(ctx, sel, &v) +} + +func (ec *executionContext) marshalN__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.InputValue) graphql.Marshaler { + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalN__InputValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValue(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalN__Type2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx context.Context, sel ast.SelectionSet, v introspection.Type) graphql.Marshaler { + return ec.___Type(ctx, sel, &v) +} + +func (ec *executionContext) marshalN__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.Type) graphql.Marshaler { + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalN__Type2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalN__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx context.Context, sel ast.SelectionSet, v *introspection.Type) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec.___Type(ctx, sel, v) +} + +func (ec *executionContext) unmarshalN__TypeKind2string(ctx context.Context, v interface{}) (string, error) { + res, err := graphql.UnmarshalString(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalN__TypeKind2string(ctx context.Context, sel ast.SelectionSet, v string) graphql.Marshaler { + res := graphql.MarshalString(v) + if res == graphql.Null { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + } + return res +} + +func (ec *executionContext) marshalNbuildConfiguration2numerousᚋcliᚋgraphqlᚋmodelᚐBuildConfiguration(ctx context.Context, sel ast.SelectionSet, v model.BuildConfiguration) graphql.Marshaler { + return ec._buildConfiguration(ctx, sel, &v) +} + +func (ec *executionContext) marshalNbuildConfiguration2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐBuildConfiguration(ctx context.Context, sel ast.SelectionSet, v *model.BuildConfiguration) graphql.Marshaler { + if v == nil { + if !graphql.HasFieldError(ctx, graphql.GetFieldContext(ctx)) { + ec.Errorf(ctx, "the requested element is null which the schema does not allow") + } + return graphql.Null + } + return ec._buildConfiguration(ctx, sel, v) +} + +func (ec *executionContext) unmarshalOBoolean2bool(ctx context.Context, v interface{}) (bool, error) { + res, err := graphql.UnmarshalBoolean(v) + return res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalOBoolean2bool(ctx context.Context, sel ast.SelectionSet, v bool) graphql.Marshaler { + res := graphql.MarshalBoolean(v) + return res +} + +func (ec *executionContext) unmarshalOBoolean2ᚖbool(ctx context.Context, v interface{}) (*bool, error) { + if v == nil { + return nil, nil + } + res, err := graphql.UnmarshalBoolean(v) + return &res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalOBoolean2ᚖbool(ctx context.Context, sel ast.SelectionSet, v *bool) graphql.Marshaler { + if v == nil { + return graphql.Null + } + res := graphql.MarshalBoolean(*v) + return res +} + +func (ec *executionContext) marshalOElement2numerousᚋcliᚋgraphqlᚋmodelᚐElement(ctx context.Context, sel ast.SelectionSet, v model.Element) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._Element(ctx, sel, v) +} + +func (ec *executionContext) marshalOElementGraphParent2numerousᚋcliᚋgraphqlᚋmodelᚐElementGraphParent(ctx context.Context, sel ast.SelectionSet, v model.ElementGraphParent) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._ElementGraphParent(ctx, sel, v) +} + +func (ec *executionContext) unmarshalOFloat2ᚖfloat64(ctx context.Context, v interface{}) (*float64, error) { + if v == nil { + return nil, nil + } + res, err := graphql.UnmarshalFloatContext(ctx, v) + return &res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalOFloat2ᚖfloat64(ctx context.Context, sel ast.SelectionSet, v *float64) graphql.Marshaler { + if v == nil { + return graphql.Null + } + res := graphql.MarshalFloatContext(*v) + return graphql.WrapContextMarshaler(ctx, res) +} + +func (ec *executionContext) unmarshalOID2ᚖstring(ctx context.Context, v interface{}) (*string, error) { + if v == nil { + return nil, nil + } + res, err := graphql.UnmarshalID(v) + return &res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalOID2ᚖstring(ctx context.Context, sel ast.SelectionSet, v *string) graphql.Marshaler { + if v == nil { + return graphql.Null + } + res := graphql.MarshalID(*v) + return res +} + +func (ec *executionContext) unmarshalOListElementInput2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐListElementInput(ctx context.Context, v interface{}) (*model.ListElementInput, error) { + if v == nil { + return nil, nil + } + res, err := ec.unmarshalInputListElementInput(ctx, v) + return &res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalOOrganizationInvitationAcceptResult2numerousᚋcliᚋgraphqlᚋmodelᚐOrganizationInvitationAcceptResult(ctx context.Context, sel ast.SelectionSet, v model.OrganizationInvitationAcceptResult) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._OrganizationInvitationAcceptResult(ctx, sel, v) +} + +func (ec *executionContext) unmarshalOOrganizationInvitationInput2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐOrganizationInvitationInput(ctx context.Context, v interface{}) (*model.OrganizationInvitationInput, error) { + if v == nil { + return nil, nil + } + res, err := ec.unmarshalInputOrganizationInvitationInput(ctx, v) + return &res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalOOrganizationInvitationQueryResult2numerousᚋcliᚋgraphqlᚋmodelᚐOrganizationInvitationQueryResult(ctx context.Context, sel ast.SelectionSet, v model.OrganizationInvitationQueryResult) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec._OrganizationInvitationQueryResult(ctx, sel, v) +} + +func (ec *executionContext) marshalOPublicTool2ᚕᚖnumerousᚋcliᚋgraphqlᚋmodelᚐPublicToolᚄ(ctx context.Context, sel ast.SelectionSet, v []*model.PublicTool) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalNPublicTool2ᚖnumerousᚋcliᚋgraphqlᚋmodelᚐPublicTool(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) unmarshalOString2ᚖstring(ctx context.Context, v interface{}) (*string, error) { + if v == nil { + return nil, nil + } + res, err := graphql.UnmarshalString(v) + return &res, graphql.ErrorOnPath(ctx, err) +} + +func (ec *executionContext) marshalOString2ᚖstring(ctx context.Context, sel ast.SelectionSet, v *string) graphql.Marshaler { + if v == nil { + return graphql.Null + } + res := graphql.MarshalString(*v) + return res +} + +func (ec *executionContext) marshalO__EnumValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValueᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.EnumValue) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalN__EnumValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐEnumValue(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalO__Field2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐFieldᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.Field) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalN__Field2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐField(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalO__InputValue2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValueᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.InputValue) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalN__InputValue2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐInputValue(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalO__Schema2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐSchema(ctx context.Context, sel ast.SelectionSet, v *introspection.Schema) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec.___Schema(ctx, sel, v) +} + +func (ec *executionContext) marshalO__Type2ᚕgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐTypeᚄ(ctx context.Context, sel ast.SelectionSet, v []introspection.Type) graphql.Marshaler { + if v == nil { + return graphql.Null + } + ret := make(graphql.Array, len(v)) + var wg sync.WaitGroup + isLen1 := len(v) == 1 + if !isLen1 { + wg.Add(len(v)) + } + for i := range v { + i := i + fc := &graphql.FieldContext{ + Index: &i, + Result: &v[i], + } + ctx := graphql.WithFieldContext(ctx, fc) + f := func(i int) { + defer func() { + if r := recover(); r != nil { + ec.Error(ctx, ec.Recover(ctx, r)) + ret = nil + } + }() + if !isLen1 { + defer wg.Done() + } + ret[i] = ec.marshalN__Type2githubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx, sel, v[i]) + } + if isLen1 { + f(i) + } else { + go f(i) + } + + } + wg.Wait() + + for _, e := range ret { + if e == graphql.Null { + return graphql.Null + } + } + + return ret +} + +func (ec *executionContext) marshalO__Type2ᚖgithubᚗcomᚋ99designsᚋgqlgenᚋgraphqlᚋintrospectionᚐType(ctx context.Context, sel ast.SelectionSet, v *introspection.Type) graphql.Marshaler { + if v == nil { + return graphql.Null + } + return ec.___Type(ctx, sel, v) +} + +// endregion ***************************** type.gotpl ***************************** diff --git a/cli/graphql/model/models_gen.go b/cli/graphql/model/models_gen.go new file mode 100644 index 00000000..dcff34e3 --- /dev/null +++ b/cli/graphql/model/models_gen.go @@ -0,0 +1,533 @@ +// Code generated by github.com/99designs/gqlgen, DO NOT EDIT. + +package model + +import ( + "fmt" + "io" + "strconv" + "time" +) + +type BuildEvent interface { + IsBuildEvent() +} + +type Element interface { + IsElement() + GetID() string + GetName() string + GetLabel() string + GetGraphContext() *ElementGraphContext +} + +type ElementGraphParent interface { + IsElementGraphParent() + GetID() string +} + +type OrganizationInvitationAcceptResult interface { + IsOrganizationInvitationAcceptResult() +} + +type OrganizationInvitationCreateResult interface { + IsOrganizationInvitationCreateResult() +} + +type OrganizationInvitationQueryResult interface { + IsOrganizationInvitationQueryResult() +} + +type OrganizationQueryResult interface { + IsOrganizationQueryResult() +} + +type OrganizationRenameResult interface { + IsOrganizationRenameResult() +} + +type ToolDeleteResult interface { + IsToolDeleteResult() +} + +type ToolSessionEvent interface { + IsToolSessionEvent() +} + +type App struct { + ID string `json:"id"` + Name string `json:"name"` + Description *string `json:"description,omitempty"` + User *User `json:"user"` + PublicURL *string `json:"publicUrl,omitempty"` + SharedURL *string `json:"sharedUrl,omitempty"` + CreatedAt time.Time `json:"createdAt"` +} + +type AppDeploy struct { + App *App `json:"app"` + BuildID string `json:"buildId"` +} + +type BuildEventFailure struct { + Result string `json:"result"` +} + +func (BuildEventFailure) IsBuildEvent() {} + +type BuildEventInfo struct { + Result string `json:"result"` +} + +func (BuildEventInfo) IsBuildEvent() {} + +type BuildEventSuccess struct { + Result string `json:"result"` +} + +func (BuildEventSuccess) IsBuildEvent() {} + +type Button struct { + ID string `json:"id"` + Name string `json:"name"` + Label string `json:"label"` + GraphContext *ElementGraphContext `json:"graphContext"` + Value string `json:"value"` +} + +func (Button) IsElement() {} +func (this Button) GetID() string { return this.ID } +func (this Button) GetName() string { return this.Name } +func (this Button) GetLabel() string { return this.Label } +func (this Button) GetGraphContext() *ElementGraphContext { return this.GraphContext } + +type Container struct { + ID string `json:"id"` + Name string `json:"name"` + Label string `json:"label"` + GraphContext *ElementGraphContext `json:"graphContext"` +} + +func (Container) IsElement() {} +func (this Container) GetID() string { return this.ID } +func (this Container) GetName() string { return this.Name } +func (this Container) GetLabel() string { return this.Label } +func (this Container) GetGraphContext() *ElementGraphContext { return this.GraphContext } + +func (Container) IsElementGraphParent() {} + +type ElementGraphContext struct { + Parent ElementGraphParent `json:"parent,omitempty"` + AffectedBy []Element `json:"affectedBy"` + Affects []Element `json:"affects"` +} + +type ElementInput struct { + ElementID string `json:"elementID"` + TextValue *string `json:"textValue,omitempty"` + NumberValue *float64 `json:"numberValue,omitempty"` + HTMLValue *string `json:"htmlValue,omitempty"` + SliderValue *float64 `json:"sliderValue,omitempty"` +} + +type ElementList struct { + ID string `json:"id"` + Name string `json:"name"` + Label string `json:"label"` + GraphContext *ElementGraphContext `json:"graphContext"` +} + +func (ElementList) IsElement() {} +func (this ElementList) GetID() string { return this.ID } +func (this ElementList) GetName() string { return this.Name } +func (this ElementList) GetLabel() string { return this.Label } +func (this ElementList) GetGraphContext() *ElementGraphContext { return this.GraphContext } + +func (ElementList) IsElementGraphParent() {} + +type ElementSelect struct { + ID string `json:"id"` + Name string `json:"name"` + Label string `json:"label"` + GraphContext *ElementGraphContext `json:"graphContext"` + SelectedOption Element `json:"selectedOption"` +} + +func (ElementSelect) IsElement() {} +func (this ElementSelect) GetID() string { return this.ID } +func (this ElementSelect) GetName() string { return this.Name } +func (this ElementSelect) GetLabel() string { return this.Label } +func (this ElementSelect) GetGraphContext() *ElementGraphContext { return this.GraphContext } + +func (ElementSelect) IsElementGraphParent() {} + +type ElementSelectInput struct { + SelectElementID string `json:"selectElementID"` + SelectedOptionID string `json:"selectedOptionID"` +} + +type HTMLElement struct { + ID string `json:"id"` + Name string `json:"name"` + Label string `json:"label"` + GraphContext *ElementGraphContext `json:"graphContext"` + HTML string `json:"html"` +} + +func (HTMLElement) IsElement() {} +func (this HTMLElement) GetID() string { return this.ID } +func (this HTMLElement) GetName() string { return this.Name } +func (this HTMLElement) GetLabel() string { return this.Label } +func (this HTMLElement) GetGraphContext() *ElementGraphContext { return this.GraphContext } + +type InvalidEmail struct { + Email string `json:"email"` +} + +func (InvalidEmail) IsOrganizationInvitationCreateResult() {} + +type Job struct { + ID string `json:"id"` + Status *string `json:"status,omitempty"` + ProxyURL *string `json:"proxyUrl,omitempty"` + User *User `json:"user"` + CreatedAt time.Time `json:"createdAt"` +} + +type ListElementInput struct { + ListElementID string `json:"listElementID"` +} + +type LogMessage struct { + Time time.Time `json:"time"` + Message string `json:"message"` +} + +type Mutation struct{} + +type NewOrganization struct { + Name string `json:"name"` +} + +type NewTool struct { + UserID string `json:"userId"` + Manifest string `json:"manifest"` +} + +type NumberField struct { + ID string `json:"id"` + Name string `json:"name"` + Label string `json:"label"` + GraphContext *ElementGraphContext `json:"graphContext"` + Value float64 `json:"value"` +} + +func (NumberField) IsElement() {} +func (this NumberField) GetID() string { return this.ID } +func (this NumberField) GetName() string { return this.Name } +func (this NumberField) GetLabel() string { return this.Label } +func (this NumberField) GetGraphContext() *ElementGraphContext { return this.GraphContext } + +type Organization struct { + ID string `json:"id"` + Name string `json:"name"` + Slug string `json:"slug"` + Apps []*App `json:"apps"` + Members []*OrganizationMembership `json:"members"` +} + +func (Organization) IsOrganizationRenameResult() {} + +func (Organization) IsOrganizationQueryResult() {} + +func (Organization) IsOrganizationInvitationAcceptResult() {} + +type OrganizationInvitation struct { + ID string `json:"id"` + Email string `json:"email"` + OrganizationName string `json:"organizationName"` + InvitedAt time.Time `json:"invitedAt"` + Role Role `json:"role"` +} + +func (OrganizationInvitation) IsOrganizationInvitationQueryResult() {} + +func (OrganizationInvitation) IsOrganizationInvitationCreateResult() {} + +type OrganizationInvitationInput struct { + Role Role `json:"role"` + Email string `json:"email"` +} + +type OrganizationInvitationNotFound struct { + ID string `json:"id"` +} + +func (OrganizationInvitationNotFound) IsOrganizationInvitationQueryResult() {} + +type OrganizationMemberExists struct { + Email string `json:"email"` +} + +func (OrganizationMemberExists) IsOrganizationInvitationCreateResult() {} + +type OrganizationMembership struct { + Organization *Organization `json:"organization"` + Role Role `json:"role"` +} + +type OrganizationNotFound struct { + ID string `json:"id"` + Slug string `json:"slug"` +} + +func (OrganizationNotFound) IsOrganizationRenameResult() {} + +func (OrganizationNotFound) IsOrganizationQueryResult() {} + +func (OrganizationNotFound) IsOrganizationInvitationQueryResult() {} + +func (OrganizationNotFound) IsOrganizationInvitationCreateResult() {} + +func (OrganizationNotFound) IsOrganizationInvitationAcceptResult() {} + +type OrganizationRenameFailure struct { + Result string `json:"result"` +} + +func (OrganizationRenameFailure) IsOrganizationRenameResult() {} + +type PublicTool struct { + Developer *User `json:"developer"` + Name string `json:"name"` + Description *string `json:"description,omitempty"` + PictureURL *string `json:"pictureUrl,omitempty"` + PublicURL string `json:"publicUrl"` +} + +type Query struct{} + +type SliderElement struct { + ID string `json:"id"` + Name string `json:"name"` + Label string `json:"label"` + GraphContext *ElementGraphContext `json:"graphContext"` + Value float64 `json:"value"` + MinValue float64 `json:"minValue"` + MaxValue float64 `json:"maxValue"` +} + +func (SliderElement) IsElement() {} +func (this SliderElement) GetID() string { return this.ID } +func (this SliderElement) GetName() string { return this.Name } +func (this SliderElement) GetLabel() string { return this.Label } +func (this SliderElement) GetGraphContext() *ElementGraphContext { return this.GraphContext } + +type StopJobPayload struct { + Message string `json:"message"` +} + +type Subscription struct{} + +type TextField struct { + ID string `json:"id"` + Name string `json:"name"` + Label string `json:"label"` + GraphContext *ElementGraphContext `json:"graphContext"` + Value string `json:"value"` +} + +func (TextField) IsElement() {} +func (this TextField) GetID() string { return this.ID } +func (this TextField) GetName() string { return this.Name } +func (this TextField) GetLabel() string { return this.Label } +func (this TextField) GetGraphContext() *ElementGraphContext { return this.GraphContext } + +type Tool struct { + ID string `json:"id"` + Name string `json:"name"` + Description *string `json:"description,omitempty"` + User *User `json:"user"` + PublicURL *string `json:"publicUrl,omitempty"` + SharedURL *string `json:"sharedUrl,omitempty"` + CreatedAt time.Time `json:"createdAt"` +} + +type ToolDeleteFailure struct { + Result string `json:"result"` +} + +func (ToolDeleteFailure) IsToolDeleteResult() {} + +type ToolDeleteSuccess struct { + Result string `json:"result"` +} + +func (ToolDeleteSuccess) IsToolDeleteResult() {} + +type ToolSession struct { + ID string `json:"id"` + Name string `json:"name"` + AllElements []Element `json:"allElements"` + IsActive bool `json:"isActive"` + ClientID string `json:"clientID"` + Title string `json:"title"` +} + +type ToolSessionActionTriggered struct { + Element *Button `json:"element"` +} + +func (ToolSessionActionTriggered) IsToolSessionEvent() {} + +type ToolSessionElementAdded struct { + Element Element `json:"element"` +} + +func (ToolSessionElementAdded) IsToolSessionEvent() {} + +type ToolSessionElementRemoved struct { + Element Element `json:"element"` +} + +func (ToolSessionElementRemoved) IsToolSessionEvent() {} + +type ToolSessionElementUpdated struct { + Element Element `json:"element"` +} + +func (ToolSessionElementUpdated) IsToolSessionEvent() {} + +type User struct { + FullName string `json:"fullName"` + Memberships []*OrganizationMembership `json:"memberships"` +} + +type BuildConfiguration struct { + BuildID string `json:"buildId"` +} + +type AuthRole string + +const ( + AuthRoleAuthenticated AuthRole = "AUTHENTICATED" + AuthRoleAdmin AuthRole = "ADMIN" + AuthRoleUser AuthRole = "USER" +) + +var AllAuthRole = []AuthRole{ + AuthRoleAuthenticated, + AuthRoleAdmin, + AuthRoleUser, +} + +func (e AuthRole) IsValid() bool { + switch e { + case AuthRoleAuthenticated, AuthRoleAdmin, AuthRoleUser: + return true + } + return false +} + +func (e AuthRole) String() string { + return string(e) +} + +func (e *AuthRole) UnmarshalGQL(v interface{}) error { + str, ok := v.(string) + if !ok { + return fmt.Errorf("enums must be strings") + } + + *e = AuthRole(str) + if !e.IsValid() { + return fmt.Errorf("%s is not a valid AuthRole", str) + } + return nil +} + +func (e AuthRole) MarshalGQL(w io.Writer) { + fmt.Fprint(w, strconv.Quote(e.String())) +} + +type Role string + +const ( + RoleAdmin Role = "ADMIN" + RoleUser Role = "USER" +) + +var AllRole = []Role{ + RoleAdmin, + RoleUser, +} + +func (e Role) IsValid() bool { + switch e { + case RoleAdmin, RoleUser: + return true + } + return false +} + +func (e Role) String() string { + return string(e) +} + +func (e *Role) UnmarshalGQL(v interface{}) error { + str, ok := v.(string) + if !ok { + return fmt.Errorf("enums must be strings") + } + + *e = Role(str) + if !e.IsValid() { + return fmt.Errorf("%s is not a valid Role", str) + } + return nil +} + +func (e Role) MarshalGQL(w io.Writer) { + fmt.Fprint(w, strconv.Quote(e.String())) +} + +type ToolHashType string + +const ( + ToolHashTypePublic ToolHashType = "public" + ToolHashTypeShared ToolHashType = "shared" +) + +var AllToolHashType = []ToolHashType{ + ToolHashTypePublic, + ToolHashTypeShared, +} + +func (e ToolHashType) IsValid() bool { + switch e { + case ToolHashTypePublic, ToolHashTypeShared: + return true + } + return false +} + +func (e ToolHashType) String() string { + return string(e) +} + +func (e *ToolHashType) UnmarshalGQL(v interface{}) error { + str, ok := v.(string) + if !ok { + return fmt.Errorf("enums must be strings") + } + + *e = ToolHashType(str) + if !e.IsValid() { + return fmt.Errorf("%s is not a valid ToolHashType", str) + } + return nil +} + +func (e ToolHashType) MarshalGQL(w io.Writer) { + fmt.Fprint(w, strconv.Quote(e.String())) +} diff --git a/cli/graphql/resolver.go b/cli/graphql/resolver.go new file mode 100644 index 00000000..a73696a9 --- /dev/null +++ b/cli/graphql/resolver.go @@ -0,0 +1,13 @@ +package graphql + +// This file will not be regenerated automatically. +// +// It serves as dependency injection for your app, add any dependencies you require here. +import ( + "numerous/cli/appdev" +) + +type Resolver struct { + AppSessionsRepo appdev.AppSessionRepository + ToolSessionService appdev.AppSessionService +} diff --git a/cli/graphql/schema.resolvers.go b/cli/graphql/schema.resolvers.go new file mode 100644 index 00000000..087cc9c9 --- /dev/null +++ b/cli/graphql/schema.resolvers.go @@ -0,0 +1,235 @@ +package graphql + +// This file will be automatically regenerated based on the schema, any resolver implementations +// will be copied through when generating and any unknown code will be moved to the end. +// Code generated by github.com/99designs/gqlgen version v0.17.45 + +import ( + "context" + "fmt" + "strconv" + + "numerous/cli/graphql/model" + + "github.com/99designs/gqlgen/graphql" +) + +// OrganizationCreate is the resolver for the organizationCreate field. +func (r *mutationResolver) OrganizationCreate(ctx context.Context, input model.NewOrganization) (*model.Organization, error) { + panic(fmt.Errorf("not implemented: OrganizationCreate - organizationCreate")) +} + +// OrganizationRename is the resolver for the organizationRename field. +func (r *mutationResolver) OrganizationRename(ctx context.Context, organizationID string, name string) (model.OrganizationRenameResult, error) { + panic(fmt.Errorf("not implemented: OrganizationRename - organizationRename")) +} + +// OrganizationInvitationCreate is the resolver for the organizationInvitationCreate field. +func (r *mutationResolver) OrganizationInvitationCreate(ctx context.Context, organizationID string, input *model.OrganizationInvitationInput) (model.OrganizationInvitationCreateResult, error) { + panic(fmt.Errorf("not implemented: OrganizationInvitationCreate - organizationInvitationCreate")) +} + +// OrganizationInvitationAccept is the resolver for the organizationInvitationAccept field. +func (r *mutationResolver) OrganizationInvitationAccept(ctx context.Context, invitationID string) (model.OrganizationInvitationAcceptResult, error) { + panic(fmt.Errorf("not implemented: OrganizationInvitationAccept - organizationInvitationAccept")) +} + +// ToolCreate is the resolver for the toolCreate field. +func (r *mutationResolver) ToolCreate(ctx context.Context, input model.NewTool) (*model.Tool, error) { + panic(fmt.Errorf("not implemented: ToolCreate - toolCreate")) +} + +// ToolPublish is the resolver for the toolPublish field. +func (r *mutationResolver) ToolPublish(ctx context.Context, id string) (*model.Tool, error) { + panic(fmt.Errorf("not implemented: ToolPublish - toolPublish")) +} + +// ToolUnpublish is the resolver for the toolUnpublish field. +func (r *mutationResolver) ToolUnpublish(ctx context.Context, id string) (*model.Tool, error) { + panic(fmt.Errorf("not implemented: ToolUnpublish - toolUnpublish")) +} + +// ToolDelete is the resolver for the toolDelete field. +func (r *mutationResolver) ToolDelete(ctx context.Context, id string) (model.ToolDeleteResult, error) { + panic(fmt.Errorf("not implemented: ToolDelete - toolDelete")) +} + +// OrganizationAppDeploy is the resolver for the organizationAppDeploy field. +func (r *mutationResolver) OrganizationAppDeploy(ctx context.Context, appID string, organizationSlug string, appArchive graphql.Upload) (*model.AppDeploy, error) { + panic(fmt.Errorf("not implemented: OrganizationAppDeploy - organizationAppDeploy")) +} + +// JobStart is the resolver for the jobStart field. +func (r *mutationResolver) JobStart(ctx context.Context, toolHash string, hashType model.ToolHashType) (*model.Job, error) { + panic(fmt.Errorf("not implemented: JobStart - jobStart")) +} + +// JobStop is the resolver for the jobStop field. +func (r *mutationResolver) JobStop(ctx context.Context, id string) (*model.StopJobPayload, error) { + panic(fmt.Errorf("not implemented: JobStop - jobStop")) +} + +// ToolSessionCreate is the resolver for the toolSessionCreate field. +func (r *mutationResolver) ToolSessionCreate(ctx context.Context) (*model.ToolSession, error) { + panic(fmt.Errorf("not implemented: ToolSessionCreate - toolSessionCreate")) +} + +// ElementUpdate is the resolver for the elementUpdate field. +func (r *mutationResolver) ElementUpdate(ctx context.Context, toolSessionID string, clientID string, element model.ElementInput) (model.Element, error) { + if convertedToolSessionID, err := strconv.ParseUint(toolSessionID, 10, 64); err != nil { + return nil, err + } else if result, err := r.ToolSessionService.UpdateElement(uint(convertedToolSessionID), clientID, ElementInputToDomain(element)); err != nil { + return nil, err + } else { + return AppSessionElementFromDomain(result.Session, *result.Element), nil + } +} + +// ElementTrigger is the resolver for the elementTrigger field. +func (r *mutationResolver) ElementTrigger(ctx context.Context, toolSessionID string, clientID string, actionElementID string) (model.Element, error) { + if convertedToolSessionID, err := strconv.ParseUint(toolSessionID, 10, 64); err != nil { + return nil, err + } else if result, err := r.ToolSessionService.TriggerAction(uint(convertedToolSessionID), clientID, actionElementID); err != nil { + return nil, err + } else { + return AppSessionElementFromDomain(result.Session, *result.Element), nil + } +} + +// ElementSelectionUpdate is the resolver for the elementSelectionUpdate field. +func (r *mutationResolver) ElementSelectionUpdate(ctx context.Context, clientID string, elementSelection model.ElementSelectInput) (model.Element, error) { + panic(fmt.Errorf("not implemented: ElementSelectionUpdate - elementSelectionUpdate")) +} + +// ListElementAdd is the resolver for the listElementAdd field. +func (r *mutationResolver) ListElementAdd(ctx context.Context, clientID string, listElement *model.ListElementInput) (model.Element, error) { + panic(fmt.Errorf("not implemented: ListElementAdd - listElementAdd")) +} + +// ListElementRemove is the resolver for the listElementRemove field. +func (r *mutationResolver) ListElementRemove(ctx context.Context, clientID string, listItemID string) (model.Element, error) { + panic(fmt.Errorf("not implemented: ListElementRemove - listElementRemove")) +} + +// BuildPush is the resolver for the buildPush field. +func (r *mutationResolver) BuildPush(ctx context.Context, file graphql.Upload, id string) (*model.BuildConfiguration, error) { + panic(fmt.Errorf("not implemented: BuildPush - buildPush")) +} + +// Me is the resolver for the me field. +func (r *queryResolver) Me(ctx context.Context) (*model.User, error) { + panic(fmt.Errorf("not implemented: Me - me")) +} + +// Organization is the resolver for the organization field. +func (r *queryResolver) Organization(ctx context.Context, organizationSlug *string) (model.OrganizationQueryResult, error) { + panic(fmt.Errorf("not implemented: Organization - organization")) +} + +// OrganizationInvitation is the resolver for the organizationInvitation field. +func (r *queryResolver) OrganizationInvitation(ctx context.Context, invitationID string) (model.OrganizationInvitationQueryResult, error) { + panic(fmt.Errorf("not implemented: OrganizationInvitation - organizationInvitation")) +} + +// PublicTools is the resolver for the publicTools field. +func (r *queryResolver) PublicTools(ctx context.Context) ([]*model.PublicTool, error) { + panic(fmt.Errorf("not implemented: PublicTools - publicTools")) +} + +// Tool is the resolver for the tool field. +func (r *queryResolver) Tool(ctx context.Context, id string) (*model.Tool, error) { + panic(fmt.Errorf("not implemented: Tool - tool")) +} + +// Tools is the resolver for the tools field. +func (r *queryResolver) Tools(ctx context.Context) ([]*model.Tool, error) { + panic(fmt.Errorf("not implemented: Tools - tools")) +} + +// Job is the resolver for the job field. +func (r *queryResolver) Job(ctx context.Context, id string) (*model.Job, error) { + panic(fmt.Errorf("not implemented: Job - job")) +} + +// JobsByTool is the resolver for the jobsByTool field. +func (r *queryResolver) JobsByTool(ctx context.Context, id string) ([]*model.Job, error) { + panic(fmt.Errorf("not implemented: JobsByTool - jobsByTool")) +} + +// Jobs is the resolver for the jobs field. +func (r *queryResolver) Jobs(ctx context.Context) ([]*model.Job, error) { + panic(fmt.Errorf("not implemented: Jobs - jobs")) +} + +// ToolSession is the resolver for the toolSession field. +func (r *queryResolver) ToolSession(ctx context.Context, id string) (*model.ToolSession, error) { + toolSessionId, err := strconv.ParseUint(id, 10, 64) + if err != nil { + return nil, err + } + + toolSession, err := r.AppSessionsRepo.Read(uint(toolSessionId)) + if err != nil { + return nil, err + } + + s := AppSessionFromDomain(*toolSession) + return s, nil +} + +// ToolSessionEvent is the resolver for the toolSessionEvent field. +func (r *subscriptionResolver) ToolSessionEvent(ctx context.Context, toolSessionID string, clientID string) (<-chan model.ToolSessionEvent, error) { + convertedToolSessionId, err := strconv.ParseUint(toolSessionID, 10, 64) + if err != nil { + return nil, err + } + + subscription := make(chan model.ToolSessionEvent) + session, err := r.AppSessionsRepo.Read(uint(convertedToolSessionId)) + if err != nil { + return nil, err + } + + events, err := r.ToolSessionService.Subscribe(ctx, toolSessionID, clientID) + if err != nil { + return nil, err + } + + go func() { + for { + subscription <- AppSessionEventFromDomain(session, <-events) + } + }() + + return subscription, nil +} + +// BuildEvents is the resolver for the buildEvents field. +func (r *subscriptionResolver) BuildEvents(ctx context.Context, buildID string, appPath *string) (<-chan model.BuildEvent, error) { + panic(fmt.Errorf("not implemented: BuildEvents - buildEvents")) +} + +// DeployEvents is the resolver for the deployEvents field. +func (r *subscriptionResolver) DeployEvents(ctx context.Context, toolID string) (<-chan model.BuildEvent, error) { + panic(fmt.Errorf("not implemented: DeployEvents - deployEvents")) +} + +// Logs is the resolver for the logs field. +func (r *subscriptionResolver) Logs(ctx context.Context, appID string) (<-chan *model.LogMessage, error) { + panic(fmt.Errorf("not implemented: Logs - logs")) +} + +// Mutation returns MutationResolver implementation. +func (r *Resolver) Mutation() MutationResolver { return &mutationResolver{r} } + +// Query returns QueryResolver implementation. +func (r *Resolver) Query() QueryResolver { return &queryResolver{r} } + +// Subscription returns SubscriptionResolver implementation. +func (r *Resolver) Subscription() SubscriptionResolver { return &subscriptionResolver{r} } + +type ( + mutationResolver struct{ *Resolver } + queryResolver struct{ *Resolver } + subscriptionResolver struct{ *Resolver } +) diff --git a/cli/internal/gql/api.go b/cli/internal/gql/api.go new file mode 100644 index 00000000..e7cbfb96 --- /dev/null +++ b/cli/internal/gql/api.go @@ -0,0 +1,7 @@ +package gql + +// Variables overridden during build for production +var ( + httpURL string = "http://localhost:8080/query" + wsURL string = "ws://localhost:8080/query" +) diff --git a/cli/internal/gql/app/create.go b/cli/internal/gql/app/create.go new file mode 100644 index 00000000..14d76e70 --- /dev/null +++ b/cli/internal/gql/app/create.go @@ -0,0 +1,49 @@ +package app + +import ( + "context" + + "numerous/cli/manifest" + "numerous/cli/tool" + + "git.sr.ht/~emersion/gqlclient" +) + +type appCreateResponse struct { + ToolCreate App +} + +func Create(a tool.Tool, client *gqlclient.Client) (App, error) { + resp := appCreateResponse{} + jsonManifest, err := manifest.FromTool(a).ToJSON() + if err != nil { + return resp.ToolCreate, err + } + + op := createAppCreateOperation(jsonManifest) + if err := client.Execute(context.TODO(), op, &resp); err != nil { + return resp.ToolCreate, err + } + + return resp.ToolCreate, nil +} + +func createAppCreateOperation(m string) *gqlclient.Operation { + op := gqlclient.NewOperation(` + mutation ToolCreate($userID: ID!, $manifest:String!) { + toolCreate(input:{userId: $userID, manifest: $manifest}) { + id + name + description + createdAt + sharedUrl + publicUrl + } + } + `) + // userID variable hardcoded as we do not have users implemented yet + op.Var("userID", "1") + op.Var("manifest", m) + + return op +} diff --git a/cli/internal/gql/app/create_test.go b/cli/internal/gql/app/create_test.go new file mode 100644 index 00000000..aa72943c --- /dev/null +++ b/cli/internal/gql/app/create_test.go @@ -0,0 +1,49 @@ +package app + +import ( + "testing" + "time" + + "numerous/cli/test" + "numerous/cli/tool" + + "github.com/stretchr/testify/assert" +) + +func TestCreate(t *testing.T) { + testApp := tool.Tool{ + Name: "name", + Library: tool.LibraryMarimo, + Python: "3.11", + AppFile: "app.py", + RequirementsFile: "requirements.txt", + CoverImage: "cover.png", + } + t.Run("can return app on AppCreate mutation", func(t *testing.T) { + expectedApp := App{ + ID: "id", + SharedURL: "https://test.com/shared/some-hash", + PublicURL: "https://test.com/public/another-hash", + Name: "test name", + CreatedAt: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC), + } + response := test.AppToQueryResult("toolCreate", expectedApp) + c := test.CreateTestGqlClient(response) + + actualApp, err := Create(testApp, c) + + assert.NoError(t, err) + assert.Equal(t, expectedApp, actualApp) + }) + + t.Run("can return error on AppCreate mutation", func(t *testing.T) { + appNotFoundResponse := `{"errors":[{"message":"Something went wrong","path":["toolCreate"]}],"data":null}` + c := test.CreateTestGqlClient(appNotFoundResponse) + + actualApp, err := Create(testApp, c) + + assert.Error(t, err) + assert.ErrorContains(t, err, "Something went wrong") + assert.Equal(t, App{}, actualApp) + }) +} diff --git a/cli/internal/gql/app/delete.go b/cli/internal/gql/app/delete.go new file mode 100644 index 00000000..d453782d --- /dev/null +++ b/cli/internal/gql/app/delete.go @@ -0,0 +1,49 @@ +package app + +import ( + "context" + "errors" + + "git.sr.ht/~emersion/gqlclient" +) + +type appDeleteResponse struct { + ToolDelete struct { + Typename string `json:"__typename"` + Result string `json:"result"` + } +} + +func Delete(id string, client *gqlclient.Client) (*appDeleteResponse, error) { + resp := appDeleteResponse{} + op := createAppDeleteOperation(id) + + if err := client.Execute(context.TODO(), op, &resp); err != nil { + return nil, err + } + + if resp.ToolDelete.Typename == "ToolDeleteSuccess" || resp.ToolDelete.Typename == "ToolDeleteFailure" { + return &resp, nil + } + + return nil, errors.New("unexpected response from toolDelete mutation") +} + +func createAppDeleteOperation(id string) *gqlclient.Operation { + op := gqlclient.NewOperation(` + mutation ToolDelete($id: ID!) { + toolDelete(id: $id){ + __typename + ... on ToolDeleteSuccess { + result + } + ... on ToolDeleteFailure { + result + } + } + } + `) + op.Var("id", id) + + return op +} diff --git a/cli/internal/gql/app/delete_test.go b/cli/internal/gql/app/delete_test.go new file mode 100644 index 00000000..83444d49 --- /dev/null +++ b/cli/internal/gql/app/delete_test.go @@ -0,0 +1,30 @@ +package app + +import ( + "testing" + + "numerous/cli/test" + + "github.com/stretchr/testify/assert" +) + +func TestDelete(t *testing.T) { + t.Run("can return status on AppDelete mutation", func(t *testing.T) { + response, expectedType := test.DeleteSuccessQueryResult() + c := test.CreateTestGqlClient(response) + + actualStatus, err := Delete("id", c) + + assert.NoError(t, err) + assert.Equal(t, expectedType, actualStatus.ToolDelete.Typename) + }) + + t.Run("can return error on AppDelete mutation", func(t *testing.T) { + appNotFoundResponse := "record not found" + response, expectedType := test.DeleteFailureQueryResult(appNotFoundResponse) + c := test.CreateTestGqlClient(response) + actualStatus, _ := Delete("id", c) + assert.Equal(t, expectedType, actualStatus.ToolDelete.Typename) + assert.Equal(t, appNotFoundResponse, actualStatus.ToolDelete.Result) + }) +} diff --git a/cli/internal/gql/app/publish.go b/cli/internal/gql/app/publish.go new file mode 100644 index 00000000..18490e37 --- /dev/null +++ b/cli/internal/gql/app/publish.go @@ -0,0 +1,40 @@ +package app + +import ( + "context" + + "git.sr.ht/~emersion/gqlclient" +) + +type appPublishResponse struct { + ToolPublish App +} + +func Publish(id string, client *gqlclient.Client) (App, error) { + resp := appPublishResponse{} + op := createAppPublishOperation(id) + + if err := client.Execute(context.TODO(), op, &resp); err != nil { + return resp.ToolPublish, err + } + + return resp.ToolPublish, nil +} + +func createAppPublishOperation(id string) *gqlclient.Operation { + op := gqlclient.NewOperation(` + mutation ToolPublish($id: ID!) { + toolPublish(id: $id) { + id + name + description + createdAt + sharedUrl + publicUrl + } + } + `) + op.Var("id", id) + + return op +} diff --git a/cli/internal/gql/app/publish_test.go b/cli/internal/gql/app/publish_test.go new file mode 100644 index 00000000..371f5dbb --- /dev/null +++ b/cli/internal/gql/app/publish_test.go @@ -0,0 +1,40 @@ +package app + +import ( + "testing" + "time" + + "numerous/cli/test" + + "github.com/stretchr/testify/assert" +) + +func TestPublish(t *testing.T) { + t.Run("can return app on AppPublish mutation", func(t *testing.T) { + expectedApp := App{ + ID: "id", + SharedURL: "https://test.com/shared/some-hash", + PublicURL: "https://test.com/public/another-hash", + Name: "test name", + CreatedAt: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC), + } + response := test.AppToQueryResult("toolPublish", expectedApp) + c := test.CreateTestGqlClient(response) + + actualApp, err := Publish(expectedApp.ID, c) + + assert.NoError(t, err) + assert.Equal(t, expectedApp, actualApp) + }) + + t.Run("can return error on AppPublish mutation", func(t *testing.T) { + appNotFoundResponse := `{"errors":[{"message":"record not found","path":["tool"]}],"data":null}` + c := test.CreateTestGqlClient(appNotFoundResponse) + + actualApp, err := Publish("id", c) + + assert.Error(t, err) + assert.ErrorContains(t, err, "record not found") + assert.Equal(t, App{}, actualApp) + }) +} diff --git a/cli/internal/gql/app/query.go b/cli/internal/gql/app/query.go new file mode 100644 index 00000000..d88e8450 --- /dev/null +++ b/cli/internal/gql/app/query.go @@ -0,0 +1,40 @@ +package app + +import ( + "context" + + "git.sr.ht/~emersion/gqlclient" +) + +type appResponse struct { + Tool App +} + +func Query(appID string, client *gqlclient.Client) (App, error) { + resp := appResponse{} + + op := queryAppOperation(appID) + if err := client.Execute(context.Background(), op, &resp); err != nil { + return resp.Tool, err + } + + return resp.Tool, nil +} + +func queryAppOperation(appID string) *gqlclient.Operation { + op := gqlclient.NewOperation(` + query ReadTool($id: ID!) { + tool(id: $id) { + id + name + description + createdAt + sharedUrl + publicUrl + } + } + `) + op.Var("id", appID) + + return op +} diff --git a/cli/internal/gql/app/query_list.go b/cli/internal/gql/app/query_list.go new file mode 100644 index 00000000..1f7f280a --- /dev/null +++ b/cli/internal/gql/app/query_list.go @@ -0,0 +1,39 @@ +package app + +import ( + "context" + + "git.sr.ht/~emersion/gqlclient" +) + +type appListResponse struct { + Tools []App +} + +func QueryList(client *gqlclient.Client) ([]App, error) { + resp := appListResponse{[]App{}} + + op := queryAppListOperation() + if err := client.Execute(context.Background(), op, &resp); err != nil { + return resp.Tools, err + } + + return resp.Tools, nil +} + +func queryAppListOperation() *gqlclient.Operation { + op := gqlclient.NewOperation(` + query ReadTools { + tools { + id + name + description + createdAt + sharedUrl + publicUrl + } + } + `) + + return op +} diff --git a/cli/internal/gql/app/query_list_test.go b/cli/internal/gql/app/query_list_test.go new file mode 100644 index 00000000..8de888aa --- /dev/null +++ b/cli/internal/gql/app/query_list_test.go @@ -0,0 +1,54 @@ +package app + +import ( + "strconv" + "strings" + "testing" + "time" + + "numerous/cli/test" + + "github.com/stretchr/testify/assert" +) + +func TestQueryList(t *testing.T) { + t.Run("can return apps on list apps query", func(t *testing.T) { + appsAsStrings := []string{} + expectedApps := []App{} + for i := 0; i < 3; i++ { + id := strconv.Itoa(i) + app := App{ + ID: id, + SharedURL: "https://test.com/shared/some-hash-" + id, + PublicURL: "", + Name: "Name " + id, + CreatedAt: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC), + } + expectedApps = append(expectedApps, app) + appsAsStrings = append(appsAsStrings, test.AppToResponse(app)) + } + + response := `{ + "data": { + "tools": [` + strings.Join(appsAsStrings, ", ") + `] + } + }` + c := test.CreateTestGqlClient(response) + + actualApps, err := QueryList(c) + + assert.NoError(t, err) + assert.Equal(t, expectedApps, actualApps) + }) + + t.Run("can return permission denied error", func(t *testing.T) { + appNotFoundResponse := `{"errors":[{"message":"permission denied","path":["tools"]}],"data":null}` + c := test.CreateTestGqlClient(appNotFoundResponse) + + actualApps, err := QueryList(c) + + assert.Error(t, err) + assert.ErrorContains(t, err, "permission denied") + assert.Equal(t, []App{}, actualApps) + }) +} diff --git a/cli/internal/gql/app/query_test.go b/cli/internal/gql/app/query_test.go new file mode 100644 index 00000000..330dec2d --- /dev/null +++ b/cli/internal/gql/app/query_test.go @@ -0,0 +1,40 @@ +package app + +import ( + "testing" + "time" + + "numerous/cli/test" + + "github.com/stretchr/testify/assert" +) + +func TestQuery(t *testing.T) { + t.Run("can return app on app query", func(t *testing.T) { + expectedApp := App{ + ID: "id", + SharedURL: "https://test.com/shared/some-hash", + PublicURL: "", + Name: "test name", + CreatedAt: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC), + } + response := test.AppToQueryResult("tool", expectedApp) + c := test.CreateTestGqlClient(response) + + actualApp, err := Query("id", c) + + assert.NoError(t, err) + assert.Equal(t, expectedApp, actualApp) + }) + + t.Run("can return error on app query", func(t *testing.T) { + appNotFoundResponse := `{"errors":[{"message":"record not found","path":["tool"]}],"data":null}` + c := test.CreateTestGqlClient(appNotFoundResponse) + + actualApp, err := Query("non-existing-id", c) + + assert.Error(t, err) + assert.ErrorContains(t, err, "record not found") + assert.Equal(t, App{}, actualApp) + }) +} diff --git a/cli/internal/gql/app/types.go b/cli/internal/gql/app/types.go new file mode 100644 index 00000000..bafcfe58 --- /dev/null +++ b/cli/internal/gql/app/types.go @@ -0,0 +1,12 @@ +package app + +import "time" + +type App struct { + ID string + Name string + Description string + PublicURL string + SharedURL string + CreatedAt time.Time +} diff --git a/cli/internal/gql/app/unpublish.go b/cli/internal/gql/app/unpublish.go new file mode 100644 index 00000000..b91d9b7a --- /dev/null +++ b/cli/internal/gql/app/unpublish.go @@ -0,0 +1,40 @@ +package app + +import ( + "context" + + "git.sr.ht/~emersion/gqlclient" +) + +type appUnpublishResponse struct { + ToolUnpublish App +} + +func Unpublish(id string, client *gqlclient.Client) (App, error) { + resp := appUnpublishResponse{} + op := createAppUnpublishOperation(id) + + if err := client.Execute(context.TODO(), op, &resp); err != nil { + return resp.ToolUnpublish, err + } + + return resp.ToolUnpublish, nil +} + +func createAppUnpublishOperation(id string) *gqlclient.Operation { + op := gqlclient.NewOperation(` + mutation ToolUnpublish($id: ID!) { + toolUnpublish(id: $id) { + id + name + description + createdAt + sharedUrl + publicUrl + } + } + `) + op.Var("id", id) + + return op +} diff --git a/cli/internal/gql/app/unpublish_test.go b/cli/internal/gql/app/unpublish_test.go new file mode 100644 index 00000000..dc53c18c --- /dev/null +++ b/cli/internal/gql/app/unpublish_test.go @@ -0,0 +1,40 @@ +package app + +import ( + "testing" + "time" + + "numerous/cli/test" + + "github.com/stretchr/testify/assert" +) + +func TestUnpublish(t *testing.T) { + t.Run("can return app on AppUnpublish mutation", func(t *testing.T) { + expectedApp := App{ + ID: "id", + SharedURL: "https://test.com/shared/some-hash", + PublicURL: "", + Name: "test name", + CreatedAt: time.Date(2024, 1, 1, 0, 0, 0, 0, time.UTC), + } + response := test.AppToQueryResult("toolUnpublish", expectedApp) + c := test.CreateTestGqlClient(response) + + actualApp, err := Unpublish(expectedApp.ID, c) + + assert.NoError(t, err) + assert.Equal(t, expectedApp, actualApp) + }) + + t.Run("can return error on AppUnpublish mutation", func(t *testing.T) { + appNotFoundResponse := `{"errors":[{"message":"record not found","path":["toolUnpublish"]}],"data":null}` + c := test.CreateTestGqlClient(appNotFoundResponse) + + actualApp, err := Unpublish("id", c) + + assert.Error(t, err) + assert.ErrorContains(t, err, "record not found") + assert.Equal(t, App{}, actualApp) + }) +} diff --git a/cli/internal/gql/build/push.go b/cli/internal/gql/build/push.go new file mode 100644 index 00000000..bde1743b --- /dev/null +++ b/cli/internal/gql/build/push.go @@ -0,0 +1,41 @@ +package build + +import ( + "context" + "os" + + "git.sr.ht/~emersion/gqlclient" +) + +type pushResponse struct { + BuildPush BuildConfiguration +} + +func Push(file *os.File, appID string, client *gqlclient.Client) (BuildConfiguration, error) { + resp := pushResponse{} + op := createBuildOperation(file, appID) + + if err := client.Execute(context.TODO(), op, &resp); err != nil { + return BuildConfiguration{}, err + } + + return resp.BuildPush, nil +} + +func createBuildOperation(file *os.File, appID string) *gqlclient.Operation { + op := gqlclient.NewOperation(` + mutation BuildPush($file: Upload!, $appID: ID!) { + buildPush(file: $file, id: $appID) { + buildId + } + } + `) + op.Var("appID", appID) + op.Var("file", gqlclient.Upload{ + Filename: file.Name(), + MIMEType: "application/zip", + Body: file, + }) + + return op +} diff --git a/cli/internal/gql/build/push_test.go b/cli/internal/gql/build/push_test.go new file mode 100644 index 00000000..8b6c6b5d --- /dev/null +++ b/cli/internal/gql/build/push_test.go @@ -0,0 +1,68 @@ +package build + +import ( + "bytes" + "io" + "net/http" + "os" + "path/filepath" + "testing" + + "numerous/cli/test" + + "git.sr.ht/~emersion/gqlclient" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestPush(t *testing.T) { + tmpFilePath := filepath.Join(t.TempDir(), "file.zip") + tmpFile, err := os.Create(tmpFilePath) + require.NoError(t, err) + defer tmpFile.Close() + + t.Run("can return app on AppCreate mutation", func(t *testing.T) { + expectedBuild := BuildConfiguration{ + BuildID: "buildID", + } + response := `{ + "data": { + "buildPush": { + "buildId": "buildID" + } + } + }` + c := createTestGqlClient(response) + appID := "app_id" + actualBuild, err := Push(tmpFile, appID, c) + + assert.NoError(t, err) + assert.Equal(t, expectedBuild, actualBuild) + }) + + t.Run("can return error on AppCreate mutation", func(t *testing.T) { + buildPushFailedResponse := `{"errors":[{"message":"Something went wrong","path":["buildPush"]}],"data":null}` + c := createTestGqlClient(buildPushFailedResponse) + + appID := "app_id" + actualBuild, err := Push(tmpFile, appID, c) + + assert.Error(t, err) + assert.ErrorContains(t, err, "Something went wrong") + assert.Equal(t, BuildConfiguration{}, actualBuild) + }) +} + +func createTestGqlClient(response string) *gqlclient.Client { + h := http.Header{} + h.Add("Content-Type", "application/json") + ts := test.TestTransport{ + WithResponse: &http.Response{ + Header: h, + StatusCode: http.StatusOK, + Body: io.NopCloser(bytes.NewReader([]byte(response))), + }, + } + + return gqlclient.New("http://localhost:8080", &http.Client{Transport: &ts}) +} diff --git a/cli/internal/gql/build/types.go b/cli/internal/gql/build/types.go new file mode 100644 index 00000000..d3af596f --- /dev/null +++ b/cli/internal/gql/build/types.go @@ -0,0 +1,5 @@ +package build + +type BuildConfiguration struct { + BuildID string +} diff --git a/cli/internal/gql/client.go b/cli/internal/gql/client.go new file mode 100644 index 00000000..cd0c0370 --- /dev/null +++ b/cli/internal/gql/client.go @@ -0,0 +1,40 @@ +package gql + +import ( + "net/http" + "net/url" + "sync" + + "numerous/cli/auth" + + "git.sr.ht/~emersion/gqlclient" +) + +var ( + client *gqlclient.Client + once sync.Once +) + +func initClient() { + var httpClient *http.Client + + if user := auth.NumerousTenantAuthenticator.GetLoggedInUserFromKeyring(); user != nil { + httpClient = &http.Client{ + Transport: &http.Transport{ + Proxy: func(r *http.Request) (*url.URL, error) { + r.Header.Set("Authorization", "Bearer "+user.AccessToken) + return nil, nil + }, + }, + } + } else { + httpClient = http.DefaultClient + } + + client = gqlclient.New(httpURL, httpClient) +} + +func GetClient() *gqlclient.Client { + once.Do(initClient) + return client +} diff --git a/cli/internal/gql/jobs/job_stop.go b/cli/internal/gql/jobs/job_stop.go new file mode 100644 index 00000000..16bc86fd --- /dev/null +++ b/cli/internal/gql/jobs/job_stop.go @@ -0,0 +1,31 @@ +package jobs + +import ( + "context" + + "git.sr.ht/~emersion/gqlclient" +) + +func JobStop(id string, client *gqlclient.Client) (string, error) { + resp := jobStopResponse{} + op := createJobStopOperation(id) + if err := client.Execute(context.TODO(), op, &resp); err != nil { + return resp.Message, err + } + + return resp.Message, nil +} + +func createJobStopOperation(id string) *gqlclient.Operation { + op := gqlclient.NewOperation(` + mutation JobStop($id: ID!) { + jobStop(id: $id) { + message + } + } + `) + + op.Var("id", id) + + return op +} diff --git a/cli/internal/gql/jobs/jobs_by_tool.go b/cli/internal/gql/jobs/jobs_by_tool.go new file mode 100644 index 00000000..4d52b3c7 --- /dev/null +++ b/cli/internal/gql/jobs/jobs_by_tool.go @@ -0,0 +1,32 @@ +package jobs + +import ( + "context" + + "git.sr.ht/~emersion/gqlclient" +) + +func JobsByTool(id string, client *gqlclient.Client) ([]Job, error) { + resp := jobsByToolResponse{} + + op := createJobsByToolOperation(id) + if err := client.Execute(context.TODO(), op, &resp); err != nil { + return resp.JobsByTool, err + } + + return resp.JobsByTool, nil +} + +func createJobsByToolOperation(id string) *gqlclient.Operation { + op := gqlclient.NewOperation(` + query JobsByTool($id: ID!) { + jobsByTool(id: $id) { + id + } + } + `) + + op.Var("id", id) + + return op +} diff --git a/cli/internal/gql/jobs/types.go b/cli/internal/gql/jobs/types.go new file mode 100644 index 00000000..3a0f279d --- /dev/null +++ b/cli/internal/gql/jobs/types.go @@ -0,0 +1,13 @@ +package jobs + +type jobsByToolResponse struct { + JobsByTool []Job +} + +type Job struct { + ID string +} + +type jobStopResponse struct { + Message string +} diff --git a/cli/internal/gql/organization/create.go b/cli/internal/gql/organization/create.go new file mode 100644 index 00000000..900fe8a8 --- /dev/null +++ b/cli/internal/gql/organization/create.go @@ -0,0 +1,42 @@ +package organization + +import ( + "context" + + "git.sr.ht/~emersion/gqlclient" +) + +type organizationCreateResponse struct { + OrganizationCreate Organization +} + +func Create(name string, client *gqlclient.Client) (Organization, error) { + resp := organizationCreateResponse{} + op := createOrganizationCreateOperation(name) + + if err := client.Execute(context.TODO(), op, &resp); err != nil { + if err.Error() == ErrOrganizationNameInvalidCharacter.Error() { + return resp.OrganizationCreate, ErrOrganizationNameInvalidCharacter + } + + return resp.OrganizationCreate, err + } + + return resp.OrganizationCreate, nil +} + +func createOrganizationCreateOperation(name string) *gqlclient.Operation { + op := gqlclient.NewOperation(` + mutation OrganizationCreate($name: String!) { + organizationCreate(input: { name: $name }) { + id + name + slug + } + } +`) + + op.Var("name", name) + + return op +} diff --git a/cli/internal/gql/organization/create_test.go b/cli/internal/gql/organization/create_test.go new file mode 100644 index 00000000..28bb0f9d --- /dev/null +++ b/cli/internal/gql/organization/create_test.go @@ -0,0 +1,65 @@ +package organization + +import ( + "fmt" + "testing" + + "numerous/cli/test" + + "github.com/stretchr/testify/assert" +) + +func TestCreate(t *testing.T) { + t.Run("can return organization on OrganizationCreate mutation", func(t *testing.T) { + expectedOrganization := Organization{ + ID: "id", + Name: "name", + Slug: "slug", + } + response := organizationToQueryResult("organizationCreate", expectedOrganization) + c := test.CreateTestGqlClient(response) + + actualOrganization, err := Create(expectedOrganization.Name, c) + + assert.NoError(t, err) + assert.Equal(t, expectedOrganization, actualOrganization) + }) + + t.Run("can return error on OrganizationCreate mutation if name contains invalid character", func(t *testing.T) { + organizationInvalidCharactersResponse := `{"errors":[{"message":"organization name contains invalid characters","path":["organizationCreate"]}],"data":null}` + c := test.CreateTestGqlClient(organizationInvalidCharactersResponse) + + actualOrganization, err := Create("!", c) + + assert.Error(t, err) + assert.ErrorContains(t, err, "organization name contains invalid characters") + assert.Equal(t, Organization{}, actualOrganization) + }) + + t.Run("can return error on OrganizationCreate mutation if unknown error", func(t *testing.T) { + organizationErrorResponse := `{"errors":[{"message":"unknown error","path":["organizationCreate"]}],"data":null}` + c := test.CreateTestGqlClient(organizationErrorResponse) + + actualOrganization, err := Create("", c) + + assert.Error(t, err) + assert.NotErrorIs(t, err, ErrOrganizationNameInvalidCharacter) + assert.Equal(t, Organization{}, actualOrganization) + }) +} + +func organizationToQueryResult(queryName string, o Organization) string { + return fmt.Sprintf(`{ + "data": { + "%s": %s + } + }`, queryName, organizationToResponse(o)) +} + +func organizationToResponse(o Organization) string { + return fmt.Sprintf(`{ + "id": "%s", + "name": "%s", + "slug": "%s" + }`, o.ID, o.Name, o.Slug) +} diff --git a/cli/internal/gql/organization/organization.go b/cli/internal/gql/organization/organization.go new file mode 100644 index 00000000..dfd21b3c --- /dev/null +++ b/cli/internal/gql/organization/organization.go @@ -0,0 +1,16 @@ +package organization + +import ( + "errors" + "fmt" +) + +var ErrOrganizationNameInvalidCharacter = errors.New("gqlclient: server failure: organization name contains invalid characters") + +func (o Organization) String() string { + return fmt.Sprintf(` +Organization: + name %s + url %s + `, o.Name, "https://numerous.com/app/organization/"+o.Slug) +} diff --git a/cli/internal/gql/organization/types.go b/cli/internal/gql/organization/types.go new file mode 100644 index 00000000..b6efc912 --- /dev/null +++ b/cli/internal/gql/organization/types.go @@ -0,0 +1,19 @@ +package organization + +type Organization struct { + ID string + Name string + Slug string +} + +type Role string + +const ( + Admin Role = "ADMIN" + User Role = "USER" +) + +type OrganizationMembership struct { + Role Role + Organization Organization +} diff --git a/cli/internal/gql/subscription_client.go b/cli/internal/gql/subscription_client.go new file mode 100644 index 00000000..9e87e006 --- /dev/null +++ b/cli/internal/gql/subscription_client.go @@ -0,0 +1,23 @@ +package gql + +import ( + "net/http" + + "numerous/cli/auth" + + "github.com/hasura/go-graphql-client" +) + +func GetSubscriptionClient() *graphql.SubscriptionClient { + client := graphql.NewSubscriptionClient(wsURL) + + if user := auth.NumerousTenantAuthenticator.GetLoggedInUserFromKeyring(); user != nil { + client = client.WithWebSocketOptions(graphql.WebsocketOptions{ + HTTPHeader: http.Header{ + "Authorization": []string{"Bearer " + user.AccessToken}, + }, + }) + } + + return client +} diff --git a/cli/internal/gql/user/query_user.go b/cli/internal/gql/user/query_user.go new file mode 100644 index 00000000..ab257c30 --- /dev/null +++ b/cli/internal/gql/user/query_user.go @@ -0,0 +1,42 @@ +package user + +import ( + "context" + + "git.sr.ht/~emersion/gqlclient" +) + +type userResponse struct { + Me User +} + +func QueryUser(client *gqlclient.Client) (User, error) { + resp := userResponse{User{}} + + op := queryUserOperation() + if err := client.Execute(context.Background(), op, &resp); err != nil { + return resp.Me, err + } + + return resp.Me, nil +} + +func queryUserOperation() *gqlclient.Operation { + op := gqlclient.NewOperation(` + query Me { + me { + fullName + memberships { + role + organization { + id + name + slug + } + } + } + } + `) + + return op +} diff --git a/cli/internal/gql/user/query_user_test.go b/cli/internal/gql/user/query_user_test.go new file mode 100644 index 00000000..ddc4932a --- /dev/null +++ b/cli/internal/gql/user/query_user_test.go @@ -0,0 +1,64 @@ +package user + +import ( + "testing" + + "numerous/cli/internal/gql/organization" + "numerous/cli/test" + + "github.com/stretchr/testify/assert" +) + +func TestQueryUser(t *testing.T) { + t.Run("can return user on user query", func(t *testing.T) { + membership := organization.OrganizationMembership{ + Role: organization.Admin, + Organization: organization.Organization{ + ID: "1", + Name: "Test org", + Slug: "test-org-slug", + }, + } + expectedUser := User{ + FullName: "Test User", + Memberships: []organization.OrganizationMembership{membership}, + } + membershipAsString := test.OrganizationMembershipToResponse(struct { + Role test.Role + Organization struct { + ID string + Name string + Slug string + } + }{ + Role: test.Role(membership.Role), + Organization: membership.Organization, + }) + + response := `{ + "data": { + "me": { + "fullName": "` + expectedUser.FullName + `", + "memberships": [` + membershipAsString + `] + } + } + }` + c := test.CreateTestGqlClient(response) + + actualUser, err := QueryUser(c) + + assert.NoError(t, err) + assert.Equal(t, expectedUser, actualUser) + }) + + t.Run("can return permission denied error", func(t *testing.T) { + userNotFoundResponse := `{"errors":[{"message":"permission denied","path":["me"]}],"data":null}` + c := test.CreateTestGqlClient(userNotFoundResponse) + + actualUser, err := QueryUser(c) + + assert.Error(t, err) + assert.ErrorContains(t, err, "permission denied") + assert.Equal(t, User{}, actualUser) + }) +} diff --git a/cli/internal/gql/user/types.go b/cli/internal/gql/user/types.go new file mode 100644 index 00000000..2b973adb --- /dev/null +++ b/cli/internal/gql/user/types.go @@ -0,0 +1,8 @@ +package user + +import "numerous/cli/internal/gql/organization" + +type User struct { + FullName string + Memberships []organization.OrganizationMembership +} diff --git a/cli/keyring/keyring.go b/cli/keyring/keyring.go new file mode 100644 index 00000000..8decaf57 --- /dev/null +++ b/cli/keyring/keyring.go @@ -0,0 +1,115 @@ +package keyring + +import ( + "errors" + "fmt" + + "github.com/zalando/go-keyring" +) + +const ( + secretRefreshToken = "Numerous CLI Refresh Token" + secretAccessToken = "Numerous CLI Access Token" + secretAccessTokenChunkSizeInBytes = 2048 + + // Access tokens have no size limit, but should be smaller than (50*2048) bytes. + // The max number of loops safeguards against infinite loops, however unlikely. + secretAccessTokenMaxChunks = 50 +) + +// ErrTokenSize is thrown when the token is invalid is larger than (50*2048) bytes. +var ErrTokenSize = errors.New("token is invalid") + +// StoreRefreshToken stores a tenant's refresh token in the system keyring. +func StoreRefreshToken(tenant, value string) error { + return keyring.Set(secretRefreshToken, tenant, value) +} + +// GetRefreshToken retrieves a tenant's refresh token from the system keyring. +func GetRefreshToken(tenant string) (string, error) { + return keyring.Get(secretRefreshToken, tenant) +} + +func StoreAccessToken(tenant, value string) error { + chunks := chunk(value, secretAccessTokenChunkSizeInBytes) + + if len(chunks) > secretAccessTokenMaxChunks { + return ErrTokenSize + } + + for i, chunk := range chunks { + err := keyring.Set(fmt.Sprintf("%s %d", secretAccessToken, i), tenant, chunk) + if err != nil { + return err + } + } + + return nil +} + +func DeleteTokens(tenant string) error { + deleteAccessTokenErr := deleteAccessToken(tenant) + deleteRefreshTokenErr := keyring.Delete(secretRefreshToken, tenant) + + if deleteAccessTokenErr != nil { + return deleteAccessTokenErr + } + if deleteRefreshTokenErr != nil { + return deleteRefreshTokenErr + } + + return nil +} + +func deleteAccessToken(tenant string) error { + for i := 0; i < secretAccessTokenMaxChunks; i++ { + err := keyring.Delete(fmt.Sprintf("%s %d", secretAccessToken, i), tenant) + // Only return if we have pulled more than 1 item from the keyring, otherwise this will be + // a valid "secret not found in keyring". + if err == keyring.ErrNotFound && i > 0 { + return nil + } + if err != nil { + return err + } + } + + return keyring.ErrNotFound +} + +func GetAccessToken(tenant string) (string, error) { + var accessToken string + + for i := 0; i < secretAccessTokenMaxChunks; i++ { + a, err := keyring.Get(fmt.Sprintf("%s %d", secretAccessToken, i), tenant) + // Only return if we have pulled more than 1 item from the keyring, otherwise this will be + // a valid "secret not found in keyring". + if err == keyring.ErrNotFound && i > 0 { + return accessToken, nil + } + if err != nil { + return "", err + } + accessToken += a + } + + return accessToken, nil +} + +// Splits string into chunks of chunkSize +func chunk(slice string, chunkSize int) []string { + var chunks []string + for i := 0; i < len(slice); i += chunkSize { + end := i + chunkSize + + // Necessary check to avoid slicing beyond + // slice capacity. + if end > len(slice) { + end = len(slice) + } + + chunks = append(chunks, slice[i:end]) + } + + return chunks +} diff --git a/cli/keyring/keyring_test.go b/cli/keyring/keyring_test.go new file mode 100644 index 00000000..ae3af06f --- /dev/null +++ b/cli/keyring/keyring_test.go @@ -0,0 +1,184 @@ +package keyring + +import ( + "fmt" + "math/rand" + "testing" + "time" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/zalando/go-keyring" +) + +const testTenantName = "numerous-cli-test.eu.auth0.com" + +func TestSecrets(t *testing.T) { + t.Run("fails to retrieve an nonexistent refresh token", func(t *testing.T) { + keyring.MockInit() + + _, actualError := GetRefreshToken(testTenantName) + assert.EqualError(t, actualError, keyring.ErrNotFound.Error()) + }) + + t.Run("successfully retrieves an existent refresh token", func(t *testing.T) { + keyring.MockInit() + + expectedRefreshToken := "fake-refresh-token" + err := keyring.Set(secretRefreshToken, testTenantName, expectedRefreshToken) + require.NoError(t, err) + + actualRefreshToken, err := GetRefreshToken(testTenantName) + require.NoError(t, err) + assert.Equal(t, expectedRefreshToken, actualRefreshToken) + }) + + t.Run("successfully stores a refresh token", func(t *testing.T) { + keyring.MockInit() + + expectedRefreshToken := "fake-refresh-token" + err := StoreRefreshToken(testTenantName, expectedRefreshToken) + require.NoError(t, err) + + actualRefreshToken, err := GetRefreshToken(testTenantName) + require.NoError(t, err) + assert.Equal(t, expectedRefreshToken, actualRefreshToken) + }) + + t.Run("fails to retrieve an nonexistent access token", func(t *testing.T) { + keyring.MockInit() + + _, actualError := GetAccessToken(testTenantName) + require.EqualError(t, actualError, keyring.ErrNotFound.Error()) + }) + + t.Run("successfully stores an access token", func(t *testing.T) { + keyring.MockInit() + + expectedAccessToken := randomStringOfLength((2048 * 5) + 1) // Some arbitrarily long random string. + err := StoreAccessToken(testTenantName, expectedAccessToken) + require.NoError(t, err) + + actualAccessToken, err := GetAccessToken(testTenantName) + require.NoError(t, err) + assert.Equal(t, expectedAccessToken, actualAccessToken) + }) + + t.Run("successfully retrieves an access token split up into multiple chunks", func(t *testing.T) { + keyring.MockInit() + + err := keyring.Set(fmt.Sprintf("%s %d", secretAccessToken, 0), testTenantName, "chunk0") + require.NoError(t, err) + err = keyring.Set(fmt.Sprintf("%s %d", secretAccessToken, 1), testTenantName, "chunk1") + require.NoError(t, err) + err = keyring.Set(fmt.Sprintf("%s %d", secretAccessToken, 2), testTenantName, "chunk2") + require.NoError(t, err) + + actualAccessToken, err := GetAccessToken(testTenantName) + require.NoError(t, err) + assert.Equal(t, "chunk0chunk1chunk2", actualAccessToken) + }) + + t.Run("successfully deletes an access token split up into multiple chunks", func(t *testing.T) { + keyring.MockInit() + + err := keyring.Set(fmt.Sprintf("%s %d", secretAccessToken, 0), testTenantName, "chunk0") + require.NoError(t, err) + err = keyring.Set(fmt.Sprintf("%s %d", secretAccessToken, 1), testTenantName, "chunk1") + require.NoError(t, err) + err = keyring.Set(fmt.Sprintf("%s %d", secretAccessToken, 2), testTenantName, "chunk2") + require.NoError(t, err) + err = keyring.Set(secretRefreshToken, testTenantName, "fake-refresh-token") + require.NoError(t, err) + + // Ensure setup is correct + actualAccessToken, err := GetAccessToken(testTenantName) + require.NoError(t, err) + assert.Equal(t, "chunk0chunk1chunk2", actualAccessToken) + + err = DeleteTokens(testTenantName) + require.NoError(t, err) + + _, actualError := GetAccessToken(testTenantName) + require.EqualError(t, actualError, keyring.ErrNotFound.Error()) + }) + + t.Run("successfully deletes an refresh token", func(t *testing.T) { + keyring.MockInit() + + err := keyring.Set(fmt.Sprintf("%s %d", secretAccessToken, 0), testTenantName, "access-token") + require.NoError(t, err) + err = keyring.Set(secretRefreshToken, testTenantName, "fake-refresh-token") + require.NoError(t, err) + + err = DeleteTokens(testTenantName) + require.NoError(t, err) + + _, actualError := GetRefreshToken(testTenantName) + require.EqualError(t, actualError, keyring.ErrNotFound.Error()) + }) + + testCases := []struct { + missingTokenType string + addToken func() error + }{ + { + missingTokenType: "accessToken", + addToken: func() error { + return keyring.Set(secretRefreshToken, testTenantName, "fake-refresh-token") + }, + }, + { + missingTokenType: "refreshToken", + addToken: func() error { + return keyring.Set(fmt.Sprintf("%s %d", secretAccessToken, 0), testTenantName, "access-token") + }, + }, + } + + for _, testCase := range testCases { + t.Run(fmt.Sprintf("deleteTokens returns error %s does not exists", testCase.missingTokenType), func(t *testing.T) { + keyring.MockInit() + + err := testCase.addToken() + require.NoError(t, err) + + actualError := DeleteTokens(testTenantName) + require.EqualError(t, actualError, keyring.ErrNotFound.Error()) + }) + } + + t.Run("returns error if access token is greater than 50 * 2048 bytes", func(t *testing.T) { + keyring.MockInit() + + accessToken := randomStringOfLength(50*2048 + 1) + + err := StoreAccessToken(testTenantName, accessToken) + + require.EqualError(t, err, ErrTokenSize.Error()) + }) + + t.Run("can store and read a token of size 50 * 2048 bytes", func(t *testing.T) { + keyring.MockInit() + + expectedAccesToken := randomStringOfLength(50 * 2048) + + err := StoreAccessToken(testTenantName, expectedAccesToken) + require.NoError(t, err) + actualAccessToken, err := GetAccessToken(testTenantName) + require.NoError(t, err) + + assert.Equal(t, expectedAccesToken, actualAccessToken) + }) +} + +func randomStringOfLength(length int) string { + seededRand := rand.New(rand.NewSource(time.Now().UnixNano())) + charset := "abcdefghijklmnopqrstuvwxyz0123456789" + b := make([]byte, length) + for i := range b { + b[i] = charset[seededRand.Intn(len(charset))] + } + + return string(b) +} diff --git a/cli/logging/loglevel.go b/cli/logging/loglevel.go new file mode 100644 index 00000000..a26a5eed --- /dev/null +++ b/cli/logging/loglevel.go @@ -0,0 +1,53 @@ +package logging + +import ( + "errors" + "fmt" + "log/slog" + "strings" +) + +type Level string + +const ( + LevelDebug Level = "debug" + LevelInfo Level = "info" + LevelWarning Level = "warning" + LevelError Level = "error" +) + +var ErrInvalidLogLevel error = errors.New(`must be one of "debug", "info", "warning" or "error"`) + +func (l *Level) String() string { + return string(*l) +} + +func (l *Level) Set(v string) error { + v = strings.ToLower(v) + switch v { + case "debug", "info", "warning", "error": + *l = Level(v) + return nil + default: + return ErrInvalidLogLevel + } +} + +func (l *Level) Type() string { + return "Log level" +} + +func (l *Level) ToSlogLevel() slog.Level { + switch strings.ToLower(l.String()) { + case "debug": + return slog.LevelDebug + case "info": + return slog.LevelInfo + case "warning": + return slog.LevelWarn + case "error": + return slog.LevelError + default: + panic(fmt.Sprintf("unexpected log level \"%s\"", l.String())) + } +} diff --git a/cli/logging/loglevel_test.go b/cli/logging/loglevel_test.go new file mode 100644 index 00000000..59ba3699 --- /dev/null +++ b/cli/logging/loglevel_test.go @@ -0,0 +1,87 @@ +package logging + +import ( + "log/slog" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestSet(t *testing.T) { + testcases := []struct { + value string + expected Level + }{ + {value: "debug", expected: LevelDebug}, + {value: "info", expected: LevelInfo}, + {value: "warning", expected: LevelWarning}, + {value: "error", expected: LevelError}, + {value: "DEBUG", expected: LevelDebug}, + {value: "INFO", expected: LevelInfo}, + {value: "WARNING", expected: LevelWarning}, + {value: "ERROR", expected: LevelError}, + } + + for _, testcase := range testcases { + t.Run(testcase.value, func(t *testing.T) { + var l Level + err := l.Set(testcase.value) + + require.NoError(t, err) + assert.Equal(t, testcase.expected, l) + }) + } + + t.Run("returns error on invalid value", func(t *testing.T) { + var l Level + + err := l.Set("some other value") + require.ErrorIs(t, err, ErrInvalidLogLevel) + }) +} + +func TestString(t *testing.T) { + testcases := []struct { + level Level + expected string + }{ + {expected: "debug", level: LevelDebug}, + {expected: "info", level: LevelInfo}, + {expected: "warning", level: LevelWarning}, + {expected: "error", level: LevelError}, + } + + for _, testcase := range testcases { + t.Run(testcase.expected, func(t *testing.T) { + actual := testcase.level.String() + assert.Equal(t, testcase.expected, actual) + }) + } +} + +func TestToSlogLevel(t *testing.T) { + testcases := []struct { + level Level + expected slog.Level + }{ + {level: LevelDebug, expected: slog.LevelDebug}, + {level: LevelInfo, expected: slog.LevelInfo}, + {level: LevelWarning, expected: slog.LevelWarn}, + {level: LevelError, expected: slog.LevelError}, + } + + for _, testcase := range testcases { + t.Run(testcase.level.String(), func(t *testing.T) { + slogLevel := testcase.level.ToSlogLevel() + assert.Equal(t, testcase.expected, slogLevel) + }) + } +} + +func TestType(t *testing.T) { + levels := []Level{LevelDebug, LevelInfo, LevelWarning, LevelError} + for _, level := range levels { + assert.Equal(t, "Log level", level.Type()) + } +} diff --git a/cli/main.go b/cli/main.go new file mode 100644 index 00000000..b036e63a --- /dev/null +++ b/cli/main.go @@ -0,0 +1,7 @@ +package main + +import "numerous/cli/cmd" + +func main() { + cmd.Execute() +} diff --git a/cli/manifest/manifest.go b/cli/manifest/manifest.go new file mode 100644 index 00000000..edbbade9 --- /dev/null +++ b/cli/manifest/manifest.go @@ -0,0 +1,155 @@ +package manifest + +import ( + "bytes" + "encoding/json" + "errors" + "fmt" + "os" + "path/filepath" + "strconv" + "strings" + + "numerous/cli/tool" + + "github.com/BurntSushi/toml" +) + +const ManifestFileName string = "numerous.toml" + +var ManifestPath string = filepath.Join(".", ManifestFileName) + +type Manifest struct { + Name string `toml:"name" json:"name"` + Description string `toml:"description" json:"description"` + Library string `toml:"library" json:"library"` + Python string `toml:"python" json:"python"` + AppFile string `toml:"app_file" json:"app_file"` + RequirementsFile string `toml:"requirements_file" json:"requirements_file"` + Port uint `toml:"port" json:"port"` + CoverImage string `toml:"cover_image" json:"cover_image"` + Exclude []string `toml:"exclude" json:"exclude"` +} + +type DeprecatedManifest struct { + Name string `toml:"name" json:"name"` + Description string `toml:"description" json:"description"` + Library string `toml:"library" json:"library"` + Python string `toml:"python" json:"python"` + AppFile string `toml:"app_file" json:"app_file"` + RequirementsFile string `toml:"requirements_file" json:"requirements_file"` + Port string `toml:"port" json:"port"` + CoverImage string `toml:"cover_image" json:"cover_image"` + Exclude []string `toml:"exclude" json:"exclude"` +} + +func LoadManifest(filePath string) (*Manifest, error) { + var m Manifest + + if _, err := toml.DecodeFile(filePath, &m); err != nil { + return loadDeprecatedManifest(filePath) + } + + return &m, nil +} + +func loadDeprecatedManifest(filePath string) (*Manifest, error) { + var m DeprecatedManifest + + _, err := toml.DecodeFile(filePath, &m) + if err != nil { + return nil, err + } + + return m.ToManifest() +} + +func (d *DeprecatedManifest) ToManifest() (*Manifest, error) { + port, err := strconv.ParseUint(d.Port, 10, 64) + if err != nil { + return nil, err + } + + m := Manifest{ + Name: d.Name, + Description: d.Description, + Library: d.Library, + Python: d.Python, + AppFile: d.AppFile, + RequirementsFile: d.RequirementsFile, + Port: uint(port), + CoverImage: d.CoverImage, + Exclude: d.Exclude, + } + + return &m, nil +} + +func FromTool(t tool.Tool) *Manifest { + return &Manifest{ + Name: t.Name, + Description: t.Description, + Library: t.Library.Key, + Python: t.Python, + AppFile: t.AppFile, + RequirementsFile: t.RequirementsFile, + Port: t.Library.Port, + CoverImage: t.CoverImage, + Exclude: []string{"*venv", "venv*", ".git"}, + } +} + +func ManifestExistsInCurrentDir() (bool, error) { + _, err := os.Stat(ManifestPath) + exists := !errors.Is(err, os.ErrNotExist) + + return exists, err +} + +func (m *Manifest) ToToml() (string, error) { + buf := new(bytes.Buffer) + err := toml.NewEncoder(buf).Encode(m) + + return buf.String(), err +} + +func (m *Manifest) ToJSON() (string, error) { + manifest, err := json.Marshal(m) + + return string(manifest), err +} + +// Validates that the app defined in the manifest is valid. Returns false, if +// the app is in a state, where it does not make sense, to be able to push the +// app. +func (m *Manifest) ValidateApp() (bool, error) { + switch m.Library { + case "numerous": + return m.validateNumerousApp() + default: + return true, nil + } +} + +func (m *Manifest) validateNumerousApp() (bool, error) { + data, err := os.ReadFile(m.AppFile) + if err != nil { + return false, err + } + + filecontent := string(data) + if strings.Contains(filecontent, "appdef =") || strings.Contains(filecontent, "class appdef") { + return true, nil + } else { + fmt.Println("Your app file must have an app definition called 'appdef'") + fmt.Println("You can solve this by assigning your app definition to this name, for example:") + fmt.Println("") + fmt.Println("@app") + fmt.Println("class MyApp:") + fmt.Println(" my_field: str") + fmt.Println("") + fmt.Println("appdef = MyApp") + + return false, nil + } +} diff --git a/cli/manifest/manifest_test.go b/cli/manifest/manifest_test.go new file mode 100644 index 00000000..0c75d486 --- /dev/null +++ b/cli/manifest/manifest_test.go @@ -0,0 +1,202 @@ +package manifest + +import ( + "os" + "testing" + + "numerous/cli/test" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +const manifestTOML string = `name = "Tool Name" +description = "A description" +library = "streamlit" +python = "3.11" +app_file = "app.py" +requirements_file = "requirements.txt" +port = 80 +cover_image = "cover.png" +exclude = ["*venv", "venv*"] +` + +const deprecatedTOML string = `name = "Tool Name" +description = "A description" +library = "streamlit" +python = "3.11" +app_file = "app.py" +requirements_file = "requirements.txt" +port = "80" +cover_image = "cover.png" +exclude = ["*venv", "venv*"] +` +const manifestJSON string = `{"name":"Tool Name","description":"A description","library":"streamlit","python":"3.11","app_file":"app.py","requirements_file":"requirements.txt","port":80,"cover_image":"cover.png","exclude":["*venv","venv*"]}` + +type encodeTOMLTestCase struct { + name string + manifest Manifest + expectedTOML string +} + +var streamlitManifest = Manifest{ + Name: "Tool Name", + Description: "A description", + Library: "streamlit", + Python: "3.11", + Port: 80, + AppFile: "app.py", + RequirementsFile: "requirements.txt", + CoverImage: "cover.png", + Exclude: []string{"*venv", "venv*"}, +} + +var encodeTOMLTestCases = []encodeTOMLTestCase{ + { + name: "streamlit app", + manifest: streamlitManifest, + expectedTOML: manifestTOML, + }, +} + +func TestTOMLEncoding(t *testing.T) { + for _, testcase := range encodeTOMLTestCases { + t.Run(testcase.name, func(t *testing.T) { + actual, err := testcase.manifest.ToToml() + require.NoError(t, err) + assert.Equal(t, testcase.expectedTOML, actual) + }) + } +} + +type encodeJSONTestCase struct { + name string + manifest Manifest + expectedJSON string +} + +var encodeJSONTestCases = []encodeJSONTestCase{ + { + name: "streamlit app", + manifest: streamlitManifest, + expectedJSON: manifestJSON, + }, +} + +func TestJSONEncoding(t *testing.T) { + for _, testcase := range encodeJSONTestCases { + t.Run(testcase.name, func(t *testing.T) { + actual, err := testcase.manifest.ToJSON() + require.NoError(t, err) + assert.Equal(t, testcase.expectedJSON, actual) + }) + } +} + +type decodeTOMLTestCase struct { + name string + tomlContent string + expected Manifest +} + +var decodeTOMLTestCases = []decodeTOMLTestCase{ + { + name: "streamlit with deprecated string port", + tomlContent: deprecatedTOML, + expected: streamlitManifest, + }, + { + name: "streamlit", + tomlContent: manifestTOML, + expected: streamlitManifest, + }, +} + +func TestManifestDecodeTOML(t *testing.T) { + for _, testcase := range decodeTOMLTestCases { + t.Run(testcase.name, func(t *testing.T) { + // Save Manifest + filePath := test.WriteTempFile(t, ManifestFileName, []byte(testcase.tomlContent)) + + defer os.Remove(filePath) + + // Decode file + actual, err := LoadManifest(filePath) + require.NoError(t, err) + + if assert.NotNil(t, actual) { + assert.Equal(t, testcase.expected, *actual) + } + }) + } +} + +var numerousAppContentAppdefAssignment string = ` +from numerous import app + +@app +class MyApp: + field: str + +appdef = MyApp +` + +var numerousAppContentAppdefDefinition string = ` +from numerous import app + +@app +class appdef: + field: str +` + +var numerousAppContentWithoutAppdef string = ` +from numerous import app + +@app +class MyApp: + field: str +` + +func TestManifestValidateApp(t *testing.T) { + testCases := []struct { + name string + library string + appfileContent string + expected bool + }{ + { + name: "numerous app with appdef definition succeeds", + library: "numerous", + appfileContent: numerousAppContentAppdefDefinition, + expected: true, + }, + { + name: "numerous app with appdef assignment succeeds", + library: "numerous", + appfileContent: numerousAppContentAppdefAssignment, + expected: true, + }, + { + name: "numerous app without appdef fails", + library: "numerous", + appfileContent: numerousAppContentWithoutAppdef, + expected: false, + }, + { + name: "non-numerous app without appdef succeeds", + library: "streamlit", + appfileContent: `the_content = "does not matter here"`, + expected: true, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + appfile := test.WriteTempFile(t, "appfile.py", []byte(testCase.appfileContent)) + m := Manifest{Library: testCase.library, AppFile: appfile} + validated, err := m.ValidateApp() + assert.NoError(t, err) + assert.Equal(t, testCase.expected, validated) + }) + } +} diff --git a/cli/server/helpers.go b/cli/server/helpers.go new file mode 100644 index 00000000..f89cb0e0 --- /dev/null +++ b/cli/server/helpers.go @@ -0,0 +1,48 @@ +package server + +import ( + "net/http" + "time" + + "github.com/99designs/gqlgen/graphql/handler" + "github.com/99designs/gqlgen/graphql/handler/extension" + "github.com/99designs/gqlgen/graphql/handler/lru" + "github.com/99designs/gqlgen/graphql/handler/transport" + "github.com/gorilla/websocket" +) + +const ( + maxQueryCacheSize = 1000 + maxUploadCacheSize = 100 + keepAlivePingInterval = 10 + maxUploadSize = 1 << 20 // 256MB + maxUploadMemory = 128 << 20 // 128MB +) + +func setServerSettings(srv *handler.Server) { + // similar to NewDefaultServer but with customized websocket + srv.AddTransport(&transport.Websocket{ + Upgrader: websocket.Upgrader{ + CheckOrigin: func(r *http.Request) bool { + return true // TODO: make configurable and update the middleware too + }, + }, + KeepAlivePingInterval: keepAlivePingInterval * time.Second, + }) + + // from NewDefaultServer + srv.AddTransport(transport.Options{}) + srv.AddTransport(transport.GET{}) + srv.AddTransport(transport.POST{}) + srv.AddTransport(transport.MultipartForm{ + MaxUploadSize: maxUploadSize, + MaxMemory: maxUploadMemory, + }) + + srv.SetQueryCache(lru.New(maxQueryCacheSize)) + + srv.Use(extension.Introspection{}) + srv.Use(extension.AutomaticPersistedQuery{ + Cache: lru.New(maxUploadCacheSize), + }) +} diff --git a/cli/server/server.go b/cli/server/server.go new file mode 100644 index 00000000..a34ee61e --- /dev/null +++ b/cli/server/server.go @@ -0,0 +1,68 @@ +package server + +import ( + "fmt" + "log/slog" + "net/http" + "os" + + "numerous/cli/appdev" + "numerous/cli/graphql" + + graphqlHandler "github.com/99designs/gqlgen/graphql/handler" + graphqlPlayground "github.com/99designs/gqlgen/graphql/playground" + "github.com/rs/cors" +) + +type HandlerRegister = func(mux *http.ServeMux) + +type ServerOptions struct { + HTTPPort string + AppSessions appdev.AppSessionRepository + AppSessionService appdev.AppSessionService + Registers []HandlerRegister + GQLPath string + PlaygroundPath string +} + +func CreateServer(opts ServerOptions) *http.Server { + mux := http.NewServeMux() + corsOptions := cors.Options{ + AllowCredentials: true, + AllowedHeaders: []string{"*"}, + Debug: false, + } + handler := cors.New(corsOptions).Handler(mux) + addGraphQLHandlers(opts, mux) + for _, register := range opts.Registers { + register(mux) + } + + return &http.Server{Addr: ":" + opts.HTTPPort, Handler: handler} +} + +func RunServer(server *http.Server) { + if err := server.ListenAndServe(); err != nil { + slog.Error(err.Error()) + os.Exit(1) + } +} + +func addGraphQLHandlers(opts ServerOptions, mux *http.ServeMux) { + cfg := graphql.Config{ + Resolvers: &graphql.Resolver{ + AppSessionsRepo: opts.AppSessions, + ToolSessionService: opts.AppSessionService, + }, + } + + srv := graphqlHandler.New(graphql.NewExecutableSchema(cfg)) + + setServerSettings(srv) + + mux.Handle(opts.PlaygroundPath, graphqlPlayground.Handler("GraphQL playground", opts.GQLPath)) + mux.Handle(opts.GQLPath, srv) + + slog.Info(fmt.Sprintf("Query GraphQL API at http://localhost:%s%s", opts.HTTPPort, opts.GQLPath)) + slog.Info(fmt.Sprintf("Connect to http://localhost:%s%s for GraphQL playground", opts.HTTPPort, opts.PlaygroundPath)) +} diff --git a/cli/test/app_id_document_helper.go b/cli/test/app_id_document_helper.go new file mode 100644 index 00000000..abcb17ed --- /dev/null +++ b/cli/test/app_id_document_helper.go @@ -0,0 +1,19 @@ +package test + +import ( + "os" + "testing" + + "numerous/cli/tool" + + "github.com/stretchr/testify/require" +) + +const appIDFilePerm = 0o644 + +func ChdirToTmpDirWithAppIDDocument(t *testing.T, id string) { + t.Helper() + tmpDir := t.TempDir() + require.NoError(t, os.Chdir(tmpDir)) + require.NoError(t, os.WriteFile(tool.ToolIDFileName, []byte(id), appIDFilePerm)) +} diff --git a/cli/test/generate_jwt.go b/cli/test/generate_jwt.go new file mode 100644 index 00000000..576d9d93 --- /dev/null +++ b/cli/test/generate_jwt.go @@ -0,0 +1,43 @@ +package test + +import ( + "crypto/rand" + "crypto/rsa" + "testing" + "time" + + "github.com/lestrrat-go/jwx/jwa" + "github.com/lestrrat-go/jwx/jwt" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +/* +Generates a JWT + +issued 1 hour before passed in expiration +*/ +func GenerateJWT(t *testing.T, issuer string, expiration time.Time) string { + t.Helper() + // Generate a private key for RS256 + amountOfBits := 2048 + privateKey, err := rsa.GenerateKey(rand.Reader, amountOfBits) + require.NoError(t, err) + + // Create a new token + token := jwt.New() + + // Set standard claims + require.NoError(t, token.Set(jwt.SubjectKey, "123456")) + require.NoError(t, token.Set(jwt.IssuerKey, issuer)) + require.NoError(t, token.Set(jwt.IssuedAtKey, expiration.Add(-time.Hour))) + require.NoError(t, token.Set(jwt.ExpirationKey, expiration)) + + // Sign the token with RS256 algorithm using the private key + signedToken, err := jwt.Sign(token, jwa.RS256, privateKey) + require.NoError(t, err) + tokenString := string(signedToken) + assert.NotEmpty(t, tokenString) + + return tokenString +} diff --git a/cli/test/gql_client.go b/cli/test/gql_client.go new file mode 100644 index 00000000..767059f2 --- /dev/null +++ b/cli/test/gql_client.go @@ -0,0 +1,49 @@ +package test + +import ( + "bytes" + "io" + "net/http" + + "git.sr.ht/~emersion/gqlclient" + "github.com/stretchr/testify/mock" +) + +func CreateTestGqlClient(response string) *gqlclient.Client { + h := http.Header{} + h.Add("Content-Type", "application/json") + + ts := TestTransport{ + WithResponse: &http.Response{ + Header: h, + StatusCode: http.StatusOK, + Body: io.NopCloser(bytes.NewReader([]byte(response))), + }, + } + + return gqlclient.New("http://localhost:8080", &http.Client{Transport: &ts}) +} + +func CreateMockGqlClient(responses ...string) (*gqlclient.Client, *MockTransport) { + ts := MockTransport{} + + for _, response := range responses { + AddResponseToMockGqlClient(response, &ts) + } + + return gqlclient.New("http://localhost:8080", &http.Client{Transport: &ts}), &ts +} + +func AddResponseToMockGqlClient(response string, ts *MockTransport) { + h := http.Header{} + h.Add("Content-Type", "application/json") + + ts.On("RoundTrip", mock.Anything).Once().Return( + &http.Response{ + Header: h, + StatusCode: http.StatusOK, + Body: io.NopCloser(bytes.NewReader([]byte(response))), + }, + nil, + ) +} diff --git a/cli/test/http_transport.go b/cli/test/http_transport.go new file mode 100644 index 00000000..924e1420 --- /dev/null +++ b/cli/test/http_transport.go @@ -0,0 +1,30 @@ +package test + +import ( + "net/http" + + "github.com/stretchr/testify/mock" +) + +// HTTPTransport implements a http.RoundTripper for testing purposes only. +type TestTransport struct { + WithResponse *http.Response + WithError error + Requests []*http.Request +} + +func (t *TestTransport) RoundTrip(req *http.Request) (*http.Response, error) { + t.Requests = append(t.Requests, req) + + return t.WithResponse, t.WithError +} + +type MockTransport struct { + mock.Mock +} + +func (m *MockTransport) RoundTrip(req *http.Request) (*http.Response, error) { + args := m.Called(req) + + return args.Get(0).(*http.Response), args.Error(1) +} diff --git a/cli/test/mocks/authenticator_mock.go b/cli/test/mocks/authenticator_mock.go new file mode 100644 index 00000000..b2e5592b --- /dev/null +++ b/cli/test/mocks/authenticator_mock.go @@ -0,0 +1,59 @@ +package mocks + +import ( + "context" + "net/http" + + "numerous/cli/auth" + + "github.com/stretchr/testify/mock" +) + +type MockAuthenticator struct { + mock.Mock +} + +func (m *MockAuthenticator) GetDeviceCode(ctx context.Context, client *http.Client) (auth.DeviceCodeState, error) { + args := m.Called(ctx, client) + return args.Get(0).(auth.DeviceCodeState), args.Error(1) +} + +func (m *MockAuthenticator) OpenURL(url string) error { + args := m.Called(url) + return args.Error(0) +} + +func (m *MockAuthenticator) WaitUntilUserLogsIn(ctx context.Context, client *http.Client, state auth.DeviceCodeState) (auth.Result, error) { + args := m.Called(ctx, client, state) + return args.Get(0).(auth.Result), args.Error(1) +} + +func (m *MockAuthenticator) StoreAccessToken(token string) error { + args := m.Called(token) + return args.Error(0) +} + +func (m *MockAuthenticator) StoreRefreshToken(token string) error { + args := m.Called(token) + return args.Error(0) +} + +func (m *MockAuthenticator) GetLoggedInUserFromKeyring() *auth.User { + args := m.Called() + return args.Get(0).(*auth.User) +} + +func (m *MockAuthenticator) RegenerateAccessToken(client *http.Client, refreshToken string) (string, error) { + args := m.Called(client, refreshToken) + return args.String(0), args.Error(1) +} + +func (m *MockAuthenticator) RevokeRefreshToken(client *http.Client, refreshToken string) error { + args := m.Called(client, refreshToken) + return args.Error(0) +} + +func (m *MockAuthenticator) RemoveLoggedInUserFromKeyring() error { + args := m.Called() + return args.Error(0) +} diff --git a/cli/test/query_response_helpers.go b/cli/test/query_response_helpers.go new file mode 100644 index 00000000..aebd4cea --- /dev/null +++ b/cli/test/query_response_helpers.go @@ -0,0 +1,105 @@ +package test + +import ( + "fmt" + "time" +) + +func AppToQueryResult(queryName string, a struct { + ID string + Name string + Description string + PublicURL string + SharedURL string + CreatedAt time.Time +}, +) string { + return fmt.Sprintf(`{ + "data": { + "%s": %s + } + }`, queryName, AppToResponse(a)) +} + +func AppToResponse(a struct { + ID string + Name string + Description string + PublicURL string + SharedURL string + CreatedAt time.Time +}, +) string { + description := quoteStringOrNull(a.Description) + sharedURL := quoteStringOrNull(a.SharedURL) + publicURL := quoteStringOrNull(a.PublicURL) + createdAt := a.CreatedAt.Format(time.RFC3339) + + return fmt.Sprintf(`{ + "id": "%s", + "name": "%s", + "description": %s, + "createdAt": "%s", + "publicUrl": %s, + "sharedUrl": %s + }`, a.ID, a.Name, description, createdAt, publicURL, sharedURL) +} + +type Role string + +const ( + Admin Role = "ADMIN" + User Role = "USER" +) + +func OrganizationMembershipToResponse(o struct { + Role Role + Organization struct { + ID string + Name string + Slug string + } +}, +) string { + return fmt.Sprintf(`{ + "role": "%s", + "organization": { + "id": "%s", + "name": "%s", + "slug": "%s" + } + }`, string(o.Role), o.Organization.ID, o.Organization.Name, o.Organization.Slug) +} + +func DeleteSuccessQueryResult() (string, string) { + resultTypename := "ToolDeleteSuccess" + + return fmt.Sprintf(`{ + "data": { + "%s": { + "__typename": "%s", + "result": "%s" + } + } + }`, "toolDelete", resultTypename, "Success"), resultTypename +} + +func DeleteFailureQueryResult(failure string) (string, string) { + resultTypename := "ToolDeleteFailure" + return fmt.Sprintf(`{ + "data": { + "%s": { + "__typename": "%s", + "result": "%s" + } + } + }`, "toolDelete", resultTypename, failure), resultTypename +} + +func quoteStringOrNull(s string) string { + if s != "" { + return fmt.Sprintf(`"%s"`, s) + } + + return "null" +} diff --git a/cli/test/tempfile.go b/cli/test/tempfile.go new file mode 100644 index 00000000..9f7e99f9 --- /dev/null +++ b/cli/test/tempfile.go @@ -0,0 +1,22 @@ +package test + +import ( + "io/fs" + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/require" +) + +var tempFileMode fs.FileMode = 0o644 + +func WriteTempFile(t *testing.T, filename string, content []byte) string { + t.Helper() + + filePath := filepath.Join(t.TempDir(), filename) + err := os.WriteFile(filePath, content, tempFileMode) + require.NoError(t, err) + + return filePath +} diff --git a/cli/tool/library.go b/cli/tool/library.go new file mode 100644 index 00000000..6f05fb09 --- /dev/null +++ b/cli/tool/library.go @@ -0,0 +1,87 @@ +package tool + +import ( + "fmt" +) + +type Library struct { + Name string + Key string + Port uint + Requirements []string +} + +var numerousApp = ` +from numerous import action, app, slider + + +@app +class MyApp: + count: float + step: float = slider(min_value=0, max_value=10) + + @action + def increment(self) -> None: + self.count += self.step + + +appdef = MyApp +` + +func (l *Library) DefaultAppFile() string { + switch l.Key { + case "numerous": + return numerousApp + default: + return "" + } +} + +var ( + streamlitPort uint = 80 + plotyPort uint = 8050 + marimoPort uint = 8000 + numerousPort uint = 7001 +) + +var ( + LibraryStreamlit = Library{Name: "Streamlit", Key: "streamlit", Port: streamlitPort, Requirements: []string{"streamlit"}} + LibraryPlotlyDash = Library{Name: "Plotly-dash", Key: "plotly", Port: plotyPort, Requirements: []string{"dash", "gunicorn"}} + LibraryMarimo = Library{Name: "Marimo", Key: "marimo", Port: marimoPort, Requirements: []string{"marimo"}} + LibraryNumerous = Library{Name: "Numerous", Key: "numerous", Port: numerousPort, Requirements: []string{"numerous"}} +) +var SupportedLibraries = []Library{LibraryStreamlit, LibraryPlotlyDash, LibraryMarimo, LibraryNumerous} + +func GetLibraryByKey(key string) (Library, error) { + for _, library := range SupportedLibraries { + if library.Key == key { + return library, nil + } + } + + return Library{}, unsupportedLibraryError(key) +} + +func GetLibraryByName(name string) (Library, error) { + for _, library := range SupportedLibraries { + if library.Name == name { + return library, nil + } + } + + return Library{}, fmt.Errorf("no library named '%s'", name) +} + +func unsupportedLibraryError(l string) error { + supportedList := SupportedLibraries[0].Key + lastIndex := len(SupportedLibraries[1:]) - 1 + for index, lib := range SupportedLibraries[1:] { + if index == lastIndex { + supportedList = fmt.Sprintf("%s, and %s", supportedList, lib.Key) + } else { + supportedList = fmt.Sprintf("%s, %s", supportedList, lib.Key) + } + } + + return fmt.Errorf("\"%s\" is not a valid app library. \nThe valid options are: %s", l, supportedList) +} diff --git a/cli/tool/library_test.go b/cli/tool/library_test.go new file mode 100644 index 00000000..3f3618c9 --- /dev/null +++ b/cli/tool/library_test.go @@ -0,0 +1,83 @@ +package tool + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestSupportedLibraries(t *testing.T) { + assert.Equal(t, []Library{ + LibraryStreamlit, LibraryPlotlyDash, LibraryMarimo, LibraryNumerous, + }, SupportedLibraries, "unexpected supported libraries - remember to update tests!") +} + +func TestGetLibraryByKey(t *testing.T) { + testCases := []struct { + key string + expected Library + }{ + {key: "streamlit", expected: LibraryStreamlit}, + {key: "numerous", expected: LibraryNumerous}, + {key: "marimo", expected: LibraryMarimo}, + {key: "plotly", expected: LibraryPlotlyDash}, + } + + for _, testCase := range testCases { + t.Run(testCase.key, func(t *testing.T) { + actual, err := GetLibraryByKey(testCase.key) + if assert.NoError(t, err) { + assert.Equal(t, testCase.expected, actual) + } + }) + } + + t.Run("unsupported library error", func(t *testing.T) { + _, err := GetLibraryByKey("unsupported") + if assert.Error(t, err) { + assert.Equal(t, "\"unsupported\" is not a valid app library. \nThe valid options are: streamlit, plotly, marimo, and numerous", err.Error()) + } + }) +} + +func TestGetLibraryByName(t *testing.T) { + testCases := []struct { + name string + expected Library + }{ + {name: "Streamlit", expected: LibraryStreamlit}, + {name: "Numerous", expected: LibraryNumerous}, + {name: "Marimo", expected: LibraryMarimo}, + {name: "Plotly-dash", expected: LibraryPlotlyDash}, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + actual, err := GetLibraryByName(testCase.name) + if assert.NoError(t, err) { + assert.Equal(t, testCase.expected, actual) + } + }) + } + + t.Run("unsupported library error", func(t *testing.T) { + _, err := GetLibraryByName("unsupported") + if assert.Error(t, err) { + assert.Equal(t, "no library named 'unsupported'", err.Error()) + } + }) +} + +func TestDefaultAppFile(t *testing.T) { + testCases := []struct { + library Library + expected string + }{ + {library: LibraryNumerous, expected: numerousApp}, + } + + for _, testCase := range testCases { + actual := testCase.library.DefaultAppFile() + assert.Equal(t, testCase.expected, actual) + } +} diff --git a/cli/tool/tool.go b/cli/tool/tool.go new file mode 100644 index 00000000..3b5f9ec1 --- /dev/null +++ b/cli/tool/tool.go @@ -0,0 +1,57 @@ +package tool + +import ( + "errors" + "fmt" + "os" + "path/filepath" +) + +const ToolIDFileName string = ".tool_id.txt" + +var ErrToolIDNotFound = fmt.Errorf("%s not found", ToolIDFileName) + +type Tool struct { + Name string + Description string + Library Library + Python string + AppFile string + RequirementsFile string + CoverImage string +} + +func ToolIDExistsInCurrentDir(t *Tool, basePath string) (bool, error) { + _, err := os.Stat(filepath.Join(basePath, ToolIDFileName)) + exists := !errors.Is(err, os.ErrNotExist) + + return exists, err +} + +func DeleteTool(basePath string) error { + return os.Remove(filepath.Join(basePath, ToolIDFileName)) +} + +func ReadToolID(basePath string) (string, error) { + toolID, err := os.ReadFile(filepath.Join(basePath, ToolIDFileName)) + if errors.Is(err, os.ErrNotExist) { + return "", ErrToolIDNotFound + } else if err != nil { + return "", err + } + + return string(toolID), nil +} + +func (t Tool) String() string { + return fmt.Sprintf(` +Tool: + name %s + description %s + library %s + python %s + appFile %s + requirementsFile %s + coverImage %s + `, t.Name, t.Description, t.Library.Key, t.Python, t.AppFile, t.RequirementsFile, t.CoverImage) +} diff --git a/cli/tool/tool_test.go b/cli/tool/tool_test.go new file mode 100644 index 00000000..fe0c8850 --- /dev/null +++ b/cli/tool/tool_test.go @@ -0,0 +1,31 @@ +package tool + +import ( + "os" + "path/filepath" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestTool(t *testing.T) { + t.Run("ReadToolID returns toolID if it exists", func(t *testing.T) { + tmpDir := t.TempDir() + path := filepath.Join(tmpDir, ToolIDFileName) + expectedToolID := "tool-id-goes-here" + require.NoError(t, os.WriteFile(path, []byte(expectedToolID), 0o644)) + + actualToolID, err := ReadToolID(tmpDir) + require.NoError(t, err) + assert.Equal(t, expectedToolID, actualToolID) + }) + + t.Run("ReadToolID returns error if tool id document does not exist", func(t *testing.T) { + tmpDir := t.TempDir() + + actualToolID, err := ReadToolID(tmpDir) + require.ErrorIs(t, err, ErrToolIDNotFound) + assert.Equal(t, "", actualToolID) + }) +} diff --git a/examples/numerous/action.py b/examples/numerous/action.py new file mode 100644 index 00000000..b07103ba --- /dev/null +++ b/examples/numerous/action.py @@ -0,0 +1,13 @@ +from numerous import action, app + + +@app +class ActionApp: + count: float + message: str + + @action + def increment(self) -> None: + self.count += 1 + self.message = f"Count now: {self.count}" + print("Incrementing count:", self.count) diff --git a/examples/numerous/container.py b/examples/numerous/container.py new file mode 100644 index 00000000..eef0487d --- /dev/null +++ b/examples/numerous/container.py @@ -0,0 +1,25 @@ +from numerous import action, app, container + + +@container +class MyNestedContainer: + nested_child: float + + +@container +class MyContainer: + child: str + nested: MyNestedContainer + + def child_updated(self) -> None: + print("wow") + + +@app +class MyContainerApp: + my_container: MyContainer + output: str + + @action + def set_output(self) -> None: + self.output = f"First child is {self.my_container.child}, deep child is {self.my_container.nested.nested_child}" diff --git a/examples/numerous/fields.py b/examples/numerous/fields.py new file mode 100644 index 00000000..02cfedca --- /dev/null +++ b/examples/numerous/fields.py @@ -0,0 +1,22 @@ +from numerous import app, field + + +@app +class FieldApp: + field_text_default: str = field() + field_number_default: float = field() + + my_text_field: str = field(label="Text Field Label") + my_number_field: float = field(label="Number Field Label") + + my_text_field_no_label: str = field(default="My text field") + my_number_field_no_label: float = field(default=42.0) + + my_text_field_with_default_value: str = field( + label="Text Field Label", + default="My text field", + ) + my_number_field_with_default_value: float = field( + label="Number Field Label", + default=42.0, + ) diff --git a/examples/numerous/html.py b/examples/numerous/html.py new file mode 100644 index 00000000..fee6a44c --- /dev/null +++ b/examples/numerous/html.py @@ -0,0 +1,32 @@ +from numerous import app, html + +HTML_TEMPLATE = """ +
+ {title}: A HTML story +

+ There once was a mark-up language with which you could create anything you liked. +

+

{story}

+

The end!

+
+""" +DEFAULT_TITLE = "Numerous and the markup" +DEFAULT_STORY = "And then, one day you found numerous to empower it even further!" + + +@app +class HTMLApp: + title: str = DEFAULT_TITLE + story: str = DEFAULT_STORY + html_example: str = html( + default=HTML_TEMPLATE.format(title=DEFAULT_TITLE, story=DEFAULT_STORY), + ) + + def set_html(self) -> None: + self.html_example = HTML_TEMPLATE.format(title=self.title, story=self.story) + + def title_updated(self) -> None: + self.set_html() + + def story_updated(self) -> None: + self.set_html() diff --git a/examples/numerous/importing.py b/examples/numerous/importing.py new file mode 100644 index 00000000..64fe400d --- /dev/null +++ b/examples/numerous/importing.py @@ -0,0 +1 @@ +from parameters import ParameterApp # noqa: F401 diff --git a/examples/numerous/parameters.py b/examples/numerous/parameters.py new file mode 100644 index 00000000..c6f2fb2e --- /dev/null +++ b/examples/numerous/parameters.py @@ -0,0 +1,12 @@ +from numerous import app + + +@app +class ParameterApp: + param1: str + param2: float + output: str + + def param1_updated(self): + print("Got an update:", self.param1) + self.output = f"output: {self.param1}" diff --git a/examples/numerous/plot.py b/examples/numerous/plot.py new file mode 100644 index 00000000..e4fa255d --- /dev/null +++ b/examples/numerous/plot.py @@ -0,0 +1,40 @@ +import math + +from numerous import app, field, slider +from plotly import graph_objects as go + + +@app +class PlotlyExample: + phase_shift: float = slider(default=1, label="Phase Shift") + vertical_shift: float = slider(default=1, label="Vertical Shift") + period: float = slider(default=1, min_value=1, max_value=100, label="Period") + amplitude: float = slider(default=1, label="Amplitude") + graph: go.Figure = field() + + def phase_shift_updated(self): + print("Updated phase shift", self.phase_shift) + self._graph() + + def vertical_shift_updated(self): + print("Updated vertical shift", self.vertical_shift) + self._graph() + + def period_updated(self): + print("Updated period", self.period) + self._graph() + + def amplitude_updated(self): + print("Updated amplitude", self.amplitude) + self._graph() + + def _graph(self): + xs = [i / 10.0 for i in range(1000)] + ys = [self._sin(x) for x in xs] + self.graph = go.Figure(go.Scatter(x=xs, y=ys)) + + def _sin(self, t: float): + b = 2.0 * math.pi / self.period + return ( + self.amplitude * math.sin(b * (t + self.phase_shift)) + self.vertical_shift + ) diff --git a/examples/numerous/sliders.py b/examples/numerous/sliders.py new file mode 100644 index 00000000..61c382a3 --- /dev/null +++ b/examples/numerous/sliders.py @@ -0,0 +1,24 @@ +from numerous import app, slider + + +@app +class SliderApp: + result: float + default_slider: float = slider() + custom_slider: float = slider( + default=10.0, + label="My custom label", + min_value=-20.0, + max_value=20.0, + ) + + def _compute(self): + self.result = self.default_slider * self.custom_slider + + def default_slider_updated(self): + self._compute() + print("default slider updated", self.default_slider, self.result) + + def custom_slider_updated(self): + self._compute() + print("custom slider updated", self.custom_slider, self.result) diff --git a/examples/numerous/syntax.py b/examples/numerous/syntax.py new file mode 100644 index 00000000..984c78e6 --- /dev/null +++ b/examples/numerous/syntax.py @@ -0,0 +1,9 @@ +# mypy: ignore-errors + +from numerous import app + + +@app +class SyntaxErrorApp: + my_syntax_error str # noqa: E999 ] + my_field: str diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 00000000..1fb50b5f --- /dev/null +++ b/poetry.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. +package = [] + +[metadata] +lock-version = "2.0" +python-versions = "*" +content-hash = "115cf985d932e9bf5f540555bbdd75decbb62cac81e399375fc19f6277f8c1d8" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..4d32b47c --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,80 @@ +[build-system] +requires = ["setuptools"] +build-backend = "setuptools.build_meta" + +[project] +name = "numerous" +readme = "README.md" +version = "0.1.0" +classifiers = ["Programming Language :: Python :: 3"] +dependencies = [ + "typing-extensions==4.9.0", + "ariadne-codegen[subscriptions]==0.12.0", + "plotly>4", + "packaging==24.0", +] + +[project.optional-dependencies] +dev = [ + "pre-commit", + "pytest==8.0.2", + "pytest-asyncio==0.23.5", + "ruff", + "mypy==1.8.0", + "coverage==7.4.0", + "twine==5.0.0", + "marimo==0.3.12", + "pydantic==2.7", + "types-setuptools>=69.5.0", + "build==1.2.1", +] + +[project.scripts] +numerous = "numerous.cli:main" + +[tool.setuptools.packages.find] +where = ["python/src"] + +[tool.ruff] +exclude = [ + "./python/src/numerous/generated/", + "./setup.py", + "./python/docs", + "./examples", +] + +[tool.ruff.lint] +select = ["ALL"] +ignore = [ + "ANN101", + "D101", + "D103", + "D107", + "D203", + "D211", + "D212", + "FA100", + "FA102", + "ISC001", + "COM812", +] + +[tool.ruff.lint.extend-per-file-ignores] +"python/tests/**" = ["INP001", "S101", "D100", "D103"] + +[tool.ariadne-codegen] +schema_path = "../shared/schema.gql" +queries_path = "queries.gql" +target_package_name = "graphql" +target_package_path = "src/numerous/generated" + +[tool.mypy] +exclude = ["build", "setup.py", ".*venv.*", "examples"] +ignore_missing_imports = true + +[tool.semantic_release] +branch = "main" +version_toml = ["pyproject.toml:project.version"] + +[tool.semantic_release.remote.token] +env = "GH_TOKEN" diff --git a/python/docs/Makefile b/python/docs/Makefile new file mode 100644 index 00000000..d0c3cbf1 --- /dev/null +++ b/python/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line, and also +# from the environment for the first two. +SPHINXOPTS ?= +SPHINXBUILD ?= sphinx-build +SOURCEDIR = source +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/python/docs/make.bat b/python/docs/make.bat new file mode 100644 index 00000000..747ffb7b --- /dev/null +++ b/python/docs/make.bat @@ -0,0 +1,35 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=sphinx-build +) +set SOURCEDIR=source +set BUILDDIR=build + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The 'sphinx-build' command was not found. Make sure you have Sphinx + echo.installed, then set the SPHINXBUILD environment variable to point + echo.to the full path of the 'sphinx-build' executable. Alternatively you + echo.may add the Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.https://www.sphinx-doc.org/ + exit /b 1 +) + +if "%1" == "" goto help + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% + +:end +popd diff --git a/python/docs/requirements.txt b/python/docs/requirements.txt new file mode 100644 index 00000000..13c143c1 --- /dev/null +++ b/python/docs/requirements.txt @@ -0,0 +1,3 @@ +sphinx==7.2.6 +sphinxcontrib-apidoc==0.5.0 +sphinx-autodoc-typehints==2.0.0 \ No newline at end of file diff --git a/python/docs/source/api/modules.rst b/python/docs/source/api/modules.rst new file mode 100644 index 00000000..7c51ce41 --- /dev/null +++ b/python/docs/source/api/modules.rst @@ -0,0 +1,7 @@ +numerous +======== + +.. toctree:: + :maxdepth: 4 + + numerous diff --git a/python/docs/source/api/numerous.cli.rst b/python/docs/source/api/numerous.cli.rst new file mode 100644 index 00000000..55b0517a --- /dev/null +++ b/python/docs/source/api/numerous.cli.rst @@ -0,0 +1,18 @@ +numerous.cli package +==================== + +Submodules +---------- + +.. toctree:: + :maxdepth: 4 + + numerous.cli.run + +Module contents +--------------- + +.. automodule:: numerous.cli + :members: + :undoc-members: + :show-inheritance: diff --git a/python/docs/source/api/numerous.cli.run.rst b/python/docs/source/api/numerous.cli.run.rst new file mode 100644 index 00000000..3b02bcda --- /dev/null +++ b/python/docs/source/api/numerous.cli.run.rst @@ -0,0 +1,7 @@ +numerous.cli.run module +======================= + +.. automodule:: numerous.cli.run + :members: + :undoc-members: + :show-inheritance: diff --git a/python/docs/source/api/numerous.data_model.rst b/python/docs/source/api/numerous.data_model.rst new file mode 100644 index 00000000..5aa259d1 --- /dev/null +++ b/python/docs/source/api/numerous.data_model.rst @@ -0,0 +1,7 @@ +numerous.data\_model module +=========================== + +.. automodule:: numerous.data_model + :members: + :undoc-members: + :show-inheritance: diff --git a/python/docs/source/api/numerous.generated.graphql.all_elements.rst b/python/docs/source/api/numerous.generated.graphql.all_elements.rst new file mode 100644 index 00000000..bddab4e1 --- /dev/null +++ b/python/docs/source/api/numerous.generated.graphql.all_elements.rst @@ -0,0 +1,7 @@ +numerous.generated.graphql.all\_elements module +=============================================== + +.. automodule:: numerous.generated.graphql.all_elements + :members: + :undoc-members: + :show-inheritance: diff --git a/python/docs/source/api/numerous.generated.graphql.async_base_client.rst b/python/docs/source/api/numerous.generated.graphql.async_base_client.rst new file mode 100644 index 00000000..c2398d25 --- /dev/null +++ b/python/docs/source/api/numerous.generated.graphql.async_base_client.rst @@ -0,0 +1,7 @@ +numerous.generated.graphql.async\_base\_client module +===================================================== + +.. automodule:: numerous.generated.graphql.async_base_client + :members: + :undoc-members: + :show-inheritance: diff --git a/python/docs/source/api/numerous.generated.graphql.base_model.rst b/python/docs/source/api/numerous.generated.graphql.base_model.rst new file mode 100644 index 00000000..75f856be --- /dev/null +++ b/python/docs/source/api/numerous.generated.graphql.base_model.rst @@ -0,0 +1,7 @@ +numerous.generated.graphql.base\_model module +============================================= + +.. automodule:: numerous.generated.graphql.base_model + :members: + :undoc-members: + :show-inheritance: diff --git a/python/docs/source/api/numerous.generated.graphql.client.rst b/python/docs/source/api/numerous.generated.graphql.client.rst new file mode 100644 index 00000000..63f8041c --- /dev/null +++ b/python/docs/source/api/numerous.generated.graphql.client.rst @@ -0,0 +1,7 @@ +numerous.generated.graphql.client module +======================================== + +.. automodule:: numerous.generated.graphql.client + :members: + :undoc-members: + :show-inheritance: diff --git a/python/docs/source/api/numerous.generated.graphql.enums.rst b/python/docs/source/api/numerous.generated.graphql.enums.rst new file mode 100644 index 00000000..e44a4d32 --- /dev/null +++ b/python/docs/source/api/numerous.generated.graphql.enums.rst @@ -0,0 +1,7 @@ +numerous.generated.graphql.enums module +======================================= + +.. automodule:: numerous.generated.graphql.enums + :members: + :undoc-members: + :show-inheritance: diff --git a/python/docs/source/api/numerous.generated.graphql.exceptions.rst b/python/docs/source/api/numerous.generated.graphql.exceptions.rst new file mode 100644 index 00000000..b44df3bd --- /dev/null +++ b/python/docs/source/api/numerous.generated.graphql.exceptions.rst @@ -0,0 +1,7 @@ +numerous.generated.graphql.exceptions module +============================================ + +.. automodule:: numerous.generated.graphql.exceptions + :members: + :undoc-members: + :show-inheritance: diff --git a/python/docs/source/api/numerous.generated.graphql.fragments.rst b/python/docs/source/api/numerous.generated.graphql.fragments.rst new file mode 100644 index 00000000..4128d6e8 --- /dev/null +++ b/python/docs/source/api/numerous.generated.graphql.fragments.rst @@ -0,0 +1,7 @@ +numerous.generated.graphql.fragments module +=========================================== + +.. automodule:: numerous.generated.graphql.fragments + :members: + :undoc-members: + :show-inheritance: diff --git a/python/docs/source/api/numerous.generated.graphql.input_types.rst b/python/docs/source/api/numerous.generated.graphql.input_types.rst new file mode 100644 index 00000000..5dc7320a --- /dev/null +++ b/python/docs/source/api/numerous.generated.graphql.input_types.rst @@ -0,0 +1,7 @@ +numerous.generated.graphql.input\_types module +============================================== + +.. automodule:: numerous.generated.graphql.input_types + :members: + :undoc-members: + :show-inheritance: diff --git a/python/docs/source/api/numerous.generated.graphql.rst b/python/docs/source/api/numerous.generated.graphql.rst new file mode 100644 index 00000000..33568a5a --- /dev/null +++ b/python/docs/source/api/numerous.generated.graphql.rst @@ -0,0 +1,27 @@ +numerous.generated.graphql package +================================== + +Submodules +---------- + +.. toctree:: + :maxdepth: 4 + + numerous.generated.graphql.all_elements + numerous.generated.graphql.async_base_client + numerous.generated.graphql.base_model + numerous.generated.graphql.client + numerous.generated.graphql.enums + numerous.generated.graphql.exceptions + numerous.generated.graphql.fragments + numerous.generated.graphql.input_types + numerous.generated.graphql.update_element + numerous.generated.graphql.updates + +Module contents +--------------- + +.. automodule:: numerous.generated.graphql + :members: + :undoc-members: + :show-inheritance: diff --git a/python/docs/source/api/numerous.generated.graphql.update_element.rst b/python/docs/source/api/numerous.generated.graphql.update_element.rst new file mode 100644 index 00000000..addc56f6 --- /dev/null +++ b/python/docs/source/api/numerous.generated.graphql.update_element.rst @@ -0,0 +1,7 @@ +numerous.generated.graphql.update\_element module +================================================= + +.. automodule:: numerous.generated.graphql.update_element + :members: + :undoc-members: + :show-inheritance: diff --git a/python/docs/source/api/numerous.generated.graphql.updates.rst b/python/docs/source/api/numerous.generated.graphql.updates.rst new file mode 100644 index 00000000..9a719d09 --- /dev/null +++ b/python/docs/source/api/numerous.generated.graphql.updates.rst @@ -0,0 +1,7 @@ +numerous.generated.graphql.updates module +========================================= + +.. automodule:: numerous.generated.graphql.updates + :members: + :undoc-members: + :show-inheritance: diff --git a/python/docs/source/api/numerous.generated.rst b/python/docs/source/api/numerous.generated.rst new file mode 100644 index 00000000..5a3cfc81 --- /dev/null +++ b/python/docs/source/api/numerous.generated.rst @@ -0,0 +1,12 @@ +numerous.generated namespace +============================ + +.. py:module:: numerous.generated + +Subpackages +----------- + +.. toctree:: + :maxdepth: 4 + + numerous.generated.graphql diff --git a/python/docs/source/api/numerous.rst b/python/docs/source/api/numerous.rst new file mode 100644 index 00000000..b7bae216 --- /dev/null +++ b/python/docs/source/api/numerous.rst @@ -0,0 +1,22 @@ +numerous package +================ + +Submodules +---------- + +.. toctree:: + :maxdepth: 4 + + numerous.data_model + numerous.session + numerous.tools + numerous.updates + numerous.utils + +Module contents +--------------- + +.. automodule:: numerous + :members: + :undoc-members: + :show-inheritance: diff --git a/python/docs/source/api/numerous.session.rst b/python/docs/source/api/numerous.session.rst new file mode 100644 index 00000000..898134c6 --- /dev/null +++ b/python/docs/source/api/numerous.session.rst @@ -0,0 +1,7 @@ +numerous.session module +======================= + +.. automodule:: numerous.session + :members: + :undoc-members: + :show-inheritance: diff --git a/python/docs/source/api/numerous.tools.rst b/python/docs/source/api/numerous.tools.rst new file mode 100644 index 00000000..c7bf05ad --- /dev/null +++ b/python/docs/source/api/numerous.tools.rst @@ -0,0 +1,7 @@ +numerous.tools module +===================== + +.. automodule:: numerous.tools + :members: + :undoc-members: + :show-inheritance: diff --git a/python/docs/source/api/numerous.updates.rst b/python/docs/source/api/numerous.updates.rst new file mode 100644 index 00000000..82bedeea --- /dev/null +++ b/python/docs/source/api/numerous.updates.rst @@ -0,0 +1,7 @@ +numerous.updates module +======================= + +.. automodule:: numerous.updates + :members: + :undoc-members: + :show-inheritance: diff --git a/python/docs/source/api/numerous.utils.rst b/python/docs/source/api/numerous.utils.rst new file mode 100644 index 00000000..3de9ef58 --- /dev/null +++ b/python/docs/source/api/numerous.utils.rst @@ -0,0 +1,7 @@ +numerous.utils module +===================== + +.. automodule:: numerous.utils + :members: + :undoc-members: + :show-inheritance: diff --git a/python/docs/source/conf.py b/python/docs/source/conf.py new file mode 100644 index 00000000..a08ad9ac --- /dev/null +++ b/python/docs/source/conf.py @@ -0,0 +1,36 @@ +# Configuration file for the Sphinx documentation builder. +# +# For the full list of built-in configuration values, see the documentation: +# https://www.sphinx-doc.org/en/master/usage/configuration.html + +# -- Project information ----------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information + +project = "numerous SDK" +copyright = "2024, Jens Feodor Nielsen" +author = "Jens Feodor Nielsen" + +# -- General configuration --------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration + +extensions = [ + "sphinx.ext.autodoc", + "sphinx.ext.autosummary", + "sphinxcontrib.apidoc", +] + +templates_path = ["_templates"] +exclude_patterns: list[str] = [] + +# -- Options for HTML output ------------------------------------------------- +# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output + +html_theme = "alabaster" +html_static_path = ["_static"] + +# -- Options for sphinx-contrib/apidoc -------------------------------------- +apidoc_module_dir = "../../src/numerous" +apidoc_output_dir = "api" +apidoc_separate_modules = True +apidoc_extra_args = ["--implicit-namespaces"] +apidoc_excluded_paths = ["cli"] diff --git a/python/docs/source/index.rst b/python/docs/source/index.rst new file mode 100644 index 00000000..1176a424 --- /dev/null +++ b/python/docs/source/index.rst @@ -0,0 +1,16 @@ +numerous SDK reference +=================================================== + +.. toctree:: + :maxdepth: 3 + :caption: SDK API reference + + api/numerous + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/python/examples/experimental/marimo/.ruff.toml b/python/examples/experimental/marimo/.ruff.toml new file mode 100644 index 00000000..d074b986 --- /dev/null +++ b/python/examples/experimental/marimo/.ruff.toml @@ -0,0 +1,3 @@ +exclude = [ + "app.py", +] \ No newline at end of file diff --git a/python/examples/experimental/marimo/README.md b/python/examples/experimental/marimo/README.md new file mode 100644 index 00000000..cd050621 --- /dev/null +++ b/python/examples/experimental/marimo/README.md @@ -0,0 +1,7 @@ +# Marimo and Pydantic Model Example + +This example demonstrates the usage of `numerous.experimental.marimo.Field` in conjunction with `numerous.experimental.model.BaseModel` in a Marimo app. + +To run the app, follow these steps: +1. Install Marimo by executing the command `pip install marimo`. +2. Run the app by executing the command `marimo edit app.py`. \ No newline at end of file diff --git a/python/examples/experimental/marimo/app.py b/python/examples/experimental/marimo/app.py new file mode 100644 index 00000000..20c3b123 --- /dev/null +++ b/python/examples/experimental/marimo/app.py @@ -0,0 +1,109 @@ +# mypy: ignore-errors + +import marimo + +__generated_with = "0.3.12" +app = marimo.App() + + +@app.cell +def __(): + import marimo as mo + return mo, + + +@app.cell +def __(): + from numerous.experimental.marimo import Field + from numerous.experimental.model import BaseModel + return BaseModel, Field + + +@app.cell +def __(BaseModel, Field): + """ + Create your own model by extending the base Model class. This is like defining a pydantic base model. You can use the same arguments for the MoField (short for Marimo Field) as you would normally for the pydantic Field. The exception is that you either need to provide a type as the annotation keyword argument or the type can be inferred from the default value specified as the first argument or the keyword "default". + + The reason for having a dedicated MoField and Model classes and not using pydantic directly is to allow for code completion to work. + + The Model class could be changed to a decorator, but this would lead to a lot of monky-patching and also not give code completion for Numerous related functionality later on. + """ + + class SubModel(BaseModel): + c = Field("c") + return SubModel, + + +@app.cell +def __(BaseModel, Field, SubModel): + """ + You can add models inside other models to create composite models easily. + """ + + class MyModel(BaseModel): + a = Field(1, ge=0, le=5) + b = Field("bla bla", min_length=0, max_length=100) + sub_model = SubModel() + return MyModel, + + +@app.cell +def __(MyModel): + """Instanciate your model as with normal pydantic.""" + my_model = MyModel() + return my_model, + + +@app.cell +def __(my_model): + """ + Each field is part from being a way to define a validation scheme also a Marimo state object. You can use this to make ui controls that respond to changes in the state. + For marimo to detect this state you need to assign it to a global variable. + """ + state_a = my_model.a + return state_a, + + +@app.cell +def __(my_model, state_a): + """Create a slider from the MoField. If you reference the state defined above, marimo will update the slider value based on other UI components making changes to it.""" + state_a + a_slider = my_model.a.slider() + a_slider + return a_slider, + + +@app.cell +def __(my_model, state_a): + """We can also make a number field easily. Try to change it to see the slider also changing above.""" + state_a + a_number = my_model.a.number() + a_number + return a_number, + + +@app.cell +def __(mo, my_model): + """ + Now we are prepared to also sync state with the Numerous platform by since the model is notified of any changes to its data and any changes on the server side can be synchronized with the UI. + + Clicking the button below mimics how Numerous could update your UI with new data from the platform. + """ + + def on_click(event): + my_model.a.value = 0 + + button = mo.ui.button(label="Update a", on_click=on_click) + button + return button, on_click + + +@app.cell +def __(my_model): + """Finally you can access a pydantic model directly if needed. Note updates to this is not reverse synchronized to my_model""" + my_model.pydantic_model + return + + +if __name__ == "__main__": + app.run() diff --git a/python/queries.gql b/python/queries.gql new file mode 100644 index 00000000..397e76c0 --- /dev/null +++ b/python/queries.gql @@ -0,0 +1,93 @@ +fragment ButtonValue on Button { + buttonValue: value +} + +fragment TextFieldValue on TextField { + textValue: value +} + +fragment NumberFieldValue on NumberField { + numberValue: value +} + +fragment SliderValue on SliderElement { + sliderValue: value + minValue + maxValue +} + +fragment HTMLValue on HTMLElement { + html +} + +fragment GraphContext on ElementGraphContext { + parent { + __typename + id + } + affectedBy { + id + } + affects { + id + } +} + +query AllElements($toolSessionId: ID!) { + session: toolSession(id: $toolSessionId) { + id + clientID + all: allElements { + id + name + graphContext { + ...GraphContext + } + ...ButtonValue + ...TextFieldValue + ...NumberFieldValue + ...HTMLValue + ...SliderValue + } + } +} + +mutation UpdateElement( + $sessionID: ID! + $clientID: ID! + $element: ElementInput! +) { + elementUpdate( + toolSessionId: $sessionID + clientId: $clientID + element: $element + ) { + __typename + } +} + +subscription Updates($sessionId: ID!, $clientId: ID!) { + toolSessionEvent(toolSessionId: $sessionId, clientId: $clientId) { + __typename + ... on ToolSessionElementUpdated { + element { + id + name + graphContext { + ...GraphContext + } + ...ButtonValue + ...TextFieldValue + ...NumberFieldValue + ...HTMLValue + ...SliderValue + } + } + ... on ToolSessionActionTriggered { + element { + id + name + } + } + } +} diff --git a/python/src/numerous/__init__.py b/python/src/numerous/__init__.py new file mode 100644 index 00000000..fff070ec --- /dev/null +++ b/python/src/numerous/__init__.py @@ -0,0 +1,5 @@ +"""The python SDK for numerous.""" + +__all__ = ("action", "app", "container", "field", "html", "slider") + +from .apps import action, app, container, field, html, slider diff --git a/python/src/numerous/__main__.py b/python/src/numerous/__main__.py new file mode 100644 index 00000000..a8f38560 --- /dev/null +++ b/python/src/numerous/__main__.py @@ -0,0 +1,50 @@ +"""An entrypoint for creating and running app sessions.""" + +import argparse +import asyncio +import logging +import sys +from pathlib import Path + +from numerous.appdev.commands import ( + read_app, + run_app_session, +) + +log = logging.getLogger(__name__) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + + shared_parser = argparse.ArgumentParser() + shared_parser.add_argument("module_path", type=Path) + shared_parser.add_argument("class_name") + + cmd_parsers = parser.add_subparsers(title="Command", dest="cmd") + read_parser = cmd_parsers.add_parser( + "read", + parents=[shared_parser], + add_help=False, + ) + run_parser = cmd_parsers.add_parser("run", parents=[shared_parser], add_help=False) + run_parser.add_argument("--graphql-url", required=True) + run_parser.add_argument("--graphql-ws-url", required=True) + run_parser.add_argument("session_id") + + ns = parser.parse_args() + + if ns.cmd == "read": + read_app(ns.module_path, ns.class_name) + elif ns.cmd == "run": + coroutine = run_app_session( + ns.graphql_url, + ns.graphql_ws_url, + ns.session_id, + ns.module_path, + ns.class_name, + ) + asyncio.run(coroutine) + else: + print(f"Unsupported command {ns.cmd!r}") # noqa: T201 + sys.exit(1) diff --git a/python/src/numerous/_plotly.py b/python/src/numerous/_plotly.py new file mode 100644 index 00000000..9d3d887c --- /dev/null +++ b/python/src/numerous/_plotly.py @@ -0,0 +1,5 @@ +import plotly.graph_objects as go + + +def plotly_html(figure: go.Figure) -> str: + return figure.to_html(include_plotlyjs="cdn", full_html=False) # type: ignore[no-any-return] diff --git a/python/src/numerous/appdev/__init__.py b/python/src/numerous/appdev/__init__.py new file mode 100644 index 00000000..ebf8da88 --- /dev/null +++ b/python/src/numerous/appdev/__init__.py @@ -0,0 +1 @@ +"""Functionality related to the app development CLI.""" diff --git a/python/src/numerous/appdev/commands.py b/python/src/numerous/appdev/commands.py new file mode 100644 index 00000000..4eec66f4 --- /dev/null +++ b/python/src/numerous/appdev/commands.py @@ -0,0 +1,207 @@ +"""App development CLI command implementations.""" + +import json +import logging +import sys +import traceback +from dataclasses import asdict, dataclass +from pathlib import Path +from textwrap import indent +from typing import Any, Optional, TextIO, Type + +from numerous.data_model import dump_data_model +from numerous.generated.graphql import Client +from numerous.session import Session +from numerous.utils import AppT + +log = logging.getLogger(__name__) + + +@dataclass +class AppNotFoundError(Exception): + app: str + existing_apps: list[str] + + +@dataclass +class AppLoadRaisedError(Exception): + traceback: str + typename: str + + +@dataclass +class AppSyntaxError(Exception): + msg: str + context: str + lineno: int + offset: int + + +def read_app(app_module: Path, app_class: str, output: TextIO = sys.stdout) -> None: + try: + app_cls = _read_app_definition(app_module, app_class) + except Exception as e: # noqa: BLE001 + print_error(output, e) + else: + print_app(output, app_cls) + + +def _transform_lineno(lineno: Optional[int]) -> int: + if lineno is None: + return 0 + return lineno - 2 + + +def _transform_offset(offset: Optional[int]) -> int: + if offset is None: + return 0 + return offset - 4 + + +def _read_app_definition(app_module: Path, app_class: str) -> Any: # noqa: ANN401 + scope: dict[str, Any] = {} + module_text = app_module.read_text() + + # Check for syntax errors with raw code text + try: + compile(module_text, str(app_module), "exec") + except SyntaxError as e: + text = e.text or "" + error_pointer = " " * ((e.offset or 0) - 1) + "^" + + # ensure newline between text and pointer + if not text.endswith("\n"): + text += "\n" + + raise AppSyntaxError( + msg=e.msg, + context=text + error_pointer, + lineno=e.lineno or 0, + offset=e.offset or 0, + ) from e + + indented_module_text = indent(module_text, " ") + exception_handled_module_text = ( + "try:\n" + f"{indented_module_text}\n" + "except ModuleNotFoundError:\n" + " raise\n" + "except BaseException as e:\n" + " __numerous_read_error__ = e\n" + ) + + code = compile(exception_handled_module_text, str(app_module), "exec") + + exec(code, scope) # noqa: S102 + + unknown_error = scope.get("__numerous_read_error__") + if isinstance(unknown_error, BaseException): + tb = traceback.TracebackException.from_exception(unknown_error) + + # handle inserted exception handler offsetting position + for frame in tb.stack: + if frame.filename == str(app_module): + frame.lineno = _transform_lineno(frame.lineno) + if sys.version_info >= (3, 11): + frame.colno = _transform_offset(frame.colno) + frame.end_lineno = _transform_lineno(frame.end_lineno) + frame.end_colno = _transform_offset(frame.end_colno) + + raise AppLoadRaisedError( + typename=type(unknown_error).__name__, + traceback="".join(tb.format()), + ) + + try: + return scope[app_class] + except KeyError as err: + raise AppNotFoundError( + app_class, + [ + app.__name__ + for app in scope.values() + if getattr(app, "__numerous_app__", False) + ], + ) from err + + +def print_app(output: TextIO, cls: Type[AppT]) -> None: + data_model = dump_data_model(cls) + output.write(json.dumps({"app": asdict(data_model)})) + output.flush() + + +def print_error(output: TextIO, error: Exception) -> None: + if isinstance(error, AppNotFoundError): + output.write( + json.dumps( + { + "error": { + "appnotfound": { + "app": error.app, + "found_apps": error.existing_apps, + }, + }, + }, + ), + ) + elif isinstance(error, AppSyntaxError): + output.write( + json.dumps( + { + "error": { + "appsyntax": { + "msg": error.msg, + "context": error.context, + "pos": { + "line": error.lineno, + "offset": error.offset, + }, + }, + }, + }, + ), + ) + output.flush() + elif isinstance(error, ModuleNotFoundError): + output.write( + json.dumps( + { + "error": { + "modulenotfound": { + "module": error.name, + }, + }, + }, + ), + ) + output.flush() + elif isinstance(error, AppLoadRaisedError): + output.write( + json.dumps( + { + "error": { + "unknown": { + "typename": error.typename, + "traceback": error.traceback, + }, + }, + }, + ), + ) + output.flush() + + +async def run_app_session( + graphql_url: str, + graphql_ws_url: str, + session_id: str, + app_module: Path, + app_class: str, +) -> None: + log.info("running %s:%s in session %s", app_module, app_class, session_id) + gql = Client(graphql_url, ws_url=graphql_ws_url) + app_cls = _read_app_definition(app_module, app_class) + session = await Session.initialize(session_id, gql, app_cls) + await session.run() + log.info("app session stopped") diff --git a/python/src/numerous/apps.py b/python/src/numerous/apps.py new file mode 100644 index 00000000..8a2f4c89 --- /dev/null +++ b/python/src/numerous/apps.py @@ -0,0 +1,155 @@ +"""Define applications with a dataclass-like interface.""" + +from dataclasses import dataclass +from types import MappingProxyType +from typing import Any, Callable, Optional, Type, Union, overload + +from typing_extensions import dataclass_transform + +from numerous.utils import MISSING, AppT + + +class HTML: + def __init__(self, default: str) -> None: + self.default = default + + +def html( # type: ignore[no-untyped-def] # noqa: ANN201, PLR0913 + *, + default: str = MISSING, # type: ignore[assignment] + default_factory: Callable[[], str] = MISSING, # type: ignore[assignment] # noqa: ARG001 + init: bool = True, # noqa: ARG001 + repr: bool = True, # noqa: ARG001, A002 + hash: Optional[bool] = None, # noqa: ARG001, A002 + compare: bool = True, # noqa: ARG001 + metadata: Optional[MappingProxyType[str, Any]] = None, # noqa: ARG001 + kw_only: bool = MISSING, # type: ignore[assignment] # noqa: ARG001 +): + return HTML(default) + + +DEFAULT_FLOAT_MIN = 0.0 +DEFAULT_FLOAT_MAX = 100.0 + + +class Slider: + def __init__( # noqa: PLR0913 + self, + *, + default: float = MISSING, # type: ignore[assignment] + default_factory: Callable[[], float] = MISSING, # type: ignore[assignment] # noqa: ARG002 + init: bool = True, # noqa: ARG002 + repr: bool = True, # noqa: ARG002, A002 + hash: Optional[bool] = None, # noqa: ARG002, A002 + compare: bool = True, # noqa: ARG002 + metadata: Optional[MappingProxyType[str, Any]] = None, # noqa: ARG002 + kw_only: bool = MISSING, # type: ignore[assignment] # noqa: ARG002 + label: Optional[str] = None, + min_value: float = DEFAULT_FLOAT_MIN, + max_value: float = DEFAULT_FLOAT_MAX, + ) -> None: + self.default = default + self.label = label + self.min_value = min_value + self.max_value = max_value + + +def slider( # type: ignore[no-untyped-def] # noqa: ANN201, PLR0913 + *, + default: float = MISSING, # type: ignore[assignment] + default_factory: Callable[[], float] = MISSING, # type: ignore[assignment] # noqa: ARG001 + init: bool = True, # noqa: ARG001 + repr: bool = True, # noqa: ARG001, A002 + hash: Optional[bool] = None, # noqa: ARG001, A002 + compare: bool = True, # noqa: ARG001 + metadata: Optional[MappingProxyType[str, Any]] = None, # noqa: ARG001 + kw_only: bool = MISSING, # type: ignore[assignment] # noqa: ARG001 + label: Optional[str] = None, + min_value: float = DEFAULT_FLOAT_MIN, + max_value: float = DEFAULT_FLOAT_MAX, +): + return Slider( + default=default, + label=label, + min_value=min_value, + max_value=max_value, + ) + + +class Field: + def __init__( # noqa: PLR0913 + self, + *, + default: Union[str, float] = MISSING, # type: ignore[assignment] + default_factory: Callable[[], Union[str, float]] = MISSING, # type: ignore[assignment] + init: bool = True, # noqa: ARG002 + repr: bool = True, # noqa: ARG002, A002 + hash: Optional[bool] = None, # noqa: ARG002, A002 + compare: bool = True, # noqa: ARG002 + metadata: Optional[MappingProxyType[str, Any]] = None, # noqa: ARG002 + kw_only: bool = MISSING, # type: ignore[assignment] # noqa: ARG002 + label: Optional[str] = None, + ) -> None: + if default is MISSING and default_factory is not MISSING: # type: ignore[comparison-overlap] + default = default_factory() + self.default = default + self.label = label + + +def field( # type: ignore[no-untyped-def] # noqa: ANN201, PLR0913 + *, + default: Union[str, float] = MISSING, # type: ignore[assignment] + default_factory: Callable[[], float] = MISSING, # type: ignore[assignment] + init: bool = True, # noqa: ARG001 + repr: bool = True, # noqa: ARG001, A002 + hash: Optional[bool] = None, # noqa: ARG001, A002 + compare: bool = True, # noqa: ARG001 + metadata: Optional[MappingProxyType[str, Any]] = None, # noqa: ARG001 + kw_only: bool = MISSING, # type: ignore[assignment] # noqa: ARG001 + label: Optional[str] = None, +): + return Field(default=default, default_factory=default_factory, label=label) + + +@dataclass_transform() +def container(cls: Type[AppT]) -> Type[AppT]: + """Define a container.""" + cls.__container__ = True # type: ignore[attr-defined] + return dataclass(cls) + + +def action(action: Callable[[AppT], Any]) -> Callable[[AppT], Any]: + """Define an action.""" + action.__action__ = True # type: ignore[attr-defined] + return action + + +@overload +def app(cls: Type[AppT]) -> Type[AppT]: ... + + +@overload +def app(title: str = ...) -> Callable[[Type[AppT]], Type[AppT]]: ... + + +def app( + *args: Any, + **kwargs: Any, +) -> Union[Type[AppT], Callable[[Type[AppT]], Type[AppT]]]: + invalid_error_message = "Invalid @app usage" + if len(args) == 1 and not kwargs: + return app_decorator()(args[0]) + if len(args) == 0 and "title" in kwargs: + return app_decorator(**kwargs) + raise ValueError(invalid_error_message) + + +def app_decorator(**kwargs: dict[str, Any]) -> Callable[[Type[AppT]], Type[AppT]]: + @dataclass_transform(field_specifiers=(field, html, slider)) + def decorator(cls: Type[AppT]) -> Type[AppT]: + cls.__numerous_app__ = True # type: ignore[attr-defined] + if title := kwargs.get("title"): + cls.__title__ = title # type: ignore[attr-defined] + return dataclass(cls) + + return decorator diff --git a/python/src/numerous/cli/__init__.py b/python/src/numerous/cli/__init__.py new file mode 100644 index 00000000..3d4e680b --- /dev/null +++ b/python/src/numerous/cli/__init__.py @@ -0,0 +1,5 @@ +"""Contains the numerous CLI wrapper.""" + +from .run import main + +__all__ = ("main",) diff --git a/python/src/numerous/cli/__main__.py b/python/src/numerous/cli/__main__.py new file mode 100644 index 00000000..e8d7563e --- /dev/null +++ b/python/src/numerous/cli/__main__.py @@ -0,0 +1,6 @@ +"""The entrypoint for the numerous CLI.""" + +from .run import main + +if __name__ == "__main__": + main() diff --git a/python/src/numerous/cli/_color.py b/python/src/numerous/cli/_color.py new file mode 100644 index 00000000..3dd97ccb --- /dev/null +++ b/python/src/numerous/cli/_color.py @@ -0,0 +1,48 @@ +from enum import Enum + + +class Color(Enum): + BLACK = 30 + RED = 31 + GREEN = 32 + YELLOW = 33 + BLUE = 34 + MAGENTA = 35 + CYAN = 36 + WHITE = 37 + + +def colorize(color: Color, message: str) -> str: + return f"\033[;{color.value}m{message}\033[0m" + + +def yellow(message: str) -> str: + return colorize(Color.YELLOW, message) + + +def green(message: str) -> str: + return colorize(Color.GREEN, message) + + +def red(message: str) -> str: + return colorize(Color.RED, message) + + +def black(message: str) -> str: + return colorize(Color.BLACK, message) + + +def white(message: str) -> str: + return colorize(Color.WHITE, message) + + +def blue(message: str) -> str: + return colorize(Color.BLUE, message) + + +def magenta(message: str) -> str: + return colorize(Color.MAGENTA, message) + + +def cyan(message: str) -> str: + return colorize(Color.CYAN, message) diff --git a/python/src/numerous/cli/_upgrade.py b/python/src/numerous/cli/_upgrade.py new file mode 100644 index 00000000..93222862 --- /dev/null +++ b/python/src/numerous/cli/_upgrade.py @@ -0,0 +1,115 @@ +import contextlib +import json +import urllib.request +from dataclasses import asdict, dataclass +from datetime import datetime +from importlib.metadata import version as metadata_version +from pathlib import Path +from typing import Any, Optional + +from packaging import version + +from ._color import blue, green + +RESPONSE_STATUS_OK = 200 +SECONDS_IN_5_MIN = 300 + + +@dataclass +class VersionState: + latest_version: Optional[str] = None + last_checked_at: Optional[str] = None + + +def _fetch_data_from_pipy() -> dict[str, Any]: + pipy_url = "https://pypi.org/pypi/numerous/json" + with urllib.request.urlopen(pipy_url) as response: # noqa: S310 + if response.status == RESPONSE_STATUS_OK: + data = response.read() + encoding = response.info().get_content_charset("utf-8") + return json.loads(data.decode(encoding)) # type: ignore[no-any-return] + + message = f"HTTP request failed with status code {response.status}" + raise Exception( # noqa: TRY002 + message, + ) + + +def get_version_from_pipy() -> Optional[str]: + try: + response = _fetch_data_from_pipy() + return response["info"]["version"] # type: ignore[no-any-return] + except: # noqa: E722 + return None + + +def check_for_updates() -> None: + try: + _check_for_updates_internal() + except Exception: # noqa: BLE001 + contextlib.suppress(Exception) + + +def _check_for_updates_internal() -> None: + # Find the state file + state_file = Path(".numerous/state.json") + home_directory = Path.home() + file_path = home_directory / state_file + + # Load the state file or create a default state if it doesn't exist + state: VersionState + try: + with Path.open(file_path) as file: + data = json.load(file) + state = VersionState(**data) + except FileNotFoundError: + state = VersionState() + + # Maybe update the state with the latest version + state = _update_with_latest_version(state) + + if not state.latest_version: + # We couldn't get the latest version, so do nothing + return + + current_version = metadata_version("numerous") + if current_version and version.parse(state.latest_version) > version.parse( + current_version, + ): + upg_str = f"{current_version} → {state.latest_version}" + message = f"Heads up - A newer version of Numerous is available {upg_str}" + print(blue(message)) # noqa: T201 + install_cmd = green("pip install --upgrade numerous") + guide_cmd = f"Please upgrade by running {install_cmd} for the best experience." + print(guide_cmd) # noqa: T201 + print() # noqa: T201 + + _maybe_create_directory(file_path) + with Path.open(file_path, "w") as file: + json.dump(asdict(state), file) + + +def _maybe_create_directory(file_path: Path) -> None: + state_directory = Path(file_path).parent + if not Path.exists(state_directory): + Path.mkdir(state_directory, parents=True) + + +def _update_with_latest_version(state: VersionState) -> VersionState: + if state.last_checked_at: + last_checked_date = datetime.strptime( + state.last_checked_at, + "%Y-%m-%d %H:%M:%S", + ).astimezone() + if (datetime.now().astimezone() - last_checked_date).seconds < SECONDS_IN_5_MIN: + return state + + try: + version = get_version_from_pipy() + state.latest_version = version + state.last_checked_at = ( + datetime.now().astimezone().strftime("%Y-%m-%d %H:%M:%S") + ) + return state # noqa: TRY300 + except Exception: # noqa: BLE001 + return state diff --git a/python/src/numerous/cli/run.py b/python/src/numerous/cli/run.py new file mode 100644 index 00000000..25f861bf --- /dev/null +++ b/python/src/numerous/cli/run.py @@ -0,0 +1,55 @@ +"""Launches the correct binary for the users OS.""" + +import os +import platform +import subprocess +import sys +from pathlib import Path + +from numerous.cli._upgrade import check_for_updates + + +def get_executable_os_name() -> str: + system = platform.system() + if system == "Linux": + return "linux" + if system == "Darwin": + return "darwin" + if os.name == "nt": + return "windows" + + print( # noqa: T201 + f"Sorry but operating system {system} is not currently supported :(", + ) + sys.exit(1) + + +def get_executable_arch_name() -> str: + arch = platform.machine().lower() + if arch in ("x86_64", "amd64"): + return "amd64" + if arch == "arm64": + return "arm64" + print( # noqa: T201 + f"Sorry but architecutre {arch} is not currently supported :(", + ) + sys.exit(1) + + +def get_executable_name() -> str: + return f"build/{get_executable_os_name()}_{get_executable_arch_name()}" + + +def main() -> None: + check_for_updates() + exe_name = get_executable_name() + exe_path = Path(__file__).parent / exe_name + try: + process = subprocess.Popen(args=[str(exe_path)] + sys.argv[1:]) + process.wait() + except KeyboardInterrupt: + process.kill() + + +if __name__ == "__main__": + main() diff --git a/python/src/numerous/data_model.py b/python/src/numerous/data_model.py new file mode 100644 index 00000000..46c4bf36 --- /dev/null +++ b/python/src/numerous/data_model.py @@ -0,0 +1,210 @@ +"""Tool data model for communication.""" + +import inspect +from dataclasses import dataclass +from typing import Any, Optional, Type + +import plotly.graph_objects as go + +from numerous._plotly import plotly_html +from numerous.apps import HTML, Field, Slider +from numerous.utils import MISSING, AppT + + +@dataclass(frozen=True) +class ElementDataModel: + name: str + label: str + + +@dataclass(frozen=True) +class HTMLElementDataModel(ElementDataModel): + default: str + type: str = "html" + + +@dataclass(frozen=True) +class TextFieldDataModel(ElementDataModel): + default: str + type: str = "string" + + +@dataclass(frozen=True) +class NumberFieldDataModel(ElementDataModel): + default: float + type: str = "number" + + +@dataclass(frozen=True) +class PlotlyElementDataModel(ElementDataModel): + default: str + type: str = "html" + + +@dataclass(frozen=True) +class SliderElementDataModel(ElementDataModel): + default: float + slider_min_value: float + slider_max_value: float + type: str = "slider" + + +@dataclass(frozen=True) +class ActionDataModel(ElementDataModel): + type: str = "action" + + +@dataclass(frozen=True) +class ContainerDataModel(ElementDataModel): + elements: list[ElementDataModel] + type: str = "container" + + +@dataclass(frozen=True) +class AppDataModel: + name: str + title: str + elements: list[ElementDataModel] + + +class ToolDataModelError(Exception): + def __init__(self, cls: Type[AppT], name: str, annotation: str) -> None: + super().__init__( + f"Invalid Tool. Unsupport field: {cls.__name__}.{name}: {annotation}", + ) + + +class ToolDefinitionError(Exception): + def __init__(self, cls: Type[AppT]) -> None: + self.cls = cls + super().__init__( + f"Tool {self.cls.__name__} not defined with the @app decorator", + ) + + +def dump_data_model(cls: Type[AppT]) -> AppDataModel: + if not getattr(cls, "__numerous_app__", False): + raise ToolDefinitionError(cls) + + title = getattr(cls, "__title__", cls.__name__) + + return AppDataModel( + name=cls.__name__, + title=title, + elements=_dump_element_data_models(cls), + ) + + +def _dump_element_from_annotation( + name: str, + annotation: Any, # noqa: ANN401 + default: Any, # noqa: ANN401 +) -> Optional[ElementDataModel]: + if annotation is str and ( + data_model := _dump_element_from_str_annotation(name, default) + ): + return data_model + + if annotation is float and ( + data_model := _dump_element_from_float_annotation(name, default) + ): + return data_model + + if annotation is go.Figure: + label = default.label if isinstance(default, Field) else name + default = ( + plotly_html(default.default) + if isinstance(default, Field) and isinstance(default.default, go.Figure) + else "" + ) + return PlotlyElementDataModel(name=name, label=label or name, default=default) + + if getattr(annotation, "__container__", False): + return dump_container_data_model(name, annotation) + + return None + + +def _dump_element_from_float_annotation( + name: str, + default: Any, # noqa: ANN401 +) -> Optional[ElementDataModel]: + if isinstance(default, (float, int)) or default is MISSING: + return NumberFieldDataModel( + name=name, + label=name, + default=float(0.0 if default is MISSING else default), + ) + if isinstance(default, Slider): + default_value = ( + default.min_value + if default.default is MISSING # type: ignore[comparison-overlap] + else default.default + ) + + return SliderElementDataModel( + name=name, + label=default.label if default.label else name, + default=default_value, + slider_min_value=default.min_value, + slider_max_value=default.max_value, + ) + if isinstance(default, Field): + return NumberFieldDataModel( + name=name, + label=default.label if default.label else name, + default=float(0.0 if default.default is MISSING else default.default), # type: ignore[comparison-overlap] + ) + return None + + +def _dump_element_from_str_annotation( + name: str, + default: Any, # noqa: ANN401 +) -> Optional[ElementDataModel]: + if isinstance(default, str) or default is MISSING: + default = "" if default is MISSING else default + return TextFieldDataModel(name=name, label=name, default=default) + if isinstance(default, HTML): + return HTMLElementDataModel(name=name, label=name, default=default.default) + if isinstance(default, Field): + return TextFieldDataModel( + name=name, + label=default.label if default.label else name, + default=str("" if default.default is MISSING else default.default), # type: ignore[comparison-overlap] + ) + return None + + +def _dump_element_data_models(cls: Type[AppT]) -> list[ElementDataModel]: + elements: list[ElementDataModel] = [] + annotations = cls.__annotations__ if hasattr(cls, "__annotations__") else {} + for name, annotation in annotations.items(): + default = getattr(cls, name, MISSING) + if elem := _dump_element_from_annotation(name, annotation, default): + elements.append(elem) + else: + raise ToolDataModelError(cls, name, annotation) + + for name, func in inspect.getmembers(cls, inspect.isfunction): + if getattr(func, "__action__", False): + elements.append(ActionDataModel(name, name)) + + return elements + + +class ContainerDefinitionError(Exception): + def __init__(self, cls: Type[AppT]) -> None: + self.cls = cls + super().__init__( + f"Container {self.cls.__name__} not defined with the @container decorator", + ) + + +def dump_container_data_model(name: str, cls: Type[AppT]) -> ContainerDataModel: + if not getattr(cls, "__container__", False): + raise ContainerDefinitionError(cls) + + elements = _dump_element_data_models(cls) + + return ContainerDataModel(name=name, label=name, elements=elements) diff --git a/python/src/numerous/experimental/__init__.py b/python/src/numerous/experimental/__init__.py new file mode 100644 index 00000000..1baaa437 --- /dev/null +++ b/python/src/numerous/experimental/__init__.py @@ -0,0 +1,8 @@ +""" +Experimental Features. + +The experimental module contains experimental features that are not yet +ready for production use. + +The classes and functions in this module are subject to change without notice. +""" diff --git a/python/src/numerous/experimental/marimo.py b/python/src/numerous/experimental/marimo.py new file mode 100644 index 00000000..6fe84df8 --- /dev/null +++ b/python/src/numerous/experimental/marimo.py @@ -0,0 +1,172 @@ +""" +Marimo Fields. + +The marimo module provides classes and functions for creating fields +specifically useful in marimo apps. + +Marimo is a Python library for building interactive web applications. + +This module contains the `Field` class, which is a field with a state that +can be used in a Marimo app. It also provides utility functions +for creating different types of UI elements such as sliders, +numbers, and text fields. + +""" + +from typing import Any, Dict, Type, TypeVar, Union + +import marimo as mo +from marimo._runtime.state import State as MoState + +from numerous.experimental.model import Field as BaseField + + +def _auto_label(key: str, label: Union[str, None]) -> str: + """ + Automatically assigns a label to a key if the label is None. + + Args: + ---- + key (str): The key to be labeled. + label (str): The label to assign to the key. If None, + the key will be used as the label. + + Returns: + ------- + str: The assigned label. + + """ + if label is None: + label = key + + return label + + +T = TypeVar("T", mo.ui.number, mo.ui.slider) + + +class Field(BaseField, MoState[Union[str, float, int]]): + def __init__( + self, + default: Union[str, float, None] = None, + annotation: Union[type, None] = None, + **kwargs: Dict[str, Any], + ) -> None: + """ + Field with a state that can be used in a Marimo app. + + Args: + ---- + default (str | float, optional): The default value for the field. + Defaults to `...`. + annotation (type | None, optional): The type annotation for the field. + Defaults to None. + **kwargs (dict): Additional keyword arguments for the field. + + """ + BaseField.__init__(self, default=default, annotation=annotation, **kwargs) + MoState.__init__(self, self.value) + + def _number_ui( + self, + ui_cls: Type[T], + step: float = 1, + label: Union[str, None] = None, + ) -> T: + if not hasattr(self, "field_info"): + error_msg = "The field_info attribute is not defined." + raise AttributeError(error_msg) + _min = self.field_info.metadata[0].ge + _max = self.field_info.metadata[1].le + + return ui_cls( + _min, + _max, + value=float(self.get()), + on_change=self.set, + label=_auto_label(self.name, label), + step=step, + ) + + def slider( + self, + step: float = 1, + label: Union[str, None] = None, + ) -> mo.ui.slider: + """ + Create a slider UI element. + + Args: + ---- + step (float, optional): The step size for the slider. Defaults to 1. + label (str | None, optional): The label for the slider. Defaults to None. + Defaults to None. + + Returns: + ------- + mo.ui.slider: The created slider UI element. + + """ + return self._number_ui(mo.ui.slider, step, label) + + def number( + self, + step: float = 1, + label: Union[str, None] = None, + ) -> mo.ui.number: + """ + Create a number UI element. + + Args: + ---- + step (float, optional): The step value for the number UI element. + Defaults to 1. + label (str, optional): The label for the number UI element. + Defaults to None. + + Returns: + ------- + mo.ui.number: The created number UI element. + + """ + number_ui = self._number_ui(mo.ui.number, step, label) + + if isinstance(number_ui, mo.ui.number): + return number_ui + + error_msg = "The number UI element is not an instance of mo.ui.number." + raise TypeError(error_msg) + + def text(self, label: Union[str, None] = None) -> mo.ui.text: + """ + Return a text field widget. + + Args: + ---- + label (str, optional): The label for the text field. Defaults to None. + + Returns: + ------- + mo.ui.text: The text field widget. + + """ + return mo.ui.text( + value=str(self.get()), + on_change=self.set, + label=_auto_label(self.name, label), + ) + + def set(self, value: Any) -> None: # noqa: ANN401 + """ + Set the value of the Marimo object. + + Args: + ---- + value (int | str): The value to be set. It can be an integer or a string. + + Overrides the set method to call the mo state set_value and then calls the super + class's set method. + + """ + self._set_value(value) + super().set(value) diff --git a/python/src/numerous/experimental/model.py b/python/src/numerous/experimental/model.py new file mode 100644 index 00000000..5f1d3aeb --- /dev/null +++ b/python/src/numerous/experimental/model.py @@ -0,0 +1,372 @@ +""" +The model module. + +The module defines a `BaseModel` class that dynamically creates +a Pydantic model based on the declared fields and interfaces +in the subclass. + +It leverages Pydantic's `create_model` function to handle validation and +type enforcement. + +The `BaseModel` class provides methods to initialize the model, +retrieve the validated data, +and access the dynamically created Pydantic model object. +Additionally, the module defines a `Field` class that represents a field +in the model. + +The `Field` class handles default values, +type annotations, and other properties of the field. + +Classes: +- BaseModel: Class representing a generic model that integrates with + Pydantic for data validation. +- Field: Class representing a field in the model. +""" + +from typing import Any, Dict, Tuple, Union + +from pydantic import BaseModel as PydanticBaseModel +from pydantic import Field as PydanticField +from pydantic import create_model + + +class _ModelInterface: + """Interface for a model object.""" + + _name: str + + @property + def model_attrs(self) -> Tuple[Any, PydanticBaseModel]: + """ + Return the model attributes. + + Returns + ------- + tuple + A tuple containing the model attributes. + + """ + raise NotImplementedError + + @property + def value(self) -> PydanticBaseModel: + """ + Return the model value. + + Returns + ------- + PydanticBaseModel + The model value. + + """ + raise NotImplementedError + + +class BaseModel(_ModelInterface): + """ + Class representing a generic model that use with Pydantic for data validation. + + This class constructs a Pydantic model dynamically based on the declared fields and + interfaces in the class. It leverages Pydantic's `create_model` function to handle + validation and type enforcement. + + Attributes + ---------- + pydantic_model_cls : PydanticBaseModel + Dynamically created Pydantic model class based on the fields + defined in the subclass. + _fields : dict + A dictionary mapping field names to Field or _ModelInterface instances, + representing the attributes of the model. + + Methods + ------- + __init__(**kwargs) + Initializes the model by creating a Pydantic model and validating + the input fields. + value() + Returns the Pydantic model instance containing validated data. + model_attrs() + Returns attributes of the dynamically created Pydantic model class. + pydantic_model() + Returns an instance of the dynamically created Pydantic model + containing validated data. + + """ + + def __init__(self, **kwargs: Dict[str, Any]) -> None: + """ + Initialize a model object with the given fields. + + Args: + ---- + **kwargs (dict): Keyword arguments representing the field values. + + """ + _attrs = {} + for key, val in self.__class__.__dict__.items(): + # Find all the fields in the class + if isinstance(val, Field): + _attrs[key] = val.field_attrs + elif isinstance(val, _ModelInterface): + # If the field is a subclass of Model, get the model attributes + _attrs[key] = val.model_attrs + + # Create a Pydantic model class with the fields + self.pydantic_model_cls = create_model(self.__class__.__name__, **_attrs) # type: ignore[call-overload] + + # Set them as values to Field objects + for key, val in kwargs.items(): + getattr(self, key)._field_value = val # noqa: SLF001 + + self._fields = {} + for key, val in self.__class__.__dict__.items(): + # Find all the fields in the class + if isinstance(val, (Field, _ModelInterface)): + val._name = key # noqa: SLF001 + self._fields[key] = val + + # Check if any non-optional fields are missing a value + for val in self._fields.values(): + # By accessing the value property, the value is checked for validity + _ = val.value + # Add self as the parent model. + # This is used to validate the model when a field is changed + val._parent_model = self # noqa: SLF001 + + # Trigger a validation of the model by accessing the value property + _ = self.pydantic_model + + @property + def value(self) -> PydanticBaseModel: + """ + Return the PydanticBaseModel instance associated with this object. + + Returns + ------- + PydanticBaseModel + The PydanticBaseModel instance. + + """ + return self.pydantic_model + + @property + def model_attrs(self) -> Tuple[Any, PydanticBaseModel]: + """ + Return the data required to create a Pydantic model object. + + Returns + ------- + tuple + A tuple containing the type of the Pydantic model + and the model object itself. + + """ + return (type(self.pydantic_model), self.pydantic_model) + + @property + def pydantic_model(self) -> PydanticBaseModel: + """ + Get a Pydantic model object representing the model. + + Returns + ------- + BaseModel + The Pydantic model object with the values from the current model. + + """ + _kwargs = {} + + # Get the values from the fields + for key, val in self._fields.items(): + _kwargs[key] = val.value + + # Create a Pydantic model object with the values + pydantic_model = self.pydantic_model_cls(**_kwargs) + if isinstance(pydantic_model, PydanticBaseModel): + return pydantic_model + + error_msg = "Invalid Pydantic model object." + raise TypeError(error_msg) + + +class Field: + def __init__( + self, + default: Union[str, float, None] = None, + annotation: Union[type, None] = None, + **kwargs: Dict[str, Any], + ) -> None: + """ + Initialize a Field object. + + Parameters + ---------- + default : str or float or None, optional + The default value for the field, by default ... + annotation : type or None, optional + The type annotation for the field, by default None + **kwargs : dict + Additional properties for the field. + + """ + self._default = default + self._props = kwargs + self._default = default + self._field_value = default + self._name: Union[str, None] = None + self._parent_model = None + + # Check if the annotation is provided if the default value is None + if annotation is None and default is None: + error_msg = "Annotation must be provided if value is None" + raise ValueError(error_msg) + + # Set the annotation to the type of the default value if it is not provided + self._annotation = annotation if annotation is not None else type(default) + + @property + def name(self) -> str: + """ + Returns the name of the field. + + Raises + ------ + ValueError + If the name has not been set. + + Returns + ------- + str + The name of the field. + + """ + if self._name is None: + error_msg = "Name has not been set" + raise ValueError(error_msg) + return self._name + + @name.setter + def name(self, name: str) -> None: + """ + Set the name of the field. + + Parameters + ---------- + name : str + The name of the field. + + Raises + ------ + ValueError + If the name has already been set. + + """ + if self._name is not None: + error_msg = "Name has already been set" + raise ValueError(error_msg) + self._name = name + + @property + def field_attrs(self) -> Tuple[type, Any]: + """ + Get the attributes of the field. + + Returns + ------- + tuple + A tuple containing the value and type annotation of the field, + along with other properties. + + """ + return (self._annotation, self.field_info) + + @property + def field_info(self) -> Any: # noqa: ANN401 + """ + Get the field information. + + Returns + ------- + tuple + A tuple containing the Pydantic Field object with the value and properties. + + """ + # Create a Pydantic Field object with the value and properties + self._field_info = PydanticField(self._default, **self._props) # type: ignore[arg-type] + return self._field_info + + @property + def value(self) -> Union[str, float]: + """ + Return the value of the object. + + Returns + ------- + str or float + The value of the object. + + """ + return self.get() + + @value.setter + def value(self, value: Union[str, float]) -> None: + """ + Set the value of the object. + + Parameters + ---------- + value : str or float + The new value to be set. + + """ + self.set(value) + + def get(self) -> Union[str, float]: + """ + Get the value of the field. + + Returns + ------- + str or float + The value of the model. + + Raises + ------ + ValueError + If the value has not been set. + + """ + if self._field_value is None: + error_msg = "Value has not been set" + raise ValueError(error_msg) + return self._field_value + + def set(self, value: Any) -> None: # noqa: ANN401 + """ + Set the value of the field. + + Parameters + ---------- + value : str or float + The new value to be set. + + Raises + ------ + Exception + If the parent model validation fails. + + """ + old_value = self._field_value + self._field_value = value + if self._parent_model is None: + error_msg = "Parent model has not been set" + raise ValueError(error_msg) + try: + # Trigger the parent model validation + _ = self._parent_model.value + except: + # If the validation fails, revert the value + self._field_value = old_value + # Raise the error + raise diff --git a/python/src/numerous/generated/graphql/__init__.py b/python/src/numerous/generated/graphql/__init__.py new file mode 100644 index 00000000..a325fe08 --- /dev/null +++ b/python/src/numerous/generated/graphql/__init__.py @@ -0,0 +1,133 @@ +# Generated by ariadne-codegen + +from .all_elements import ( + AllElements, + AllElementsSession, + AllElementsSessionAllButton, + AllElementsSessionAllButtonGraphContext, + AllElementsSessionAllElement, + AllElementsSessionAllElementGraphContext, + AllElementsSessionAllHTMLElement, + AllElementsSessionAllHTMLElementGraphContext, + AllElementsSessionAllNumberField, + AllElementsSessionAllNumberFieldGraphContext, + AllElementsSessionAllSliderElement, + AllElementsSessionAllSliderElementGraphContext, + AllElementsSessionAllTextField, + AllElementsSessionAllTextFieldGraphContext, +) +from .async_base_client import AsyncBaseClient +from .base_model import BaseModel, Upload +from .client import Client +from .enums import AuthRole, Role, ToolHashType +from .exceptions import ( + GraphQLClientError, + GraphQLClientGraphQLError, + GraphQLClientGraphQLMultiError, + GraphQLClientHttpError, + GraphQLClientInvalidResponseError, +) +from .fragments import ( + ButtonValue, + GraphContext, + GraphContextAffectedBy, + GraphContextAffects, + GraphContextParent, + HTMLValue, + NumberFieldValue, + SliderValue, + TextFieldValue, +) +from .input_types import ( + ElementInput, + ElementSelectInput, + ListElementInput, + NewOrganization, + NewTool, + OrganizationInvitationInput, +) +from .update_element import UpdateElement, UpdateElementElementUpdate +from .updates import ( + Updates, + UpdatesToolSessionEventToolSessionActionTriggered, + UpdatesToolSessionEventToolSessionActionTriggeredElement, + UpdatesToolSessionEventToolSessionElementAdded, + UpdatesToolSessionEventToolSessionElementRemoved, + UpdatesToolSessionEventToolSessionElementUpdated, + UpdatesToolSessionEventToolSessionElementUpdatedElementButton, + UpdatesToolSessionEventToolSessionElementUpdatedElementButtonGraphContext, + UpdatesToolSessionEventToolSessionElementUpdatedElementElement, + UpdatesToolSessionEventToolSessionElementUpdatedElementElementGraphContext, + UpdatesToolSessionEventToolSessionElementUpdatedElementHTMLElement, + UpdatesToolSessionEventToolSessionElementUpdatedElementHTMLElementGraphContext, + UpdatesToolSessionEventToolSessionElementUpdatedElementNumberField, + UpdatesToolSessionEventToolSessionElementUpdatedElementNumberFieldGraphContext, + UpdatesToolSessionEventToolSessionElementUpdatedElementSliderElement, + UpdatesToolSessionEventToolSessionElementUpdatedElementSliderElementGraphContext, + UpdatesToolSessionEventToolSessionElementUpdatedElementTextField, + UpdatesToolSessionEventToolSessionElementUpdatedElementTextFieldGraphContext, +) + +__all__ = [ + "AllElements", + "AllElementsSession", + "AllElementsSessionAllButton", + "AllElementsSessionAllButtonGraphContext", + "AllElementsSessionAllElement", + "AllElementsSessionAllElementGraphContext", + "AllElementsSessionAllHTMLElement", + "AllElementsSessionAllHTMLElementGraphContext", + "AllElementsSessionAllNumberField", + "AllElementsSessionAllNumberFieldGraphContext", + "AllElementsSessionAllSliderElement", + "AllElementsSessionAllSliderElementGraphContext", + "AllElementsSessionAllTextField", + "AllElementsSessionAllTextFieldGraphContext", + "AsyncBaseClient", + "AuthRole", + "BaseModel", + "ButtonValue", + "Client", + "ElementInput", + "ElementSelectInput", + "GraphContext", + "GraphContextAffectedBy", + "GraphContextAffects", + "GraphContextParent", + "GraphQLClientError", + "GraphQLClientGraphQLError", + "GraphQLClientGraphQLMultiError", + "GraphQLClientHttpError", + "GraphQLClientInvalidResponseError", + "HTMLValue", + "ListElementInput", + "NewOrganization", + "NewTool", + "NumberFieldValue", + "OrganizationInvitationInput", + "Role", + "SliderValue", + "TextFieldValue", + "ToolHashType", + "UpdateElement", + "UpdateElementElementUpdate", + "Updates", + "UpdatesToolSessionEventToolSessionActionTriggered", + "UpdatesToolSessionEventToolSessionActionTriggeredElement", + "UpdatesToolSessionEventToolSessionElementAdded", + "UpdatesToolSessionEventToolSessionElementRemoved", + "UpdatesToolSessionEventToolSessionElementUpdated", + "UpdatesToolSessionEventToolSessionElementUpdatedElementButton", + "UpdatesToolSessionEventToolSessionElementUpdatedElementButtonGraphContext", + "UpdatesToolSessionEventToolSessionElementUpdatedElementElement", + "UpdatesToolSessionEventToolSessionElementUpdatedElementElementGraphContext", + "UpdatesToolSessionEventToolSessionElementUpdatedElementHTMLElement", + "UpdatesToolSessionEventToolSessionElementUpdatedElementHTMLElementGraphContext", + "UpdatesToolSessionEventToolSessionElementUpdatedElementNumberField", + "UpdatesToolSessionEventToolSessionElementUpdatedElementNumberFieldGraphContext", + "UpdatesToolSessionEventToolSessionElementUpdatedElementSliderElement", + "UpdatesToolSessionEventToolSessionElementUpdatedElementSliderElementGraphContext", + "UpdatesToolSessionEventToolSessionElementUpdatedElementTextField", + "UpdatesToolSessionEventToolSessionElementUpdatedElementTextFieldGraphContext", + "Upload", +] diff --git a/python/src/numerous/generated/graphql/all_elements.py b/python/src/numerous/generated/graphql/all_elements.py new file mode 100644 index 00000000..46de227e --- /dev/null +++ b/python/src/numerous/generated/graphql/all_elements.py @@ -0,0 +1,118 @@ +# Generated by ariadne-codegen +# Source: queries.gql + +from typing import Annotated, List, Literal, Union + +from pydantic import Field + +from .base_model import BaseModel +from .fragments import ( + ButtonValue, + GraphContext, + HTMLValue, + NumberFieldValue, + SliderValue, + TextFieldValue, +) + + +class AllElements(BaseModel): + session: "AllElementsSession" + + +class AllElementsSession(BaseModel): + id: str + client_id: str = Field(alias="clientID") + all: List[ + Annotated[ + Union[ + "AllElementsSessionAllElement", + "AllElementsSessionAllButton", + "AllElementsSessionAllHTMLElement", + "AllElementsSessionAllNumberField", + "AllElementsSessionAllSliderElement", + "AllElementsSessionAllTextField", + ], + Field(discriminator="typename__"), + ] + ] + + +class AllElementsSessionAllElement(BaseModel): + typename__: Literal["Container", "Element", "ElementList", "ElementSelect"] = Field( + alias="__typename" + ) + id: str + name: str + graph_context: "AllElementsSessionAllElementGraphContext" = Field( + alias="graphContext" + ) + + +class AllElementsSessionAllElementGraphContext(GraphContext): + pass + + +class AllElementsSessionAllButton(ButtonValue): + typename__: Literal["Button"] = Field(alias="__typename") + id: str + name: str + graph_context: "AllElementsSessionAllButtonGraphContext" = Field( + alias="graphContext" + ) + + +class AllElementsSessionAllButtonGraphContext(GraphContext): + pass + + +class AllElementsSessionAllHTMLElement(HTMLValue): + typename__: Literal["HTMLElement"] = Field(alias="__typename") + id: str + name: str + graph_context: "AllElementsSessionAllHTMLElementGraphContext" = Field( + alias="graphContext" + ) + + +class AllElementsSessionAllHTMLElementGraphContext(GraphContext): + pass + + +class AllElementsSessionAllNumberField(NumberFieldValue): + typename__: Literal["NumberField"] = Field(alias="__typename") + id: str + name: str + graph_context: "AllElementsSessionAllNumberFieldGraphContext" = Field( + alias="graphContext" + ) + + +class AllElementsSessionAllNumberFieldGraphContext(GraphContext): + pass + + +class AllElementsSessionAllSliderElement(SliderValue): + typename__: Literal["SliderElement"] = Field(alias="__typename") + id: str + name: str + graph_context: "AllElementsSessionAllSliderElementGraphContext" = Field( + alias="graphContext" + ) + + +class AllElementsSessionAllSliderElementGraphContext(GraphContext): + pass + + +class AllElementsSessionAllTextField(TextFieldValue): + typename__: Literal["TextField"] = Field(alias="__typename") + id: str + name: str + graph_context: "AllElementsSessionAllTextFieldGraphContext" = Field( + alias="graphContext" + ) + + +class AllElementsSessionAllTextFieldGraphContext(GraphContext): + pass diff --git a/python/src/numerous/generated/graphql/async_base_client.py b/python/src/numerous/generated/graphql/async_base_client.py new file mode 100644 index 00000000..311e672a --- /dev/null +++ b/python/src/numerous/generated/graphql/async_base_client.py @@ -0,0 +1,372 @@ +# Generated by ariadne-codegen + +import enum +import json +from typing import IO, Any, AsyncIterator, Dict, List, Optional, Tuple, TypeVar, cast +from uuid import uuid4 + +import httpx +from pydantic import BaseModel +from pydantic_core import to_jsonable_python + +from .base_model import UNSET, Upload +from .exceptions import ( + GraphQLClientGraphQLMultiError, + GraphQLClientHttpError, + GraphQLClientInvalidMessageFormat, + GraphQLClientInvalidResponseError, +) + +try: + from websockets.client import ( # type: ignore[import-not-found,unused-ignore] + WebSocketClientProtocol, + connect as ws_connect, + ) + from websockets.typing import ( # type: ignore[import-not-found,unused-ignore] + Data, + Origin, + Subprotocol, + ) +except ImportError: + from contextlib import asynccontextmanager + + @asynccontextmanager # type: ignore + async def ws_connect(*args, **kwargs): # pylint: disable=unused-argument + raise NotImplementedError("Subscriptions require 'websockets' package.") + yield # pylint: disable=unreachable + + WebSocketClientProtocol = Any # type: ignore[misc,assignment,unused-ignore] + Data = Any # type: ignore[misc,assignment,unused-ignore] + Origin = Any # type: ignore[misc,assignment,unused-ignore] + + def Subprotocol(*args, **kwargs): # type: ignore # pylint: disable=invalid-name + raise NotImplementedError("Subscriptions require 'websockets' package.") + + +Self = TypeVar("Self", bound="AsyncBaseClient") + +GRAPHQL_TRANSPORT_WS = "graphql-transport-ws" + + +class GraphQLTransportWSMessageType(str, enum.Enum): + CONNECTION_INIT = "connection_init" + CONNECTION_ACK = "connection_ack" + PING = "ping" + PONG = "pong" + SUBSCRIBE = "subscribe" + NEXT = "next" + ERROR = "error" + COMPLETE = "complete" + + +class AsyncBaseClient: + def __init__( + self, + url: str = "", + headers: Optional[Dict[str, str]] = None, + http_client: Optional[httpx.AsyncClient] = None, + ws_url: str = "", + ws_headers: Optional[Dict[str, Any]] = None, + ws_origin: Optional[str] = None, + ws_connection_init_payload: Optional[Dict[str, Any]] = None, + ) -> None: + self.url = url + self.headers = headers + self.http_client = ( + http_client if http_client else httpx.AsyncClient(headers=headers) + ) + + self.ws_url = ws_url + self.ws_headers = ws_headers or {} + self.ws_origin = Origin(ws_origin) if ws_origin else None + self.ws_connection_init_payload = ws_connection_init_payload + + async def __aenter__(self: Self) -> Self: + return self + + async def __aexit__( + self, + exc_type: object, + exc_val: object, + exc_tb: object, + ) -> None: + await self.http_client.aclose() + + async def execute( + self, + query: str, + operation_name: Optional[str] = None, + variables: Optional[Dict[str, Any]] = None, + **kwargs: Any, + ) -> httpx.Response: + processed_variables, files, files_map = self._process_variables(variables) + + if files and files_map: + return await self._execute_multipart( + query=query, + operation_name=operation_name, + variables=processed_variables, + files=files, + files_map=files_map, + **kwargs, + ) + + return await self._execute_json( + query=query, + operation_name=operation_name, + variables=processed_variables, + **kwargs, + ) + + def get_data(self, response: httpx.Response) -> Dict[str, Any]: + if not response.is_success: + raise GraphQLClientHttpError( + status_code=response.status_code, response=response + ) + + try: + response_json = response.json() + except ValueError as exc: + raise GraphQLClientInvalidResponseError(response=response) from exc + + if (not isinstance(response_json, dict)) or ( + "data" not in response_json and "errors" not in response_json + ): + raise GraphQLClientInvalidResponseError(response=response) + + data = response_json.get("data") + errors = response_json.get("errors") + + if errors: + raise GraphQLClientGraphQLMultiError.from_errors_dicts( + errors_dicts=errors, data=data + ) + + return cast(Dict[str, Any], data) + + async def execute_ws( + self, + query: str, + operation_name: Optional[str] = None, + variables: Optional[Dict[str, Any]] = None, + **kwargs: Any, + ) -> AsyncIterator[Dict[str, Any]]: + headers = self.ws_headers.copy() + headers.update(kwargs.get("extra_headers", {})) + + merged_kwargs: Dict[str, Any] = {"origin": self.ws_origin} + merged_kwargs.update(kwargs) + merged_kwargs["extra_headers"] = headers + + operation_id = str(uuid4()) + async with ws_connect( + self.ws_url, + subprotocols=[Subprotocol(GRAPHQL_TRANSPORT_WS)], + **merged_kwargs, + ) as websocket: + await self._send_connection_init(websocket) + # wait for connection_ack from server + await self._handle_ws_message( + await websocket.recv(), + websocket, + expected_type=GraphQLTransportWSMessageType.CONNECTION_ACK, + ) + await self._send_subscribe( + websocket, + operation_id=operation_id, + query=query, + operation_name=operation_name, + variables=variables, + ) + + async for message in websocket: + data = await self._handle_ws_message(message, websocket) + if data: + yield data + + def _process_variables( + self, variables: Optional[Dict[str, Any]] + ) -> Tuple[ + Dict[str, Any], Dict[str, Tuple[str, IO[bytes], str]], Dict[str, List[str]] + ]: + if not variables: + return {}, {}, {} + + serializable_variables = self._convert_dict_to_json_serializable(variables) + return self._get_files_from_variables(serializable_variables) + + def _convert_dict_to_json_serializable( + self, dict_: Dict[str, Any] + ) -> Dict[str, Any]: + return { + key: self._convert_value(value) + for key, value in dict_.items() + if value is not UNSET + } + + def _convert_value(self, value: Any) -> Any: + if isinstance(value, BaseModel): + return value.model_dump(by_alias=True, exclude_unset=True) + if isinstance(value, list): + return [self._convert_value(item) for item in value] + return value + + def _get_files_from_variables( + self, variables: Dict[str, Any] + ) -> Tuple[ + Dict[str, Any], Dict[str, Tuple[str, IO[bytes], str]], Dict[str, List[str]] + ]: + files_map: Dict[str, List[str]] = {} + files_list: List[Upload] = [] + + def separate_files(path: str, obj: Any) -> Any: + if isinstance(obj, list): + nulled_list = [] + for index, value in enumerate(obj): + value = separate_files(f"{path}.{index}", value) + nulled_list.append(value) + return nulled_list + + if isinstance(obj, dict): + nulled_dict = {} + for key, value in obj.items(): + value = separate_files(f"{path}.{key}", value) + nulled_dict[key] = value + return nulled_dict + + if isinstance(obj, Upload): + if obj in files_list: + file_index = files_list.index(obj) + files_map[str(file_index)].append(path) + else: + file_index = len(files_list) + files_list.append(obj) + files_map[str(file_index)] = [path] + return None + + return obj + + nulled_variables = separate_files("variables", variables) + files: Dict[str, Tuple[str, IO[bytes], str]] = { + str(i): (file_.filename, cast(IO[bytes], file_.content), file_.content_type) + for i, file_ in enumerate(files_list) + } + return nulled_variables, files, files_map + + async def _execute_multipart( + self, + query: str, + operation_name: Optional[str], + variables: Dict[str, Any], + files: Dict[str, Tuple[str, IO[bytes], str]], + files_map: Dict[str, List[str]], + **kwargs: Any, + ) -> httpx.Response: + data = { + "operations": json.dumps( + { + "query": query, + "operationName": operation_name, + "variables": variables, + }, + default=to_jsonable_python, + ), + "map": json.dumps(files_map, default=to_jsonable_python), + } + + return await self.http_client.post( + url=self.url, data=data, files=files, **kwargs + ) + + async def _execute_json( + self, + query: str, + operation_name: Optional[str], + variables: Dict[str, Any], + **kwargs: Any, + ) -> httpx.Response: + headers: Dict[str, str] = {"Content-Type": "application/json"} + headers.update(kwargs.get("headers", {})) + + merged_kwargs: Dict[str, Any] = kwargs.copy() + merged_kwargs["headers"] = headers + + return await self.http_client.post( + url=self.url, + content=json.dumps( + { + "query": query, + "operationName": operation_name, + "variables": variables, + }, + default=to_jsonable_python, + ), + **merged_kwargs, + ) + + async def _send_connection_init(self, websocket: WebSocketClientProtocol) -> None: + payload: Dict[str, Any] = { + "type": GraphQLTransportWSMessageType.CONNECTION_INIT.value + } + if self.ws_connection_init_payload: + payload["payload"] = self.ws_connection_init_payload + await websocket.send(json.dumps(payload)) + + async def _send_subscribe( + self, + websocket: WebSocketClientProtocol, + operation_id: str, + query: str, + operation_name: Optional[str] = None, + variables: Optional[Dict[str, Any]] = None, + ) -> None: + payload: Dict[str, Any] = { + "id": operation_id, + "type": GraphQLTransportWSMessageType.SUBSCRIBE.value, + "payload": {"query": query, "operationName": operation_name}, + } + if variables: + payload["payload"]["variables"] = self._convert_dict_to_json_serializable( + variables + ) + await websocket.send(json.dumps(payload)) + + async def _handle_ws_message( + self, + message: Data, + websocket: WebSocketClientProtocol, + expected_type: Optional[GraphQLTransportWSMessageType] = None, + ) -> Optional[Dict[str, Any]]: + try: + message_dict = json.loads(message) + except json.JSONDecodeError as exc: + raise GraphQLClientInvalidMessageFormat(message=message) from exc + + type_ = message_dict.get("type") + payload = message_dict.get("payload", {}) + + if not type_ or type_ not in {t.value for t in GraphQLTransportWSMessageType}: + raise GraphQLClientInvalidMessageFormat(message=message) + + if expected_type and expected_type != type_: + raise GraphQLClientInvalidMessageFormat( + f"Invalid message received. Expected: {expected_type.value}" + ) + + if type_ == GraphQLTransportWSMessageType.NEXT: + if "data" not in payload: + raise GraphQLClientInvalidMessageFormat(message=message) + return cast(Dict[str, Any], payload["data"]) + + if type_ == GraphQLTransportWSMessageType.COMPLETE: + await websocket.close() + elif type_ == GraphQLTransportWSMessageType.PING: + await websocket.send( + json.dumps({"type": GraphQLTransportWSMessageType.PONG.value}) + ) + elif type_ == GraphQLTransportWSMessageType.ERROR: + raise GraphQLClientGraphQLMultiError.from_errors_dicts( + errors_dicts=payload, data=message_dict + ) + + return None diff --git a/python/src/numerous/generated/graphql/base_model.py b/python/src/numerous/generated/graphql/base_model.py new file mode 100644 index 00000000..76b84873 --- /dev/null +++ b/python/src/numerous/generated/graphql/base_model.py @@ -0,0 +1,29 @@ +# Generated by ariadne-codegen + +from io import IOBase + +from pydantic import BaseModel as PydanticBaseModel, ConfigDict + + +class UnsetType: + def __bool__(self) -> bool: + return False + + +UNSET = UnsetType() + + +class BaseModel(PydanticBaseModel): + model_config = ConfigDict( + populate_by_name=True, + validate_assignment=True, + arbitrary_types_allowed=True, + protected_namespaces=(), + ) + + +class Upload: + def __init__(self, filename: str, content: IOBase, content_type: str): + self.filename = filename + self.content = content + self.content_type = content_type diff --git a/python/src/numerous/generated/graphql/client.py b/python/src/numerous/generated/graphql/client.py new file mode 100644 index 00000000..fa5145a0 --- /dev/null +++ b/python/src/numerous/generated/graphql/client.py @@ -0,0 +1,179 @@ +# Generated by ariadne-codegen +# Source: queries.gql + +from typing import Any, AsyncIterator, Dict + +from .all_elements import AllElements +from .async_base_client import AsyncBaseClient +from .input_types import ElementInput +from .update_element import UpdateElement +from .updates import Updates + + +def gql(q: str) -> str: + return q + + +class Client(AsyncBaseClient): + async def all_elements(self, tool_session_id: str, **kwargs: Any) -> AllElements: + query = gql( + """ + query AllElements($toolSessionId: ID!) { + session: toolSession(id: $toolSessionId) { + id + clientID + all: allElements { + __typename + id + name + graphContext { + ...GraphContext + } + ...ButtonValue + ...TextFieldValue + ...NumberFieldValue + ...HTMLValue + ...SliderValue + } + } + } + + fragment ButtonValue on Button { + buttonValue: value + } + + fragment GraphContext on ElementGraphContext { + parent { + __typename + id + } + affectedBy { + id + } + affects { + id + } + } + + fragment HTMLValue on HTMLElement { + html + } + + fragment NumberFieldValue on NumberField { + numberValue: value + } + + fragment SliderValue on SliderElement { + sliderValue: value + minValue + maxValue + } + + fragment TextFieldValue on TextField { + textValue: value + } + """ + ) + variables: Dict[str, object] = {"toolSessionId": tool_session_id} + response = await self.execute( + query=query, operation_name="AllElements", variables=variables, **kwargs + ) + data = self.get_data(response) + return AllElements.model_validate(data) + + async def update_element( + self, session_id: str, client_id: str, element: ElementInput, **kwargs: Any + ) -> UpdateElement: + query = gql( + """ + mutation UpdateElement($sessionID: ID!, $clientID: ID!, $element: ElementInput!) { + elementUpdate(toolSessionId: $sessionID, clientId: $clientID, element: $element) { + __typename + } + } + """ + ) + variables: Dict[str, object] = { + "sessionID": session_id, + "clientID": client_id, + "element": element, + } + response = await self.execute( + query=query, operation_name="UpdateElement", variables=variables, **kwargs + ) + data = self.get_data(response) + return UpdateElement.model_validate(data) + + async def updates( + self, session_id: str, client_id: str, **kwargs: Any + ) -> AsyncIterator[Updates]: + query = gql( + """ + subscription Updates($sessionId: ID!, $clientId: ID!) { + toolSessionEvent(toolSessionId: $sessionId, clientId: $clientId) { + __typename + ... on ToolSessionElementUpdated { + element { + __typename + id + name + graphContext { + ...GraphContext + } + ...ButtonValue + ...TextFieldValue + ...NumberFieldValue + ...HTMLValue + ...SliderValue + } + } + ... on ToolSessionActionTriggered { + element { + id + name + } + } + } + } + + fragment ButtonValue on Button { + buttonValue: value + } + + fragment GraphContext on ElementGraphContext { + parent { + __typename + id + } + affectedBy { + id + } + affects { + id + } + } + + fragment HTMLValue on HTMLElement { + html + } + + fragment NumberFieldValue on NumberField { + numberValue: value + } + + fragment SliderValue on SliderElement { + sliderValue: value + minValue + maxValue + } + + fragment TextFieldValue on TextField { + textValue: value + } + """ + ) + variables: Dict[str, object] = {"sessionId": session_id, "clientId": client_id} + async for data in self.execute_ws( + query=query, operation_name="Updates", variables=variables, **kwargs + ): + yield Updates.model_validate(data) diff --git a/python/src/numerous/generated/graphql/enums.py b/python/src/numerous/generated/graphql/enums.py new file mode 100644 index 00000000..7a5d6fe1 --- /dev/null +++ b/python/src/numerous/generated/graphql/enums.py @@ -0,0 +1,20 @@ +# Generated by ariadne-codegen +# Source: ../shared/schema.gql + +from enum import Enum + + +class AuthRole(str, Enum): + AUTHENTICATED = "AUTHENTICATED" + ADMIN = "ADMIN" + USER = "USER" + + +class Role(str, Enum): + ADMIN = "ADMIN" + USER = "USER" + + +class ToolHashType(str, Enum): + public = "public" + shared = "shared" diff --git a/python/src/numerous/generated/graphql/exceptions.py b/python/src/numerous/generated/graphql/exceptions.py new file mode 100644 index 00000000..9fbe116d --- /dev/null +++ b/python/src/numerous/generated/graphql/exceptions.py @@ -0,0 +1,85 @@ +# Generated by ariadne-codegen + +from typing import Any, Dict, List, Optional, Union + +import httpx + + +class GraphQLClientError(Exception): + """Base exception.""" + + +class GraphQLClientHttpError(GraphQLClientError): + def __init__(self, status_code: int, response: httpx.Response) -> None: + self.status_code = status_code + self.response = response + + def __str__(self) -> str: + return f"HTTP status code: {self.status_code}" + + +class GraphQLClientInvalidResponseError(GraphQLClientError): + def __init__(self, response: httpx.Response) -> None: + self.response = response + + def __str__(self) -> str: + return "Invalid response format." + + +class GraphQLClientGraphQLError(GraphQLClientError): + def __init__( + self, + message: str, + locations: Optional[List[Dict[str, int]]] = None, + path: Optional[List[str]] = None, + extensions: Optional[Dict[str, object]] = None, + orginal: Optional[Dict[str, object]] = None, + ): + self.message = message + self.locations = locations + self.path = path + self.extensions = extensions + self.orginal = orginal + + def __str__(self) -> str: + return self.message + + @classmethod + def from_dict(cls, error: Dict[str, Any]) -> "GraphQLClientGraphQLError": + return cls( + message=error["message"], + locations=error.get("locations"), + path=error.get("path"), + extensions=error.get("extensions"), + orginal=error, + ) + + +class GraphQLClientGraphQLMultiError(GraphQLClientError): + def __init__( + self, + errors: List[GraphQLClientGraphQLError], + data: Optional[Dict[str, Any]] = None, + ): + self.errors = errors + self.data = data + + def __str__(self) -> str: + return "; ".join(str(e) for e in self.errors) + + @classmethod + def from_errors_dicts( + cls, errors_dicts: List[Dict[str, Any]], data: Optional[Dict[str, Any]] = None + ) -> "GraphQLClientGraphQLMultiError": + return cls( + errors=[GraphQLClientGraphQLError.from_dict(e) for e in errors_dicts], + data=data, + ) + + +class GraphQLClientInvalidMessageFormat(GraphQLClientError): + def __init__(self, message: Union[str, bytes]) -> None: + self.message = message + + def __str__(self) -> str: + return "Invalid message format." diff --git a/python/src/numerous/generated/graphql/fragments.py b/python/src/numerous/generated/graphql/fragments.py new file mode 100644 index 00000000..c210be23 --- /dev/null +++ b/python/src/numerous/generated/graphql/fragments.py @@ -0,0 +1,81 @@ +# Generated by ariadne-codegen +# Source: queries.gql + +from typing import List, Literal, Optional + +from pydantic import Field + +from .base_model import BaseModel + + +class ButtonValue(BaseModel): + button_value: str = Field(alias="buttonValue") + + +class GraphContext(BaseModel): + parent: Optional["GraphContextParent"] + affected_by: List[Optional["GraphContextAffectedBy"]] = Field(alias="affectedBy") + affects: List[Optional["GraphContextAffects"]] + + +class GraphContextParent(BaseModel): + typename__: Literal[ + "Container", "ElementGraphParent", "ElementList", "ElementSelect" + ] = Field(alias="__typename") + id: str + + +class GraphContextAffectedBy(BaseModel): + typename__: Literal[ + "Button", + "Container", + "Element", + "ElementList", + "ElementSelect", + "HTMLElement", + "NumberField", + "SliderElement", + "TextField", + ] = Field(alias="__typename") + id: str + + +class GraphContextAffects(BaseModel): + typename__: Literal[ + "Button", + "Container", + "Element", + "ElementList", + "ElementSelect", + "HTMLElement", + "NumberField", + "SliderElement", + "TextField", + ] = Field(alias="__typename") + id: str + + +class HTMLValue(BaseModel): + html: str + + +class NumberFieldValue(BaseModel): + number_value: float = Field(alias="numberValue") + + +class SliderValue(BaseModel): + slider_value: float = Field(alias="sliderValue") + min_value: float = Field(alias="minValue") + max_value: float = Field(alias="maxValue") + + +class TextFieldValue(BaseModel): + text_value: str = Field(alias="textValue") + + +ButtonValue.model_rebuild() +GraphContext.model_rebuild() +HTMLValue.model_rebuild() +NumberFieldValue.model_rebuild() +SliderValue.model_rebuild() +TextFieldValue.model_rebuild() diff --git a/python/src/numerous/generated/graphql/input_types.py b/python/src/numerous/generated/graphql/input_types.py new file mode 100644 index 00000000..dc88e8c2 --- /dev/null +++ b/python/src/numerous/generated/graphql/input_types.py @@ -0,0 +1,40 @@ +# Generated by ariadne-codegen +# Source: ../shared/schema.gql + +from typing import Optional + +from pydantic import Field + +from .base_model import BaseModel +from .enums import Role + + +class OrganizationInvitationInput(BaseModel): + role: Role + email: str + + +class NewOrganization(BaseModel): + name: str + + +class NewTool(BaseModel): + user_id: str = Field(alias="userId") + manifest: str + + +class ElementInput(BaseModel): + element_id: str = Field(alias="elementID") + text_value: Optional[str] = Field(alias="textValue", default=None) + number_value: Optional[float] = Field(alias="numberValue", default=None) + html_value: Optional[str] = Field(alias="htmlValue", default=None) + slider_value: Optional[float] = Field(alias="sliderValue", default=None) + + +class ElementSelectInput(BaseModel): + select_element_id: str = Field(alias="selectElementID") + selected_option_id: str = Field(alias="selectedOptionID") + + +class ListElementInput(BaseModel): + list_element_id: str = Field(alias="listElementID") diff --git a/python/src/numerous/generated/graphql/update_element.py b/python/src/numerous/generated/graphql/update_element.py new file mode 100644 index 00000000..d53fc20b --- /dev/null +++ b/python/src/numerous/generated/graphql/update_element.py @@ -0,0 +1,26 @@ +# Generated by ariadne-codegen +# Source: queries.gql + +from typing import Literal + +from pydantic import Field + +from .base_model import BaseModel + + +class UpdateElement(BaseModel): + element_update: "UpdateElementElementUpdate" = Field(alias="elementUpdate") + + +class UpdateElementElementUpdate(BaseModel): + typename__: Literal[ + "Button", + "Container", + "Element", + "ElementList", + "ElementSelect", + "HTMLElement", + "NumberField", + "SliderElement", + "TextField", + ] = Field(alias="__typename") diff --git a/python/src/numerous/generated/graphql/updates.py b/python/src/numerous/generated/graphql/updates.py new file mode 100644 index 00000000..666aad7d --- /dev/null +++ b/python/src/numerous/generated/graphql/updates.py @@ -0,0 +1,149 @@ +# Generated by ariadne-codegen +# Source: queries.gql + +from typing import Literal, Union + +from pydantic import Field + +from .base_model import BaseModel +from .fragments import ( + ButtonValue, + GraphContext, + HTMLValue, + NumberFieldValue, + SliderValue, + TextFieldValue, +) + + +class Updates(BaseModel): + tool_session_event: Union[ + "UpdatesToolSessionEventToolSessionElementAdded", + "UpdatesToolSessionEventToolSessionElementRemoved", + "UpdatesToolSessionEventToolSessionElementUpdated", + "UpdatesToolSessionEventToolSessionActionTriggered", + ] = Field(alias="toolSessionEvent", discriminator="typename__") + + +class UpdatesToolSessionEventToolSessionElementAdded(BaseModel): + typename__: Literal["ToolSessionElementAdded"] = Field(alias="__typename") + + +class UpdatesToolSessionEventToolSessionElementRemoved(BaseModel): + typename__: Literal["ToolSessionElementRemoved"] = Field(alias="__typename") + + +class UpdatesToolSessionEventToolSessionElementUpdated(BaseModel): + typename__: Literal["ToolSessionElementUpdated"] = Field(alias="__typename") + element: Union[ + "UpdatesToolSessionEventToolSessionElementUpdatedElementElement", + "UpdatesToolSessionEventToolSessionElementUpdatedElementButton", + "UpdatesToolSessionEventToolSessionElementUpdatedElementHTMLElement", + "UpdatesToolSessionEventToolSessionElementUpdatedElementNumberField", + "UpdatesToolSessionEventToolSessionElementUpdatedElementSliderElement", + "UpdatesToolSessionEventToolSessionElementUpdatedElementTextField", + ] = Field(discriminator="typename__") + + +class UpdatesToolSessionEventToolSessionElementUpdatedElementElement(BaseModel): + typename__: Literal["Container", "Element", "ElementList", "ElementSelect"] = Field( + alias="__typename" + ) + id: str + name: str + graph_context: ( + "UpdatesToolSessionEventToolSessionElementUpdatedElementElementGraphContext" + ) = Field(alias="graphContext") + + +class UpdatesToolSessionEventToolSessionElementUpdatedElementElementGraphContext( + GraphContext +): + pass + + +class UpdatesToolSessionEventToolSessionElementUpdatedElementButton(ButtonValue): + typename__: Literal["Button"] = Field(alias="__typename") + id: str + name: str + graph_context: ( + "UpdatesToolSessionEventToolSessionElementUpdatedElementButtonGraphContext" + ) = Field(alias="graphContext") + + +class UpdatesToolSessionEventToolSessionElementUpdatedElementButtonGraphContext( + GraphContext +): + pass + + +class UpdatesToolSessionEventToolSessionElementUpdatedElementHTMLElement(HTMLValue): + typename__: Literal["HTMLElement"] = Field(alias="__typename") + id: str + name: str + graph_context: ( + "UpdatesToolSessionEventToolSessionElementUpdatedElementHTMLElementGraphContext" + ) = Field(alias="graphContext") + + +class UpdatesToolSessionEventToolSessionElementUpdatedElementHTMLElementGraphContext( + GraphContext +): + pass + + +class UpdatesToolSessionEventToolSessionElementUpdatedElementNumberField( + NumberFieldValue +): + typename__: Literal["NumberField"] = Field(alias="__typename") + id: str + name: str + graph_context: ( + "UpdatesToolSessionEventToolSessionElementUpdatedElementNumberFieldGraphContext" + ) = Field(alias="graphContext") + + +class UpdatesToolSessionEventToolSessionElementUpdatedElementNumberFieldGraphContext( + GraphContext +): + pass + + +class UpdatesToolSessionEventToolSessionElementUpdatedElementSliderElement(SliderValue): + typename__: Literal["SliderElement"] = Field(alias="__typename") + id: str + name: str + graph_context: ( + "UpdatesToolSessionEventToolSessionElementUpdatedElementSliderElementGraphContext" + ) = Field(alias="graphContext") + + +class UpdatesToolSessionEventToolSessionElementUpdatedElementSliderElementGraphContext( + GraphContext +): + pass + + +class UpdatesToolSessionEventToolSessionElementUpdatedElementTextField(TextFieldValue): + typename__: Literal["TextField"] = Field(alias="__typename") + id: str + name: str + graph_context: ( + "UpdatesToolSessionEventToolSessionElementUpdatedElementTextFieldGraphContext" + ) = Field(alias="graphContext") + + +class UpdatesToolSessionEventToolSessionElementUpdatedElementTextFieldGraphContext( + GraphContext +): + pass + + +class UpdatesToolSessionEventToolSessionActionTriggered(BaseModel): + typename__: Literal["ToolSessionActionTriggered"] = Field(alias="__typename") + element: "UpdatesToolSessionEventToolSessionActionTriggeredElement" + + +class UpdatesToolSessionEventToolSessionActionTriggeredElement(BaseModel): + id: str + name: str diff --git a/python/src/numerous/py.typed b/python/src/numerous/py.typed new file mode 100644 index 00000000..e69de29b diff --git a/python/src/numerous/session.py b/python/src/numerous/session.py new file mode 100644 index 00000000..5cb06404 --- /dev/null +++ b/python/src/numerous/session.py @@ -0,0 +1,520 @@ +"""App sessions manages app instances.""" + +import asyncio +import logging +import random +import string +import threading +import typing +from concurrent.futures import Future +from typing import Any, Callable, Generic, Optional, Type, Union + +from plotly import graph_objects as go + +from numerous._plotly import plotly_html +from numerous.apps import HTML, Slider +from numerous.data_model import ( + ActionDataModel, + AppDataModel, + ContainerDataModel, + ElementDataModel, + HTMLElementDataModel, + NumberFieldDataModel, + PlotlyElementDataModel, + SliderElementDataModel, + TextFieldDataModel, + dump_data_model, +) +from numerous.generated.graphql.fragments import GraphContextParent +from numerous.generated.graphql.input_types import ElementInput +from numerous.updates import UpdateHandler +from numerous.utils import AppT + +from .generated.graphql.all_elements import ( + AllElementsSession, + AllElementsSessionAllButton, + AllElementsSessionAllElement, + AllElementsSessionAllHTMLElement, + AllElementsSessionAllNumberField, + AllElementsSessionAllSliderElement, + AllElementsSessionAllTextField, +) +from .generated.graphql.client import Client +from .generated.graphql.updates import ( + UpdatesToolSessionEventToolSessionElementAdded, + UpdatesToolSessionEventToolSessionElementRemoved, + UpdatesToolSessionEventToolSessionElementUpdated, +) + +alphabet = string.ascii_lowercase + string.digits +ToolSessionEvent = Union[ + UpdatesToolSessionEventToolSessionElementAdded, + UpdatesToolSessionEventToolSessionElementRemoved, + UpdatesToolSessionEventToolSessionElementUpdated, +] +ToolSessionElement = Union[ + AllElementsSessionAllElement, + AllElementsSessionAllButton, + AllElementsSessionAllNumberField, + AllElementsSessionAllTextField, + AllElementsSessionAllHTMLElement, + AllElementsSessionAllSliderElement, +] + + +AllElementsSession.model_rebuild() + +log = logging.getLogger(__name__) + + +def get_client_id() -> str: + return "".join(random.choices(alphabet, k=8)) # noqa: S311 + + +class SessionElementTypeMismatchError(Exception): + def __init__(self, sess_elem: ToolSessionElement, elem: ElementDataModel) -> None: + super().__init__( + f"{type(elem).__name__!r} does not match {type(sess_elem).__name__!r}", + ) + + +class SessionElementMissingError(Exception): + def __init__(self, elem: ElementDataModel) -> None: + super().__init__(f"Tool session missing required element '{elem.name}'") + + +class ThreadedEventLoop: + """Wrapper for an asyncio event loop running in a thread.""" + + def __init__(self) -> None: + self._loop = asyncio.new_event_loop() + self._thread = threading.Thread( + target=self._run_loop_forever, + name="Event Loop Thread", + daemon=True, + ) + + def start(self) -> None: + """Start the thread and run the event loop.""" + if not self._thread.is_alive(): + self._thread.start() + + def stop(self) -> None: + """Stop the event loop, and terminate the thread.""" + if self._thread.is_alive(): + self._loop.stop() + + def schedule(self, coroutine: typing.Awaitable[typing.Any]) -> Future[Any]: + """Schedule a coroutine in the event loop.""" + return asyncio.run_coroutine_threadsafe(coroutine, self._loop) + + def _run_loop_forever(self) -> None: + asyncio.set_event_loop(self._loop) + self._loop.run_forever() + + +class Session(Generic[AppT]): + def __init__( + self, + session_id: str, + client_id: str, + instance: AppT, + gql: Client, + ) -> None: + self._session_id = session_id + self._client_id = client_id + self._instance = instance + self._gql = gql + self._update_handler = UpdateHandler(instance) + + @staticmethod + async def initialize( + session_id: str, + gql: Client, + cls: Type[AppT], + ) -> "Session[AppT]": + """ + Initialize the session. + + Creates an instance, and validates it according to the remote app session. + """ + threaded_event_loop = ThreadedEventLoop() + threaded_event_loop.start() + result = await gql.all_elements(session_id) + client_id = result.session.client_id + print( # noqa: T201 + f"Running in session {session_id!r} as client {client_id!r}", + ) + data_model = dump_data_model(cls) + _validate_app_session(data_model, result.session) + _wrap_app_class_setattr(threaded_event_loop, session_id, client_id, cls, gql) + kwargs = _get_kwargs(cls, result.session) + instance = cls(**kwargs) + _add_element_ids(instance, None, result.session) + _add_data_models(instance, data_model) + return Session(session_id, client_id, instance, gql) + + async def run(self) -> None: + """Run the app.""" + async for update in self._gql.updates(self._session_id, self._client_id): + self._update_handler.handle_update(update) + + +def _add_element_ids( + instance: AppT, + element_id: Optional[str], + session: AllElementsSession, +) -> None: + names_to_ids = {} + ids_to_names = {} + + for elem in session.all: + if _element_parent_is(elem.graph_context.parent, element_id): + names_to_ids[elem.name] = elem.id + ids_to_names[elem.id] = elem.name + + instance.__element_names_to_ids__ = names_to_ids # type: ignore[attr-defined] + instance.__element_ids_to_names__ = ids_to_names # type: ignore[attr-defined] + + +def _element_parent_is( + graph_parent: Optional[GraphContextParent], + parent_element_id: Optional[str], +) -> bool: + graph_parent_id = graph_parent.id if graph_parent else None + return ( + graph_parent_id is None and parent_element_id is None + ) or graph_parent_id == parent_element_id + + +def _add_data_models( + instance: object, + data_model: Union[AppDataModel, ContainerDataModel], +) -> None: + names_to_data_models = {} + for el in data_model.elements: + obj = getattr(instance, el.name, None) + if obj is None: + continue + + names_to_data_models[el.name] = el + + if isinstance(el, ContainerDataModel) and getattr(obj, "__container__", False): + _add_data_models(obj, el) + + instance.__element_data_models__ = names_to_data_models # type: ignore[attr-defined] + + +def _send_sync_update( + loop: ThreadedEventLoop, + gql: Client, + session_id: str, + client_id: str, + element_input: ElementInput, +) -> None: + done = threading.Event() + + async def update() -> None: + try: + await gql.update_element( + session_id=session_id, + client_id=client_id, + element=element_input, + ) + finally: + done.set() + + loop.schedule(update()) + + done.wait() + + +def get_setattr( + loop: ThreadedEventLoop, + gql: Client, + old_setattr: Callable[[object, str, Any], None], + session_id: str, + client_id: str, +) -> Callable[[object, str, Any], None]: + def setattr_override( + instance: AppT, + name: str, + value: Any, # noqa: ANN401 + ) -> None: + old_setattr(instance, name, value) + element_id = _get_element_id(instance, name) + if element_id is None: + return + + data_model = _get_data_model(instance, name) + + update_element_input = _get_setattr_value_update_input( + data_model, + value, + element_id, + ) + if update_element_input: + _send_sync_update(loop, gql, session_id, client_id, update_element_input) + else: + log.debug( + "could not update element id=%s name=%s value=%s", + element_id, + name, + value, + ) + + return setattr_override + + +def _get_element_id(instance: AppT, name: str) -> Optional[str]: + element_names_to_ids: Optional[dict[str, str]] = getattr( + instance, + "__element_names_to_ids__", + None, + ) + + if element_names_to_ids is None: + return None + + return element_names_to_ids.get(name) + + +def _get_data_model(instance: AppT, name: str) -> Optional[ElementDataModel]: + element_names_to_data_models: Optional[dict[str, ElementDataModel]] = getattr( + instance, + "__element_data_models__", + None, + ) + if element_names_to_data_models is None: + return None + + return element_names_to_data_models.get(name) + + +def _get_setattr_value_update_input( # noqa: PLR0911 + data_model: Optional[ElementDataModel], + value: Any, # noqa: ANN401 + element_id: str, +) -> Optional[ElementInput]: + if isinstance(value, str): + if isinstance(data_model, HTMLElementDataModel): + return ElementInput(elementID=element_id, htmlValue=value) + return ElementInput(elementID=element_id, textValue=value) + + if isinstance(value, go.Figure) and isinstance(data_model, PlotlyElementDataModel): + return ElementInput(elementID=element_id, htmlValue=plotly_html(value)) + + if isinstance(value, (float, int)): + if isinstance(data_model, SliderElementDataModel): + return ElementInput(elementID=element_id, sliderValue=float(value)) + return ElementInput( + elementID=element_id, + numberValue=float(value), + ) + + if isinstance(data_model, Slider): + return ElementInput(elementID=element_id, sliderValue=float(value)) + + if isinstance(value, HTML): + return ElementInput( + elementID=element_id, + htmlValue=value.default, + ) + + return None + + +def _wrap_app_class_setattr( + loop: ThreadedEventLoop, + session_id: str, + client_id: str, + cls: Type[AppT], + gql: Client, +) -> None: + annotations = _get_annotations(cls) + for annotation in annotations.values(): + if not getattr(annotation, "__container__", False): + continue + _wrap_container_class_setattr(loop, session_id, client_id, cls, gql) + new_setattr = get_setattr(loop, gql, cls.__setattr__, session_id, client_id) + cls.__setattr__ = new_setattr # type: ignore[assignment] + + +def _get_annotations(cls: type) -> dict[str, Any]: + return cls.__annotations__ if hasattr(cls, "__annotations__") else {} + + +def _wrap_container_class_setattr( + loop: ThreadedEventLoop, + session_id: str, + client_id: str, + cls: Union[Type[AppT]], + gql: Client, +) -> None: + annotations = _get_annotations(cls) + for annotation in annotations.values(): + if not getattr(annotation, "__container__", False): + continue + _wrap_container_class_setattr(loop, session_id, client_id, annotation, gql) + new_setattr = get_setattr(loop, gql, cls.__setattr__, session_id, client_id) + cls.__setattr__ = new_setattr # type: ignore[method-assign, assignment] + + +def _validate_app_session( + data_model: AppDataModel, + session: AllElementsSession, +) -> None: + session_elements = {sess_elem.name: sess_elem for sess_elem in session.all} + for elem in data_model.elements: + if elem.name not in session_elements: + raise SessionElementMissingError(elem) + sess_elem = session_elements[elem.name] + _validate_element(elem, sess_elem) + # TODO(jens): validate session elements exist in data model # noqa: TD003, FIX002 + # TODO(jens): validate child elements # noqa: TD003, FIX002 + + +def _validate_element(elem: ElementDataModel, sess_elem: ToolSessionElement) -> None: + valid_text_element = isinstance(elem, TextFieldDataModel) and isinstance( + sess_elem, + AllElementsSessionAllTextField, + ) + valid_number_element = isinstance(elem, NumberFieldDataModel) and isinstance( + sess_elem, + AllElementsSessionAllNumberField, + ) + valid_action_element = isinstance(elem, ActionDataModel) and isinstance( + sess_elem, + AllElementsSessionAllButton, + ) + valid_html_element = isinstance( + elem, + (HTMLElementDataModel, PlotlyElementDataModel), + ) and isinstance( + sess_elem, + AllElementsSessionAllHTMLElement, + ) + valid_slider_element = isinstance(elem, SliderElementDataModel) and isinstance( + sess_elem, + AllElementsSessionAllSliderElement, + ) + valid_container_element = ( + isinstance(elem, ContainerDataModel) + and isinstance(sess_elem, AllElementsSessionAllElement) + and sess_elem.typename__ == "Container" + ) + if not ( + valid_text_element + or valid_number_element + or valid_action_element + or valid_container_element + or valid_html_element + or valid_slider_element + ): + raise SessionElementTypeMismatchError(sess_elem, elem) + + +def _get_kwargs(cls: Type[AppT], session: AllElementsSession) -> dict[str, Any]: + kwargs: dict[str, Any] = {} + annotations = _get_annotations(cls) + for element in session.all: + if element.graph_context.parent is not None: + continue + if element.typename__ == "Button": + continue + kwargs[element.name] = _get_kwarg_value( + annotations[element.name], + session, + element, + ) + return kwargs + + +class SessionElementAnnotationMismatchError(Exception): + def __init__(self, sess_elem: ToolSessionElement, annotation: type) -> None: + sess_name = type(sess_elem).__name__ + ann_name = ( + annotation.__name__ + if type(annotation) is type + else type(annotation).__name__ + ) + super().__init__(f"{sess_name!r} does not match annotation {ann_name!r}") + + +def _get_kwarg_value( + annotation: type, + session: AllElementsSession, + element: ToolSessionElement, +) -> Any: # noqa: ANN401 + if isinstance(element, AllElementsSessionAllNumberField) and annotation is float: + return element.number_value + + if isinstance(element, AllElementsSessionAllTextField) and annotation is str: + return element.text_value + + if isinstance(element, AllElementsSessionAllHTMLElement) and ( + annotation is str or annotation is go.Figure + ): + return element.html + + if isinstance(element, AllElementsSessionAllSliderElement) and annotation is float: + return element.slider_value + + if ( + isinstance(element, AllElementsSessionAllElement) + and element.typename__ == "Container" + and getattr(annotation, "__container__", False) + ): + return _get_container_kwarg_value( + annotation, + session, + element, + ) + + raise SessionElementAnnotationMismatchError(element, annotation) + + +class ContainerInitializeElementError(Exception): + def __init__(self, container: AllElementsSessionAllElement) -> None: + name = container.typename__ + super().__init__(f"cannot initialize non-container element {name!r}") + + +class ContainerInitializeAnnotationError(Exception): + def __init__(self, container_cls: Type[AppT]) -> None: + name = type(container_cls).__name__ + super().__init__(f"cannot initialize non-container annotation {name!r}") + + +def _get_container_kwarg_value( + container_cls: Type[AppT], + session: AllElementsSession, + container: AllElementsSessionAllElement, +) -> Any: # noqa: ANN401 + if container.typename__ != "Container": + raise ContainerInitializeElementError(container) + + if not getattr(container_cls, "__container__", False): + raise ContainerInitializeAnnotationError(container_cls) + + annotations = ( + container_cls.__annotations__ + if hasattr(container_cls, "__annotations__") + else {} + ) + + children = { + e.name: e + for e in session.all + if e.graph_context.parent and e.graph_context.parent.id == container.id + } + + kwargs = { + name: _get_kwarg_value(annotation, session, children[name]) + for name, annotation in annotations.items() + if name in children + } + + instance = container_cls(**kwargs) + _add_element_ids(instance, container.id, session) + return instance diff --git a/python/src/numerous/tools/__init__.py b/python/src/numerous/tools/__init__.py new file mode 100644 index 00000000..c0971f7b --- /dev/null +++ b/python/src/numerous/tools/__init__.py @@ -0,0 +1,11 @@ +""" +A deprecated package. + +Only raises an error to help users fix their usage of this package. +""" + +msg = ( + "You are trying to import from 'numerous.tools', which is deprecated. Use " + "'numerous.apps', and the @app decorator instead." +) +raise RuntimeError(msg) diff --git a/python/src/numerous/updates.py b/python/src/numerous/updates.py new file mode 100644 index 00000000..f608a0bf --- /dev/null +++ b/python/src/numerous/updates.py @@ -0,0 +1,179 @@ +"""Handling of updates sent to the tool session instance.""" + +import inspect +import logging +from types import MethodType +from typing import Any, Callable, Optional, Union + +from numerous.generated.graphql import Updates +from numerous.generated.graphql.updates import ( + UpdatesToolSessionEventToolSessionActionTriggered, + UpdatesToolSessionEventToolSessionElementUpdated, + UpdatesToolSessionEventToolSessionElementUpdatedElementHTMLElement, + UpdatesToolSessionEventToolSessionElementUpdatedElementNumberField, + UpdatesToolSessionEventToolSessionElementUpdatedElementSliderElement, + UpdatesToolSessionEventToolSessionElementUpdatedElementTextField, +) + +log = logging.getLogger(__name__) + + +class ElementUpdateError(Exception): + def __init__(self, element_name: str, instance_element_name: str) -> None: + super().__init__( + f"expected name {element_name} but instead found {instance_element_name}", + ) + + +class UpdateHandler: + """Updates app instances according to events sent to the app session.""" + + def __init__(self, instance: object) -> None: + self._instance = instance + self._update_handlers = _find_instance_update_handlers(instance) + self._actions = self._find_actions(instance) + + def _find_actions(self, instance: object) -> dict[str, Callable[[], Any]]: + methods = inspect.getmembers(instance, predicate=inspect.ismethod) + return { + name: method + for name, method in methods + if getattr(method, "__action__", True) + } + + def handle_update(self, updates: Updates) -> None: + """Handle an update for the tool session.""" + event = updates.tool_session_event + if isinstance(event, UpdatesToolSessionEventToolSessionElementUpdated): + self._handle_element_updated(event) + elif isinstance(event, UpdatesToolSessionEventToolSessionActionTriggered): + self._handle_action_triggered(event) + else: + log.info("unhandled event %s", event) + + def _handle_element_updated( + self, + event: UpdatesToolSessionEventToolSessionElementUpdated, + ) -> None: + element = event.element + update_value = self._get_element_update_value(event) + + if update_value is not None: + if self._naive_update_element( + self._instance, + element.id, + element.name, + update_value, + ): + log.debug( + "did not update element %s with value %s", + element, + update_value, + ) + else: + log.debug("unexpected update element %s", element) + + if element.id in self._update_handlers: + log.debug("calling update handler for %s", element.name) + self._update_handlers[element.id]() + else: + log.debug("no associated update handler for %s", element.name) + + def _get_element_update_value( + self, + event: UpdatesToolSessionEventToolSessionElementUpdated, + ) -> Union[str, float, None]: + element = event.element + if isinstance( + element, + UpdatesToolSessionEventToolSessionElementUpdatedElementTextField, + ): + return element.text_value + + if isinstance( + element, + UpdatesToolSessionEventToolSessionElementUpdatedElementNumberField, + ): + return element.number_value + + if isinstance( + element, + UpdatesToolSessionEventToolSessionElementUpdatedElementHTMLElement, + ): + return element.html + + if isinstance( + element, + UpdatesToolSessionEventToolSessionElementUpdatedElementSliderElement, + ): + return element.slider_value + + return None + + def _handle_action_triggered( + self, + event: UpdatesToolSessionEventToolSessionActionTriggered, + ) -> None: + action = event.element + if action.name in self._actions: + self._actions[action.name]() + else: + log.warning("no action found for %r", action.name) + + def _naive_update_element( + self, + app_or_container: Any, # noqa: ANN401 + element_id: str, + element_name: str, + value: Any, # noqa: ANN401 + ) -> bool: + element_ids_to_names: dict[str, str] = getattr( + app_or_container, + "__element_ids_to_names__", + None, + ) # type: ignore[assignment] + if element_ids_to_names is None: + return False + + if element_id in element_ids_to_names: + instance_element_name = element_ids_to_names[element_id] + if instance_element_name != element_name: + raise ElementUpdateError(element_name, instance_element_name) + app_or_container.__dict__[element_name] = value + return True + + for child_name in element_ids_to_names.values(): + child = getattr(app_or_container, child_name) + if self._naive_update_element(child, element_id, element_name, value): + return True + + return False + + +def _find_instance_update_handlers(instance: object) -> dict[str, MethodType]: + element_names_to_ids: Optional[dict[str, str]] = getattr( + instance, + "__element_names_to_ids__", + None, + ) + if element_names_to_ids is None: + return {} + + methods = inspect.getmembers(instance, predicate=inspect.ismethod) + element_names_to_handlers = { + name.removesuffix("_updated"): method + for name, method in methods + if name.endswith("_updated") + } + + element_ids_to_handlers = { + element_names_to_ids[element_name]: handler + for element_name, handler in element_names_to_handlers.items() + if element_name in element_names_to_ids + } + + for element_name in element_names_to_ids: + child = getattr(instance, element_name, None) + element_ids_to_handlers.update(_find_instance_update_handlers(child)) + + return element_ids_to_handlers diff --git a/python/src/numerous/utils.py b/python/src/numerous/utils.py new file mode 100644 index 00000000..5dd7ba50 --- /dev/null +++ b/python/src/numerous/utils.py @@ -0,0 +1,12 @@ +"""Miscellaneous utilities.""" + +from typing import TypeVar + + +class _MissingType: + pass + + +MISSING = _MissingType() + +AppT = TypeVar("AppT") diff --git a/python/tests/experimental/test_marimo.py b/python/tests/experimental/test_marimo.py new file mode 100644 index 00000000..84763131 --- /dev/null +++ b/python/tests/experimental/test_marimo.py @@ -0,0 +1,78 @@ +import html +import json + +import pytest +from numerous.experimental.marimo import Field +from numerous.experimental.model import BaseModel + +number_value = 5 +number_min = 0 +number_max = 10 +text_value = "text" + + +class DataModel(BaseModel): + number_field = Field(default=number_value, ge=number_min, le=number_max) # type: ignore[arg-type] + text_field = Field(default=text_value) + + +def test_number_field_has_default_value() -> None: + model = DataModel() + + assert model.number_field.value == number_value + + +def test_slider_values_match_field_defintion() -> None: + model = DataModel() + + marimo_slider = model.number_field.slider(label="Test") + + assert marimo_slider.start == number_min + assert marimo_slider.stop == number_max + assert marimo_slider.value == number_value + + +def test_number_values_match_field_defintion() -> None: + model = DataModel() + + marimo_number = model.number_field.number(label="Test") + + assert marimo_number.start == number_min + assert marimo_number.stop == number_max + assert marimo_number.value == number_value + + +def test_number_out_of_range_raises_value_error() -> None: + model = DataModel() + + with pytest.raises(ValueError): # noqa: PT011 + model.number_field.value = number_max + 1 + + with pytest.raises(ValueError): # noqa: PT011 + model.number_field.value = number_min - 1 + + +def test_text_values_match_field_defintion() -> None: + model = DataModel() + + marimo_text = model.text_field.text(label="Test") + + assert marimo_text.value == text_value + + +def test_label_none_uses_field_name() -> None: + class DataModel(BaseModel): + field_name = Field(default=5, ge=0, le=10) # type: ignore[arg-type] + + model = DataModel() + + marimo_slider = model.field_name.slider(label=None) + expected_data_label_value = marimo_escape_html( + 'field_name', + ) + assert expected_data_label_value in marimo_slider.text + + +def marimo_escape_html(value: str) -> str: + processed = html.escape(json.dumps(value)) + return processed.replace("\\", "\").replace("$", "$") diff --git a/python/tests/experimental/test_model.py b/python/tests/experimental/test_model.py new file mode 100644 index 00000000..b1c5734e --- /dev/null +++ b/python/tests/experimental/test_model.py @@ -0,0 +1,139 @@ +import pytest +from numerous.experimental.model import BaseModel, Field + +# Create a field with an annotation but no default value. +field = Field(annotation=int) + + +def test_field_value() -> None: + # Since no default value is provided, getting the value should raise an error. + with pytest.raises(ValueError): # noqa: PT011 + field.value # noqa: B018 + + +def test_assignment_before_parent_model() -> None: + # The field has no parent model, so setting the value should raise an error, + # since validation occurs in the model. + with pytest.raises(ValueError): # noqa: PT011 + field.value = 5 + + +def test_check_name_before_assignment() -> None: + # The field has not been named, so getting the name should raise an error. + with pytest.raises(ValueError): # noqa: PT011 + field.name # noqa: B018 + + +def test_rename() -> None: + # Naming the field should work. + field.name = "field" + + # The field has been named, so naming again should raise an error. + with pytest.raises(ValueError): # noqa: PT011 + field.name = "field2" + + # Check that the name is correct. + assert field.name == "field", "Field name is incorrect." + + +def test_field_default_value() -> None: + # Create a field with a default value. + val = 5 + field = Field(default=val) + + # The field was provided a default value, so getting the value should work. + assert field.value == val, "Field value is incorrect." + + +a_val = 5 +a_val2 = 10 + + +# Define a model with a field. +class DataModel(BaseModel): + a = Field(default=a_val) + + +def test_model_field_value() -> None: + model = DataModel() + + assert model.a.value == a_val + + +def test_model_field_name() -> None: + model = DataModel() + + assert model.a.name == "a" + + +def test_parent_model_correct() -> None: + model = DataModel() + + assert model.a._parent_model == model # noqa: SLF001 + + +def test_set_value() -> None: + model = DataModel() + + model.a.value = a_val2 + + assert model.a.value == a_val2 + + +def test_set_wrong_type_raises_valueerror() -> None: + model = DataModel() + + with pytest.raises(ValueError): # noqa: PT011 + model.a.name = "Text" + + +def test_submodel_() -> None: + number_value = 10 + + class SubModel(BaseModel): + number_field = Field(default=number_value) + + class DataModel(BaseModel): + number_field = Field(default=5) + sub_model = SubModel() + + model = DataModel() + + assert model.sub_model.number_field.value == number_value + assert model.pydantic_model.sub_model.number_field == number_value # type: ignore[attr-defined] + + +def test_non_existing_field_raise_error() -> None: + class DataModel(BaseModel): + a = Field(default=5) + + # Trying to set a non-existing field should raise an error. + with pytest.raises(AttributeError): + DataModel(b=5) # type: ignore[arg-type] + + +def test_no_default_provided_and_no_value_raises_value_error() -> None: + class DataModel(BaseModel): + a = Field(annotation=int) + + # Trying to instanciate the model without a value should raise an error. + with pytest.raises(ValueError): # noqa: PT011 + DataModel() + + +def test_annotation_is_used_to_validate_value() -> None: + class DataModel(BaseModel): + a = Field(annotation=int) + + DataModel(a=5) # type: ignore[arg-type] + + with pytest.raises(ValueError): # noqa: PT011 + DataModel(a="text") # type: ignore[arg-type] + + +def test_defining_field_without_annotation_or_default_raises_value_error() -> None: + """Test that you cannot define a model without an annotation or a default value.""" + with pytest.raises(ValueError): # noqa: PT011 + + class DataModel(BaseModel): + a = Field() diff --git a/python/tests/test_data_model.py b/python/tests/test_data_model.py new file mode 100644 index 00000000..336db0ce --- /dev/null +++ b/python/tests/test_data_model.py @@ -0,0 +1,333 @@ +from typing import Generator +from unittest.mock import Mock, patch + +import pytest +from numerous import app, container, field, html, slider +from numerous.data_model import ( + AppDataModel, + ContainerDataModel, + HTMLElementDataModel, + NumberFieldDataModel, + PlotlyElementDataModel, + SliderElementDataModel, + TextFieldDataModel, + dump_data_model, +) + + +def test_dump_data_model_expected_app_name() -> None: + @app + class AppWithAName: + param: str + + data_model = dump_data_model(AppWithAName) + + assert data_model.name == "AppWithAName" + + +def test_dump_data_model_number_field() -> None: + default_param_value = 5 + + @app + class App: + param: float = default_param_value + + data_model = dump_data_model(App) + + assert data_model == AppDataModel( + name="App", + title="App", + elements=[ + NumberFieldDataModel( + name="param", + label="param", + default=default_param_value, + ), + ], + ) + + +def test_dump_data_model_text_field() -> None: + default_param_value = "default string" + + @app + class App: + param: str = default_param_value + + data_model = dump_data_model(App) + + assert data_model == AppDataModel( + name="App", + title="App", + elements=[ + TextFieldDataModel( + name="param", + label="param", + default=default_param_value, + ), + ], + ) + + +def test_dump_data_model_html_element_field() -> None: + @app + class HTMLApp: + html: str = html(default="
") + + data_model = dump_data_model(HTMLApp) + + assert data_model == AppDataModel( + name="HTMLApp", + title="HTMLApp", + elements=[ + HTMLElementDataModel(name="html", label="html", default="
"), + ], + ) + + +def test_dump_data_model_slider_element_field() -> None: + @app + class SliderApp: + slider: float = slider( + default=10.0, + label="Slider label", + min_value=-20.0, + max_value=30.0, + ) + + data_model = dump_data_model(SliderApp) + + assert data_model == AppDataModel( + name="SliderApp", + title="SliderApp", + elements=[ + SliderElementDataModel( + name="slider", + label="Slider label", + default=10.0, + slider_min_value=-20.0, + slider_max_value=30.0, + ), + ], + ) + + +def test_dump_data_model_slider_element_field_with_defaults() -> None: + @app + class SliderApp: + slider: float = slider() + + data_model = dump_data_model(SliderApp) + + assert data_model == AppDataModel( + name="SliderApp", + title="SliderApp", + elements=[ + SliderElementDataModel( + name="slider", + label="slider", + default=0.0, + slider_min_value=0.0, + slider_max_value=100.0, + ), + ], + ) + + +def test_dump_data_model_field_element_string_with_label() -> None: + @app + class FieldApp: + text_field: str = field( + default="text field default", + label="My text field label", + ) + + data_model = dump_data_model(FieldApp) + + assert data_model == AppDataModel( + name="FieldApp", + title="FieldApp", + elements=[ + TextFieldDataModel( + name="text_field", + label="My text field label", + default="text field default", + ), + ], + ) + + +def test_dump_data_model_field_element_float_with_label() -> None: + @app + class FieldApp: + number_field: float = field( + default=42.0, + label="My number field label", + ) + + data_model = dump_data_model(FieldApp) + + assert data_model == AppDataModel( + name="FieldApp", + title="FieldApp", + elements=[ + NumberFieldDataModel( + name="number_field", + label="My number field label", + default=42.0, + ), + ], + ) + + +def test_dump_data_model_field_element_string_with_defaults() -> None: + @app + class FieldApp: + text_field: str = field() + + data_model = dump_data_model(FieldApp) + + assert data_model == AppDataModel( + name="FieldApp", + title="FieldApp", + elements=[ + TextFieldDataModel( + name="text_field", + label="text_field", + default="", + ), + ], + ) + + +def test_dump_data_model_field_element_float_with_defaults() -> None: + @app + class FieldApp: + number_field: float = field() + + data_model = dump_data_model(FieldApp) + + assert data_model == AppDataModel( + name="FieldApp", + title="FieldApp", + elements=[ + NumberFieldDataModel( + name="number_field", + label="number_field", + default=0.0, + ), + ], + ) + + +def test_dump_data_model_container_field() -> None: + default_param_value = "default string" + + @container + class Container: + param: str = default_param_value + + @app + class App: + container: Container + + data_model = dump_data_model(App) + + assert data_model == AppDataModel( + name="App", + title="App", + elements=[ + ContainerDataModel( + name="container", + label="container", + elements=[ + TextFieldDataModel( + name="param", + label="param", + default=default_param_value, + ), + ], + ), + ], + ) + + +def test_dump_data_model_plotly_field() -> None: + import plotly.graph_objects as go + + @app + class App: + figure: go.Figure + + data_model = dump_data_model(App) + + assert data_model == AppDataModel( + name="App", + title="App", + elements=[ + PlotlyElementDataModel( + name="figure", + label="figure", + default="", + ), + ], + ) + + +@pytest.fixture() +def patch_uuid4() -> Generator[Mock, None, None]: + mock = Mock() + with patch("plotly.io._html.uuid.uuid4", mock): + yield mock + + +def test_dump_data_model_plotly_field_defalt_is_html(patch_uuid4: Mock) -> None: + import plotly.graph_objects as go + + patch_uuid4.return_value = "abc123" # mock uuid so div IDs are the same in HTML + + @app + class App: + figure: go.Figure = field( + default_factory=lambda: go.Figure( + go.Scatter(x=[1, 2, 3, 4, 5], y=[1, 2, 3, 4, 5]), + ), + ) + + data_model = dump_data_model(App) + + assert data_model == AppDataModel( + name="App", + title="App", + elements=[ + PlotlyElementDataModel( + name="figure", + label="figure", + default=go.Figure( + go.Scatter(x=[1, 2, 3, 4, 5], y=[1, 2, 3, 4, 5]), + ).to_html(include_plotlyjs="cdn", full_html=False), + ), + ], + ) + + +def test_dump_data_model_plotly_field_with_label() -> None: + import plotly.graph_objects as go + + @app + class App: + figure: go.Figure = field(label="My Figure") + + data_model = dump_data_model(App) + + assert data_model == AppDataModel( + name="App", + title="App", + elements=[ + PlotlyElementDataModel( + name="figure", + label="My Figure", + default="", + ), + ], + ) diff --git a/python/tests/test_read.py b/python/tests/test_read.py new file mode 100644 index 00000000..844b5977 --- /dev/null +++ b/python/tests/test_read.py @@ -0,0 +1,237 @@ +import json +from io import StringIO +from pathlib import Path +from textwrap import dedent + +import pytest +from numerous.appdev.commands import ( + read_app, +) + + +@pytest.fixture() +def default_app_file(tmp_path: Path) -> Path: + appfile = tmp_path / "app.py" + # fmt: off + appfile.write_text(dedent(""" + from numerous.apps import app, field + + @app + class MyApp: + field: str = field(label="My Field", default="my default") + """)) + return appfile + + +def test_read_prints_expected_data_model( + default_app_file: Path, +) -> None: + output = StringIO() + read_app(default_app_file, "MyApp", output=output) + + expected_data_model = json.dumps( + { + "app": { + "name": "MyApp", + "title": "MyApp", + "elements": [ + { + "name": "field", + "label": "My Field", + "default": "my default", + "type": "string", + }, + ], + }, + }, + ) + assert output.getvalue() == expected_data_model + + +def test_read_app_with_invalid_app_class_raises_appnotfound_error( + default_app_file: Path, +) -> None: + output = StringIO() + + read_app(default_app_file, "NonExistingApp", output) + + expected_error = json.dumps( + { + "error": { + "appnotfound": { + "app": "NonExistingApp", + "found_apps": ["MyApp"], + }, + }, + }, + ) + assert output.getvalue() == expected_error + + +def test_read_app_with_syntax_error_raises_syntaxerror( + tmp_path: Path, +) -> None: + appfile = tmp_path / "app.py" + # fmt: off + src = dedent(""" + from numerous.apps import app, field + + @app + class MyApp: + field: str = field():some syntax error: + """) + appfile.write_text(src) + output = StringIO() + + read_app(appfile, "MyApp", output=output) + + expected_context = "\n".join([ # noqa: FLY002 + " field: str = field():some syntax error:", + " ^", + ]) + expected_error = json.dumps({ + "error": { + "appsyntax": { + "msg": "invalid syntax", + "context": expected_context, + "pos": {"line": 6, "offset": 25}}, + }, + }, + ) + actual = output.getvalue() + assert actual == expected_error + + +def test_read_app_with_import_error_raises_modulenotfounderror( + tmp_path: Path, +) -> None: + appfile = tmp_path / "app.py" + # fmt: off + src = dedent(""" + from numerous.apps import app, field + from weirdlibrary import stuff + + @app + class MyApp: + field: str = field() + """) + appfile.write_text(src) + output = StringIO() + + read_app(appfile, "MyApp", output=output) + + + expected_error = json.dumps({ + "error": { + "modulenotfound": { + "module": "weirdlibrary", + }, + }, + }) + assert output.getvalue() == expected_error + + +def test_read_app_raising_exception_at_module_level_returns_unknown_error( + tmp_path: Path, +) -> None: + appfile = tmp_path / "app.py" + # fmt: off + src = dedent(""" + from numerous.apps import app, field + + raise Exception("raising at module level") + + @app + class MyApp: + field: str = field() + """) + appfile.write_text(src) + output = StringIO() + + read_app(appfile, "MyApp", output=output) + + # fmt: off + expected_traceback = dedent(f""" + Traceback (most recent call last): + File "{appfile}", line 3, in + Exception: raising at module level + """).lstrip("\n") + expected_error = json.dumps({ + "error": { + "unknown": { + "typename": "Exception", + "traceback": expected_traceback, + }, + }, + }) + actual = output.getvalue() + assert actual == expected_error + + +def test_read_deprecated_tool_app_prints_expected_error(tmp_path: Path) -> None: + output = StringIO() + appfile = tmp_path / "app.py" + # fmt: off + appfile.write_text(dedent(""" + from numerous.tools import tool, field + + @tool + class MyApp: + field: str = field(label="My Field", default="my default") + """)) + read_app(appfile, "MyApp", output=output) + + import numerous + deprecated_module_file = Path(numerous.__file__).parent / "tools" / "__init__.py" + # fmt: off + expected_traceback = dedent(f""" + Traceback (most recent call last): + File "{appfile}", line 1, in + File "{deprecated_module_file}", line 11, in + raise RuntimeError(msg) + RuntimeError: You are trying to import from 'numerous.tools', which is deprecated. Use 'numerous.apps', and the @app decorator instead. + """).lstrip("\n") # noqa: E501 + expected_output = json.dumps( + { + "error": { + "unknown": { + "typename": "RuntimeError", + "traceback": expected_traceback, + }, + }, + }, + ) + actual_output = output.getvalue() + assert actual_output == expected_output + + +def test_read_app_without_empty_line_prints_expected_data_model(tmp_path: Path) -> None: + appfile = tmp_path / "app.py" + # fmt: off + appfile.write_text(dedent(""" + from numerous.apps import app, field + + @app + class MyApp: + field: str = field(label="My Field", default="my default")""")) + + output = StringIO() + read_app(appfile, "MyApp", output=output) + + expected_data_model = json.dumps( + { + "app": { + "name": "MyApp", + "title": "MyApp", + "elements": [ + { + "name": "field", + "label": "My Field", + "default": "my default", + "type": "string", + }, + ], + }, + }, + ) + assert output.getvalue() == expected_data_model diff --git a/python/tests/test_session.py b/python/tests/test_session.py new file mode 100644 index 00000000..f14ec8d3 --- /dev/null +++ b/python/tests/test_session.py @@ -0,0 +1,782 @@ +from typing import AsyncIterator +from unittest.mock import Mock + +import pytest +from numerous import action, app, container, html, slider +from numerous.generated.graphql import Client +from numerous.generated.graphql.all_elements import ( + AllElements, + AllElementsSession, + AllElementsSessionAllButton, + AllElementsSessionAllButtonGraphContext, + AllElementsSessionAllElement, + AllElementsSessionAllElementGraphContext, + AllElementsSessionAllHTMLElement, + AllElementsSessionAllHTMLElementGraphContext, + AllElementsSessionAllNumberField, + AllElementsSessionAllNumberFieldGraphContext, + AllElementsSessionAllSliderElement, + AllElementsSessionAllSliderElementGraphContext, + AllElementsSessionAllTextField, + AllElementsSessionAllTextFieldGraphContext, +) +from numerous.generated.graphql.fragments import GraphContextParent +from numerous.generated.graphql.input_types import ElementInput +from numerous.generated.graphql.update_element import ( + UpdateElement, + UpdateElementElementUpdate, +) +from numerous.generated.graphql.updates import ( + Updates, + UpdatesToolSessionEventToolSessionActionTriggered, + UpdatesToolSessionEventToolSessionActionTriggeredElement, + UpdatesToolSessionEventToolSessionElementUpdated, + UpdatesToolSessionEventToolSessionElementUpdatedElementHTMLElement, + UpdatesToolSessionEventToolSessionElementUpdatedElementHTMLElementGraphContext, + UpdatesToolSessionEventToolSessionElementUpdatedElementNumberField, + UpdatesToolSessionEventToolSessionElementUpdatedElementNumberFieldGraphContext, + UpdatesToolSessionEventToolSessionElementUpdatedElementSliderElement, + UpdatesToolSessionEventToolSessionElementUpdatedElementSliderElementGraphContext, + UpdatesToolSessionEventToolSessionElementUpdatedElementTextField, + UpdatesToolSessionEventToolSessionElementUpdatedElementTextFieldGraphContext, +) +from numerous.session import Session, SessionElementMissingError + +DEFAULT_SESSION_ID = "test_session_id" +DEFAULT_CLIENT_ID = "test_client_id" + +TEXT_ELEMENT_ID = "text_element_id" +TEXT_ELEMENT_NAME = "text_param" +TEXT_ELEMENT = AllElementsSessionAllTextField( + __typename="TextField", + id=TEXT_ELEMENT_ID, + graphContext=AllElementsSessionAllTextFieldGraphContext( + parent=None, + affectedBy=[], + affects=[], + ), + name=TEXT_ELEMENT_NAME, + textValue="text value", +) + +NUMBER_ELEMENT_ID = "number_element_id" +NUMBER_ELEMENT_NAME = "number_param" +NUMBER_ELEMENT = AllElementsSessionAllNumberField( + __typename="NumberField", + id=NUMBER_ELEMENT_ID, + graphContext=AllElementsSessionAllNumberFieldGraphContext( + parent=None, + affectedBy=[], + affects=[], + ), + name=NUMBER_ELEMENT_NAME, + numberValue=100.0, +) + +SLIDER_ELEMENT_ID = "slider_element_id" +SLIDER_ELEMENT_NAME = "slider_param" +SLIDER_ELEMENT_MIN_VALUE = -200.0 +SLIDER_ELEMENT_MAX_VALUE = 300.0 +SLIDER_ELEMENT = AllElementsSessionAllSliderElement( + __typename="SliderElement", + id=SLIDER_ELEMENT_ID, + graphContext=AllElementsSessionAllSliderElementGraphContext( + parent=None, + affectedBy=[], + affects=[], + ), + name=SLIDER_ELEMENT_NAME, + sliderValue=100.0, + minValue=SLIDER_ELEMENT_MIN_VALUE, + maxValue=SLIDER_ELEMENT_MAX_VALUE, +) + +HTML_ELEMENT_ID = "html_element_id" +HTML_ELEMENT_NAME = "html_param" +HTML_ELEMENT = AllElementsSessionAllHTMLElement( + __typename="HTMLElement", + id=HTML_ELEMENT_ID, + name=HTML_ELEMENT_NAME, + html="", + graphContext=AllElementsSessionAllHTMLElementGraphContext( + parent=None, + affectedBy=[], + affects=[], + ), +) + +ACTION_ELEMENT_ID = "button_element_id" +ACTION_ELEMENT_NAME = "my_action" +ACTION_ELEMENT = AllElementsSessionAllButton( + __typename="Button", + id=ACTION_ELEMENT_ID, + graphContext=AllElementsSessionAllButtonGraphContext( + parent=None, + affectedBy=[], + affects=[], + ), + name=ACTION_ELEMENT_NAME, + buttonValue="button value", +) + +CONTAINER_ELEMENT_ID = "container_element_id" +CONTAINER_ELEMENT_NAME = "container" +CONTAINER_ELEMENT = AllElementsSessionAllElement( + __typename="Container", + id=CONTAINER_ELEMENT_ID, + graphContext=AllElementsSessionAllElementGraphContext( + parent=None, + affectedBy=[], + affects=[], + ), + name=CONTAINER_ELEMENT_NAME, +) + +CONTAINER_CHILD_ELEMENT_ID = "container_child_element_id" +CONTAINER_CHILD_ELEMENT_NAME = "container_child" +CONTAINER_CHILD_ELEMENT = AllElementsSessionAllNumberField( + __typename="NumberField", + id=CONTAINER_CHILD_ELEMENT_ID, + graphContext=AllElementsSessionAllNumberFieldGraphContext( + parent=GraphContextParent( + __typename="Container", + id=CONTAINER_ELEMENT_ID, + ), + affectedBy=[], + affects=[], + ), + name=CONTAINER_CHILD_ELEMENT_NAME, + numberValue=100.0, +) + + +async def updates_mock_with_action_trigger( + _session_id: str, + _client_id: str, +) -> AsyncIterator[Updates]: + yield Updates( + toolSessionEvent=UpdatesToolSessionEventToolSessionActionTriggered( + __typename="ToolSessionActionTriggered", + element=UpdatesToolSessionEventToolSessionActionTriggeredElement( + id=ACTION_ELEMENT_ID, + name=ACTION_ELEMENT_NAME, + ), + ), + ) + + +@pytest.mark.asyncio() +async def test_initialize_requests_element_information() -> None: + gql = Mock(Client) + gql.all_elements.return_value = AllElements( + session=AllElementsSession( + id=DEFAULT_SESSION_ID, + all=[TEXT_ELEMENT], + clientID=DEFAULT_CLIENT_ID, + ), + ) + + @app + class TestTool: + text_param: str = "default" + + await Session.initialize(DEFAULT_SESSION_ID, gql, TestTool) + + gql.all_elements.assert_called_once_with(DEFAULT_SESSION_ID) + + +@pytest.mark.asyncio() +async def test_initialize_fails_when_session_is_missing_parameter() -> None: + gql = Mock(Client) + gql.all_elements.return_value = AllElements( + session=AllElementsSession( + id=DEFAULT_SESSION_ID, + all=[], + clientID=DEFAULT_CLIENT_ID, + ), + ) + + @app + class TestTool: + text_param: str + + with pytest.raises(SessionElementMissingError) as exception_info: + await Session.initialize( + DEFAULT_SESSION_ID, + gql, + TestTool, + ) + assert exception_info.value.args == ( + "Tool session missing required element 'text_param'", + ) + + +@pytest.mark.asyncio() +async def test_initialize_fails_when_session_is_missing_action() -> None: + gql = Mock(Client) + gql.all_elements.return_value = AllElements( + session=AllElementsSession( + id=DEFAULT_SESSION_ID, + all=[], + clientID=DEFAULT_CLIENT_ID, + ), + ) + + @app + class TestTool: + @action + def my_action(self) -> None: + pass + + with pytest.raises(SessionElementMissingError) as exception_info: + await Session.initialize( + DEFAULT_SESSION_ID, + gql, + TestTool, + ) + assert exception_info.value.args == ( + "Tool session missing required element 'my_action'", + ) + + +@pytest.mark.asyncio() +async def test_initialize_fails_when_session_is_missing_container() -> None: + gql = Mock(Client) + gql.all_elements.return_value = AllElements( + session=AllElementsSession( + id=DEFAULT_SESSION_ID, + all=[], + clientID=DEFAULT_CLIENT_ID, + ), + ) + + @container + class TestContainer: + param: str + + @app + class TestTool: + container: TestContainer + + with pytest.raises(SessionElementMissingError) as exception_info: + await Session.initialize( + DEFAULT_SESSION_ID, + gql, + TestTool, + ) + assert exception_info.value.args == ( + "Tool session missing required element 'container'", + ) + + +@pytest.mark.asyncio() +async def test_initialize_fails_when_session_is_missing_element_in_container() -> None: + gql = Mock(Client) + gql.all_elements.return_value = AllElements( + session=AllElementsSession( + id=DEFAULT_SESSION_ID, + all=[], + clientID=DEFAULT_CLIENT_ID, + ), + ) + + @container + class TestContainer: + param: str + + @app + class TestTool: + container: TestContainer + + with pytest.raises(SessionElementMissingError) as exception_info: + await Session.initialize( + DEFAULT_SESSION_ID, + gql, + TestTool, + ) + assert exception_info.value.args == ( + "Tool session missing required element 'container'", + ) + + +@pytest.mark.asyncio() +async def test_text_element_update_updates_value_in_instance() -> None: + gql = Mock(Client) + gql.all_elements.return_value = AllElements( + session=AllElementsSession( + id=DEFAULT_SESSION_ID, + all=[TEXT_ELEMENT], + clientID=DEFAULT_CLIENT_ID, + ), + ) + + async def updates_mock( + _session_id: str, + _client_id: str, + ) -> AsyncIterator[Updates]: + yield Updates( + toolSessionEvent=UpdatesToolSessionEventToolSessionElementUpdated( + __typename="ToolSessionElementUpdated", + element=UpdatesToolSessionEventToolSessionElementUpdatedElementTextField( + __typename="TextField", + id=TEXT_ELEMENT_ID, + name=TEXT_ELEMENT_NAME, + textValue="new text value", + graphContext=UpdatesToolSessionEventToolSessionElementUpdatedElementTextFieldGraphContext( + parent=None, + affectedBy=[], + affects=[], + ), + ), + ), + ) + + gql.updates = updates_mock + value_after_update = None + + @app + class TestTool: + text_param: str + + def text_param_updated(self) -> None: + nonlocal value_after_update + value_after_update = self.text_param + + session = await Session.initialize( + DEFAULT_SESSION_ID, + gql, + TestTool, + ) + await session.run() + + assert value_after_update == "new text value" + + +@pytest.mark.asyncio() +async def test_html_element_update_updates_value_in_instance() -> None: + gql = Mock(Client) + gql.all_elements.return_value = AllElements( + session=AllElementsSession( + id=DEFAULT_SESSION_ID, + all=[HTML_ELEMENT], + clientID=DEFAULT_CLIENT_ID, + ), + ) + + async def updates_mock( + _session_id: str, + _client_id: str, + ) -> AsyncIterator[Updates]: + yield Updates( + toolSessionEvent=UpdatesToolSessionEventToolSessionElementUpdated( + __typename="ToolSessionElementUpdated", + element=UpdatesToolSessionEventToolSessionElementUpdatedElementHTMLElement( + __typename="HTMLElement", + id=HTML_ELEMENT_ID, + name=HTML_ELEMENT_NAME, + html="
updated html!
", + graphContext=UpdatesToolSessionEventToolSessionElementUpdatedElementHTMLElementGraphContext( + parent=None, + affectedBy=[], + affects=[], + ), + ), + ), + ) + + gql.updates = updates_mock + value_after_update = None + + @app + class TestTool: + html_param: str = html() + + def html_param_updated(self) -> None: + nonlocal value_after_update + value_after_update = self.html_param + + session = await Session.initialize( + DEFAULT_SESSION_ID, + gql, + TestTool, + ) + await session.run() + + assert value_after_update == "
updated html!
" + + +@pytest.mark.asyncio() +async def test_number_element_update_updates_value_in_instance() -> None: + expected_number_value = 123.0 + gql = Mock(Client) + gql.all_elements.return_value = AllElements( + session=AllElementsSession( + id=DEFAULT_SESSION_ID, + all=[NUMBER_ELEMENT], + clientID=DEFAULT_CLIENT_ID, + ), + ) + + async def updates_mock( + _session_id: str, + _client_id: str, + ) -> AsyncIterator[Updates]: + yield Updates( + toolSessionEvent=UpdatesToolSessionEventToolSessionElementUpdated( + __typename="ToolSessionElementUpdated", + element=UpdatesToolSessionEventToolSessionElementUpdatedElementNumberField( + __typename="NumberField", + id=NUMBER_ELEMENT_ID, + name=NUMBER_ELEMENT_NAME, + numberValue=expected_number_value, + graphContext=UpdatesToolSessionEventToolSessionElementUpdatedElementNumberFieldGraphContext( + parent=None, + affectedBy=[], + affects=[], + ), + ), + ), + ) + + gql.updates = updates_mock + value_after_update = None + + @app + class TestTool: + number_param: float + + def number_param_updated(self) -> None: + nonlocal value_after_update + value_after_update = self.number_param + + session = await Session.initialize( + DEFAULT_SESSION_ID, + gql, + TestTool, + ) + await session.run() + + assert value_after_update == expected_number_value + + +@pytest.mark.asyncio() +async def test_slider_element_update_updates_value_in_instance() -> None: + expected_slider_value = 123.0 + gql = Mock(Client) + gql.all_elements.return_value = AllElements( + session=AllElementsSession( + id=DEFAULT_SESSION_ID, + all=[SLIDER_ELEMENT], + clientID=DEFAULT_CLIENT_ID, + ), + ) + + async def updates_mock( + _session_id: str, + _client_id: str, + ) -> AsyncIterator[Updates]: + yield Updates( + toolSessionEvent=UpdatesToolSessionEventToolSessionElementUpdated( + __typename="ToolSessionElementUpdated", + element=UpdatesToolSessionEventToolSessionElementUpdatedElementSliderElement( + __typename="SliderElement", + id=SLIDER_ELEMENT_ID, + name=SLIDER_ELEMENT_NAME, + graphContext=UpdatesToolSessionEventToolSessionElementUpdatedElementSliderElementGraphContext( + parent=None, + affectedBy=[], + affects=[], + ), + sliderValue=expected_slider_value, + minValue=SLIDER_ELEMENT_MIN_VALUE, + maxValue=SLIDER_ELEMENT_MAX_VALUE, + ), + ), + ) + + gql.updates = updates_mock + value_after_update = None + + @app + class TestTool: + slider_param: float = slider( + min_value=SLIDER_ELEMENT_MIN_VALUE, + max_value=SLIDER_ELEMENT_MAX_VALUE, + ) + + def slider_param_updated(self) -> None: + nonlocal value_after_update + value_after_update = self.slider_param + + session = await Session.initialize( + DEFAULT_SESSION_ID, + gql, + TestTool, + ) + await session.run() + + assert value_after_update == expected_slider_value + + +@pytest.mark.asyncio() +async def test_container_child_element_update_updates_value_in_instance() -> None: + expected_number_value = 123.0 + gql = Mock(Client) + gql.all_elements.return_value = AllElements( + session=AllElementsSession( + id=DEFAULT_SESSION_ID, + all=[CONTAINER_ELEMENT, CONTAINER_CHILD_ELEMENT], + clientID=DEFAULT_CLIENT_ID, + ), + ) + + async def updates_mock( + _session_id: str, + _client_id: str, + ) -> AsyncIterator[Updates]: + yield Updates( + toolSessionEvent=UpdatesToolSessionEventToolSessionElementUpdated( + __typename="ToolSessionElementUpdated", + element=UpdatesToolSessionEventToolSessionElementUpdatedElementNumberField( + __typename="NumberField", + id=CONTAINER_CHILD_ELEMENT_ID, + name=CONTAINER_CHILD_ELEMENT_NAME, + numberValue=expected_number_value, + graphContext=UpdatesToolSessionEventToolSessionElementUpdatedElementNumberFieldGraphContext( + parent=GraphContextParent( + __typename="Container", + id=CONTAINER_ELEMENT_ID, + ), + affectedBy=[], + affects=[], + ), + ), + ), + ) + + gql.updates = updates_mock + value_after_update = None + + @container + class TestContainer: + container_child: float + + def container_child_updated(self) -> None: + nonlocal value_after_update + value_after_update = self.container_child + + @app + class TestTool: + container: TestContainer + + session = await Session.initialize( + DEFAULT_SESSION_ID, + gql, + TestTool, + ) + await session.run() + + assert value_after_update == expected_number_value + + +@pytest.mark.asyncio() +async def test_element_updated_event_triggers_update_handler() -> None: + gql = Mock(Client) + gql.all_elements.return_value = AllElements( + session=AllElementsSession( + id=DEFAULT_SESSION_ID, + all=[TEXT_ELEMENT], + clientID=DEFAULT_CLIENT_ID, + ), + ) + + async def updates_mock(_session_id: str, _client_id: str) -> AsyncIterator[Updates]: + yield Updates( + toolSessionEvent=UpdatesToolSessionEventToolSessionElementUpdated( + __typename="ToolSessionElementUpdated", + element=UpdatesToolSessionEventToolSessionElementUpdatedElementTextField( + __typename="TextField", + id=TEXT_ELEMENT_ID, + name=TEXT_ELEMENT_NAME, + textValue="new text value", + graphContext=UpdatesToolSessionEventToolSessionElementUpdatedElementTextFieldGraphContext( + parent=None, + affectedBy=[], + affects=[], + ), + ), + ), + ) + + gql.updates = updates_mock + + param_updated = False + + @app + class TestTool: + text_param: str = "default value" + + def text_param_updated(self) -> None: + nonlocal param_updated + param_updated = True + + session = await Session.initialize( + DEFAULT_SESSION_ID, + gql, + TestTool, + ) + await session.run() + + assert param_updated + + +@pytest.mark.asyncio() +async def test_action_triggered_event_calls_action_method() -> None: + gql = Mock(Client) + gql.all_elements.return_value = AllElements( + session=AllElementsSession( + id=DEFAULT_SESSION_ID, + all=[ACTION_ELEMENT], + clientID=DEFAULT_CLIENT_ID, + ), + ) + gql.updates = updates_mock_with_action_trigger + + action_called = False + + @app + class TestTool: + @action + def my_action(self) -> None: + nonlocal action_called + action_called = True + + session = await Session.initialize( + DEFAULT_SESSION_ID, + gql, + TestTool, + ) + await session.run() + + assert action_called + + +@pytest.mark.asyncio() +async def test_setting_parameter_value_calls_element_update_mutation() -> None: + gql = Mock(Client) + gql.all_elements.return_value = AllElements( + session=AllElementsSession( + id=DEFAULT_SESSION_ID, + all=[TEXT_ELEMENT, ACTION_ELEMENT], + clientID=DEFAULT_CLIENT_ID, + ), + ) + gql.update_element.return_value = UpdateElement( + elementUpdate=UpdateElementElementUpdate(__typename="TextField"), + ) + gql.updates = updates_mock_with_action_trigger + + @app + class UpdateParameterTool: + text_param: str = "text value" + + def my_action(self) -> None: + self.text_param = "new text value" + + session = await Session.initialize( + DEFAULT_SESSION_ID, + gql, + UpdateParameterTool, + ) + await session.run() + + gql.update_element.assert_called_once_with( + session_id=DEFAULT_SESSION_ID, + client_id=DEFAULT_CLIENT_ID, + element=ElementInput(elementID=TEXT_ELEMENT_ID, textValue="new text value"), + ) + + +@pytest.mark.asyncio() +async def test_setting_html_element_value_calls_element_update_mutation() -> None: + gql = Mock(Client) + gql.all_elements.return_value = AllElements( + session=AllElementsSession( + id=DEFAULT_SESSION_ID, + all=[HTML_ELEMENT, ACTION_ELEMENT], + clientID=DEFAULT_CLIENT_ID, + ), + ) + gql.update_element.return_value = UpdateElement( + elementUpdate=UpdateElementElementUpdate(__typename="HTMLElement"), + ) + gql.updates = updates_mock_with_action_trigger + + @app + class UpdateParameterTool: + html_param: str = html() + + @action + def my_action(self) -> None: + self.html_param = "
new html content!
" + + session = await Session.initialize( + DEFAULT_SESSION_ID, + gql, + UpdateParameterTool, + ) + await session.run() + + gql.update_element.assert_called_once_with( + session_id=DEFAULT_SESSION_ID, + client_id=DEFAULT_CLIENT_ID, + element=ElementInput( + elementID=HTML_ELEMENT_ID, + htmlValue="
new html content!
", + ), + ) + + +@pytest.mark.asyncio() +async def test_setting_slider_element_value_calls_element_update_mutation() -> None: + expected_slider_update_value = 111.0 + + gql = Mock(Client) + gql.all_elements.return_value = AllElements( + session=AllElementsSession( + id=DEFAULT_SESSION_ID, + all=[SLIDER_ELEMENT, ACTION_ELEMENT], + clientID=DEFAULT_CLIENT_ID, + ), + ) + gql.update_element.return_value = UpdateElement( + elementUpdate=UpdateElementElementUpdate(__typename="SliderElement"), + ) + gql.updates = updates_mock_with_action_trigger + + @app + class UpdateParameterTool: + slider_param: float = slider( + min_value=SLIDER_ELEMENT_MIN_VALUE, + max_value=SLIDER_ELEMENT_MAX_VALUE, + ) + + @action + def my_action(self) -> None: + self.slider_param = expected_slider_update_value + + session = await Session.initialize( + DEFAULT_SESSION_ID, + gql, + UpdateParameterTool, + ) + await session.run() + + gql.update_element.assert_called_once_with( + session_id=DEFAULT_SESSION_ID, + client_id=DEFAULT_CLIENT_ID, + element=ElementInput( + elementID=SLIDER_ELEMENT_ID, + sliderValue=expected_slider_update_value, + ), + ) diff --git a/python/tests/test_tool.py b/python/tests/test_tool.py new file mode 100644 index 00000000..649f6bc5 --- /dev/null +++ b/python/tests/test_tool.py @@ -0,0 +1,44 @@ +from numerous import app, container + + +def test_initialize_decorated_app() -> None: + param_value = 5 + + @app + class App: + param: int = param_value + + instance = App() + + assert instance + assert instance.param == param_value + assert getattr(instance, "__numerous_app__", False) is True + + +def test_initialize_decorated_container() -> None: + param_value = 5 + + @container + class Container: + param: int = param_value + + instance = Container() + + assert instance + assert instance.param == param_value + assert getattr(instance, "__container__", False) is True + + +def test_initialize_decorated_app_with_pretty_name() -> None: + param_value = 5 + + @app(title="my_pretty_test_app") + class App: + param: int = param_value + + instance = App() + + assert instance + assert instance.param == param_value + assert getattr(instance, "__title__", False) == "my_pretty_test_app" + assert getattr(instance, "__numerous_app__", False) is True diff --git a/python/tests/test_updates.py b/python/tests/test_updates.py new file mode 100644 index 00000000..e69de29b diff --git a/setup.py b/setup.py new file mode 100644 index 00000000..60684932 --- /dev/null +++ b/setup.py @@ -0,0 +1,3 @@ +from setuptools import setup + +setup() diff --git a/shared/schema.gql b/shared/schema.gql new file mode 100644 index 00000000..e6355244 --- /dev/null +++ b/shared/schema.gql @@ -0,0 +1,478 @@ +scalar Time +scalar Upload + +directive @client on QUERY | FIELD +directive @trackOperation(eventName: String!) on FIELD_DEFINITION +directive @canAccessInvitation on FIELD_DEFINITION + +############################################################################### +### Auth +############################################################################### + +directive @hasRole(role: AuthRole!) on FIELD_DEFINITION + +enum AuthRole { + AUTHENTICATED + ADMIN + USER +} + +############################################################################### +### Auth end +############################################################################### + +############################################################################### +### User management +############################################################################### + +enum Role { + ADMIN + USER +} + +type OrganizationMembership { + organization: Organization! + role: Role! +} + +type User { + fullName: String! + memberships: [OrganizationMembership!]! +} + +type Query { + me: User! @hasRole(role: AUTHENTICATED) +} + +############################################################################### +### End of user management +############################################################################### + +############################################################################### +### Organization management +############################################################################### + +type Organization { + id: ID! + name: String! + slug: String! + apps: [App!]! + members: [OrganizationMembership!]! +} + +type OrganizationInvitation { + id: ID! + email: String! + organizationName: String! + invitedAt: Time! + role: Role! +} + +type InvalidEmail { + email: String! +} + +type OrganizationMemberExists { + email: String! +} + +input OrganizationInvitationInput { + role: Role! + email: String! +} + +input NewOrganization { + name: String! +} + +type OrganizationNotFound { + id: ID! + slug: String! +} + +type OrganizationRenameFailure { + result: String! +} + +union OrganizationRenameResult = + | Organization + | OrganizationNotFound + | OrganizationRenameFailure + +union OrganizationQueryResult = Organization | OrganizationNotFound + +type OrganizationInvitationNotFound { + id: ID! +} + +union OrganizationInvitationQueryResult = + | OrganizationInvitation + | OrganizationNotFound + | OrganizationInvitationNotFound + +union OrganizationInvitationCreateResult = + | OrganizationInvitation + | OrganizationNotFound + | InvalidEmail + | OrganizationMemberExists + +union OrganizationInvitationAcceptResult = Organization | OrganizationNotFound + +extend type Query { + organization(organizationSlug: ID): OrganizationQueryResult! + @hasRole(role: USER) + organizationInvitation(invitationId: ID!): OrganizationInvitationQueryResult + @canAccessInvitation +} +type Mutation { + organizationCreate(input: NewOrganization!): Organization! + @hasRole(role: AUTHENTICATED) + organizationRename( + organizationId: ID! + name: String! + ): OrganizationRenameResult! @hasRole(role: ADMIN) + organizationInvitationCreate( + organizationId: ID! + input: OrganizationInvitationInput + ): OrganizationInvitationCreateResult! @hasRole(role: ADMIN) + organizationInvitationAccept( + invitationId: ID! + ): OrganizationInvitationAcceptResult @canAccessInvitation +} + +############################################################################### +### End of organization management +############################################################################### + +############################################################################### +### Tool management +############################################################################### + +type Tool { + id: ID! + name: String! + description: String + user: User! + publicUrl: String + sharedUrl: String + createdAt: Time! +} + +type App { + id: ID! + name: String! + description: String + user: User! + publicUrl: String + sharedUrl: String + createdAt: Time! +} + +type PublicTool { + developer: User! + name: String! + description: String + pictureUrl: String + publicUrl: String! +} + +extend type Query { + publicTools: [PublicTool!] + tool(id: ID!): Tool! + tools: [Tool!]! @hasRole(role: AUTHENTICATED) +} + +input NewTool { + userId: ID! + manifest: String! +} + +type ToolDeleteSuccess { + result: String! +} + +type ToolDeleteFailure { + result: String! +} + +union ToolDeleteResult = ToolDeleteSuccess | ToolDeleteFailure + +type AppDeploy { + app: App! + buildId: ID! +} + +extend type Mutation { + toolCreate(input: NewTool!): Tool! @trackOperation(eventName: "App Create") + toolPublish(id: ID!): Tool! @trackOperation(eventName: "App Publish") + toolUnpublish(id: ID!): Tool! @trackOperation(eventName: "App Unpublish") + toolDelete(id: ID!): ToolDeleteResult! + @trackOperation(eventName: "App Delete") + organizationAppDeploy( + appId: ID! + organizationSlug: ID! + appArchive: Upload! + ): AppDeploy! @hasRole(role: USER) +} + +############################################################################### +### End of tool management +############################################################################### + +############################################################################### +### Job management +############################################################################### + +type Job { + id: ID! + status: String + proxyUrl: String + user: User! + createdAt: Time! +} + +type StopJobPayload { + message: String! +} + +enum ToolHashType { + public + shared +} + +extend type Query { + job(id: ID!): Job! + jobsByTool(id: ID!): [Job!]! + jobs: [Job!]! +} + +extend type Mutation { + jobStart(toolHash: ID!, hashType: ToolHashType!): Job! + @trackOperation(eventName: "App Use/Requested from Proxy") + jobStop(id: ID!): StopJobPayload! +} + +############################################################################### +### End of job management +############################################################################### + +############################################################################### +### Custom tool development +############################################################################### + +interface ElementGraphParent { + id: ID! +} + +type ElementGraphContext { + parent: ElementGraphParent + affectedBy: [Element]! + affects: [Element]! +} + +interface Element { + id: ID! + name: String! + label: String! + graphContext: ElementGraphContext! +} + +type Container implements Element & ElementGraphParent { + id: ID! + name: String! + label: String! + graphContext: ElementGraphContext! +} + +type SliderElement implements Element { + id: ID! + name: String! + label: String! + graphContext: ElementGraphContext! + value: Float! + minValue: Float! + maxValue: Float! +} + +type HTMLElement implements Element { + id: ID! + name: String! + label: String! + graphContext: ElementGraphContext! + html: String! +} + +type Button implements Element { + id: ID! + name: String! + label: String! + graphContext: ElementGraphContext! + value: String! +} + +type TextField implements Element { + id: ID! + name: String! + label: String! + graphContext: ElementGraphContext! + value: String! +} + +type NumberField implements Element { + id: ID! + name: String! + label: String! + graphContext: ElementGraphContext! + value: Float! +} + +type ElementList implements Element & ElementGraphParent { + id: ID! + name: String! + label: String! + graphContext: ElementGraphContext! +} + +type ElementSelect implements Element & ElementGraphParent { + id: ID! + name: String! + label: String! + graphContext: ElementGraphContext! + selectedOption: Element! +} + +type ToolSession { + id: ID! + name: String! + allElements: [Element!]! + isActive: Boolean! + clientID: String! + title: String! +} + +input ElementInput { + elementID: ID! + textValue: String + numberValue: Float + htmlValue: String + sliderValue: Float +} + +input ElementSelectInput { + selectElementID: ID! + selectedOptionID: ID! +} + +input ListElementInput { + listElementID: ID! +} + +extend type Query { + toolSession(id: ID!): ToolSession! +} + +extend type Mutation { + toolSessionCreate: ToolSession! + elementUpdate( + toolSessionId: ID! + clientId: ID! + element: ElementInput! + ): Element! + elementTrigger( + toolSessionId: ID! + clientId: ID! + actionElementId: ID! + ): Element! + elementSelectionUpdate( + clientId: ID! + elementSelection: ElementSelectInput! + ): Element! + listElementAdd(clientId: ID!, listElement: ListElementInput): Element! + listElementRemove(clientId: ID!, listItemID: ID!): Element! +} + +type ToolSessionElementAdded { + element: Element! +} + +type ToolSessionElementRemoved { + element: Element! +} + +type ToolSessionElementUpdated { + element: Element! +} + +type ToolSessionActionTriggered { + element: Button! +} + +union ToolSessionEvent = + | ToolSessionElementAdded + | ToolSessionElementRemoved + | ToolSessionElementUpdated + | ToolSessionActionTriggered + +type Subscription { + toolSessionEvent(toolSessionId: ID!, clientId: ID!): ToolSessionEvent! +} + +############################################################################### +### End of custom tool development +############################################################################### + +############################################################################### +### CLI Push command +############################################################################### + +type buildConfiguration { + buildId: ID! +} + +type BuildEventSuccess { + result: String! +} + +type BuildEventFailure { + result: String! +} + +type BuildEventInfo { + result: String! +} + +union BuildEvent = BuildEventSuccess | BuildEventFailure | BuildEventInfo + +extend type Mutation { + buildPush(file: Upload!, id: ID!): buildConfiguration! + @trackOperation(eventName: "App Push") +} + +extend type Subscription { + buildEvents(buildId: ID!, appPath: String): BuildEvent! +} + +extend type Subscription { + deployEvents(toolID: ID!): BuildEvent! +} + +############################################################################### +### End of CLI Push command +############################################################################### + +############################################################################### +### CLI Logs command +############################################################################### + +type LogMessage { + time: Time! + message: String! +} + +extend type Subscription { + logs(appId: ID!): LogMessage! +} + +############################################################################### +### End of CLI Push command +###############################################################################