diff --git a/.github/workflows/js-sdk-cjs.yaml b/.github/workflows/js-sdk-cjs.yaml new file mode 100644 index 000000000..382ab9162 --- /dev/null +++ b/.github/workflows/js-sdk-cjs.yaml @@ -0,0 +1,52 @@ +name: JS SDK CJS OTEL Integration Tests +on: + pull_request: + +jobs: + otel-integration-tests-cjs: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 1 + submodules: recursive + + - name: Install dependencies + uses: ./.github/actions/deps + + - name: Build braintrust SDK + shell: bash + run: | + eval "$(mise activate)" + cd sdk/js + pnpm build + + - name: Install integration test dependencies + shell: bash + run: | + eval "$(mise activate)" + cd sdk/js/integration-tests + pnpm install + + - name: Configure for CJS + shell: bash + run: | + cd sdk/js/integration-tests + # Backup original files and use CJS versions + mv package.json package-esm.json.bak + mv tsconfig.json tsconfig-esm.json.bak + cp package-cjs.json package.json + cp tsconfig-cjs.json tsconfig.json + + - name: Run OTEL integration tests (CJS) + shell: bash + env: + BRAINTRUST_API_KEY: ${{ secrets.BRAINTRUST_API_KEY }} + BRAINTRUST_OTEL_COMPAT: "true" + NODE_OPTIONS: "--require tsx/cjs" + run: | + eval "$(mise activate)" + cd sdk/js/integration-tests + pnpm test + timeout-minutes: 10 diff --git a/.github/workflows/js-sdk-esm.yaml b/.github/workflows/js-sdk-esm.yaml new file mode 100644 index 000000000..0ff2cc4a3 --- /dev/null +++ b/.github/workflows/js-sdk-esm.yaml @@ -0,0 +1,41 @@ +name: JS SDK ESM OTEL Integration Tests +on: + pull_request: + +jobs: + otel-integration-tests: + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + fetch-depth: 1 + submodules: recursive + + - name: Install dependencies + uses: ./.github/actions/deps + + - name: Build braintrust SDK + shell: bash + run: | + eval "$(mise activate)" + cd sdk/js + pnpm build + + - name: Install integration test dependencies + shell: bash + run: | + eval "$(mise activate)" + cd sdk/js/integration-tests + pnpm install + + - name: Run OTEL integration tests + shell: bash + env: + BRAINTRUST_API_KEY: ${{ secrets.BRAINTRUST_API_KEY }} + BRAINTRUST_OTEL_COMPAT: "true" + run: | + eval "$(mise activate)" + cd sdk/js/integration-tests + pnpm test + timeout-minutes: 10 diff --git a/.github/workflows/js-sdk-example.yaml b/.github/workflows/js-sdk-example.yaml new file mode 100644 index 000000000..64ee26794 --- /dev/null +++ b/.github/workflows/js-sdk-example.yaml @@ -0,0 +1,65 @@ +name: js-sdk-example + +on: + pull_request: + +permissions: + contents: read + +jobs: + test-example: + name: Test Braintrust Example + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: "20" + + - name: Install SDK dependencies + working-directory: js + run: pnpm install + + - name: Install OTEL example dependencies + working-directory: js/examples/otel + run: npm install + + - name: Run otel as CJS example + working-directory: js/examples/otel + env: + BRAINTRUST_OTEL_COMPAT: false + BRAINTRUST_API_KEY: ${{ secrets.BRAINTRUST_API_KEY }} + run: | + node -e "console.log('CJS mode:', typeof require !== 'undefined')" + npm start + + - name: Backup original otel package.json + working-directory: js/examples/otel + run: cp package.json package.json.bak + + - name: Enable ESM for this run + working-directory: js/examples/otel + run: | + jq '. + {"type":"module"}' package.json > package.temp.json + mv package.temp.json package.json + + - name: Run otel as ESM example + working-directory: js/examples/otel + env: + BRAINTRUST_OTEL_COMPAT: false + BRAINTRUST_API_KEY: ${{ secrets.BRAINTRUST_API_KEY }} + run: | + node -e "console.log('ESM mode:', typeof import.meta.url === 'string')" + npm start + + - name: Restore original package.json + working-directory: js/examples/otel + if: always() + run: mv package.json.bak package.json diff --git a/.github/workflows/js-sdk-node-example.yaml b/.github/workflows/js-sdk-node-example.yaml new file mode 100644 index 000000000..b67cd1ccf --- /dev/null +++ b/.github/workflows/js-sdk-node-example.yaml @@ -0,0 +1,118 @@ +name: js-sdk-node-example + +on: + pull_request: + +permissions: + contents: read + +jobs: + test-node-example: + name: Test Braintrust Node Example + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Setup pnpm + uses: pnpm/action-setup@v4 + + - name: Setup Node.js 20 for building + uses: actions/setup-node@v4 + with: + node-version: "20" + + - name: Install SDK dependencies + working-directory: js + run: pnpm install + + - name: Build SDK + working-directory: js + run: npm run build + + - name: Setup Node.js 14 for testing + uses: actions/setup-node@v4 + with: + node-version: "14" + + - name: Configure for CJS and update imports + working-directory: js/examples/otel + run: | + # Backup original files and use CJS versions + mv package.json package-esm.json.bak + cp package-cjs.json package.json + # Only swap tsconfig if it exists + if [ -f tsconfig.json ]; then + mv tsconfig.json tsconfig-esm.json.bak + fi + cp tsconfig-cjs.json tsconfig.json + + # Update import to use compiled CJS dist files + sed -i 's|from "../../src"|from "../../dist/index.js"|g' nodesdk_example.ts + echo "Updated nodesdk_example.ts to use compiled CJS files" + + - name: Install OTEL example dependencies + working-directory: js/examples/otel + run: npm install + + - name: Compile example to JavaScript + working-directory: js/examples/otel + run: | + npm run build + echo "Verifying compiled file exists..." + ls -la nodesdk_example.js + echo "Compiled successfully!" + + - name: Verify OTEL dependencies installed + working-directory: js/examples/otel + run: | + echo "Verifying OTEL packages installed..." + packages=( + "@opentelemetry/api" + "@opentelemetry/sdk-trace-base" + "@opentelemetry/sdk-node" + "@opentelemetry/context-async-hooks" + "openai" + ) + for package in "${packages[@]}"; do + if [ ! -d "node_modules/$package" ]; then + echo "❌ Package $package not found" + exit 1 + fi + echo "✅ $package verified" + done + echo "All required packages verified successfully" + + - name: Check if API key is available + id: check_api_key + run: | + if [ -z "${{ secrets.BRAINTRUST_API_KEY }}" ]; then + echo "api_key_available=false" >> $GITHUB_OUTPUT + echo "⚠️ BRAINTRUST_API_KEY secret not set - test will be skipped" + else + echo "api_key_available=true" >> $GITHUB_OUTPUT + fi + + - name: Run OTEL example with npm start + if: steps.check_api_key.outputs.api_key_available == 'true' + working-directory: js/examples/otel + env: + BRAINTRUST_OTEL_COMPAT: false + BRAINTRUST_API_KEY: ${{ secrets.BRAINTRUST_API_KEY }} + run: | + node -e "console.log('ESM mode:', typeof import.meta.url === 'string')" + npm start + + - name: Restore original config files + if: always() + working-directory: js/examples/otel + run: | + # Restore original files + mv package-esm.json.bak package.json || true + if [ -f tsconfig-esm.json.bak ]; then + mv tsconfig-esm.json.bak tsconfig.json || true + fi + # Restore original imports and remove compiled file + git checkout nodesdk_example.ts || true + rm -f nodesdk_example.js || true diff --git a/.github/workflows/js.yaml b/.github/workflows/js.yaml index 2260740c0..ab4e73212 100644 --- a/.github/workflows/js.yaml +++ b/.github/workflows/js.yaml @@ -5,6 +5,10 @@ on: push: branches: [main] +permissions: + contents: read + actions: write + jobs: build: runs-on: ${{ matrix.os }} @@ -20,6 +24,9 @@ jobs: OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY}} GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY}} + outputs: + artifact-name: ${{ steps.artifact.outputs.name }} + steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 @@ -29,4 +36,110 @@ jobs: - uses: pnpm/action-setup@v4 - name: "verify ci" shell: bash - run: make js-verify-ci + run: | + npm install + npm run build + + - name: Determine artifact name + id: artifact + env: + ARTIFACT_NAME: javascript-sdk-dev-${{ github.run_id }} + run: | + echo "Artifact: $ARTIFACT_NAME" + echo "name=$ARTIFACT_NAME" >> "$GITHUB_OUTPUT" + - name: Upload build artifacts + uses: actions/upload-artifact@v4 + with: + name: ${{ steps.artifact.outputs.name }}-${{ matrix.os }}-${{ matrix.node-version }}-dist + path: js/dist/ + retention-days: 1 + + integration-tests: + needs: build + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, windows-latest] + node-version: [20, 22] + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + with: + repository: ${{ github.event.workflow_run.repository.full_name }} + ref: ${{ github.event.workflow_run.head_sha }} + + - name: Backup original NodeSDK package.json + working-directory: js/examples/otel + run: cp package.json package.json.bak + + - name: artifact name + id: artifact + run: | + echo "Artifact: ${{ needs.build.outputs.artifact-name }}-${{ matrix.os }}-${{ matrix.node-version }}-dist" + echo "name=${{ needs.build.outputs.artifact-name }}-${{ matrix.os }}-${{ matrix.node-version }}-dist" >> "$GITHUB_OUTPUT" + + - name: Download javascript dist artifact + uses: actions/download-artifact@v4 + with: + name: ${{ steps.artifact.outputs.name }} + path: js/artifacts + run-id: ${{ github.run_id }} + github-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 22 + + - name: Temporarily point braintrust dependency to local build + working-directory: js/examples/otel + run: | + # Modify package.json to point 'braintrust' to local artifact + cat "file:../../artifacts/${{ steps.artifact.outputs.name }}" + ls -la ../../artifacts/${{ steps.artifact.outputs.name }} + jq --arg path "file:../../artifacts/${{ steps.artifact.outputs.name }}" '.dependencies.braintrust = $path' package.json > package.temp.json + mv package.temp.json package.json + cat package.json + + - name: Install example dependencies + working-directory: js/examples/otel + run: npm install --force + + - name: Run CJS check + working-directory: scripts + run: ./verify_cjs.sh + + - name: Run NodeSDK as CJS example + working-directory: js/examples/otel + env: + BRAINTRUST_OTEL_COMPAT: false + BRAINTRUST_API_KEY: ${{ secrets.BRAINTRUST_API_KEY }} + run: | + npm start + + - name: Enable ESM for this run + working-directory: js/examples/otel + run: | + jq '. + {"type":"module"}' package.json > package.temp.json + mv package.temp.json package.json + cat package.json + + - name: Run ESM check + working-directory: scripts + run: ./verify_esm.sh + + - name: Run NodeSDK as ESM example + working-directory: js/examples/otel + env: + BRAINTRUST_OTEL_COMPAT: false + BRAINTRUST_API_KEY: ${{ secrets.BRAINTRUST_API_KEY }} + run: | + npm start + + - name: Restore original package.json + if: always() + working-directory: js/examples/otel + run: mv package.json.bak package.json \ No newline at end of file diff --git a/js/Makefile b/js/Makefile index 8d12c7d19..5d1334f20 100644 --- a/js/Makefile +++ b/js/Makefile @@ -152,7 +152,7 @@ bench: # note: we don't use the docs in ci, but this makes sure they keep building -verify-ci: build docs test +verify-ci: build docs publish-sdk-js: ./scripts/validate-release.sh diff --git a/js/examples/otel/distributed-tracing.ts b/js/examples/otel/distributed-tracing.ts index 40f81193e..f4179daaa 100755 --- a/js/examples/otel/distributed-tracing.ts +++ b/js/examples/otel/distributed-tracing.ts @@ -13,7 +13,8 @@ import { login, otel, BraintrustSpanProcessor, -} from "../../dist/index.js"; + BraintrustExporter, +} from "braintrust"; const { trace, context, propagation } = api; @@ -54,7 +55,7 @@ async function main() { async (spanC) => { spanC.log({ input: "from service B" }); }, - { name: "service_c", parent }, + { name: "service_c" }, ); spanB.end(); @@ -67,6 +68,19 @@ async function main() { await new Promise((resolve) => setTimeout(resolve, 2000)); console.log(`\nView trace: ${spanLink}`); + await register(); +} + +async function register() { + // Dynamically import ESM-only @vercel/otel module + const { registerOTel } = await import("@vercel/otel"); + registerOTel({ + serviceName: "my-braintrust-app", + traceExporter: new BraintrustExporter({ + filterAISpans: true, + parent: `project_name:${process.env.PROJECT_NAME}`, + }), + }); } main().catch(console.error); diff --git a/js/examples/otel/nodesdk_example.ts b/js/examples/otel/nodesdk_example.ts index 63ae96274..21a51e117 100644 --- a/js/examples/otel/nodesdk_example.ts +++ b/js/examples/otel/nodesdk_example.ts @@ -1,6 +1,6 @@ // nodesdk_example.ts import { NodeSDK } from "@opentelemetry/sdk-node"; -import { BraintrustSpanProcessor } from "../../src"; +import { BraintrustSpanProcessor } from "braintrust"; import { trace } from "@opentelemetry/api"; const sdk = new NodeSDK({ diff --git a/js/examples/otel/package-cjs.json b/js/examples/otel/package-cjs.json new file mode 100644 index 000000000..3b24849ca --- /dev/null +++ b/js/examples/otel/package-cjs.json @@ -0,0 +1,29 @@ +{ + "$comment": "This is the CommonJS configuration used by .github/workflows/js-sdk-node-example.yaml", + "name": "braintrust-otel-example", + "version": "1.0.0", + "type": "commonjs", + "description": "Example using BraintrustSpanProcessor with OpenTelemetry NodeSDK (CommonJS)", + "main": "nodesdk_example.js", + "scripts": { + "build": "npx tsup --config tsup.config.ts && (tsc --project tsconfig.json --outDir . || exit 0)", + "start": "node dist/nodesdk_example.js" + }, + "dependencies": { + "openai": "^4.73.1", + "braintrust": "latest", + "@opentelemetry/api": "^1.9.0", + "@opentelemetry/context-async-hooks": "^1.28.0", + "@opentelemetry/exporter-trace-otlp-http": "^0.54.2", + "@opentelemetry/resources": "^1.28.0", + "@opentelemetry/sdk-trace-base": "^1.28.0", + "@opentelemetry/sdk-trace-node": "^1.28.0", + "@opentelemetry/semantic-conventions": "^1.28.0", + "@opentelemetry/sdk-node": "^0.54.2" + }, + "devDependencies": { + "@types/node": "^14.18.0", + "tsup": "^6.7.0", + "typescript": "^5.4.4" + } +} diff --git a/js/examples/otel/package-lock.json b/js/examples/otel/package-lock.json index 5ed6aaf39..d3c965c92 100644 --- a/js/examples/otel/package-lock.json +++ b/js/examples/otel/package-lock.json @@ -17,6 +17,7 @@ "@opentelemetry/sdk-trace-node": "^2.0.1", "@opentelemetry/semantic-conventions": "^1.36.0", "@traceloop/instrumentation-openai": "^0.14.0", + "braintrust": "latest", "openai": "^4.73.1", "tsx": "^4.19.2" }, @@ -25,10 +26,22 @@ "typescript": "^5.4.4" } }, + "node_modules/@ai-sdk/provider": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@ai-sdk/provider/-/provider-1.1.3.tgz", + "integrity": "sha512-qZMxYJ0qqX/RfnuIaab+zp8UAeJn/ygXXAffR5I4N0n1IrvA6qBsjc8hXLmBiMV2zoXlifkacF7sEFnYnjBcqg==", + "license": "Apache-2.0", + "dependencies": { + "json-schema": "^0.4.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.6.tgz", - "integrity": "sha512-ShbM/3XxwuxjFiuVBHA+d3j5dyac0aEVVq1oluIDf71hUw0aRF59dV/efUsIwFnR6m8JNM2FjZOzmaZ8yG61kw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.12.tgz", + "integrity": "sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==", "cpu": [ "ppc64" ], @@ -42,9 +55,9 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.6.tgz", - "integrity": "sha512-S8ToEOVfg++AU/bHwdksHNnyLyVM+eMVAOf6yRKFitnwnbwwPNqKr3srzFRe7nzV69RQKb5DgchIX5pt3L53xg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.12.tgz", + "integrity": "sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==", "cpu": [ "arm" ], @@ -58,9 +71,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.6.tgz", - "integrity": "sha512-hd5zdUarsK6strW+3Wxi5qWws+rJhCCbMiC9QZyzoxfk5uHRIE8T287giQxzVpEvCwuJ9Qjg6bEjcRJcgfLqoA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.12.tgz", + "integrity": "sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==", "cpu": [ "arm64" ], @@ -74,9 +87,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.6.tgz", - "integrity": "sha512-0Z7KpHSr3VBIO9A/1wcT3NTy7EB4oNC4upJ5ye3R7taCc2GUdeynSLArnon5G8scPwaU866d3H4BCrE5xLW25A==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.12.tgz", + "integrity": "sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==", "cpu": [ "x64" ], @@ -90,9 +103,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.6.tgz", - "integrity": "sha512-FFCssz3XBavjxcFxKsGy2DYK5VSvJqa6y5HXljKzhRZ87LvEi13brPrf/wdyl/BbpbMKJNOr1Sd0jtW4Ge1pAA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz", + "integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==", "cpu": [ "arm64" ], @@ -106,9 +119,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.6.tgz", - "integrity": "sha512-GfXs5kry/TkGM2vKqK2oyiLFygJRqKVhawu3+DOCk7OxLy/6jYkWXhlHwOoTb0WqGnWGAS7sooxbZowy+pK9Yg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.12.tgz", + "integrity": "sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==", "cpu": [ "x64" ], @@ -122,9 +135,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.6.tgz", - "integrity": "sha512-aoLF2c3OvDn2XDTRvn8hN6DRzVVpDlj2B/F66clWd/FHLiHaG3aVZjxQX2DYphA5y/evbdGvC6Us13tvyt4pWg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.12.tgz", + "integrity": "sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==", "cpu": [ "arm64" ], @@ -138,9 +151,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.6.tgz", - "integrity": "sha512-2SkqTjTSo2dYi/jzFbU9Plt1vk0+nNg8YC8rOXXea+iA3hfNJWebKYPs3xnOUf9+ZWhKAaxnQNUf2X9LOpeiMQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.12.tgz", + "integrity": "sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==", "cpu": [ "x64" ], @@ -154,9 +167,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.6.tgz", - "integrity": "sha512-SZHQlzvqv4Du5PrKE2faN0qlbsaW/3QQfUUc6yO2EjFcA83xnwm91UbEEVx4ApZ9Z5oG8Bxz4qPE+HFwtVcfyw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.12.tgz", + "integrity": "sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==", "cpu": [ "arm" ], @@ -170,9 +183,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.6.tgz", - "integrity": "sha512-b967hU0gqKd9Drsh/UuAm21Khpoh6mPBSgz8mKRq4P5mVK8bpA+hQzmm/ZwGVULSNBzKdZPQBRT3+WuVavcWsQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.12.tgz", + "integrity": "sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==", "cpu": [ "arm64" ], @@ -186,9 +199,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.6.tgz", - "integrity": "sha512-aHWdQ2AAltRkLPOsKdi3xv0mZ8fUGPdlKEjIEhxCPm5yKEThcUjHpWB1idN74lfXGnZ5SULQSgtr5Qos5B0bPw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.12.tgz", + "integrity": "sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==", "cpu": [ "ia32" ], @@ -202,9 +215,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.6.tgz", - "integrity": "sha512-VgKCsHdXRSQ7E1+QXGdRPlQ/e08bN6WMQb27/TMfV+vPjjTImuT9PmLXupRlC90S1JeNNW5lzkAEO/McKeJ2yg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.12.tgz", + "integrity": "sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==", "cpu": [ "loong64" ], @@ -218,9 +231,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.6.tgz", - "integrity": "sha512-WViNlpivRKT9/py3kCmkHnn44GkGXVdXfdc4drNmRl15zVQ2+D2uFwdlGh6IuK5AAnGTo2qPB1Djppj+t78rzw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.12.tgz", + "integrity": "sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==", "cpu": [ "mips64el" ], @@ -234,9 +247,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.6.tgz", - "integrity": "sha512-wyYKZ9NTdmAMb5730I38lBqVu6cKl4ZfYXIs31Baf8aoOtB4xSGi3THmDYt4BTFHk7/EcVixkOV2uZfwU3Q2Jw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.12.tgz", + "integrity": "sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==", "cpu": [ "ppc64" ], @@ -250,9 +263,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.6.tgz", - "integrity": "sha512-KZh7bAGGcrinEj4qzilJ4hqTY3Dg2U82c8bv+e1xqNqZCrCyc+TL9AUEn5WGKDzm3CfC5RODE/qc96OcbIe33w==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.12.tgz", + "integrity": "sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==", "cpu": [ "riscv64" ], @@ -266,9 +279,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.6.tgz", - "integrity": "sha512-9N1LsTwAuE9oj6lHMyyAM+ucxGiVnEqUdp4v7IaMmrwb06ZTEVCIs3oPPplVsnjPfyjmxwHxHMF8b6vzUVAUGw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.12.tgz", + "integrity": "sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==", "cpu": [ "s390x" ], @@ -282,9 +295,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.6.tgz", - "integrity": "sha512-A6bJB41b4lKFWRKNrWoP2LHsjVzNiaurf7wyj/XtFNTsnPuxwEBWHLty+ZE0dWBKuSK1fvKgrKaNjBS7qbFKig==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.12.tgz", + "integrity": "sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==", "cpu": [ "x64" ], @@ -298,9 +311,9 @@ } }, "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.6.tgz", - "integrity": "sha512-IjA+DcwoVpjEvyxZddDqBY+uJ2Snc6duLpjmkXm/v4xuS3H+3FkLZlDm9ZsAbF9rsfP3zeA0/ArNDORZgrxR/Q==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.12.tgz", + "integrity": "sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==", "cpu": [ "arm64" ], @@ -314,9 +327,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.6.tgz", - "integrity": "sha512-dUXuZr5WenIDlMHdMkvDc1FAu4xdWixTCRgP7RQLBOkkGgwuuzaGSYcOpW4jFxzpzL1ejb8yF620UxAqnBrR9g==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.12.tgz", + "integrity": "sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==", "cpu": [ "x64" ], @@ -330,9 +343,9 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.6.tgz", - "integrity": "sha512-l8ZCvXP0tbTJ3iaqdNf3pjaOSd5ex/e6/omLIQCVBLmHTlfXW3zAxQ4fnDmPLOB1x9xrcSi/xtCWFwCZRIaEwg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.12.tgz", + "integrity": "sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==", "cpu": [ "arm64" ], @@ -346,9 +359,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.6.tgz", - "integrity": "sha512-hKrmDa0aOFOr71KQ/19JC7az1P0GWtCN1t2ahYAf4O007DHZt/dW8ym5+CUdJhQ/qkZmI1HAF8KkJbEFtCL7gw==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.12.tgz", + "integrity": "sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==", "cpu": [ "x64" ], @@ -362,9 +375,9 @@ } }, "node_modules/@esbuild/openharmony-arm64": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.6.tgz", - "integrity": "sha512-+SqBcAWoB1fYKmpWoQP4pGtx+pUUC//RNYhFdbcSA16617cchuryuhOCRpPsjCblKukAckWsV+aQ3UKT/RMPcA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.12.tgz", + "integrity": "sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==", "cpu": [ "arm64" ], @@ -378,9 +391,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.6.tgz", - "integrity": "sha512-dyCGxv1/Br7MiSC42qinGL8KkG4kX0pEsdb0+TKhmJZgCUDBGmyo1/ArCjNGiOLiIAgdbWgmWgib4HoCi5t7kA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.12.tgz", + "integrity": "sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==", "cpu": [ "x64" ], @@ -394,9 +407,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.6.tgz", - "integrity": "sha512-42QOgcZeZOvXfsCBJF5Afw73t4veOId//XD3i+/9gSkhSV6Gk3VPlWncctI+JcOyERv85FUo7RxuxGy+z8A43Q==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.12.tgz", + "integrity": "sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==", "cpu": [ "arm64" ], @@ -410,9 +423,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.6.tgz", - "integrity": "sha512-4AWhgXmDuYN7rJI6ORB+uU9DHLq/erBbuMoAuB4VWJTu5KtCgcKYPynF0YI1VkBNuEfjNlLrFr9KZPJzrtLkrQ==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.12.tgz", + "integrity": "sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==", "cpu": [ "ia32" ], @@ -426,9 +439,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.6.tgz", - "integrity": "sha512-NgJPHHbEpLQgDH2MjQu90pzW/5vvXIZ7KOnPyNBm92A6WgZ/7b6fJyUBjoumLqeOQQGqY2QjQxRo97ah4Sj0cA==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.12.tgz", + "integrity": "sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==", "cpu": [ "x64" ], @@ -482,6 +495,27 @@ "url": "https://opencollective.com/js-sdsl" } }, + "node_modules/@kwsites/file-exists": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", + "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==", + "license": "MIT", + "dependencies": { + "debug": "^4.1.1" + } + }, + "node_modules/@kwsites/promise-deferred": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", + "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==", + "license": "MIT" + }, + "node_modules/@next/env": { + "version": "14.2.33", + "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.33.tgz", + "integrity": "sha512-CgVHNZ1fRIlxkLhIX22flAZI/HmpDaZ8vwyJ/B0SDPTBuLZ1PJ+DWMjCHhqnExfmSQzA/PbZi8OAc7PAq2w9IA==", + "license": "MIT" + }, "node_modules/@opentelemetry/api": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.0.tgz", @@ -2075,6 +2109,23 @@ "@types/node": "*" } }, + "node_modules/@vercel/functions": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@vercel/functions/-/functions-1.6.0.tgz", + "integrity": "sha512-R6FKQrYT5MZs5IE1SqeCJWxMuBdHawFcCZboKKw8p7s+6/mcd55Gx6tWmyKnQTyrSEA04NH73Tc9CbqpEle8RA==", + "license": "Apache-2.0", + "engines": { + "node": ">= 16" + }, + "peerDependencies": { + "@aws-sdk/credential-provider-web-identity": "*" + }, + "peerDependenciesMeta": { + "@aws-sdk/credential-provider-web-identity": { + "optional": true + } + } + }, "node_modules/abort-controller": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", @@ -2087,6 +2138,19 @@ "node": ">=6.5" } }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/acorn": { "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", @@ -2153,12 +2217,30 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "license": "Python-2.0" + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==", + "license": "MIT" + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "license": "MIT" }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, "node_modules/base64-js": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", @@ -2188,6 +2270,99 @@ "node": "*" } }, + "node_modules/body-parser": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braintrust": { + "version": "0.4.9", + "resolved": "https://registry.npmjs.org/braintrust/-/braintrust-0.4.9.tgz", + "integrity": "sha512-Gyd2Zp/KoWZ26DV/rl+j2TzVR3TCPMFwrUOwTqTt+GN+oqxO1v/SR9pUFovc7TuJdsLzPp0pw0svm7NN10XnDw==", + "license": "MIT", + "dependencies": { + "@ai-sdk/provider": "^1.1.3", + "@next/env": "^14.2.3", + "@vercel/functions": "^1.0.2", + "argparse": "^2.0.1", + "chalk": "^4.1.2", + "cli-progress": "^3.12.0", + "cors": "^2.8.5", + "dotenv": "^16.4.5", + "esbuild": "^0.25.10", + "eventsource-parser": "^1.1.2", + "express": "^4.21.2", + "graceful-fs": "^4.2.11", + "http-errors": "^2.0.0", + "minimatch": "^9.0.3", + "mustache": "^4.2.0", + "pluralize": "^8.0.0", + "simple-git": "^3.21.0", + "slugify": "^1.6.6", + "source-map": "^0.7.4", + "uuid": "^9.0.1", + "zod": "^3.25.34", + "zod-to-json-schema": "^3.22.5" + }, + "bin": { + "braintrust": "dist/cli.js" + }, + "peerDependencies": { + "zod": "^3.25.34" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", @@ -2201,12 +2376,56 @@ "node": ">= 0.4" } }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/cjs-module-lexer": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz", "integrity": "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==", "license": "MIT" }, + "node_modules/cli-progress": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/cli-progress/-/cli-progress-3.12.0.tgz", + "integrity": "sha512-tRkV3HJ1ASwm19THiiLIXLO7Im7wlTuKnvkYaTkyoAPefqjNg7W7DHKUlGRxy9vxDvbyCYQkQozvptuMkGCg8A==", + "license": "MIT", + "dependencies": { + "string-width": "^4.2.3" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/cliui": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", @@ -2251,6 +2470,55 @@ "node": ">= 0.8" } }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", + "license": "MIT" + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, "node_modules/debug": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", @@ -2277,6 +2545,37 @@ "node": ">=0.4.0" } }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/dotenv": { + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", + "integrity": "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -2291,12 +2590,27 @@ "node": ">= 0.4" } }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "license": "MIT" }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/es-define-property": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", @@ -2343,9 +2657,9 @@ } }, "node_modules/esbuild": { - "version": "0.25.6", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.6.tgz", - "integrity": "sha512-GVuzuUwtdsghE3ocJ9Bs8PNoF13HNQ5TXbEi2AhvVb8xU1Iwt9Fos9FEamfoee+u/TOsn7GUWc04lz46n2bbTg==", + "version": "0.25.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz", + "integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==", "hasInstallScript": true, "license": "MIT", "bin": { @@ -2355,32 +2669,32 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.6", - "@esbuild/android-arm": "0.25.6", - "@esbuild/android-arm64": "0.25.6", - "@esbuild/android-x64": "0.25.6", - "@esbuild/darwin-arm64": "0.25.6", - "@esbuild/darwin-x64": "0.25.6", - "@esbuild/freebsd-arm64": "0.25.6", - "@esbuild/freebsd-x64": "0.25.6", - "@esbuild/linux-arm": "0.25.6", - "@esbuild/linux-arm64": "0.25.6", - "@esbuild/linux-ia32": "0.25.6", - "@esbuild/linux-loong64": "0.25.6", - "@esbuild/linux-mips64el": "0.25.6", - "@esbuild/linux-ppc64": "0.25.6", - "@esbuild/linux-riscv64": "0.25.6", - "@esbuild/linux-s390x": "0.25.6", - "@esbuild/linux-x64": "0.25.6", - "@esbuild/netbsd-arm64": "0.25.6", - "@esbuild/netbsd-x64": "0.25.6", - "@esbuild/openbsd-arm64": "0.25.6", - "@esbuild/openbsd-x64": "0.25.6", - "@esbuild/openharmony-arm64": "0.25.6", - "@esbuild/sunos-x64": "0.25.6", - "@esbuild/win32-arm64": "0.25.6", - "@esbuild/win32-ia32": "0.25.6", - "@esbuild/win32-x64": "0.25.6" + "@esbuild/aix-ppc64": "0.25.12", + "@esbuild/android-arm": "0.25.12", + "@esbuild/android-arm64": "0.25.12", + "@esbuild/android-x64": "0.25.12", + "@esbuild/darwin-arm64": "0.25.12", + "@esbuild/darwin-x64": "0.25.12", + "@esbuild/freebsd-arm64": "0.25.12", + "@esbuild/freebsd-x64": "0.25.12", + "@esbuild/linux-arm": "0.25.12", + "@esbuild/linux-arm64": "0.25.12", + "@esbuild/linux-ia32": "0.25.12", + "@esbuild/linux-loong64": "0.25.12", + "@esbuild/linux-mips64el": "0.25.12", + "@esbuild/linux-ppc64": "0.25.12", + "@esbuild/linux-riscv64": "0.25.12", + "@esbuild/linux-s390x": "0.25.12", + "@esbuild/linux-x64": "0.25.12", + "@esbuild/netbsd-arm64": "0.25.12", + "@esbuild/netbsd-x64": "0.25.12", + "@esbuild/openbsd-arm64": "0.25.12", + "@esbuild/openbsd-x64": "0.25.12", + "@esbuild/openharmony-arm64": "0.25.12", + "@esbuild/sunos-x64": "0.25.12", + "@esbuild/win32-arm64": "0.25.12", + "@esbuild/win32-ia32": "0.25.12", + "@esbuild/win32-x64": "0.25.12" } }, "node_modules/escalade": { @@ -2392,6 +2706,21 @@ "node": ">=6" } }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/event-target-shim": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", @@ -2401,12 +2730,115 @@ "node": ">=6" } }, + "node_modules/eventsource-parser": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-1.1.2.tgz", + "integrity": "sha512-v0eOBUbiaFojBu2s2NPBfYUoRR9GjcDNvCXVaqEf5vVfpIAh9f8RCo4vXTP8c63QRKCFwoLpMpTdPwwhEKVgzA==", + "license": "MIT", + "engines": { + "node": ">=14.18" + } + }, + "node_modules/express": { + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "license": "MIT", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.3", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.12", + "proxy-addr": "~2.0.7", + "qs": "6.13.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.19.0", + "serve-static": "1.16.2", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, "node_modules/extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "license": "MIT" }, + "node_modules/finalhandler": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, "node_modules/form-data": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", @@ -2442,12 +2874,30 @@ "node": ">= 12.20" } }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/forwarded-parse": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/forwarded-parse/-/forwarded-parse-2.1.2.tgz", "integrity": "sha512-alTFZZQDKMporBH77856pXgzhEzaUVmLCDk+egLgIgHst3Tpndzz8MnKe+GzRJRfvVdn69HhpW7cmXzvtLvJAw==", "license": "MIT" }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -2580,6 +3030,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/has-symbols": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", @@ -2619,6 +3084,22 @@ "node": ">= 0.4" } }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/https-proxy-agent": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", @@ -2641,6 +3122,18 @@ "ms": "^2.0.0" } }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/import-in-the-middle": { "version": "1.14.2", "resolved": "https://registry.npmjs.org/import-in-the-middle/-/import-in-the-middle-1.14.2.tgz", @@ -2653,6 +3146,21 @@ "module-details-from-path": "^1.0.3" } }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/is-core-module": { "version": "2.16.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", @@ -2707,6 +3215,12 @@ "bignumber.js": "^9.0.0" } }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "license": "(AFL-2.1 OR BSD-3-Clause)" + }, "node_modules/lodash.camelcase": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", @@ -2728,6 +3242,45 @@ "node": ">= 0.4" } }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -2749,6 +3302,21 @@ "node": ">= 0.6" } }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/module-details-from-path": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/module-details-from-path/-/module-details-from-path-1.0.4.tgz", @@ -2761,6 +3329,24 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, + "node_modules/mustache": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", + "license": "MIT", + "bin": { + "mustache": "bin/mustache" + } + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/node-domexception": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", @@ -2801,6 +3387,39 @@ } } }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/openai": { "version": "4.104.0", "resolved": "https://registry.npmjs.org/openai/-/openai-4.104.0.tgz", @@ -2846,12 +3465,27 @@ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "license": "MIT" }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "license": "MIT" }, + "node_modules/path-to-regexp": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==", + "license": "MIT" + }, "node_modules/pg-int8": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", @@ -2883,6 +3517,15 @@ "node": ">=4" } }, + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/postgres-array": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", @@ -2946,6 +3589,58 @@ "node": ">=12.0.0" } }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/qs": { + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.0.6" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -2998,6 +3693,32 @@ "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" } }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, "node_modules/semver": { "version": "7.7.2", "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", @@ -3010,12 +3731,195 @@ "node": ">=10" } }, + "node_modules/send": { + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", + "license": "MIT", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" + }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/serve-static": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", + "license": "MIT", + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.19.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, "node_modules/shimmer": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/shimmer/-/shimmer-1.2.1.tgz", "integrity": "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==", "license": "BSD-2-Clause" }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/simple-git": { + "version": "3.30.0", + "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.30.0.tgz", + "integrity": "sha512-q6lxyDsCmEal/MEGhP1aVyQ3oxnagGlBDOVSIB4XUVLl1iZh0Pah6ebC9V4xBap/RfgP2WlI8EKs0WS0rMEJHg==", + "license": "MIT", + "dependencies": { + "@kwsites/file-exists": "^1.1.1", + "@kwsites/promise-deferred": "^1.1.1", + "debug": "^4.4.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/steveukx/git-js?sponsor=1" + } + }, + "node_modules/slugify": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.6.6.tgz", + "integrity": "sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw==", + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/string-width": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", @@ -3042,6 +3946,18 @@ "node": ">=8" } }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", @@ -3054,6 +3970,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, "node_modules/tr46": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", @@ -3085,6 +4010,19 @@ "fsevents": "~2.3.3" } }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/typescript": { "version": "5.8.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", @@ -3105,6 +4043,24 @@ "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", "license": "MIT" }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/uuid": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", @@ -3118,6 +4074,15 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/web-streams-polyfill": { "version": "4.0.0-beta.3", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", @@ -3204,6 +4169,24 @@ "engines": { "node": ">=12" } + }, + "node_modules/zod": { + "version": "3.25.76", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz", + "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "node_modules/zod-to-json-schema": { + "version": "3.24.6", + "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.6.tgz", + "integrity": "sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==", + "license": "ISC", + "peerDependencies": { + "zod": "^3.24.1" + } } } } diff --git a/js/examples/otel/package.json b/js/examples/otel/package.json index f1c71026c..c59b9ab8a 100644 --- a/js/examples/otel/package.json +++ b/js/examples/otel/package.json @@ -4,7 +4,8 @@ "description": "Example using BraintrustSpanProcessor with OpenTelemetry NodeSDK", "main": "nodesdk_example.ts", "scripts": { - "start": "tsx nodesdk_example.ts" + "start": "tsx nodesdk_example.ts", + "sdk-example": "tsx nodesdk_example.ts" }, "dependencies": { "@traceloop/instrumentation-openai": "^0.14.0", @@ -17,7 +18,8 @@ "@opentelemetry/sdk-trace-node": "^2.0.1", "@opentelemetry/semantic-conventions": "^1.36.0", "openai": "^4.73.1", - "tsx": "^4.19.2" + "tsx": "^4.19.2", + "braintrust": "latest" }, "devDependencies": { "@types/node": "^20.10.5", diff --git a/js/examples/otel/tsconfig-cjs.json b/js/examples/otel/tsconfig-cjs.json new file mode 100644 index 000000000..6e80cea5f --- /dev/null +++ b/js/examples/otel/tsconfig-cjs.json @@ -0,0 +1,20 @@ +{ + "$comment": "This is the CommonJS tsconfig used by .github/workflows/js-sdk-node-example.yaml", + "compilerOptions": { + "module": "CommonJS", + "moduleResolution": "node", + "target": "ES2020", + "lib": ["ES2020"], + "esModuleInterop": true, + "skipLibCheck": true, + "allowSyntheticDefaultImports": true, + "resolveJsonModule": true, + "declaration": false, + "sourceMap": false, + "noEmitOnError": false, + "strict": false, + "noImplicitAny": false + }, + "include": ["nodesdk_example.ts"], + "exclude": ["node_modules"] +} diff --git a/js/examples/otel/tsup.config.ts b/js/examples/otel/tsup.config.ts new file mode 100644 index 000000000..826c7bb76 --- /dev/null +++ b/js/examples/otel/tsup.config.ts @@ -0,0 +1,14 @@ +import { defineConfig } from "tsup"; + +export default defineConfig({ + entry: ["nodesdk_example.ts"], + format: ["cjs", "esm"], + target: "node14", + outDir: "dist", + clean: true, + splitting: false, + sourcemap: false, + minify: false, + dts: false, + noExternal: [/.*/], +}); diff --git a/js/src/wrappers/anthropic.test.ts b/js/src/wrappers/anthropic.test.ts deleted file mode 100644 index e88883406..000000000 --- a/js/src/wrappers/anthropic.test.ts +++ /dev/null @@ -1,586 +0,0 @@ -import { - test, - expect, - describe, - beforeEach, - beforeAll, - afterEach, - vi, - assert, -} from "vitest"; -import Anthropic from "@anthropic-ai/sdk"; -import { wrapAnthropic } from "./anthropic"; -import { initLogger, _exportsForTestingOnly, Attachment } from "../logger"; -import { configureNode } from "../node"; -import { getCurrentUnixTimestamp } from "../util"; - -// use the cheapest model for tests -const TEST_MODEL = "claude-3-haiku-20240307"; - -interface TextBlock { - type: "text"; - text: string; -} - -interface Message { - content: TextBlock[]; - role: string; - id: string; - usage: { - input_tokens: number; - output_tokens: number; - cache_creation_input_tokens?: number; - cache_read_input_tokens?: number; - }; -} - -try { - configureNode(); -} catch (e) { - // FIXME[matt] have a better of way of initializing brainstrust state once per process. -} - -test("anthropic is installed", () => { - expect(Anthropic).toBeDefined(); -}); - -describe("anthropic client unit tests", { retry: 3 }, () => { - let anthropic: Anthropic; - let client: any; - let backgroundLogger: any; - let logger: any; - - // fake login before we test. once is enough. - beforeAll(async () => { - await _exportsForTestingOnly.simulateLoginForTests(); - }); - - beforeEach(async () => { - backgroundLogger = _exportsForTestingOnly.useTestBackgroundLogger(); - - anthropic = new Anthropic(); - client = wrapAnthropic(anthropic); - - logger = initLogger({ - projectName: "anthropic.test.ts", - projectId: "test-project-id", - }); - }); - - afterEach(() => { - _exportsForTestingOnly.clearTestBackgroundLogger(); - }); - - test("test client.messages.create works with system text blocks", async (context) => { - expect(await backgroundLogger.drain()).toHaveLength(0); - - const system: Record[] = [ - { text: "translate to english", type: "text" }, - { text: "remove all punctuation", type: "text" }, - { text: "only the answer, no other text", type: "text" }, - ]; - const response = await client.messages.create({ - model: TEST_MODEL, - messages: [{ role: "user", content: "Bonjour mon ami!" }], - max_tokens: 20, - system: system, - temperature: 0.01, - }); - expect(response).toBeDefined(); - - const spans = await backgroundLogger.drain(); - expect(spans).toHaveLength(1); - const span = spans[0] as any; - expect(span["span_attributes"].name).toBe("anthropic.messages.create"); - expect(span.input).toBeDefined(); - const inputsByRole: Record = {}; - for (const msg of span.input) { - inputsByRole[msg["role"]] = msg; - } - const userInput = inputsByRole["user"]; - expect(userInput).toBeDefined(); - const systemInput = inputsByRole["system"]; - expect(systemInput.role).toEqual("system"); - expect(systemInput.content).toEqual(system); - }); - - test("test client.messages.stream", async (context) => { - expect(await backgroundLogger.drain()).toHaveLength(0); - - const onMessage = vi.fn(); - - const stream = client.messages - .stream({ - messages: [{ role: "user", content: "tell me about old pond haiku" }], - system: "no punctuation", - model: TEST_MODEL, - max_tokens: 200, - temperature: 0.01, - }) - .on("message", onMessage); - - for await (const event of stream) { - // console.log(event); - } - const message = await stream.finalMessage(); - // just making sure we don't break the API. - expect(onMessage).toHaveBeenCalledTimes(1); - - expect(message.content[0].type).toBe("text"); - const content = message.content[0] as unknown; - if (typeof content === "object" && content !== null && "text" in content) { - expect(content.text).toContain("old pond"); - } else { - throw new Error("Content is not a text block"); - } - - const spans = await backgroundLogger.drain(); - - expect(spans).toHaveLength(1); - const span = spans[0] as any; - expect(span["span_attributes"].name).toBe("anthropic.messages.create"); - const metrics = span.metrics; - expect(metrics).toBeDefined(); - expect(metrics.start).toBeDefined(); - expect(metrics.end).toBeDefined(); - expect(metrics.time_to_first_token).toBeDefined(); - expect(metrics.prompt_tokens).toBeGreaterThan(0); - expect(metrics.completion_tokens).toBeGreaterThan(0); - expect(metrics.tokens).toBeDefined(); - }); - - // TODO[matt] - test("test with tools", async (context) => { - // TODO[matt] - context.skip(); - }); - - test("test client.message.create with stream=true", async () => { - const startTime = getCurrentUnixTimestamp(); - const response = await client.messages.create({ - model: TEST_MODEL, - messages: [ - { - role: "user", - content: "What is Shakespeare's sonnet 18?", - }, - ], - max_tokens: 1000, - system: - "No punctuation, newlines or non-alphanumeric characters. Just the poem.", - temperature: 0.01, - stream: true, - }); - - let ttft = 0; - for await (const event of response) { - if (ttft === 0) { - ttft = getCurrentUnixTimestamp() - startTime; - } - } - - const endTime = getCurrentUnixTimestamp(); - - // check that the background logger got the log - const spans = await backgroundLogger.drain(); - expect(spans).toHaveLength(1); - const span = spans[0] as any; - expect(span.input).toBeDefined(); - - // clean up the output to make it easier to spot check - const output = span.output - .toLowerCase() - .replace(/\n/g, " ") - .replace(/'/g, ""); - // Validate we collected all the text, so check the first, line, the last line - // and a few others too. - expect(output).toContain("shall i compare thee to a summers day"); - expect(output).toContain("too hot the eye of heaven shines"); - expect(output).toContain("so long as men can breathe or eyes can see"); - expect(output).toContain("so long lives this and this gives life to thee"); - - expect(span["span_attributes"].type).toBe("llm"); - expect(span["span_attributes"].name).toBe("anthropic.messages.create"); - const metrics = span.metrics; - expect(metrics).toBeDefined(); - - const pt = metrics["prompt_tokens"]; - const ct = metrics["completion_tokens"]; - const t = metrics["tokens"]; - - expect(pt).toBeGreaterThan(0); - expect(ct).toBeGreaterThan(0); - expect(t).toEqual(pt + ct); - expect(startTime <= metrics.start).toBe(true); - expect(metrics.start < metrics.end).toBe(true); - expect(metrics.end <= endTime).toBe(true); - expect(ttft).toBeGreaterThanOrEqual(metrics.time_to_first_token); - }); - - test("test client.messages.create basics", async () => { - const startTime = getCurrentUnixTimestamp(); - const response: Message = await client.messages.create({ - model: TEST_MODEL, - messages: [{ role: "user", content: "What's 4*4?" }], - max_tokens: 100, - system: "Return the result only.", - temperature: 0.5, - }); - expect(response).toBeDefined(); - - const endTime = getCurrentUnixTimestamp(); - - const content = response.content[0] as unknown; - if (typeof content === "object" && content !== null && "text" in content) { - expect(content.text).toContain("16"); - } else { - throw new Error("Content is not a text block"); - } - - const spans = await backgroundLogger.drain(); - expect(spans).toHaveLength(1); - const span = spans[0] as any; - expect(span["span_attributes"].type).toBe("llm"); - expect(span["span_attributes"].name).toBe("anthropic.messages.create"); - const metadata = span.metadata; - expect(metadata?.model).toBe(TEST_MODEL); - expect(metadata?.provider).toBe("anthropic"); - expect(metadata?.max_tokens).toBe(100); - expect(metadata["stop_reason"]).toBe("end_turn"); - expect(metadata["temperature"]).toBe(0.5); - expect(span?.input).toBeDefined(); - expect(span?.output).toBeDefined(); - const output = span.output.content[0].text; - expect(output).toContain("16"); - const metrics = span.metrics; - const usage = response.usage; - expect(metrics).toBeDefined(); - expect(metrics["prompt_tokens"]).toBe(usage.input_tokens); - expect(metrics["completion_tokens"]).toBe(usage.output_tokens); - expect(metrics["tokens"]).toBe(usage.input_tokens + usage.output_tokens); - expect(metrics.prompt_cache_creation_tokens).toBe( - usage.cache_creation_input_tokens, - ); - expect(metrics.prompt_cached_tokens).toBe(usage.cache_read_input_tokens); - expect(startTime <= metrics.start).toBe(true); - expect(metrics.start < metrics.end).toBe(true); - expect(metrics.end <= endTime).toBe(true); - }); - - test("test client.beta.messages.create", async () => { - let startTime: number = -1; - let endTime: number = -1; - - // wrapped has to be last so the timing test works - const clients = [anthropic, client]; - const responses = await Promise.all( - clients.map(async (c) => { - startTime = getCurrentUnixTimestamp(); - - const response = await c.beta.messages.create({ - model: TEST_MODEL, - messages: [{ role: "user", content: "What's 4*4?" }], - max_tokens: 100, - system: "Return the result only.", - temperature: 0.1, - }); - endTime = getCurrentUnixTimestamp(); - return response; - }), - ); - - // validate that the wrapped and unwrapped clients produce the same response - assertAnthropicResponsesEqual(responses); - - // validate we traced the second request - const spans = await backgroundLogger.drain(); - expect(spans).toHaveLength(1); - const span = spans[0] as any; - - expect(span).toMatchObject({ - project_id: expect.any(String), - log_id: expect.any(String), - created: expect.any(String), - span_id: expect.any(String), - root_span_id: expect.any(String), - span_attributes: { - type: "llm", - name: "anthropic.messages.create", - }, - metadata: { - model: TEST_MODEL, - provider: "anthropic", - max_tokens: 100, - temperature: 0.1, - }, - input: [ - { role: "user", content: "What's 4*4?" }, - { role: "system", content: "Return the result only." }, - ], - output: { - role: "assistant", - content: [{ type: "text", text: "16" }], - }, - metrics: { - prompt_tokens: expect.any(Number), - completion_tokens: expect.any(Number), - tokens: expect.any(Number), - start: expect.any(Number), - end: expect.any(Number), - }, - }); - - const { metrics } = span; - assertValidMetrics(metrics, startTime, endTime); - }); - - test("test client.beta.messages.create with stream=true", async () => { - let startTime: number = -1; - let endTime: number = -1; - - // wrapped has to be last so the timing test works - const clients = [anthropic, client]; - const responses = await Promise.all( - clients.map(async (c) => { - startTime = getCurrentUnixTimestamp(); - - const response = await c.beta.messages.create({ - model: TEST_MODEL, - messages: [{ role: "user", content: "What's 4*4?" }], - max_tokens: 100, - system: "Return the result only.", - temperature: 0.1, - stream: true, - }); - - let ttft = 0; - const chunks = []; - for await (const event of response) { - if (ttft === 0) { - ttft = getCurrentUnixTimestamp() - startTime; - } - chunks.push(event); - } - endTime = getCurrentUnixTimestamp(); - return chunks; - }), - ); - - // validate that the wrapped and unwrapped clients produce the same output - const messages = []; - const chunks = []; - for (const resp of responses) { - assert(resp.length >= 1); - const msg = resp[0]["message"]; - assert(msg); - messages.push(msg); - chunks.push(resp.slice(1)); - } - assertAnthropicResponsesEqual(messages); - expect(chunks[0]).toEqual(chunks[1]); - - // validate we traced the second request - const spans = await backgroundLogger.drain(); - expect(spans).toHaveLength(1); - const span = spans[0] as any; - - expect(span).toMatchObject({ - project_id: expect.any(String), - log_id: expect.any(String), - created: expect.any(String), - span_id: expect.any(String), - root_span_id: expect.any(String), - span_attributes: { - type: "llm", - name: "anthropic.messages.create", - }, - metadata: { - model: TEST_MODEL, - provider: "anthropic", - max_tokens: 100, - temperature: 0.1, - }, - input: [ - { role: "user", content: "What's 4*4?" }, - { role: "system", content: "Return the result only." }, - ], - output: expect.stringContaining("16"), - metrics: { - prompt_tokens: expect.any(Number), - completion_tokens: expect.any(Number), - tokens: expect.any(Number), - start: expect.any(Number), - end: expect.any(Number), - time_to_first_token: expect.any(Number), - }, - }); - - const { metrics } = span; - assertValidMetrics(metrics, startTime, endTime); - }); - - test("test client.beta.messages.stream", async () => { - let startTime: number = -1; - let endTime: number = -1; - - // wrapped has to be last so the timing test works - const clients = [anthropic, client]; - const responses = await Promise.all( - clients.map(async (c) => { - startTime = getCurrentUnixTimestamp(); - - const stream = c.beta.messages.stream({ - model: TEST_MODEL, - messages: [{ role: "user", content: "What's 4*4?" }], - max_tokens: 100, - system: "Return the result only.", - temperature: 0.1, - }); - - let ttft = 0; - let chunks = []; - for await (const event of stream) { - if (ttft === 0) { - ttft = getCurrentUnixTimestamp() - startTime; - } - chunks.push(event); - } - - endTime = getCurrentUnixTimestamp(); - return chunks; - }), - ); - - // validate that the wrapped and unwrapped clients produce the same output - const respRaw = responses[0]; - const respWrapped = responses[1]; - - assertAnthropicResponsesEqual([ - respRaw[0]["message"], - respWrapped[0]["message"], - ]); - - expect(respRaw.slice(1)).toEqual(respWrapped.slice(1)); - - // validate we traced the second request - const spans = await backgroundLogger.drain(); - expect(spans).toHaveLength(1); - const span = spans[0] as any; - - expect(span).toMatchObject({ - project_id: expect.any(String), - log_id: expect.any(String), - created: expect.any(String), - span_id: expect.any(String), - root_span_id: expect.any(String), - span_attributes: { - type: "llm", - name: "anthropic.messages.create", - }, - metadata: { - model: TEST_MODEL, - provider: "anthropic", - max_tokens: 100, - temperature: 0.1, - }, - input: [ - { role: "user", content: "What's 4*4?" }, - { role: "system", content: "Return the result only." }, - ], - output: expect.stringContaining("16"), - metrics: { - prompt_tokens: expect.any(Number), - completion_tokens: expect.any(Number), - tokens: expect.any(Number), - start: expect.any(Number), - end: expect.any(Number), - time_to_first_token: expect.any(Number), - }, - }); - - const { metrics } = span; - assertValidMetrics(metrics, startTime, endTime); - }); - - test("test base64 image conversion to attachments in input", async () => { - // Create a small test image (1x1 red pixel PNG) - const base64Image = - "iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8DwHwAFBQIAX8jx0gAAAABJRU5ErkJggg=="; - - const response = await client.messages.create({ - model: "claude-haiku-4-5-20251001", - messages: [ - { - role: "user", - content: [ - { - type: "image", - source: { - type: "base64", - media_type: "image/png", - data: base64Image, - }, - }, - { - type: "text", - text: "Describe this image in 3 words or less.", - }, - ], - }, - ], - max_tokens: 20, - temperature: 0.01, - }); - - expect(response).toBeDefined(); - expect(response.content).toBeDefined(); - - const spans = await backgroundLogger.drain(); - expect(spans).toHaveLength(1); - const span = spans[0] as any; - - // Verify that the input was processed - expect(span.input).toBeDefined(); - const userMessage = span.input.find((msg: any) => msg.role === "user"); - expect(userMessage).toBeDefined(); - expect(userMessage.content).toBeDefined(); - - // Find the image content block - const imageBlock = userMessage.content.find( - (block: any) => block.type === "image", - ); - expect(imageBlock).toBeDefined(); - expect(imageBlock.source).toBeDefined(); - - // Verify that the base64 data was replaced with an Attachment - expect(imageBlock.source.data).toBeInstanceOf(Attachment); - expect(imageBlock.source.data.reference.content_type).toBe("image/png"); - expect(imageBlock.source.data.reference.filename).toBe("image.png"); - }); -}); - -function assertAnthropicResponsesEqual(responses: Message[]) { - expect(responses.length).toBe(2); - const parsed = responses.map((r) => JSON.parse(JSON.stringify(r))); - for (const p of parsed) { - delete p.id; - } - expect(parsed[0]).toEqual(parsed[1]); -} - -function assertValidMetrics(metrics: any, start: number, end: number) { - expect(metrics).toBeDefined(); - expect(metrics.start).toBeDefined(); - expect(metrics.end).toBeDefined(); - //expect(metrics.time_to_first_token).toBeDefined(); - for (const [key, value] of Object.entries(metrics)) { - expect(value).toBeDefined(); - // if "tokens" is in key, it should be greater than 0 - if (key.includes("tokens")) { - expect(value).toBeGreaterThanOrEqual(0); - } - } - expect(start).toBeLessThanOrEqual(metrics.start); - expect(metrics.start).toBeLessThanOrEqual(metrics.end); - expect(metrics.end).toBeLessThanOrEqual(end); -} diff --git a/scripts/verify_cjs.sh b/scripts/verify_cjs.sh new file mode 100644 index 000000000..82a4fdb5d --- /dev/null +++ b/scripts/verify_cjs.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +node -e ' +if (typeof require === "undefined") { + console.error("Error: Not running in CommonJS"); + process.exit(1); +} else { + console.log("Running in CommonJS"); +} +' diff --git a/scripts/verify_esm.sh b/scripts/verify_esm.sh new file mode 100644 index 000000000..85b5eb0aa --- /dev/null +++ b/scripts/verify_esm.sh @@ -0,0 +1,9 @@ +#!/usr/bin/env bash +node -e ' +if (typeof import.meta.url !== "string") { + console.error("Error: Not running in ESM"); + process.exit(1); +} else { + console.log("Running in ESM"); +} +'