mirror of
https://github.com/BerriAI/litellm.git
synced 2026-11-13 08:52:02 +00:00
revert: separate dependency fixes from Chinese localization
Revert merge3a3bc917fbrelative to its first parent. Restore the exact premerge Chinese localization tree from9baf20e312. Preserve the reviewed security and dependency fixes on their separate branch for an independent PR.
This commit is contained in:
parent
3a3bc917fb
commit
490e1baad1
24 changed files with 511 additions and 1094 deletions
|
|
@ -317,9 +317,6 @@ class _RequestedIdGenerator(RandomIdGenerator):
|
|||
the tracer's id generator, so the request rides on a context variable instead.
|
||||
"""
|
||||
|
||||
def is_trace_id_random(self) -> bool:
|
||||
return _requested_trace_id.get() is None
|
||||
|
||||
def generate_trace_id(self) -> int:
|
||||
requested: Final = _requested_trace_id.get()
|
||||
return super().generate_trace_id() if requested is None else requested
|
||||
|
|
|
|||
|
|
@ -3161,14 +3161,13 @@ class OpenTelemetry(OTELGenAISemconvMixin, CustomLogger):
|
|||
otel_exporter,
|
||||
)
|
||||
normalized_endpoint = self._normalize_otel_endpoint(otel_endpoint, "traces")
|
||||
from litellm.integrations.otel.plumbing.otlp_transport import build_otlp_http_transport
|
||||
|
||||
tls: Final = resolve_otlp_http_tls("TRACES", _split_otel_headers)
|
||||
tls: Final = resolve_otlp_http_tls("TRACES")
|
||||
return BatchSpanProcessor(
|
||||
OTLPSpanExporterHTTP(
|
||||
endpoint=normalized_endpoint,
|
||||
headers=_split_otel_headers,
|
||||
_transport=build_otlp_http_transport("TRACES", tls),
|
||||
certificate_file=tls.certificate_file,
|
||||
session=tls.session,
|
||||
),
|
||||
)
|
||||
elif otel_exporter == "otlp_grpc" or otel_exporter == "grpc":
|
||||
|
|
@ -3250,13 +3249,12 @@ class OpenTelemetry(OTELGenAISemconvMixin, CustomLogger):
|
|||
self.OTEL_EXPORTER,
|
||||
normalized_endpoint,
|
||||
)
|
||||
from litellm.integrations.otel.plumbing.otlp_transport import build_otlp_http_transport
|
||||
|
||||
tls: Final = resolve_otlp_http_tls("LOGS", _split_otel_headers)
|
||||
tls: Final = resolve_otlp_http_tls("LOGS")
|
||||
return OTLPLogExporter(
|
||||
endpoint=normalized_endpoint,
|
||||
headers=_split_otel_headers,
|
||||
_transport=build_otlp_http_transport("LOGS", tls),
|
||||
certificate_file=tls.certificate_file,
|
||||
session=tls.session,
|
||||
)
|
||||
elif self.OTEL_EXPORTER == "otlp_grpc" or self.OTEL_EXPORTER == "grpc":
|
||||
try:
|
||||
|
|
@ -3320,13 +3318,12 @@ class OpenTelemetry(OTELGenAISemconvMixin, CustomLogger):
|
|||
OTLPMetricExporter,
|
||||
)
|
||||
|
||||
from litellm.integrations.otel.plumbing.otlp_transport import build_otlp_http_transport
|
||||
|
||||
tls: Final = resolve_otlp_http_tls("METRICS", _split_otel_headers)
|
||||
tls: Final = resolve_otlp_http_tls("METRICS")
|
||||
exporter = OTLPMetricExporter(
|
||||
endpoint=normalized_endpoint,
|
||||
headers=_split_otel_headers,
|
||||
_transport=build_otlp_http_transport("METRICS", tls),
|
||||
certificate_file=tls.certificate_file,
|
||||
session=tls.session,
|
||||
)
|
||||
return PeriodicExportingMetricReader(exporter, export_interval_millis=5000)
|
||||
|
||||
|
|
|
|||
|
|
@ -126,9 +126,6 @@ def instrument_fastapi_app(app: "FastAPI", tracer_provider: "TracerProvider | No
|
|||
try:
|
||||
if not is_otel_v2_enabled():
|
||||
return
|
||||
if app.middleware_stack is not None:
|
||||
verbose_logger.debug("Skipping OTel V2 FastAPI instrumentation after the middleware stack was built")
|
||||
return
|
||||
|
||||
# Lazy: only the V2-enabled path needs the optional
|
||||
# ``opentelemetry-instrumentation-fastapi`` package, which is not part of the
|
||||
|
|
|
|||
|
|
@ -1,26 +1,77 @@
|
|||
"""OTLP/JSON export with the same requests and TLS configuration as OTLP/protobuf."""
|
||||
"""OTLP/HTTP span exporter that sends the OTLP/JSON encoding instead of protobuf.
|
||||
|
||||
from collections.abc import Mapping
|
||||
from typing import Final
|
||||
The SDK only ships a protobuf OTLP/HTTP exporter; this reuses its transport and
|
||||
retry loop and swaps the payload for OTLP/JSON (enums as integers, ids as hex).
|
||||
"""
|
||||
|
||||
import base64
|
||||
import json
|
||||
from collections.abc import Mapping, Sequence
|
||||
from types import MappingProxyType
|
||||
from typing import Final, TypeAlias
|
||||
|
||||
import requests
|
||||
from opentelemetry.exporter.otlp.json.http.trace_exporter import OTLPSpanExporter
|
||||
from google.protobuf.json_format import MessageToDict
|
||||
from opentelemetry.exporter.otlp.proto.common.trace_encoder import encode_spans
|
||||
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
|
||||
from opentelemetry.sdk.trace import ReadableSpan
|
||||
|
||||
from litellm.integrations.otel.plumbing.otlp_tls import OtlpHttpTls
|
||||
from litellm.integrations.otel.plumbing.otlp_transport import build_otlp_http_transport
|
||||
JSON_CONTENT_TYPE: Final = "application/json"
|
||||
_HEX_ID_KEYS: Final = frozenset({"traceId", "spanId", "parentSpanId"})
|
||||
|
||||
_JsonValue: TypeAlias = "Mapping[str, _JsonValue] | Sequence[_JsonValue] | str | int | float | bool | None"
|
||||
_JsonObject: TypeAlias = Mapping[str, "_JsonValue"]
|
||||
|
||||
|
||||
def _objects(node: _JsonObject, key: str) -> tuple[_JsonObject, ...]:
|
||||
items: Final = node.get(key)
|
||||
if isinstance(items, str) or not isinstance(items, Sequence):
|
||||
return ()
|
||||
return tuple(item for item in items if isinstance(item, Mapping))
|
||||
|
||||
|
||||
def _hex_ids(node: _JsonObject) -> _JsonObject:
|
||||
return MappingProxyType(
|
||||
{
|
||||
key: base64.b64decode(item).hex() if key in _HEX_ID_KEYS and isinstance(item, str) else item
|
||||
for key, item in node.items()
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def _hex_span(span: _JsonObject) -> _JsonObject:
|
||||
links: Final = _objects(span, "links")
|
||||
if not links:
|
||||
return _hex_ids(span)
|
||||
return MappingProxyType({**_hex_ids(span), "links": tuple(_hex_ids(link) for link in links)})
|
||||
|
||||
|
||||
def _hex_scope_spans(scope: _JsonObject) -> _JsonObject:
|
||||
return MappingProxyType({**scope, "spans": tuple(_hex_span(span) for span in _objects(scope, "spans"))})
|
||||
|
||||
|
||||
def _hex_resource_spans(resource: _JsonObject) -> _JsonObject:
|
||||
scope_spans: Final = tuple(_hex_scope_spans(scope) for scope in _objects(resource, "scopeSpans"))
|
||||
return MappingProxyType({**resource, "scopeSpans": scope_spans})
|
||||
|
||||
|
||||
def encode_spans_json(spans: Sequence[ReadableSpan]) -> bytes:
|
||||
payload: Final[_JsonObject] = MessageToDict(encode_spans(spans), use_integers_for_enums=True)
|
||||
resource_spans: Final = tuple(_hex_resource_spans(resource) for resource in _objects(payload, "resourceSpans"))
|
||||
hexed: Final[_JsonObject] = MappingProxyType({**payload, "resourceSpans": resource_spans})
|
||||
return json.dumps(hexed, default=dict, separators=(",", ":")).encode()
|
||||
|
||||
|
||||
class OTLPJsonSpanExporter(OTLPSpanExporter):
|
||||
def __init__(
|
||||
self,
|
||||
endpoint: str | None,
|
||||
headers: Mapping[str, str],
|
||||
headers: dict[str, str], # mutable-ok: SDK __init__ takes Dict
|
||||
certificate_file: str | None = None,
|
||||
session: requests.Session | None = None,
|
||||
session: "requests.Session | None" = None,
|
||||
) -> None:
|
||||
transport: Final = build_otlp_http_transport(
|
||||
"TRACES", OtlpHttpTls(certificate_file=certificate_file, session=session), use_credential_provider=False
|
||||
)
|
||||
super().__init__(
|
||||
endpoint=endpoint, headers={**headers, "content-type": "application/json"}, _transport=transport
|
||||
)
|
||||
super().__init__(endpoint=endpoint, headers=headers, certificate_file=certificate_file, session=session)
|
||||
self._session.headers["Content-Type"] = JSON_CONTENT_TYPE
|
||||
|
||||
def _serialize_spans(self, spans: Sequence[ReadableSpan]) -> bytes:
|
||||
return encode_spans_json(spans)
|
||||
|
|
|
|||
|
|
@ -1,19 +1,11 @@
|
|||
import os
|
||||
from collections.abc import Mapping
|
||||
from copy import copy
|
||||
from dataclasses import dataclass
|
||||
from typing import Final, Literal
|
||||
|
||||
import requests
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
from requests.adapters import HTTPAdapter
|
||||
|
||||
|
||||
class _RequestHeaders(BaseModel):
|
||||
model_config = ConfigDict(frozen=True, from_attributes=True)
|
||||
headers: Mapping[str, str] | None = None
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class OtlpHttpTls:
|
||||
certificate_file: str | None
|
||||
|
|
@ -33,65 +25,17 @@ class _NoVerifyAdapter(HTTPAdapter):
|
|||
)
|
||||
|
||||
|
||||
class _IsolatedHeadersSession(requests.Session):
|
||||
def __init__(self, signal: str, headers: Mapping[str, str], content_type: str) -> None:
|
||||
from opentelemetry.util.re import parse_env_headers
|
||||
|
||||
super().__init__()
|
||||
environment: Final = parse_env_headers(
|
||||
os.getenv(f"OTEL_EXPORTER_OTLP_{signal}_HEADERS") or os.getenv("OTEL_EXPORTER_OTLP_HEADERS", ""),
|
||||
liberal=True,
|
||||
)
|
||||
explicit: Final = frozenset(key.lower() for key in headers)
|
||||
self._excluded_headers: Final = frozenset(key.lower() for key in environment) - explicit
|
||||
self._content_type: Final = content_type
|
||||
self._compression: Final = (
|
||||
(
|
||||
os.getenv(f"OTEL_EXPORTER_OTLP_{signal}_COMPRESSION")
|
||||
or os.getenv("OTEL_EXPORTER_OTLP_COMPRESSION", "none")
|
||||
)
|
||||
.strip()
|
||||
.lower()
|
||||
)
|
||||
|
||||
def prepare_request(self, request: requests.Request) -> requests.PreparedRequest:
|
||||
isolated: Final = copy(request)
|
||||
source: Final[Mapping[str, str]] = _RequestHeaders.model_validate(request).headers or {}
|
||||
kept: Final = {key: value for key, value in source.items() if key.lower() not in self._excluded_headers}
|
||||
content_type: Final = {"Content-Type": self._content_type} if "content-type" in self._excluded_headers else {}
|
||||
compression: Final = (
|
||||
{"Content-Encoding": self._compression}
|
||||
if "content-encoding" in self._excluded_headers and self._compression in ("gzip", "deflate")
|
||||
else {}
|
||||
)
|
||||
isolated.headers = {**kept, **content_type, **compression}
|
||||
session: Final = copy(self)
|
||||
session.headers = {
|
||||
key: value for key, value in self.headers.items() if key.lower() not in self._excluded_headers
|
||||
}
|
||||
return requests.Session.prepare_request(session, isolated)
|
||||
|
||||
|
||||
def resolve_otlp_http_tls(
|
||||
signal: Literal["TRACES", "METRICS", "LOGS"],
|
||||
headers: Mapping[str, str] | None = None,
|
||||
*,
|
||||
content_type: str = "application/x-protobuf",
|
||||
isolate_headers: bool = False,
|
||||
) -> OtlpHttpTls:
|
||||
session: Final = (
|
||||
_IsolatedHeadersSession(signal, headers or {}, content_type) if headers or isolate_headers else None
|
||||
)
|
||||
def resolve_otlp_http_tls(signal: Literal["TRACES", "METRICS", "LOGS"]) -> OtlpHttpTls:
|
||||
if os.getenv(f"OTEL_EXPORTER_OTLP_{signal}_CERTIFICATE") or os.getenv("OTEL_EXPORTER_OTLP_CERTIFICATE"):
|
||||
return OtlpHttpTls(certificate_file=None, session=session)
|
||||
return OtlpHttpTls(certificate_file=None, session=None)
|
||||
|
||||
from litellm.llms.custom_httpx.http_handler import get_ssl_verify
|
||||
|
||||
verify: Final = get_ssl_verify()
|
||||
if verify is False:
|
||||
unverified: Final = session or requests.Session()
|
||||
unverified.mount("https://", _NoVerifyAdapter())
|
||||
return OtlpHttpTls(certificate_file=None, session=unverified)
|
||||
session: Final = requests.Session()
|
||||
session.mount("https://", _NoVerifyAdapter())
|
||||
return OtlpHttpTls(certificate_file=None, session=session)
|
||||
if isinstance(verify, str):
|
||||
return OtlpHttpTls(certificate_file=verify, session=session)
|
||||
return OtlpHttpTls(certificate_file=None, session=session)
|
||||
return OtlpHttpTls(certificate_file=verify, session=None)
|
||||
return OtlpHttpTls(certificate_file=None, session=None)
|
||||
|
|
|
|||
|
|
@ -1,95 +0,0 @@
|
|||
"""Keep explicit collector TLS settings authoritative at request time."""
|
||||
|
||||
import os
|
||||
from collections.abc import Mapping
|
||||
from typing import Final, Literal
|
||||
|
||||
import requests
|
||||
from opentelemetry.exporter.http.transport._requests import RequestsHTTPResult, RequestsHTTPTransport
|
||||
from opentelemetry.exporter.otlp.proto.http._common import (
|
||||
_load_session_from_envvar, # pyright: ignore[reportPrivateUsage] # pinned SDK loader preserves operator auth
|
||||
)
|
||||
|
||||
from litellm.integrations.otel.plumbing.otlp_tls import OtlpHttpTls
|
||||
|
||||
|
||||
class _OtlpHTTPTransport(RequestsHTTPTransport):
|
||||
def __init__(
|
||||
self,
|
||||
verify: bool | str,
|
||||
cert: str | tuple[str, str] | None,
|
||||
session: requests.Session | None,
|
||||
) -> None:
|
||||
self._request_session: Final = session if session is not None else requests.Session()
|
||||
self._request_verify: Final = verify
|
||||
super().__init__(verify=verify, cert=cert, session=self._request_session)
|
||||
|
||||
def request(
|
||||
self,
|
||||
method: str,
|
||||
url: str,
|
||||
*,
|
||||
headers: Mapping[str, str] | None = None,
|
||||
timeout: float | None = None,
|
||||
data: bytes | None = None,
|
||||
) -> RequestsHTTPResult:
|
||||
try:
|
||||
response: Final = self._request_session.request(
|
||||
method=method,
|
||||
url=url,
|
||||
headers=headers,
|
||||
data=data,
|
||||
timeout=timeout,
|
||||
verify=self._request_verify,
|
||||
allow_redirects=False,
|
||||
)
|
||||
except Exception as error: # noqa: BLE001 # SDK transport returns all session and auth failures as values
|
||||
return RequestsHTTPResult(error=error)
|
||||
return RequestsHTTPResult(status_code=response.status_code, reason=response.reason, response=response)
|
||||
|
||||
|
||||
def build_otlp_http_transport(
|
||||
signal: Literal["TRACES", "LOGS", "METRICS"],
|
||||
tls: OtlpHttpTls,
|
||||
*,
|
||||
use_credential_provider: bool = True,
|
||||
client_key_file: str | None = None,
|
||||
client_certificate_file: str | None = None,
|
||||
) -> RequestsHTTPTransport:
|
||||
verify: Final = (
|
||||
tls.certificate_file
|
||||
or os.getenv(f"OTEL_EXPORTER_OTLP_{signal}_CERTIFICATE")
|
||||
or os.getenv("OTEL_EXPORTER_OTLP_CERTIFICATE")
|
||||
or True
|
||||
)
|
||||
client_key: Final = (
|
||||
client_key_file
|
||||
or os.getenv(f"OTEL_EXPORTER_OTLP_{signal}_CLIENT_KEY")
|
||||
or os.getenv("OTEL_EXPORTER_OTLP_CLIENT_KEY")
|
||||
)
|
||||
client_certificate: Final = (
|
||||
client_certificate_file
|
||||
or os.getenv(f"OTEL_EXPORTER_OTLP_{signal}_CLIENT_CERTIFICATE")
|
||||
or os.getenv("OTEL_EXPORTER_OTLP_CLIENT_CERTIFICATE")
|
||||
)
|
||||
credential_variable: Final[
|
||||
Literal[
|
||||
"OTEL_PYTHON_EXPORTER_OTLP_HTTP_TRACES_CREDENTIAL_PROVIDER",
|
||||
"OTEL_PYTHON_EXPORTER_OTLP_HTTP_LOGS_CREDENTIAL_PROVIDER",
|
||||
"OTEL_PYTHON_EXPORTER_OTLP_HTTP_METRICS_CREDENTIAL_PROVIDER",
|
||||
]
|
||||
] = (
|
||||
"OTEL_PYTHON_EXPORTER_OTLP_HTTP_TRACES_CREDENTIAL_PROVIDER"
|
||||
if signal == "TRACES"
|
||||
else "OTEL_PYTHON_EXPORTER_OTLP_HTTP_LOGS_CREDENTIAL_PROVIDER"
|
||||
if signal == "LOGS"
|
||||
else "OTEL_PYTHON_EXPORTER_OTLP_HTTP_METRICS_CREDENTIAL_PROVIDER"
|
||||
)
|
||||
session: Final = tls.session or (
|
||||
_load_session_from_envvar(credential_variable) if use_credential_provider else None
|
||||
)
|
||||
return _OtlpHTTPTransport(
|
||||
verify=verify,
|
||||
cert=(client_certificate, client_key) if client_certificate and client_key else client_certificate,
|
||||
session=session,
|
||||
)
|
||||
|
|
@ -16,9 +16,9 @@ from opentelemetry.metrics import MeterProvider, NoOpMeterProvider
|
|||
from opentelemetry.sdk._logs import LoggerProvider as SDKLoggerProvider
|
||||
from opentelemetry.sdk._logs.export import (
|
||||
BatchLogRecordProcessor,
|
||||
ConsoleLogRecordExporter,
|
||||
InMemoryLogRecordExporter,
|
||||
LogRecordExporter,
|
||||
ConsoleLogExporter,
|
||||
InMemoryLogExporter,
|
||||
LogExporter,
|
||||
SimpleLogRecordProcessor,
|
||||
)
|
||||
from opentelemetry.sdk.metrics import MeterProvider as SDKMeterProvider
|
||||
|
|
@ -194,7 +194,7 @@ def exporter_transport(kind: str) -> Literal["http", "grpc", "headerless"]:
|
|||
return "headerless"
|
||||
|
||||
|
||||
def _exporter_from_spec(spec: ExporterSpec, *, isolate_headers: bool = False) -> SpanExporter:
|
||||
def _exporter_from_spec(spec: ExporterSpec) -> SpanExporter:
|
||||
kind: Final = (spec.kind or "console").lower()
|
||||
factory: Final = _EXPORTER_FACTORIES.get(kind)
|
||||
if factory is not None:
|
||||
|
|
@ -204,9 +204,7 @@ def _exporter_from_spec(spec: ExporterSpec, *, isolate_headers: bool = False) ->
|
|||
if kind in _OTLP_HTTP_JSON_KINDS:
|
||||
from litellm.integrations.otel.plumbing.otlp_json import OTLPJsonSpanExporter
|
||||
|
||||
tls: Final = resolve_otlp_http_tls(
|
||||
"TRACES", parse_headers(spec.headers), content_type="application/json", isolate_headers=isolate_headers
|
||||
)
|
||||
tls: Final = resolve_otlp_http_tls("TRACES")
|
||||
return OTLPJsonSpanExporter(
|
||||
endpoint=spec.traces_endpoint or _otlp_traces_endpoint(spec.endpoint),
|
||||
headers=parse_headers(spec.headers),
|
||||
|
|
@ -218,13 +216,12 @@ def _exporter_from_spec(spec: ExporterSpec, *, isolate_headers: bool = False) ->
|
|||
OTLPSpanExporter as HTTPExporter,
|
||||
)
|
||||
|
||||
from litellm.integrations.otel.plumbing.otlp_transport import build_otlp_http_transport
|
||||
|
||||
http_tls: Final = resolve_otlp_http_tls("TRACES", parse_headers(spec.headers), isolate_headers=isolate_headers)
|
||||
http_tls: Final = resolve_otlp_http_tls("TRACES")
|
||||
return HTTPExporter(
|
||||
endpoint=spec.traces_endpoint or _otlp_traces_endpoint(spec.endpoint),
|
||||
headers=parse_headers(spec.headers),
|
||||
_transport=build_otlp_http_transport("TRACES", http_tls),
|
||||
certificate_file=http_tls.certificate_file,
|
||||
session=http_tls.session,
|
||||
)
|
||||
if kind in _OTLP_GRPC_KINDS:
|
||||
from opentelemetry.exporter.otlp.proto.grpc.trace_exporter import (
|
||||
|
|
@ -1016,7 +1013,7 @@ def _destination_processor(destination: "OtelDestination") -> SpanProcessor | No
|
|||
headers=destination.header_string(),
|
||||
owner=None,
|
||||
)
|
||||
return _processor_for(_exporter_from_spec(spec, isolate_headers=True), use_simple=False)
|
||||
return _processor_for(_exporter_from_spec(spec), use_simple=False)
|
||||
except Exception as exc: # noqa: BLE001 # a malformed destination must not break the request or the other destinations
|
||||
verbose_logger.debug("OTel V2 fan-out: no processor for %s: %s", destination.endpoint, exc)
|
||||
return None
|
||||
|
|
@ -1189,13 +1186,12 @@ def build_metric_reader(config: OpenTelemetryV2Config) -> "MetricReader":
|
|||
OTLPMetricExporter as HTTPMetricExporter,
|
||||
)
|
||||
|
||||
from litellm.integrations.otel.plumbing.otlp_transport import build_otlp_http_transport
|
||||
|
||||
tls: Final = resolve_otlp_http_tls("METRICS", parse_headers(config.headers))
|
||||
tls: Final = resolve_otlp_http_tls("METRICS")
|
||||
exporter: object = HTTPMetricExporter(
|
||||
endpoint=_otlp_metrics_endpoint(config.endpoint),
|
||||
headers=parse_headers(config.headers),
|
||||
_transport=build_otlp_http_transport("METRICS", tls),
|
||||
certificate_file=tls.certificate_file,
|
||||
session=tls.session,
|
||||
)
|
||||
elif kind in ("otlp_grpc", "grpc"):
|
||||
try:
|
||||
|
|
@ -1237,7 +1233,7 @@ def _otlp_logs_endpoint(endpoint: str | None) -> str | None:
|
|||
return endpoint + "/v1/logs"
|
||||
|
||||
|
||||
def build_log_exporter(config: OpenTelemetryV2Config) -> LogRecordExporter:
|
||||
def build_log_exporter(config: OpenTelemetryV2Config) -> LogExporter:
|
||||
"""Build a log exporter mirroring the exporter selection of the other signals.
|
||||
|
||||
``console`` (and any unrecognized kind) exports to the console; ``otlp_http``
|
||||
|
|
@ -1247,19 +1243,18 @@ def build_log_exporter(config: OpenTelemetryV2Config) -> LogRecordExporter:
|
|||
"""
|
||||
kind: Final = (config.exporter or "console").lower()
|
||||
if kind in ("in_memory", "inmemory", "memory"):
|
||||
return InMemoryLogRecordExporter()
|
||||
return InMemoryLogExporter()
|
||||
if kind in ("otlp_http", "http", "http/protobuf", "http/json"):
|
||||
from opentelemetry.exporter.otlp.proto.http._log_exporter import (
|
||||
OTLPLogExporter as HTTPLogExporter,
|
||||
)
|
||||
|
||||
from litellm.integrations.otel.plumbing.otlp_transport import build_otlp_http_transport
|
||||
|
||||
tls: Final = resolve_otlp_http_tls("LOGS", parse_headers(config.headers))
|
||||
tls: Final = resolve_otlp_http_tls("LOGS")
|
||||
return HTTPLogExporter(
|
||||
endpoint=_otlp_logs_endpoint(config.endpoint),
|
||||
headers=parse_headers(config.headers),
|
||||
_transport=build_otlp_http_transport("LOGS", tls),
|
||||
certificate_file=tls.certificate_file,
|
||||
session=tls.session,
|
||||
)
|
||||
if kind in ("otlp_grpc", "grpc"):
|
||||
try:
|
||||
|
|
@ -1273,24 +1268,24 @@ def build_log_exporter(config: OpenTelemetryV2Config) -> LogRecordExporter:
|
|||
) from exc
|
||||
|
||||
return GRPCLogExporter(endpoint=config.endpoint, headers=parse_headers(config.headers))
|
||||
return ConsoleLogRecordExporter()
|
||||
return ConsoleLogExporter()
|
||||
|
||||
|
||||
def build_logger_provider(
|
||||
config: OpenTelemetryV2Config,
|
||||
log_exporter: LogRecordExporter | None = None,
|
||||
log_exporter: LogExporter | None = None,
|
||||
) -> SDKLoggerProvider:
|
||||
"""Build the :class:`LoggerProvider` GenAI events export through.
|
||||
|
||||
``log_exporter`` is an explicit override (tests inject an
|
||||
``InMemoryLogRecordExporter``); otherwise the exporter is selected from the config's
|
||||
``InMemoryLogExporter``); otherwise the exporter is selected from the config's
|
||||
exporter kind via :func:`build_log_exporter`. Console and in-memory exporters
|
||||
get a Simple processor (synchronous export, which tests rely on), everything
|
||||
else a Batch processor — the same split as span processing.
|
||||
"""
|
||||
exporter: Final = log_exporter if log_exporter is not None else build_log_exporter(config)
|
||||
provider: Final = SDKLoggerProvider(resource=build_resource(config))
|
||||
use_simple: Final = isinstance(exporter, (ConsoleLogRecordExporter, InMemoryLogRecordExporter))
|
||||
use_simple: Final = isinstance(exporter, (ConsoleLogExporter, InMemoryLogExporter))
|
||||
provider.add_log_record_processor(
|
||||
SimpleLogRecordProcessor(exporter) if use_simple else BatchLogRecordProcessor(exporter)
|
||||
)
|
||||
|
|
|
|||
|
|
@ -9,14 +9,14 @@ this preset registers a custom exporter (``kind="agentops"``) that mints the JWT
|
|||
worker thread, off any event loop — and caches it for the process lifetime.
|
||||
"""
|
||||
|
||||
from collections.abc import Sequence
|
||||
from typing import Final
|
||||
|
||||
import httpx
|
||||
import requests
|
||||
from opentelemetry.sdk.trace.export import SpanExporter
|
||||
from opentelemetry.sdk.trace import ReadableSpan
|
||||
from opentelemetry.sdk.trace.export import SpanExporter, SpanExportResult
|
||||
from pydantic import Field
|
||||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||
from requests.auth import AuthBase
|
||||
|
||||
from litellm._logging import verbose_logger
|
||||
from litellm.integrations.otel.model.config import (
|
||||
|
|
@ -24,7 +24,6 @@ from litellm.integrations.otel.model.config import (
|
|||
ExporterSpec,
|
||||
OpenTelemetryV2Config,
|
||||
)
|
||||
from litellm.integrations.otel.plumbing.otlp_tls import OtlpHttpTls, resolve_otlp_http_tls
|
||||
from litellm.integrations.otel.plumbing.providers import register_exporter_factory
|
||||
|
||||
_AGENTOPS_ENDPOINT: Final = "https://otlp.agentops.ai/v1/traces"
|
||||
|
|
@ -75,44 +74,47 @@ def agentops_preset(
|
|||
)
|
||||
|
||||
|
||||
class _AgentOpsAuth(AuthBase):
|
||||
def __init__(self, api_key: str | None) -> None:
|
||||
self._api_key = api_key
|
||||
self._resolved = False
|
||||
self._token: str | None = None
|
||||
|
||||
def __call__(self, request: requests.PreparedRequest) -> requests.PreparedRequest:
|
||||
if not self._resolved:
|
||||
self._resolved = True
|
||||
if self._api_key:
|
||||
try:
|
||||
token: Final = _fetch_agentops_jwt(self._api_key).get("token")
|
||||
if isinstance(token, str) and token:
|
||||
self._token = token
|
||||
except Exception as error:
|
||||
verbose_logger.debug("AgentOps JWT fetch failed: %s", error)
|
||||
authenticated: Final = request.copy()
|
||||
if self._token:
|
||||
authenticated.headers["Authorization"] = f"Bearer {self._token}"
|
||||
return authenticated
|
||||
|
||||
|
||||
def _build_agentops_exporter(spec: ExporterSpec) -> SpanExporter:
|
||||
"""Authenticate lazily through requests' public session authentication API."""
|
||||
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
|
||||
"""Factory for the ``agentops`` exporter kind: a lazy-auth OTLP/HTTP exporter."""
|
||||
from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
|
||||
OTLPSpanExporter,
|
||||
)
|
||||
|
||||
from litellm.integrations.otel.plumbing.otlp_transport import build_otlp_http_transport
|
||||
class _LazyAuthAgentOpsExporter(OTLPSpanExporter):
|
||||
"""OTLP/HTTP exporter that mints the AgentOps JWT on its first export.
|
||||
|
||||
``export`` runs in the ``BatchSpanProcessor`` worker thread, so the
|
||||
blocking token fetch never touches an event loop. The result is cached
|
||||
after the first attempt (success or failure) so it runs at most once.
|
||||
"""
|
||||
|
||||
def __init__(self, *, endpoint: str | None, api_key: str | None) -> None:
|
||||
super().__init__(endpoint=endpoint)
|
||||
self._agentops_api_key = api_key
|
||||
self._auth_resolved = False
|
||||
|
||||
def _ensure_authenticated(self) -> None:
|
||||
if self._auth_resolved:
|
||||
return
|
||||
self._auth_resolved = True
|
||||
if not self._agentops_api_key:
|
||||
return
|
||||
try:
|
||||
token: Final = _fetch_agentops_jwt(self._agentops_api_key).get("token")
|
||||
if token:
|
||||
# ``_session`` is the requests.Session the base exporter
|
||||
# POSTs through; updating its Authorization header is how the
|
||||
# minted JWT reaches every subsequent export.
|
||||
self._session.headers["Authorization"] = f"Bearer {token}"
|
||||
except Exception as e:
|
||||
verbose_logger.debug("AgentOps JWT fetch failed: %s", e)
|
||||
|
||||
def export(self, spans: Sequence[ReadableSpan]) -> SpanExportResult:
|
||||
self._ensure_authenticated()
|
||||
return super().export(spans)
|
||||
|
||||
options: Final = spec.options or {}
|
||||
tls: Final = resolve_otlp_http_tls("TRACES", isolate_headers=True)
|
||||
session: Final = tls.session or requests.Session()
|
||||
session.auth = _AgentOpsAuth(options.get("api_key"))
|
||||
return OTLPSpanExporter(
|
||||
endpoint=spec.endpoint,
|
||||
_transport=build_otlp_http_transport(
|
||||
"TRACES", OtlpHttpTls(certificate_file=tls.certificate_file, session=session)
|
||||
),
|
||||
)
|
||||
return _LazyAuthAgentOpsExporter(endpoint=spec.endpoint, api_key=options.get("api_key"))
|
||||
|
||||
|
||||
def _fetch_agentops_jwt(api_key: str) -> dict[str, object]:
|
||||
|
|
|
|||
|
|
@ -25,8 +25,6 @@ from opentelemetry.sdk.metrics.export import PeriodicExportingMetricReader
|
|||
from opentelemetry.sdk.resources import Resource
|
||||
|
||||
from litellm._logging import verbose_proxy_logger
|
||||
from litellm.integrations.otel.plumbing.otlp_tls import OtlpHttpTls
|
||||
from litellm.integrations.otel.plumbing.otlp_transport import build_otlp_http_transport
|
||||
from litellm.proxy.middleware.billable_request_metrics_middleware import (
|
||||
BillableCategory,
|
||||
)
|
||||
|
|
@ -106,12 +104,10 @@ def build_mtls_meter_provider(config: BillingMetricsConfig) -> MeterProvider:
|
|||
"""
|
||||
exporter: Final = OTLPMetricExporter(
|
||||
endpoint=_metrics_endpoint(config.endpoint),
|
||||
_transport=build_otlp_http_transport(
|
||||
"METRICS",
|
||||
OtlpHttpTls(certificate_file=config.ca_cert_path, session=None),
|
||||
client_certificate_file=config.client_cert_path,
|
||||
client_key_file=config.client_key_path,
|
||||
),
|
||||
# None -> exporter falls back to the system trust store.
|
||||
certificate_file=config.ca_cert_path,
|
||||
client_certificate_file=config.client_cert_path,
|
||||
client_key_file=config.client_key_path,
|
||||
)
|
||||
reader: Final = PeriodicExportingMetricReader(exporter, export_interval_millis=config.export_interval_ms)
|
||||
return MeterProvider(metric_readers=[reader], resource=Resource.create(_resource_attributes(config)))
|
||||
|
|
|
|||
|
|
@ -177,17 +177,16 @@ proxy-runtime = [
|
|||
"grpcio==1.78.0",
|
||||
"prometheus-client>=0.20.0,<1.0",
|
||||
"langfuse>=4.7,<5.0",
|
||||
"opentelemetry-api==1.45.1",
|
||||
"opentelemetry-sdk==1.45.1",
|
||||
"opentelemetry-exporter-otlp==1.45.1",
|
||||
"opentelemetry-exporter-otlp-json-http==0.66b1",
|
||||
"opentelemetry-instrumentation-fastapi==0.66b1",
|
||||
"opentelemetry-api==1.33.1",
|
||||
"opentelemetry-sdk==1.33.1",
|
||||
"opentelemetry-exporter-otlp==1.33.1",
|
||||
"opentelemetry-instrumentation-fastapi==0.54b1",
|
||||
"ddtrace>=4.8.2,<5.0",
|
||||
"sentry-sdk>=2.21.0,<3.0",
|
||||
"mangum>=0.17.0,<1.0",
|
||||
"azure-ai-contentsafety>=1.0.0,<2.0",
|
||||
"azure-storage-file-datalake>=12.20.0,<13.0",
|
||||
"pypdf>=6.21.1,<7.0",
|
||||
"pypdf>=6.16.1,<7.0",
|
||||
"llm-sandbox>=0.3.39,<1.0",
|
||||
"detect-secrets>=1.5.0,<2.0",
|
||||
]
|
||||
|
|
@ -224,11 +223,10 @@ dev = [
|
|||
"types-PyYAML==6.0.12.20250915",
|
||||
"botocore-stubs==1.43.14",
|
||||
"types-boto3[bedrock,bedrock-agent,bedrock-runtime,kms,s3,sagemaker-runtime,sts]==1.43.30",
|
||||
"opentelemetry-api==1.45.1",
|
||||
"opentelemetry-sdk==1.45.1",
|
||||
"opentelemetry-exporter-otlp==1.45.1",
|
||||
"opentelemetry-exporter-otlp-json-http==0.66b1",
|
||||
"opentelemetry-instrumentation-fastapi==0.66b1",
|
||||
"opentelemetry-api==1.33.1",
|
||||
"opentelemetry-sdk==1.33.1",
|
||||
"opentelemetry-exporter-otlp==1.33.1",
|
||||
"opentelemetry-instrumentation-fastapi==0.54b1",
|
||||
"langfuse>=4.7,<5.0",
|
||||
"fastapi-offline==1.7.6",
|
||||
"fakeredis==2.34.1",
|
||||
|
|
@ -257,11 +255,10 @@ proxy-dev = [
|
|||
"hypercorn==0.17.3",
|
||||
"prometheus-client==0.20.0",
|
||||
"sentry-sdk==2.21.0",
|
||||
"opentelemetry-api==1.45.1",
|
||||
"opentelemetry-sdk==1.45.1",
|
||||
"opentelemetry-exporter-otlp==1.45.1",
|
||||
"opentelemetry-exporter-otlp-json-http==0.66b1",
|
||||
"opentelemetry-instrumentation-fastapi==0.66b1",
|
||||
"opentelemetry-api==1.33.1",
|
||||
"opentelemetry-sdk==1.33.1",
|
||||
"opentelemetry-exporter-otlp==1.33.1",
|
||||
"opentelemetry-instrumentation-fastapi==0.54b1",
|
||||
"azure-identity==1.25.2",
|
||||
"a2a-sdk==1.1.0",
|
||||
"backports-zstd==1.8.0; python_version < '3.14'",
|
||||
|
|
@ -283,7 +280,7 @@ ci = [
|
|||
"langchain==1.3.9",
|
||||
"lunary==1.4.36; python_version == '3.10'",
|
||||
"lunary==1.4.37; python_version >= '3.11'",
|
||||
"logfire==5.2.0",
|
||||
"logfire==4.6.0",
|
||||
"traceloop-sdk==0.34.0",
|
||||
"detect-secrets==1.5.0",
|
||||
"PyGithub==2.8.1",
|
||||
|
|
|
|||
|
|
@ -165,30 +165,6 @@ def test_requested_trace_id_is_the_exported_trace_id_and_the_generation_is_its_r
|
|||
assert span.parent is None
|
||||
|
||||
|
||||
|
||||
@pytest.mark.parametrize("trace_id", ["0" * 31 + "1", None])
|
||||
def test_trace_randomness_flag_matches_the_id_source(channel, trace_id):
|
||||
from opentelemetry.context import Context
|
||||
from litellm.integrations.langfuse.langfuse_sdk import _start_span
|
||||
|
||||
tracing, exporter = channel
|
||||
span = _start_span(
|
||||
tracing.tracer,
|
||||
name="id-source",
|
||||
context=Context(),
|
||||
start_time=CALL_START,
|
||||
trace_id=trace_id,
|
||||
observation_id=None,
|
||||
attributes={},
|
||||
)
|
||||
span.end(end_time=to_unix_nanos(CALL_END))
|
||||
tracing.flush()
|
||||
exported = _only_span(exporter, "id-source")
|
||||
assert exported.context.trace_flags.random_trace_id is (trace_id is None)
|
||||
assert exported.context.trace_flags.sampled
|
||||
if trace_id is not None:
|
||||
assert exported.context.trace_id == int(trace_id, 16)
|
||||
|
||||
def test_parent_observation_id_nests_the_generation_under_the_callers_observation(channel):
|
||||
tracing, exporter = channel
|
||||
_generation(tracing, name="child-gen", parent=PARENT_C).end(CALL_END)
|
||||
|
|
|
|||
|
|
@ -23,9 +23,8 @@ from opentelemetry.proto.collector.trace.v1.trace_service_pb2 import ( # noqa:
|
|||
from opentelemetry import baggage # noqa: E402
|
||||
from opentelemetry.context import attach, detach # noqa: E402
|
||||
from opentelemetry._logs.severity import SeverityNumber # noqa: E402
|
||||
from opentelemetry._logs import LogRecord
|
||||
from opentelemetry.sdk._logs import ReadableLogRecord # noqa: E402
|
||||
from opentelemetry.sdk._logs.export import LogRecordExportResult # noqa: E402
|
||||
from opentelemetry.sdk._logs import LogData, LogRecord # noqa: E402
|
||||
from opentelemetry.sdk._logs.export import LogExportResult # noqa: E402
|
||||
from opentelemetry.sdk.metrics import MeterProvider # noqa: E402
|
||||
from opentelemetry.sdk.metrics.export import InMemoryMetricReader # noqa: E402
|
||||
from opentelemetry.sdk.trace import TracerProvider # noqa: E402
|
||||
|
|
@ -677,9 +676,7 @@ def test_parse_headers_percent_decodes_values():
|
|||
documents ``Authorization=Basic%20<token>``. Forwarding the literal ``%20``
|
||||
makes the backend reject the export as a malformed credential.
|
||||
"""
|
||||
from base64 import b64encode
|
||||
|
||||
token: Final = b64encode(b"TEST_ONLY_USER:TEST_ONLY_PASSWORD").decode()
|
||||
token = "MTMzNzc4MzpnbGNfZXlKdklqb2lNVEl6TkNJPQ=="
|
||||
assert providers.parse_headers(f"Authorization=Basic%20{token}") == {"authorization": f"Basic {token}"}
|
||||
assert providers.parse_headers("x-scope-orgid=team%20a") == {"x-scope-orgid": "team a"}
|
||||
|
||||
|
|
@ -736,7 +733,7 @@ def _export_one_trace_to_local_collector(exporter_kind: str) -> tuple[list[dict]
|
|||
class Collector(BaseHTTPRequestHandler):
|
||||
def do_POST(self):
|
||||
body = self.rfile.read(int(self.headers["Content-Length"]))
|
||||
received.append({"path": self.path, "headers": requests.structures.CaseInsensitiveDict(self.headers), "body": body})
|
||||
received.append({"path": self.path, "headers": dict(self.headers), "body": body})
|
||||
self.send_response(200)
|
||||
self.end_headers()
|
||||
|
||||
|
|
@ -789,60 +786,13 @@ def test_http_json_exporter_posts_otlp_json_to_traces_endpoint():
|
|||
assert parent["kind"] == 2
|
||||
assert parent["traceId"] == format(trace_id, "032x")
|
||||
assert parent["spanId"] == format(parent_id, "016x")
|
||||
assert parent.get("parentSpanId", "") == ""
|
||||
assert "parentSpanId" not in parent
|
||||
child = _only_span(child_request)
|
||||
assert child["traceId"] == format(trace_id, "032x")
|
||||
assert child["spanId"] == format(child_id, "016x")
|
||||
assert child["parentSpanId"] == format(parent_id, "016x")
|
||||
|
||||
|
||||
|
||||
@pytest.mark.parametrize("compression", ["none", "gzip", "deflate"])
|
||||
def test_http_json_exporter_preserves_session_tls_auth_and_compression(monkeypatch, requests_mock, compression):
|
||||
import gzip
|
||||
import zlib
|
||||
|
||||
from opentelemetry.sdk.trace.export import SpanExportResult
|
||||
from litellm.integrations.otel.plumbing.otlp_json import OTLPJsonSpanExporter
|
||||
|
||||
monkeypatch.setenv("REQUESTS_CA_BUNDLE", "/corporate/global-ca.pem")
|
||||
monkeypatch.setenv("OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE", "/collector/environment-ca.pem")
|
||||
monkeypatch.setenv("OTEL_EXPORTER_OTLP_TRACES_COMPRESSION", compression)
|
||||
monkeypatch.setenv("OTEL_EXPORTER_OTLP_TRACES_CLIENT_CERTIFICATE", "/collector/client.crt")
|
||||
monkeypatch.setenv("OTEL_EXPORTER_OTLP_TRACES_CLIENT_KEY", "/collector/client.key")
|
||||
monkeypatch.setenv("HTTPS_PROXY", "http://proxy.example:8080")
|
||||
collector = requests_mock.post("https://collector.example/v1/traces", status_code=200)
|
||||
session = requests.Session()
|
||||
session.headers["x-session-marker"] = "retained"
|
||||
session.auth = requests.auth.HTTPBasicAuth("session-user", "synthetic-password")
|
||||
exporter = OTLPJsonSpanExporter(
|
||||
endpoint="https://collector.example/v1/traces",
|
||||
headers={"x-exporter-marker": "configured"},
|
||||
certificate_file="/collector/ca.crt",
|
||||
session=session,
|
||||
)
|
||||
provider = TracerProvider()
|
||||
span = provider.get_tracer(__name__).start_span("session-export")
|
||||
span.end()
|
||||
try:
|
||||
assert exporter.export([span]) is SpanExportResult.SUCCESS
|
||||
request = collector.last_request
|
||||
assert request.headers["Content-Type"] == "application/json"
|
||||
assert request.headers["x-session-marker"] == "retained"
|
||||
assert request.headers["x-exporter-marker"] == "configured"
|
||||
assert request.headers["Authorization"] == "Basic c2Vzc2lvbi11c2VyOnN5bnRoZXRpYy1wYXNzd29yZA=="
|
||||
assert request.verify == "/collector/ca.crt"
|
||||
assert request.cert == ("/collector/client.crt", "/collector/client.key")
|
||||
assert request.proxies["https"] == "http://proxy.example:8080"
|
||||
decompress = {"none": lambda body: body, "gzip": gzip.decompress, "deflate": zlib.decompress}[compression]
|
||||
payload = json.loads(decompress(request.body))
|
||||
exported = payload["resourceSpans"][0]["scopeSpans"][0]["spans"][0]
|
||||
assert exported["name"] == "session-export"
|
||||
assert exported["traceId"] == f"{span.get_span_context().trace_id:032x}"
|
||||
finally:
|
||||
exporter.shutdown()
|
||||
provider.shutdown()
|
||||
|
||||
def test_http_protobuf_exporter_still_posts_protobuf():
|
||||
(_child_request, parent_request), (trace_id, _parent_id, _child_id) = _export_one_trace_to_local_collector(
|
||||
"http/protobuf"
|
||||
|
|
@ -974,20 +924,20 @@ def test_otlp_logs_endpoint_normalization():
|
|||
|
||||
|
||||
def test_build_log_exporter_variants():
|
||||
from opentelemetry.sdk._logs.export import ConsoleLogRecordExporter, InMemoryLogRecordExporter
|
||||
from opentelemetry.sdk._logs.export import ConsoleLogExporter, InMemoryLogExporter
|
||||
|
||||
assert isinstance(
|
||||
providers.build_log_exporter(OpenTelemetryV2Config(exporter="console")),
|
||||
ConsoleLogRecordExporter,
|
||||
ConsoleLogExporter,
|
||||
)
|
||||
assert isinstance(
|
||||
providers.build_log_exporter(OpenTelemetryV2Config(exporter="in_memory")),
|
||||
InMemoryLogRecordExporter,
|
||||
InMemoryLogExporter,
|
||||
)
|
||||
# An unrecognized kind falls back to console rather than dropping events.
|
||||
assert isinstance(
|
||||
providers.build_log_exporter(OpenTelemetryV2Config(exporter="unknown")),
|
||||
ConsoleLogRecordExporter,
|
||||
ConsoleLogExporter,
|
||||
)
|
||||
http_exporter = providers.build_log_exporter(OpenTelemetryV2Config(exporter="otlp_http", endpoint="http://h:4318"))
|
||||
assert "OTLPLogExporter" in type(http_exporter).__name__
|
||||
|
|
@ -1680,13 +1630,9 @@ def test_v2_otlp_http_log_export_trusts_ssl_cert_file(monkeypatch: pytest.Monkey
|
|||
severity_number=SeverityNumber.INFO,
|
||||
body="v2-tls-test",
|
||||
)
|
||||
log_data = ReadableLogRecord(
|
||||
log_record=record,
|
||||
resource=providers.build_resource(cfg),
|
||||
instrumentation_scope=InstrumentationScope("v2-tls-test"),
|
||||
)
|
||||
log_data = LogData(log_record=record, instrumentation_scope=InstrumentationScope("v2-tls-test"))
|
||||
result = exporter.export([log_data])
|
||||
assert result is LogRecordExportResult.SUCCESS, f"log export failed: {result}"
|
||||
assert result is LogExportResult.SUCCESS, f"log export failed: {result}"
|
||||
assert tls_sink.received.get(timeout=5) == "/v1/logs"
|
||||
finally:
|
||||
exporter.shutdown()
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
import asyncio
|
||||
import contextvars
|
||||
import gzip
|
||||
import os
|
||||
import threading
|
||||
import time
|
||||
from base64 import b64encode
|
||||
|
|
@ -5069,267 +5067,3 @@ class TestArizeProjectRouting:
|
|||
monkeypatch.setenv("ARIZE_PROJECT_NAME", "gateway-prod")
|
||||
|
||||
assert self._forwarded_projects() == {"gateway-prod"}
|
||||
|
||||
|
||||
def _export_header_probe(api: str, signal: str, endpoint: str, headers: str | None) -> None:
|
||||
from opentelemetry.sdk.metrics import MeterProvider
|
||||
|
||||
from litellm.integrations.opentelemetry import OpenTelemetry, OpenTelemetryConfig
|
||||
|
||||
config: Final = OpenTelemetryV2Config(
|
||||
exporter="http/json" if api == "v2-json" else "otlp_http", endpoint=endpoint, headers=headers
|
||||
)
|
||||
tracing: Final = TracerProvider()
|
||||
legacy: Final = (
|
||||
OpenTelemetry(
|
||||
config=OpenTelemetryConfig(exporter="otlp_http", endpoint=endpoint, headers=headers),
|
||||
tracer_provider=tracing,
|
||||
)
|
||||
if api == "v1"
|
||||
else None
|
||||
)
|
||||
try:
|
||||
if signal == "metrics":
|
||||
reader: Final = legacy._get_metric_reader() if legacy else otel_providers.build_metric_reader(config)
|
||||
metrics: Final = MeterProvider(metric_readers=(reader,))
|
||||
try:
|
||||
metrics.get_meter("header-isolation").create_counter("header_probe").add(1)
|
||||
assert metrics.force_flush()
|
||||
finally:
|
||||
metrics.shutdown()
|
||||
elif signal == "logs":
|
||||
logs: Final = legacy._get_log_exporter() if legacy else otel_providers.build_log_exporter(config)
|
||||
try:
|
||||
assert logs.export(()).name == "SUCCESS"
|
||||
finally:
|
||||
logs.shutdown()
|
||||
elif legacy:
|
||||
processor: Final = legacy._get_span_processor()
|
||||
try:
|
||||
assert processor.span_exporter.export(()).name == "SUCCESS"
|
||||
finally:
|
||||
processor.shutdown()
|
||||
else:
|
||||
spans: Final = otel_providers.build_span_exporter(config)
|
||||
try:
|
||||
assert spans.export(()).name == "SUCCESS"
|
||||
finally:
|
||||
spans.shutdown()
|
||||
finally:
|
||||
tracing.shutdown()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("api", "signal"),
|
||||
(
|
||||
("v1", "traces"),
|
||||
("v1", "metrics"),
|
||||
("v1", "logs"),
|
||||
("v2", "traces"),
|
||||
("v2", "metrics"),
|
||||
("v2", "logs"),
|
||||
("v2-json", "traces"),
|
||||
),
|
||||
)
|
||||
@pytest.mark.parametrize("signal_headers", (False, True))
|
||||
def test_http_destinations_do_not_inherit_other_accounts_headers(
|
||||
monkeypatch, requests_mock, api: str, signal: str, signal_headers: bool
|
||||
) -> None:
|
||||
variable: Final = f"OTEL_EXPORTER_OTLP_{signal.upper()}_HEADERS" if signal_headers else "OTEL_EXPORTER_OTLP_HEADERS"
|
||||
operator_headers: Final = "Authorization=Bearer%20operator-key,x-operator-key=operator-only"
|
||||
monkeypatch.setenv(variable, operator_headers)
|
||||
for account, configured in (("tenant-a", "a-key"), ("tenant-b", "b-key"), ("operator", None)):
|
||||
endpoint: Final = f"https://{account}.example.test"
|
||||
captured: Final = requests_mock.post(f"{endpoint}/v1/{signal}", content=b"")
|
||||
|
||||
_export_header_probe(api, signal, endpoint, f"x-tenant-key={configured}" if configured else None)
|
||||
|
||||
assert captured.request_history, f"{account} never exported {signal}"
|
||||
for request in captured.request_history:
|
||||
credentials: Final = {
|
||||
name.lower(): value
|
||||
for name, value in request.headers.items()
|
||||
if name.lower() in {"authorization", "x-operator-key", "x-tenant-key"}
|
||||
}
|
||||
assert credentials == (
|
||||
{"x-tenant-key": configured}
|
||||
if configured
|
||||
else {"authorization": "Bearer operator-key", "x-operator-key": "operator-only"}
|
||||
)
|
||||
assert os.environ[variable] == operator_headers
|
||||
|
||||
|
||||
@pytest.mark.parametrize("protocol", ("otlp_http", "http/json"))
|
||||
def test_headerless_tenant_destination_does_not_receive_operator_credentials(monkeypatch, requests_mock, protocol):
|
||||
monkeypatch.setenv("OTEL_EXPORTER_OTLP_HEADERS", "Authorization=Bearer%20operator-key")
|
||||
captured: Final = requests_mock.post("https://tenant.example.test/v1/traces", content=b"")
|
||||
processor: Final = otel_providers._destination_processor(
|
||||
OtelDestination(endpoint="https://tenant.example.test", headers={}, protocol=protocol)
|
||||
)
|
||||
assert processor is not None
|
||||
provider: Final = TracerProvider()
|
||||
provider.add_span_processor(processor)
|
||||
try:
|
||||
emit(provider, "headerless-tenant")
|
||||
assert provider.force_flush()
|
||||
assert captured.request_history
|
||||
assert all("Authorization" not in request.headers for request in captured.request_history)
|
||||
finally:
|
||||
provider.shutdown()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("api", ("v2", "v2-json"))
|
||||
def test_isolated_headers_keep_the_exporters_content_type_and_compression(monkeypatch, requests_mock, api):
|
||||
monkeypatch.setenv("OTEL_EXPORTER_OTLP_HEADERS", "Content-Type=operator-only,Content-Encoding=operator-only")
|
||||
monkeypatch.setenv("OTEL_EXPORTER_OTLP_TRACES_COMPRESSION", "gzip")
|
||||
captured: Final = requests_mock.post("https://tenant.example.test/v1/traces", content=b"")
|
||||
|
||||
_export_header_probe(api, "traces", "https://tenant.example.test", "x-tenant-key=tenant-key")
|
||||
|
||||
assert len(captured.request_history) == 1
|
||||
request: Final = captured.last_request
|
||||
assert request.headers["Content-Type"] == ("application/json" if api == "v2-json" else "application/x-protobuf")
|
||||
assert request.headers["Content-Encoding"] == "gzip"
|
||||
monkeypatch.delenv("OTEL_EXPORTER_OTLP_TRACES_COMPRESSION")
|
||||
|
||||
_export_header_probe(api, "traces", "https://tenant.example.test", "x-tenant-key=tenant-key")
|
||||
|
||||
assert gzip.decompress(request.body) == (captured.last_request.body or b"")
|
||||
|
||||
|
||||
@pytest.mark.parametrize("api", ("v2", "v2-json"))
|
||||
@pytest.mark.parametrize("header", ("Authorization", "AUTHORIZATION", "authorization"))
|
||||
def test_tenant_authorization_replaces_operator_authorization(monkeypatch, requests_mock, api, header):
|
||||
monkeypatch.setenv("OTEL_EXPORTER_OTLP_HEADERS", "Authorization=Bearer%20operator-key")
|
||||
captured: Final = requests_mock.post("https://tenant.example.test/v1/traces", content=b"")
|
||||
|
||||
_export_header_probe(api, "traces", "https://tenant.example.test", f"{header}=Bearer tenant-key")
|
||||
|
||||
assert len(captured.request_history) == 1
|
||||
assert captured.last_request.headers["Authorization"] == "Bearer tenant-key"
|
||||
assert "Bearer operator-key" not in captured.last_request.headers.values()
|
||||
|
||||
|
||||
@pytest.mark.parametrize("protocol", ("otlp_http", "http/json"))
|
||||
def test_session_defaults_cannot_restore_excluded_operator_headers(monkeypatch, requests_mock, protocol):
|
||||
from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
|
||||
|
||||
from litellm.integrations.otel.plumbing.otlp_json import OTLPJsonSpanExporter
|
||||
from litellm.integrations.otel.plumbing.otlp_tls import resolve_otlp_http_tls
|
||||
|
||||
monkeypatch.setenv("OTEL_EXPORTER_OTLP_HEADERS", "Authorization=Bearer%20operator-key,x-operator-key=operator-only")
|
||||
captured: Final = requests_mock.post("https://tenant.example.test/v1/traces", content=b"")
|
||||
headers: Final = {"x-tenant-key": "tenant-key"}
|
||||
tls: Final = resolve_otlp_http_tls("TRACES", headers)
|
||||
assert tls.session is not None
|
||||
tls.session.headers.update({"AUTHORIZATION": "Bearer operator-key", "X-Operator-Key": "operator-only"})
|
||||
exporter_type: Final = OTLPJsonSpanExporter if protocol == "http/json" else OTLPSpanExporter
|
||||
exporter: Final = exporter_type(
|
||||
endpoint="https://tenant.example.test/v1/traces", headers=headers, session=tls.session
|
||||
)
|
||||
try:
|
||||
assert exporter.export(()).name == "SUCCESS"
|
||||
assert len(captured.request_history) == 1
|
||||
assert captured.last_request.headers["x-tenant-key"] == "tenant-key"
|
||||
assert "Authorization" not in captured.last_request.headers
|
||||
assert "x-operator-key" not in captured.last_request.headers
|
||||
finally:
|
||||
exporter.shutdown()
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("api", "signal"),
|
||||
(("v1", "traces"), ("v1", "logs"), ("v1", "metrics"),
|
||||
("v2", "traces"), ("v2", "logs"), ("v2", "metrics"), ("v2-json", "traces")),
|
||||
)
|
||||
@pytest.mark.parametrize("requests_ca", ("REQUESTS_CA_BUNDLE", "CURL_CA_BUNDLE"))
|
||||
@pytest.mark.parametrize("collector_ca", ("signal", "global", "SSL_CERT_FILE", "ssl_verify"))
|
||||
@pytest.mark.parametrize("tenant", (False, True))
|
||||
def test_explicit_collector_ca_precedes_requests_environment(
|
||||
monkeypatch, requests_mock, tmp_path, api: str, signal: str, requests_ca: str, collector_ca: str, tenant: bool
|
||||
) -> None:
|
||||
certificate_path: Final = tmp_path / "collector-ca.pem"
|
||||
certificate_path.write_text("TEST_ONLY_CA")
|
||||
certificate: Final = str(certificate_path)
|
||||
for variable in ("REQUESTS_CA_BUNDLE", "CURL_CA_BUNDLE", "SSL_CERT_FILE", "SSL_VERIFY",
|
||||
"OTEL_EXPORTER_OTLP_CERTIFICATE", f"OTEL_EXPORTER_OTLP_{signal.upper()}_CERTIFICATE"):
|
||||
monkeypatch.delenv(variable, raising=False)
|
||||
monkeypatch.setattr(litellm, "ssl_verify", True)
|
||||
monkeypatch.setenv(requests_ca, "/corporate/global-ca.pem")
|
||||
if collector_ca == "ssl_verify":
|
||||
monkeypatch.setattr(litellm, "ssl_verify", certificate)
|
||||
else:
|
||||
variable: Final = (
|
||||
f"OTEL_EXPORTER_OTLP_{signal.upper()}_CERTIFICATE" if collector_ca == "signal"
|
||||
else "OTEL_EXPORTER_OTLP_CERTIFICATE" if collector_ca == "global" else collector_ca
|
||||
)
|
||||
monkeypatch.setenv(variable, certificate)
|
||||
if collector_ca == "signal":
|
||||
monkeypatch.setenv("OTEL_EXPORTER_OTLP_CERTIFICATE", "/collector/generic-ca.pem")
|
||||
monkeypatch.setenv(f"OTEL_EXPORTER_OTLP_{signal.upper()}_CLIENT_CERTIFICATE", "/collector/client.pem")
|
||||
monkeypatch.setenv(f"OTEL_EXPORTER_OTLP_{signal.upper()}_CLIENT_KEY", "/collector/client.key")
|
||||
monkeypatch.setenv("HTTPS_PROXY", "http://proxy.example.invalid:8080")
|
||||
monkeypatch.setenv("OTEL_EXPORTER_OTLP_HEADERS", "Authorization=Bearer%20TEST_ONLY_OPERATOR")
|
||||
captured: Final = requests_mock.post(f"https://collector.example.invalid/v1/{signal}", content=b"")
|
||||
|
||||
_export_header_probe(api, signal, "https://collector.example.invalid", "x-tenant-key=TEST_ONLY" if tenant else None)
|
||||
|
||||
assert captured.request_history
|
||||
for request in captured.request_history:
|
||||
assert request.verify == certificate
|
||||
assert request.cert == ("/collector/client.pem", "/collector/client.key")
|
||||
assert request.proxies["https"] == "http://proxy.example.invalid:8080"
|
||||
assert request.headers.get("Authorization") == (None if tenant else "Bearer TEST_ONLY_OPERATOR")
|
||||
assert request.headers.get("x-tenant-key") == ("TEST_ONLY" if tenant else None)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("api", ("v1", "v2"))
|
||||
@pytest.mark.parametrize("signal", ("traces", "logs", "metrics"))
|
||||
@pytest.mark.parametrize("global_provider", (False, True))
|
||||
@pytest.mark.parametrize("tenant", (False, True))
|
||||
def test_collector_tls_preserves_operator_credential_provider_without_tenant_leakage(
|
||||
monkeypatch, requests_mock, api: str, signal: str, global_provider: bool, tenant: bool
|
||||
) -> None:
|
||||
from types import SimpleNamespace
|
||||
|
||||
import requests
|
||||
from opentelemetry.exporter.otlp.proto.http import _common
|
||||
|
||||
session: Final = requests.Session()
|
||||
session.auth = requests.auth.HTTPBasicAuth("TEST_ONLY_USER", "TEST_ONLY_PASSWORD")
|
||||
session.headers["x-session-marker"] = "TEST_ONLY_SESSION"
|
||||
provider_variable: Final = (
|
||||
"OTEL_PYTHON_EXPORTER_OTLP_HTTP_CREDENTIAL_PROVIDER" if global_provider
|
||||
else f"OTEL_PYTHON_EXPORTER_OTLP_HTTP_{signal.upper()}_CREDENTIAL_PROVIDER"
|
||||
)
|
||||
monkeypatch.setenv(provider_variable, "TEST_ONLY_PROVIDER")
|
||||
monkeypatch.setenv(f"OTEL_EXPORTER_OTLP_{signal.upper()}_CERTIFICATE", "/collector/collector-ca.pem")
|
||||
monkeypatch.setenv("REQUESTS_CA_BUNDLE", "/corporate/global-ca.pem")
|
||||
monkeypatch.setattr(_common, "entry_points", lambda **kwargs: (SimpleNamespace(load=lambda: lambda: session),))
|
||||
captured: Final = requests_mock.post(f"https://collector.example.invalid/v1/{signal}", content=b"")
|
||||
|
||||
_export_header_probe(api, signal, "https://collector.example.invalid", "x-tenant-key=TEST_ONLY" if tenant else None)
|
||||
|
||||
assert captured.request_history
|
||||
for request in captured.request_history:
|
||||
assert request.verify == "/collector/collector-ca.pem"
|
||||
assert request.headers.get("x-session-marker") == (None if tenant else "TEST_ONLY_SESSION")
|
||||
assert request.headers.get("Authorization") == (
|
||||
None if tenant else "Basic " + b64encode(b"TEST_ONLY_USER:TEST_ONLY_PASSWORD").decode()
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.parametrize("api", ("v1", "v2", "v2-json"))
|
||||
@pytest.mark.parametrize("requests_ca", ("REQUESTS_CA_BUNDLE", "CURL_CA_BUNDLE"))
|
||||
def test_requests_environment_ca_remains_fallback(monkeypatch, requests_mock, api: str, requests_ca: str) -> None:
|
||||
for variable in ("REQUESTS_CA_BUNDLE", "CURL_CA_BUNDLE", "SSL_CERT_FILE", "SSL_VERIFY",
|
||||
"OTEL_EXPORTER_OTLP_CERTIFICATE", "OTEL_EXPORTER_OTLP_TRACES_CERTIFICATE"):
|
||||
monkeypatch.delenv(variable, raising=False)
|
||||
monkeypatch.setattr(litellm, "ssl_verify", True)
|
||||
monkeypatch.setenv(requests_ca, "/corporate/global-ca.pem")
|
||||
captured: Final = requests_mock.post("https://collector.example.invalid/v1/traces", content=b"")
|
||||
|
||||
_export_header_probe(api, "traces", "https://collector.example.invalid", None)
|
||||
|
||||
assert captured.request_history
|
||||
assert captured.last_request.verify == "/corporate/global-ca.pem"
|
||||
|
|
|
|||
|
|
@ -382,7 +382,7 @@ def test_every_traced_response_names_its_own_server_span(monkeypatch):
|
|||
assert responses["/stream"].text == "data: first\n\ndata: [DONE]\n\n"
|
||||
for path, response in responses.items():
|
||||
context = server_spans[path].context
|
||||
assert response.headers.get_list("traceresponse") == [f"00-{context.trace_id:032x}-{context.span_id:016x}-{context.trace_flags:02x}"]
|
||||
assert response.headers.get_list("traceresponse") == [f"00-{context.trace_id:032x}-{context.span_id:016x}-01"]
|
||||
|
||||
|
||||
@pytest.mark.parametrize("path", ["/relayed", "/relayed/health"])
|
||||
|
|
@ -472,20 +472,13 @@ def test_gate_off_responses_carry_no_traceresponse(monkeypatch):
|
|||
assert "traceresponse" not in TestClient(app).get("/ping").headers
|
||||
|
||||
|
||||
def test_started_app_keeps_serving_without_registering_a_response_propagator(monkeypatch):
|
||||
def test_failed_instrumentation_registers_no_response_propagator(monkeypatch):
|
||||
monkeypatch.setenv("LITELLM_OTEL_V2", "1")
|
||||
app = fastapi.FastAPI()
|
||||
|
||||
@app.get("/running")
|
||||
def running():
|
||||
return {"ok": True}
|
||||
|
||||
with TestClient(app) as client:
|
||||
with TestClient(app):
|
||||
instrument_fastapi_app(app)
|
||||
response = client.get("/running")
|
||||
|
||||
assert response.json() == {"ok": True}
|
||||
assert "traceresponse" not in response.headers
|
||||
assert get_global_response_propagator() is None
|
||||
|
||||
|
||||
|
|
@ -552,4 +545,4 @@ def test_the_unhandled_error_helper_names_the_span_it_is_given_in_any_context(mo
|
|||
|
||||
headers = contextvars.Context().run(trace_response_headers, span)
|
||||
|
||||
assert headers["traceresponse"] == f"00-{context.trace_id:032x}-{context.span_id:016x}-{context.trace_flags:02x}"
|
||||
assert headers["traceresponse"] == f"00-{context.trace_id:032x}-{context.span_id:016x}-01"
|
||||
|
|
|
|||
|
|
@ -2,8 +2,6 @@
|
|||
event loop: the preset does no network I/O, and a custom exporter mints the JWT
|
||||
lazily on its first export (in the BatchSpanProcessor worker thread)."""
|
||||
|
||||
import json
|
||||
|
||||
import httpx
|
||||
import pytest
|
||||
|
||||
|
|
@ -77,53 +75,50 @@ def test_dynamic_cred_presets_tag_exporter_with_matching_owner(monkeypatch):
|
|||
)
|
||||
|
||||
|
||||
def test_agentops_exporter_mints_jwt_lazily(monkeypatch, requests_mock, respx_mock):
|
||||
from opentelemetry.sdk.trace import TracerProvider
|
||||
from opentelemetry.sdk.trace.export import SpanExportResult
|
||||
|
||||
monkeypatch.setenv("OTEL_EXPORTER_OTLP_HEADERS", "Authorization=Bearer%20operator,x-operator-key=operator-secret")
|
||||
auth = respx_mock.post(agentops_mod._AGENTOPS_AUTH_ENDPOINT).respond(200, json={"token": "jwt-xyz"})
|
||||
collector = requests_mock.post(_AGENTOPS_ENDPOINT, status_code=200)
|
||||
exporter = _build_agentops_exporter(
|
||||
ExporterSpec(kind=_AGENTOPS_EXPORTER_KIND, endpoint=_AGENTOPS_ENDPOINT, options={"api_key": "ak"})
|
||||
def test_agentops_exporter_mints_jwt_lazily(monkeypatch):
|
||||
pytest.importorskip("opentelemetry.exporter.otlp.proto.http.trace_exporter")
|
||||
monkeypatch.setattr(
|
||||
agentops_mod, "_fetch_agentops_jwt", lambda _k: {"token": "jwt-xyz"}
|
||||
)
|
||||
provider = TracerProvider()
|
||||
span = provider.get_tracer(__name__).start_span("authenticated")
|
||||
span.end()
|
||||
try:
|
||||
assert auth.call_count == 0
|
||||
assert exporter.export([span]) is SpanExportResult.SUCCESS
|
||||
assert exporter.export([]) is SpanExportResult.SUCCESS
|
||||
assert auth.call_count == 1
|
||||
assert json.loads(auth.calls[0].request.content) == {"api_key": "ak"}
|
||||
assert [request.headers["Authorization"] for request in collector.request_history] == [
|
||||
"Bearer jwt-xyz",
|
||||
"Bearer jwt-xyz",
|
||||
]
|
||||
assert all("x-operator-key" not in request.headers for request in collector.request_history)
|
||||
finally:
|
||||
exporter.shutdown()
|
||||
provider.shutdown()
|
||||
|
||||
|
||||
def test_agentops_exporter_tolerates_fetch_failure(monkeypatch, requests_mock, respx_mock):
|
||||
from opentelemetry.sdk.trace.export import SpanExportResult
|
||||
|
||||
monkeypatch.setenv("OTEL_EXPORTER_OTLP_TRACES_HEADERS", "Authorization=Bearer%20operator,x-operator-key=operator-secret")
|
||||
auth = respx_mock.post(agentops_mod._AGENTOPS_AUTH_ENDPOINT).respond(503, text="auth down")
|
||||
collector = requests_mock.post(_AGENTOPS_ENDPOINT, status_code=200)
|
||||
exporter = _build_agentops_exporter(
|
||||
ExporterSpec(kind=_AGENTOPS_EXPORTER_KIND, endpoint=_AGENTOPS_ENDPOINT, options={"api_key": "ak"})
|
||||
spec = ExporterSpec(
|
||||
kind=_AGENTOPS_EXPORTER_KIND,
|
||||
endpoint=_AGENTOPS_ENDPOINT,
|
||||
options={"api_key": "ak"},
|
||||
)
|
||||
try:
|
||||
assert exporter.export([]) is SpanExportResult.SUCCESS
|
||||
assert exporter.export([]) is SpanExportResult.SUCCESS
|
||||
assert auth.call_count == 1
|
||||
assert collector.call_count == 2
|
||||
assert all("Authorization" not in request.headers for request in collector.request_history)
|
||||
assert all("x-operator-key" not in request.headers for request in collector.request_history)
|
||||
finally:
|
||||
exporter.shutdown()
|
||||
exporter = _build_agentops_exporter(spec)
|
||||
|
||||
# No auth header until the first export triggers the (off-loop) fetch.
|
||||
assert "Authorization" not in exporter._session.headers
|
||||
exporter._ensure_authenticated()
|
||||
assert exporter._session.headers["Authorization"] == "Bearer jwt-xyz"
|
||||
|
||||
# Cached: a second resolution does not re-fetch.
|
||||
calls = []
|
||||
monkeypatch.setattr(
|
||||
agentops_mod,
|
||||
"_fetch_agentops_jwt",
|
||||
lambda k: calls.append(k) or {"token": "again"},
|
||||
)
|
||||
exporter._ensure_authenticated()
|
||||
assert calls == []
|
||||
|
||||
|
||||
def test_agentops_exporter_tolerates_fetch_failure(monkeypatch):
|
||||
pytest.importorskip("opentelemetry.exporter.otlp.proto.http.trace_exporter")
|
||||
|
||||
def _raise(_k):
|
||||
raise RuntimeError("auth down")
|
||||
|
||||
monkeypatch.setattr(agentops_mod, "_fetch_agentops_jwt", _raise)
|
||||
exporter = _build_agentops_exporter(
|
||||
ExporterSpec(
|
||||
kind=_AGENTOPS_EXPORTER_KIND,
|
||||
endpoint=_AGENTOPS_ENDPOINT,
|
||||
options={"api_key": "ak"},
|
||||
)
|
||||
)
|
||||
exporter._ensure_authenticated() # must not raise
|
||||
assert "Authorization" not in exporter._session.headers
|
||||
|
||||
|
||||
def test_fetch_jwt_uses_owned_client_not_shared_pool(monkeypatch):
|
||||
|
|
|
|||
|
|
@ -591,7 +591,7 @@ class TestLangfuseOtelKeyDynamicConfig:
|
|||
assert logger.construct_dynamic_otel_config(self._dynamic_params(langfuse_secret_key=None)) is None
|
||||
assert logger.construct_dynamic_otel_config(self._dynamic_params(langfuse_public_key=None)) is None
|
||||
|
||||
def test_key_dynamic_params_create_otlp_exporter_without_global_env(self, requests_mock):
|
||||
def test_key_dynamic_params_create_otlp_exporter_without_global_env(self):
|
||||
"""Without global LANGFUSE_* env vars, a request carrying key-scoped Langfuse
|
||||
credentials must get a tracer exporting via OTLP HTTP to that key's host."""
|
||||
from opentelemetry.exporter.otlp.proto.http.trace_exporter import (
|
||||
|
|
@ -617,17 +617,15 @@ class TestLangfuseOtelKeyDynamicConfig:
|
|||
|
||||
exporter = span_processors[0].span_exporter
|
||||
assert isinstance(exporter, OTLPSpanExporter)
|
||||
assert exporter._endpoint == "https://langfuse.example.com/api/public/otel/v1/traces"
|
||||
|
||||
import base64
|
||||
|
||||
expected_auth = base64.b64encode(b"key_public:key_secret").decode()
|
||||
collector = requests_mock.post("https://langfuse.example.com/api/public/otel/v1/traces", status_code=200)
|
||||
with tracer.start_as_current_span("dynamic-credentials"):
|
||||
pass
|
||||
assert provider.force_flush()
|
||||
assert collector.call_count == 1
|
||||
assert collector.last_request.headers["Authorization"] == f"Basic {expected_auth}"
|
||||
assert collector.last_request.headers["x-langfuse-ingestion-version"] == "4"
|
||||
assert exporter._headers == {
|
||||
"Authorization": f"Basic {expected_auth}",
|
||||
"x-langfuse-ingestion-version": "4",
|
||||
}
|
||||
|
||||
def test_key_dynamic_params_reuse_cached_provider(self):
|
||||
with self._clean_env():
|
||||
|
|
@ -646,7 +644,7 @@ class TestLangfuseOtelKeyDynamicConfig:
|
|||
assert tracer is logger.tracer
|
||||
assert logger._tracer_provider_cache == {}
|
||||
|
||||
def test_key_credentials_never_passed_to_debug_logger(self, requests_mock):
|
||||
def test_key_credentials_never_passed_to_debug_logger(self):
|
||||
"""The span-processor debug logs must receive a redacted header value, so the
|
||||
key-scoped Langfuse secret never enters a log record regardless of downstream
|
||||
handler configuration, while the exporter still gets the real header."""
|
||||
|
|
@ -680,12 +678,10 @@ class TestLangfuseOtelKeyDynamicConfig:
|
|||
provider = next(iter(logger._tracer_provider_cache.values())).provider
|
||||
exporter = provider._active_span_processor._span_processors[0].span_exporter
|
||||
assert isinstance(exporter, OTLPSpanExporter)
|
||||
from opentelemetry.sdk.trace.export import SpanExportResult
|
||||
|
||||
collector = requests_mock.post("https://langfuse.example.com/api/public/otel/v1/traces", status_code=200)
|
||||
assert exporter.export([]) is SpanExportResult.SUCCESS
|
||||
assert collector.last_request.headers["Authorization"] == f"Basic {secret}"
|
||||
assert collector.last_request.headers["x-langfuse-ingestion-version"] == "4"
|
||||
assert exporter._headers == {
|
||||
"Authorization": f"Basic {secret}",
|
||||
"x-langfuse-ingestion-version": "4",
|
||||
}
|
||||
|
||||
|
||||
class TestLangfuseOtelResponsesAPI:
|
||||
|
|
|
|||
|
|
@ -12,23 +12,21 @@ import weakref
|
|||
from datetime import datetime, timedelta, timezone
|
||||
from pathlib import Path
|
||||
from types import MappingProxyType
|
||||
from typing import ClassVar, Final
|
||||
from typing import Final
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
# Adds the grandparent directory to sys.path to allow importing project modules
|
||||
from opentelemetry import trace
|
||||
from opentelemetry._logs import LogRecord
|
||||
from opentelemetry._logs.severity import SeverityNumber
|
||||
from opentelemetry.sdk._logs import ReadableLogRecord
|
||||
from opentelemetry.sdk._logs import LogData, LogRecord
|
||||
from opentelemetry.sdk._logs import LoggerProvider as OTLoggerProvider
|
||||
from opentelemetry.sdk._logs.export import InMemoryLogExporter, LogRecordExportResult, SimpleLogRecordProcessor
|
||||
from opentelemetry.sdk._logs.export import InMemoryLogExporter, LogExportResult, SimpleLogRecordProcessor
|
||||
from opentelemetry.sdk.metrics import MeterProvider
|
||||
from opentelemetry.sdk.metrics.export import InMemoryMetricReader, MetricsData
|
||||
from opentelemetry.sdk.resources import Resource
|
||||
from opentelemetry.sdk.trace import ReadableSpan, SpanLimits, TracerProvider
|
||||
from opentelemetry.sdk.trace.export import BatchSpanProcessor, SimpleSpanProcessor, SpanExportResult
|
||||
from opentelemetry.sdk.trace.export import SimpleSpanProcessor, SpanExportResult
|
||||
from opentelemetry.sdk.util.instrumentation import InstrumentationScope
|
||||
from opentelemetry.sdk.trace.export.in_memory_span_exporter import InMemorySpanExporter
|
||||
from parameterized import parameterized
|
||||
|
|
@ -2323,13 +2321,9 @@ def test_otlp_http_log_export_trusts_ssl_cert_file(monkeypatch: pytest.MonkeyPat
|
|||
severity_number=SeverityNumber.INFO,
|
||||
body="tls-export-test",
|
||||
)
|
||||
log_data: Final = ReadableLogRecord(
|
||||
log_record=record,
|
||||
resource=Resource.create({}),
|
||||
instrumentation_scope=InstrumentationScope("tls-export-test"),
|
||||
)
|
||||
log_data: Final = LogData(log_record=record, instrumentation_scope=InstrumentationScope("tls-export-test"))
|
||||
result: Final = exporter.export([log_data])
|
||||
assert result is LogRecordExportResult.SUCCESS, f"log export failed: {result}"
|
||||
assert result is LogExportResult.SUCCESS, f"log export failed: {result}"
|
||||
assert tls_sink.received.get(timeout=5) == "/v1/logs"
|
||||
finally:
|
||||
exporter.shutdown()
|
||||
|
|
@ -6645,7 +6639,7 @@ class TestOpenTelemetryProviderlessCallAttributes(unittest.TestCase):
|
|||
time.sleep(self.POLL_INTERVAL)
|
||||
return None
|
||||
|
||||
def _emitted_log_records(self, semconv_opt_in: str) -> tuple[ReadableLogRecord, ...]:
|
||||
def _emitted_log_records(self, semconv_opt_in: str) -> tuple[LogData, ...]:
|
||||
log_exporter = InMemoryLogExporter()
|
||||
logger_provider = OTLoggerProvider()
|
||||
logger_provider.add_log_record_processor(SimpleLogRecordProcessor(log_exporter))
|
||||
|
|
@ -6719,19 +6713,7 @@ class TestDynamicTracerProviderCache(unittest.TestCase):
|
|||
must be bounded and must shut down whatever it drops (LIT-5437: threads accumulated
|
||||
until pods were OOMKilled)."""
|
||||
|
||||
BSP_THREAD_NAME: ClassVar[str]
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls) -> None:
|
||||
before: Final = frozenset(threading.enumerate())
|
||||
processor: Final = BatchSpanProcessor(InMemorySpanExporter())
|
||||
try:
|
||||
workers: Final = tuple(thread for thread in threading.enumerate() if thread not in before)
|
||||
assert len(workers) == 1
|
||||
assert workers[0].is_alive()
|
||||
cls.BSP_THREAD_NAME = workers[0].name
|
||||
finally:
|
||||
processor.shutdown()
|
||||
BSP_THREAD_NAME = "OtelBatchSpanProcessor"
|
||||
|
||||
def _logger(self, cap=3, exporter="console"):
|
||||
logger = OpenTelemetry(
|
||||
|
|
@ -6769,6 +6751,8 @@ class TestDynamicTracerProviderCache(unittest.TestCase):
|
|||
logger._get_tracer_with_dynamic_headers({"authorization": f"Basic tenant-{i}"})
|
||||
|
||||
self.assertEqual(len(logger._tracer_provider_cache), 3)
|
||||
# Guards the thread-name constant: a rename upstream would make this read 0 and the
|
||||
# bound assertion below would pass while measuring nothing.
|
||||
self.assertGreaterEqual(len(self._live_exporter_threads()), 1)
|
||||
self.assertLessEqual(self._wait_for_exporter_threads(before + 3) - before, 3)
|
||||
|
||||
|
|
@ -6939,8 +6923,8 @@ class TestOpenTelemetryDatabaseSemconvAttributes(unittest.TestCase):
|
|||
database's own metrics.
|
||||
"""
|
||||
|
||||
DSN = "postgresql://TEST_ONLY_USER:TEST_ONLY_PASSWORD@primary-db.example.invalid:6432/TEST_ONLY_DATABASE?schema=reporting"
|
||||
REPLICA_DSN = "postgresql://TEST_ONLY_REPLICA_USER:TEST_ONLY_REPLICA_PASSWORD@replica-db.example.invalid/TEST_ONLY_DATABASE"
|
||||
DSN = "postgresql://llmproxy:dbpassword9090@litellm-prod.abc123.us-east-1.rds.amazonaws.com:6432/litellm?schema=reporting"
|
||||
REPLICA_DSN = "postgresql://reader:r3ad0nly@litellm-prod-ro.abc123.us-east-1.rds.amazonaws.com/litellm"
|
||||
|
||||
def _service_span(self, service, call_type, dsn, error=None, replica_dsn=None):
|
||||
exporter = InMemorySpanExporter()
|
||||
|
|
@ -6981,10 +6965,10 @@ class TestOpenTelemetryDatabaseSemconvAttributes(unittest.TestCase):
|
|||
self.assertEqual(span.attributes["db.operation.name"], "get_data")
|
||||
self.assertEqual(
|
||||
span.attributes["server.address"],
|
||||
"primary-db.example.invalid",
|
||||
"litellm-prod.abc123.us-east-1.rds.amazonaws.com",
|
||||
)
|
||||
self.assertEqual(span.attributes["server.port"], 6432)
|
||||
self.assertEqual(span.attributes["db.namespace"], "TEST_ONLY_DATABASE|reporting")
|
||||
self.assertEqual(span.attributes["db.namespace"], "litellm|reporting")
|
||||
|
||||
def test_datastore_span_is_a_client_span_carrying_the_legacy_db_system(self):
|
||||
"""Datadog types a span as a database call from CLIENT kind plus
|
||||
|
|
@ -7010,16 +6994,16 @@ class TestOpenTelemetryDatabaseSemconvAttributes(unittest.TestCase):
|
|||
self.assertEqual(span.kind, trace.SpanKind.CLIENT)
|
||||
self.assertEqual(
|
||||
span.attributes["server.address"],
|
||||
"primary-db.example.invalid",
|
||||
"litellm-prod.abc123.us-east-1.rds.amazonaws.com",
|
||||
)
|
||||
self.assertEqual(span.attributes["error"], "connection refused")
|
||||
|
||||
def test_no_credential_from_the_dsn_lands_on_the_span(self):
|
||||
span = self._service_span(ServiceTypes.DB, "get_data", self.DSN)
|
||||
exported = " ".join(str(value) for value in span.attributes.values())
|
||||
self.assertIn("primary-db.example.invalid", exported)
|
||||
self.assertNotIn("TEST_ONLY_PASSWORD", exported)
|
||||
self.assertNotIn("TEST_ONLY_USER", exported)
|
||||
self.assertIn("litellm-prod.abc123.us-east-1.rds.amazonaws.com", exported)
|
||||
self.assertNotIn("dbpassword9090", exported)
|
||||
self.assertNotIn("llmproxy", exported)
|
||||
|
||||
def test_redis_span_does_not_borrow_the_postgres_endpoint(self):
|
||||
span = self._service_span(ServiceTypes.REDIS, "async_set_cache", self.DSN)
|
||||
|
|
|
|||
|
|
@ -2043,7 +2043,7 @@ async def test_logfire_logger_accepts_env_vars_for_base_url(monkeypatch):
|
|||
],
|
||||
)
|
||||
def test_langtrace_callback_exports_to_api_trace_with_x_api_key(
|
||||
monkeypatch: pytest.MonkeyPatch, api_host: str | None, expected_endpoint: str, requests_mock
|
||||
monkeypatch: pytest.MonkeyPatch, api_host: str | None, expected_endpoint: str
|
||||
) -> None:
|
||||
"""The exporter must post to Langtrace's complete /api/trace path with the key in x-api-key,
|
||||
without leaking it into the process-wide OTEL_EXPORTER_OTLP_TRACES_HEADERS."""
|
||||
|
|
@ -2069,12 +2069,8 @@ def test_langtrace_callback_exports_to_api_trace_with_x_api_key(
|
|||
assert type(logger) is OpenTelemetry and logger.callback_name == "langtrace"
|
||||
exporter: Final = logger._get_span_processor().span_exporter
|
||||
assert isinstance(exporter, OTLPSpanExporter)
|
||||
from opentelemetry.sdk.trace.export import SpanExportResult
|
||||
|
||||
collector: Final = requests_mock.post(expected_endpoint, status_code=200)
|
||||
assert exporter.export([]) is SpanExportResult.SUCCESS
|
||||
assert collector.call_count == 1
|
||||
assert collector.last_request.headers["x-api-key"] == api_key
|
||||
assert exporter._endpoint == expected_endpoint
|
||||
assert exporter._headers == {"x-api-key": api_key}
|
||||
assert "OTEL_EXPORTER_OTLP_TRACES_HEADERS" not in os.environ
|
||||
finally:
|
||||
logging_module._in_memory_loggers.clear()
|
||||
|
|
@ -8023,14 +8019,14 @@ def test_payload_without_guardrail_cost_is_unchanged(logging_obj):
|
|||
assert payload["cost_breakdown"] is None
|
||||
|
||||
|
||||
_AWS_SECRET = "TEST_ONLY_AWS_SECRET_NOT_A_CREDENTIAL"
|
||||
_GEMINI_KEY = "TEST_ONLY_GEMINI_KEY_NOT_A_CREDENTIAL"
|
||||
_AWS_SECRET = "wJalrXUtnFEMIK7MDENGbPxRfiCYEXAMPLEKEY"
|
||||
_GEMINI_KEY = "AIzaSyC0000000000000000000000000000000"
|
||||
|
||||
|
||||
def test_empty_api_base_does_not_dump_call_state(logging_obj):
|
||||
"""Direct (non-HTTP) providers pass api_base='', which used to echo model_call_details."""
|
||||
logging_obj.model_call_details["litellm_params"] = {
|
||||
"api_key": "sk-TEST_ONLY_API_KEY_NOT_A_CREDENTIAL",
|
||||
"api_key": "sk-proj-hunter2hunter2hunter2hunter2",
|
||||
"aws_secret_access_key": _AWS_SECRET,
|
||||
}
|
||||
|
||||
|
|
@ -8043,7 +8039,7 @@ def test_empty_api_base_does_not_dump_call_state(logging_obj):
|
|||
|
||||
assert "litellm_call_id" not in curl_command
|
||||
assert _AWS_SECRET not in curl_command
|
||||
assert "sk-TEST_ONLY_API_KEY_NOT_A_CREDENTIAL" not in curl_command
|
||||
assert "hunter2" not in curl_command
|
||||
|
||||
|
||||
def test_pre_call_redacts_and_masks_raw_request(logging_obj):
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import os
|
|||
import socket
|
||||
import stat
|
||||
from pathlib import Path
|
||||
from typing import Dict, Final, List, Optional
|
||||
from typing import Dict, List, Optional
|
||||
|
||||
import pytest
|
||||
from opentelemetry.sdk.metrics import MeterProvider
|
||||
|
|
@ -350,30 +350,19 @@ def _fake_exporter_class(captured: Dict[str, object]) -> type:
|
|||
return _FakeExporter
|
||||
|
||||
|
||||
@pytest.mark.parametrize("requests_ca", ("REQUESTS_CA_BUNDLE", "CURL_CA_BUNDLE"))
|
||||
def test_meter_provider_preserves_explicit_tls_settings(tmp_path, monkeypatch, requests_mock, requests_ca: str) -> None:
|
||||
monkeypatch.delenv("REQUESTS_CA_BUNDLE", raising=False)
|
||||
monkeypatch.delenv("CURL_CA_BUNDLE", raising=False)
|
||||
monkeypatch.setenv(requests_ca, "/corporate/global-ca.pem")
|
||||
monkeypatch.setenv("OTEL_EXPORTER_OTLP_METRICS_CERTIFICATE", "/operator/collector-ca.pem")
|
||||
monkeypatch.setenv("OTEL_EXPORTER_OTLP_METRICS_CLIENT_CERTIFICATE", "/operator/client.pem")
|
||||
monkeypatch.setenv("OTEL_EXPORTER_OTLP_METRICS_CLIENT_KEY", "/operator/client.key")
|
||||
monkeypatch.setenv("HTTPS_PROXY", "http://proxy.example.invalid:8080")
|
||||
captured: Final = requests_mock.post("https://collector.example:4317/v1/metrics", content=b"")
|
||||
config: Final = _config(tmp_path)
|
||||
provider: Final = bm.build_mtls_meter_provider(config)
|
||||
try:
|
||||
bm.BillingMetricsRecorder(provider).record(
|
||||
category=BillableCategory.LLM, route="/chat/completions", status_code=200, model_id=None
|
||||
)
|
||||
assert provider.force_flush()
|
||||
assert captured.request_history
|
||||
for request in captured.request_history:
|
||||
assert request.verify == config.ca_cert_path
|
||||
assert request.cert == (config.client_cert_path, config.client_key_path)
|
||||
assert request.proxies["https"] == "http://proxy.example.invalid:8080"
|
||||
finally:
|
||||
provider.shutdown()
|
||||
def test_meter_provider_wires_client_cert_into_http_exporter(tmp_path, monkeypatch):
|
||||
"""Client cert+key authenticate us at the collector's mTLS front end; CA override rides certificate_file."""
|
||||
captured: Dict[str, object] = {}
|
||||
|
||||
monkeypatch.setattr(bm, "OTLPMetricExporter", _fake_exporter_class(captured))
|
||||
config = _config(tmp_path)
|
||||
provider = bm.build_mtls_meter_provider(config)
|
||||
provider.shutdown()
|
||||
|
||||
assert captured["endpoint"] == "https://collector.example:4317/v1/metrics"
|
||||
assert captured["client_certificate_file"] == config.client_cert_path
|
||||
assert captured["client_key_file"] == config.client_key_path
|
||||
assert captured["certificate_file"] == config.ca_cert_path
|
||||
|
||||
|
||||
def test_load_config_without_ca_is_valid(monkeypatch, tmp_path):
|
||||
|
|
|
|||
210
ui/litellm-dashboard/package-lock.json
generated
210
ui/litellm-dashboard/package-lock.json
generated
|
|
@ -29,7 +29,7 @@
|
|||
"jwt-decode": "4.0.0",
|
||||
"lucide-react": "0.513.0",
|
||||
"moment": "2.31.0",
|
||||
"next": "16.4.1",
|
||||
"next": "16.3.8",
|
||||
"next-themes": "^0.4.6",
|
||||
"nuqs": "^2.9.4",
|
||||
"openai": "6.49.0",
|
||||
|
|
@ -71,8 +71,8 @@
|
|||
"@types/react-copy-to-clipboard": "5.0.7",
|
||||
"@types/react-dom": "19.2.4",
|
||||
"@types/react-syntax-highlighter": "15.5.13",
|
||||
"@vitest/coverage-v8": "4.1.12",
|
||||
"@vitest/ui": "4.1.12",
|
||||
"@vitest/coverage-v8": "4.1.11",
|
||||
"@vitest/ui": "4.1.11",
|
||||
"eslint": "9.39.2",
|
||||
"eslint-config-next": "16.3.3",
|
||||
"eslint-config-prettier": "10.1.8",
|
||||
|
|
@ -89,7 +89,7 @@
|
|||
"typescript": "5.9.3",
|
||||
"typescript-eslint": "8.60.1",
|
||||
"vite": "7.3.7",
|
||||
"vitest": "4.1.12"
|
||||
"vitest": "4.1.11"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=24.14.1",
|
||||
|
|
@ -2155,9 +2155,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@next/env": {
|
||||
"version": "16.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@next/env/-/env-16.4.1.tgz",
|
||||
"integrity": "sha512-5sUUrrSvs/2/2LnLoesybMGx12EtPB46fdZ6RhAw0XDGSPxU2LFyQBB7yuEiOFFJPKmBY6+q2jTr1/AMbnp0/g==",
|
||||
"version": "16.3.8",
|
||||
"resolved": "https://registry.npmjs.org/@next/env/-/env-16.3.8.tgz",
|
||||
"integrity": "sha512-Al9zqHVV7TJv0eFuOU4U7Lvv74PTih4Ch63sk2xCIpSTkE3udFnaOcnzP2lQVymiL7yS9Cj2iClUXlR3EQ5sEw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@next/eslint-plugin-next": {
|
||||
|
|
@ -2172,9 +2172,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@next/swc-darwin-arm64": {
|
||||
"version": "16.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.4.1.tgz",
|
||||
"integrity": "sha512-U+hQ5Gj3fpzf4fveTIF3dpUFYhaSW8vHhdAnbiIomzXzg7boreYFgBqprepXFtW4sw+aTttiNmg0gew/iFNhbg==",
|
||||
"version": "16.3.8",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.3.8.tgz",
|
||||
"integrity": "sha512-2JPRMh2nmQG5CiL7cXGL9AGwnPWJQ//cTtAUCT+w511QHk79SYz3LGv/pc5X643B/WEO0rvu3Yww0hqwt3kgeA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
|
@ -2188,9 +2188,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@next/swc-darwin-x64": {
|
||||
"version": "16.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.4.1.tgz",
|
||||
"integrity": "sha512-/hqC3V1XLUjhMASf/WridKdO9FXoEgN3HBWmtKbj00MPgnltutfraWJ3bYTpCRIgEIpbjJyOVLpYgAhh/BkdcQ==",
|
||||
"version": "16.3.8",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.3.8.tgz",
|
||||
"integrity": "sha512-GZtCCOBKJ4leVIT/Th0llWKhD1ca92lzbQiS5R5ON9QkoiFnilFsebDae1JU2a3HWoKMEmEZWGs1AGLavVM72Q==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
|
@ -2204,12 +2204,15 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-arm64-gnu": {
|
||||
"version": "16.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.4.1.tgz",
|
||||
"integrity": "sha512-GHzncHbcaS9g95kcvTNtKQW3aCLoR+xc3Jm7qrkpk1R+D2BjMHIPyvQGRPKCdMX95BsH/421jBUK06q9tEwzjw==",
|
||||
"version": "16.3.8",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.3.8.tgz",
|
||||
"integrity": "sha512-O659ygeQYqneJ1fBKMpFxIFqYkYswu8IAS1OCKK/4f3ZgJJm1dRz4fVJZRi/kLLWjnBKnebOePA4WNv+sV1pVA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
|
|
@ -2220,12 +2223,15 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-arm64-musl": {
|
||||
"version": "16.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.4.1.tgz",
|
||||
"integrity": "sha512-1SuJyDxW/PR9dHJat/ZRgcYLhuSZ+1psP4DlKb2tKIuXbjygqpLrJWRSq+onZQBv8LcmU67EIrmb6c3XTaJLjw==",
|
||||
"version": "16.3.8",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.3.8.tgz",
|
||||
"integrity": "sha512-dSjKSyWpzxoO1d3DIZZcP4XJcNaKeLmxQMFOiYl5vuBRMmweIqnAhty8tAmRsvTss779cK1FtYnDMj40e4TQlg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
|
|
@ -2236,12 +2242,15 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-x64-gnu": {
|
||||
"version": "16.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.4.1.tgz",
|
||||
"integrity": "sha512-Istng1hMGp9TGO4lUqeKLd70MPN/OOkucVTP2Nmj+gLkwBgmPqUw8CJYBCC7nbl/B/23bBCcjCI5Hsh6hazC1A==",
|
||||
"version": "16.3.8",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.3.8.tgz",
|
||||
"integrity": "sha512-lbqOuz3RPRcv+o9msNsJw5x4+Y1ZwPTs6vmL6DCf7i0fZfvng/F59wyeDwqHIvV0mK//RBy/jJkZ+nCKsSMXjQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"libc": [
|
||||
"glibc"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
|
|
@ -2252,12 +2261,15 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-x64-musl": {
|
||||
"version": "16.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.4.1.tgz",
|
||||
"integrity": "sha512-aSC9wMNiZRRFVpPkPWBzRwLQxIGm/CiQcXyFF1XNcgodb+uMxdk7aSSGGpDXCbnvZdf4itjHxpOd5h7i7zaiYw==",
|
||||
"version": "16.3.8",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.3.8.tgz",
|
||||
"integrity": "sha512-+316WswI8ScVgZeUd+1KGaXkHhaYQzCjvH/05TZSpJ8zBizb1a4G7DtO7F12jcBIqMOtsz9ji1t48fmKtzqsGA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"libc": [
|
||||
"musl"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
|
|
@ -2268,9 +2280,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@next/swc-win32-arm64-msvc": {
|
||||
"version": "16.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.4.1.tgz",
|
||||
"integrity": "sha512-t/myvwFDlypMUjRvbBf8qLPyuaB0iXYYdBtwMt6DM6f+60wtGr4bSYholdPqNeV5VUXZhrpMwfza829kmhS3iA==",
|
||||
"version": "16.3.8",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.3.8.tgz",
|
||||
"integrity": "sha512-ji0gd4kMYUxO+1fJBIbiBVRCjzG/lloiyCccnlebvb1ZJ5qXCPZqYg4Jl1DrrixnWNMKylzgpmMWx0yNDYXlzw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
|
|
@ -2284,9 +2296,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@next/swc-win32-x64-msvc": {
|
||||
"version": "16.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.4.1.tgz",
|
||||
"integrity": "sha512-6ICqPo9awCkrtYNPhwkx1uU7rlFWrZRrIboDHS2LU+jv088UBYQtmJ25h6pCp27/+FZjF6BQ4Te4ErugyMeuBg==",
|
||||
"version": "16.3.8",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.3.8.tgz",
|
||||
"integrity": "sha512-WcTlaKt/TWkh5kUjdJcUmB1XgZ+1c6fz4Y9fDHL73YNSdGaUWjceeWrrlwF0nv19iABYWC4iAq1oX1w4Bn0vfg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
|
|
@ -4480,14 +4492,14 @@
|
|||
]
|
||||
},
|
||||
"node_modules/@vitest/coverage-v8": {
|
||||
"version": "4.1.12",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.12.tgz",
|
||||
"integrity": "sha512-6S7/iVknKglLAxMFxQGNppBI0iqJS2NgM6FBxavitj7KaDq/vywOWGf6dGu7F2L1Qy0G6S3uTp7aGshHrzK8JA==",
|
||||
"version": "4.1.11",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.11.tgz",
|
||||
"integrity": "sha512-8MVGEFnJIcdGjcbfKmeq8z0pZHH0JlVtoVZH9Q/qwUp6wyFnEJUBMrw9DCaj+ra3vShGmhavjalMIhPNxZAUcw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@bcoe/v8-coverage": "^1.0.2",
|
||||
"@vitest/utils": "4.1.12",
|
||||
"@vitest/utils": "4.1.11",
|
||||
"ast-v8-to-istanbul": "^1.0.0",
|
||||
"istanbul-lib-coverage": "^3.2.2",
|
||||
"istanbul-lib-report": "^3.0.1",
|
||||
|
|
@ -4501,8 +4513,8 @@
|
|||
"url": "https://opencollective.com/vitest"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@vitest/browser": "4.1.12",
|
||||
"vitest": "4.1.12"
|
||||
"@vitest/browser": "4.1.11",
|
||||
"vitest": "4.1.11"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@vitest/browser": {
|
||||
|
|
@ -4511,16 +4523,16 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@vitest/expect": {
|
||||
"version": "4.1.12",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.12.tgz",
|
||||
"integrity": "sha512-vFlTt+YEu9WBpNjdGayNmlMVzrWPi1+sv853/7t2FU7hpO5gAFBKHzQmkCq5Xjpr+evegF2994LQT3hF3mRlqQ==",
|
||||
"version": "4.1.11",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.11.tgz",
|
||||
"integrity": "sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@standard-schema/spec": "^1.1.0",
|
||||
"@types/chai": "^5.2.2",
|
||||
"@vitest/spy": "4.1.12",
|
||||
"@vitest/utils": "4.1.12",
|
||||
"@vitest/spy": "4.1.11",
|
||||
"@vitest/utils": "4.1.11",
|
||||
"chai": "^6.2.2",
|
||||
"tinyrainbow": "^3.1.0"
|
||||
},
|
||||
|
|
@ -4529,13 +4541,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@vitest/mocker": {
|
||||
"version": "4.1.12",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.12.tgz",
|
||||
"integrity": "sha512-fKShNpKZzupWZuY0z7egydvL0sqW4INEZBEExMBMAa6izlENEVHwoXgdaTCaBZ5fwlr4xf2o1wXC83n9RpO+NA==",
|
||||
"version": "4.1.11",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.11.tgz",
|
||||
"integrity": "sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/spy": "4.1.12",
|
||||
"@vitest/spy": "4.1.11",
|
||||
"estree-walker": "^3.0.3",
|
||||
"magic-string": "^0.30.21"
|
||||
},
|
||||
|
|
@ -4556,9 +4568,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@vitest/pretty-format": {
|
||||
"version": "4.1.12",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.12.tgz",
|
||||
"integrity": "sha512-XW9O8+Mxx4VpCtkYdMJLZQQwsVryP9wk7cPKDxtXFfwSak6yRh5+2fep/Y0XF/ElBvJHq8bcYdi6aeuai0opZA==",
|
||||
"version": "4.1.11",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.11.tgz",
|
||||
"integrity": "sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
|
@ -4569,13 +4581,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@vitest/runner": {
|
||||
"version": "4.1.12",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.12.tgz",
|
||||
"integrity": "sha512-NKlVKCr5QnCe8jijdMnmkpHHU+WTqiLFR6G0pHji9uRjXK9xJl1k1nTw6F3pOOj2PDcsDt2GKQMI7wIsaT491w==",
|
||||
"version": "4.1.11",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.11.tgz",
|
||||
"integrity": "sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/utils": "4.1.12",
|
||||
"@vitest/utils": "4.1.11",
|
||||
"pathe": "^2.0.3"
|
||||
},
|
||||
"funding": {
|
||||
|
|
@ -4583,14 +4595,14 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@vitest/snapshot": {
|
||||
"version": "4.1.12",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.12.tgz",
|
||||
"integrity": "sha512-ko1y1Qgb/slzQ9mr+b89Cuqud8WG1TKtsPD8r7ZUBdvVOGt85Af2HwCqHujrhwJq95hs/9RM7fcAPg57o1vlzw==",
|
||||
"version": "4.1.11",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.11.tgz",
|
||||
"integrity": "sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/pretty-format": "4.1.12",
|
||||
"@vitest/utils": "4.1.12",
|
||||
"@vitest/pretty-format": "4.1.11",
|
||||
"@vitest/utils": "4.1.11",
|
||||
"magic-string": "^0.30.21",
|
||||
"pathe": "^2.0.3"
|
||||
},
|
||||
|
|
@ -4599,9 +4611,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@vitest/spy": {
|
||||
"version": "4.1.12",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.12.tgz",
|
||||
"integrity": "sha512-RGq9x4JNGNTZHEJxvN0oSiJjeSCExm0n2gZKKJZHY9cX5AVA6M7VJILBT3ZJ/tJ/0J9uWT7fETV9/btoi//vSg==",
|
||||
"version": "4.1.11",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.11.tgz",
|
||||
"integrity": "sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
|
|
@ -4609,13 +4621,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@vitest/ui": {
|
||||
"version": "4.1.12",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-4.1.12.tgz",
|
||||
"integrity": "sha512-eYUTHtsp52Fu6YGUw9T9173bba7YUr9j/Xj9CdhUaOb8AppLKcknHUaiZQeqJ8MiJ8C2VyKiZuUGSKdvPIKQKA==",
|
||||
"version": "4.1.11",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/ui/-/ui-4.1.11.tgz",
|
||||
"integrity": "sha512-r/rwyKoev21mWdRGSEkZOqkQ2BYy68mwjihg9M90nNRbf4NGrgzZ4cj6JNCEwlOGJkbKeMgsjlykvwKUbRr7gw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/utils": "4.1.12",
|
||||
"@vitest/utils": "4.1.11",
|
||||
"fflate": "^0.8.2",
|
||||
"flatted": "^3.4.2",
|
||||
"pathe": "^2.0.3",
|
||||
|
|
@ -4627,17 +4639,17 @@
|
|||
"url": "https://opencollective.com/vitest"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vitest": "4.1.12"
|
||||
"vitest": "4.1.11"
|
||||
}
|
||||
},
|
||||
"node_modules/@vitest/utils": {
|
||||
"version": "4.1.12",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.12.tgz",
|
||||
"integrity": "sha512-Q3awXrwOfEV+qc3WmO5ONyE0yO7Q1gQ9/oyHxGLZ/pl7N3NO/ZztqQwKLuwMkV+CA1JYSIeO3gkHnRDIo4AVaA==",
|
||||
"version": "4.1.11",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.11.tgz",
|
||||
"integrity": "sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/pretty-format": "4.1.12",
|
||||
"@vitest/pretty-format": "4.1.11",
|
||||
"convert-source-map": "^2.0.0",
|
||||
"tinyrainbow": "^3.1.0"
|
||||
},
|
||||
|
|
@ -9737,12 +9749,12 @@
|
|||
"license": "MIT"
|
||||
},
|
||||
"node_modules/next": {
|
||||
"version": "16.4.1",
|
||||
"resolved": "https://registry.npmjs.org/next/-/next-16.4.1.tgz",
|
||||
"integrity": "sha512-uc657V62E34fOI6W5NtG9IzwsPcms0Z60grz2MJGtglgD+pTFnNt4Yw2PzaU622tfX4vhrDgLZzicE2YlhI20Q==",
|
||||
"version": "16.3.8",
|
||||
"resolved": "https://registry.npmjs.org/next/-/next-16.3.8.tgz",
|
||||
"integrity": "sha512-U7QEZaTini6wKrb8A8hqLLqYQyCetegKjCpJOyxk642vWoMoU1x5PyZCJFvgYgiptA8xc5j/9xYlZFO7w9Sjmw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@next/env": "16.4.1",
|
||||
"@next/env": "16.3.8",
|
||||
"@swc/helpers": "0.5.23",
|
||||
"baseline-browser-mapping": "^2.9.19",
|
||||
"caniuse-lite": "^1.0.30001579",
|
||||
|
|
@ -9756,15 +9768,15 @@
|
|||
"node": ">=20.9.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@next/swc-darwin-arm64": "16.4.1",
|
||||
"@next/swc-darwin-x64": "16.4.1",
|
||||
"@next/swc-linux-arm64-gnu": "16.4.1",
|
||||
"@next/swc-linux-arm64-musl": "16.4.1",
|
||||
"@next/swc-linux-x64-gnu": "16.4.1",
|
||||
"@next/swc-linux-x64-musl": "16.4.1",
|
||||
"@next/swc-win32-arm64-msvc": "16.4.1",
|
||||
"@next/swc-win32-x64-msvc": "16.4.1",
|
||||
"sharp": "^0.35.5"
|
||||
"@next/swc-darwin-arm64": "16.3.8",
|
||||
"@next/swc-darwin-x64": "16.3.8",
|
||||
"@next/swc-linux-arm64-gnu": "16.3.8",
|
||||
"@next/swc-linux-arm64-musl": "16.3.8",
|
||||
"@next/swc-linux-x64-gnu": "16.3.8",
|
||||
"@next/swc-linux-x64-musl": "16.3.8",
|
||||
"@next/swc-win32-arm64-msvc": "16.3.8",
|
||||
"@next/swc-win32-x64-msvc": "16.3.8",
|
||||
"sharp": "^0.35.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@opentelemetry/api": "^1.1.0",
|
||||
|
|
@ -12566,19 +12578,19 @@
|
|||
}
|
||||
},
|
||||
"node_modules/vitest": {
|
||||
"version": "4.1.12",
|
||||
"resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.12.tgz",
|
||||
"integrity": "sha512-5eWdz2yb3ajxWF3C8C4TjkXl7FGm3n2E/VlazALrQHzK7nYMSGFnCZto0bbPNl77AwkOZVLk0YnBAejUu0NiWA==",
|
||||
"version": "4.1.11",
|
||||
"resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.11.tgz",
|
||||
"integrity": "sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/expect": "4.1.12",
|
||||
"@vitest/mocker": "4.1.12",
|
||||
"@vitest/pretty-format": "4.1.12",
|
||||
"@vitest/runner": "4.1.12",
|
||||
"@vitest/snapshot": "4.1.12",
|
||||
"@vitest/spy": "4.1.12",
|
||||
"@vitest/utils": "4.1.12",
|
||||
"@vitest/expect": "4.1.11",
|
||||
"@vitest/mocker": "4.1.11",
|
||||
"@vitest/pretty-format": "4.1.11",
|
||||
"@vitest/runner": "4.1.11",
|
||||
"@vitest/snapshot": "4.1.11",
|
||||
"@vitest/spy": "4.1.11",
|
||||
"@vitest/utils": "4.1.11",
|
||||
"es-module-lexer": "^2.0.0",
|
||||
"expect-type": "^1.3.0",
|
||||
"magic-string": "^0.30.21",
|
||||
|
|
@ -12606,12 +12618,12 @@
|
|||
"@edge-runtime/vm": "*",
|
||||
"@opentelemetry/api": "^1.9.0",
|
||||
"@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0",
|
||||
"@vitest/browser-playwright": "4.1.12",
|
||||
"@vitest/browser-preview": "4.1.12",
|
||||
"@vitest/browser-webdriverio": "^4.1.11",
|
||||
"@vitest/coverage-istanbul": "4.1.12",
|
||||
"@vitest/coverage-v8": "4.1.12",
|
||||
"@vitest/ui": "4.1.12",
|
||||
"@vitest/browser-playwright": "4.1.11",
|
||||
"@vitest/browser-preview": "4.1.11",
|
||||
"@vitest/browser-webdriverio": "4.1.11",
|
||||
"@vitest/coverage-istanbul": "4.1.11",
|
||||
"@vitest/coverage-v8": "4.1.11",
|
||||
"@vitest/ui": "4.1.11",
|
||||
"happy-dom": "*",
|
||||
"jsdom": "*",
|
||||
"vite": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
||||
|
|
|
|||
|
|
@ -46,7 +46,7 @@
|
|||
"jwt-decode": "4.0.0",
|
||||
"lucide-react": "0.513.0",
|
||||
"moment": "2.31.0",
|
||||
"next": "16.4.1",
|
||||
"next": "16.3.8",
|
||||
"next-themes": "^0.4.6",
|
||||
"nuqs": "^2.9.4",
|
||||
"openai": "6.49.0",
|
||||
|
|
@ -88,8 +88,8 @@
|
|||
"@types/react-copy-to-clipboard": "5.0.7",
|
||||
"@types/react-dom": "19.2.4",
|
||||
"@types/react-syntax-highlighter": "15.5.13",
|
||||
"@vitest/coverage-v8": "4.1.12",
|
||||
"@vitest/ui": "4.1.12",
|
||||
"@vitest/coverage-v8": "4.1.11",
|
||||
"@vitest/ui": "4.1.11",
|
||||
"eslint": "9.39.2",
|
||||
"eslint-config-next": "16.3.3",
|
||||
"eslint-config-prettier": "10.1.8",
|
||||
|
|
@ -106,7 +106,7 @@
|
|||
"typescript": "5.9.3",
|
||||
"typescript-eslint": "8.60.1",
|
||||
"vite": "7.3.7",
|
||||
"vitest": "4.1.12"
|
||||
"vitest": "4.1.11"
|
||||
},
|
||||
"overrides": {
|
||||
"prismjs": "1.30.0",
|
||||
|
|
@ -119,10 +119,7 @@
|
|||
"axios": "1.13.6",
|
||||
"postcss": "8.5.23",
|
||||
"esbuild": "0.28.1",
|
||||
"sharp": "^0.35.5",
|
||||
"@litellm/lens-ui": {
|
||||
"next": "$next"
|
||||
}
|
||||
"sharp": "^0.35.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=24.14.1",
|
||||
|
|
|
|||
246
uv.lock
generated
246
uv.lock
generated
|
|
@ -2482,14 +2482,14 @@ wheels = [
|
|||
|
||||
[[package]]
|
||||
name = "gitpython"
|
||||
version = "3.2.1"
|
||||
version = "3.1.62"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "gitdb" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c0/ff/fee293f1ec3e1b64db6eb270e00964f29c086d769201474cedb8d1608930/gitpython-3.2.1.tar.gz", hash = "sha256:0f1229ec5c057bdabdeeda8bda4f17bda679ab33dbccc00f24e6a480553c8613", size = 241688, upload-time = "2026-10-14T12:20:20.589Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/e0/db/3ca813cbacb23ab6fe46ff38a9b5ef8e73e970c8051f2ce903aacafe0446/gitpython-3.1.62.tar.gz", hash = "sha256:1791de66309bc0c7cfca40bf8d2e3de7ca091cbf94e6051be1ad0722c61062af", size = 231728, upload-time = "2026-09-07T02:57:21.155Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/6b/50/2a923c4dc02522ff9567f07c67ed1deca6d5fa9474f4708168b8088dfa37/gitpython-3.2.1-py3-none-any.whl", hash = "sha256:d66b0832aa8755c1a84892937282df0befb16c97e5a64aeebd68be9c5e323f53", size = 231548, upload-time = "2026-10-14T12:20:18.844Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/d6/0b/29d7965215f8ef830a7ca1f42997fe13e5693d85e9edb18f938d063ef5f2/gitpython-3.1.62-py3-none-any.whl", hash = "sha256:7002251225e10e29d2e1f49e6532613fe5d5d9f0b6f1f02997a52b38fe56899e", size = 222753, upload-time = "2026-09-07T02:57:19.762Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -2987,11 +2987,11 @@ wheels = [
|
|||
|
||||
[[package]]
|
||||
name = "graphql-core"
|
||||
version = "3.2.13"
|
||||
version = "3.2.8"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/4e/5e/aa0d4e701b50db0bab71b125dd19ddb0f98c638d008d6f7e3d8ce9cbc92e/graphql_core-3.2.13.tar.gz", hash = "sha256:bb81dd266d4ab7b591bd976f1b23639d97776cb9ac1a896b4a93c271e11ed618", size = 577471, upload-time = "2026-09-27T12:22:57.136Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/68/c5/36aa96205c3ecbb3d34c7c24189e4553c7ca2ebc7e1dd07432339b980272/graphql_core-3.2.8.tar.gz", hash = "sha256:015457da5d996c924ddf57a43f4e959b0b94fb695b85ed4c29446e508ed65cf3", size = 513181, upload-time = "2026-03-05T19:55:37.332Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/1f/b4/b52a324b0b297ddc49b8ea31a51d39fae63132f694a267b9381d94e2e0af/graphql_core-3.2.13-py3-none-any.whl", hash = "sha256:b0eb04f2c31556b2310a77c8fb53c74e8b56570f8fea594d89c6ef7827dbb497", size = 268191, upload-time = "2026-09-27T12:22:55.661Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/86/41/cb887d9afc5dabd78feefe6ccbaf83ff423c206a7a1b7aeeac05120b2125/graphql_core-3.2.8-py3-none-any.whl", hash = "sha256:cbee07bee1b3ed5e531723685369039f32ff815ef60166686e0162f540f1520c", size = 207349, upload-time = "2026-03-05T19:55:35.911Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -4727,7 +4727,6 @@ proxy-runtime = [
|
|||
{ name = "mangum" },
|
||||
{ name = "opentelemetry-api" },
|
||||
{ name = "opentelemetry-exporter-otlp" },
|
||||
{ name = "opentelemetry-exporter-otlp-json-http" },
|
||||
{ name = "opentelemetry-instrumentation-fastapi" },
|
||||
{ name = "opentelemetry-sdk" },
|
||||
{ name = "prometheus-client" },
|
||||
|
|
@ -4811,7 +4810,6 @@ dev = [
|
|||
{ name = "openapi-core" },
|
||||
{ name = "opentelemetry-api" },
|
||||
{ name = "opentelemetry-exporter-otlp" },
|
||||
{ name = "opentelemetry-exporter-otlp-json-http" },
|
||||
{ name = "opentelemetry-instrumentation-fastapi" },
|
||||
{ name = "opentelemetry-sdk" },
|
||||
{ name = "parameterized" },
|
||||
|
|
@ -4859,7 +4857,6 @@ proxy-dev = [
|
|||
{ name = "litellm-admin-mcp", marker = "python_full_version >= '3.12'" },
|
||||
{ name = "opentelemetry-api" },
|
||||
{ name = "opentelemetry-exporter-otlp" },
|
||||
{ name = "opentelemetry-exporter-otlp-json-http" },
|
||||
{ name = "opentelemetry-instrumentation-fastapi" },
|
||||
{ name = "opentelemetry-sdk" },
|
||||
{ name = "prisma" },
|
||||
|
|
@ -4933,11 +4930,10 @@ requires-dist = [
|
|||
{ name = "numpydoc", marker = "extra == 'utils'", specifier = ">=1.8.0,<2.0" },
|
||||
{ name = "nvidia-riva-client", marker = "extra == 'stt-nvidia-riva'", specifier = ">=2.15.0" },
|
||||
{ name = "openai", specifier = ">=2.20.0,<4.0.0" },
|
||||
{ name = "opentelemetry-api", marker = "extra == 'proxy-runtime'", specifier = "==1.45.1" },
|
||||
{ name = "opentelemetry-exporter-otlp", marker = "extra == 'proxy-runtime'", specifier = "==1.45.1" },
|
||||
{ name = "opentelemetry-exporter-otlp-json-http", marker = "extra == 'proxy-runtime'", specifier = "==0.66b1" },
|
||||
{ name = "opentelemetry-instrumentation-fastapi", marker = "extra == 'proxy-runtime'", specifier = "==0.66b1" },
|
||||
{ name = "opentelemetry-sdk", marker = "extra == 'proxy-runtime'", specifier = "==1.45.1" },
|
||||
{ name = "opentelemetry-api", marker = "extra == 'proxy-runtime'", specifier = "==1.33.1" },
|
||||
{ name = "opentelemetry-exporter-otlp", marker = "extra == 'proxy-runtime'", specifier = "==1.33.1" },
|
||||
{ name = "opentelemetry-instrumentation-fastapi", marker = "extra == 'proxy-runtime'", specifier = "==0.54b1" },
|
||||
{ name = "opentelemetry-sdk", marker = "extra == 'proxy-runtime'", specifier = "==1.33.1" },
|
||||
{ name = "orjson", marker = "extra == 'proxy'", specifier = ">=3.11.6,<4.0" },
|
||||
{ name = "packaging", specifier = ">=24.0" },
|
||||
{ name = "polars", marker = "extra == 'proxy'", specifier = ">=1.38.1,<2.0" },
|
||||
|
|
@ -4952,7 +4948,7 @@ requires-dist = [
|
|||
{ name = "pydantic-settings", specifier = ">=2.14.1,<3.0" },
|
||||
{ name = "pyjwt", marker = "extra == 'proxy'", specifier = ">=2.13.0,<3.0" },
|
||||
{ name = "pynacl", marker = "extra == 'proxy'", specifier = ">=1.6.2,<2.0" },
|
||||
{ name = "pypdf", marker = "extra == 'proxy-runtime'", specifier = ">=6.21.1,<7.0" },
|
||||
{ name = "pypdf", marker = "extra == 'proxy-runtime'", specifier = ">=6.16.1,<7.0" },
|
||||
{ name = "pyroscope-io", marker = "sys_platform != 'win32' and extra == 'proxy'", specifier = ">=0.8.16,<1.0" },
|
||||
{ name = "python-dotenv", specifier = ">=1.0.0,<2.0" },
|
||||
{ name = "python-multipart", marker = "extra == 'proxy'", specifier = ">=0.0.27,<1.0" },
|
||||
|
|
@ -5008,7 +5004,7 @@ ci = [
|
|||
{ name = "langchain-openai", specifier = "==1.1.14" },
|
||||
{ name = "langgraph", specifier = ">=1.2.4,<1.3.0" },
|
||||
{ name = "langgraph-prebuilt", specifier = ">=1.1.0,<1.3.0" },
|
||||
{ name = "logfire", specifier = "==5.2.0" },
|
||||
{ name = "logfire", specifier = "==4.6.0" },
|
||||
{ name = "lunary", marker = "python_full_version == '3.10.*'", specifier = "==1.4.36" },
|
||||
{ name = "lunary", marker = "python_full_version >= '3.11'", specifier = "==1.4.37" },
|
||||
{ name = "pillow", marker = "python_full_version == '3.10.*'", specifier = "==12.3.0" },
|
||||
|
|
@ -5035,11 +5031,10 @@ dev = [
|
|||
{ name = "mypy", specifier = "==1.20.1" },
|
||||
{ name = "numpy", specifier = ">=1.26.0,<3.0" },
|
||||
{ name = "openapi-core", specifier = "==0.22.0" },
|
||||
{ name = "opentelemetry-api", specifier = "==1.45.1" },
|
||||
{ name = "opentelemetry-exporter-otlp", specifier = "==1.45.1" },
|
||||
{ name = "opentelemetry-exporter-otlp-json-http", specifier = "==0.66b1" },
|
||||
{ name = "opentelemetry-instrumentation-fastapi", specifier = "==0.66b1" },
|
||||
{ name = "opentelemetry-sdk", specifier = "==1.45.1" },
|
||||
{ name = "opentelemetry-api", specifier = "==1.33.1" },
|
||||
{ name = "opentelemetry-exporter-otlp", specifier = "==1.33.1" },
|
||||
{ name = "opentelemetry-instrumentation-fastapi", specifier = "==0.54b1" },
|
||||
{ name = "opentelemetry-sdk", specifier = "==1.33.1" },
|
||||
{ name = "parameterized", specifier = "==0.9.0" },
|
||||
{ name = "psycopg", specifier = "==3.3.3" },
|
||||
{ name = "psycopg-binary", specifier = "==3.3.3" },
|
||||
|
|
@ -5083,11 +5078,10 @@ proxy-dev = [
|
|||
{ name = "backports-zstd", marker = "python_full_version < '3.14'", specifier = "==1.8.0" },
|
||||
{ name = "hypercorn", specifier = "==0.17.3" },
|
||||
{ name = "litellm-admin-mcp", marker = "python_full_version >= '3.12'", url = "https://github.com/BerriAI/liteadmin-mcp/archive/d35ec9c19c117d4c50cc1eccf6ce1296aac25a1a.tar.gz" },
|
||||
{ name = "opentelemetry-api", specifier = "==1.45.1" },
|
||||
{ name = "opentelemetry-exporter-otlp", specifier = "==1.45.1" },
|
||||
{ name = "opentelemetry-exporter-otlp-json-http", specifier = "==0.66b1" },
|
||||
{ name = "opentelemetry-instrumentation-fastapi", specifier = "==0.66b1" },
|
||||
{ name = "opentelemetry-sdk", specifier = "==1.45.1" },
|
||||
{ name = "opentelemetry-api", specifier = "==1.33.1" },
|
||||
{ name = "opentelemetry-exporter-otlp", specifier = "==1.33.1" },
|
||||
{ name = "opentelemetry-instrumentation-fastapi", specifier = "==0.54b1" },
|
||||
{ name = "opentelemetry-sdk", specifier = "==1.33.1" },
|
||||
{ name = "prisma", specifier = "==0.11.0" },
|
||||
{ name = "prometheus-client", specifier = "==0.20.0" },
|
||||
{ name = "sentry-sdk", specifier = "==2.21.0" },
|
||||
|
|
@ -5179,24 +5173,21 @@ wheels = [
|
|||
|
||||
[[package]]
|
||||
name = "logfire"
|
||||
version = "5.2.0"
|
||||
version = "4.6.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "executing" },
|
||||
{ name = "opentelemetry-api" },
|
||||
{ name = "opentelemetry-exporter-otlp-proto-http" },
|
||||
{ name = "opentelemetry-instrumentation" },
|
||||
{ name = "opentelemetry-sdk" },
|
||||
{ name = "opentelemetry-semantic-conventions" },
|
||||
{ name = "protobuf" },
|
||||
{ name = "requests" },
|
||||
{ name = "rich" },
|
||||
{ name = "tomli", marker = "python_full_version < '3.11'" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/56/5a/e6cccc98d30358b8beee47c61c2a1ca66ac7a76a07de9ba333aa5219b9a6/logfire-5.2.0.tar.gz", hash = "sha256:5fb9ddda303759766e86f5704a1ae96f3a0072906d52e21fbaad2e3c3b03f823", size = 1404990, upload-time = "2026-10-13T17:36:30.746Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/19/fa/14cbd976e8ff77290c0c87f93c45029785537ffb84e2f5215416786cda11/logfire-4.6.0.tar.gz", hash = "sha256:974bc8f4efd3aa9df2d0c7b1d53b35dc4612ff5cee2be6c40dd65e5c26eab694", size = 533174, upload-time = "2025-09-10T14:56:42.168Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/73/cb/bfcd484c16eeac8cdeb2defe1a2ee39bb1b4b6e69324b85515e7818eb678/logfire-5.2.0-py3-none-any.whl", hash = "sha256:c73dd02cfe048f2254e803962aa992d7f53217d121f3488e797926c30442342c", size = 495128, upload-time = "2026-10-13T17:36:27.305Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/04/9c/6384dc69601bfba19c1f5909a472b00cc4b5863f411ecf85be308beacf8f/logfire-4.6.0-py3-none-any.whl", hash = "sha256:d322844db7a2f1935976f2852a07e3753489ecc4e83fa288173b05a453bb1cbf", size = 219556, upload-time = "2025-09-10T14:56:37.278Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -6315,144 +6306,81 @@ wheels = [
|
|||
|
||||
[[package]]
|
||||
name = "opentelemetry-api"
|
||||
version = "1.45.1"
|
||||
version = "1.33.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "typing-extensions" },
|
||||
{ name = "deprecated" },
|
||||
{ name = "importlib-metadata" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/2e/02/6e0ae9cc61bd3169d401077b507b3ebc344745171e1051ab430be012dcd9/opentelemetry_api-1.45.1.tar.gz", hash = "sha256:aa38ed19bcc084ba42782a73255b3582283eced7ad6dddbd6695189e69adfb75", size = 72804, upload-time = "2026-10-06T17:32:58.133Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/9a/8d/1f5a45fbcb9a7d87809d460f09dc3399e3fbd31d7f3e14888345e9d29951/opentelemetry_api-1.33.1.tar.gz", hash = "sha256:1c6055fc0a2d3f23a50c7e17e16ef75ad489345fd3df1f8b8af7c0bbf8a109e8", size = 65002, upload-time = "2025-05-16T18:52:41.146Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/1e/41/f7dcf80b81ee8e71c1a2b59f14208bc723edbd89ed027a73b175abf6348e/opentelemetry_api-1.45.1-py3-none-any.whl", hash = "sha256:b31553efa588ae44bc306f863c785c5333a9ecc091248c6ee68b4b6c87fdedfb", size = 60256, upload-time = "2026-10-06T17:32:33.506Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-exporter-http-transport"
|
||||
version = "0.66b1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "opentelemetry-api" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/62/0c/e3ebdb4b507f66afcc905e6885a4946969bd75b45988492643356fbbdc63/opentelemetry_exporter_http_transport-0.66b1.tar.gz", hash = "sha256:443080203bf52586ce0b2ad901e8951c61833eab1aa539ae6f1f16fe9e8e7952", size = 11693, upload-time = "2026-10-06T17:32:59.65Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/04/69/6af86ff66492b481c6a4c05dcfd68beb47ed8ba046440a26a2aac76b95c7/opentelemetry_exporter_http_transport-0.66b1-py3-none-any.whl", hash = "sha256:2f95404bdee7f9d2d529c7de56c7bd86d014d774d8fbf137810e0167f8a492bf", size = 12155, upload-time = "2026-10-06T17:32:35.454Z" },
|
||||
]
|
||||
|
||||
[package.optional-dependencies]
|
||||
requests = [
|
||||
{ name = "requests" },
|
||||
]
|
||||
urllib3 = [
|
||||
{ name = "urllib3" },
|
||||
{ url = "https://files.pythonhosted.org/packages/05/44/4c45a34def3506122ae61ad684139f0bbc4e00c39555d4f7e20e0e001c8a/opentelemetry_api-1.33.1-py3-none-any.whl", hash = "sha256:4db83ebcf7ea93e64637ec6ee6fabee45c5cbe4abd9cf3da95c43828ddb50b83", size = 65771, upload-time = "2025-05-16T18:52:17.419Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-exporter-otlp"
|
||||
version = "1.45.1"
|
||||
version = "1.33.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "opentelemetry-exporter-otlp-proto-grpc" },
|
||||
{ name = "opentelemetry-exporter-otlp-proto-http" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/e3/6f/5a561048ea372894f22f58f70e8478e4cd97d9a4e2d6f014559584a29bc5/opentelemetry_exporter_otlp-1.45.1.tar.gz", hash = "sha256:d0ac35592e77663a9fabf2740b4818c57196b1b764e0c8449d0d7bb2c7b2bc67", size = 6094, upload-time = "2026-10-06T17:33:00.966Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b1/3f/c8ad4f1c3aaadcea2b0f1b4d7970e7b7898c145699769a789f3435143f69/opentelemetry_exporter_otlp-1.33.1.tar.gz", hash = "sha256:4d050311ea9486e3994575aa237e32932aad58330a31fba24fdba5c0d531cf04", size = 6189, upload-time = "2025-05-16T18:52:43.176Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/36/e1/68c28d7da4482ce882a640b2c61405a78284c0a3a17a4db125647189b0b7/opentelemetry_exporter_otlp-1.45.1-py3-none-any.whl", hash = "sha256:ef3910d32b36ccbaf62390189759bd43a8109885e2d50b738ed9c9b255bf5cb5", size = 6730, upload-time = "2026-10-06T17:32:37.236Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-exporter-otlp-common"
|
||||
version = "0.66b1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "opentelemetry-sdk" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/cb/19/41de712173f43057e4532d42ece7d0c6d4210d353e5752433cb14987643f/opentelemetry_exporter_otlp_common-0.66b1.tar.gz", hash = "sha256:6b1403487a2185ac1feb45fd5546fdf8630ce71c36bcefaadf51e2130e9e23f9", size = 14325, upload-time = "2026-10-06T17:33:01.725Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/fc/39/8c23d67665c762aa51840fa06f86e902e8f6f1693bc8d7e3d98cd6e2f753/opentelemetry_exporter_otlp_common-0.66b1-py3-none-any.whl", hash = "sha256:00ff8592c3a7cb729ff3fdc7ffa12372c243bdf2163e80c180994d0c7bd83ee9", size = 12385, upload-time = "2026-10-06T17:32:38.177Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-exporter-otlp-json-common"
|
||||
version = "0.66b1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "opentelemetry-proto-json" },
|
||||
{ name = "opentelemetry-sdk" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ca/27/fd51023a4916ad00ef0c970577e148fba36e3682716d15a1495f74f830fb/opentelemetry_exporter_otlp_json_common-0.66b1.tar.gz", hash = "sha256:d8bd656ee03be5d2f54b533e03e297792c5017501417d132c3c67eb2ac95b3de", size = 24519, upload-time = "2026-10-06T17:33:02.52Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/0f/34/6e7a4794ff9995042c8372af5c7e4e5127aea10dfeec64402fbec93a6d43/opentelemetry_exporter_otlp_json_common-0.66b1-py3-none-any.whl", hash = "sha256:1ae23eb3dfcd756607367c1ff5df2b4120fe481a523e7868b26b61720c558875", size = 14826, upload-time = "2026-10-06T17:32:39.052Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-exporter-otlp-json-http"
|
||||
version = "0.66b1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "opentelemetry-exporter-http-transport", extra = ["urllib3"] },
|
||||
{ name = "opentelemetry-exporter-otlp-common" },
|
||||
{ name = "opentelemetry-exporter-otlp-json-common" },
|
||||
{ name = "opentelemetry-proto-json" },
|
||||
{ name = "opentelemetry-sdk" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/44/30/47c00f9329242b71724df87536613cb21596b41f294cdc37d8b216c5afaa/opentelemetry_exporter_otlp_json_http-0.66b1.tar.gz", hash = "sha256:940ca96fff3509ca06b3ce8733d4818ee022620aa9329cb7025c63e43c2d224d", size = 17583, upload-time = "2026-10-06T17:33:03.868Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e2/2d/469689a34b17ed83d4ddee480db8322246dcffeb95ef5fc5050bb8a16c8c/opentelemetry_exporter_otlp_json_http-0.66b1-py3-none-any.whl", hash = "sha256:4bd7607120fb7cc77aae88d5c7f629c40515d225b3ca5db293d20d091a248156", size = 14523, upload-time = "2026-10-06T17:32:40.837Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4d/32/b9add70dd4e845654fc9fcd1401a705477743880be6c3e62acb1ad0d8662/opentelemetry_exporter_otlp-1.33.1-py3-none-any.whl", hash = "sha256:9bcf1def35b880b55a49e31ebd63910edac14b294fd2ab884953c4deaff5b300", size = 7045, upload-time = "2025-05-16T18:52:21.022Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-exporter-otlp-proto-common"
|
||||
version = "1.45.1"
|
||||
version = "1.33.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "opentelemetry-proto" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c1/8e/65e85e5137991a3c493b11682151d198638a5bc1dd4b4c5f67e013c57d7c/opentelemetry_exporter_otlp_proto_common-1.45.1.tar.gz", hash = "sha256:2e4adcc3a67bcf57804fc49514f0ef64974ca7590aa3491da389852b4a0628f6", size = 18873, upload-time = "2026-10-06T17:33:04.471Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/7a/18/a1ec9dcb6713a48b4bdd10f1c1e4d5d2489d3912b80d2bcc059a9a842836/opentelemetry_exporter_otlp_proto_common-1.33.1.tar.gz", hash = "sha256:c57b3fa2d0595a21c4ed586f74f948d259d9949b58258f11edb398f246bec131", size = 20828, upload-time = "2025-05-16T18:52:43.795Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/84/aa/92f225d353904e7f70b8b3e3c1b02db0cf56f744c2e83c581dc372e78873/opentelemetry_exporter_otlp_proto_common-1.45.1-py3-none-any.whl", hash = "sha256:2f446183ae7047b036226f1d846c41a834b0e8755ad13b51a51dd38952eb466c", size = 15393, upload-time = "2026-10-06T17:32:41.911Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/09/52/9bcb17e2c29c1194a28e521b9d3f2ced09028934c3c52a8205884c94b2df/opentelemetry_exporter_otlp_proto_common-1.33.1-py3-none-any.whl", hash = "sha256:b81c1de1ad349785e601d02715b2d29d6818aed2c809c20219f3d1f20b038c36", size = 18839, upload-time = "2025-05-16T18:52:22.447Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-exporter-otlp-proto-grpc"
|
||||
version = "1.45.1"
|
||||
version = "1.33.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "deprecated" },
|
||||
{ name = "googleapis-common-protos" },
|
||||
{ name = "grpcio" },
|
||||
{ name = "opentelemetry-api" },
|
||||
{ name = "opentelemetry-exporter-otlp-common" },
|
||||
{ name = "opentelemetry-exporter-otlp-proto-common" },
|
||||
{ name = "opentelemetry-proto" },
|
||||
{ name = "opentelemetry-sdk" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d6/00/a82af0be959dc58495740b169c6669a86e0811f6cd353a01eda34d255db3/opentelemetry_exporter_otlp_proto_grpc-1.45.1.tar.gz", hash = "sha256:3b3dcfbfdcb4e35149fcf309972282054b45228f5c10547d0095d6578510a9a0", size = 25997, upload-time = "2026-10-06T17:33:05.114Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d8/5f/75ef5a2a917bd0e6e7b83d3fb04c99236ee958f6352ba3019ea9109ae1a6/opentelemetry_exporter_otlp_proto_grpc-1.33.1.tar.gz", hash = "sha256:345696af8dc19785fac268c8063f3dc3d5e274c774b308c634f39d9c21955728", size = 22556, upload-time = "2025-05-16T18:52:44.76Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/4d/46/2d1da202f1e17c81aae7efcf702898d524b46709e4d3e2bf1f7f8ca8fbc6/opentelemetry_exporter_otlp_proto_grpc-1.45.1-py3-none-any.whl", hash = "sha256:e42ecb789d2fc5d8145e3dadc3e2991c9f18cd166d7c7514e234702540274b76", size = 19492, upload-time = "2026-10-06T17:32:42.838Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ba/ec/6047e230bb6d092c304511315b13893b1c9d9260044dd1228c9d48b6ae0e/opentelemetry_exporter_otlp_proto_grpc-1.33.1-py3-none-any.whl", hash = "sha256:7e8da32c7552b756e75b4f9e9c768a61eb47dee60b6550b37af541858d669ce1", size = 18591, upload-time = "2025-05-16T18:52:23.772Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-exporter-otlp-proto-http"
|
||||
version = "1.45.1"
|
||||
version = "1.33.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "deprecated" },
|
||||
{ name = "googleapis-common-protos" },
|
||||
{ name = "opentelemetry-api" },
|
||||
{ name = "opentelemetry-exporter-http-transport", extra = ["requests"] },
|
||||
{ name = "opentelemetry-exporter-otlp-common" },
|
||||
{ name = "opentelemetry-exporter-otlp-proto-common" },
|
||||
{ name = "opentelemetry-proto" },
|
||||
{ name = "opentelemetry-sdk" },
|
||||
{ name = "requests" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/1b/17/26487707ea4caa97b17e6e4b5fa72133a53512ffa2f5cf7a49ef284b29cb/opentelemetry_exporter_otlp_proto_http-1.45.1.tar.gz", hash = "sha256:45c218405ce3fd879596924b1874bf9a8f6880206d61065c5a912c8e5c297fb7", size = 28839, upload-time = "2026-10-06T17:33:05.713Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/60/48/e4314ac0ed2ad043c07693d08c9c4bf5633857f5b72f2fefc64fd2b114f6/opentelemetry_exporter_otlp_proto_http-1.33.1.tar.gz", hash = "sha256:46622d964a441acb46f463ebdc26929d9dec9efb2e54ef06acdc7305e8593c38", size = 15353, upload-time = "2025-05-16T18:52:45.522Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/aa/1f/517eaa0187ba106a9da97160ce2add3a371812681dc440930b267f714e42/opentelemetry_exporter_otlp_proto_http-1.45.1-py3-none-any.whl", hash = "sha256:24a97cf3753c7fb52fad44a696e452ff371686339e2acf3309e2eda3d0230700", size = 22180, upload-time = "2026-10-06T17:32:43.946Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/63/ba/5a4ad007588016fe37f8d36bf08f325fe684494cc1e88ca8fa064a4c8f57/opentelemetry_exporter_otlp_proto_http-1.33.1-py3-none-any.whl", hash = "sha256:ebd6c523b89a2ecba0549adb92537cc2bf647b4ee61afbbd5a4c6535aa3da7cf", size = 17733, upload-time = "2025-05-16T18:52:25.137Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-instrumentation"
|
||||
version = "0.66b1"
|
||||
version = "0.54b1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "opentelemetry-api" },
|
||||
|
|
@ -6460,9 +6388,9 @@ dependencies = [
|
|||
{ name = "packaging" },
|
||||
{ name = "wrapt" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a5/03/89e47ff8d52a4f83b343e6eb9ef1698ff45357216e5b6b2b21e0da5c5c7d/opentelemetry_instrumentation-0.66b1.tar.gz", hash = "sha256:e79a510f7d87c72d95e964ddb42193a0d9a75668c027d980eab032ea1322a5ce", size = 43308, upload-time = "2026-10-06T17:36:10.703Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c3/fd/5756aea3fdc5651b572d8aef7d94d22a0a36e49c8b12fcb78cb905ba8896/opentelemetry_instrumentation-0.54b1.tar.gz", hash = "sha256:7658bf2ff914b02f246ec14779b66671508125c0e4227361e56b5ebf6cef0aec", size = 28436, upload-time = "2025-05-16T19:03:22.223Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/da/b2/d1413681ff43e13ac9860df27e1226d3199ab0b97b352ceea41abcc660a5/opentelemetry_instrumentation-0.66b1-py3-none-any.whl", hash = "sha256:4c4aa14dc9a24a02325a9d4c42c4d0208dbb1374c2b1b8fe6c9392d59f3e1008", size = 36904, upload-time = "2026-10-06T17:35:11.663Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f4/89/0790abc5d9c4fc74bd3e03cb87afe2c820b1d1a112a723c1163ef32453ee/opentelemetry_instrumentation-0.54b1-py3-none-any.whl", hash = "sha256:a4ae45f4a90c78d7006c51524f57cd5aa1231aef031eae905ee34d5423f5b198", size = 31019, upload-time = "2025-05-16T19:02:15.611Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -6497,7 +6425,7 @@ wheels = [
|
|||
|
||||
[[package]]
|
||||
name = "opentelemetry-instrumentation-asgi"
|
||||
version = "0.66b1"
|
||||
version = "0.54b1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "asgiref" },
|
||||
|
|
@ -6506,9 +6434,9 @@ dependencies = [
|
|||
{ name = "opentelemetry-semantic-conventions" },
|
||||
{ name = "opentelemetry-util-http" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/5a/d9/ff522f5c3e340e9007554923b1a4d2ac451676f8757bafb3d0057f68b5c3/opentelemetry_instrumentation_asgi-0.66b1.tar.gz", hash = "sha256:78cdc5e45e897e16a8dac9d282e8d5bdf9af2d58e1313fa0bdd4a134c6f9dafc", size = 25992, upload-time = "2026-10-06T17:36:14.593Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/20/f7/a3377f9771947f4d3d59c96841d3909274f446c030dbe8e4af871695ddee/opentelemetry_instrumentation_asgi-0.54b1.tar.gz", hash = "sha256:ab4df9776b5f6d56a78413c2e8bbe44c90694c67c844a1297865dc1bd926ed3c", size = 24230, upload-time = "2025-05-16T19:03:30.234Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/67/ea/10ba99110bf3c9fb736af39c96ca8f3668b988cabb6b59309e058c44461c/opentelemetry_instrumentation_asgi-0.66b1-py3-none-any.whl", hash = "sha256:78b3f9bdf0fa38c65935a2ab46d59e0f9de873a51e0c95b0329f106e2ccb5274", size = 15812, upload-time = "2026-10-06T17:35:17.638Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/20/24/7a6f0ae79cae49927f528ecee2db55a5bddd87b550e310ce03451eae7491/opentelemetry_instrumentation_asgi-0.54b1-py3-none-any.whl", hash = "sha256:84674e822b89af563b283a5283c2ebb9ed585d1b80a1c27fb3ac20b562e9f9fc", size = 16338, upload-time = "2025-05-16T19:02:22.808Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -6559,7 +6487,7 @@ wheels = [
|
|||
|
||||
[[package]]
|
||||
name = "opentelemetry-instrumentation-fastapi"
|
||||
version = "0.66b1"
|
||||
version = "0.54b1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "opentelemetry-api" },
|
||||
|
|
@ -6568,9 +6496,9 @@ dependencies = [
|
|||
{ name = "opentelemetry-semantic-conventions" },
|
||||
{ name = "opentelemetry-util-http" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/5d/2a/cd4125b7acbea2ed17f1d31b58c184cb0a79fcb5541ceb4de90ffc6d8c01/opentelemetry_instrumentation_fastapi-0.66b1.tar.gz", hash = "sha256:584cf9d2c4417ff8b2d6ff2bc606bfe13c8b3456018bf94f50f2cf658492505b", size = 26634, upload-time = "2026-10-06T17:36:25.157Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/98/3b/9a262cdc1a4defef0e52afebdde3e8add658cc6f922e39e9dcee0da98349/opentelemetry_instrumentation_fastapi-0.54b1.tar.gz", hash = "sha256:1fcad19cef0db7092339b571a59e6f3045c9b58b7fd4670183f7addc459d78df", size = 19325, upload-time = "2025-05-16T19:03:45.359Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/75/70/676928d537978acc7bff2ac8657bd0836ba608ffc8f65455238f1fa2bd0f/opentelemetry_instrumentation_fastapi-0.66b1-py3-none-any.whl", hash = "sha256:97f8ac8fd7537517f9e6988bd0aca04bfa5aad564bcd46c245530739e2be72d1", size = 14216, upload-time = "2026-10-06T17:35:32.827Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/df/9c/6b2b0f9d6c5dea7528ae0bf4e461dd765b0ae35f13919cd452970bb0d0b3/opentelemetry_instrumentation_fastapi-0.54b1-py3-none-any.whl", hash = "sha256:fb247781cfa75fd09d3d8713c65e4a02bd1e869b00e2c322cc516d4b5429860c", size = 12125, upload-time = "2025-05-16T19:02:41.172Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -6666,16 +6594,15 @@ wheels = [
|
|||
|
||||
[[package]]
|
||||
name = "opentelemetry-instrumentation-logging"
|
||||
version = "0.66b1"
|
||||
version = "0.54b1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "opentelemetry-api" },
|
||||
{ name = "opentelemetry-instrumentation" },
|
||||
{ name = "opentelemetry-semantic-conventions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/28/ca/0fcf525f238f4ab9df3a6d0423fb057085ea39a3e79ac912fef3d5fa16b8/opentelemetry_instrumentation_logging-0.66b1.tar.gz", hash = "sha256:2250240ecb1fce36939f64eafd988832338684564fb4c7b401c9b9af0ee11d46", size = 20353, upload-time = "2026-10-06T17:36:29.546Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d9/5b/88ed39f22e8c6eb4f6192ab9a62adaa115579fcbcadb3f0241ee645eea56/opentelemetry_instrumentation_logging-0.54b1.tar.gz", hash = "sha256:893a3cbfda893b64ff71b81991894e2fd6a9267ba85bb6c251f51c0419fbe8fa", size = 9976, upload-time = "2025-05-16T19:03:49.976Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/2e/7b/76bea1e80787848a9ac9882a598cbf1e761f16cebdb399d0e675221e34a0/opentelemetry_instrumentation_logging-0.66b1-py3-none-any.whl", hash = "sha256:f13761110c52eecae9d7debedb0f88b46acc248c20437e97c2a5b3a2b4f96a02", size = 15928, upload-time = "2026-10-06T17:35:39.915Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/96/0c/b441fb30d860f25040eaed61e89d68f4d9ee31873159ed18cbc1b92eba56/opentelemetry_instrumentation_logging-0.54b1-py3-none-any.whl", hash = "sha256:01a4cec54348f13941707d857b850b0febf9d49f45d0fcf0673866e079d7357b", size = 12579, upload-time = "2025-05-16T19:02:49.039Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -6801,7 +6728,7 @@ wheels = [
|
|||
|
||||
[[package]]
|
||||
name = "opentelemetry-instrumentation-requests"
|
||||
version = "0.66b1"
|
||||
version = "0.54b1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "opentelemetry-api" },
|
||||
|
|
@ -6809,9 +6736,9 @@ dependencies = [
|
|||
{ name = "opentelemetry-semantic-conventions" },
|
||||
{ name = "opentelemetry-util-http" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/08/62/dcca0b7a2008675056040c61b70d37b5a24439613c7822068908ad3255ae/opentelemetry_instrumentation_requests-0.66b1.tar.gz", hash = "sha256:28578f72e68e3a5be3226c618ac9570ed360ef1dd22d5d6e0721c6905a4ccc67", size = 17985, upload-time = "2026-10-06T17:36:37.478Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/e7/45/116da84930d3dc2f5cdd876283ca96e9b96547bccee7eaa0bd01ce6bf046/opentelemetry_instrumentation_requests-0.54b1.tar.gz", hash = "sha256:3eca5d697c5564af04c6a1dd23b6a3ffbaf11e64887c6051655cee03998f4654", size = 15148, upload-time = "2025-05-16T19:04:00.488Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/88/01/98e9bb7fef12784cd19811e454cf25bce4d774fd3e46b3f5fd2bce237075/opentelemetry_instrumentation_requests-0.66b1-py3-none-any.whl", hash = "sha256:7ba17d984a2bd876b88bf0aafcca27b5e3ff4c1821e0fe07641e380a3cf3a3a2", size = 13320, upload-time = "2026-10-06T17:35:52.477Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/2b/b1/6e33d2c3d3cc9e3ae20a9a77625ec81a509a0e5d7fa87e09e7f879468990/opentelemetry_instrumentation_requests-0.54b1-py3-none-any.whl", hash = "sha256:a0c4cd5d946224f336d6bd73cdabdecc6f80d5c39208f84eb96eb15f16cd41a0", size = 12968, upload-time = "2025-05-16T19:03:03.131Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -6831,7 +6758,7 @@ wheels = [
|
|||
|
||||
[[package]]
|
||||
name = "opentelemetry-instrumentation-sqlalchemy"
|
||||
version = "0.66b1"
|
||||
version = "0.54b1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "opentelemetry-api" },
|
||||
|
|
@ -6840,23 +6767,23 @@ dependencies = [
|
|||
{ name = "packaging" },
|
||||
{ name = "wrapt" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/d4/3e/d69fb08dacc4c248daedf7357732ddca7a0aaff7072a55e311d3da3ea51c/opentelemetry_instrumentation_sqlalchemy-0.66b1.tar.gz", hash = "sha256:a10043953fcba71911bf29a024f8cc337260c1ef0b4fc844b96cae0de0947baa", size = 18181, upload-time = "2026-10-06T17:36:38.111Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ac/33/78a25ae4233d42058bb0b363ba4fea7d7210e53c24e5e31f16d5cf6cf957/opentelemetry_instrumentation_sqlalchemy-0.54b1.tar.gz", hash = "sha256:97839acf1c9b96ded857fca57a09b86a56cf8d9eb6d706b7ceaee9352a460e03", size = 14620, upload-time = "2025-05-16T19:04:01.215Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/08/05/f8cff0c68a7f9ab8fab01904be5a49c5214435109c2a6b6d173a974c10d9/opentelemetry_instrumentation_sqlalchemy-0.66b1-py3-none-any.whl", hash = "sha256:aa30b10d880d7e91cf94b23a92ac85cec09ffddd8f0d40256d7c510e3dd33971", size = 14425, upload-time = "2026-10-06T17:35:53.436Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c7/2b/1c954885815614ef5c1e8c7bbf57a5275e64cd6fb5946b65e17162a34037/opentelemetry_instrumentation_sqlalchemy-0.54b1-py3-none-any.whl", hash = "sha256:d2ca5edb4c7ecef120d51aad6793b7da1cc80207ccfd31c437ee18f098e7c4c4", size = 14169, upload-time = "2025-05-16T19:03:04.119Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-instrumentation-threading"
|
||||
version = "0.66b1"
|
||||
version = "0.54b1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "opentelemetry-api" },
|
||||
{ name = "opentelemetry-instrumentation" },
|
||||
{ name = "wrapt" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/55/4f/5fa05266cf24cae93fc32d557d0d2d2f605f81cca1df90614231bbad3cd1/opentelemetry_instrumentation_threading-0.66b1.tar.gz", hash = "sha256:2c217359439d09ca4a4be524db368c05a3cc7f218b85e8086f22664db0a03538", size = 9031, upload-time = "2026-10-06T17:36:41.147Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a0/bd/561245292e7cc78ac7a0a75537873aea87440cb9493d41371421b3308c2b/opentelemetry_instrumentation_threading-0.54b1.tar.gz", hash = "sha256:3a081085b59675baf7bd93126a681903e6304a5f283df5eaecdd44bcb66df578", size = 8774, upload-time = "2025-05-16T19:04:04.482Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/86/da/1cd52b8be7a521958ccdb9a1c4e5ae743aa2be295ba21ec0b620dc87842a/opentelemetry_instrumentation_threading-0.66b1-py3-none-any.whl", hash = "sha256:94039c60603060d26524e31aed1181a5d153e43f58462d110dbeb4830687d7d7", size = 8493, upload-time = "2026-10-06T17:35:57.958Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/81/10/d87ec07d69546adaad525ba5d40d27324a45cba29097d9854a53d9af5047/opentelemetry_instrumentation_threading-0.54b1-py3-none-any.whl", hash = "sha256:bc229e6cd3f2b29fafe0a8dd3141f452e16fcb4906bca4fbf52609f99fb1eb42", size = 9314, upload-time = "2025-05-16T19:03:09.527Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -6891,7 +6818,7 @@ wheels = [
|
|||
|
||||
[[package]]
|
||||
name = "opentelemetry-instrumentation-urllib3"
|
||||
version = "0.66b1"
|
||||
version = "0.54b1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "opentelemetry-api" },
|
||||
|
|
@ -6900,9 +6827,9 @@ dependencies = [
|
|||
{ name = "opentelemetry-util-http" },
|
||||
{ name = "wrapt" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/08/ab/2dd6b3a69df31ae12714bf24fcc2772956d7cb8f9082432c9e63a37e6930/opentelemetry_instrumentation_urllib3-0.66b1.tar.gz", hash = "sha256:31e84a2ccfa86ca1d4f1209ea66c1f709c335348d5c487477d3843172efcc408", size = 18826, upload-time = "2026-10-06T17:36:43.547Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/ed/6f/76a46806cd21002cac1bfd087f5e4674b195ab31ab44c773ca534b6bb546/opentelemetry_instrumentation_urllib3-0.54b1.tar.gz", hash = "sha256:0d30ba3b230e4100cfadaad29174bf7bceac70e812e4f5204e681e4b55a74cd9", size = 15697, upload-time = "2025-05-16T19:04:07.709Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/be/7f/16f82bf359c28fb71ad4dc5ad386cce3483abbf1ce0ade087fe78c18daf3/opentelemetry_instrumentation_urllib3-0.66b1-py3-none-any.whl", hash = "sha256:e48b448fed4a127e54c584c37a443c91d80d34b9f9de324af9a00cead8b338b8", size = 13462, upload-time = "2026-10-06T17:36:02.242Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ff/7a/d75bec41edb6deaf1d2859bab66a84c8ba03e822e7eafdb245da205e53f6/opentelemetry_instrumentation_urllib3-0.54b1-py3-none-any.whl", hash = "sha256:e87958c297ddd36d30e1c9069f34a9690e845e4ccc2662dd80e99ed976d4c03e", size = 13123, upload-time = "2025-05-16T19:03:14.053Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -6952,50 +6879,41 @@ wheels = [
|
|||
|
||||
[[package]]
|
||||
name = "opentelemetry-proto"
|
||||
version = "1.45.1"
|
||||
version = "1.33.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "protobuf" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/4b/7f/15f014fb195da6c2dbb6c71399b8e76824878718e94de6454038488eed28/opentelemetry_proto-1.45.1.tar.gz", hash = "sha256:79e0fb95e4616691a469439238aa9224d75779b3e108e895d1aa125ab29ca77c", size = 46488, upload-time = "2026-10-06T17:33:11.49Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/f6/dc/791f3d60a1ad8235930de23eea735ae1084be1c6f96fdadf38710662a7e5/opentelemetry_proto-1.33.1.tar.gz", hash = "sha256:9627b0a5c90753bf3920c398908307063e4458b287bb890e5c1d6fa11ad50b68", size = 34363, upload-time = "2025-05-16T18:52:52.141Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/ab/9a/42ec8180a769516ae757e893b69736826efceac7332553915b4528a91c6d/opentelemetry_proto-1.45.1-py3-none-any.whl", hash = "sha256:f38e2a8413053c180cd3d2637fbb279673ec2f6a6e09c995aafa2f452c52b46e", size = 72488, upload-time = "2026-10-06T17:32:53.057Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-proto-json"
|
||||
version = "0.66b1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/90/25/a845cc4644123c6b29b2c21822341a55e7f1808703d4f557d24cbd841290/opentelemetry_proto_json-0.66b1.tar.gz", hash = "sha256:92bb70ff0f05815821e922ea628bfdf96f034b981747b0ba8e09db61e1a9cddd", size = 18708, upload-time = "2026-10-06T17:33:12.169Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/93/7d/bb6acc006c6c4042ef9f734f4901630a440992033f48b66a58fc8fd5e3f4/opentelemetry_proto_json-0.66b1-py3-none-any.whl", hash = "sha256:0d07f1922451cf3a8705bb46fa807f478a1164fbe9287bf7bd50e1ff43f75da3", size = 32061, upload-time = "2026-10-06T17:32:54.097Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/c4/29/48609f4c875c2b6c80930073c82dd1cafd36b6782244c01394007b528960/opentelemetry_proto-1.33.1-py3-none-any.whl", hash = "sha256:243d285d9f29663fc7ea91a7171fcc1ccbbfff43b48df0774fd64a37d98eda70", size = 55854, upload-time = "2025-05-16T18:52:36.269Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-sdk"
|
||||
version = "1.45.1"
|
||||
version = "1.33.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "opentelemetry-api" },
|
||||
{ name = "opentelemetry-semantic-conventions" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a1/79/7392e21a1c8f0c61d90b223e31c7e48cb9d452e91a6b820ad24cca5f23c4/opentelemetry_sdk-1.45.1.tar.gz", hash = "sha256:63d24a6ca645019a631e6a51999c73e93adcac1196ca640b8ae78a7cc4762bf3", size = 218324, upload-time = "2026-10-06T17:33:13.26Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/67/12/909b98a7d9b110cce4b28d49b2e311797cffdce180371f35eba13a72dd00/opentelemetry_sdk-1.33.1.tar.gz", hash = "sha256:85b9fcf7c3d23506fbc9692fd210b8b025a1920535feec50bd54ce203d57a531", size = 161885, upload-time = "2025-05-16T18:52:52.832Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/95/3c/87c42b4bd6dd297536f04cd9383d212ac557ecd49f2cbdcd46da1c9ef5c8/opentelemetry_sdk-1.45.1-py3-none-any.whl", hash = "sha256:c604c11dc429810812348989115fa44bd558772a3d7442afc43d024f2c250ca4", size = 140063, upload-time = "2026-10-06T17:32:55.04Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/df/8e/ae2d0742041e0bd7fe0d2dcc5e7cce51dcf7d3961a26072d5b43cc8fa2a7/opentelemetry_sdk-1.33.1-py3-none-any.whl", hash = "sha256:19ea73d9a01be29cacaa5d6c8ce0adc0b7f7b4d58cc52f923e4413609f670112", size = 118950, upload-time = "2025-05-16T18:52:37.297Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "opentelemetry-semantic-conventions"
|
||||
version = "0.66b1"
|
||||
version = "0.54b1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "deprecated" },
|
||||
{ name = "opentelemetry-api" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/46/e4/dbbfb2a010c4db2224a5114638acede6fe563d33cc20fb1752cebcbe6298/opentelemetry_semantic_conventions-0.66b1.tar.gz", hash = "sha256:497ca63bf383723411e8eaf60c8779e9877633c936bb641080adab59d0eb6ec8", size = 150250, upload-time = "2026-10-06T17:33:14.073Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/5b/2c/d7990fc1ffc82889d466e7cd680788ace44a26789809924813b164344393/opentelemetry_semantic_conventions-0.54b1.tar.gz", hash = "sha256:d1cecedae15d19bdaafca1e56b29a66aa286f50b5d08f036a145c7f3e9ef9cee", size = 118642, upload-time = "2025-05-16T18:52:53.962Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/bc/14/67f8aa798857f8cf686f515bf93d9bb877ce952ddc8efae0fa25b45ce0d6/opentelemetry_semantic_conventions-0.66b1-py3-none-any.whl", hash = "sha256:d4cddeb4315490b35213f55e2bdc9ac54bb1e4d318927475bed62b35545e581b", size = 206279, upload-time = "2026-10-06T17:32:56.103Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/0a/80/08b1698c52ff76d96ba440bf15edc2f4bc0a279868778928e947c1004bdd/opentelemetry_semantic_conventions-0.54b1-py3-none-any.whl", hash = "sha256:29dab644a7e435b58d3a3918b58c333c92686236b30f7891d5e51f02933ca60d", size = 194938, upload-time = "2025-05-16T18:52:38.796Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -7009,11 +6927,11 @@ wheels = [
|
|||
|
||||
[[package]]
|
||||
name = "opentelemetry-util-http"
|
||||
version = "0.66b1"
|
||||
version = "0.54b1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/7c/b5/df4b61da899f6ebdffdbdf0c8b0f3189ee57151694ccd5b7d50ee2906241/opentelemetry_util_http-0.66b1.tar.gz", hash = "sha256:047dea1a628031f857a5a32261dc0e955bc162d39993ed1cffb8f2cff5ba8a62", size = 11586, upload-time = "2026-10-06T17:36:46.572Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/a8/9f/1d8a1d1f34b9f62f2b940b388bf07b8167a8067e70870055bd05db354e5c/opentelemetry_util_http-0.54b1.tar.gz", hash = "sha256:f0b66868c19fbaf9c9d4e11f4a7599fa15d5ea50b884967a26ccd9d72c7c9d15", size = 8044, upload-time = "2025-05-16T19:04:10.79Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/eb/9b/c77ecaea79ba0de1a11e7f06a7f5eea7043ec23f1860dcf5f03536698e4c/opentelemetry_util_http-0.66b1-py3-none-any.whl", hash = "sha256:8f443d7abcaf29c4a07b373bbd31b5b39132c0ed3c27d015a59dc0323d5b1c58", size = 8387, upload-time = "2026-10-06T17:36:06.984Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a4/ef/c5aa08abca6894792beed4c0405e85205b35b8e73d653571c9ff13a8e34e/opentelemetry_util_http-0.54b1-py3-none-any.whl", hash = "sha256:b1c91883f980344a1c3c486cffd47ae5c9c1dd7323f9cbe9fdb7cadb401c87c9", size = 7301, upload-time = "2025-05-16T19:03:18.18Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
@ -8239,14 +8157,14 @@ wheels = [
|
|||
|
||||
[[package]]
|
||||
name = "pypdf"
|
||||
version = "6.21.1"
|
||||
version = "6.19.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/51/e1/32a9c4dbd94618145f8bab5c623bdb0a528f23fc8719afd77ba0278fd377/pypdf-6.21.1.tar.gz", hash = "sha256:2d62c383acd6e0dff0a96322ba8b1135229343b084d73c6f6cfd947fd291afcb", size = 7088597, upload-time = "2026-10-17T10:29:52.801Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/1f/ac/63d71aaedb59acbcdef491e6ca6469165e3771c9c74358204818fd9bc5a6/pypdf-6.19.0.tar.gz", hash = "sha256:bbc43aca292369ccc6cbc8a921991ecf2538a3587ab5a116eff06c321d647155", size = 7033266, upload-time = "2026-09-16T09:32:05.946Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/85/e6/24c944e473c34e818cf1b98085796fcd780465ecfe17663f2bf8fee1958b/pypdf-6.21.1-py3-none-any.whl", hash = "sha256:553e2d42f5bb3bb2a785a7d3de8ef90bb7df74b5413eff5a7b4388007ea9254b", size = 405134, upload-time = "2026-10-17T10:29:50.687Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/3c/2c/c43c03eaf630435f023f1dc61ec4a4a78951ad5530a62c71cc89bde307b7/pypdf-6.19.0-py3-none-any.whl", hash = "sha256:7e5d6e730e7dae87d560a2cee218b852f6498c8be61966f3cd02ead971e48d14", size = 395480, upload-time = "2026-09-16T09:32:04.087Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
|
|
|||
90
vscode-extension/package-lock.json
generated
90
vscode-extension/package-lock.json
generated
|
|
@ -17,7 +17,7 @@
|
|||
"@vscode/vsce": "^4.0.0",
|
||||
"esbuild": "^0.28.2",
|
||||
"typescript": "^5.9.3",
|
||||
"vitest": "^4.1.12"
|
||||
"vitest": "^4.1.11"
|
||||
},
|
||||
"engines": {
|
||||
"vscode": "^1.115.0"
|
||||
|
|
@ -1323,16 +1323,16 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@vitest/expect": {
|
||||
"version": "4.1.12",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.12.tgz",
|
||||
"integrity": "sha512-vFlTt+YEu9WBpNjdGayNmlMVzrWPi1+sv853/7t2FU7hpO5gAFBKHzQmkCq5Xjpr+evegF2994LQT3hF3mRlqQ==",
|
||||
"version": "4.1.11",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.11.tgz",
|
||||
"integrity": "sha512-VX2x5vNJXET47KAFzwERI+KRMtTTCSWTfSMKsW7JsUsXV4psq++e3DvZpuTDOpHcxytiDs6p2nhVb2tVDiiUYw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@standard-schema/spec": "^1.1.0",
|
||||
"@types/chai": "^5.2.2",
|
||||
"@vitest/spy": "4.1.12",
|
||||
"@vitest/utils": "4.1.12",
|
||||
"@vitest/spy": "4.1.11",
|
||||
"@vitest/utils": "4.1.11",
|
||||
"chai": "^6.2.2",
|
||||
"tinyrainbow": "^3.1.0"
|
||||
},
|
||||
|
|
@ -1341,13 +1341,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@vitest/mocker": {
|
||||
"version": "4.1.12",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.12.tgz",
|
||||
"integrity": "sha512-fKShNpKZzupWZuY0z7egydvL0sqW4INEZBEExMBMAa6izlENEVHwoXgdaTCaBZ5fwlr4xf2o1wXC83n9RpO+NA==",
|
||||
"version": "4.1.11",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.11.tgz",
|
||||
"integrity": "sha512-2XJVD55d1o5AZous5CCGKS74g/riOj9odEt2bQpCVZeblHyHdnMeFl4jl0XjU21stf4mbjUkew2eXQZt65g5CQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/spy": "4.1.12",
|
||||
"@vitest/spy": "4.1.11",
|
||||
"estree-walker": "^3.0.3",
|
||||
"magic-string": "^0.30.21"
|
||||
},
|
||||
|
|
@ -1368,9 +1368,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@vitest/pretty-format": {
|
||||
"version": "4.1.12",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.12.tgz",
|
||||
"integrity": "sha512-XW9O8+Mxx4VpCtkYdMJLZQQwsVryP9wk7cPKDxtXFfwSak6yRh5+2fep/Y0XF/ElBvJHq8bcYdi6aeuai0opZA==",
|
||||
"version": "4.1.11",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.11.tgz",
|
||||
"integrity": "sha512-yiZzPbGTS9Sr/JpFl8zHrcIkAofNbFV6k21vIgQN/cY/oxZeXhJv5sc/MBJ5jFKWmWs+oJHw0UXLZjmf931+Vw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
|
@ -1381,13 +1381,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@vitest/runner": {
|
||||
"version": "4.1.12",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.12.tgz",
|
||||
"integrity": "sha512-NKlVKCr5QnCe8jijdMnmkpHHU+WTqiLFR6G0pHji9uRjXK9xJl1k1nTw6F3pOOj2PDcsDt2GKQMI7wIsaT491w==",
|
||||
"version": "4.1.11",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.11.tgz",
|
||||
"integrity": "sha512-LztvUgdwMNJMIkj3hQnnxiC2Xy1zNxq928W/xhjCLaNCzqTZOudjwbQf6v9IntZGPw132i2Lq2rgTRZHD3JHNw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/utils": "4.1.12",
|
||||
"@vitest/utils": "4.1.11",
|
||||
"pathe": "^2.0.3"
|
||||
},
|
||||
"funding": {
|
||||
|
|
@ -1395,14 +1395,14 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@vitest/snapshot": {
|
||||
"version": "4.1.12",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.12.tgz",
|
||||
"integrity": "sha512-ko1y1Qgb/slzQ9mr+b89Cuqud8WG1TKtsPD8r7ZUBdvVOGt85Af2HwCqHujrhwJq95hs/9RM7fcAPg57o1vlzw==",
|
||||
"version": "4.1.11",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.11.tgz",
|
||||
"integrity": "sha512-pN7ikn1ON7h8ee4gIAp4AzyK+zBtJPzVbqOgu5LCEh4VaJVbPQcgYQYJIMGQPXVeJJq1fnfazis7a5pFNPahog==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/pretty-format": "4.1.12",
|
||||
"@vitest/utils": "4.1.12",
|
||||
"@vitest/pretty-format": "4.1.11",
|
||||
"@vitest/utils": "4.1.11",
|
||||
"magic-string": "^0.30.21",
|
||||
"pathe": "^2.0.3"
|
||||
},
|
||||
|
|
@ -1411,9 +1411,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@vitest/spy": {
|
||||
"version": "4.1.12",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.12.tgz",
|
||||
"integrity": "sha512-RGq9x4JNGNTZHEJxvN0oSiJjeSCExm0n2gZKKJZHY9cX5AVA6M7VJILBT3ZJ/tJ/0J9uWT7fETV9/btoi//vSg==",
|
||||
"version": "4.1.11",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.11.tgz",
|
||||
"integrity": "sha512-apNa/prQy2qCeywhnixOHPRCgGNhvg7T4Dapfl1GahLp/R+uhBm5cPyFoNVyqsNd2h1nJxL6BqqdIjiABL60YA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
|
|
@ -1421,13 +1421,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@vitest/utils": {
|
||||
"version": "4.1.12",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.12.tgz",
|
||||
"integrity": "sha512-Q3awXrwOfEV+qc3WmO5ONyE0yO7Q1gQ9/oyHxGLZ/pl7N3NO/ZztqQwKLuwMkV+CA1JYSIeO3gkHnRDIo4AVaA==",
|
||||
"version": "4.1.11",
|
||||
"resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.11.tgz",
|
||||
"integrity": "sha512-zTCVGpyFsGWBhllOyKlTw/vnr6D9qxsfSDyfbyZmTyjHw5N/VuvzHpHoQjm2ZJzn4RJgx5w4r7V0er69CmLgPQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/pretty-format": "4.1.12",
|
||||
"@vitest/pretty-format": "4.1.11",
|
||||
"convert-source-map": "^2.0.0",
|
||||
"tinyrainbow": "^3.1.0"
|
||||
},
|
||||
|
|
@ -3390,19 +3390,19 @@
|
|||
}
|
||||
},
|
||||
"node_modules/vitest": {
|
||||
"version": "4.1.12",
|
||||
"resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.12.tgz",
|
||||
"integrity": "sha512-5eWdz2yb3ajxWF3C8C4TjkXl7FGm3n2E/VlazALrQHzK7nYMSGFnCZto0bbPNl77AwkOZVLk0YnBAejUu0NiWA==",
|
||||
"version": "4.1.11",
|
||||
"resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.11.tgz",
|
||||
"integrity": "sha512-fhACrNXUidIbGSBr5FlbuBkO7VWC1ZyLl0DO4CU2DrQoAPxX84Ysxs+HeGQpii5lZWV1Q4gBZTTu49mF+A6Edw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@vitest/expect": "4.1.12",
|
||||
"@vitest/mocker": "4.1.12",
|
||||
"@vitest/pretty-format": "4.1.12",
|
||||
"@vitest/runner": "4.1.12",
|
||||
"@vitest/snapshot": "4.1.12",
|
||||
"@vitest/spy": "4.1.12",
|
||||
"@vitest/utils": "4.1.12",
|
||||
"@vitest/expect": "4.1.11",
|
||||
"@vitest/mocker": "4.1.11",
|
||||
"@vitest/pretty-format": "4.1.11",
|
||||
"@vitest/runner": "4.1.11",
|
||||
"@vitest/snapshot": "4.1.11",
|
||||
"@vitest/spy": "4.1.11",
|
||||
"@vitest/utils": "4.1.11",
|
||||
"es-module-lexer": "^2.0.0",
|
||||
"expect-type": "^1.3.0",
|
||||
"magic-string": "^0.30.21",
|
||||
|
|
@ -3430,12 +3430,12 @@
|
|||
"@edge-runtime/vm": "*",
|
||||
"@opentelemetry/api": "^1.9.0",
|
||||
"@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0",
|
||||
"@vitest/browser-playwright": "4.1.12",
|
||||
"@vitest/browser-preview": "4.1.12",
|
||||
"@vitest/browser-webdriverio": "^4.1.11",
|
||||
"@vitest/coverage-istanbul": "4.1.12",
|
||||
"@vitest/coverage-v8": "4.1.12",
|
||||
"@vitest/ui": "4.1.12",
|
||||
"@vitest/browser-playwright": "4.1.11",
|
||||
"@vitest/browser-preview": "4.1.11",
|
||||
"@vitest/browser-webdriverio": "4.1.11",
|
||||
"@vitest/coverage-istanbul": "4.1.11",
|
||||
"@vitest/coverage-v8": "4.1.11",
|
||||
"@vitest/ui": "4.1.11",
|
||||
"happy-dom": "*",
|
||||
"jsdom": "*",
|
||||
"vite": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
||||
|
|
|
|||
|
|
@ -82,6 +82,6 @@
|
|||
"@vscode/vsce": "^4.0.0",
|
||||
"esbuild": "^0.28.2",
|
||||
"typescript": "^5.9.3",
|
||||
"vitest": "^4.1.12"
|
||||
"vitest": "^4.1.11"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue