From ed2d6ee1421c301d4e99ecf5b4c17b3ba88d578c Mon Sep 17 00:00:00 2001 From: bntvllnt <32437578+bntvllnt@users.noreply.github.com> Date: Wed, 17 Jun 2026 23:02:08 +0200 Subject: [PATCH] chore(analytics): adopt @vllnt toolchain; drop mcp + demo packages - packages/convex-analytics: add @vllnt/eslint-config + @vllnt/typescript devDeps; tsconfig now extends @vllnt/typescript/node-library.json - remove packages/convex-analytics-mcp and the demo host package; strip their pnpm-workspace, ci.yml, publish.yml, .gitignore, eslint, and convex.json wiring - docs-sync: drop MCP + demo references from README, llms.txt, AGENTS.md, CLAUDE.md, CONTRIBUTING.md, quick-start.md, CHANGELOG.md; delete docs/mcp-tools.md; regenerate llms-full.txt --- .github/workflows/ci.yml | 7 +- .github/workflows/publish.yml | 16 - .gitignore | 1 - AGENTS.md | 5 +- CHANGELOG.md | 2 - CLAUDE.md | 5 +- CONTRIBUTING.md | 3 +- README.md | 13 +- demo/.gitignore | 2 - demo/convex/convex.config.ts | 6 - demo/convex/example.ts | 118 ---- demo/convex/tsconfig.json | 25 - demo/package.json | 13 - docs/mcp-tools.md | 70 --- docs/quick-start.md | 12 +- eslint.config.js | 1 - llms-full.txt | 118 +--- llms.txt | 5 - packages/convex-analytics-mcp/package.json | 35 -- packages/convex-analytics-mcp/src/server.ts | 449 -------------- .../convex-analytics-mcp/tests/mcp.test.ts | 118 ---- packages/convex-analytics-mcp/tsconfig.json | 18 - .../convex-analytics-mcp/vitest.config.ts | 8 - packages/convex-analytics/convex.json | 6 - packages/convex-analytics/package.json | 2 + .../scripts/generate-llms.mjs | 1 - packages/convex-analytics/tsconfig.json | 1 + pnpm-lock.yaml | 567 +----------------- pnpm-workspace.yaml | 1 - 29 files changed, 43 insertions(+), 1585 deletions(-) delete mode 100644 demo/.gitignore delete mode 100644 demo/convex/convex.config.ts delete mode 100644 demo/convex/example.ts delete mode 100644 demo/convex/tsconfig.json delete mode 100644 demo/package.json delete mode 100644 docs/mcp-tools.md delete mode 100644 packages/convex-analytics-mcp/package.json delete mode 100644 packages/convex-analytics-mcp/src/server.ts delete mode 100644 packages/convex-analytics-mcp/tests/mcp.test.ts delete mode 100644 packages/convex-analytics-mcp/tsconfig.json delete mode 100644 packages/convex-analytics-mcp/vitest.config.ts delete mode 100644 packages/convex-analytics/convex.json diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aa7c604..3844118 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -26,14 +26,11 @@ jobs: - name: Lint (core) run: pnpm --filter @vllnt/convex-analytics lint - - name: Typecheck (core + mcp) - run: pnpm --filter @vllnt/convex-analytics typecheck && pnpm --filter convex-analytics-mcp typecheck + - name: Typecheck (core) + run: pnpm --filter @vllnt/convex-analytics typecheck - name: Test core (100% coverage) run: pnpm --filter @vllnt/convex-analytics test:coverage - - name: Test mcp - run: pnpm --filter convex-analytics-mcp test - - name: Build (core) run: pnpm --filter @vllnt/convex-analytics build diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 7cebb28..8d15f8c 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -43,9 +43,7 @@ jobs: - run: pnpm install --frozen-lockfile - run: pnpm --filter @vllnt/convex-analytics lint - run: pnpm --filter @vllnt/convex-analytics typecheck - - run: pnpm --filter convex-analytics-mcp typecheck - run: pnpm --filter @vllnt/convex-analytics test:coverage - - run: pnpm --filter convex-analytics-mcp test - run: pnpm build canary: @@ -80,20 +78,6 @@ jobs: # returns 401 under OIDC — so @latest is left untouched. Install the newest canary # with `npm i @vllnt/convex-analytics@canary`. npx -y npm@11 publish --tag canary --provenance --access public --ignore-scripts - - name: Publish canary — convex-analytics-mcp - # Best-effort: the secondary MCP package needs its own npm Trusted Publisher - # configured before OIDC publish works. Don't fail the canary on it — the - # component (above) is the deliverable. - continue-on-error: true - working-directory: packages/convex-analytics-mcp - run: | - sed -i '/_authToken/d' "$NPM_CONFIG_USERCONFIG" 2>/dev/null || true - unset NODE_AUTH_TOKEN - BASE_VERSION=$(node -p "require('./package.json').version") - SHORT_SHA=$(echo "$GITHUB_SHA" | cut -c1-7) - CANARY="${BASE_VERSION}-canary.${SHORT_SHA}" - npm version "$CANARY" --no-git-tag-version --ignore-scripts - npx -y npm@11 publish --tag canary --provenance --access public --ignore-scripts release: name: Publish Release diff --git a/.gitignore b/.gitignore index 66da506..963e7b3 100644 --- a/.gitignore +++ b/.gitignore @@ -5,7 +5,6 @@ dist/ !.env.example # Ignore app _generated but NOT component _generated (needed for convex-test) convex/_generated/ -demo/convex/_generated/ .turbo/ *.tsbuildinfo coverage/ diff --git a/AGENTS.md b/AGENTS.md index b8080d2..b7306e8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -6,7 +6,7 @@ Any event, any dimension, any domain. Follows the vllnt Component Standard (see ## Package structure -This repo is a small monorepo (turbo): the core component, an MCP server, and a demo host. +This repo is a small monorepo (turbo) holding the core analytics component. ``` packages/ @@ -27,8 +27,6 @@ packages/ internal_mutations.ts # crons: prune, closeSessions; backfill http.ts # five generic x-api-key REST routes validators.ts # shared validators (typed scalar props — no v.any()) - convex-analytics-mcp/ # MCP server (npm: convex-analytics-mcp) — 7 tools -demo/convex/ # host harness (convex.config.ts + example.ts) — exercises the client ``` ## Ownership boundary @@ -118,7 +116,6 @@ pnpm lint # lint all packages | `docs/web-preset.md` | Opt-in web dimensions + UA/geo helpers + React note | | `docs/multi-product.md` | The opaque `scope` partition | | `docs/architecture.md` | Rollup-on-write, child components, crons | -| `docs/mcp-tools.md` | The 7 MCP tools | | `docs/quick-start.md` | Install → mount → track → read walkthrough | | `llms.txt` | curated index — `convex@>=1.21.0` must match `package.json` `peerDependencies.convex` | | `llms-full.txt` | generated by `pnpm --filter @vllnt/convex-analytics generate:llms` — regenerate on every API/schema/README change | diff --git a/CHANGELOG.md b/CHANGELOG.md index 515d4df..4176bb0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,7 +40,5 @@ is folded into this single `0.1.0` entry. `useTimeseries`, `useUniques` over the host's re-exported aggregate query refs. - **REST API** — five generic `x-api-key`-authed routes (/track, /metric, /top, /timeseries, /uniques), timing-safe key comparison. -- **MCP server** — 7 tools (`track`, `get_metric`, `get_top`, `get_timeseries`, `get_uniques`, - `detect_anomalies`, `query_analytics`). - **Testing** — `@vllnt/convex-analytics/test` export for convex-test, registering the child components so `track` is exercised end-to-end. diff --git a/CLAUDE.md b/CLAUDE.md index b8080d2..b7306e8 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -6,7 +6,7 @@ Any event, any dimension, any domain. Follows the vllnt Component Standard (see ## Package structure -This repo is a small monorepo (turbo): the core component, an MCP server, and a demo host. +This repo is a small monorepo (turbo) holding the core analytics component. ``` packages/ @@ -27,8 +27,6 @@ packages/ internal_mutations.ts # crons: prune, closeSessions; backfill http.ts # five generic x-api-key REST routes validators.ts # shared validators (typed scalar props — no v.any()) - convex-analytics-mcp/ # MCP server (npm: convex-analytics-mcp) — 7 tools -demo/convex/ # host harness (convex.config.ts + example.ts) — exercises the client ``` ## Ownership boundary @@ -118,7 +116,6 @@ pnpm lint # lint all packages | `docs/web-preset.md` | Opt-in web dimensions + UA/geo helpers + React note | | `docs/multi-product.md` | The opaque `scope` partition | | `docs/architecture.md` | Rollup-on-write, child components, crons | -| `docs/mcp-tools.md` | The 7 MCP tools | | `docs/quick-start.md` | Install → mount → track → read walkthrough | | `llms.txt` | curated index — `convex@>=1.21.0` must match `package.json` `peerDependencies.convex` | | `llms-full.txt` | generated by `pnpm --filter @vllnt/convex-analytics generate:llms` — regenerate on every API/schema/README change | diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9ace54d..89cf6ac 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -37,7 +37,7 @@ pnpm test 4. **Commit** using [Conventional Commits](https://www.conventionalcommits.org/): ``` feat(analytics): add new breakdown dimension - fix(mcp): handle empty timeseries response + fix(analytics): handle empty timeseries response docs: update API reference chore: bump dependencies ``` @@ -96,7 +96,6 @@ When changing public API or behavior, update the relevant files in `docs/`: | Client SDK method change | `docs/client-sdk.md` | | Schema change | `docs/schema.md` | | New cron or write path change | `docs/architecture.md` | -| New MCP tool | `docs/mcp-tools.md` | | New scoping field | `docs/multi-product.md` | After updating `docs/`, also update `llms-full.txt` (concatenation of all docs). diff --git a/README.md b/README.md index 522b6dd..0b14ed6 100644 --- a/README.md +++ b/README.md @@ -152,17 +152,6 @@ const byPlan = useTop(api.analytics.top, { name: "signup", dimension: "plan" }); Thin reactive wrappers over the host's re-exported query refs (`metric`, `top`, `timeseries`, `uniques`). `react` + `convex` are optional peer deps; backend-only consumers pull no React. -## MCP (Claude Code) - -```bash -claude mcp add convex-analytics-mcp \ - --env CONVEX_URL=https://your-deployment.convex.cloud \ - --env ANALYTICS_API_KEY=your-key -``` - -7 tools: `track`, `get_metric`, `get_top`, `get_timeseries`, `get_uniques`, `detect_anomalies`, -`query_analytics` (NL router). See [docs/mcp-tools.md](docs/mcp-tools.md). - ## Security - Auth-agnostic mount — the host gates access and passes opaque `subjectRef` / `sessionRef` in. @@ -189,7 +178,7 @@ analyticsTest.register(t); [Schema](docs/schema.md) · [Client SDK](docs/client-sdk.md) · [REST API](docs/api-reference.md) · [Web Preset](docs/web-preset.md) · [Multi-Product](docs/multi-product.md) · -[Architecture](docs/architecture.md) · [MCP Tools](docs/mcp-tools.md). For AI agents: +[Architecture](docs/architecture.md). For AI agents: [`llms.txt`](llms.txt) · [`llms-full.txt`](llms-full.txt). ## Contributing diff --git a/demo/.gitignore b/demo/.gitignore deleted file mode 100644 index 8c5fbb9..0000000 --- a/demo/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ - -.env.local diff --git a/demo/convex/convex.config.ts b/demo/convex/convex.config.ts deleted file mode 100644 index 87d7890..0000000 --- a/demo/convex/convex.config.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { defineApp } from "convex/server"; -import analytics from "@vllnt/convex-analytics/convex.config"; - -const app = defineApp(); -app.use(analytics); -export default app; diff --git a/demo/convex/example.ts b/demo/convex/example.ts deleted file mode 100644 index 4e224bf..0000000 --- a/demo/convex/example.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { mutation, query } from "./_generated/server"; -import { components } from "./_generated/api"; -import { AnalyticsClient } from "@vllnt/convex-analytics"; -import { v } from "convex/values"; - -type MyProps = { - plan?: string; - tutorialId?: string; - duration?: number; - attempts?: number; -}; - -const analytics = new AnalyticsClient(components.analytics, { - dimensions: ["plan"], - granularities: ["day"], -}); - -export const trackEvent = mutation({ - args: { - name: v.string(), - subjectRef: v.optional(v.string()), - sessionRef: v.optional(v.string()), - props: v.optional(v.record(v.string(), v.union(v.string(), v.number(), v.boolean(), v.null()))), - }, - handler: async (ctx, args) => { - return analytics.track(ctx, args.name, { - subjectRef: args.subjectRef, - sessionRef: args.sessionRef, - props: args.props as MyProps | undefined, - }); - }, -}); - -export const getMetric = query({ - args: { - name: v.string(), - }, - handler: async (ctx, args) => { - return analytics.metric(ctx, args.name); - }, -}); - -export const getTop = query({ - args: { - name: v.string(), - dimension: v.string(), - }, - handler: async (ctx, args) => { - return analytics.top(ctx, args.name, args.dimension); - }, -}); - -export const getTimeseries = query({ - args: { - name: v.string(), - }, - handler: async (ctx, args) => { - const now = Date.now(); - return analytics.timeseries(ctx, args.name, { - granularity: "day", - range: { from: now - 30 * 24 * 60 * 60 * 1000, to: now }, - }); - }, -}); - -export const getUniques = query({ - args: {}, - handler: async (ctx) => { - const now = Date.now(); - return analytics.uniques(ctx, { - range: { from: now - 7 * 24 * 60 * 60 * 1000, to: now }, - granularity: "day", - }); - }, -}); - -export const getDistribution = query({ - args: { - name: v.string(), - measure: v.string(), - buckets: v.array(v.number()), - }, - handler: async (ctx, args) => { - return analytics.distribution(ctx, args.name, args.measure, { - buckets: args.buckets, - }); - }, -}); - -const WINDOW = 30 * 24 * 60 * 60 * 1000; - -export const getFunnel = query({ - args: { steps: v.array(v.string()) }, - handler: async (ctx, args) => { - const now = Date.now(); - return analytics.funnel(ctx, args.steps, { - range: { from: now - WINDOW, to: now + WINDOW }, - }); - }, -}); - -export const getRetention = query({ - args: {}, - handler: async (ctx) => { - const now = Date.now(); - return analytics.retention(ctx, { - cohortRange: { from: now - WINDOW, to: now + WINDOW }, - periods: 3, - }); - }, -}); - -export const getList = query({ - args: { name: v.string() }, - handler: async (ctx, args) => { - return analytics.list(ctx, args.name, { numItems: 10, cursor: null }); - }, -}); diff --git a/demo/convex/tsconfig.json b/demo/convex/tsconfig.json deleted file mode 100644 index 41bfbb9..0000000 --- a/demo/convex/tsconfig.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - /* This TypeScript project config describes the environment that - * Convex functions run in and is used to typecheck them. - * You can modify it, but some settings are required to use Convex. - */ - "compilerOptions": { - /* These settings are not required by Convex and can be modified. */ - "allowJs": true, - "strict": true, - "moduleResolution": "Bundler", - "jsx": "react-jsx", - "skipLibCheck": true, - "allowSyntheticDefaultImports": true, - - /* These compiler options are required by Convex */ - "target": "ESNext", - "lib": ["ES2023", "dom"], - "forceConsistentCasingInFileNames": true, - "module": "ESNext", - "isolatedModules": true, - "noEmit": true - }, - "include": ["./**/*"], - "exclude": ["./_generated"] -} diff --git a/demo/package.json b/demo/package.json deleted file mode 100644 index 20ac82d..0000000 --- a/demo/package.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "convex-analytics-demo", - "private": true, - "version": "0.0.0", - "description": "Demo app showing convex-analytics integration", - "scripts": { - "dev": "npx convex dev" - }, - "dependencies": { - "convex": "^1.21.0", - "@vllnt/convex-analytics": "workspace:*" - } -} diff --git a/docs/mcp-tools.md b/docs/mcp-tools.md deleted file mode 100644 index 60bb0d0..0000000 --- a/docs/mcp-tools.md +++ /dev/null @@ -1,70 +0,0 @@ -# MCP Tools - -The `convex-analytics-mcp` server exposes the generic analytics surface as MCP tools over the -component's REST endpoints. - -## Setup - -```bash -claude mcp add convex-analytics-mcp \ - --env CONVEX_URL=https://your-deployment.convex.cloud \ - --env ANALYTICS_API_KEY=your-key -``` - -Requires `CONVEX_URL` and `ANALYTICS_API_KEY`. The server targets the `.convex.site` REST -host derived from `CONVEX_URL`. - -## Tools (7) - -### track - -Ingest an event (rollup-on-write). - -- Input: `name` (required), `dimensions` (required, string[]), `subjectRef`, `sessionRef`, `props`, `granularities`, `scope`, `dedupeKey`. -- Output: the `track` result (`tracked` / `dropped` / `duplicate`). - -### get_metric - -Total count for an event over a range, optionally filtered by a dimension value. - -- Input: `name` (required), `from`, `to`, `dim`, `val`, `scope`. -- Output: `: events`. - -### get_top - -Top values of any dimension (generic breakdown — `plan`, `country`, `device`, `path`, …). - -- Input: `name` (required), `dimension` (required), `limit`, `from`, `to`, `scope`. -- Output: table of `value | count`. - -### get_timeseries - -Event counts bucketed over time. - -- Input: `name` (required), `granularity` (`hour` \| `day`), `from`, `to`, `dim`, `val`, `scope`. -- Output: table of `bucket | count`. - -### get_uniques - -DAU / WAU / MAU over a range. - -- Input: `granularity` (`hour` \| `day`), `from`, `to`, `scope`. -- Output: JSON `{ dau, wau, mau, trend }`. - -### detect_anomalies - -Statistical anomaly detection over a timeseries (Z-score). Flags buckets that deviate from -the mean. - -- Input: `name` (required), `granularity`, `from`, `to`, `threshold` (default 2), `scope`. -- Output: table of anomalous buckets with `count`, `zscore`, `type` (SPIKE / DROP). - -### query_analytics - -Natural-language router — describe what you want and it dispatches to the right structured -tool. - -- Input: `question` (required), `name`, `dimension`, `scope`. -- Routes on keywords: trend/over-time → `get_timeseries`; breakdown/top/by → `get_top`; - unique/dau/mau → `get_uniques`; anomaly/spike/drop → `detect_anomalies`; - count/total/how-many → `get_metric` (default). diff --git a/docs/quick-start.md b/docs/quick-start.md index a66566a..2a7dbfa 100644 --- a/docs/quick-start.md +++ b/docs/quick-start.md @@ -94,17 +94,7 @@ await trackPageview(web, ctx, { path: "/pricing", headers: request.headers }); See [Web Preset](./web-preset.md). -## 8. (Optional) MCP for Claude Code - -```bash -claude mcp add convex-analytics-mcp \ - --env CONVEX_URL=https://your-deployment.convex.cloud \ - --env ANALYTICS_API_KEY=your-key -``` - -Gives Claude Code 7 analytics tools. See [MCP Tools](./mcp-tools.md). - -## 9. Testing +## 8. Testing ```ts import analyticsTest from "@vllnt/convex-analytics/test"; diff --git a/eslint.config.js b/eslint.config.js index 0c8c08a..96a36ae 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -67,7 +67,6 @@ export default [ "**/dist/**", "**/_generated/**", ".turbo/**", - "demo/**", ], }, ]; diff --git a/llms-full.txt b/llms-full.txt index 319d742..babb75d 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -160,17 +160,6 @@ const byPlan = useTop(api.analytics.top, { name: "signup", dimension: "plan" }); Thin reactive wrappers over the host's re-exported query refs (`metric`, `top`, `timeseries`, `uniques`). `react` + `convex` are optional peer deps; backend-only consumers pull no React. -## MCP (Claude Code) - -```bash -claude mcp add convex-analytics-mcp \ - --env CONVEX_URL=https://your-deployment.convex.cloud \ - --env ANALYTICS_API_KEY=your-key -``` - -7 tools: `track`, `get_metric`, `get_top`, `get_timeseries`, `get_uniques`, `detect_anomalies`, -`query_analytics` (NL router). See [docs/mcp-tools.md](docs/mcp-tools.md). - ## Security - Auth-agnostic mount — the host gates access and passes opaque `subjectRef` / `sessionRef` in. @@ -197,7 +186,7 @@ analyticsTest.register(t); [Schema](docs/schema.md) · [Client SDK](docs/client-sdk.md) · [REST API](docs/api-reference.md) · [Web Preset](docs/web-preset.md) · [Multi-Product](docs/multi-product.md) · -[Architecture](docs/architecture.md) · [MCP Tools](docs/mcp-tools.md). For AI agents: +[Architecture](docs/architecture.md). For AI agents: [`llms.txt`](llms.txt) · [`llms-full.txt`](llms-full.txt). ## Contributing @@ -263,8 +252,6 @@ is folded into this single `0.1.0` entry. `useTimeseries`, `useUniques` over the host's re-exported aggregate query refs. - **REST API** — five generic `x-api-key`-authed routes (/track, /metric, /top, /timeseries, /uniques), timing-safe key comparison. -- **MCP server** — 7 tools (`track`, `get_metric`, `get_top`, `get_timeseries`, `get_uniques`, - `detect_anomalies`, `query_analytics`). - **Testing** — `@vllnt/convex-analytics/test` export for convex-test, registering the child components so `track` is exercised end-to-end. @@ -940,82 +927,6 @@ component never reads host or sibling tables. Host data enters only as opaque st (`subjectRef`, `sessionRef`) or host-typed scalar `props` — never `v.any()`. ---- - -## docs/mcp-tools.md - -# MCP Tools - -The `convex-analytics-mcp` server exposes the generic analytics surface as MCP tools over the -component's REST endpoints. - -## Setup - -```bash -claude mcp add convex-analytics-mcp \ - --env CONVEX_URL=https://your-deployment.convex.cloud \ - --env ANALYTICS_API_KEY=your-key -``` - -Requires `CONVEX_URL` and `ANALYTICS_API_KEY`. The server targets the `.convex.site` REST -host derived from `CONVEX_URL`. - -## Tools (7) - -### track - -Ingest an event (rollup-on-write). - -- Input: `name` (required), `dimensions` (required, string[]), `subjectRef`, `sessionRef`, `props`, `granularities`, `scope`, `dedupeKey`. -- Output: the `track` result (`tracked` / `dropped` / `duplicate`). - -### get_metric - -Total count for an event over a range, optionally filtered by a dimension value. - -- Input: `name` (required), `from`, `to`, `dim`, `val`, `scope`. -- Output: `: events`. - -### get_top - -Top values of any dimension (generic breakdown — `plan`, `country`, `device`, `path`, …). - -- Input: `name` (required), `dimension` (required), `limit`, `from`, `to`, `scope`. -- Output: table of `value | count`. - -### get_timeseries - -Event counts bucketed over time. - -- Input: `name` (required), `granularity` (`hour` \| `day`), `from`, `to`, `dim`, `val`, `scope`. -- Output: table of `bucket | count`. - -### get_uniques - -DAU / WAU / MAU over a range. - -- Input: `granularity` (`hour` \| `day`), `from`, `to`, `scope`. -- Output: JSON `{ dau, wau, mau, trend }`. - -### detect_anomalies - -Statistical anomaly detection over a timeseries (Z-score). Flags buckets that deviate from -the mean. - -- Input: `name` (required), `granularity`, `from`, `to`, `threshold` (default 2), `scope`. -- Output: table of anomalous buckets with `count`, `zscore`, `type` (SPIKE / DROP). - -### query_analytics - -Natural-language router — describe what you want and it dispatches to the right structured -tool. - -- Input: `question` (required), `name`, `dimension`, `scope`. -- Routes on keywords: trend/over-time → `get_timeseries`; breakdown/top/by → `get_top`; - unique/dau/mau → `get_uniques`; anomaly/spike/drop → `detect_anomalies`; - count/total/how-many → `get_metric` (default). - - --- ## packages/convex-analytics/src/shared.ts @@ -2664,15 +2575,26 @@ export const list = query({ }, returns: eventPage, handler: async (ctx, args) => { - const result = await ctx.db + // `.paginate()` is not supported inside a Convex component, so paginate + // manually with a `ts`-keyed cursor (newest-first). Bounded + index-backed. + // Note: events sharing the exact boundary `ts` may be skipped across a page + // edge — adequate for a raw-event peek; precise feeds belong in the host. + const { numItems, cursor } = args.paginationOpts; + const before = cursor ? Number(cursor) : null; + const rows = await ctx.db .query("events") - .withIndex("by_scope_name_ts", (q) => - q.eq("scope", args.scope).eq("name", args.name), - ) + .withIndex("by_scope_name_ts", (q) => { + const base = q.eq("scope", args.scope).eq("name", args.name); + return before !== null ? base.lt("ts", before) : base; + }) .order("desc") - .paginate(args.paginationOpts); + .take(numItems + 1); + + const hasMore = rows.length > numItems; + const page = hasMore ? rows.slice(0, numItems) : rows; + const last = page.length > 0 ? page[page.length - 1]! : null; return { - page: result.page.map((e) => ({ + page: page.map((e) => ({ _id: e._id as string, _creationTime: e._creationTime, scope: e.scope, @@ -2684,8 +2606,8 @@ export const list = query({ seq: e.seq, dedupeKey: e.dedupeKey, })), - isDone: result.isDone, - continueCursor: result.continueCursor, + isDone: !hasMore, + continueCursor: last ? String(last.ts) : "", }; }, }); diff --git a/llms.txt b/llms.txt index 465ac43..d780f43 100644 --- a/llms.txt +++ b/llms.txt @@ -20,11 +20,6 @@ optional `@vllnt/convex-analytics/react` entry. Peer dependency: `convex@>=1.21. - [Web Preset](docs/web-preset.md): opt-in web dimensions + UA/geo helpers + React note - [Multi-Product](docs/multi-product.md): the opaque `scope` partition - [Architecture](docs/architecture.md): rollup-on-write, child components, crons -- [MCP Tools](docs/mcp-tools.md): 7 tools for AI-native queries - -## Examples - -- [Demo app](demo/convex/example.ts): mount + client + track + read in a host harness ## Optional diff --git a/packages/convex-analytics-mcp/package.json b/packages/convex-analytics-mcp/package.json deleted file mode 100644 index a10e940..0000000 --- a/packages/convex-analytics-mcp/package.json +++ /dev/null @@ -1,35 +0,0 @@ -{ - "name": "convex-analytics-mcp", - "version": "0.1.0", - "description": "MCP server for convex-analytics — 12 tools for AI-native analytics", - "license": "MIT", - "type": "module", - "main": "./src/server.ts", - "bin": { - "convex-analytics-mcp": "./src/server.ts" - }, - "exports": { - ".": "./src/server.ts" - }, - "files": [ - "src", - "README.md", - "LICENSE" - ], - "scripts": { - "build": "tsc", - "test": "vitest run", - "typecheck": "tsc --noEmit", - "lint": "eslint src/" - }, - "dependencies": { - "@modelcontextprotocol/sdk": "^1.0.0", - "@vllnt/logger": "^0.1.2", - "convex": "^1.21.0" - }, - "devDependencies": { - "@types/node": "^25.5.0", - "typescript": "~5.7.0", - "vitest": "^3.0.0" - } -} diff --git a/packages/convex-analytics-mcp/src/server.ts b/packages/convex-analytics-mcp/src/server.ts deleted file mode 100644 index 1cf84b3..0000000 --- a/packages/convex-analytics-mcp/src/server.ts +++ /dev/null @@ -1,449 +0,0 @@ -#!/usr/bin/env node -/** - * convex-analytics-mcp — MCP server for convex-analytics - * - * 7 tools: 5 structured + 1 computed anomaly detector + 1 NL router - * - * Usage: - * claude mcp add convex-analytics-mcp \ - * --env CONVEX_URL=https://your-deployment.convex.cloud \ - * --env ANALYTICS_API_KEY=your-key - */ - -import { createBackendLogger } from "@vllnt/logger"; - -const logger = createBackendLogger("convex-analytics-mcp"); - -const _CONVEX_URL = process.env["CONVEX_URL"]; -const _API_KEY = process.env["ANALYTICS_API_KEY"]; - -if (!_CONVEX_URL) { - logger.error("missing-env", { variable: "CONVEX_URL" }); - process.exit(1); -} -if (!_API_KEY) { - logger.error("missing-env", { variable: "ANALYTICS_API_KEY" }); - process.exit(1); -} - -const CONVEX_URL: string = _CONVEX_URL; -const API_KEY: string = _API_KEY; -const BASE_URL = CONVEX_URL.replace(/\.convex\.cloud$/, ".convex.site"); - -async function apiGet(path: string, params?: Record): Promise { - const url = new URL(`${BASE_URL}${path}`); - if (params) { - for (const [k, v] of Object.entries(params)) { - if (v !== undefined && v !== "") url.searchParams.set(k, v); - } - } - const res = await fetch(url.toString(), { - headers: { "x-api-key": API_KEY }, - }); - if (!res.ok) { - const body = await res.text(); - throw new Error(`API error ${res.status}: ${body}`); - } - return res.json(); -} - -async function apiPost(path: string, body: unknown): Promise { - const url = `${BASE_URL}${path}`; - const res = await fetch(url, { - method: "POST", - headers: { - "x-api-key": API_KEY, - "Content-Type": "application/json", - }, - body: JSON.stringify(body), - }); - if (!res.ok) { - const text = await res.text(); - throw new Error(`API error ${res.status}: ${text}`); - } - return res.json(); -} - -function formatTable(data: Array>, columns?: string[]): string { - if (data.length === 0) return "No data"; - const cols = columns ?? Object.keys(data[0]!); - const header = cols.join(" | "); - const separator = cols.map(() => "---").join(" | "); - const rows = data.map((row) => - cols.map((c) => String(row[c] ?? "")).join(" | "), - ); - return [header, separator, ...rows].join("\n"); -} - -// ─── Tool Definitions ───────────────────────────────────────────────────── - -interface Tool { - name: string; - description: string; - inputSchema: Record; - handler: (args: Record) => Promise; -} - -const tools: Tool[] = [ - { - name: "track", - description: - "Ingest an analytics event. Rollup-on-write: increments counters and dimension rollups immediately.", - inputSchema: { - type: "object", - properties: { - name: { type: "string", description: "Event name (e.g. 'signup', 'page_view')" }, - subjectRef: { type: "string", description: "Opaque subject identifier (user id, device id, etc.)" }, - sessionRef: { type: "string", description: "Opaque session identifier" }, - props: { - type: "object", - description: "Arbitrary key/value props (string/number/boolean/null values)", - additionalProperties: true, - }, - dimensions: { - type: "array", - items: { type: "string" }, - description: "Prop keys to roll up on (must match the component mount config)", - }, - granularities: { - type: "array", - items: { type: "string", enum: ["hour", "day"] }, - description: "Rollup time buckets. Defaults to [\"day\"]", - }, - scope: { type: "string", description: "Scope/partition key. Defaults to \"default\"" }, - dedupeKey: { type: "string", description: "Optional idempotency key" }, - }, - required: ["name", "dimensions"], - }, - handler: async (args) => { - const result = await apiPost("/track", { - name: args["name"], - subjectRef: args["subjectRef"], - sessionRef: args["sessionRef"], - props: args["props"], - dimensions: args["dimensions"] ?? [], - granularities: args["granularities"] ?? ["day"], - scope: args["scope"] ?? "default", - dedupeKey: args["dedupeKey"], - }); - return JSON.stringify(result); - }, - }, - { - name: "get_metric", - description: - "Get the total event count for an event name over a time range, optionally filtered by a dimension value.", - inputSchema: { - type: "object", - properties: { - name: { type: "string", description: "Event name" }, - from: { type: "string", description: "Start timestamp (ms since epoch)" }, - to: { type: "string", description: "End timestamp (ms since epoch)" }, - dim: { type: "string", description: "Dimension key to filter by" }, - val: { type: "string", description: "Dimension value to filter by (requires dim)" }, - scope: { type: "string" }, - }, - required: ["name"], - }, - handler: async (args) => { - const data = await apiGet("/metric", { - name: args["name"] as string, - from: args["from"] ? String(args["from"]) : "", - to: args["to"] ? String(args["to"]) : "", - dim: (args["dim"] as string) ?? "", - val: (args["val"] as string) ?? "", - scope: (args["scope"] as string) ?? "", - }); - const result = data as { name: string; count: number }; - return `${result.name}: ${result.count} events`; - }, - }, - { - name: "get_top", - description: - "Get the top values of a dimension for an event (generic breakdown). Use for any dimension: plan, country, device, path, source, etc.", - inputSchema: { - type: "object", - properties: { - name: { type: "string", description: "Event name" }, - dimension: { type: "string", description: "Dimension key to break down by (e.g. 'plan', 'country', 'device')" }, - limit: { type: "number", default: 10 }, - from: { type: "string", description: "Start timestamp (ms since epoch)" }, - to: { type: "string", description: "End timestamp (ms since epoch)" }, - scope: { type: "string" }, - }, - required: ["name", "dimension"], - }, - handler: async (args) => { - const data = await apiGet("/top", { - name: args["name"] as string, - dimension: args["dimension"] as string, - limit: args["limit"] ? String(args["limit"]) : "10", - from: args["from"] ? String(args["from"]) : "", - to: args["to"] ? String(args["to"]) : "", - scope: (args["scope"] as string) ?? "", - }); - return formatTable(data as Array>, ["value", "count"]); - }, - }, - { - name: "get_timeseries", - description: - "Get event counts bucketed over time (hourly or daily). Returns time-series data for trend analysis.", - inputSchema: { - type: "object", - properties: { - name: { type: "string", description: "Event name" }, - granularity: { - type: "string", - enum: ["hour", "day"], - default: "day", - }, - from: { type: "string", description: "Start timestamp (ms since epoch)" }, - to: { type: "string", description: "End timestamp (ms since epoch)" }, - dim: { type: "string", description: "Filter dimension key" }, - val: { type: "string", description: "Filter dimension value" }, - scope: { type: "string" }, - }, - required: ["name"], - }, - handler: async (args) => { - const data = await apiGet("/timeseries", { - name: args["name"] as string, - granularity: (args["granularity"] as string) ?? "day", - from: args["from"] ? String(args["from"]) : "", - to: args["to"] ? String(args["to"]) : "", - dim: (args["dim"] as string) ?? "", - val: (args["val"] as string) ?? "", - scope: (args["scope"] as string) ?? "", - }); - return formatTable(data as Array>, ["bucket", "count"]); - }, - }, - { - name: "get_uniques", - description: - "Get unique active subjects (DAU/WAU/MAU) over a time range, bucketed by hour or day.", - inputSchema: { - type: "object", - properties: { - granularity: { - type: "string", - enum: ["hour", "day"], - default: "day", - }, - from: { type: "string", description: "Start timestamp (ms since epoch)" }, - to: { type: "string", description: "End timestamp (ms since epoch)" }, - scope: { type: "string" }, - }, - }, - handler: async (args) => { - const data = await apiGet("/uniques", { - granularity: (args["granularity"] as string) ?? "day", - from: args["from"] ? String(args["from"]) : "", - to: args["to"] ? String(args["to"]) : "", - scope: (args["scope"] as string) ?? "", - }); - return JSON.stringify(data, null, 2); - }, - }, - { - name: "detect_anomalies", - description: - "Detect statistical anomalies in event counts. Fetches timeseries and flags buckets that deviate significantly from the mean (Z-score).", - inputSchema: { - type: "object", - properties: { - name: { type: "string", description: "Event name" }, - granularity: { type: "string", enum: ["hour", "day"], default: "day" }, - from: { type: "string", description: "Start timestamp (ms since epoch)" }, - to: { type: "string", description: "End timestamp (ms since epoch)" }, - threshold: { type: "number", default: 2, description: "Z-score threshold (default 2)" }, - scope: { type: "string" }, - }, - required: ["name"], - }, - handler: async (args) => { - const threshold = (args["threshold"] as number) ?? 2; - const data = (await apiGet("/timeseries", { - name: args["name"] as string, - granularity: (args["granularity"] as string) ?? "day", - from: args["from"] ? String(args["from"]) : "", - to: args["to"] ? String(args["to"]) : "", - scope: (args["scope"] as string) ?? "", - })) as Array<{ bucket: string; count: number }>; - - if (data.length < 3) return "Not enough data for anomaly detection (need 3+ buckets)"; - - const counts = data.map((d) => d.count); - const mean = counts.reduce((a, b) => a + b, 0) / counts.length; - const std = Math.sqrt( - counts.reduce((sum, c) => sum + (c - mean) ** 2, 0) / counts.length, - ); - - if (std === 0) return "No variance in data — all counts identical"; - - const anomalies = data - .map((d) => ({ ...d, zscore: (d.count - mean) / std })) - .filter((d) => Math.abs(d.zscore) >= threshold); - - if (anomalies.length === 0) return `No anomalies detected (threshold: ${threshold}σ, mean: ${mean.toFixed(0)})`; - - return `Anomalies (threshold: ${threshold}σ, mean: ${mean.toFixed(0)}, std: ${std.toFixed(1)}):\n\n${formatTable( - anomalies.map((a) => ({ - bucket: a.bucket, - count: a.count, - zscore: a.zscore.toFixed(2), - type: a.zscore > 0 ? "SPIKE" : "DROP", - })), - ["bucket", "count", "zscore", "type"], - )}`; - }, - }, - { - name: "query_analytics", - description: - "Natural language analytics query. Describe what you want to know and this tool routes to the correct structured query.", - inputSchema: { - type: "object", - properties: { - question: { type: "string", description: "Your analytics question in plain English" }, - name: { type: "string", description: "Event name hint (optional)" }, - dimension: { type: "string", description: "Dimension hint for breakdown queries (optional)" }, - scope: { type: "string" }, - }, - required: ["question"], - }, - handler: async (args) => { - const q = (args["question"] as string).toLowerCase(); - const nameHint = (args["name"] as string | undefined) ?? extractName(q); - const dimHint = (args["dimension"] as string | undefined) ?? extractDimension(q); - const scope = (args["scope"] as string) ?? ""; - - if (q.includes("trending") || q.includes("trend") || q.includes("over time") || q.includes("timeseries")) { - return tools.find((t) => t.name === "get_timeseries")!.handler({ name: nameHint, scope }); - } - - if (q.includes("breakdown") || q.includes("top ") || q.includes("by ")) { - return tools.find((t) => t.name === "get_top")!.handler({ name: nameHint, dimension: dimHint, scope }); - } - - if (q.includes("unique") || q.includes("dau") || q.includes("mau") || q.includes("active users")) { - return tools.find((t) => t.name === "get_uniques")!.handler({ scope }); - } - - if (q.includes("anomal") || q.includes("unusual") || q.includes("spike") || q.includes("drop")) { - return tools.find((t) => t.name === "detect_anomalies")!.handler({ name: nameHint, scope }); - } - - if (q.includes("count") || q.includes("total") || q.includes("how many")) { - return tools.find((t) => t.name === "get_metric")!.handler({ name: nameHint, scope }); - } - - return tools.find((t) => t.name === "get_metric")!.handler({ name: nameHint, scope }); - }, - }, -]; - -function extractName(q: string): string { - const m = q.match(/(?:for|of|on|event)\s+["']?(\w+)["']?/); - return m?.[1] ?? "page_view"; -} - -function extractDimension(q: string): string { - const m = q.match(/\bby\s+(\w+)/); - return m?.[1] ?? "value"; -} - -// ─── MCP Server (stdio transport) ───────────────────────────────────────── - -const SERVER_INFO = { - name: "convex-analytics-mcp", - version: "0.2.0", - description: "Analytics MCP server for convex-analytics Convex Component (generic API)", -}; - -async function handleToolCall( - name: string, - args: Record, -): Promise<{ content: Array<{ type: string; text: string }> }> { - const tool = tools.find((t) => t.name === name); - if (!tool) { - return { - content: [{ type: "text", text: `Unknown tool: ${name}` }], - }; - } - try { - const result = await tool.handler(args); - return { content: [{ type: "text", text: result }] }; - } catch (err) { - return { - content: [ - { type: "text", text: `Error: ${err instanceof Error ? err.message : String(err)}` }, - ], - }; - } -} - -async function main(): Promise { - const readline = await import("readline"); - const rl = readline.createInterface({ input: process.stdin }); - - for await (const line of rl) { - try { - const msg = JSON.parse(line); - - if (msg.method === "initialize") { - const response = { - jsonrpc: "2.0", - id: msg.id, - result: { - protocolVersion: "2024-11-05", - serverInfo: SERVER_INFO, - capabilities: { - tools: { listChanged: false }, - }, - }, - }; - process.stdout.write(JSON.stringify(response) + "\n"); - } else if (msg.method === "tools/list") { - const response = { - jsonrpc: "2.0", - id: msg.id, - result: { - tools: tools.map((t) => ({ - name: t.name, - description: t.description, - inputSchema: t.inputSchema, - })), - }, - }; - process.stdout.write(JSON.stringify(response) + "\n"); - } else if (msg.method === "tools/call") { - const result = await handleToolCall( - msg.params.name, - msg.params.arguments ?? {}, - ); - const response = { - jsonrpc: "2.0", - id: msg.id, - result, - }; - process.stdout.write(JSON.stringify(response) + "\n"); - } else if (msg.method === "notifications/initialized") { - // Client acknowledged init — no response needed - } else { - const response = { - jsonrpc: "2.0", - id: msg.id, - error: { code: -32601, message: `Method not found: ${msg.method}` }, - }; - process.stdout.write(JSON.stringify(response) + "\n"); - } - } catch { - // Invalid JSON — skip - } - } -} - -main().catch((err: unknown) => logger.error("fatal", { error: err instanceof Error ? err.message : String(err) })); diff --git a/packages/convex-analytics-mcp/tests/mcp.test.ts b/packages/convex-analytics-mcp/tests/mcp.test.ts deleted file mode 100644 index d92836a..0000000 --- a/packages/convex-analytics-mcp/tests/mcp.test.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { describe, it, expect } from "vitest"; - -describe("MCP tool routing", () => { - function routeQuery(q: string): string { - q = q.toLowerCase(); - if (q.includes("trending") || q.includes("trend") || q.includes("over time") || q.includes("timeseries")) return "get_timeseries"; - if (q.includes("breakdown") || q.includes("top ") || q.includes("by ")) return "get_top"; - if (q.includes("unique") || q.includes("dau") || q.includes("mau") || q.includes("active users")) return "get_uniques"; - if (q.includes("anomal") || q.includes("spike") || q.includes("drop")) return "detect_anomalies"; - if (q.includes("count") || q.includes("total") || q.includes("how many")) return "get_metric"; - return "get_metric"; - } - - it("routes trending questions to timeseries", () => { - expect(routeQuery("How are signups trending this month?")).toBe("get_timeseries"); - expect(routeQuery("Show me page_view over time")).toBe("get_timeseries"); - }); - - it("routes breakdown questions to get_top", () => { - expect(routeQuery("Break down signups by plan")).toBe("get_top"); - expect(routeQuery("Top events by country")).toBe("get_top"); - }); - - it("routes unique/DAU questions to get_uniques", () => { - expect(routeQuery("What's the DAU this week?")).toBe("get_uniques"); - expect(routeQuery("How many unique active users?")).toBe("get_uniques"); - }); - - it("routes anomaly questions correctly", () => { - expect(routeQuery("Any anomalies this week?")).toBe("detect_anomalies"); - expect(routeQuery("Why did signups spike?")).toBe("detect_anomalies"); - expect(routeQuery("Was there a drop?")).toBe("detect_anomalies"); - }); - - it("routes count/total questions to get_metric", () => { - expect(routeQuery("How many signups total?")).toBe("get_metric"); - expect(routeQuery("Count of purchases")).toBe("get_metric"); - }); - - it("falls back to get_metric for unknown queries", () => { - expect(routeQuery("Tell me about analytics")).toBe("get_metric"); - expect(routeQuery("Hello")).toBe("get_metric"); - }); -}); - -describe("anomaly detection", () => { - it("AC-34: detects Z-score deviations", () => { - const data = [ - { bucket: "2026-03-01", count: 10 }, - { bucket: "2026-03-02", count: 10 }, - { bucket: "2026-03-03", count: 10 }, - { bucket: "2026-03-04", count: 10 }, - { bucket: "2026-03-05", count: 10 }, - { bucket: "2026-03-06", count: 10 }, - { bucket: "2026-03-07", count: 50 }, - ]; - - const counts = data.map((d) => d.count); - const mean = counts.reduce((a, b) => a + b, 0) / counts.length; - const std = Math.sqrt( - counts.reduce((sum, c) => sum + (c - mean) ** 2, 0) / counts.length, - ); - - const anomalies = data - .map((d) => ({ ...d, zscore: (d.count - mean) / std })) - .filter((d) => Math.abs(d.zscore) >= 2); - - expect(anomalies).toHaveLength(1); - expect(anomalies[0]!.bucket).toBe("2026-03-07"); - expect(anomalies[0]!.zscore).toBeGreaterThan(2); - }); - - it("handles no variance gracefully", () => { - const data = [ - { bucket: "2026-03-01", count: 5 }, - { bucket: "2026-03-02", count: 5 }, - { bucket: "2026-03-03", count: 5 }, - ]; - - const counts = data.map((d) => d.count); - const mean = counts.reduce((a, b) => a + b, 0) / counts.length; - const std = Math.sqrt( - counts.reduce((sum, c) => sum + (c - mean) ** 2, 0) / counts.length, - ); - - expect(std).toBe(0); - }); -}); - -describe("formatTable", () => { - function formatTable(data: Array>, columns?: string[]): string { - if (data.length === 0) return "No data"; - const cols = columns ?? Object.keys(data[0]!); - const header = cols.join(" | "); - const separator = cols.map(() => "---").join(" | "); - const rows = data.map((row) => - cols.map((c) => String(row[c] ?? "")).join(" | "), - ); - return [header, separator, ...rows].join("\n"); - } - - it("formats data as markdown table", () => { - const result = formatTable( - [ - { name: "signup", count: 42 }, - { name: "login", count: 100 }, - ], - ["name", "count"], - ); - expect(result).toContain("name | count"); - expect(result).toContain("signup | 42"); - expect(result).toContain("login | 100"); - }); - - it("handles empty data", () => { - expect(formatTable([])).toBe("No data"); - }); -}); diff --git a/packages/convex-analytics-mcp/tsconfig.json b/packages/convex-analytics-mcp/tsconfig.json deleted file mode 100644 index 467c0a3..0000000 --- a/packages/convex-analytics-mcp/tsconfig.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "compilerOptions": { - "target": "ESNext", - "module": "ESNext", - "moduleResolution": "bundler", - "lib": ["ESNext", "DOM"], - "types": ["node"], - "strict": true, - "declaration": true, - "outDir": "dist", - "rootDir": "src", - "skipLibCheck": true, - "esModuleInterop": true, - "isolatedModules": true - }, - "include": ["src"], - "exclude": ["node_modules", "dist"] -} diff --git a/packages/convex-analytics-mcp/vitest.config.ts b/packages/convex-analytics-mcp/vitest.config.ts deleted file mode 100644 index ba29bd1..0000000 --- a/packages/convex-analytics-mcp/vitest.config.ts +++ /dev/null @@ -1,8 +0,0 @@ -import { defineConfig } from "vitest/config"; - -export default defineConfig({ - test: { - include: ["tests/**/*.test.ts"], - environment: "node", - }, -}); diff --git a/packages/convex-analytics/convex.json b/packages/convex-analytics/convex.json deleted file mode 100644 index 22c6084..0000000 --- a/packages/convex-analytics/convex.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "functions": "../../demo/convex", - "codegen": { - "legacyComponentApi": false - } -} diff --git a/packages/convex-analytics/package.json b/packages/convex-analytics/package.json index 0f02abf..8389c53 100644 --- a/packages/convex-analytics/package.json +++ b/packages/convex-analytics/package.json @@ -60,6 +60,8 @@ "@testing-library/react": "^16.1.0", "@types/react": "^19.0.0", "@vitest/coverage-v8": "^3.0.0", + "@vllnt/eslint-config": "^1.0.0", + "@vllnt/typescript": "^1.0.0", "convex-test": "^0.0.36", "jsdom": "^26.0.0", "react": "^19.0.0", diff --git a/packages/convex-analytics/scripts/generate-llms.mjs b/packages/convex-analytics/scripts/generate-llms.mjs index 6e86b42..e3d940d 100644 --- a/packages/convex-analytics/scripts/generate-llms.mjs +++ b/packages/convex-analytics/scripts/generate-llms.mjs @@ -18,7 +18,6 @@ const docs = [ "docs/web-preset.md", "docs/multi-product.md", "docs/architecture.md", - "docs/mcp-tools.md", ]; // Public source files, fenced as TypeScript. Keep in sync with the public surface. diff --git a/packages/convex-analytics/tsconfig.json b/packages/convex-analytics/tsconfig.json index 3874713..09f205f 100644 --- a/packages/convex-analytics/tsconfig.json +++ b/packages/convex-analytics/tsconfig.json @@ -1,4 +1,5 @@ { + "extends": "@vllnt/typescript/node-library.json", "compilerOptions": { "target": "ESNext", "module": "ESNext", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 76111af..c0763b7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -21,15 +21,6 @@ importers: specifier: ~5.7.0 version: 5.7.3 - demo: - dependencies: - '@vllnt/convex-analytics': - specifier: workspace:* - version: link:../packages/convex-analytics - convex: - specifier: ^1.21.0 - version: 1.34.0(react@19.2.7) - packages/convex-analytics: dependencies: '@convex-dev/aggregate': @@ -57,6 +48,12 @@ importers: '@vitest/coverage-v8': specifier: ^3.0.0 version: 3.2.6(vitest@3.2.4(@edge-runtime/vm@4.0.4)(@types/node@25.5.0)(jsdom@26.1.0)) + '@vllnt/eslint-config': + specifier: ^1.0.0 + version: 1.0.0(@typescript-eslint/parser@8.57.2(eslint@9.39.4)(typescript@5.7.3))(convex@1.34.0(react@19.2.7))(eslint@9.39.4)(prettier@3.8.1)(turbo@2.8.20)(typescript@5.7.3) + '@vllnt/typescript': + specifier: ^1.0.0 + version: 1.0.0 convex-test: specifier: ^0.0.36 version: 0.0.36(convex@1.34.0(react@19.2.7)) @@ -79,28 +76,6 @@ importers: specifier: ^3.0.0 version: 3.2.4(@edge-runtime/vm@4.0.4)(@types/node@25.5.0)(jsdom@26.1.0) - packages/convex-analytics-mcp: - dependencies: - '@modelcontextprotocol/sdk': - specifier: ^1.0.0 - version: 1.27.1(zod@4.3.6) - '@vllnt/logger': - specifier: ^0.1.2 - version: 0.1.2 - convex: - specifier: ^1.21.0 - version: 1.34.0(react@19.2.7) - devDependencies: - '@types/node': - specifier: ^25.5.0 - version: 25.5.0 - typescript: - specifier: ~5.7.0 - version: 5.7.3 - vitest: - specifier: ^3.0.0 - version: 3.2.4(@edge-runtime/vm@4.0.4)(@types/node@25.5.0)(jsdom@26.1.0) - packages: '@ampproject/remapping@2.3.0': @@ -599,12 +574,6 @@ packages: resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@hono/node-server@1.19.11': - resolution: {integrity: sha512-dr8/3zEaB+p0D2n/IUrlPF1HZm586qgJNXK1a9fhg/PzdtkK7Ksd5l312tJX2yBuALqDYBlG20QEbayqPyxn+g==} - engines: {node: '>=18.14.1'} - peerDependencies: - hono: ^4 - '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} engines: {node: '>=18.18.0'} @@ -645,16 +614,6 @@ packages: '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - '@modelcontextprotocol/sdk@1.27.1': - resolution: {integrity: sha512-sr6GbP+4edBwFndLbM60gf07z0FQ79gaExpnsjMGePXqFcSSb7t6iscpjk9DhFhwd+mTEQrzNafGP8/iGGFYaA==} - engines: {node: '>=18'} - peerDependencies: - '@cfworker/json-schema': ^4.1.1 - zod: ^3.25 || ^4.0 - peerDependenciesMeta: - '@cfworker/json-schema': - optional: true - '@next/eslint-plugin-next@16.2.1': resolution: {integrity: sha512-r0epZGo24eT4g08jJlg2OEryBphXqO8aL18oajoTKLzHJ6jVr6P6FI58DLMug04MwD3j8Fj0YK0slyzneKVyzA==} @@ -1018,12 +977,9 @@ packages: typescript: optional: true - '@vllnt/logger@0.1.2': - resolution: {integrity: sha512-xHSQgoArRKtFODnpEgjVyKRNXiCRTCiGDHK2kdMJ6/6+VGv9KXwzP265KC8RcXAL79/sLXVXdFoWXe3xACYOFw==} - - accepts@2.0.0: - resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} - engines: {node: '>= 0.6'} + '@vllnt/typescript@1.0.0': + resolution: {integrity: sha512-0hr7yBLLWb6Z5QN3a4IF9TQyU8v8/NoygCAuL5LG64vrHaLdXccIuXzkkOJxBmSVj5dmoxVbJ8IvuCTHC/3IWA==} + engines: {node: '>=22'} acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} @@ -1043,20 +999,9 @@ packages: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} - ajv-formats@3.0.1: - resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} - peerDependencies: - ajv: ^8.0.0 - peerDependenciesMeta: - ajv: - optional: true - ajv@6.14.0: resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==} - ajv@8.18.0: - resolution: {integrity: sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==} - ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -1153,10 +1098,6 @@ packages: engines: {node: '>=6.0.0'} hasBin: true - body-parser@2.2.2: - resolution: {integrity: sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==} - engines: {node: '>=18'} - brace-expansion@1.1.12: resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} @@ -1180,10 +1121,6 @@ packages: resolution: {integrity: sha512-bkXY9WsVpY7CvMhKSR6pZilZu9Ln5WDrKVBUXf2S443etkmEO4V58heTecXcUIsNsi4Rx8JUO4NfX1IcQl4deg==} engines: {node: '>=18.20'} - bytes@3.1.2: - resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} - engines: {node: '>= 0.8'} - cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} @@ -1243,14 +1180,6 @@ packages: concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - content-disposition@1.0.1: - resolution: {integrity: sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==} - engines: {node: '>=18'} - - content-type@1.0.5: - resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} - engines: {node: '>= 0.6'} - convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} @@ -1275,21 +1204,9 @@ packages: react: optional: true - cookie-signature@1.2.2: - resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} - engines: {node: '>=6.6.0'} - - cookie@0.7.2: - resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} - engines: {node: '>= 0.6'} - core-js-compat@3.49.0: resolution: {integrity: sha512-VQXt1jr9cBz03b331DFDCCP90b3fanciLkgiOoy8SBHy06gNf+vQ1A3WFLqG7I8TipYIKeYK9wxd0tUrvHcOZA==} - cors@2.8.6: - resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} - engines: {node: '>= 0.10'} - cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} @@ -1359,10 +1276,6 @@ packages: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} - depd@2.0.0: - resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} - engines: {node: '>= 0.8'} - dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} @@ -1388,9 +1301,6 @@ packages: eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - ee-first@1.1.1: - resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - electron-to-chromium@1.5.321: resolution: {integrity: sha512-L2C7Q279W2D/J4PLZLk7sebOILDSWos7bMsMNN06rK482umHUrh/3lM8G7IlHFOYip2oAg5nha1rCMxr/rs6ZQ==} @@ -1400,10 +1310,6 @@ packages: emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - encodeurl@2.0.0: - resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} - engines: {node: '>= 0.8'} - entities@6.0.1: resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} engines: {node: '>=0.12'} @@ -1457,9 +1363,6 @@ packages: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} - escape-html@1.0.3: - resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} - escape-string-regexp@1.0.5: resolution: {integrity: sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==} engines: {node: '>=0.8.0'} @@ -1632,32 +1535,10 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} - etag@1.8.1: - resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} - engines: {node: '>= 0.6'} - - eventsource-parser@3.0.6: - resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==} - engines: {node: '>=18.0.0'} - - eventsource@3.0.7: - resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} - engines: {node: '>=18.0.0'} - expect-type@1.3.0: resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} engines: {node: '>=12.0.0'} - express-rate-limit@8.3.1: - resolution: {integrity: sha512-D1dKN+cmyPWuvB+G2SREQDzPY1agpBIcTa9sJxOPMCNeH3gwzhqJRDWCXW3gg0y//+LQ/8j52JbMROWyrKdMdw==} - engines: {node: '>= 16'} - peerDependencies: - express: '>= 4.11' - - express@5.2.1: - resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} - engines: {node: '>= 18'} - fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -1674,9 +1555,6 @@ packages: fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - fast-uri@3.1.0: - resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} - fastq@1.20.1: resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} @@ -1697,10 +1575,6 @@ packages: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} engines: {node: '>=8'} - finalhandler@2.1.1: - resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} - engines: {node: '>= 18.0.0'} - find-up-simple@1.0.1: resolution: {integrity: sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==} engines: {node: '>=18'} @@ -1724,14 +1598,6 @@ packages: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} - forwarded@0.2.0: - resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} - engines: {node: '>= 0.6'} - - fresh@2.0.0: - resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} - engines: {node: '>= 0.8'} - fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -1839,10 +1705,6 @@ packages: hermes-parser@0.25.1: resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} - hono@4.12.8: - resolution: {integrity: sha512-VJCEvtrezO1IAR+kqEYnxUOoStaQPGrCmX3j4wDTNOcD1uRPFpGlwQUIW8niPuvHXaTUxeOUl5MMDGrl+tmO9A==} - engines: {node: '>=16.9.0'} - html-encoding-sniffer@4.0.0: resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} engines: {node: '>=18'} @@ -1850,10 +1712,6 @@ packages: html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} - http-errors@2.0.1: - resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} - engines: {node: '>= 0.8'} - http-proxy-agent@7.0.2: resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} engines: {node: '>= 14'} @@ -1866,10 +1724,6 @@ packages: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} engines: {node: '>=0.10.0'} - iconv-lite@0.7.2: - resolution: {integrity: sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==} - engines: {node: '>=0.10.0'} - ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} @@ -1890,21 +1744,10 @@ packages: resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} engines: {node: '>=12'} - inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - internal-slot@1.1.0: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} - ip-address@10.1.0: - resolution: {integrity: sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==} - engines: {node: '>= 12'} - - ipaddr.js@1.9.1: - resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} - engines: {node: '>= 0.10'} - is-array-buffer@3.0.5: resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} engines: {node: '>= 0.4'} @@ -1986,9 +1829,6 @@ packages: is-potential-custom-element-name@1.0.1: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} - is-promise@4.0.0: - resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} - is-regex@1.2.1: resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} engines: {node: '>= 0.4'} @@ -2054,9 +1894,6 @@ packages: jackspeak@3.4.3: resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} - jose@6.2.2: - resolution: {integrity: sha512-d7kPDd34KO/YnzaDOlikGpOurfF0ByC2sEV4cANCtdqLlTfBlw2p14O/5d/zv40gJPbIQxfES3nSx1/oYNyuZQ==} - js-tokens@10.0.0: resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==} @@ -2090,12 +1927,6 @@ packages: json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - json-schema-traverse@1.0.0: - resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - - json-schema-typed@8.0.2: - resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==} - json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} @@ -2163,14 +1994,6 @@ packages: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} - media-typer@1.1.0: - resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} - engines: {node: '>= 0.8'} - - merge-descriptors@2.0.0: - resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} - engines: {node: '>=18'} - merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} @@ -2179,14 +2002,6 @@ packages: resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} - mime-db@1.54.0: - resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} - engines: {node: '>= 0.6'} - - mime-types@3.0.2: - resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} - engines: {node: '>=18'} - minimatch@10.2.4: resolution: {integrity: sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==} engines: {node: 18 || 20 || >=22} @@ -2220,10 +2035,6 @@ packages: resolution: {integrity: sha512-kKHJhxwpR/Okycz4HhQKKlhWe4ASEfPgkSWNmKFHd7+ezuQlxkA5cM3+XkBPvm1gmHen3w53qsYAv+8GwRrBlg==} engines: {node: '>=18'} - negotiator@1.0.0: - resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} - engines: {node: '>= 0.6'} - neo-async@2.6.2: resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} @@ -2269,13 +2080,6 @@ packages: resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} engines: {node: '>= 0.4'} - on-finished@2.4.1: - resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} - engines: {node: '>= 0.8'} - - once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -2302,10 +2106,6 @@ packages: parse5@7.3.0: resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} - parseurl@1.3.3: - resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} - engines: {node: '>= 0.8'} - passive-voice@0.1.0: resolution: {integrity: sha512-Pj9iwzXw4bKEtdugGYm92jT4tnsj+xrTSkHFEM4bn6fefqbFdZi49tZMmGIZ91aIQTyFtMUww7O2qYaZKAsDag==} @@ -2324,9 +2124,6 @@ packages: resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} engines: {node: '>=16 || 14 >=14.18'} - path-to-regexp@8.3.0: - resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==} - pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} @@ -2345,10 +2142,6 @@ packages: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} - pkce-challenge@5.0.1: - resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} - engines: {node: '>=16.20.0'} - pluralize@8.0.0: resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} engines: {node: '>=4'} @@ -2381,29 +2174,13 @@ packages: prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} - proxy-addr@2.0.7: - resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} - engines: {node: '>= 0.10'} - punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - qs@6.15.0: - resolution: {integrity: sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==} - engines: {node: '>=0.6'} - queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - range-parser@1.2.1: - resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} - engines: {node: '>= 0.6'} - - raw-body@3.0.2: - resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} - engines: {node: '>= 0.10'} - react-dom@19.2.7: resolution: {integrity: sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==} peerDependencies: @@ -2435,10 +2212,6 @@ packages: resolution: {integrity: sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==} hasBin: true - require-from-string@2.0.2: - resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} - engines: {node: '>=0.10.0'} - requireindex@1.1.0: resolution: {integrity: sha512-LBnkqsDE7BZKvqylbmn7lTIVdpx4K/QCduRATpO5R+wtPmky/a8pN1bO2D6wXppn1497AJF9mNjqAXr6bdl9jg==} engines: {node: '>=0.10.5'} @@ -2466,10 +2239,6 @@ packages: engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true - router@2.2.0: - resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} - engines: {node: '>= 18'} - rrweb-cssom@0.8.0: resolution: {integrity: sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==} @@ -2507,14 +2276,6 @@ packages: engines: {node: '>=10'} hasBin: true - send@1.2.1: - resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} - engines: {node: '>= 18'} - - serve-static@2.2.1: - resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} - engines: {node: '>= 18'} - set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} @@ -2527,9 +2288,6 @@ packages: resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} engines: {node: '>= 0.4'} - setprototypeof@1.2.0: - resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} engines: {node: '>=8'} @@ -2572,10 +2330,6 @@ packages: stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} - statuses@2.0.2: - resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} - engines: {node: '>= 0.8'} - std-env@3.10.0: resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} @@ -2685,10 +2439,6 @@ packages: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} - toidentifier@1.0.1: - resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} - engines: {node: '>=0.6'} - too-wordy@0.3.6: resolution: {integrity: sha512-fK4DKkEcrpBbK6uANekH37VeNAb/88qKdkqc/nBOFJpHdvXKXdA4lZRkiM6zNlow00Zp4W4/lnWyqqCaOQlg/w==} engines: {node: '>=6', npm: '>=5'} @@ -2720,10 +2470,6 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} - type-is@2.0.1: - resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} - engines: {node: '>= 0.6'} - typed-array-buffer@1.0.3: resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} engines: {node: '>= 0.4'} @@ -2764,10 +2510,6 @@ packages: undici-types@7.18.2: resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} - unpipe@1.0.0: - resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} - engines: {node: '>= 0.8'} - update-browserslist-db@1.2.3: resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} hasBin: true @@ -2777,10 +2519,6 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - vary@1.1.2: - resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} - engines: {node: '>= 0.8'} - vite-node@3.2.4: resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} @@ -2919,9 +2657,6 @@ packages: resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} engines: {node: '>=12'} - wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - write-good@1.0.8: resolution: {integrity: sha512-P1Ct7+DNrOcr2JAxDZ3Q5i5sx2LSveu7iLaoUL0A+YiG0GKf0l5+9j3rwMeyh6JeTL1+HfQV1rnwEvzhNIvpFw==} engines: {node: '>=6', npm: '>=5'} @@ -2953,11 +2688,6 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} - zod-to-json-schema@3.25.1: - resolution: {integrity: sha512-pM/SU9d3YAggzi6MtR4h7ruuQlqKtad8e9S0fmxcMi+ueAK5Korys/aWcV9LIIHTVbj01NdzxcnXSN+O74ZIVA==} - peerDependencies: - zod: ^3.25 || ^4 - zod-validation-error@4.0.2: resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} engines: {node: '>=18.0.0'} @@ -3352,10 +3082,6 @@ snapshots: '@eslint/core': 0.17.0 levn: 0.4.1 - '@hono/node-server@1.19.11(hono@4.12.8)': - dependencies: - hono: 4.12.8 - '@humanfs/core@0.19.1': {} '@humanfs/node@0.16.7': @@ -3397,28 +3123,6 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 - '@modelcontextprotocol/sdk@1.27.1(zod@4.3.6)': - dependencies: - '@hono/node-server': 1.19.11(hono@4.12.8) - ajv: 8.18.0 - ajv-formats: 3.0.1(ajv@8.18.0) - content-type: 1.0.5 - cors: 2.8.6 - cross-spawn: 7.0.6 - eventsource: 3.0.7 - eventsource-parser: 3.0.6 - express: 5.2.1 - express-rate-limit: 8.3.1(express@5.2.1) - hono: 4.12.8 - jose: 6.2.2 - json-schema-typed: 8.0.2 - pkce-challenge: 5.0.1 - raw-body: 3.0.2 - zod: 4.3.6 - zod-to-json-schema: 3.25.1(zod@4.3.6) - transitivePeerDependencies: - - supports-color - '@next/eslint-plugin-next@16.2.1': dependencies: fast-glob: 3.3.1 @@ -3569,6 +3273,7 @@ snapshots: '@types/node@25.5.0': dependencies: undici-types: 7.18.2 + optional: true '@types/react@19.2.17': dependencies: @@ -3809,12 +3514,7 @@ snapshots: - supports-color - turbo - '@vllnt/logger@0.1.2': {} - - accepts@2.0.0: - dependencies: - mime-types: 3.0.2 - negotiator: 1.0.0 + '@vllnt/typescript@1.0.0': {} acorn-jsx@5.3.2(acorn@8.16.0): dependencies: @@ -3826,10 +3526,6 @@ snapshots: agent-base@7.1.4: {} - ajv-formats@3.0.1(ajv@8.18.0): - optionalDependencies: - ajv: 8.18.0 - ajv@6.14.0: dependencies: fast-deep-equal: 3.1.3 @@ -3837,13 +3533,6 @@ snapshots: json-schema-traverse: 0.4.1 uri-js: 4.4.1 - ajv@8.18.0: - dependencies: - fast-deep-equal: 3.1.3 - fast-uri: 3.1.0 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - ansi-regex@5.0.1: {} ansi-regex@6.2.2: {} @@ -3947,20 +3636,6 @@ snapshots: baseline-browser-mapping@2.10.10: {} - body-parser@2.2.2: - dependencies: - bytes: 3.1.2 - content-type: 1.0.5 - debug: 4.4.3 - http-errors: 2.0.1 - iconv-lite: 0.7.2 - on-finished: 2.4.1 - qs: 6.15.0 - raw-body: 3.0.2 - type-is: 2.0.1 - transitivePeerDependencies: - - supports-color - brace-expansion@1.1.12: dependencies: balanced-match: 1.0.2 @@ -3988,8 +3663,6 @@ snapshots: builtin-modules@5.0.0: {} - bytes@3.1.2: {} - cac@6.7.14: {} call-bind-apply-helpers@1.0.2: @@ -4046,10 +3719,6 @@ snapshots: concat-map@0.0.1: {} - content-disposition@1.0.1: {} - - content-type@1.0.5: {} - convert-source-map@2.0.0: {} convex-test@0.0.36(convex@1.34.0(react@19.2.7)): @@ -4067,19 +3736,10 @@ snapshots: - bufferutil - utf-8-validate - cookie-signature@1.2.2: {} - - cookie@0.7.2: {} - core-js-compat@3.49.0: dependencies: browserslist: 4.28.1 - cors@2.8.6: - dependencies: - object-assign: 4.1.1 - vary: 1.1.2 - cross-spawn@7.0.6: dependencies: path-key: 3.1.1 @@ -4146,8 +3806,6 @@ snapshots: has-property-descriptors: 1.0.2 object-keys: 1.1.1 - depd@2.0.0: {} - dequal@2.0.3: {} doctrine@2.1.0: @@ -4168,16 +3826,12 @@ snapshots: eastasianwidth@0.2.0: {} - ee-first@1.1.1: {} - electron-to-chromium@1.5.321: {} emoji-regex@8.0.0: {} emoji-regex@9.2.2: {} - encodeurl@2.0.0: {} - entities@6.0.1: {} es-abstract@1.24.1: @@ -4344,8 +3998,6 @@ snapshots: escalade@3.2.0: {} - escape-html@1.0.3: {} - escape-string-regexp@1.0.5: {} escape-string-regexp@4.0.0: {} @@ -4587,54 +4239,8 @@ snapshots: esutils@2.0.3: {} - etag@1.8.1: {} - - eventsource-parser@3.0.6: {} - - eventsource@3.0.7: - dependencies: - eventsource-parser: 3.0.6 - expect-type@1.3.0: {} - express-rate-limit@8.3.1(express@5.2.1): - dependencies: - express: 5.2.1 - ip-address: 10.1.0 - - express@5.2.1: - dependencies: - accepts: 2.0.0 - body-parser: 2.2.2 - content-disposition: 1.0.1 - content-type: 1.0.5 - cookie: 0.7.2 - cookie-signature: 1.2.2 - debug: 4.4.3 - depd: 2.0.0 - encodeurl: 2.0.0 - escape-html: 1.0.3 - etag: 1.8.1 - finalhandler: 2.1.1 - fresh: 2.0.0 - http-errors: 2.0.1 - merge-descriptors: 2.0.0 - mime-types: 3.0.2 - on-finished: 2.4.1 - once: 1.4.0 - parseurl: 1.3.3 - proxy-addr: 2.0.7 - qs: 6.15.0 - range-parser: 1.2.1 - router: 2.2.0 - send: 1.2.1 - serve-static: 2.2.1 - statuses: 2.0.2 - type-is: 2.0.1 - vary: 1.1.2 - transitivePeerDependencies: - - supports-color - fast-deep-equal@3.1.3: {} fast-diff@1.3.0: {} @@ -4651,8 +4257,6 @@ snapshots: fast-levenshtein@2.0.6: {} - fast-uri@3.1.0: {} - fastq@1.20.1: dependencies: reusify: 1.1.0 @@ -4669,17 +4273,6 @@ snapshots: dependencies: to-regex-range: 5.0.1 - finalhandler@2.1.1: - dependencies: - debug: 4.4.3 - encodeurl: 2.0.0 - escape-html: 1.0.3 - on-finished: 2.4.1 - parseurl: 1.3.3 - statuses: 2.0.2 - transitivePeerDependencies: - - supports-color - find-up-simple@1.0.1: {} find-up@5.0.0: @@ -4703,10 +4296,6 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 - forwarded@0.2.0: {} - - fresh@2.0.0: {} - fsevents@2.3.3: optional: true @@ -4820,22 +4409,12 @@ snapshots: dependencies: hermes-estree: 0.25.1 - hono@4.12.8: {} - html-encoding-sniffer@4.0.0: dependencies: whatwg-encoding: 3.1.1 html-escaper@2.0.2: {} - http-errors@2.0.1: - dependencies: - depd: 2.0.0 - inherits: 2.0.4 - setprototypeof: 1.2.0 - statuses: 2.0.2 - toidentifier: 1.0.1 - http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.4 @@ -4854,10 +4433,6 @@ snapshots: dependencies: safer-buffer: 2.1.2 - iconv-lite@0.7.2: - dependencies: - safer-buffer: 2.1.2 - ignore@5.3.2: {} ignore@7.0.5: {} @@ -4871,18 +4446,12 @@ snapshots: indent-string@5.0.0: {} - inherits@2.0.4: {} - internal-slot@1.1.0: dependencies: es-errors: 1.3.0 hasown: 2.0.2 side-channel: 1.1.0 - ip-address@10.1.0: {} - - ipaddr.js@1.9.1: {} - is-array-buffer@3.0.5: dependencies: call-bind: 1.0.8 @@ -4970,8 +4539,6 @@ snapshots: is-potential-custom-element-name@1.0.1: {} - is-promise@4.0.0: {} - is-regex@1.2.1: dependencies: call-bound: 1.0.4 @@ -5051,8 +4618,6 @@ snapshots: optionalDependencies: '@pkgjs/parseargs': 0.11.0 - jose@6.2.2: {} - js-tokens@10.0.0: {} js-tokens@4.0.0: {} @@ -5096,10 +4661,6 @@ snapshots: json-schema-traverse@0.4.1: {} - json-schema-traverse@1.0.0: {} - - json-schema-typed@8.0.2: {} - json-stable-stringify-without-jsonify@1.0.1: {} json5@2.2.3: {} @@ -5164,10 +4725,6 @@ snapshots: math-intrinsics@1.1.0: {} - media-typer@1.1.0: {} - - merge-descriptors@2.0.0: {} - merge2@1.4.1: {} micromatch@4.0.8: @@ -5175,12 +4732,6 @@ snapshots: braces: 3.0.3 picomatch: 2.3.1 - mime-db@1.54.0: {} - - mime-types@3.0.2: - dependencies: - mime-db: 1.54.0 - minimatch@10.2.4: dependencies: brace-expansion: 5.0.4 @@ -5205,8 +4756,6 @@ snapshots: natural-orderby@5.0.0: {} - negotiator@1.0.0: {} - neo-async@2.6.2: {} no-cliches@0.3.6: {} @@ -5258,14 +4807,6 @@ snapshots: define-properties: 1.2.1 es-object-atoms: 1.1.1 - on-finished@2.4.1: - dependencies: - ee-first: 1.1.1 - - once@1.4.0: - dependencies: - wrappy: 1.0.2 - optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -5299,8 +4840,6 @@ snapshots: dependencies: entities: 6.0.1 - parseurl@1.3.3: {} - passive-voice@0.1.0: {} path-exists@4.0.0: {} @@ -5314,8 +4853,6 @@ snapshots: lru-cache: 10.4.3 minipass: 7.1.3 - path-to-regexp@8.3.0: {} - pathe@2.0.3: {} pathval@2.0.1: {} @@ -5326,8 +4863,6 @@ snapshots: picomatch@4.0.3: {} - pkce-challenge@5.0.1: {} - pluralize@8.0.0: {} possible-typed-array-names@1.1.0: {} @@ -5358,28 +4893,10 @@ snapshots: object-assign: 4.1.1 react-is: 16.13.1 - proxy-addr@2.0.7: - dependencies: - forwarded: 0.2.0 - ipaddr.js: 1.9.1 - punycode@2.3.1: {} - qs@6.15.0: - dependencies: - side-channel: 1.1.0 - queue-microtask@1.2.3: {} - range-parser@1.2.1: {} - - raw-body@3.0.2: - dependencies: - bytes: 3.1.2 - http-errors: 2.0.1 - iconv-lite: 0.7.2 - unpipe: 1.0.0 - react-dom@19.2.7(react@19.2.7): dependencies: react: 19.2.7 @@ -5417,8 +4934,6 @@ snapshots: dependencies: jsesc: 3.1.0 - require-from-string@2.0.2: {} - requireindex@1.1.0: {} resolve-from@4.0.0: {} @@ -5471,16 +4986,6 @@ snapshots: '@rollup/rollup-win32-x64-msvc': 4.59.0 fsevents: 2.3.3 - router@2.2.0: - dependencies: - debug: 4.4.3 - depd: 2.0.0 - is-promise: 4.0.0 - parseurl: 1.3.3 - path-to-regexp: 8.3.0 - transitivePeerDependencies: - - supports-color - rrweb-cssom@0.8.0: {} run-parallel@1.2.0: @@ -5518,31 +5023,6 @@ snapshots: semver@7.7.4: {} - send@1.2.1: - dependencies: - debug: 4.4.3 - encodeurl: 2.0.0 - escape-html: 1.0.3 - etag: 1.8.1 - fresh: 2.0.0 - http-errors: 2.0.1 - mime-types: 3.0.2 - ms: 2.1.3 - on-finished: 2.4.1 - range-parser: 1.2.1 - statuses: 2.0.2 - transitivePeerDependencies: - - supports-color - - serve-static@2.2.1: - dependencies: - encodeurl: 2.0.0 - escape-html: 1.0.3 - parseurl: 1.3.3 - send: 1.2.1 - transitivePeerDependencies: - - supports-color - set-function-length@1.2.2: dependencies: define-data-property: 1.1.4 @@ -5565,8 +5045,6 @@ snapshots: es-errors: 1.3.0 es-object-atoms: 1.1.1 - setprototypeof@1.2.0: {} - shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 @@ -5611,8 +5089,6 @@ snapshots: stackback@0.0.2: {} - statuses@2.0.2: {} - std-env@3.10.0: {} stop-iteration-iterator@1.1.0: @@ -5741,8 +5217,6 @@ snapshots: dependencies: is-number: 7.0.0 - toidentifier@1.0.1: {} - too-wordy@0.3.6: {} tough-cookie@5.1.2: @@ -5775,12 +5249,6 @@ snapshots: dependencies: prelude-ls: 1.2.1 - type-is@2.0.1: - dependencies: - content-type: 1.0.5 - media-typer: 1.1.0 - mime-types: 3.0.2 - typed-array-buffer@1.0.3: dependencies: call-bound: 1.0.4 @@ -5837,9 +5305,8 @@ snapshots: has-symbols: 1.1.0 which-boxed-primitive: 1.1.1 - undici-types@7.18.2: {} - - unpipe@1.0.0: {} + undici-types@7.18.2: + optional: true update-browserslist-db@1.2.3(browserslist@4.28.1): dependencies: @@ -5851,8 +5318,6 @@ snapshots: dependencies: punycode: 2.3.1 - vary@1.1.2: {} - vite-node@3.2.4(@types/node@25.5.0): dependencies: cac: 6.7.14 @@ -6014,8 +5479,6 @@ snapshots: string-width: 5.1.2 strip-ansi: 7.2.0 - wrappy@1.0.2: {} - write-good@1.0.8: dependencies: adverb-where: 0.2.6 @@ -6036,10 +5499,6 @@ snapshots: yocto-queue@0.1.0: {} - zod-to-json-schema@3.25.1(zod@4.3.6): - dependencies: - zod: 4.3.6 - zod-validation-error@4.0.2(zod@4.3.6): dependencies: zod: 4.3.6 diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 7bcbe5c..dee51e9 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,3 +1,2 @@ packages: - "packages/*" - - "demo"