diff --git a/deployment/server/docker-compose.dev.yml b/deployment/server/docker-compose.dev.yml index bb33b2b2..922103f6 100644 --- a/deployment/server/docker-compose.dev.yml +++ b/deployment/server/docker-compose.dev.yml @@ -18,6 +18,9 @@ services: - DATABASE_NAME=${DATABASE_NAME} - DATABASE_USER=${DATABASE_USER} - DATABASE_PASSWORD=${DATABASE_PASSWORD} + # Sentry + - SENTRY_DSN=${SENTRY_DSN} + - SENTRY_ENVIRONMENT=local depends_on: - db healthcheck: @@ -37,6 +40,8 @@ services: - VITE_AUTH0_DOMAIN=${VITE_AUTH0_DOMAIN} - VITE_AUTH0_CLIENT_ID=${VITE_AUTH0_CLIENT_ID} - VITE_AUTH0_AUDIENCE=${VITE_AUTH0_AUDIENCE} + - VITE_SENTRY_DSN=${VITE_SENTRY_DSN} + - VITE_SENTRY_ENVIRONMENT=local depends_on: - api healthcheck: diff --git a/deployment/server/docker-compose.yml b/deployment/server/docker-compose.yml index 4b713b99..b82eb62c 100644 --- a/deployment/server/docker-compose.yml +++ b/deployment/server/docker-compose.yml @@ -16,6 +16,9 @@ services: - DATABASE_NAME=${DATABASE_NAME} - DATABASE_USER=${DATABASE_USER} - DATABASE_PASSWORD=${DATABASE_PASSWORD} + # Sentry + - SENTRY_DSN=${SENTRY_DSN} + - SENTRY_ENVIRONMENT=prod depends_on: - db healthcheck: @@ -35,6 +38,8 @@ services: - VITE_AUTH0_DOMAIN=${VITE_AUTH0_DOMAIN} - VITE_AUTH0_CLIENT_ID=${VITE_AUTH0_CLIENT_ID} - VITE_AUTH0_AUDIENCE=${VITE_AUTH0_AUDIENCE} + - VITE_SENTRY_DSN=${VITE_SENTRY_DSN} + - VITE_SENTRY_ENVIRONMENT=prod depends_on: - api healthcheck: diff --git a/services/api/carlos/api/app_factory.py b/services/api/carlos/api/app_factory.py index 4e31ada0..a29b43c2 100644 --- a/services/api/carlos/api/app_factory.py +++ b/services/api/carlos/api/app_factory.py @@ -2,9 +2,16 @@ from typing import Any +import sentry_sdk from fastapi import FastAPI from fastapi.routing import APIRoute from pydantic.alias_generators import to_camel +from sentry_sdk.integrations.asyncio import AsyncioIntegration +from sentry_sdk.integrations.asyncpg import AsyncPGIntegration +from sentry_sdk.integrations.fastapi import FastApiIntegration +from sentry_sdk.integrations.httpx import HttpxIntegration +from sentry_sdk.integrations.loguru import LoguruIntegration +from sentry_sdk.integrations.sqlalchemy import SqlalchemyIntegration from starlette.middleware.cors import CORSMiddleware from starlette.middleware.gzip import GZipMiddleware @@ -22,6 +29,8 @@ def create_app(api_settings: CarlosAPISettings | None = None) -> FastAPI: api_settings = api_settings or CarlosAPISettings() + configure_sentry() + # ensures that the logging is handled via loguru setup_logging(level=api_settings.LOG_LEVEL) @@ -76,3 +85,17 @@ def get_cors_kwargs(api_settings: CarlosAPISettings) -> dict[str, Any]: "allow_methods": ["*"], "allow_headers": ["*"], } + + +def configure_sentry(): + """Initializes sentry based on environment variables.""" + sentry_sdk.init( + integrations=[ + AsyncPGIntegration(), + AsyncioIntegration(), + FastApiIntegration(), + HttpxIntegration(), + LoguruIntegration(), + SqlalchemyIntegration(), + ], + ) diff --git a/services/api/carlos/api/routes/data_routes_test.py b/services/api/carlos/api/routes/data_routes_test.py index 78909d40..44d35faa 100644 --- a/services/api/carlos/api/routes/data_routes_test.py +++ b/services/api/carlos/api/routes/data_routes_test.py @@ -14,8 +14,8 @@ async def test_get_timeseries_route( "/data/timeseries", params={ "timeseriesId": [signal.timeseries_id for signal in driver_signals], - "start_at_utc": "2022-01-01T00:00:00Z", - "end_at_utc": "2022-01-02T00:00:00Z", + "startAtUtc": "2022-01-01T00:00:00Z", + "endAtUtc": "2022-01-02T00:00:00Z", }, ) assert response.status_code == 200 diff --git a/services/api/carlos/api/routes/signals_routes_test.py b/services/api/carlos/api/routes/signals_routes_test.py index 0c3b087f..84d93990 100644 --- a/services/api/carlos/api/routes/signals_routes_test.py +++ b/services/api/carlos/api/routes/signals_routes_test.py @@ -15,7 +15,7 @@ def test_update_device_signal_route( response = client.put( f"/signals/{driver_signals[0].timeseries_id}", - json=to_update.dict(), + json=to_update.model_dump(), ) assert response.is_success, response.text updated = CarlosDeviceSignal.model_validate(response.json()) diff --git a/services/api/poetry.lock b/services/api/poetry.lock index 54fd0d63..826845c0 100644 --- a/services/api/poetry.lock +++ b/services/api/poetry.lock @@ -1786,6 +1786,58 @@ files = [ {file = "semver-3.0.2.tar.gz", hash = "sha256:6253adb39c70f6e51afed2fa7152bcd414c411286088fb4b9effb133885ab4cc"}, ] +[[package]] +name = "sentry-sdk" +version = "2.0.1" +description = "Python client for Sentry (https://sentry.io)" +optional = false +python-versions = ">=3.6" +files = [ + {file = "sentry_sdk-2.0.1-py2.py3-none-any.whl", hash = "sha256:b54c54a2160f509cf2757260d0cf3885b608c6192c2555a3857e3a4d0f84bdb3"}, + {file = "sentry_sdk-2.0.1.tar.gz", hash = "sha256:c278e0f523f6f0ee69dc43ad26dcdb1202dffe5ac326ae31472e012d941bee21"}, +] + +[package.dependencies] +asyncpg = {version = ">=0.23", optional = true, markers = "extra == \"asyncpg\""} +certifi = "*" +fastapi = {version = ">=0.79.0", optional = true, markers = "extra == \"fastapi\""} +httpx = {version = ">=0.16.0", optional = true, markers = "extra == \"httpx\""} +loguru = {version = ">=0.5", optional = true, markers = "extra == \"loguru\""} +sqlalchemy = {version = ">=1.2", optional = true, markers = "extra == \"sqlalchemy\""} +urllib3 = ">=1.26.11" + +[package.extras] +aiohttp = ["aiohttp (>=3.5)"] +arq = ["arq (>=0.23)"] +asyncpg = ["asyncpg (>=0.23)"] +beam = ["apache-beam (>=2.12)"] +bottle = ["bottle (>=0.12.13)"] +celery = ["celery (>=3)"] +celery-redbeat = ["celery-redbeat (>=2)"] +chalice = ["chalice (>=1.16.0)"] +clickhouse-driver = ["clickhouse-driver (>=0.2.0)"] +django = ["django (>=1.8)"] +falcon = ["falcon (>=1.4)"] +fastapi = ["fastapi (>=0.79.0)"] +flask = ["blinker (>=1.1)", "flask (>=0.11)", "markupsafe"] +grpcio = ["grpcio (>=1.21.1)"] +httpx = ["httpx (>=0.16.0)"] +huey = ["huey (>=2)"] +loguru = ["loguru (>=0.5)"] +openai = ["openai (>=1.0.0)", "tiktoken (>=0.3.0)"] +opentelemetry = ["opentelemetry-distro (>=0.35b0)"] +opentelemetry-experimental = ["opentelemetry-distro (>=0.40b0,<1.0)", "opentelemetry-instrumentation-aiohttp-client (>=0.40b0,<1.0)", "opentelemetry-instrumentation-django (>=0.40b0,<1.0)", "opentelemetry-instrumentation-fastapi (>=0.40b0,<1.0)", "opentelemetry-instrumentation-flask (>=0.40b0,<1.0)", "opentelemetry-instrumentation-requests (>=0.40b0,<1.0)", "opentelemetry-instrumentation-sqlite3 (>=0.40b0,<1.0)", "opentelemetry-instrumentation-urllib (>=0.40b0,<1.0)"] +pure-eval = ["asttokens", "executing", "pure-eval"] +pymongo = ["pymongo (>=3.1)"] +pyspark = ["pyspark (>=2.4.4)"] +quart = ["blinker (>=1.1)", "quart (>=0.16.1)"] +rq = ["rq (>=0.6)"] +sanic = ["sanic (>=0.8)"] +sqlalchemy = ["sqlalchemy (>=1.2)"] +starlette = ["starlette (>=0.19.1)"] +starlite = ["starlite (>=1.48)"] +tornado = ["tornado (>=5)"] + [[package]] name = "smbus2" version = "0.4.3" @@ -2280,4 +2332,4 @@ dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"] [metadata] lock-version = "2.0" python-versions = ">=3.11,<3.12" -content-hash = "aac80bee0a13dfaa487ea3a78ea849e41332173cea738d99e632cf00f74f4cd1" +content-hash = "4b8ff551471531a1742563953a3d9ac189d739c8e447170c6fa7c4efa5726a75" diff --git a/services/api/pyproject.toml b/services/api/pyproject.toml index fbf5767b..b1607566 100644 --- a/services/api/pyproject.toml +++ b/services/api/pyproject.toml @@ -25,13 +25,10 @@ httpx = ">=0.23.1,<1.0.0" sqlalchemy = {extras = ["mypy"], version = "^2.0.0"} asyncpg = "^0.29.0" loguru = "^0.7.2" +sentry-sdk = {extras = ["fastapi", "sqlalchemy", "loguru", "asyncpg", "httpx"], version = "^2.0.1"} [tool.poetry.group.dev.dependencies] "devtools" = {path = "../../lib/py_dev_dependencies", develop = true} -"carlos.database" = {path = "../../lib/py_carlos_database", develop = true} -"carlos.edge.interface" = {path = "../../lib/py_edge_interface", develop = true} -"carlos.edge.device" = {path = "../../lib/py_edge_device", develop = true} -"carlos.edge.server" = {path = "../../lib/py_edge_server", develop = true} [build-system] requires = ["poetry-core>=1.0.0"] diff --git a/services/device/device/run.py b/services/device/device/run.py index 8ff366dd..8e1e0626 100644 --- a/services/device/device/run.py +++ b/services/device/device/run.py @@ -3,6 +3,7 @@ from loguru import logger from device.connection import read_connection_settings +from device.sentry import setup_sentry from device.websocket import DeviceWebsocketClient @@ -24,6 +25,8 @@ async def main(): # pragma: no cover logger.info(f"Starting Carlos device (v{VERSION})...") + setup_sentry() + device_connection = read_connection_settings() protocol = DeviceWebsocketClient(settings=device_connection) diff --git a/services/device/device/sentry.py b/services/device/device/sentry.py new file mode 100644 index 00000000..72c1b6e4 --- /dev/null +++ b/services/device/device/sentry.py @@ -0,0 +1,43 @@ +from pathlib import Path + +import sentry_sdk +import yaml +from loguru import logger +from pydantic import Field, ValidationError +from pydantic_settings import BaseSettings +from sentry_sdk.integrations.asyncio import AsyncioIntegration +from sentry_sdk.integrations.httpx import HttpxIntegration +from sentry_sdk.integrations.loguru import LoguruIntegration +from sentry_sdk.integrations.sqlalchemy import SqlalchemyIntegration + + +class SentrySettings(BaseSettings): # pragma: no cover + + SENTRY_DSN: str = Field( + ..., + description="The DSN tells the SDK where to send the events. If this value " + "is not provided, the SDK will try to read it from the " + "SENTRY_DSN environment variable. If that variable also does not exist, " + "the SDK will just not send any events.", + ) + + +def setup_sentry(): # pragma: no cover + + try: + with open(Path.cwd() / "sentry_config", "r") as file: + sentry_config = SentrySettings.model_validate(yaml.safe_load(file)) + except FileNotFoundError: + return + except ValidationError: + logger.exception("Failed to validate sentry config.") + + sentry_sdk.init( + dsn=sentry_config.SENTRY_DSN, + integrations=[ + AsyncioIntegration(), + HttpxIntegration(), + SqlalchemyIntegration(), + LoguruIntegration(), + ], + ) diff --git a/services/device/poetry.lock b/services/device/poetry.lock index 16bdbe4c..875927fe 100644 --- a/services/device/poetry.lock +++ b/services/device/poetry.lock @@ -1371,6 +1371,55 @@ files = [ {file = "semver-3.0.2.tar.gz", hash = "sha256:6253adb39c70f6e51afed2fa7152bcd414c411286088fb4b9effb133885ab4cc"}, ] +[[package]] +name = "sentry-sdk" +version = "2.0.1" +description = "Python client for Sentry (https://sentry.io)" +optional = false +python-versions = ">=3.6" +files = [ + {file = "sentry_sdk-2.0.1-py2.py3-none-any.whl", hash = "sha256:b54c54a2160f509cf2757260d0cf3885b608c6192c2555a3857e3a4d0f84bdb3"}, + {file = "sentry_sdk-2.0.1.tar.gz", hash = "sha256:c278e0f523f6f0ee69dc43ad26dcdb1202dffe5ac326ae31472e012d941bee21"}, +] + +[package.dependencies] +certifi = "*" +loguru = {version = ">=0.5", optional = true, markers = "extra == \"loguru\""} +sqlalchemy = {version = ">=1.2", optional = true, markers = "extra == \"sqlalchemy\""} +urllib3 = ">=1.26.11" + +[package.extras] +aiohttp = ["aiohttp (>=3.5)"] +arq = ["arq (>=0.23)"] +asyncpg = ["asyncpg (>=0.23)"] +beam = ["apache-beam (>=2.12)"] +bottle = ["bottle (>=0.12.13)"] +celery = ["celery (>=3)"] +celery-redbeat = ["celery-redbeat (>=2)"] +chalice = ["chalice (>=1.16.0)"] +clickhouse-driver = ["clickhouse-driver (>=0.2.0)"] +django = ["django (>=1.8)"] +falcon = ["falcon (>=1.4)"] +fastapi = ["fastapi (>=0.79.0)"] +flask = ["blinker (>=1.1)", "flask (>=0.11)", "markupsafe"] +grpcio = ["grpcio (>=1.21.1)"] +httpx = ["httpx (>=0.16.0)"] +huey = ["huey (>=2)"] +loguru = ["loguru (>=0.5)"] +openai = ["openai (>=1.0.0)", "tiktoken (>=0.3.0)"] +opentelemetry = ["opentelemetry-distro (>=0.35b0)"] +opentelemetry-experimental = ["opentelemetry-distro (>=0.40b0,<1.0)", "opentelemetry-instrumentation-aiohttp-client (>=0.40b0,<1.0)", "opentelemetry-instrumentation-django (>=0.40b0,<1.0)", "opentelemetry-instrumentation-fastapi (>=0.40b0,<1.0)", "opentelemetry-instrumentation-flask (>=0.40b0,<1.0)", "opentelemetry-instrumentation-requests (>=0.40b0,<1.0)", "opentelemetry-instrumentation-sqlite3 (>=0.40b0,<1.0)", "opentelemetry-instrumentation-urllib (>=0.40b0,<1.0)"] +pure-eval = ["asttokens", "executing", "pure-eval"] +pymongo = ["pymongo (>=3.1)"] +pyspark = ["pyspark (>=2.4.4)"] +quart = ["blinker (>=1.1)", "quart (>=0.16.1)"] +rq = ["rq (>=0.6)"] +sanic = ["sanic (>=0.8)"] +sqlalchemy = ["sqlalchemy (>=1.2)"] +starlette = ["starlette (>=0.19.1)"] +starlite = ["starlite (>=1.48)"] +tornado = ["tornado (>=5)"] + [[package]] name = "shellingham" version = "1.5.4" @@ -1539,6 +1588,17 @@ rich = ">=10.11.0" shellingham = ">=1.3.0" typing-extensions = ">=3.7.4.3" +[[package]] +name = "types-pyyaml" +version = "6.0.12.20240311" +description = "Typing stubs for PyYAML" +optional = false +python-versions = ">=3.8" +files = [ + {file = "types-PyYAML-6.0.12.20240311.tar.gz", hash = "sha256:a9e0f0f88dc835739b0c1ca51ee90d04ca2a897a71af79de9aec5f38cb0a5342"}, + {file = "types_PyYAML-6.0.12.20240311-py3-none-any.whl", hash = "sha256:b845b06a1c7e54b8e5b4c683043de0d9caf205e7434b3edc678ff2411979b8f6"}, +] + [[package]] name = "typing-extensions" version = "4.11.0" @@ -1720,4 +1780,4 @@ dev = ["black (>=19.3b0)", "pytest (>=4.6.2)"] [metadata] lock-version = "2.0" python-versions = ">=3.11,<3.12" -content-hash = "616752a3340cadd82d4cae29f20be522d6ef952c7208eb49836ed5286c710962" +content-hash = "0ff1c5adf0ab3c2e9a3fb3007a15cdd79c59cc0c91337917cb477289dff28eb8" diff --git a/services/device/pyproject.toml b/services/device/pyproject.toml index 8cbdd083..6da2253e 100644 --- a/services/device/pyproject.toml +++ b/services/device/pyproject.toml @@ -16,10 +16,11 @@ httpx = "^0.27.0" # CLI tooling typer = "^0.12.0" rich = "^13.7.1" +sentry-sdk = {extras = ["sqlalchemy", "loguru",], version = "^2.0.1"} [tool.poetry.group.dev.dependencies] "devtools" = {path = "../../lib/py_dev_dependencies", develop = true} -"carlos.edge.device" = {path = "../../lib/py_edge_device", develop = true} +types-pyyaml = "^6.0.12.20240311" [tool.poetry.scripts] carlos-device = "device.cli:main" diff --git a/services/frontend/package.json b/services/frontend/package.json index c26f7481..bcf96516 100644 --- a/services/frontend/package.json +++ b/services/frontend/package.json @@ -20,6 +20,7 @@ "dependencies": { "@auth0/auth0-vue": "^2.3.3", "@carbon/icons-vue": "^10.83.1", + "@sentry/vue": "^7.112.2", "axios": "^1.6.8", "axios-jwt": "^4.0.2", "chart.js": "^4.4.2", diff --git a/services/frontend/src/main.ts b/services/frontend/src/main.ts index 771e4174..31ed8364 100644 --- a/services/frontend/src/main.ts +++ b/services/frontend/src/main.ts @@ -21,6 +21,9 @@ import config from '@/config.ts'; import i18n from '@/plugins/i18n'; import '@/plugins/chartjs'; import '@/plugins/dayjs'; +import { + useSentry, +} from '@/plugins/sentry.ts'; const pinia = createPinia(); const app = createApp(App); @@ -42,6 +45,8 @@ app.use( ); app.use(router); +useSentry(app); + app.directive('tooltip', Tooltip); app.mount('#app'); diff --git a/services/frontend/src/plugins/sentry.ts b/services/frontend/src/plugins/sentry.ts new file mode 100644 index 00000000..768ac3c8 --- /dev/null +++ b/services/frontend/src/plugins/sentry.ts @@ -0,0 +1,33 @@ +import * as Sentry from '@sentry/vue'; +import { + App, +} from 'vue'; +import config from '@/config'; +import packageInfo from '@/../package.json'; + +export function useSentry(app: App) { + const tracePropagationTargets = [ + 'localhost', + ]; + if (config.VITE_APP_API_URL !== undefined) { + tracePropagationTargets.push(config.VITE_APP_API_URL); + } + + Sentry.init({ + app, + dsn: config.VITE_SENTRY_DSN, + environment: config.VITE_SENTRY_ENVIRONMENT, + release: `Carlos Frontend@${packageInfo.version}`, + integrations: [ + Sentry.browserTracingIntegration(), + Sentry.replayIntegration(), + ], + // Performance Monitoring + tracesSampleRate: 0.1, + // Set 'tracePropagationTargets' to control for which URLs distributed tracing should be enabled + tracePropagationTargets, + // Session Replay + replaysSessionSampleRate: 0.0, + replaysOnErrorSampleRate: 1.0, + }); +} diff --git a/yarn.lock b/yarn.lock index ae774da7..f846b67d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -487,6 +487,98 @@ resolved "https://registry.yarnpkg.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.17.0.tgz#3b8ec9d6a7eccca80dd1f16fe444abe128a2ec08" integrity sha512-ve+D8t1prRSRnF2S3pyDtTXDlvW1Pngbz76tjgYFQW1jxVSysmQCZfPoDAo4WP+Ano8zeYp85LsArZBI12HfwQ== +"@sentry-internal/feedback@7.112.2": + version "7.112.2" + resolved "https://registry.yarnpkg.com/@sentry-internal/feedback/-/feedback-7.112.2.tgz#3945ae9e980854e1d53560ed6a28684f02625fbc" + integrity sha512-z+XP8BwB8B3pa+i8xqbrPsbtDWUFUS6wo+FJbmOYUqOusJJbVFDAhBoEdKoo5ZjOcsAZG7XR6cA9zrhJynIWBA== + dependencies: + "@sentry/core" "7.112.2" + "@sentry/types" "7.112.2" + "@sentry/utils" "7.112.2" + +"@sentry-internal/replay-canvas@7.112.2": + version "7.112.2" + resolved "https://registry.yarnpkg.com/@sentry-internal/replay-canvas/-/replay-canvas-7.112.2.tgz#a29719ffb816dec01661b81def09d24704476d86" + integrity sha512-BCCCxrZ1wJvN6La5gg1JJbKitAhJI5MATCnhtklsZbUcHkHB9iZoj19J65+P56gwssvHz5xh63AjNiITaetIRg== + dependencies: + "@sentry/core" "7.112.2" + "@sentry/replay" "7.112.2" + "@sentry/types" "7.112.2" + "@sentry/utils" "7.112.2" + +"@sentry-internal/tracing@7.112.2": + version "7.112.2" + resolved "https://registry.yarnpkg.com/@sentry-internal/tracing/-/tracing-7.112.2.tgz#83460e51875ddb160c060bfee2e21833117f259c" + integrity sha512-fT1Y46J4lfXZkgFkb03YMNeIEs2xS6jdKMoukMFQfRfVvL9fSWEbTgZpHPd/YTT8r2i082XzjtAoQNgklm/0Hw== + dependencies: + "@sentry/core" "7.112.2" + "@sentry/types" "7.112.2" + "@sentry/utils" "7.112.2" + +"@sentry/browser@7.112.2": + version "7.112.2" + resolved "https://registry.yarnpkg.com/@sentry/browser/-/browser-7.112.2.tgz#8c25b8f96257685279cf6837ba4ea6e6cba8c9e2" + integrity sha512-wULwavCch84+d0bueAdFm6CDm1u0TfOjN91VgY+sj/vxUV2vesvDgI8zRZfmbZEor3MYA90zerkZT3ehZQKbYw== + dependencies: + "@sentry-internal/feedback" "7.112.2" + "@sentry-internal/replay-canvas" "7.112.2" + "@sentry-internal/tracing" "7.112.2" + "@sentry/core" "7.112.2" + "@sentry/integrations" "7.112.2" + "@sentry/replay" "7.112.2" + "@sentry/types" "7.112.2" + "@sentry/utils" "7.112.2" + +"@sentry/core@7.112.2": + version "7.112.2" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-7.112.2.tgz#d2e6d2acb6947fcb384298a3bd2b0c8183533dd8" + integrity sha512-gHPCcJobbMkk0VR18J65WYQTt3ED4qC6X9lHKp27Ddt63E+MDGkG6lvYBU1LS8cV7CdyBGC1XXDCfor61GvLsA== + dependencies: + "@sentry/types" "7.112.2" + "@sentry/utils" "7.112.2" + +"@sentry/integrations@7.112.2": + version "7.112.2" + resolved "https://registry.yarnpkg.com/@sentry/integrations/-/integrations-7.112.2.tgz#2aad01719b1e4a1326f42db78f77fcf1e58d4c63" + integrity sha512-ioC2yyU6DqtLkdmWnm87oNvdn2+9oKctJeA4t+jkS6JaJ10DcezjCwiLscX4rhB9aWJV3IWF7Op0O6K3w0t2Hg== + dependencies: + "@sentry/core" "7.112.2" + "@sentry/types" "7.112.2" + "@sentry/utils" "7.112.2" + localforage "^1.8.1" + +"@sentry/replay@7.112.2": + version "7.112.2" + resolved "https://registry.yarnpkg.com/@sentry/replay/-/replay-7.112.2.tgz#4910244b80dabd32a83cc02b9fdd566ff766df34" + integrity sha512-7Ns/8D54WPsht1nlVj93Inf6rXyve2AZoibYN0YfcM2w3lI4NO51gPPHJU0lFEfMwzwK4ZBJWzOeW9098a+uEg== + dependencies: + "@sentry-internal/tracing" "7.112.2" + "@sentry/core" "7.112.2" + "@sentry/types" "7.112.2" + "@sentry/utils" "7.112.2" + +"@sentry/types@7.112.2": + version "7.112.2" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-7.112.2.tgz#71ff27c668309ccd8d17b7793e044e46f81eca1b" + integrity sha512-kCMLt7yhY5OkWE9MeowlTNmox9pqDxcpvqguMo4BDNZM5+v9SEb1AauAdR78E1a1V8TyCzjBD7JDfXWhvpYBcQ== + +"@sentry/utils@7.112.2": + version "7.112.2" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-7.112.2.tgz#223f9feee5860459792a43904db4bf38fba73ed3" + integrity sha512-OjLh0hx0t1EcL4ZIjf+4svlmmP+tHUDGcr5qpFWH78tjmkPW4+cqPuZCZfHSuWcDdeiaXi8TnYoVRqDcJKK/eQ== + dependencies: + "@sentry/types" "7.112.2" + +"@sentry/vue@^7.112.2": + version "7.112.2" + resolved "https://registry.yarnpkg.com/@sentry/vue/-/vue-7.112.2.tgz#296eba4b02388f461620f04410652cd17df8d371" + integrity sha512-CHfirgFV0kBQ5jnObOccDOkv0BQx4UmIH+ClDDvBiJRii6+OmyYyzgpPE8wYBfrrBWFSyd8VaPJ9j7NNH6N57A== + dependencies: + "@sentry/browser" "7.112.2" + "@sentry/core" "7.112.2" + "@sentry/types" "7.112.2" + "@sentry/utils" "7.112.2" + "@sinclair/typebox@^0.27.8": version "0.27.8" resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.27.8.tgz#6667fac16c436b5434a387a34dedb013198f6e6e" @@ -2195,6 +2287,11 @@ ignore@^5.2.0, ignore@^5.3.1: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== +immediate@~3.0.5: + version "3.0.6" + resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b" + integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ== + immutable@^4.0.0: version "4.3.5" resolved "https://registry.yarnpkg.com/immutable/-/immutable-4.3.5.tgz#f8b436e66d59f99760dc577f5c99a4fd2a5cc5a0" @@ -2520,6 +2617,13 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" +lie@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/lie/-/lie-3.1.1.tgz#9a436b2cc7746ca59de7a41fa469b3efb76bd87e" + integrity sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw== + dependencies: + immediate "~3.0.5" + lilconfig@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.1.0.tgz#78e23ac89ebb7e1bfbf25b18043de756548e7f52" @@ -2550,6 +2654,13 @@ local-pkg@^0.5.0: mlly "^1.4.2" pkg-types "^1.0.3" +localforage@^1.8.1: + version "1.10.0" + resolved "https://registry.yarnpkg.com/localforage/-/localforage-1.10.0.tgz#5c465dc5f62b2807c3a84c0c6a1b1b3212781dd4" + integrity sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg== + dependencies: + lie "3.1.1" + locate-path@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286"