diff --git a/.env.example b/.env.example index 4d130ed6e6..f3fdda08f5 100644 --- a/.env.example +++ b/.env.example @@ -25,7 +25,8 @@ EVAL_TRACE_TRANSPORT="native" # Optional Braintrust OTEL parent override (defaults to project_name:stagehand-dev, # or project_name:stagehand in CI). # BRAINTRUST_OTEL_PARENT="project_name:stagehand-dev" -# Optional Braintrust OTEL traces endpoint override. +# Optional Braintrust OTEL traces endpoint override. The first-party processor +# derives its Braintrust API base URL from this endpoint. # BRAINTRUST_OTEL_URL="https://api.braintrust.dev/otel/v1/traces" # Primary trace sink when multiple are configured ("braintrust" | "langsmith"). EVAL_TRACE_PRIMARY="braintrust" diff --git a/packages/evals/framework/otel.ts b/packages/evals/framework/otel.ts index 8fc47e9bf8..6385dfe525 100644 --- a/packages/evals/framework/otel.ts +++ b/packages/evals/framework/otel.ts @@ -65,27 +65,23 @@ async function initializeTracerProvider(options?: { const braintrustApiKey = process.env.BRAINTRUST_API_KEY; if (braintrustApiKey) { - const { OTLPTraceExporter } = await import( - "@opentelemetry/exporter-trace-otlp-proto" - ); + const { BraintrustSpanProcessor } = await import("@braintrust/otel"); const braintrustProjectName = process.env.CI === "true" ? "stagehand" : "stagehand-dev"; const parent = options?.braintrustParent ?? process.env.BRAINTRUST_OTEL_PARENT ?? `project_name:${braintrustProjectName}`; + const braintrustOtelUrl = process.env.BRAINTRUST_OTEL_URL; spanProcessors.push( - new BatchSpanProcessor( - new OTLPTraceExporter({ - url: - process.env.BRAINTRUST_OTEL_URL ?? - "https://api.braintrust.dev/otel/v1/traces", - headers: { - Authorization: `Bearer ${braintrustApiKey}`, - "x-bt-parent": parent, - }, + new BraintrustSpanProcessor({ + apiKey: braintrustApiKey, + parent, + filterAISpans: false, + ...(braintrustOtelUrl && { + apiUrl: braintrustOtelUrl.replace(/otel\/v1\/traces\/?$/, ""), }), - ), + }), ); } diff --git a/packages/evals/lib/AISdkClientWrapped.ts b/packages/evals/lib/AISdkClientWrapped.ts index 07acd409be..70a7da1249 100644 --- a/packages/evals/lib/AISdkClientWrapped.ts +++ b/packages/evals/lib/AISdkClientWrapped.ts @@ -21,24 +21,27 @@ import { toJsonSchema, } from "@browserbasehq/stagehand"; -type WrappedAI = ReturnType<(typeof import("braintrust"))["wrapAISDK"]>; +type WrappedAI = Pick< + typeof ai, + "generateText" | "generateObject" | "streamText" | "streamObject" +>; let wrappedAiPromise: Promise | undefined; async function loadWrappedAISDK(): Promise { wrappedAiPromise ??= (async () => { if (!process.env.BRAINTRUST_API_KEY) { - return ai as unknown as WrappedAI; + return ai; } const { wrapAISDK } = await import("braintrust"); - return wrapAISDK(ai); + return wrapAISDK(ai) as WrappedAI; })(); return wrappedAiPromise; } async function loadAISDK(): Promise { if (process.env.EVAL_TRACE_TRANSPORT === "otel") { - return ai as unknown as WrappedAI; + return ai; } return loadWrappedAISDK(); } diff --git a/packages/evals/package.json b/packages/evals/package.json index a2acfd7ef9..46064dd43d 100644 --- a/packages/evals/package.json +++ b/packages/evals/package.json @@ -25,9 +25,9 @@ "@ai-sdk/provider": "^2.0.0", "@anthropic-ai/claude-agent-sdk": "^0.2.141", "@browserbasehq/stagehand": "workspace:*", + "@braintrust/otel": "^0.2.1", "@openai/codex-sdk": "0.125.0", "@opentelemetry/api": "^1.9.0", - "@opentelemetry/exporter-trace-otlp-proto": "^0.220.0", "@opentelemetry/sdk-trace-base": "^2.0.0", "@opentelemetry/sdk-trace-node": "^2.0.0", "ai": "^5.0.133", @@ -41,7 +41,7 @@ }, "devDependencies": { "@types/node": "^25.6.2", - "braintrust": "^0.4.10", + "braintrust": "^3.21.0", "chalk": "^5.4.1", "gray-matter": "^4.0.3", "string-comparison": "^1.3.0", diff --git a/packages/evals/tests/framework/otel.test.ts b/packages/evals/tests/framework/otel.test.ts index 20ecc1a2d3..21bb87d31a 100644 --- a/packages/evals/tests/framework/otel.test.ts +++ b/packages/evals/tests/framework/otel.test.ts @@ -1,9 +1,11 @@ import { afterAll, beforeEach, describe, expect, it, vi } from "vitest"; const mocks = vi.hoisted(() => { - const braintrustExporter = vi.fn(function () { + const braintrustSpanProcessor = vi.fn(function () { return { - export: vi.fn(), + forceFlush: vi.fn().mockResolvedValue(undefined), + onEnd: vi.fn(), + onStart: vi.fn(), shutdown: vi.fn().mockResolvedValue(undefined), }; }); @@ -24,14 +26,14 @@ const mocks = vi.hoisted(() => { }); return { - braintrustExporter, + braintrustSpanProcessor, langSmithExporter, nodeTracerProvider, }; }); -vi.mock("@opentelemetry/exporter-trace-otlp-proto", () => ({ - OTLPTraceExporter: mocks.braintrustExporter, +vi.mock("@braintrust/otel", () => ({ + BraintrustSpanProcessor: mocks.braintrustSpanProcessor, })); vi.mock("langsmith/experimental/otel/exporter", () => ({ @@ -91,12 +93,10 @@ describe("buildTracerProvider", () => { const { buildTracerProvider } = await import("../../framework/otel.js"); await expect(buildTracerProvider()).resolves.not.toBeNull(); - expect(mocks.braintrustExporter).toHaveBeenCalledWith({ - url: "https://api.braintrust.dev/otel/v1/traces", - headers: { - Authorization: "Bearer braintrust-test-key", - "x-bt-parent": "project_name:stagehand-dev", - }, + expect(mocks.braintrustSpanProcessor).toHaveBeenCalledWith({ + apiKey: "braintrust-test-key", + parent: "project_name:stagehand-dev", + filterAISpans: false, }); expect(mocks.langSmithExporter).toHaveBeenCalledOnce(); expect(constructedSpanProcessors()).toHaveLength(2); @@ -108,12 +108,10 @@ describe("buildTracerProvider", () => { const { buildTracerProvider } = await import("../../framework/otel.js"); await expect(buildTracerProvider()).resolves.not.toBeNull(); - expect(mocks.braintrustExporter).toHaveBeenCalledWith({ - url: "https://api.braintrust.dev/otel/v1/traces", - headers: { - Authorization: "Bearer braintrust-test-key", - "x-bt-parent": "project_name:stagehand-dev", - }, + expect(mocks.braintrustSpanProcessor).toHaveBeenCalledWith({ + apiKey: "braintrust-test-key", + parent: "project_name:stagehand-dev", + filterAISpans: false, }); expect(mocks.langSmithExporter).not.toHaveBeenCalled(); expect(constructedSpanProcessors()).toHaveLength(1); @@ -128,12 +126,26 @@ describe("buildTracerProvider", () => { await expect( buildTracerProvider({ braintrustParent: "project_name:custom" }), ).resolves.not.toBeNull(); - expect(mocks.braintrustExporter).toHaveBeenCalledWith({ - url: "https://api.braintrust.dev/otel/v1/traces", - headers: { - Authorization: "Bearer braintrust-test-key", - "x-bt-parent": "project_name:custom", - }, + expect(mocks.braintrustSpanProcessor).toHaveBeenCalledWith({ + apiKey: "braintrust-test-key", + parent: "project_name:custom", + filterAISpans: false, + }); + }); + + it("derives the Braintrust apiUrl from BRAINTRUST_OTEL_URL", async () => { + process.env.EVAL_TRACE_TRANSPORT = "otel"; + process.env.BRAINTRUST_API_KEY = "braintrust-test-key"; + process.env.BRAINTRUST_OTEL_URL = + "https://custom.example.com/otel/v1/traces"; + const { buildTracerProvider } = await import("../../framework/otel.js"); + + await expect(buildTracerProvider()).resolves.not.toBeNull(); + expect(mocks.braintrustSpanProcessor).toHaveBeenCalledWith({ + apiKey: "braintrust-test-key", + parent: "project_name:stagehand-dev", + filterAISpans: false, + apiUrl: "https://custom.example.com/", }); }); @@ -144,7 +156,7 @@ describe("buildTracerProvider", () => { const { buildTracerProvider } = await import("../../framework/otel.js"); await expect(buildTracerProvider()).resolves.not.toBeNull(); - expect(mocks.braintrustExporter).not.toHaveBeenCalled(); + expect(mocks.braintrustSpanProcessor).not.toHaveBeenCalled(); expect(mocks.langSmithExporter).toHaveBeenCalledOnce(); expect(constructedSpanProcessors()).toHaveLength(1); }); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dac066f17f..7b99f2c470 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -338,6 +338,9 @@ importers: '@anthropic-ai/claude-agent-sdk': specifier: ^0.2.141 version: 0.2.141(@cfworker/json-schema@4.1.1)(zod@4.2.1) + '@braintrust/otel': + specifier: ^0.2.1 + version: 0.2.1(@opentelemetry/api@1.9.0)(@opentelemetry/core@2.10.0(@opentelemetry/api@1.9.0))(@opentelemetry/exporter-trace-otlp-http@0.221.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.10.0(@opentelemetry/api@1.9.0))(braintrust@3.25.0(@aws-sdk/credential-provider-web-identity@3.972.46)(zod@4.2.1)) '@browserbasehq/stagehand': specifier: workspace:* version: link:../core @@ -347,9 +350,6 @@ importers: '@opentelemetry/api': specifier: ^1.9.0 version: 1.9.0 - '@opentelemetry/exporter-trace-otlp-proto': - specifier: ^0.220.0 - version: 0.220.0(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-trace-base': specifier: ^2.0.0 version: 2.10.0(@opentelemetry/api@1.9.0) @@ -385,8 +385,8 @@ importers: specifier: ^25.6.2 version: 25.6.2 braintrust: - specifier: ^0.4.10 - version: 0.4.10(@aws-sdk/credential-provider-web-identity@3.972.46)(zod@4.2.1) + specifier: ^3.21.0 + version: 3.25.0(@aws-sdk/credential-provider-web-identity@3.972.46)(zod@4.2.1) chalk: specifier: ^5.4.1 version: 5.4.1 @@ -634,10 +634,6 @@ packages: peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/provider@1.1.3': - resolution: {integrity: sha512-qZMxYJ0qqX/RfnuIaab+zp8UAeJn/ygXXAffR5I4N0n1IrvA6qBsjc8hXLmBiMV2zoXlifkacF7sEFnYnjBcqg==} - engines: {node: '>=18'} - '@ai-sdk/provider@2.0.0': resolution: {integrity: sha512-6o7Y2SeO9vFKB8lArHXehNuusnpddKPk7xqL7T2/b+OvXMRIXUO1rR4wcv1hAFUAT9avGZshty3Wlua/XA7TvA==} engines: {node: '>=18'} @@ -911,6 +907,50 @@ packages: resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} engines: {node: '>=18'} + '@braintrust/bt-darwin-arm64@0.12.0': + resolution: {integrity: sha512-mY6VW/3VwcOQOGN8sYHS6F0xzHTFwgZcNlj7zlQttI6OXOCGt/bhonGIqd03QBhxmj0M31ymSS7TqSeCK/RYIQ==} + cpu: [arm64] + os: [darwin] + + '@braintrust/bt-darwin-x64@0.12.0': + resolution: {integrity: sha512-woyRyDv2DfCF8+von+3X9f1cddAbFnKLSfCbEkrBQVc0ZsAM60as8nehYv7DkafJF/67yKFx/sUraV65sukesQ==} + cpu: [x64] + os: [darwin] + + '@braintrust/bt-linux-arm64@0.12.0': + resolution: {integrity: sha512-J9/7f3EIMKmFmSSQHQnAQLpUgB8YJENrOlkABjlTprBgsIYVgz7tSH7yg2P3ur+2Jem7PpGnrDxHGh/UjRfjsg==} + cpu: [arm64] + os: [linux] + + '@braintrust/bt-linux-x64-musl@0.12.0': + resolution: {integrity: sha512-KnLgENOoztBXcH+mLFJe4bYzi67kSOuELOQrm4Hler35GjgaBMI1fFLIUjKRPAmyT9VIhBMhy1ICfGEFLueMEQ==} + cpu: [x64] + os: [linux] + + '@braintrust/bt-linux-x64@0.12.0': + resolution: {integrity: sha512-HJFbUl3HYYY1Ivw8OYBeIMcIsU9r7+fC9BzLWB5FdH7881ToKee2wbbLZssMCxFbMVeUxzEo+SzGD/1Z9Gk9CA==} + cpu: [x64] + os: [linux] + + '@braintrust/bt-win32-arm64@0.12.0': + resolution: {integrity: sha512-+7PkdBAmiqEJsWteGHP/Zs62F75PkHPA8m/ej4TOz/mHGKulUU0bZibw91KRqIB7J7jGi5ItvCiqkiGaLKLnyw==} + cpu: [arm64] + os: [win32] + + '@braintrust/bt-win32-x64@0.12.0': + resolution: {integrity: sha512-Q0c+pVUGm82n/7N8QJ5s6j/G/Q0GFzqOaTipHjkmElLbAOOEcfRH/uljdtIPNBiEQcrzqirS0GmOgiFkeQ3Txg==} + cpu: [x64] + os: [win32] + + '@braintrust/otel@0.2.1': + resolution: {integrity: sha512-1HFjkD+ZpOKEUMEoz/Zo5HbVBz4pnE3cLtiSmhccIhTJXZxMwFUlWi9XeQOtRaPQgCQHqeYTeIcs7DzsdLAuIQ==} + peerDependencies: + '@opentelemetry/api': '>=1.9.0' + '@opentelemetry/core': '>=1.9.0' + '@opentelemetry/exporter-trace-otlp-http': '>=0.35.0' + '@opentelemetry/sdk-trace-base': '>=1.9.0' + braintrust: '>=1.0.0-0' + '@bramus/specificity@2.4.2': resolution: {integrity: sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==} hasBin: true @@ -985,6 +1025,10 @@ packages: '@changesets/write@0.4.0': resolution: {integrity: sha512-CdTLvIOPiCNuH71pyDu3rA+Q0n65cmAbXnwWH84rKGiFumFzkmHNT8KHTMEchcxN+Kl8I54xGUhJ7l3E7X396Q==} + '@colors/colors@1.5.0': + resolution: {integrity: sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==} + engines: {node: '>=0.1.90'} + '@csstools/color-helpers@6.0.2': resolution: {integrity: sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==} engines: {node: '>=20.19.0'} @@ -1778,6 +1822,9 @@ packages: '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + '@jridgewell/resolve-uri@3.1.2': resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} @@ -1972,6 +2019,10 @@ packages: resolution: {integrity: sha512-CmVa4ImJ+ynfrPMNaAXHET6Bhb44SwzmfyVJFq9ni2jgXJR/l7C6gfVFddNmHP+ZOkP9cf4f9DBe68qVLTHc9w==} engines: {node: '>=8.0.0'} + '@opentelemetry/api-logs@0.221.0': + resolution: {integrity: sha512-OlanaW1vv7ufTqQ3/fPLI4arGt5ZoM+P8abOMki6uEYnpRazepSWDwDnnw+la7kE26SHVC18//SMccrDvLKOXQ==} + engines: {node: '>=8.0.0'} + '@opentelemetry/api@1.9.0': resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} engines: {node: '>=8.0.0'} @@ -1994,6 +2045,12 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' + '@opentelemetry/exporter-trace-otlp-http@0.221.0': + resolution: {integrity: sha512-AySXiKoC+meiWm6zdVj5T2LnPDZuatveBby1cMOeQteIWsYXAUxs8Sru13G2pVSPrUXz6vF+og7QVBX6GdC/oQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + '@opentelemetry/exporter-trace-otlp-proto@0.220.0': resolution: {integrity: sha512-voTAD8XgJxlK7zLkXh8EzMB09zrQr3tyY/BsnDTlDiQU/UdK58MZ63A3mUjdEDrxMjCVmBHU3WQJhRmQe+Dvzg==} engines: {node: ^18.19.0 || >=20.6.0} @@ -2006,12 +2063,24 @@ packages: peerDependencies: '@opentelemetry/api': ^1.3.0 + '@opentelemetry/otlp-exporter-base@0.221.0': + resolution: {integrity: sha512-UFPIq80OH3Ns/oPFHRj14d4DTOxUo+MUFU8hUiCq5jTqFhdeJnfVSANHT+xp92409cA+oxzvlZCe6NM1wvCuBA==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + '@opentelemetry/otlp-transformer@0.220.0': resolution: {integrity: sha512-lXGrv7KXZ0gNH9SVNUaa6vv6phVYGvJxfXAlMbzbakiXru75f5MZl8Z7oqiMMQD77riVHJCFlQvbZs/VVN2/4A==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 + '@opentelemetry/otlp-transformer@0.221.0': + resolution: {integrity: sha512-lg6lkOU08Az23jVcn/0Els9HP+V8PnR4Km6p0KgpTggS0n/WuhnmY64rSh83Of9iR9nD+dpWr6adlcX8KzAwjg==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': ^1.3.0 + '@opentelemetry/resources@2.10.0': resolution: {integrity: sha512-q6MMm2zhggzsHVNbabYwut+a6nbuQQe3URUoxaojM/8K1IBfwwPzvxIjNi2/lI1TFe+fMHMW9MWhrtDLEXEnkA==} engines: {node: ^18.19.0 || >=20.6.0} @@ -2030,6 +2099,18 @@ packages: peerDependencies: '@opentelemetry/api': '>=1.4.0 <1.10.0' + '@opentelemetry/sdk-logs@0.221.0': + resolution: {integrity: sha512-FaDcazjyMp7TZZZAsqbo4IkovP0UegoCu0EBkiNt+qCqvUf7FPAsfcrZ3+ZEkKgXZ/jHafop+JoGPDk3A0SmLg==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.4.0 <1.10.0' + + '@opentelemetry/sdk-metrics@2.10.0': + resolution: {integrity: sha512-t6r1VSvXNtSDnPXU1FbZeetJb7yyovHmgu0wRSoftxtE0g2rSNhQZQUy69sRUCL+iioJpX8SN/S6wq6ZtvLySQ==} + engines: {node: ^18.19.0 || >=20.6.0} + peerDependencies: + '@opentelemetry/api': '>=1.9.0 <1.10.0' + '@opentelemetry/sdk-metrics@2.9.0': resolution: {integrity: sha512-Xx8RGS4H5XEBl01WuCreMIpiah9cCXMbSkeuIePPdD2cUpq/vUzYmj8E/MK1OsbOc93FuAD4jfn2WOacKwLn7Q==} engines: {node: ^18.19.0 || >=20.6.0} @@ -3000,6 +3081,11 @@ packages: resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} engines: {node: '>= 0.6'} + acorn-import-attributes@1.9.5: + resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==} + peerDependencies: + acorn: ^8 + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -3350,11 +3436,11 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} - braintrust@0.4.10: - resolution: {integrity: sha512-Dk4aVsHWjgeTyGcM056vleXZGLz3qIHw6rDYP4iyY4DOZeD6JSDGSepGb1dulpcwqf2WC6w9XIFTF7Y/4gfahg==} + braintrust@3.25.0: + resolution: {integrity: sha512-0BIk3RDO9nLcvx4C7zaVJV0NfepZlJGi+K4jjUA/D8M9qq6YpCAP2gnBZr4UHAju8+t2Rl7MINim05K0BfaA9Q==} hasBin: true peerDependencies: - zod: ^3.25.34 + zod: ^3.25.34 || ^4.0 buffer-crc32@0.2.13: resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} @@ -3431,10 +3517,6 @@ packages: resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} engines: {node: '>=18'} - chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - chalk@5.2.0: resolution: {integrity: sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} @@ -3499,6 +3581,9 @@ packages: peerDependencies: devtools-protocol: '*' + cjs-module-lexer@2.2.0: + resolution: {integrity: sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==} + clean-stack@3.0.1: resolution: {integrity: sha512-lR9wNiMRcVQjSB3a7xXGLuz4cr4wJuuXlaAEbRutGowQTmlp7R72/DOgN21e8jdwblMWl9UOJMJXarX94pzKdg==} engines: {node: '>=10'} @@ -3527,6 +3612,10 @@ packages: resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} engines: {node: '>=6'} + cli-table3@0.6.5: + resolution: {integrity: sha512-+W/5efTR7y5HRD7gACw9yQjqMVvEMLBHmboM/kPWam+H+Hmyrgjh6YncVKK122YZkXrLudzTuAukUw9FnMf7IQ==} + engines: {node: 10.* || >= 12.*} + cli-truncate@4.0.0: resolution: {integrity: sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==} engines: {node: '>=18'} @@ -3738,6 +3827,9 @@ packages: dateformat@4.6.3: resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==} + dc-browser@1.0.4: + resolution: {integrity: sha512-7oEtnzNlcE+hr4OvO3GR6Gndgw8BhW+wKOEwMqSleyY7N29jbAxzyW5BaJl7qBCw+6OIxfMWtY0T+6dxq8RWLw==} + debug@2.6.9: resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} peerDependencies: @@ -4214,10 +4306,6 @@ packages: resolution: {integrity: sha512-c2iPh3xp5vvCLgaHK03+mWLFPhox7j1LwyxcZwFVApEv5i0X+IjPpbT50SJJwwLpdBVfp45AkK/v+AFgv/XlfQ==} engines: {node: '>= 0.10.0'} - express@4.22.1: - resolution: {integrity: sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==} - engines: {node: '>= 0.10.0'} - express@5.2.1: resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} engines: {node: '>= 18'} @@ -5488,6 +5576,10 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} + meriyah@6.1.4: + resolution: {integrity: sha512-Sz8FzjzI0kN13GK/6MVEsVzMZEPvOhnmmI1lU5+/1cGOiK3QUahntrNNtdVeihrO7t9JpoH75iMNXg6R6uWflQ==} + engines: {node: '>=18.0.0'} + methods@1.1.2: resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} engines: {node: '>= 0.6'} @@ -5685,6 +5777,9 @@ packages: mkdirp-classic@0.5.3: resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + module-details-from-path@1.0.4: + resolution: {integrity: sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==} + mri@1.2.0: resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} engines: {node: '>=4'} @@ -6657,6 +6752,9 @@ packages: secure-json-parse@4.1.0: resolution: {integrity: sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==} + semifies@1.0.0: + resolution: {integrity: sha512-xXR3KGeoxTNWPD4aBvL5NUpMTT7WMANr3EWnaS190QVkY52lqqcVRD7Q05UVbBhiWDGWMlJEUam9m7uFFGVScw==} + semver@7.7.2: resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} engines: {node: '>=10'} @@ -6793,10 +6891,6 @@ packages: resolution: {integrity: sha512-stxByr12oeeOyY2BlviTNQlYV5xOj47GirPr4yA1hE9JCtxfQN0+tVbkxwCtYDQWhEKWFHsEK48ORg5jrouCAg==} engines: {node: '>=20'} - slugify@1.6.9: - resolution: {integrity: sha512-vZ7rfeehZui7wQs438JXBckYLkIIdfHOXsaVEUMyS5fHo1483l1bMdo0EDSWYclY0yZKFOipDy4KHuKs6ssvdg==} - engines: {node: '>=8.0.0'} - smart-buffer@4.2.0: resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} @@ -7026,6 +7120,10 @@ packages: resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} engines: {node: '>=8'} + termi-link@1.1.0: + resolution: {integrity: sha512-2qSN6TnomHgVLtk+htSWbaYs4Rd2MH/RU7VpHTy6MBstyNyWbM4yKd1DCYpE3fDg8dmGWojXCngNi/MHCzGuAA==} + engines: {node: '>=12'} + test-exclude@8.0.0: resolution: {integrity: sha512-ZOffsNrXYggvU1mDGHk54I96r26P8SyMjO5slMKSc7+IWmtB/MQKnEC2fP51imB3/pT6YK5cT5E8f+Dd9KdyOQ==} engines: {node: 20 || >=22} @@ -7328,6 +7426,10 @@ packages: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} + unplugin@2.3.11: + resolution: {integrity: sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==} + engines: {node: '>=18.12.0'} + upper-case-first@2.0.2: resolution: {integrity: sha512-514ppYHBaKwfJRK/pNC6c/OxfGa0obSnAl106u97Ed0I625Nin96KAjttZF6ZL3e1XLtphxnqrOi9iWgm+u+bg==} @@ -7511,6 +7613,9 @@ packages: resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==} engines: {node: '>=20'} + webpack-virtual-modules@0.6.2: + resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} + whatwg-mimetype@5.0.0: resolution: {integrity: sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==} engines: {node: '>=20'} @@ -7894,10 +7999,6 @@ snapshots: eventsource-parser: 3.1.0 zod: 4.2.1 - '@ai-sdk/provider@1.1.3': - dependencies: - json-schema: 0.4.0 - '@ai-sdk/provider@2.0.0': dependencies: json-schema: 0.4.0 @@ -8351,6 +8452,35 @@ snapshots: '@bcoe/v8-coverage@1.0.2': {} + '@braintrust/bt-darwin-arm64@0.12.0': + optional: true + + '@braintrust/bt-darwin-x64@0.12.0': + optional: true + + '@braintrust/bt-linux-arm64@0.12.0': + optional: true + + '@braintrust/bt-linux-x64-musl@0.12.0': + optional: true + + '@braintrust/bt-linux-x64@0.12.0': + optional: true + + '@braintrust/bt-win32-arm64@0.12.0': + optional: true + + '@braintrust/bt-win32-x64@0.12.0': + optional: true + + '@braintrust/otel@0.2.1(@opentelemetry/api@1.9.0)(@opentelemetry/core@2.10.0(@opentelemetry/api@1.9.0))(@opentelemetry/exporter-trace-otlp-http@0.221.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.10.0(@opentelemetry/api@1.9.0))(braintrust@3.25.0(@aws-sdk/credential-provider-web-identity@3.972.46)(zod@4.2.1))': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/exporter-trace-otlp-http': 0.221.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace-base': 2.10.0(@opentelemetry/api@1.9.0) + braintrust: 3.25.0(@aws-sdk/credential-provider-web-identity@3.972.46)(zod@4.2.1) + '@bramus/specificity@2.4.2': dependencies: css-tree: 3.2.1 @@ -8530,6 +8660,9 @@ snapshots: human-id: 4.1.3 prettier: 2.8.8 + '@colors/colors@1.5.0': + optional: true + '@csstools/color-helpers@6.0.2': {} '@csstools/css-calc@3.2.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': @@ -9320,6 +9453,11 @@ snapshots: '@jridgewell/sourcemap-codec': 1.5.5 '@jridgewell/trace-mapping': 0.3.31 + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + '@jridgewell/resolve-uri@3.1.2': {} '@jridgewell/sourcemap-codec@1.5.5': {} @@ -9842,6 +9980,11 @@ snapshots: '@opentelemetry/api-logs@0.220.0': dependencies: '@opentelemetry/api': 1.9.0 + optional: true + + '@opentelemetry/api-logs@0.221.0': + dependencies: + '@opentelemetry/api': 1.9.0 '@opentelemetry/api@1.9.0': {} @@ -9858,6 +10001,14 @@ snapshots: dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/semantic-conventions': 1.43.0 + optional: true + + '@opentelemetry/exporter-trace-otlp-http@0.221.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/otlp-exporter-base': 0.221.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.221.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace': 2.10.0(@opentelemetry/api@1.9.0) '@opentelemetry/exporter-trace-otlp-proto@0.220.0(@opentelemetry/api@1.9.0)': dependencies: @@ -9867,12 +10018,20 @@ snapshots: '@opentelemetry/otlp-transformer': 0.220.0(@opentelemetry/api@1.9.0) '@opentelemetry/resources': 2.9.0(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-trace': 2.9.0(@opentelemetry/api@1.9.0) + optional: true '@opentelemetry/otlp-exporter-base@0.220.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.0) '@opentelemetry/otlp-transformer': 0.220.0(@opentelemetry/api@1.9.0) + optional: true + + '@opentelemetry/otlp-exporter-base@0.221.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/otlp-transformer': 0.221.0(@opentelemetry/api@1.9.0) '@opentelemetry/otlp-transformer@0.220.0(@opentelemetry/api@1.9.0)': dependencies: @@ -9883,6 +10042,17 @@ snapshots: '@opentelemetry/sdk-logs': 0.220.0(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-metrics': 2.9.0(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-trace': 2.9.0(@opentelemetry/api@1.9.0) + optional: true + + '@opentelemetry/otlp-transformer@0.221.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs': 0.221.0 + '@opentelemetry/core': 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-logs': 0.221.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-metrics': 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/sdk-trace': 2.10.0(@opentelemetry/api@1.9.0) '@opentelemetry/resources@2.10.0(@opentelemetry/api@1.9.0)': dependencies: @@ -9895,6 +10065,7 @@ snapshots: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.0) '@opentelemetry/semantic-conventions': 1.43.0 + optional: true '@opentelemetry/sdk-logs@0.220.0(@opentelemetry/api@1.9.0)': dependencies: @@ -9903,12 +10074,28 @@ snapshots: '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.0) '@opentelemetry/resources': 2.9.0(@opentelemetry/api@1.9.0) '@opentelemetry/semantic-conventions': 1.43.0 + optional: true + + '@opentelemetry/sdk-logs@0.221.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/api-logs': 0.221.0 + '@opentelemetry/core': 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/semantic-conventions': 1.43.0 + + '@opentelemetry/sdk-metrics@2.10.0(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/api': 1.9.0 + '@opentelemetry/core': 2.10.0(@opentelemetry/api@1.9.0) + '@opentelemetry/resources': 2.10.0(@opentelemetry/api@1.9.0) '@opentelemetry/sdk-metrics@2.9.0(@opentelemetry/api@1.9.0)': dependencies: '@opentelemetry/api': 1.9.0 '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.0) '@opentelemetry/resources': 2.9.0(@opentelemetry/api@1.9.0) + optional: true '@opentelemetry/sdk-trace-base@2.10.0(@opentelemetry/api@1.9.0)': dependencies: @@ -9938,6 +10125,7 @@ snapshots: '@opentelemetry/core': 2.9.0(@opentelemetry/api@1.9.0) '@opentelemetry/resources': 2.9.0(@opentelemetry/api@1.9.0) '@opentelemetry/semantic-conventions': 1.43.0 + optional: true '@opentelemetry/semantic-conventions@1.43.0': {} @@ -11007,6 +11195,10 @@ snapshots: mime-types: 3.0.1 negotiator: 1.0.0 + acorn-import-attributes@1.9.5(acorn@8.16.0): + dependencies: + acorn: 8.16.0 + acorn-jsx@5.3.2(acorn@8.11.2): dependencies: acorn: 8.11.2 @@ -11357,30 +11549,47 @@ snapshots: dependencies: fill-range: 7.1.1 - braintrust@0.4.10(@aws-sdk/credential-provider-web-identity@3.972.46)(zod@4.2.1): + braintrust@3.25.0(@aws-sdk/credential-provider-web-identity@3.972.46)(zod@4.2.1): dependencies: - '@ai-sdk/provider': 1.1.3 '@next/env': 14.2.35 '@vercel/functions': 1.6.0(@aws-sdk/credential-provider-web-identity@3.972.46) + acorn: 8.16.0 + acorn-import-attributes: 1.9.5(acorn@8.16.0) + ajv: 8.20.0 argparse: 2.0.1 - chalk: 4.1.2 + astring: 1.9.0 + cjs-module-lexer: 2.2.0 cli-progress: 3.12.0 + cli-table3: 0.6.5 cors: 2.8.6 + dc-browser: 1.0.4 dotenv: 16.6.1 esbuild: 0.28.1 + esquery: 1.7.0 eventsource-parser: 1.1.2 - express: 4.22.1 - graceful-fs: 4.2.11 + express: 5.2.1 http-errors: 2.0.1 + meriyah: 6.1.4 minimatch: 3.1.5 + module-details-from-path: 1.0.4 mustache: 4.2.0 pluralize: 8.0.0 + semifies: 1.0.0 simple-git: 3.36.0 - slugify: 1.6.9 source-map: 0.7.6 + termi-link: 1.1.0 + unplugin: 2.3.11 uuid: 11.1.1 zod: 4.2.1 zod-to-json-schema: 3.25.2(zod@4.2.1) + optionalDependencies: + '@braintrust/bt-darwin-arm64': 0.12.0 + '@braintrust/bt-darwin-x64': 0.12.0 + '@braintrust/bt-linux-arm64': 0.12.0 + '@braintrust/bt-linux-x64': 0.12.0 + '@braintrust/bt-linux-x64-musl': 0.12.0 + '@braintrust/bt-win32-arm64': 0.12.0 + '@braintrust/bt-win32-x64': 0.12.0 transitivePeerDependencies: - '@aws-sdk/credential-provider-web-identity' - supports-color @@ -11470,11 +11679,6 @@ snapshots: chai@6.2.2: {} - chalk@4.1.2: - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - chalk@5.2.0: {} chalk@5.3.0: {} @@ -11560,6 +11764,8 @@ snapshots: mitt: 3.0.1 zod: 3.25.76 + cjs-module-lexer@2.2.0: {} + clean-stack@3.0.1: dependencies: escape-string-regexp: 4.0.0 @@ -11584,6 +11790,12 @@ snapshots: cli-spinners@2.9.2: {} + cli-table3@0.6.5: + dependencies: + string-width: 4.2.3 + optionalDependencies: + '@colors/colors': 1.5.0 + cli-truncate@4.0.0: dependencies: slice-ansi: 5.0.0 @@ -11787,6 +11999,8 @@ snapshots: dateformat@4.6.3: {} + dc-browser@1.0.4: {} + debug@2.6.9: dependencies: ms: 2.0.0 @@ -12423,42 +12637,6 @@ snapshots: transitivePeerDependencies: - supports-color - express@4.22.1: - dependencies: - accepts: 1.3.8 - array-flatten: 1.1.1 - body-parser: 1.20.5 - content-disposition: 0.5.4 - content-type: 1.0.5 - cookie: 0.7.2 - cookie-signature: 1.0.7 - debug: 2.6.9 - depd: 2.0.0 - encodeurl: 2.0.0 - escape-html: 1.0.3 - etag: 1.8.1 - finalhandler: 1.3.2 - fresh: 0.5.2 - http-errors: 2.0.1 - merge-descriptors: 1.0.3 - methods: 1.1.2 - on-finished: 2.4.1 - parseurl: 1.3.3 - path-to-regexp: 0.1.13 - proxy-addr: 2.0.7 - qs: 6.15.2 - range-parser: 1.2.1 - safe-buffer: 5.2.1 - send: 0.19.2 - serve-static: 1.16.3 - setprototypeof: 1.2.0 - statuses: 2.0.2 - type-is: 1.6.18 - utils-merge: 1.0.1 - vary: 1.1.2 - transitivePeerDependencies: - - supports-color - express@5.2.1: dependencies: accepts: 2.0.0 @@ -14165,6 +14343,8 @@ snapshots: merge2@1.4.1: {} + meriyah@6.1.4: {} + methods@1.1.2: {} micromark-core-commonmark@2.0.3: @@ -14535,6 +14715,8 @@ snapshots: mkdirp-classic@0.5.3: optional: true + module-details-from-path@1.0.4: {} + mri@1.2.0: {} ms@2.0.0: {} @@ -15749,6 +15931,8 @@ snapshots: secure-json-parse@4.1.0: {} + semifies@1.0.0: {} + semver@7.7.2: {} semver@7.8.0: {} @@ -16002,8 +16186,6 @@ snapshots: ansi-styles: 6.2.3 is-fullwidth-code-point: 5.1.0 - slugify@1.6.9: {} - smart-buffer@4.2.0: {} snake-case@3.0.4: @@ -16334,6 +16516,8 @@ snapshots: term-size@2.2.1: {} + termi-link@1.1.0: {} + test-exclude@8.0.0: dependencies: '@istanbuljs/schema': 0.1.6 @@ -16677,6 +16861,13 @@ snapshots: unpipe@1.0.0: {} + unplugin@2.3.11: + dependencies: + '@jridgewell/remapping': 2.3.5 + acorn: 8.16.0 + picomatch: 4.0.4 + webpack-virtual-modules: 0.6.2 + upper-case-first@2.0.2: dependencies: tslib: 2.8.1 @@ -16948,6 +17139,8 @@ snapshots: webidl-conversions@8.0.1: {} + webpack-virtual-modules@0.6.2: {} + whatwg-mimetype@5.0.0: {} whatwg-url@16.0.1: