diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml
new file mode 100644
index 00000000..44d1343c
--- /dev/null
+++ b/.github/workflows/e2e.yml
@@ -0,0 +1,139 @@
+name: E2E Tracing Tests
+
+on:
+ push:
+ branches:
+ - master
+ - release/**
+ pull_request:
+
+jobs:
+ tracing-e2e:
+ name: Tracing E2E Tests
+ runs-on: ubuntu-latest
+ timeout-minutes: 15
+
+ steps:
+ - name: Check out repository
+ uses: actions/checkout@v4
+
+ - name: Setup Elixir and Erlang
+ uses: erlef/setup-beam@e6d7c94229049569db56a7ad5a540c051a010af9
+ with:
+ elixir-version: "1.18"
+ otp-version: "27.2"
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: "20"
+
+ - name: Cache Elixir dependencies
+ uses: actions/cache@v4
+ with:
+ path: |
+ deps
+ _build
+ test_integrations/phoenix_app/deps
+ test_integrations/phoenix_app/_build
+ key: ${{ runner.os }}-elixir-1.18-otp-27.2-mix-${{ hashFiles('**/mix.lock') }}
+ restore-keys: |
+ ${{ runner.os }}-elixir-1.18-otp-27.2-mix-
+
+ - name: Cache Node.js dependencies
+ uses: actions/cache@v4
+ with:
+ path: |
+ test_integrations/tracing/node_modules
+ test_integrations/tracing/svelte_mini/node_modules
+ key: ${{ runner.os }}-node-20-${{ hashFiles('test_integrations/tracing/package-lock.json', 'test_integrations/tracing/svelte_mini/package-lock.json') }}
+ restore-keys: |
+ ${{ runner.os }}-node-20-
+
+ - name: Install main project dependencies
+ run: mix deps.get
+
+ - name: Install Phoenix app dependencies
+ working-directory: test_integrations/phoenix_app
+ run: mix deps.get
+
+ - name: Compile Phoenix app
+ working-directory: test_integrations/phoenix_app
+ run: mix compile
+
+ - name: Install tracing test npm dependencies
+ working-directory: test_integrations/tracing
+ run: npm install
+
+ - name: Install Svelte app dependencies
+ working-directory: test_integrations/tracing/svelte_mini
+ run: npm install
+
+ - name: Install Playwright browsers
+ working-directory: test_integrations/tracing
+ run: npx playwright install --with-deps --only-shell chromium
+
+ - name: Start Phoenix server
+ working-directory: test_integrations/phoenix_app
+ run: |
+ rm -f tmp/sentry_debug_events.log
+ SENTRY_E2E_TEST_MODE=true mix phx.server &
+ echo $! > /tmp/phoenix.pid
+ echo "Phoenix server started with PID $(cat /tmp/phoenix.pid)"
+
+ - name: Start Svelte server
+ working-directory: test_integrations/tracing/svelte_mini
+ run: |
+ SENTRY_E2E_SVELTE_APP_PORT=4001 npm run dev &
+ echo $! > /tmp/svelte.pid
+ echo "Svelte server started with PID $(cat /tmp/svelte.pid)"
+
+ - name: Wait for Phoenix server
+ run: |
+ echo "Waiting for Phoenix server at http://localhost:4000/health..."
+ timeout 60 bash -c 'until curl -s http://localhost:4000/health > /dev/null 2>&1; do echo "Waiting..."; sleep 2; done'
+ echo "Phoenix server is ready!"
+ curl -s http://localhost:4000/health
+
+ - name: Wait for Svelte server
+ run: |
+ echo "Waiting for Svelte server at http://localhost:4001/health..."
+ timeout 60 bash -c 'until curl -s http://localhost:4001/health > /dev/null 2>&1; do echo "Waiting..."; sleep 2; done'
+ echo "Svelte server is ready!"
+ curl -s http://localhost:4001/health
+
+ - name: Run Playwright tests
+ working-directory: test_integrations/tracing
+ env:
+ SENTRY_E2E_PHOENIX_APP_URL: http://localhost:4000
+ SENTRY_E2E_SVELTE_APP_URL: http://localhost:4001
+ SENTRY_E2E_SERVERS_RUNNING: "true"
+ run: npx playwright test --reporter=list
+
+ - name: Upload Playwright report
+ uses: actions/upload-artifact@v4
+ if: failure()
+ with:
+ name: playwright-report
+ path: test_integrations/tracing/playwright-report/
+ retention-days: 7
+
+ - name: Upload test screenshots
+ uses: actions/upload-artifact@v4
+ if: failure()
+ with:
+ name: test-screenshots
+ path: test_integrations/tracing/test-results/
+ retention-days: 7
+
+ - name: Show Phoenix server logs
+ if: failure()
+ run: |
+ echo "=== Sentry debug events log ==="
+ cat test_integrations/phoenix_app/tmp/sentry_debug_events.log 2>/dev/null || echo "No events logged"
+
+ - name: Cleanup servers
+ if: always()
+ run: |
+ [ -f /tmp/phoenix.pid ] && kill $(cat /tmp/phoenix.pid) 2>/dev/null || true
+ [ -f /tmp/svelte.pid ] && kill $(cat /tmp/svelte.pid) 2>/dev/null || true
diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index 2d76e256..fca5736d 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -54,7 +54,7 @@ jobs:
uses: actions/checkout@v4
- name: Setup Elixir and Erlang
- uses: erlef/setup-beam@v1
+ uses: erlef/setup-beam@e6d7c94229049569db56a7ad5a540c051a010af9
with:
elixir-version: ${{ matrix.elixir }}
otp-version: ${{ matrix.otp }}
@@ -117,6 +117,8 @@ jobs:
run: mix test
- name: Run integration tests
+ env:
+ SKIP_TRACING_E2E: "true"
run: mix test.integrations
- name: Cache Dialyzer PLT
diff --git a/.gitignore b/.gitignore
index 39814143..4b41496f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -17,3 +17,4 @@ test_integrations/phoenix_app/db
test_integrations/*/_build
test_integrations/*/deps
+test_integrations/*/test-results/
diff --git a/test_integrations/phoenix_app/config/config.exs b/test_integrations/phoenix_app/config/config.exs
index 68901111..66dd0fc3 100644
--- a/test_integrations/phoenix_app/config/config.exs
+++ b/test_integrations/phoenix_app/config/config.exs
@@ -65,6 +65,14 @@ config :opentelemetry, span_processor: {Sentry.OpenTelemetry.SpanProcessor, []}
config :opentelemetry,
sampler: {Sentry.OpenTelemetry.Sampler, [drop: ["Elixir.Oban.Stager process"]]}
+# Configure OpenTelemetry to use Sentry propagator for distributed tracing
+config :opentelemetry,
+ text_map_propagators: [
+ :trace_context,
+ :baggage,
+ Sentry.OpenTelemetry.Propagator
+ ]
+
# Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above.
import_config "#{config_env()}.exs"
diff --git a/test_integrations/phoenix_app/config/runtime.exs b/test_integrations/phoenix_app/config/runtime.exs
index 6aa62dab..24cad9a7 100644
--- a/test_integrations/phoenix_app/config/runtime.exs
+++ b/test_integrations/phoenix_app/config/runtime.exs
@@ -20,6 +20,21 @@ if System.get_env("PHX_SERVER") do
config :phoenix_app, PhoenixAppWeb.Endpoint, server: true
end
+# For e2e tracing tests, use the TestClient to log events to a file
+# This must be in runtime.exs because the env var is set at runtime, not compile time
+if System.get_env("SENTRY_E2E_TEST_MODE") == "true" do
+ config :sentry,
+ dsn: "https://public@sentry.example.com/1",
+ client: PhoenixApp.TestClient
+else
+ # Allow runtime configuration of Sentry DSN and environment
+ if dsn = System.get_env("SENTRY_DSN") do
+ config :sentry,
+ dsn: dsn,
+ environment_name: System.get_env("SENTRY_ENVIRONMENT") || config_env()
+ end
+end
+
if config_env() == :prod do
# database_url =
# System.get_env("DATABASE_URL") ||
diff --git a/test_integrations/phoenix_app/lib/phoenix_app/test_client.ex b/test_integrations/phoenix_app/lib/phoenix_app/test_client.ex
new file mode 100644
index 00000000..43a33ac8
--- /dev/null
+++ b/test_integrations/phoenix_app/lib/phoenix_app/test_client.ex
@@ -0,0 +1,86 @@
+defmodule PhoenixApp.TestClient do
+ @moduledoc """
+ A test Sentry client that logs envelopes to a file for e2e test validation.
+
+ This client mimics the behavior of Sentry::DebugTransport in sentry-ruby,
+ logging all envelopes to a file that can be read by Playwright tests.
+ """
+
+ require Logger
+
+ @behaviour Sentry.HTTPClient
+
+ @impl true
+ def post(_url, _headers, body) do
+ log_envelope(body)
+
+ # Return success response
+ {:ok, 200, [], ~s({"id":"test-event-id"})}
+ end
+
+ defp log_envelope(body) when is_binary(body) do
+ log_file = Path.join([File.cwd!(), "tmp", "sentry_debug_events.log"])
+
+ # Ensure the tmp directory exists
+ log_dir = Path.dirname(log_file)
+ File.mkdir_p!(log_dir)
+
+ # Parse the envelope binary to extract events and headers
+ case parse_envelope(body) do
+ {:ok, envelope_data} ->
+ # Write the envelope data as JSON
+ json = Jason.encode!(envelope_data)
+ File.write!(log_file, json <> "\n", [:append])
+
+ {:error, reason} ->
+ Logger.warning("Failed to parse envelope for logging: #{inspect(reason)}")
+ end
+ rescue
+ error ->
+ Logger.warning("Failed to log envelope: #{inspect(error)}")
+ end
+
+ defp parse_envelope(body) when is_binary(body) do
+ # Envelope format: header\nitem_header\nitem_payload[\nitem_header\nitem_payload...]
+ # See: https://develop.sentry.dev/sdk/envelopes/
+
+ lines = String.split(body, "\n")
+
+ with {:ok, header_line, rest} <- get_first_line(lines),
+ {:ok, envelope_headers} <- Jason.decode(header_line),
+ {:ok, items} <- parse_items(rest) do
+
+ envelope = %{
+ headers: envelope_headers,
+ items: items
+ }
+
+ {:ok, envelope}
+ else
+ error -> {:error, error}
+ end
+ end
+
+ defp get_first_line([first | rest]), do: {:ok, first, rest}
+ defp get_first_line([]), do: {:error, :empty_envelope}
+
+ defp parse_items(lines), do: parse_items(lines, [])
+
+ defp parse_items([], acc), do: {:ok, Enum.reverse(acc)}
+
+ defp parse_items([item_header_line, payload_line | rest], acc) do
+ with {:ok, _item_header} <- Jason.decode(item_header_line),
+ {:ok, payload} <- Jason.decode(payload_line) do
+ parse_items(rest, [payload | acc])
+ else
+ _error ->
+ # Skip malformed items
+ parse_items(rest, acc)
+ end
+ end
+
+ defp parse_items([_single_line], acc) do
+ # Handle trailing empty line
+ {:ok, Enum.reverse(acc)}
+ end
+end
diff --git a/test_integrations/phoenix_app/lib/phoenix_app_web/controllers/page_controller.ex b/test_integrations/phoenix_app/lib/phoenix_app_web/controllers/page_controller.ex
index 8b31383c..c80e3800 100644
--- a/test_integrations/phoenix_app/lib/phoenix_app_web/controllers/page_controller.ex
+++ b/test_integrations/phoenix_app/lib/phoenix_app_web/controllers/page_controller.ex
@@ -48,4 +48,35 @@ defmodule PhoenixAppWeb.PageController do
render(conn, :home, layout: false)
end
+
+ # E2E tracing test endpoints
+
+ def api_error(_conn, _params) do
+ raise ArithmeticError, "bad argument in arithmetic expression"
+ end
+
+ def health(conn, _params) do
+ json(conn, %{status: "ok"})
+ end
+
+ def api_data(conn, _params) do
+ Tracer.with_span "fetch_data" do
+ users = Repo.all(User)
+
+ Tracer.with_span "process_data" do
+ user_count = length(users)
+
+ first_user = Repo.get(User, 1)
+
+ json(conn, %{
+ message: "Data fetched successfully",
+ data: %{
+ user_count: user_count,
+ first_user: if(first_user, do: first_user.name, else: nil),
+ timestamp: DateTime.utc_now() |> DateTime.to_iso8601()
+ }
+ })
+ end
+ end
+ end
end
diff --git a/test_integrations/phoenix_app/lib/phoenix_app_web/endpoint.ex b/test_integrations/phoenix_app/lib/phoenix_app_web/endpoint.ex
index cbc6c40a..894cc5c2 100644
--- a/test_integrations/phoenix_app/lib/phoenix_app_web/endpoint.ex
+++ b/test_integrations/phoenix_app/lib/phoenix_app_web/endpoint.ex
@@ -44,6 +44,8 @@ defmodule PhoenixAppWeb.Endpoint do
plug Plug.RequestId
plug Plug.Telemetry, event_prefix: [:phoenix, :endpoint]
+ plug :cors
+
plug Plug.Parsers,
parsers: [:urlencoded, :multipart, :json],
pass: ["*/*"],
@@ -53,4 +55,22 @@ defmodule PhoenixAppWeb.Endpoint do
plug Plug.Head
plug Plug.Session, @session_options
plug PhoenixAppWeb.Router
+
+ # CORS plug for e2e tests - allows the Svelte frontend to make
+ # cross-origin requests to the Phoenix backend
+ defp cors(conn, _opts) do
+ conn
+ |> put_resp_header("access-control-allow-origin", "*")
+ |> put_resp_header("access-control-allow-methods", "GET, POST, PUT, DELETE, OPTIONS")
+ |> put_resp_header("access-control-allow-headers", "content-type, sentry-trace, baggage")
+ |> handle_preflight()
+ end
+
+ defp handle_preflight(%{method: "OPTIONS"} = conn) do
+ conn
+ |> send_resp(200, "")
+ |> halt()
+ end
+
+ defp handle_preflight(conn), do: conn
end
diff --git a/test_integrations/phoenix_app/lib/phoenix_app_web/router.ex b/test_integrations/phoenix_app/lib/phoenix_app_web/router.ex
index 597506b1..66a07292 100644
--- a/test_integrations/phoenix_app/lib/phoenix_app_web/router.ex
+++ b/test_integrations/phoenix_app/lib/phoenix_app_web/router.ex
@@ -12,6 +12,14 @@ defmodule PhoenixAppWeb.Router do
pipeline :api do
plug :accepts, ["json"]
+ plug :put_cors_headers
+ end
+
+ defp put_cors_headers(conn, _opts) do
+ conn
+ |> put_resp_header("access-control-allow-origin", "*")
+ |> put_resp_header("access-control-allow-methods", "GET, POST, PUT, DELETE, OPTIONS")
+ |> put_resp_header("access-control-allow-headers", "content-type, authorization, sentry-trace, baggage")
end
scope "/", PhoenixAppWeb do
@@ -32,6 +40,15 @@ defmodule PhoenixAppWeb.Router do
live "/users/:id/show/edit", UserLive.Show, :edit
end
+ # For e2e DT tests with a front-end app
+ scope "/", PhoenixAppWeb do
+ pipe_through :api
+
+ get "/error", PageController, :api_error
+ get "/health", PageController, :health
+ get "/api/data", PageController, :api_data
+ end
+
# Other scopes may use custom stacks.
# scope "/api", PhoenixAppWeb do
# pipe_through :api
diff --git a/test_integrations/tracing/package-lock.json b/test_integrations/tracing/package-lock.json
new file mode 100644
index 00000000..3ba888b0
--- /dev/null
+++ b/test_integrations/tracing/package-lock.json
@@ -0,0 +1,105 @@
+{
+ "name": "tracing-e2e-tests",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "tracing-e2e-tests",
+ "version": "1.0.0",
+ "devDependencies": {
+ "@playwright/test": "^1.48.0",
+ "@types/node": "^22.19.2",
+ "typescript": "^5.6.0"
+ }
+ },
+ "node_modules/@playwright/test": {
+ "version": "1.56.1",
+ "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.56.1.tgz",
+ "integrity": "sha512-vSMYtL/zOcFpvJCW71Q/OEGQb7KYBPAdKh35WNSkaZA75JlAO8ED8UN6GUNTm3drWomcbcqRPFqQbLae8yBTdg==",
+ "dev": true,
+ "dependencies": {
+ "playwright": "1.56.1"
+ },
+ "bin": {
+ "playwright": "cli.js"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@types/node": {
+ "version": "22.19.2",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.2.tgz",
+ "integrity": "sha512-LPM2G3Syo1GLzXLGJAKdqoU35XvrWzGJ21/7sgZTUpbkBaOasTj8tjwn6w+hCkqaa1TfJ/w67rJSwYItlJ2mYw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~6.21.0"
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+ "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+ "dev": true,
+ "hasInstallScript": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/playwright": {
+ "version": "1.56.1",
+ "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.56.1.tgz",
+ "integrity": "sha512-aFi5B0WovBHTEvpM3DzXTUaeN6eN0qWnTkKx4NQaH4Wvcmc153PdaY2UBdSYKaGYw+UyWXSVyxDUg5DoPEttjw==",
+ "dev": true,
+ "dependencies": {
+ "playwright-core": "1.56.1"
+ },
+ "bin": {
+ "playwright": "cli.js"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "fsevents": "2.3.2"
+ }
+ },
+ "node_modules/playwright-core": {
+ "version": "1.56.1",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.56.1.tgz",
+ "integrity": "sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==",
+ "dev": true,
+ "bin": {
+ "playwright-core": "cli.js"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/typescript": {
+ "version": "5.9.3",
+ "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz",
+ "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==",
+ "dev": true,
+ "bin": {
+ "tsc": "bin/tsc",
+ "tsserver": "bin/tsserver"
+ },
+ "engines": {
+ "node": ">=14.17"
+ }
+ },
+ "node_modules/undici-types": {
+ "version": "6.21.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
+ "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
+ "dev": true
+ }
+ }
+}
diff --git a/test_integrations/tracing/package.json b/test_integrations/tracing/package.json
new file mode 100644
index 00000000..2233f34a
--- /dev/null
+++ b/test_integrations/tracing/package.json
@@ -0,0 +1,15 @@
+{
+ "name": "tracing-e2e-tests",
+ "version": "1.0.0",
+ "type": "module",
+ "scripts": {
+ "test": "playwright test",
+ "test:debug": "playwright test --debug",
+ "test:ui": "playwright test --ui"
+ },
+ "devDependencies": {
+ "@playwright/test": "^1.48.0",
+ "@types/node": "^22.19.2",
+ "typescript": "^5.6.0"
+ }
+}
diff --git a/test_integrations/tracing/playwright.config.ts b/test_integrations/tracing/playwright.config.ts
new file mode 100644
index 00000000..622ffb09
--- /dev/null
+++ b/test_integrations/tracing/playwright.config.ts
@@ -0,0 +1,54 @@
+import { defineConfig, devices } from "@playwright/test";
+
+const PHOENIX_URL =
+ process.env.SENTRY_E2E_PHOENIX_APP_URL || "http://localhost:4000";
+const SVELTE_URL =
+ process.env.SENTRY_E2E_SVELTE_APP_URL || "http://localhost:4001";
+
+// When servers are started externally (e.g., in CI workflow steps), skip webServer config
+const serversRunningExternally = process.env.SENTRY_E2E_SERVERS_RUNNING === "true";
+
+export default defineConfig({
+ testDir: "./tests",
+ fullyParallel: false,
+ forbidOnly: !!process.env.CI,
+ retries: process.env.CI ? 2 : 0,
+ workers: 1,
+ reporter: "list",
+
+ use: {
+ baseURL: SVELTE_URL,
+ trace: "on-first-retry",
+ screenshot: "only-on-failure",
+ },
+
+ projects: [
+ {
+ name: "chromium",
+ use: {
+ ...devices["Desktop Chrome"],
+ headless: true,
+ },
+ },
+ ],
+
+ // Skip webServer when servers are managed externally (better CI debugging)
+ ...(serversRunningExternally
+ ? {}
+ : {
+ webServer: [
+ {
+ command:
+ 'cd ../phoenix_app && rm -f tmp/sentry_debug_events.log && SENTRY_E2E_TEST_MODE=true mix phx.server',
+ url: `${PHOENIX_URL}/health`,
+ reuseExistingServer: true
+ },
+ {
+ command:
+ 'cd svelte_mini && SENTRY_E2E_SVELTE_APP_PORT=4001 npm run dev',
+ url: `${SVELTE_URL}/health`,
+ reuseExistingServer: true
+ },
+ ],
+ }),
+});
diff --git a/test_integrations/tracing/svelte_mini/index.html b/test_integrations/tracing/svelte_mini/index.html
new file mode 100644
index 00000000..88e70534
--- /dev/null
+++ b/test_integrations/tracing/svelte_mini/index.html
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+ Svelte Mini App
+
+
+
+
+
+
+
+
diff --git a/test_integrations/tracing/svelte_mini/package-lock.json b/test_integrations/tracing/svelte_mini/package-lock.json
new file mode 100644
index 00000000..59ce8d28
--- /dev/null
+++ b/test_integrations/tracing/svelte_mini/package-lock.json
@@ -0,0 +1,1421 @@
+{
+ "name": "svelte-mini",
+ "version": "1.0.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "svelte-mini",
+ "version": "1.0.0",
+ "dependencies": {
+ "@sentry/svelte": "~10.5"
+ },
+ "devDependencies": {
+ "@sveltejs/vite-plugin-svelte": "^5.0.0",
+ "svelte": "~5.3.0",
+ "vite": "^6.0.0"
+ }
+ },
+ "node_modules/@ampproject/remapping": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
+ "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==",
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ },
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@esbuild/aix-ppc64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz",
+ "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "aix"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz",
+ "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz",
+ "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/android-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz",
+ "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz",
+ "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/darwin-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz",
+ "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz",
+ "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/freebsd-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz",
+ "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz",
+ "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz",
+ "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ia32": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz",
+ "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-loong64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz",
+ "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-mips64el": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz",
+ "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==",
+ "cpu": [
+ "mips64el"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-ppc64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz",
+ "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-riscv64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz",
+ "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-s390x": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz",
+ "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/linux-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz",
+ "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz",
+ "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/netbsd-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz",
+ "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "netbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz",
+ "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openbsd-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz",
+ "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openbsd"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/openharmony-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz",
+ "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/sunos-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz",
+ "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "sunos"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-arm64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz",
+ "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-ia32": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz",
+ "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@esbuild/win32-x64": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz",
+ "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@jridgewell/gen-mapping": {
+ "version": "0.3.13",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz",
+ "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.0",
+ "@jridgewell/trace-mapping": "^0.3.24"
+ }
+ },
+ "node_modules/@jridgewell/resolve-uri": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
+ "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ },
+ "node_modules/@jridgewell/sourcemap-codec": {
+ "version": "1.5.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+ "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+ "license": "MIT"
+ },
+ "node_modules/@jridgewell/trace-mapping": {
+ "version": "0.3.31",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz",
+ "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
+ }
+ },
+ "node_modules/@rollup/rollup-android-arm-eabi": {
+ "version": "4.53.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.53.5.tgz",
+ "integrity": "sha512-iDGS/h7D8t7tvZ1t6+WPK04KD0MwzLZrG0se1hzBjSi5fyxlsiggoJHwh18PCFNn7tG43OWb6pdZ6Y+rMlmyNQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-android-arm64": {
+ "version": "4.53.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.53.5.tgz",
+ "integrity": "sha512-wrSAViWvZHBMMlWk6EJhvg8/rjxzyEhEdgfMMjREHEq11EtJ6IP6yfcCH57YAEca2Oe3FNCE9DSTgU70EIGmVw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-arm64": {
+ "version": "4.53.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.53.5.tgz",
+ "integrity": "sha512-S87zZPBmRO6u1YXQLwpveZm4JfPpAa6oHBX7/ghSiGH3rz/KDgAu1rKdGutV+WUI6tKDMbaBJomhnT30Y2t4VQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-darwin-x64": {
+ "version": "4.53.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.53.5.tgz",
+ "integrity": "sha512-YTbnsAaHo6VrAczISxgpTva8EkfQus0VPEVJCEaboHtZRIb6h6j0BNxRBOwnDciFTZLDPW5r+ZBmhL/+YpTZgA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-arm64": {
+ "version": "4.53.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.53.5.tgz",
+ "integrity": "sha512-1T8eY2J8rKJWzaznV7zedfdhD1BqVs1iqILhmHDq/bqCUZsrMt+j8VCTHhP0vdfbHK3e1IQ7VYx3jlKqwlf+vw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-freebsd-x64": {
+ "version": "4.53.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.53.5.tgz",
+ "integrity": "sha512-sHTiuXyBJApxRn+VFMaw1U+Qsz4kcNlxQ742snICYPrY+DDL8/ZbaC4DVIB7vgZmp3jiDaKA0WpBdP0aqPJoBQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+ "version": "4.53.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.53.5.tgz",
+ "integrity": "sha512-dV3T9MyAf0w8zPVLVBptVlzaXxka6xg1f16VAQmjg+4KMSTWDvhimI/Y6mp8oHwNrmnmVl9XxJ/w/mO4uIQONA==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-musleabihf": {
+ "version": "4.53.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.53.5.tgz",
+ "integrity": "sha512-wIGYC1x/hyjP+KAu9+ewDI+fi5XSNiUi9Bvg6KGAh2TsNMA3tSEs+Sh6jJ/r4BV/bx/CyWu2ue9kDnIdRyafcQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-gnu": {
+ "version": "4.53.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.53.5.tgz",
+ "integrity": "sha512-Y+qVA0D9d0y2FRNiG9oM3Hut/DgODZbU9I8pLLPwAsU0tUKZ49cyV1tzmB/qRbSzGvY8lpgGkJuMyuhH7Ma+Vg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm64-musl": {
+ "version": "4.53.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.53.5.tgz",
+ "integrity": "sha512-juaC4bEgJsyFVfqhtGLz8mbopaWD+WeSOYr5E16y+1of6KQjc0BpwZLuxkClqY1i8sco+MdyoXPNiCkQou09+g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-loong64-gnu": {
+ "version": "4.53.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.53.5.tgz",
+ "integrity": "sha512-rIEC0hZ17A42iXtHX+EPJVL/CakHo+tT7W0pbzdAGuWOt2jxDFh7A/lRhsNHBcqL4T36+UiAgwO8pbmn3dE8wA==",
+ "cpu": [
+ "loong64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-ppc64-gnu": {
+ "version": "4.53.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.53.5.tgz",
+ "integrity": "sha512-T7l409NhUE552RcAOcmJHj3xyZ2h7vMWzcwQI0hvn5tqHh3oSoclf9WgTl+0QqffWFG8MEVZZP1/OBglKZx52Q==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-gnu": {
+ "version": "4.53.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.53.5.tgz",
+ "integrity": "sha512-7OK5/GhxbnrMcxIFoYfhV/TkknarkYC1hqUw1wU2xUN3TVRLNT5FmBv4KkheSG2xZ6IEbRAhTooTV2+R5Tk0lQ==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-riscv64-musl": {
+ "version": "4.53.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.53.5.tgz",
+ "integrity": "sha512-GwuDBE/PsXaTa76lO5eLJTyr2k8QkPipAyOrs4V/KJufHCZBJ495VCGJol35grx9xryk4V+2zd3Ri+3v7NPh+w==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-s390x-gnu": {
+ "version": "4.53.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.53.5.tgz",
+ "integrity": "sha512-IAE1Ziyr1qNfnmiQLHBURAD+eh/zH1pIeJjeShleII7Vj8kyEm2PF77o+lf3WTHDpNJcu4IXJxNO0Zluro8bOw==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-gnu": {
+ "version": "4.53.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.53.5.tgz",
+ "integrity": "sha512-Pg6E+oP7GvZ4XwgRJBuSXZjcqpIW3yCBhK4BcsANvb47qMvAbCjR6E+1a/U2WXz1JJxp9/4Dno3/iSJLcm5auw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-x64-musl": {
+ "version": "4.53.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.53.5.tgz",
+ "integrity": "sha512-txGtluxDKTxaMDzUduGP0wdfng24y1rygUMnmlUJ88fzCCULCLn7oE5kb2+tRB+MWq1QDZT6ObT5RrR8HFRKqg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-openharmony-arm64": {
+ "version": "4.53.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.53.5.tgz",
+ "integrity": "sha512-3DFiLPnTxiOQV993fMc+KO8zXHTcIjgaInrqlG8zDp1TlhYl6WgrOHuJkJQ6M8zHEcntSJsUp1XFZSY8C1DYbg==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "openharmony"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-arm64-msvc": {
+ "version": "4.53.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.53.5.tgz",
+ "integrity": "sha512-nggc/wPpNTgjGg75hu+Q/3i32R00Lq1B6N1DO7MCU340MRKL3WZJMjA9U4K4gzy3dkZPXm9E1Nc81FItBVGRlA==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-ia32-msvc": {
+ "version": "4.53.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.53.5.tgz",
+ "integrity": "sha512-U/54pTbdQpPLBdEzCT6NBCFAfSZMvmjr0twhnD9f4EIvlm9wy3jjQ38yQj1AGznrNO65EWQMgm/QUjuIVrYF9w==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-gnu": {
+ "version": "4.53.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.53.5.tgz",
+ "integrity": "sha512-2NqKgZSuLH9SXBBV2dWNRCZmocgSOx8OJSdpRaEcRlIfX8YrKxUT6z0F1NpvDVhOsl190UFTRh2F2WDWWCYp3A==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@rollup/rollup-win32-x64-msvc": {
+ "version": "4.53.5",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.53.5.tgz",
+ "integrity": "sha512-JRpZUhCfhZ4keB5v0fe02gQJy05GqboPOaxvjugW04RLSYYoB/9t2lx2u/tMs/Na/1NXfY8QYjgRljRpN+MjTQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@sentry-internal/browser-utils": {
+ "version": "10.5.0",
+ "resolved": "https://registry.npmjs.org/@sentry-internal/browser-utils/-/browser-utils-10.5.0.tgz",
+ "integrity": "sha512-4KIJdEj/8Ip9yqJleVSFe68r/U5bn5o/lYUwnFNEnDNxmpUbOlr7x3DXYuRFi1sfoMUxK9K1DrjnBkR7YYF00g==",
+ "license": "MIT",
+ "dependencies": {
+ "@sentry/core": "10.5.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@sentry-internal/feedback": {
+ "version": "10.5.0",
+ "resolved": "https://registry.npmjs.org/@sentry-internal/feedback/-/feedback-10.5.0.tgz",
+ "integrity": "sha512-x79P4VZwUxb1EGZb9OQ5EEgrDWFCUlrbzHBwV/oocQA5Ss1SFz5u6cP5Ak7yJtILiJtdGzAyAoQOy4GKD13D4Q==",
+ "license": "MIT",
+ "dependencies": {
+ "@sentry/core": "10.5.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@sentry-internal/replay": {
+ "version": "10.5.0",
+ "resolved": "https://registry.npmjs.org/@sentry-internal/replay/-/replay-10.5.0.tgz",
+ "integrity": "sha512-Dp4coE/nPzhFrYH3iVrpVKmhNJ1m/jGXMEDBCNg3wJZRszI41Hrj0jCAM0Y2S3Q4IxYOmFYaFbGtVpAznRyOHg==",
+ "license": "MIT",
+ "dependencies": {
+ "@sentry-internal/browser-utils": "10.5.0",
+ "@sentry/core": "10.5.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@sentry-internal/replay-canvas": {
+ "version": "10.5.0",
+ "resolved": "https://registry.npmjs.org/@sentry-internal/replay-canvas/-/replay-canvas-10.5.0.tgz",
+ "integrity": "sha512-5nrRKd5swefd9+sFXFZ/NeL3bz/VxBls3ubAQ3afak15FikkSyHq3oKRKpMOtDsiYKXE3Bc0y3rF5A+y3OXjIA==",
+ "license": "MIT",
+ "dependencies": {
+ "@sentry-internal/replay": "10.5.0",
+ "@sentry/core": "10.5.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@sentry/browser": {
+ "version": "10.5.0",
+ "resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-10.5.0.tgz",
+ "integrity": "sha512-o5pEJeZ/iZ7Fmaz2sIirThfnmSVNiP5ZYhacvcDi0qc288TmBbikCX3fXxq3xiSkhXfe1o5QIbNyovzfutyuVw==",
+ "license": "MIT",
+ "dependencies": {
+ "@sentry-internal/browser-utils": "10.5.0",
+ "@sentry-internal/feedback": "10.5.0",
+ "@sentry-internal/replay": "10.5.0",
+ "@sentry-internal/replay-canvas": "10.5.0",
+ "@sentry/core": "10.5.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@sentry/core": {
+ "version": "10.5.0",
+ "resolved": "https://registry.npmjs.org/@sentry/core/-/core-10.5.0.tgz",
+ "integrity": "sha512-jTJ8NhZSKB2yj3QTVRXfCCngQzAOLThQUxCl9A7Mv+XF10tP7xbH/88MVQ5WiOr2IzcmrB9r2nmUe36BnMlLjA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@sentry/svelte": {
+ "version": "10.5.0",
+ "resolved": "https://registry.npmjs.org/@sentry/svelte/-/svelte-10.5.0.tgz",
+ "integrity": "sha512-lw50mOZne0t1qiU2rhoJ5d0YVDlpLiLxE40GH/gn2e2chM7DVZWkC85EerVrhfqMuwBDA2n8tXTm+WNfY7IThw==",
+ "license": "MIT",
+ "dependencies": {
+ "@sentry/browser": "10.5.0",
+ "@sentry/core": "10.5.0",
+ "magic-string": "^0.30.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "svelte": "3.x || 4.x || 5.x"
+ }
+ },
+ "node_modules/@sveltejs/vite-plugin-svelte": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-5.1.1.tgz",
+ "integrity": "sha512-Y1Cs7hhTc+a5E9Va/xwKlAJoariQyHY+5zBgCZg4PFWNYQ1nMN9sjK1zhw1gK69DuqVP++sht/1GZg1aRwmAXQ==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@sveltejs/vite-plugin-svelte-inspector": "^4.0.1",
+ "debug": "^4.4.1",
+ "deepmerge": "^4.3.1",
+ "kleur": "^4.1.5",
+ "magic-string": "^0.30.17",
+ "vitefu": "^1.0.6"
+ },
+ "engines": {
+ "node": "^18.0.0 || ^20.0.0 || >=22"
+ },
+ "peerDependencies": {
+ "svelte": "^5.0.0",
+ "vite": "^6.0.0"
+ }
+ },
+ "node_modules/@sveltejs/vite-plugin-svelte-inspector": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-4.0.1.tgz",
+ "integrity": "sha512-J/Nmb2Q2y7mck2hyCX4ckVHcR5tu2J+MtBEQqpDrrgELZ2uvraQcK/ioCV61AqkdXFgriksOKIceDcQmqnGhVw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "debug": "^4.3.7"
+ },
+ "engines": {
+ "node": "^18.0.0 || ^20.0.0 || >=22"
+ },
+ "peerDependencies": {
+ "@sveltejs/vite-plugin-svelte": "^5.0.0",
+ "svelte": "^5.0.0",
+ "vite": "^6.0.0"
+ }
+ },
+ "node_modules/@types/estree": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
+ "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
+ "license": "MIT"
+ },
+ "node_modules/acorn": {
+ "version": "8.15.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
+ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
+ "license": "MIT",
+ "peer": true,
+ "bin": {
+ "acorn": "bin/acorn"
+ },
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
+ "node_modules/acorn-typescript": {
+ "version": "1.4.13",
+ "resolved": "https://registry.npmjs.org/acorn-typescript/-/acorn-typescript-1.4.13.tgz",
+ "integrity": "sha512-xsc9Xv0xlVfwp2o7sQ+GCQ1PgbkdcpWdTzrwXxO3xDMTAywVS3oXVOcOHuRjAPkS4P9b+yc/qNF15460v+jp4Q==",
+ "license": "MIT",
+ "peerDependencies": {
+ "acorn": ">=8.9.0"
+ }
+ },
+ "node_modules/aria-query": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz",
+ "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/axobject-query": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",
+ "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==",
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/debug": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/deepmerge": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz",
+ "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/esbuild": {
+ "version": "0.25.12",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz",
+ "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "bin": {
+ "esbuild": "bin/esbuild"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "optionalDependencies": {
+ "@esbuild/aix-ppc64": "0.25.12",
+ "@esbuild/android-arm": "0.25.12",
+ "@esbuild/android-arm64": "0.25.12",
+ "@esbuild/android-x64": "0.25.12",
+ "@esbuild/darwin-arm64": "0.25.12",
+ "@esbuild/darwin-x64": "0.25.12",
+ "@esbuild/freebsd-arm64": "0.25.12",
+ "@esbuild/freebsd-x64": "0.25.12",
+ "@esbuild/linux-arm": "0.25.12",
+ "@esbuild/linux-arm64": "0.25.12",
+ "@esbuild/linux-ia32": "0.25.12",
+ "@esbuild/linux-loong64": "0.25.12",
+ "@esbuild/linux-mips64el": "0.25.12",
+ "@esbuild/linux-ppc64": "0.25.12",
+ "@esbuild/linux-riscv64": "0.25.12",
+ "@esbuild/linux-s390x": "0.25.12",
+ "@esbuild/linux-x64": "0.25.12",
+ "@esbuild/netbsd-arm64": "0.25.12",
+ "@esbuild/netbsd-x64": "0.25.12",
+ "@esbuild/openbsd-arm64": "0.25.12",
+ "@esbuild/openbsd-x64": "0.25.12",
+ "@esbuild/openharmony-arm64": "0.25.12",
+ "@esbuild/sunos-x64": "0.25.12",
+ "@esbuild/win32-arm64": "0.25.12",
+ "@esbuild/win32-ia32": "0.25.12",
+ "@esbuild/win32-x64": "0.25.12"
+ }
+ },
+ "node_modules/esm-env": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz",
+ "integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==",
+ "license": "MIT"
+ },
+ "node_modules/esrap": {
+ "version": "1.4.9",
+ "resolved": "https://registry.npmjs.org/esrap/-/esrap-1.4.9.tgz",
+ "integrity": "sha512-3OMlcd0a03UGuZpPeUC1HxR3nA23l+HEyCiZw3b3FumJIN9KphoGzDJKMXI1S72jVS1dsenDyQC0kJlO1U9E1g==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.4.15"
+ }
+ },
+ "node_modules/fdir": {
+ "version": "6.5.0",
+ "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
+ "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "peerDependencies": {
+ "picomatch": "^3 || ^4"
+ },
+ "peerDependenciesMeta": {
+ "picomatch": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/is-reference": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz",
+ "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==",
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "^1.0.6"
+ }
+ },
+ "node_modules/kleur": {
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz",
+ "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/locate-character": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz",
+ "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==",
+ "license": "MIT"
+ },
+ "node_modules/magic-string": {
+ "version": "0.30.21",
+ "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz",
+ "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
+ "license": "MIT",
+ "dependencies": {
+ "@jridgewell/sourcemap-codec": "^1.5.5"
+ }
+ },
+ "node_modules/ms": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
+ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/nanoid": {
+ "version": "3.3.11",
+ "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
+ "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "bin": {
+ "nanoid": "bin/nanoid.cjs"
+ },
+ "engines": {
+ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
+ }
+ },
+ "node_modules/picocolors": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+ "dev": true,
+ "license": "ISC"
+ },
+ "node_modules/picomatch": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
+ "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/postcss": {
+ "version": "8.5.6",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
+ "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "tidelift",
+ "url": "https://tidelift.com/funding/github/npm/postcss"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "nanoid": "^3.3.11",
+ "picocolors": "^1.1.1",
+ "source-map-js": "^1.2.1"
+ },
+ "engines": {
+ "node": "^10 || ^12 || >=14"
+ }
+ },
+ "node_modules/rollup": {
+ "version": "4.53.5",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.53.5.tgz",
+ "integrity": "sha512-iTNAbFSlRpcHeeWu73ywU/8KuU/LZmNCSxp6fjQkJBD3ivUb8tpDrXhIxEzA05HlYMEwmtaUnb3RP+YNv162OQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/estree": "1.0.8"
+ },
+ "bin": {
+ "rollup": "dist/bin/rollup"
+ },
+ "engines": {
+ "node": ">=18.0.0",
+ "npm": ">=8.0.0"
+ },
+ "optionalDependencies": {
+ "@rollup/rollup-android-arm-eabi": "4.53.5",
+ "@rollup/rollup-android-arm64": "4.53.5",
+ "@rollup/rollup-darwin-arm64": "4.53.5",
+ "@rollup/rollup-darwin-x64": "4.53.5",
+ "@rollup/rollup-freebsd-arm64": "4.53.5",
+ "@rollup/rollup-freebsd-x64": "4.53.5",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.53.5",
+ "@rollup/rollup-linux-arm-musleabihf": "4.53.5",
+ "@rollup/rollup-linux-arm64-gnu": "4.53.5",
+ "@rollup/rollup-linux-arm64-musl": "4.53.5",
+ "@rollup/rollup-linux-loong64-gnu": "4.53.5",
+ "@rollup/rollup-linux-ppc64-gnu": "4.53.5",
+ "@rollup/rollup-linux-riscv64-gnu": "4.53.5",
+ "@rollup/rollup-linux-riscv64-musl": "4.53.5",
+ "@rollup/rollup-linux-s390x-gnu": "4.53.5",
+ "@rollup/rollup-linux-x64-gnu": "4.53.5",
+ "@rollup/rollup-linux-x64-musl": "4.53.5",
+ "@rollup/rollup-openharmony-arm64": "4.53.5",
+ "@rollup/rollup-win32-arm64-msvc": "4.53.5",
+ "@rollup/rollup-win32-ia32-msvc": "4.53.5",
+ "@rollup/rollup-win32-x64-gnu": "4.53.5",
+ "@rollup/rollup-win32-x64-msvc": "4.53.5",
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/source-map-js": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+ "dev": true,
+ "license": "BSD-3-Clause",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/svelte": {
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.3.2.tgz",
+ "integrity": "sha512-a0vmqDZt91jRocPB4U+/o03w5p7ujknsSNvImeNRpfI06Rc/V8ObHmud9VomVlk2k2XnPTZcomtxb2H0kp5E6Q==",
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "@ampproject/remapping": "^2.3.0",
+ "@jridgewell/sourcemap-codec": "^1.5.0",
+ "@types/estree": "^1.0.5",
+ "acorn": "^8.12.1",
+ "acorn-typescript": "^1.4.13",
+ "aria-query": "^5.3.1",
+ "axobject-query": "^4.1.0",
+ "esm-env": "^1.2.1",
+ "esrap": "^1.2.3",
+ "is-reference": "^3.0.3",
+ "locate-character": "^3.0.0",
+ "magic-string": "^0.30.11",
+ "zimmerframe": "^1.1.2"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/tinyglobby": {
+ "version": "0.2.15",
+ "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
+ "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "fdir": "^6.5.0",
+ "picomatch": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/SuperchupuDev"
+ }
+ },
+ "node_modules/vite": {
+ "version": "6.4.1",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz",
+ "integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
+ "dev": true,
+ "license": "MIT",
+ "peer": true,
+ "dependencies": {
+ "esbuild": "^0.25.0",
+ "fdir": "^6.4.4",
+ "picomatch": "^4.0.2",
+ "postcss": "^8.5.3",
+ "rollup": "^4.34.9",
+ "tinyglobby": "^0.2.13"
+ },
+ "bin": {
+ "vite": "bin/vite.js"
+ },
+ "engines": {
+ "node": "^18.0.0 || ^20.0.0 || >=22.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/vitejs/vite?sponsor=1"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.3"
+ },
+ "peerDependencies": {
+ "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
+ "jiti": ">=1.21.0",
+ "less": "*",
+ "lightningcss": "^1.21.0",
+ "sass": "*",
+ "sass-embedded": "*",
+ "stylus": "*",
+ "sugarss": "*",
+ "terser": "^5.16.0",
+ "tsx": "^4.8.1",
+ "yaml": "^2.4.2"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ },
+ "jiti": {
+ "optional": true
+ },
+ "less": {
+ "optional": true
+ },
+ "lightningcss": {
+ "optional": true
+ },
+ "sass": {
+ "optional": true
+ },
+ "sass-embedded": {
+ "optional": true
+ },
+ "stylus": {
+ "optional": true
+ },
+ "sugarss": {
+ "optional": true
+ },
+ "terser": {
+ "optional": true
+ },
+ "tsx": {
+ "optional": true
+ },
+ "yaml": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/vitefu": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.1.1.tgz",
+ "integrity": "sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==",
+ "dev": true,
+ "license": "MIT",
+ "workspaces": [
+ "tests/deps/*",
+ "tests/projects/*",
+ "tests/projects/workspace/packages/*"
+ ],
+ "peerDependencies": {
+ "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0"
+ },
+ "peerDependenciesMeta": {
+ "vite": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/zimmerframe": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.4.tgz",
+ "integrity": "sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==",
+ "license": "MIT"
+ }
+ }
+}
diff --git a/test_integrations/tracing/svelte_mini/package.json b/test_integrations/tracing/svelte_mini/package.json
new file mode 100644
index 00000000..ef305e42
--- /dev/null
+++ b/test_integrations/tracing/svelte_mini/package.json
@@ -0,0 +1,18 @@
+{
+ "name": "svelte-mini",
+ "version": "1.0.0",
+ "type": "module",
+ "scripts": {
+ "dev": "vite",
+ "build": "vite build",
+ "preview": "vite preview"
+ },
+ "devDependencies": {
+ "@sveltejs/vite-plugin-svelte": "^5.0.0",
+ "svelte": "~5.3.0",
+ "vite": "^6.0.0"
+ },
+ "dependencies": {
+ "@sentry/svelte": "~10.5"
+ }
+}
diff --git a/test_integrations/tracing/svelte_mini/src/App.svelte b/test_integrations/tracing/svelte_mini/src/App.svelte
new file mode 100644
index 00000000..ca95a96c
--- /dev/null
+++ b/test_integrations/tracing/svelte_mini/src/App.svelte
@@ -0,0 +1,148 @@
+
+
+
+ Svelte Mini App
+
+ Test distributed tracing between frontend and backend:
+
+
+
+
+
+
+
+
+ {#if result}
+
+ {/if}
+
+
+
diff --git a/test_integrations/tracing/svelte_mini/src/main.js b/test_integrations/tracing/svelte_mini/src/main.js
new file mode 100644
index 00000000..cb854f31
--- /dev/null
+++ b/test_integrations/tracing/svelte_mini/src/main.js
@@ -0,0 +1,19 @@
+import * as Sentry from "@sentry/svelte";
+import { mount } from "svelte";
+import App from "./App.svelte"
+
+Sentry.init({
+ dsn: import.meta.env.SENTRY_DSN || "https://user:secret@sentry.localdomain/42",
+ debug: true,
+ integrations: [Sentry.browserTracingIntegration(), Sentry.replayIntegration()],
+ tracesSampleRate: 1.0,
+ replaysSessionSampleRate: 1.0,
+ replaysOnErrorSampleRate: 1.0,
+ tracePropagationTargets: ["localhost:4000"],
+});
+
+const app = mount(App, {
+ target: document.getElementById("app"),
+})
+
+export default app
diff --git a/test_integrations/tracing/svelte_mini/vite.config.js b/test_integrations/tracing/svelte_mini/vite.config.js
new file mode 100644
index 00000000..36590bbf
--- /dev/null
+++ b/test_integrations/tracing/svelte_mini/vite.config.js
@@ -0,0 +1,34 @@
+import { defineConfig } from "vite"
+import { svelte } from "@sveltejs/vite-plugin-svelte"
+
+export default defineConfig({
+ plugins: [
+ svelte(),
+ {
+ name: "health-check",
+ configureServer(server) {
+ server.middlewares.use("/health", (req, res, next) => {
+ if (req.method === "GET") {
+ res.setHeader("Content-Type", "application/json")
+ res.setHeader("Access-Control-Allow-Origin", "*")
+ res.end(JSON.stringify({
+ status: "ok",
+ timestamp: new Date().toISOString(),
+ service: "svelte-mini"
+ }))
+ } else {
+ next()
+ }
+ })
+ }
+ }
+ ],
+ server: {
+ port: parseInt(process.env.SENTRY_E2E_SVELTE_APP_PORT || "4001"),
+ host: "0.0.0.0",
+ },
+ define: {
+ SENTRY_E2E_PHOENIX_APP_URL: JSON.stringify(process.env.SENTRY_E2E_PHOENIX_APP_URL || "http://localhost:4000")
+ },
+ envPrefix: ["SENTRY_"]
+})
diff --git a/test_integrations/tracing/tests/helpers.ts b/test_integrations/tracing/tests/helpers.ts
new file mode 100644
index 00000000..235dc58d
--- /dev/null
+++ b/test_integrations/tracing/tests/helpers.ts
@@ -0,0 +1,99 @@
+import fs from "fs";
+import path from "path";
+
+const DEBUG_LOG_PATH = path.join(
+ process.cwd(),
+ "..",
+ "phoenix_app",
+ "tmp",
+ "sentry_debug_events.log"
+);
+
+export interface SentryEvent {
+ type?: string;
+ transaction?: string;
+ exception?: Array<{
+ type: string;
+ value: string;
+ }>;
+ contexts?: {
+ trace?: {
+ trace_id?: string;
+ span_id?: string;
+ parent_span_id?: string;
+ op?: string;
+ data?: Record;
+ };
+ };
+ _meta?: {
+ dsc?: {
+ sample_rand?: string;
+ };
+ };
+ request?: {
+ headers?: Record;
+ };
+}
+
+export interface SentryEnvelope {
+ headers: {
+ trace?: {
+ trace_id?: string;
+ sample_rate?: string;
+ sample_rand?: string;
+ sampled?: string;
+ environment?: string;
+ public_key?: string;
+ [key: string]: any;
+ };
+ };
+ items: SentryEvent[];
+}
+
+export interface LoggedEvents {
+ events: SentryEvent[];
+ envelopes: SentryEnvelope[];
+ event_count: number;
+}
+
+export function getLoggedEvents(): LoggedEvents {
+ const events: SentryEvent[] = [];
+ const envelopes: SentryEnvelope[] = [];
+
+ if (!fs.existsSync(DEBUG_LOG_PATH)) {
+ return { events: [], envelopes: [], event_count: 0 };
+ }
+
+ const content = fs.readFileSync(DEBUG_LOG_PATH, "utf-8");
+ const lines = content
+ .trim()
+ .split("\n")
+ .filter((line) => line.trim());
+
+ for (const line of lines) {
+ try {
+ const data = JSON.parse(line);
+
+ // Check if it's an envelope format
+ if (data.headers) {
+ envelopes.push(data as SentryEnvelope);
+ if (data.items) {
+ events.push(...data.items);
+ }
+ } else {
+ // Individual event
+ events.push(data as SentryEvent);
+ }
+ } catch (e) {
+ // Skip malformed lines
+ }
+ }
+
+ return { events, envelopes, event_count: events.length };
+}
+
+export function clearLoggedEvents(): void {
+ if (fs.existsSync(DEBUG_LOG_PATH)) {
+ fs.writeFileSync(DEBUG_LOG_PATH, "");
+ }
+}
diff --git a/test_integrations/tracing/tests/tracing.spec.ts b/test_integrations/tracing/tests/tracing.spec.ts
new file mode 100644
index 00000000..dc47c643
--- /dev/null
+++ b/test_integrations/tracing/tests/tracing.spec.ts
@@ -0,0 +1,218 @@
+import { test, expect } from "@playwright/test";
+import { clearLoggedEvents, getLoggedEvents } from "./helpers";
+
+test.describe("Tracing", () => {
+ test.beforeEach(() => {
+ clearLoggedEvents();
+ });
+
+ test("validates basic tracing functionality", async ({ page }) => {
+ await page.goto("/");
+
+ await expect(page.locator("h1")).toContainText("Svelte Mini App");
+ await expect(page.locator("button#trigger-error-btn")).toBeVisible();
+
+ await page.click("button#trigger-error-btn");
+
+ await expect(page.locator(".result")).toContainText("Error:");
+ await page.waitForTimeout(2000);
+
+ const logged = getLoggedEvents();
+ expect(logged.event_count).toBeGreaterThan(0);
+
+ const errorEvents = logged.events.filter((event) => event.exception);
+ expect(errorEvents.length).toBeGreaterThan(0);
+
+ const errorEvent = errorEvents[errorEvents.length - 1];
+ const exceptionValues = errorEvent.exception;
+ expect(exceptionValues).toBeDefined();
+ expect(exceptionValues!.length).toBeGreaterThan(0);
+ expect(exceptionValues![0].type).toBe("ArithmeticError");
+
+ const transactionEvents = logged.events.filter(
+ (event) => event.type === "transaction"
+ );
+ expect(transactionEvents.length).toBeGreaterThan(0);
+
+ const errorTransactions = transactionEvents.filter(
+ (event) =>
+ event.transaction?.includes("error") ||
+ event.transaction?.includes("GET")
+ );
+
+ errorTransactions.forEach((transaction) => {
+ const traceContext = transaction.contexts?.trace;
+ expect(traceContext).toBeDefined();
+ expect(traceContext?.trace_id).toBeDefined();
+ expect(traceContext?.trace_id).toMatch(/^[a-f0-9]{32}$/);
+ expect(traceContext?.span_id).toBeDefined();
+ expect(traceContext?.span_id).toMatch(/^[a-f0-9]{16}$/);
+ expect(traceContext?.op).toBe("http.server");
+
+ const traceData = traceContext?.data as Record | undefined;
+ expect(traceData).toBeDefined();
+ expect(traceData?.["http.request.method"]).toBe("GET");
+ expect(traceData?.["http.route"]).toBe("/error");
+ expect(traceData?.["phoenix.action"]).toBe("api_error");
+ });
+ });
+
+ test.describe("OpenTelemetry trace propagation", () => {
+ test("validates trace IDs are properly generated for backend requests", async ({
+ page,
+ }) => {
+ await page.goto("/");
+
+ await expect(page.locator("h1")).toContainText("Svelte Mini App");
+ await expect(page.locator("button#trigger-error-btn")).toBeVisible();
+
+ await page.click("button#trigger-error-btn");
+
+ await expect(page.locator(".result")).toContainText("Error:");
+
+ await page.waitForTimeout(2000);
+
+ const logged = getLoggedEvents();
+
+ const transactionEvents = logged.events.filter(
+ (event) => event.type === "transaction"
+ );
+ expect(transactionEvents.length).toBeGreaterThan(0);
+
+ const errorTransaction = transactionEvents.find(
+ (event) =>
+ event.transaction?.includes("/error") ||
+ event.transaction?.includes("GET")
+ );
+ expect(errorTransaction).toBeDefined();
+
+ const traceContext = errorTransaction!.contexts?.trace;
+ expect(traceContext).toBeDefined();
+ expect(traceContext?.trace_id).toMatch(/^[a-f0-9]{32}$/);
+ expect(traceContext?.span_id).toMatch(/^[a-f0-9]{16}$/);
+ expect(traceContext?.op).toBe("http.server");
+ });
+
+ test("validates distributed tracing across multiple requests", async ({
+ page,
+ }) => {
+ await page.goto("/");
+
+ await expect(page.locator("h1")).toContainText("Svelte Mini App");
+
+ for (let i = 0; i < 3; i++) {
+ await page.click("button#trigger-error-btn");
+ await page.waitForTimeout(100);
+ }
+
+ await expect(page.locator(".result")).toContainText("Error:");
+
+ await page.waitForTimeout(2000);
+
+ const logged = getLoggedEvents();
+
+ const transactionEvents = logged.events.filter(
+ (event) => event.type === "transaction"
+ );
+
+ const errorTransactions = transactionEvents.filter((event) =>
+ event.transaction?.includes("/error")
+ );
+
+ expect(errorTransactions.length).toBeGreaterThanOrEqual(3);
+
+ const traceIds = errorTransactions
+ .map((t) => t.contexts?.trace?.trace_id)
+ .filter(Boolean);
+ expect(traceIds.length).toBeGreaterThanOrEqual(3);
+
+ traceIds.forEach((traceId) => {
+ expect(traceId).toMatch(/^[a-f0-9]{32}$/);
+ });
+
+ const uniqueTraceIds = [...new Set(traceIds)];
+ expect(uniqueTraceIds.length).toBe(1);
+
+ errorTransactions.forEach((transaction) => {
+ const parentSpanId = transaction.contexts?.trace?.parent_span_id;
+ expect(parentSpanId).toBeDefined();
+ expect(parentSpanId).toMatch(/^[a-f0-9]{16}$/);
+ });
+ });
+
+ test("validates child span data is preserved in distributed tracing", async ({
+ page,
+ }) => {
+ await page.goto("/");
+
+ await expect(page.locator("h1")).toContainText("Svelte Mini App");
+
+ await page.evaluate(async () => {
+ const response = await fetch("http://localhost:4000/api/data", {
+ method: "GET",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ });
+ return response.json();
+ });
+
+ await page.waitForTimeout(2000);
+
+ const logged = getLoggedEvents();
+
+ const transactionEvents = logged.events.filter(
+ (event) => event.type === "transaction"
+ );
+ expect(transactionEvents.length).toBeGreaterThan(0);
+
+ const dataTransactions = transactionEvents.filter(
+ (event) =>
+ event.transaction?.includes("/api/data") ||
+ event.transaction?.includes("fetch_data") ||
+ (event.contexts?.trace?.data as any)?.["http.route"] === "/api/data"
+ );
+
+ expect(dataTransactions.length).toBeGreaterThan(0);
+
+ const dataTransaction = dataTransactions[0];
+ expect(dataTransaction.contexts?.trace?.parent_span_id).toBeDefined();
+ expect(dataTransaction.contexts?.trace?.parent_span_id).toMatch(
+ /^[a-f0-9]{16}$/
+ );
+
+ const spans = (dataTransaction as any).spans;
+ expect(spans).toBeDefined();
+ expect(spans.length).toBeGreaterThan(0);
+
+ spans.forEach((span: any) => {
+ expect(span.span_id).toBeDefined();
+ expect(span.span_id).toMatch(/^[a-f0-9]{16}$/);
+ expect(span.trace_id).toBeDefined();
+ expect(span.trace_id).toMatch(/^[a-f0-9]{32}$/);
+ expect(span.op).toBeDefined();
+ expect(span.description).toBeDefined();
+
+ expect(span.data).toBeDefined();
+ expect(typeof span.data).toBe("object");
+
+ expect(span.data["otel.kind"]).toBeDefined();
+ });
+
+ const dbSpans = spans.filter((span: any) => span.op === "db");
+ expect(dbSpans.length).toBeGreaterThan(0);
+
+ dbSpans.forEach((dbSpan: any) => {
+ expect(dbSpan.data["db.system"]).toBeDefined();
+
+ expect(dbSpan.description).toBeDefined();
+ expect(dbSpan.description.length).toBeGreaterThan(0);
+
+ expect(dbSpan.description).toMatch(/SELECT/i);
+
+ expect(dbSpan.data["db.statement"]).toBeDefined();
+ expect(dbSpan.data["db.statement"]).toMatch(/SELECT/i);
+ });
+ });
+ });
+});
diff --git a/test_integrations/tracing/tsconfig.json b/test_integrations/tracing/tsconfig.json
new file mode 100644
index 00000000..58559850
--- /dev/null
+++ b/test_integrations/tracing/tsconfig.json
@@ -0,0 +1,12 @@
+{
+ "compilerOptions": {
+ "target": "ESNext",
+ "module": "ESNext",
+ "moduleResolution": "Bundler",
+ "strict": true,
+ "esModuleInterop": true,
+ "skipLibCheck": true,
+ "types": ["node"]
+ },
+ "include": ["tests/**/*.ts", "playwright.config.ts"]
+}