From 7893a4aea5bd68e1f6f0adece794ddfd5884086e Mon Sep 17 00:00:00 2001 From: Mike Cann Date: Fri, 1 Aug 2025 10:43:30 +0800 Subject: [PATCH 01/77] wip --- example/.gitignore | 2 ++ example/package-lock.json | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/example/.gitignore b/example/.gitignore index 983c26f..9161d90 100644 --- a/example/.gitignore +++ b/example/.gitignore @@ -14,3 +14,5 @@ playground-temp temp TODOs.md .eslintcache + +.env.local diff --git a/example/package-lock.json b/example/package-lock.json index 234d401..49fbd43 100644 --- a/example/package-lock.json +++ b/example/package-lock.json @@ -27,7 +27,7 @@ }, "..": { "name": "@convex-dev/aggregate", - "version": "0.1.16", + "version": "0.1.21", "license": "Apache-2.0", "devDependencies": { "@eslint/js": "^9.9.1", @@ -43,7 +43,7 @@ "vitest": "^2.1.1" }, "peerDependencies": { - "convex": "~1.16.5 || ~1.17.0" + "convex": "~1.16.5 || >=1.17.0 <1.35.0" } }, "node_modules/@convex-dev/aggregate": { From 57497be68a88cc40c0a66467e5e58eecc1dfc008 Mon Sep 17 00:00:00 2001 From: Mike Cann Date: Fri, 1 Aug 2025 11:02:56 +0800 Subject: [PATCH 02/77] wip adding a vite project --- example/.cursor/rules/convex_rules.mdc | 676 +++ example/.gitignore | 37 +- example/convex/_generated/api.d.ts | 847 --- example/convex/_generated/api.js | 23 - example/convex/_generated/dataModel.d.ts | 60 - example/convex/_generated/server.d.ts | 149 - example/convex/_generated/server.js | 90 - example/convex/aggregate.test.ts | 22 +- example/convex/leaderboard.ts | 12 +- example/convex/photos.ts | 10 +- example/convex/shuffle.ts | 10 +- example/convex/stats.ts | 4 +- example/convex/tsconfig.json | 14 +- example/eslint.config.js | 77 + example/index.html | 14 + example/package-lock.json | 6932 +++++++++++++++------- example/package.json | 41 +- example/public/convex.svg | 17 + example/src/App.tsx | 122 + example/src/index.css | 22 + example/src/main.tsx | 14 + example/src/vite-env.d.ts | 1 + example/tsconfig.app.json | 31 + example/tsconfig.json | 7 + example/tsconfig.node.json | 24 + example/vite.config.ts | 14 + 26 files changed, 6050 insertions(+), 3220 deletions(-) create mode 100644 example/.cursor/rules/convex_rules.mdc delete mode 100644 example/convex/_generated/api.d.ts delete mode 100644 example/convex/_generated/api.js delete mode 100644 example/convex/_generated/dataModel.d.ts delete mode 100644 example/convex/_generated/server.d.ts delete mode 100644 example/convex/_generated/server.js create mode 100644 example/eslint.config.js create mode 100644 example/index.html create mode 100644 example/public/convex.svg create mode 100644 example/src/App.tsx create mode 100644 example/src/index.css create mode 100644 example/src/main.tsx create mode 100644 example/src/vite-env.d.ts create mode 100644 example/tsconfig.app.json create mode 100644 example/tsconfig.json create mode 100644 example/tsconfig.node.json create mode 100644 example/vite.config.ts diff --git a/example/.cursor/rules/convex_rules.mdc b/example/.cursor/rules/convex_rules.mdc new file mode 100644 index 0000000..bbc40b4 --- /dev/null +++ b/example/.cursor/rules/convex_rules.mdc @@ -0,0 +1,676 @@ +--- +description: Guidelines and best practices for building Convex projects, including database schema design, queries, mutations, and real-world examples +globs: **/*.ts,**/*.tsx,**/*.js,**/*.jsx +--- + +# Convex guidelines +## Function guidelines +### New function syntax +- ALWAYS use the new function syntax for Convex functions. For example: +```typescript +import { query } from "./_generated/server"; +import { v } from "convex/values"; +export const f = query({ + args: {}, + returns: v.null(), + handler: async (ctx, args) => { + // Function body + }, +}); +``` + +### Http endpoint syntax +- HTTP endpoints are defined in `convex/http.ts` and require an `httpAction` decorator. For example: +```typescript +import { httpRouter } from "convex/server"; +import { httpAction } from "./_generated/server"; +const http = httpRouter(); +http.route({ + path: "/echo", + method: "POST", + handler: httpAction(async (ctx, req) => { + const body = await req.bytes(); + return new Response(body, { status: 200 }); + }), +}); +``` +- HTTP endpoints are always registered at the exact path you specify in the `path` field. For example, if you specify `/api/someRoute`, the endpoint will be registered at `/api/someRoute`. + +### Validators +- Below is an example of an array validator: +```typescript +import { mutation } from "./_generated/server"; +import { v } from "convex/values"; + +export default mutation({ +args: { + simpleArray: v.array(v.union(v.string(), v.number())), +}, +handler: async (ctx, args) => { + //... +}, +}); +``` +- Below is an example of a schema with validators that codify a discriminated union type: +```typescript +import { defineSchema, defineTable } from "convex/server"; +import { v } from "convex/values"; + +export default defineSchema({ + results: defineTable( + v.union( + v.object({ + kind: v.literal("error"), + errorMessage: v.string(), + }), + v.object({ + kind: v.literal("success"), + value: v.number(), + }), + ), + ) +}); +``` +- Always use the `v.null()` validator when returning a null value. Below is an example query that returns a null value: +```typescript +import { query } from "./_generated/server"; +import { v } from "convex/values"; + +export const exampleQuery = query({ + args: {}, + returns: v.null(), + handler: async (ctx, args) => { + console.log("This query returns a null value"); + return null; + }, +}); +``` +- Here are the valid Convex types along with their respective validators: +Convex Type | TS/JS type | Example Usage | Validator for argument validation and schemas | Notes | +| ----------- | ------------| -----------------------| -----------------------------------------------| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Id | string | `doc._id` | `v.id(tableName)` | | +| Null | null | `null` | `v.null()` | JavaScript's `undefined` is not a valid Convex value. Functions the return `undefined` or do not return will return `null` when called from a client. Use `null` instead. | +| Int64 | bigint | `3n` | `v.int64()` | Int64s only support BigInts between -2^63 and 2^63-1. Convex supports `bigint`s in most modern browsers. | +| Float64 | number | `3.1` | `v.number()` | Convex supports all IEEE-754 double-precision floating point numbers (such as NaNs). Inf and NaN are JSON serialized as strings. | +| Boolean | boolean | `true` | `v.boolean()` | +| String | string | `"abc"` | `v.string()` | Strings are stored as UTF-8 and must be valid Unicode sequences. Strings must be smaller than the 1MB total size limit when encoded as UTF-8. | +| Bytes | ArrayBuffer | `new ArrayBuffer(8)` | `v.bytes()` | Convex supports first class bytestrings, passed in as `ArrayBuffer`s. Bytestrings must be smaller than the 1MB total size limit for Convex types. | +| Array | Array] | `[1, 3.2, "abc"]` | `v.array(values)` | Arrays can have at most 8192 values. | +| Object | Object | `{a: "abc"}` | `v.object({property: value})` | Convex only supports "plain old JavaScript objects" (objects that do not have a custom prototype). Objects can have at most 1024 entries. Field names must be nonempty and not start with "$" or "_". | +| Record | Record | `{"a": "1", "b": "2"}` | `v.record(keys, values)` | Records are objects at runtime, but can have dynamic keys. Keys must be only ASCII characters, nonempty, and not start with "$" or "_". | + +### Function registration +- Use `internalQuery`, `internalMutation`, and `internalAction` to register internal functions. These functions are private and aren't part of an app's API. They can only be called by other Convex functions. These functions are always imported from `./_generated/server`. +- Use `query`, `mutation`, and `action` to register public functions. These functions are part of the public API and are exposed to the public Internet. Do NOT use `query`, `mutation`, or `action` to register sensitive internal functions that should be kept private. +- You CANNOT register a function through the `api` or `internal` objects. +- ALWAYS include argument and return validators for all Convex functions. This includes all of `query`, `internalQuery`, `mutation`, `internalMutation`, `action`, and `internalAction`. If a function doesn't return anything, include `returns: v.null()` as its output validator. +- If the JavaScript implementation of a Convex function doesn't have a return value, it implicitly returns `null`. + +### Function calling +- Use `ctx.runQuery` to call a query from a query, mutation, or action. +- Use `ctx.runMutation` to call a mutation from a mutation or action. +- Use `ctx.runAction` to call an action from an action. +- ONLY call an action from another action if you need to cross runtimes (e.g. from V8 to Node). Otherwise, pull out the shared code into a helper async function and call that directly instead. +- Try to use as few calls from actions to queries and mutations as possible. Queries and mutations are transactions, so splitting logic up into multiple calls introduces the risk of race conditions. +- All of these calls take in a `FunctionReference`. Do NOT try to pass the callee function directly into one of these calls. +- When using `ctx.runQuery`, `ctx.runMutation`, or `ctx.runAction` to call a function in the same file, specify a type annotation on the return value to work around TypeScript circularity limitations. For example, +``` +export const f = query({ + args: { name: v.string() }, + returns: v.string(), + handler: async (ctx, args) => { + return "Hello " + args.name; + }, +}); + +export const g = query({ + args: {}, + returns: v.null(), + handler: async (ctx, args) => { + const result: string = await ctx.runQuery(api.example.f, { name: "Bob" }); + return null; + }, +}); +``` + +### Function references +- Function references are pointers to registered Convex functions. +- Use the `api` object defined by the framework in `convex/_generated/api.ts` to call public functions registered with `query`, `mutation`, or `action`. +- Use the `internal` object defined by the framework in `convex/_generated/api.ts` to call internal (or private) functions registered with `internalQuery`, `internalMutation`, or `internalAction`. +- Convex uses file-based routing, so a public function defined in `convex/example.ts` named `f` has a function reference of `api.example.f`. +- A private function defined in `convex/example.ts` named `g` has a function reference of `internal.example.g`. +- Functions can also registered within directories nested within the `convex/` folder. For example, a public function `h` defined in `convex/messages/access.ts` has a function reference of `api.messages.access.h`. + +### Api design +- Convex uses file-based routing, so thoughtfully organize files with public query, mutation, or action functions within the `convex/` directory. +- Use `query`, `mutation`, and `action` to define public functions. +- Use `internalQuery`, `internalMutation`, and `internalAction` to define private, internal functions. + +### Pagination +- Paginated queries are queries that return a list of results in incremental pages. +- You can define pagination using the following syntax: + +```ts +import { v } from "convex/values"; +import { query, mutation } from "./_generated/server"; +import { paginationOptsValidator } from "convex/server"; +export const listWithExtraArg = query({ + args: { paginationOpts: paginationOptsValidator, author: v.string() }, + handler: async (ctx, args) => { + return await ctx.db + .query("messages") + .filter((q) => q.eq(q.field("author"), args.author)) + .order("desc") + .paginate(args.paginationOpts); + }, +}); +``` +Note: `paginationOpts` is an object with the following properties: +- `numItems`: the maximum number of documents to return (the validator is `v.number()`) +- `cursor`: the cursor to use to fetch the next page of documents (the validator is `v.union(v.string(), v.null())`) +- A query that ends in `.paginate()` returns an object that has the following properties: + - page (contains an array of documents that you fetches) + - isDone (a boolean that represents whether or not this is the last page of documents) + - continueCursor (a string that represents the cursor to use to fetch the next page of documents) + + +## Validator guidelines +- `v.bigint()` is deprecated for representing signed 64-bit integers. Use `v.int64()` instead. +- Use `v.record()` for defining a record type. `v.map()` and `v.set()` are not supported. + +## Schema guidelines +- Always define your schema in `convex/schema.ts`. +- Always import the schema definition functions from `convex/server`: +- System fields are automatically added to all documents and are prefixed with an underscore. The two system fields that are automatically added to all documents are `_creationTime` which has the validator `v.number()` and `_id` which has the validator `v.id(tableName)`. +- Always include all index fields in the index name. For example, if an index is defined as `["field1", "field2"]`, the index name should be "by_field1_and_field2". +- Index fields must be queried in the same order they are defined. If you want to be able to query by "field1" then "field2" and by "field2" then "field1", you must create separate indexes. + +## Typescript guidelines +- You can use the helper typescript type `Id` imported from './_generated/dataModel' to get the type of the id for a given table. For example if there is a table called 'users' you can use `Id<'users'>` to get the type of the id for that table. +- If you need to define a `Record` make sure that you correctly provide the type of the key and value in the type. For example a validator `v.record(v.id('users'), v.string())` would have the type `Record, string>`. Below is an example of using `Record` with an `Id` type in a query: +```ts +import { query } from "./_generated/server"; +import { Doc, Id } from "./_generated/dataModel"; + +export const exampleQuery = query({ + args: { userIds: v.array(v.id("users")) }, + returns: v.record(v.id("users"), v.string()), + handler: async (ctx, args) => { + const idToUsername: Record, string> = {}; + for (const userId of args.userIds) { + const user = await ctx.db.get(userId); + if (user) { + users[user._id] = user.username; + } + } + + return idToUsername; + }, +}); +``` +- Be strict with types, particularly around id's of documents. For example, if a function takes in an id for a document in the 'users' table, take in `Id<'users'>` rather than `string`. +- Always use `as const` for string literals in discriminated union types. +- When using the `Array` type, make sure to always define your arrays as `const array: Array = [...];` +- When using the `Record` type, make sure to always define your records as `const record: Record = {...};` +- Always add `@types/node` to your `package.json` when using any Node.js built-in modules. + +## Full text search guidelines +- A query for "10 messages in channel '#general' that best match the query 'hello hi' in their body" would look like: + +const messages = await ctx.db + .query("messages") + .withSearchIndex("search_body", (q) => + q.search("body", "hello hi").eq("channel", "#general"), + ) + .take(10); + +## Query guidelines +- Do NOT use `filter` in queries. Instead, define an index in the schema and use `withIndex` instead. +- Convex queries do NOT support `.delete()`. Instead, `.collect()` the results, iterate over them, and call `ctx.db.delete(row._id)` on each result. +- Use `.unique()` to get a single document from a query. This method will throw an error if there are multiple documents that match the query. +- When using async iteration, don't use `.collect()` or `.take(n)` on the result of a query. Instead, use the `for await (const row of query)` syntax. +### Ordering +- By default Convex always returns documents in ascending `_creationTime` order. +- You can use `.order('asc')` or `.order('desc')` to pick whether a query is in ascending or descending order. If the order isn't specified, it defaults to ascending. +- Document queries that use indexes will be ordered based on the columns in the index and can avoid slow table scans. + + +## Mutation guidelines +- Use `ctx.db.replace` to fully replace an existing document. This method will throw an error if the document does not exist. +- Use `ctx.db.patch` to shallow merge updates into an existing document. This method will throw an error if the document does not exist. + +## Action guidelines +- Always add `"use node";` to the top of files containing actions that use Node.js built-in modules. +- Never use `ctx.db` inside of an action. Actions don't have access to the database. +- Below is an example of the syntax for an action: +```ts +import { action } from "./_generated/server"; + +export const exampleAction = action({ + args: {}, + returns: v.null(), + handler: async (ctx, args) => { + console.log("This action does not return anything"); + return null; + }, +}); +``` + +## Scheduling guidelines +### Cron guidelines +- Only use the `crons.interval` or `crons.cron` methods to schedule cron jobs. Do NOT use the `crons.hourly`, `crons.daily`, or `crons.weekly` helpers. +- Both cron methods take in a FunctionReference. Do NOT try to pass the function directly into one of these methods. +- Define crons by declaring the top-level `crons` object, calling some methods on it, and then exporting it as default. For example, +```ts +import { cronJobs } from "convex/server"; +import { internal } from "./_generated/api"; +import { internalAction } from "./_generated/server"; + +const empty = internalAction({ + args: {}, + returns: v.null(), + handler: async (ctx, args) => { + console.log("empty"); + }, +}); + +const crons = cronJobs(); + +// Run `internal.crons.empty` every two hours. +crons.interval("delete inactive users", { hours: 2 }, internal.crons.empty, {}); + +export default crons; +``` +- You can register Convex functions within `crons.ts` just like any other file. +- If a cron calls an internal function, always import the `internal` object from '_generated/api', even if the internal function is registered in the same file. + + +## File storage guidelines +- Convex includes file storage for large files like images, videos, and PDFs. +- The `ctx.storage.getUrl()` method returns a signed URL for a given file. It returns `null` if the file doesn't exist. +- Do NOT use the deprecated `ctx.storage.getMetadata` call for loading a file's metadata. + + Instead, query the `_storage` system table. For example, you can use `ctx.db.system.get` to get an `Id<"_storage">`. +``` +import { query } from "./_generated/server"; +import { Id } from "./_generated/dataModel"; + +type FileMetadata = { + _id: Id<"_storage">; + _creationTime: number; + contentType?: string; + sha256: string; + size: number; +} + +export const exampleQuery = query({ + args: { fileId: v.id("_storage") }, + returns: v.null(); + handler: async (ctx, args) => { + const metadata: FileMetadata | null = await ctx.db.system.get(args.fileId); + console.log(metadata); + return null; + }, +}); +``` +- Convex storage stores items as `Blob` objects. You must convert all items to/from a `Blob` when using Convex storage. + + +# Examples: +## Example: chat-app + +### Task +``` +Create a real-time chat application backend with AI responses. The app should: +- Allow creating users with names +- Support multiple chat channels +- Enable users to send messages to channels +- Automatically generate AI responses to user messages +- Show recent message history + +The backend should provide APIs for: +1. User management (creation) +2. Channel management (creation) +3. Message operations (sending, listing) +4. AI response generation using OpenAI's GPT-4 + +Messages should be stored with their channel, author, and content. The system should maintain message order +and limit history display to the 10 most recent messages per channel. + +``` + +### Analysis +1. Task Requirements Summary: +- Build a real-time chat backend with AI integration +- Support user creation +- Enable channel-based conversations +- Store and retrieve messages with proper ordering +- Generate AI responses automatically + +2. Main Components Needed: +- Database tables: users, channels, messages +- Public APIs for user/channel management +- Message handling functions +- Internal AI response generation system +- Context loading for AI responses + +3. Public API and Internal Functions Design: +Public Mutations: +- createUser: + - file path: convex/index.ts + - arguments: {name: v.string()} + - returns: v.object({userId: v.id("users")}) + - purpose: Create a new user with a given name +- createChannel: + - file path: convex/index.ts + - arguments: {name: v.string()} + - returns: v.object({channelId: v.id("channels")}) + - purpose: Create a new channel with a given name +- sendMessage: + - file path: convex/index.ts + - arguments: {channelId: v.id("channels"), authorId: v.id("users"), content: v.string()} + - returns: v.null() + - purpose: Send a message to a channel and schedule a response from the AI + +Public Queries: +- listMessages: + - file path: convex/index.ts + - arguments: {channelId: v.id("channels")} + - returns: v.array(v.object({ + _id: v.id("messages"), + _creationTime: v.number(), + channelId: v.id("channels"), + authorId: v.optional(v.id("users")), + content: v.string(), + })) + - purpose: List the 10 most recent messages from a channel in descending creation order + +Internal Functions: +- generateResponse: + - file path: convex/index.ts + - arguments: {channelId: v.id("channels")} + - returns: v.null() + - purpose: Generate a response from the AI for a given channel +- loadContext: + - file path: convex/index.ts + - arguments: {channelId: v.id("channels")} + - returns: v.array(v.object({ + _id: v.id("messages"), + _creationTime: v.number(), + channelId: v.id("channels"), + authorId: v.optional(v.id("users")), + content: v.string(), + })) +- writeAgentResponse: + - file path: convex/index.ts + - arguments: {channelId: v.id("channels"), content: v.string()} + - returns: v.null() + - purpose: Write an AI response to a given channel + +4. Schema Design: +- users + - validator: { name: v.string() } + - indexes: +- channels + - validator: { name: v.string() } + - indexes: +- messages + - validator: { channelId: v.id("channels"), authorId: v.optional(v.id("users")), content: v.string() } + - indexes + - by_channel: ["channelId"] + +5. Background Processing: +- AI response generation runs asynchronously after each user message +- Uses OpenAI's GPT-4 to generate contextual responses +- Maintains conversation context using recent message history + + +### Implementation + +#### package.json +```typescript +{ + "name": "chat-app", + "description": "This example shows how to build a chat app without authentication.", + "version": "1.0.0", + "dependencies": { + "convex": "^1.17.4", + "openai": "^4.79.0" + }, + "devDependencies": { + "typescript": "^5.7.3" + } +} +``` + +#### tsconfig.json +```typescript +{ + "compilerOptions": { + "target": "ESNext", + "lib": ["DOM", "DOM.Iterable", "ESNext"], + "skipLibCheck": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "module": "ESNext", + "moduleResolution": "Bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "allowImportingTsExtensions": true, + "noEmit": true, + "jsx": "react-jsx" + }, + "exclude": ["convex"], + "include": ["**/src/**/*.tsx", "**/src/**/*.ts", "vite.config.ts"] +} +``` + +#### convex/index.ts +```typescript +import { + query, + mutation, + internalQuery, + internalMutation, + internalAction, +} from "./_generated/server"; +import { v } from "convex/values"; +import OpenAI from "openai"; +import { internal } from "./_generated/api"; + +/** + * Create a user with a given name. + */ +export const createUser = mutation({ + args: { + name: v.string(), + }, + returns: v.id("users"), + handler: async (ctx, args) => { + return await ctx.db.insert("users", { name: args.name }); + }, +}); + +/** + * Create a channel with a given name. + */ +export const createChannel = mutation({ + args: { + name: v.string(), + }, + returns: v.id("channels"), + handler: async (ctx, args) => { + return await ctx.db.insert("channels", { name: args.name }); + }, +}); + +/** + * List the 10 most recent messages from a channel in descending creation order. + */ +export const listMessages = query({ + args: { + channelId: v.id("channels"), + }, + returns: v.array( + v.object({ + _id: v.id("messages"), + _creationTime: v.number(), + channelId: v.id("channels"), + authorId: v.optional(v.id("users")), + content: v.string(), + }), + ), + handler: async (ctx, args) => { + const messages = await ctx.db + .query("messages") + .withIndex("by_channel", (q) => q.eq("channelId", args.channelId)) + .order("desc") + .take(10); + return messages; + }, +}); + +/** + * Send a message to a channel and schedule a response from the AI. + */ +export const sendMessage = mutation({ + args: { + channelId: v.id("channels"), + authorId: v.id("users"), + content: v.string(), + }, + returns: v.null(), + handler: async (ctx, args) => { + const channel = await ctx.db.get(args.channelId); + if (!channel) { + throw new Error("Channel not found"); + } + const user = await ctx.db.get(args.authorId); + if (!user) { + throw new Error("User not found"); + } + await ctx.db.insert("messages", { + channelId: args.channelId, + authorId: args.authorId, + content: args.content, + }); + await ctx.scheduler.runAfter(0, internal.index.generateResponse, { + channelId: args.channelId, + }); + return null; + }, +}); + +const openai = new OpenAI(); + +export const generateResponse = internalAction({ + args: { + channelId: v.id("channels"), + }, + returns: v.null(), + handler: async (ctx, args) => { + const context = await ctx.runQuery(internal.index.loadContext, { + channelId: args.channelId, + }); + const response = await openai.chat.completions.create({ + model: "gpt-4o", + messages: context, + }); + const content = response.choices[0].message.content; + if (!content) { + throw new Error("No content in response"); + } + await ctx.runMutation(internal.index.writeAgentResponse, { + channelId: args.channelId, + content, + }); + return null; + }, +}); + +export const loadContext = internalQuery({ + args: { + channelId: v.id("channels"), + }, + returns: v.array( + v.object({ + role: v.union(v.literal("user"), v.literal("assistant")), + content: v.string(), + }), + ), + handler: async (ctx, args) => { + const channel = await ctx.db.get(args.channelId); + if (!channel) { + throw new Error("Channel not found"); + } + const messages = await ctx.db + .query("messages") + .withIndex("by_channel", (q) => q.eq("channelId", args.channelId)) + .order("desc") + .take(10); + + const result = []; + for (const message of messages) { + if (message.authorId) { + const user = await ctx.db.get(message.authorId); + if (!user) { + throw new Error("User not found"); + } + result.push({ + role: "user" as const, + content: `${user.name}: ${message.content}`, + }); + } else { + result.push({ role: "assistant" as const, content: message.content }); + } + } + return result; + }, +}); + +export const writeAgentResponse = internalMutation({ + args: { + channelId: v.id("channels"), + content: v.string(), + }, + returns: v.null(), + handler: async (ctx, args) => { + await ctx.db.insert("messages", { + channelId: args.channelId, + content: args.content, + }); + return null; + }, +}); +``` + +#### convex/schema.ts +```typescript +import { defineSchema, defineTable } from "convex/server"; +import { v } from "convex/values"; + +export default defineSchema({ + channels: defineTable({ + name: v.string(), + }), + + users: defineTable({ + name: v.string(), + }), + + messages: defineTable({ + channelId: v.id("channels"), + authorId: v.optional(v.id("users")), + content: v.string(), + }).index("by_channel", ["channelId"]), +}); +``` + +#### src/App.tsx +```typescript +export default function App() { + return
Hello World
; +} +``` + diff --git a/example/.gitignore b/example/.gitignore index 9161d90..fe60c1c 100644 --- a/example/.gitignore +++ b/example/.gitignore @@ -1,18 +1,27 @@ -!**/glob-import/dir/node_modules -.DS_Store -.idea -*.cpuprofile -*.local +# Logs +logs *.log -/.vscode/ -/docs/.vitepress/cache +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules dist dist-ssr -explorations -node_modules -playground-temp -temp -TODOs.md -.eslintcache +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? -.env.local +# Ignored for the template, you probably want to remove it: +package-lock.json \ No newline at end of file diff --git a/example/convex/_generated/api.d.ts b/example/convex/_generated/api.d.ts deleted file mode 100644 index 6900773..0000000 --- a/example/convex/_generated/api.d.ts +++ /dev/null @@ -1,847 +0,0 @@ -/* eslint-disable */ -/** - * Generated `api` utility. - * - * THIS CODE IS AUTOMATICALLY GENERATED. - * - * To regenerate, run `npx convex dev`. - * @module - */ - -import type * as leaderboard from "../leaderboard.js"; -import type * as photos from "../photos.js"; -import type * as shuffle from "../shuffle.js"; -import type * as stats from "../stats.js"; - -import type { - ApiFromModules, - FilterApi, - FunctionReference, -} from "convex/server"; -/** - * A utility for referencing Convex functions in your app's API. - * - * Usage: - * ```js - * const myFunctionReference = api.myModule.myFunction; - * ``` - */ -declare const fullApi: ApiFromModules<{ - leaderboard: typeof leaderboard; - photos: typeof photos; - shuffle: typeof shuffle; - stats: typeof stats; -}>; -declare const fullApiWithMounts: typeof fullApi; - -export declare const api: FilterApi< - typeof fullApiWithMounts, - FunctionReference ->; -export declare const internal: FilterApi< - typeof fullApiWithMounts, - FunctionReference ->; - -export declare const components: { - aggregateByScore: { - btree: { - aggregateBetween: FunctionReference< - "query", - "internal", - { k1?: any; k2?: any; namespace?: any }, - { count: number; sum: number } - >; - atNegativeOffset: FunctionReference< - "query", - "internal", - { k1?: any; k2?: any; namespace?: any; offset: number }, - { k: any; s: number; v: any } - >; - atOffset: FunctionReference< - "query", - "internal", - { k1?: any; k2?: any; namespace?: any; offset: number }, - { k: any; s: number; v: any } - >; - get: FunctionReference< - "query", - "internal", - { key: any; namespace?: any }, - null | { k: any; s: number; v: any } - >; - offset: FunctionReference< - "query", - "internal", - { k1?: any; key: any; namespace?: any }, - number - >; - offsetUntil: FunctionReference< - "query", - "internal", - { k2?: any; key: any; namespace?: any }, - number - >; - paginate: FunctionReference< - "query", - "internal", - { - cursor?: string; - k1?: any; - k2?: any; - limit: number; - namespace?: any; - order: "asc" | "desc"; - }, - { - cursor: string; - isDone: boolean; - page: Array<{ k: any; s: number; v: any }>; - } - >; - paginateNamespaces: FunctionReference< - "query", - "internal", - { cursor?: string; limit: number }, - { cursor: string; isDone: boolean; page: Array } - >; - validate: FunctionReference< - "query", - "internal", - { namespace?: any }, - any - >; - }; - inspect: { - display: FunctionReference<"query", "internal", { namespace?: any }, any>; - dump: FunctionReference<"query", "internal", { namespace?: any }, string>; - inspectNode: FunctionReference< - "query", - "internal", - { namespace?: any; node?: string }, - null - >; - }; - public: { - clear: FunctionReference< - "mutation", - "internal", - { maxNodeSize?: number; namespace?: any; rootLazy?: boolean }, - null - >; - deleteIfExists: FunctionReference< - "mutation", - "internal", - { key: any; namespace?: any }, - any - >; - delete_: FunctionReference< - "mutation", - "internal", - { key: any; namespace?: any }, - null - >; - init: FunctionReference< - "mutation", - "internal", - { maxNodeSize?: number; namespace?: any; rootLazy?: boolean }, - null - >; - insert: FunctionReference< - "mutation", - "internal", - { key: any; namespace?: any; summand?: number; value: any }, - null - >; - makeRootLazy: FunctionReference< - "mutation", - "internal", - { namespace?: any }, - null - >; - replace: FunctionReference< - "mutation", - "internal", - { - currentKey: any; - namespace?: any; - newKey: any; - newNamespace?: any; - summand?: number; - value: any; - }, - null - >; - replaceOrInsert: FunctionReference< - "mutation", - "internal", - { - currentKey: any; - namespace?: any; - newKey: any; - newNamespace?: any; - summand?: number; - value: any; - }, - any - >; - }; - }; - aggregateScoreByUser: { - btree: { - aggregateBetween: FunctionReference< - "query", - "internal", - { k1?: any; k2?: any; namespace?: any }, - { count: number; sum: number } - >; - atNegativeOffset: FunctionReference< - "query", - "internal", - { k1?: any; k2?: any; namespace?: any; offset: number }, - { k: any; s: number; v: any } - >; - atOffset: FunctionReference< - "query", - "internal", - { k1?: any; k2?: any; namespace?: any; offset: number }, - { k: any; s: number; v: any } - >; - get: FunctionReference< - "query", - "internal", - { key: any; namespace?: any }, - null | { k: any; s: number; v: any } - >; - offset: FunctionReference< - "query", - "internal", - { k1?: any; key: any; namespace?: any }, - number - >; - offsetUntil: FunctionReference< - "query", - "internal", - { k2?: any; key: any; namespace?: any }, - number - >; - paginate: FunctionReference< - "query", - "internal", - { - cursor?: string; - k1?: any; - k2?: any; - limit: number; - namespace?: any; - order: "asc" | "desc"; - }, - { - cursor: string; - isDone: boolean; - page: Array<{ k: any; s: number; v: any }>; - } - >; - paginateNamespaces: FunctionReference< - "query", - "internal", - { cursor?: string; limit: number }, - { cursor: string; isDone: boolean; page: Array } - >; - validate: FunctionReference< - "query", - "internal", - { namespace?: any }, - any - >; - }; - inspect: { - display: FunctionReference<"query", "internal", { namespace?: any }, any>; - dump: FunctionReference<"query", "internal", { namespace?: any }, string>; - inspectNode: FunctionReference< - "query", - "internal", - { namespace?: any; node?: string }, - null - >; - }; - public: { - clear: FunctionReference< - "mutation", - "internal", - { maxNodeSize?: number; namespace?: any; rootLazy?: boolean }, - null - >; - deleteIfExists: FunctionReference< - "mutation", - "internal", - { key: any; namespace?: any }, - any - >; - delete_: FunctionReference< - "mutation", - "internal", - { key: any; namespace?: any }, - null - >; - init: FunctionReference< - "mutation", - "internal", - { maxNodeSize?: number; namespace?: any; rootLazy?: boolean }, - null - >; - insert: FunctionReference< - "mutation", - "internal", - { key: any; namespace?: any; summand?: number; value: any }, - null - >; - makeRootLazy: FunctionReference< - "mutation", - "internal", - { namespace?: any }, - null - >; - replace: FunctionReference< - "mutation", - "internal", - { - currentKey: any; - namespace?: any; - newKey: any; - newNamespace?: any; - summand?: number; - value: any; - }, - null - >; - replaceOrInsert: FunctionReference< - "mutation", - "internal", - { - currentKey: any; - namespace?: any; - newKey: any; - newNamespace?: any; - summand?: number; - value: any; - }, - any - >; - }; - }; - music: { - btree: { - aggregateBetween: FunctionReference< - "query", - "internal", - { k1?: any; k2?: any; namespace?: any }, - { count: number; sum: number } - >; - atNegativeOffset: FunctionReference< - "query", - "internal", - { k1?: any; k2?: any; namespace?: any; offset: number }, - { k: any; s: number; v: any } - >; - atOffset: FunctionReference< - "query", - "internal", - { k1?: any; k2?: any; namespace?: any; offset: number }, - { k: any; s: number; v: any } - >; - get: FunctionReference< - "query", - "internal", - { key: any; namespace?: any }, - null | { k: any; s: number; v: any } - >; - offset: FunctionReference< - "query", - "internal", - { k1?: any; key: any; namespace?: any }, - number - >; - offsetUntil: FunctionReference< - "query", - "internal", - { k2?: any; key: any; namespace?: any }, - number - >; - paginate: FunctionReference< - "query", - "internal", - { - cursor?: string; - k1?: any; - k2?: any; - limit: number; - namespace?: any; - order: "asc" | "desc"; - }, - { - cursor: string; - isDone: boolean; - page: Array<{ k: any; s: number; v: any }>; - } - >; - paginateNamespaces: FunctionReference< - "query", - "internal", - { cursor?: string; limit: number }, - { cursor: string; isDone: boolean; page: Array } - >; - validate: FunctionReference< - "query", - "internal", - { namespace?: any }, - any - >; - }; - inspect: { - display: FunctionReference<"query", "internal", { namespace?: any }, any>; - dump: FunctionReference<"query", "internal", { namespace?: any }, string>; - inspectNode: FunctionReference< - "query", - "internal", - { namespace?: any; node?: string }, - null - >; - }; - public: { - clear: FunctionReference< - "mutation", - "internal", - { maxNodeSize?: number; namespace?: any; rootLazy?: boolean }, - null - >; - deleteIfExists: FunctionReference< - "mutation", - "internal", - { key: any; namespace?: any }, - any - >; - delete_: FunctionReference< - "mutation", - "internal", - { key: any; namespace?: any }, - null - >; - init: FunctionReference< - "mutation", - "internal", - { maxNodeSize?: number; namespace?: any; rootLazy?: boolean }, - null - >; - insert: FunctionReference< - "mutation", - "internal", - { key: any; namespace?: any; summand?: number; value: any }, - null - >; - makeRootLazy: FunctionReference< - "mutation", - "internal", - { namespace?: any }, - null - >; - replace: FunctionReference< - "mutation", - "internal", - { - currentKey: any; - namespace?: any; - newKey: any; - newNamespace?: any; - summand?: number; - value: any; - }, - null - >; - replaceOrInsert: FunctionReference< - "mutation", - "internal", - { - currentKey: any; - namespace?: any; - newKey: any; - newNamespace?: any; - summand?: number; - value: any; - }, - any - >; - }; - }; - photos: { - btree: { - aggregateBetween: FunctionReference< - "query", - "internal", - { k1?: any; k2?: any; namespace?: any }, - { count: number; sum: number } - >; - atNegativeOffset: FunctionReference< - "query", - "internal", - { k1?: any; k2?: any; namespace?: any; offset: number }, - { k: any; s: number; v: any } - >; - atOffset: FunctionReference< - "query", - "internal", - { k1?: any; k2?: any; namespace?: any; offset: number }, - { k: any; s: number; v: any } - >; - get: FunctionReference< - "query", - "internal", - { key: any; namespace?: any }, - null | { k: any; s: number; v: any } - >; - offset: FunctionReference< - "query", - "internal", - { k1?: any; key: any; namespace?: any }, - number - >; - offsetUntil: FunctionReference< - "query", - "internal", - { k2?: any; key: any; namespace?: any }, - number - >; - paginate: FunctionReference< - "query", - "internal", - { - cursor?: string; - k1?: any; - k2?: any; - limit: number; - namespace?: any; - order: "asc" | "desc"; - }, - { - cursor: string; - isDone: boolean; - page: Array<{ k: any; s: number; v: any }>; - } - >; - paginateNamespaces: FunctionReference< - "query", - "internal", - { cursor?: string; limit: number }, - { cursor: string; isDone: boolean; page: Array } - >; - validate: FunctionReference< - "query", - "internal", - { namespace?: any }, - any - >; - }; - inspect: { - display: FunctionReference<"query", "internal", { namespace?: any }, any>; - dump: FunctionReference<"query", "internal", { namespace?: any }, string>; - inspectNode: FunctionReference< - "query", - "internal", - { namespace?: any; node?: string }, - null - >; - }; - public: { - clear: FunctionReference< - "mutation", - "internal", - { maxNodeSize?: number; namespace?: any; rootLazy?: boolean }, - null - >; - deleteIfExists: FunctionReference< - "mutation", - "internal", - { key: any; namespace?: any }, - any - >; - delete_: FunctionReference< - "mutation", - "internal", - { key: any; namespace?: any }, - null - >; - init: FunctionReference< - "mutation", - "internal", - { maxNodeSize?: number; namespace?: any; rootLazy?: boolean }, - null - >; - insert: FunctionReference< - "mutation", - "internal", - { key: any; namespace?: any; summand?: number; value: any }, - null - >; - makeRootLazy: FunctionReference< - "mutation", - "internal", - { namespace?: any }, - null - >; - replace: FunctionReference< - "mutation", - "internal", - { - currentKey: any; - namespace?: any; - newKey: any; - newNamespace?: any; - summand?: number; - value: any; - }, - null - >; - replaceOrInsert: FunctionReference< - "mutation", - "internal", - { - currentKey: any; - namespace?: any; - newKey: any; - newNamespace?: any; - summand?: number; - value: any; - }, - any - >; - }; - }; - stats: { - btree: { - aggregateBetween: FunctionReference< - "query", - "internal", - { k1?: any; k2?: any; namespace?: any }, - { count: number; sum: number } - >; - atNegativeOffset: FunctionReference< - "query", - "internal", - { k1?: any; k2?: any; namespace?: any; offset: number }, - { k: any; s: number; v: any } - >; - atOffset: FunctionReference< - "query", - "internal", - { k1?: any; k2?: any; namespace?: any; offset: number }, - { k: any; s: number; v: any } - >; - get: FunctionReference< - "query", - "internal", - { key: any; namespace?: any }, - null | { k: any; s: number; v: any } - >; - offset: FunctionReference< - "query", - "internal", - { k1?: any; key: any; namespace?: any }, - number - >; - offsetUntil: FunctionReference< - "query", - "internal", - { k2?: any; key: any; namespace?: any }, - number - >; - paginate: FunctionReference< - "query", - "internal", - { - cursor?: string; - k1?: any; - k2?: any; - limit: number; - namespace?: any; - order: "asc" | "desc"; - }, - { - cursor: string; - isDone: boolean; - page: Array<{ k: any; s: number; v: any }>; - } - >; - paginateNamespaces: FunctionReference< - "query", - "internal", - { cursor?: string; limit: number }, - { cursor: string; isDone: boolean; page: Array } - >; - validate: FunctionReference< - "query", - "internal", - { namespace?: any }, - any - >; - }; - inspect: { - display: FunctionReference<"query", "internal", { namespace?: any }, any>; - dump: FunctionReference<"query", "internal", { namespace?: any }, string>; - inspectNode: FunctionReference< - "query", - "internal", - { namespace?: any; node?: string }, - null - >; - }; - public: { - clear: FunctionReference< - "mutation", - "internal", - { maxNodeSize?: number; namespace?: any; rootLazy?: boolean }, - null - >; - deleteIfExists: FunctionReference< - "mutation", - "internal", - { key: any; namespace?: any }, - any - >; - delete_: FunctionReference< - "mutation", - "internal", - { key: any; namespace?: any }, - null - >; - init: FunctionReference< - "mutation", - "internal", - { maxNodeSize?: number; namespace?: any; rootLazy?: boolean }, - null - >; - insert: FunctionReference< - "mutation", - "internal", - { key: any; namespace?: any; summand?: number; value: any }, - null - >; - makeRootLazy: FunctionReference< - "mutation", - "internal", - { namespace?: any }, - null - >; - replace: FunctionReference< - "mutation", - "internal", - { - currentKey: any; - namespace?: any; - newKey: any; - newNamespace?: any; - summand?: number; - value: any; - }, - null - >; - replaceOrInsert: FunctionReference< - "mutation", - "internal", - { - currentKey: any; - namespace?: any; - newKey: any; - newNamespace?: any; - summand?: number; - value: any; - }, - any - >; - }; - }; - migrations: { - lib: { - cancel: FunctionReference< - "mutation", - "internal", - { name: string }, - { - batchSize?: number; - cursor?: string | null; - error?: string; - isDone: boolean; - latestEnd?: number; - latestStart: number; - name: string; - next?: Array; - processed: number; - state: "inProgress" | "success" | "failed" | "canceled" | "unknown"; - } - >; - cancelAll: FunctionReference< - "mutation", - "internal", - { sinceTs?: number }, - Array<{ - batchSize?: number; - cursor?: string | null; - error?: string; - isDone: boolean; - latestEnd?: number; - latestStart: number; - name: string; - next?: Array; - processed: number; - state: "inProgress" | "success" | "failed" | "canceled" | "unknown"; - }> - >; - clearAll: FunctionReference< - "mutation", - "internal", - { before?: number }, - any - >; - getStatus: FunctionReference< - "query", - "internal", - { limit?: number; names?: Array }, - Array<{ - batchSize?: number; - cursor?: string | null; - error?: string; - isDone: boolean; - latestEnd?: number; - latestStart: number; - name: string; - next?: Array; - processed: number; - state: "inProgress" | "success" | "failed" | "canceled" | "unknown"; - }> - >; - migrate: FunctionReference< - "mutation", - "internal", - { - batchSize?: number; - cursor?: string | null; - dryRun: boolean; - fnHandle: string; - name: string; - next?: Array<{ fnHandle: string; name: string }>; - }, - { - batchSize?: number; - cursor?: string | null; - error?: string; - isDone: boolean; - latestEnd?: number; - latestStart: number; - name: string; - next?: Array; - processed: number; - state: "inProgress" | "success" | "failed" | "canceled" | "unknown"; - } - >; - }; - }; -}; diff --git a/example/convex/_generated/api.js b/example/convex/_generated/api.js deleted file mode 100644 index 44bf985..0000000 --- a/example/convex/_generated/api.js +++ /dev/null @@ -1,23 +0,0 @@ -/* eslint-disable */ -/** - * Generated `api` utility. - * - * THIS CODE IS AUTOMATICALLY GENERATED. - * - * To regenerate, run `npx convex dev`. - * @module - */ - -import { anyApi, componentsGeneric } from "convex/server"; - -/** - * A utility for referencing Convex functions in your app's API. - * - * Usage: - * ```js - * const myFunctionReference = api.myModule.myFunction; - * ``` - */ -export const api = anyApi; -export const internal = anyApi; -export const components = componentsGeneric(); diff --git a/example/convex/_generated/dataModel.d.ts b/example/convex/_generated/dataModel.d.ts deleted file mode 100644 index 8541f31..0000000 --- a/example/convex/_generated/dataModel.d.ts +++ /dev/null @@ -1,60 +0,0 @@ -/* eslint-disable */ -/** - * Generated data model types. - * - * THIS CODE IS AUTOMATICALLY GENERATED. - * - * To regenerate, run `npx convex dev`. - * @module - */ - -import type { - DataModelFromSchemaDefinition, - DocumentByName, - TableNamesInDataModel, - SystemTableNames, -} from "convex/server"; -import type { GenericId } from "convex/values"; -import schema from "../schema.js"; - -/** - * The names of all of your Convex tables. - */ -export type TableNames = TableNamesInDataModel; - -/** - * The type of a document stored in Convex. - * - * @typeParam TableName - A string literal type of the table name (like "users"). - */ -export type Doc = DocumentByName< - DataModel, - TableName ->; - -/** - * An identifier for a document in Convex. - * - * Convex documents are uniquely identified by their `Id`, which is accessible - * on the `_id` field. To learn more, see [Document IDs](https://docs.convex.dev/using/document-ids). - * - * Documents can be loaded using `db.get(id)` in query and mutation functions. - * - * IDs are just strings at runtime, but this type can be used to distinguish them from other - * strings when type checking. - * - * @typeParam TableName - A string literal type of the table name (like "users"). - */ -export type Id = - GenericId; - -/** - * A type describing your Convex data model. - * - * This type includes information about what tables you have, the type of - * documents stored in those tables, and the indexes defined on them. - * - * This type is used to parameterize methods like `queryGeneric` and - * `mutationGeneric` to make them type-safe. - */ -export type DataModel = DataModelFromSchemaDefinition; diff --git a/example/convex/_generated/server.d.ts b/example/convex/_generated/server.d.ts deleted file mode 100644 index b5c6828..0000000 --- a/example/convex/_generated/server.d.ts +++ /dev/null @@ -1,149 +0,0 @@ -/* eslint-disable */ -/** - * Generated utilities for implementing server-side Convex query and mutation functions. - * - * THIS CODE IS AUTOMATICALLY GENERATED. - * - * To regenerate, run `npx convex dev`. - * @module - */ - -import { - ActionBuilder, - AnyComponents, - HttpActionBuilder, - MutationBuilder, - QueryBuilder, - GenericActionCtx, - GenericMutationCtx, - GenericQueryCtx, - GenericDatabaseReader, - GenericDatabaseWriter, - FunctionReference, -} from "convex/server"; -import type { DataModel } from "./dataModel.js"; - -type GenericCtx = - | GenericActionCtx - | GenericMutationCtx - | GenericQueryCtx; - -/** - * Define a query in this Convex app's public API. - * - * This function will be allowed to read your Convex database and will be accessible from the client. - * - * @param func - The query function. It receives a {@link QueryCtx} as its first argument. - * @returns The wrapped query. Include this as an `export` to name it and make it accessible. - */ -export declare const query: QueryBuilder; - -/** - * Define a query that is only accessible from other Convex functions (but not from the client). - * - * This function will be allowed to read from your Convex database. It will not be accessible from the client. - * - * @param func - The query function. It receives a {@link QueryCtx} as its first argument. - * @returns The wrapped query. Include this as an `export` to name it and make it accessible. - */ -export declare const internalQuery: QueryBuilder; - -/** - * Define a mutation in this Convex app's public API. - * - * This function will be allowed to modify your Convex database and will be accessible from the client. - * - * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument. - * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible. - */ -export declare const mutation: MutationBuilder; - -/** - * Define a mutation that is only accessible from other Convex functions (but not from the client). - * - * This function will be allowed to modify your Convex database. It will not be accessible from the client. - * - * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument. - * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible. - */ -export declare const internalMutation: MutationBuilder; - -/** - * Define an action in this Convex app's public API. - * - * An action is a function which can execute any JavaScript code, including non-deterministic - * code and code with side-effects, like calling third-party services. - * They can be run in Convex's JavaScript environment or in Node.js using the "use node" directive. - * They can interact with the database indirectly by calling queries and mutations using the {@link ActionCtx}. - * - * @param func - The action. It receives an {@link ActionCtx} as its first argument. - * @returns The wrapped action. Include this as an `export` to name it and make it accessible. - */ -export declare const action: ActionBuilder; - -/** - * Define an action that is only accessible from other Convex functions (but not from the client). - * - * @param func - The function. It receives an {@link ActionCtx} as its first argument. - * @returns The wrapped function. Include this as an `export` to name it and make it accessible. - */ -export declare const internalAction: ActionBuilder; - -/** - * Define an HTTP action. - * - * This function will be used to respond to HTTP requests received by a Convex - * deployment if the requests matches the path and method where this action - * is routed. Be sure to route your action in `convex/http.js`. - * - * @param func - The function. It receives an {@link ActionCtx} as its first argument. - * @returns The wrapped function. Import this function from `convex/http.js` and route it to hook it up. - */ -export declare const httpAction: HttpActionBuilder; - -/** - * A set of services for use within Convex query functions. - * - * The query context is passed as the first argument to any Convex query - * function run on the server. - * - * This differs from the {@link MutationCtx} because all of the services are - * read-only. - */ -export type QueryCtx = GenericQueryCtx; - -/** - * A set of services for use within Convex mutation functions. - * - * The mutation context is passed as the first argument to any Convex mutation - * function run on the server. - */ -export type MutationCtx = GenericMutationCtx; - -/** - * A set of services for use within Convex action functions. - * - * The action context is passed as the first argument to any Convex action - * function run on the server. - */ -export type ActionCtx = GenericActionCtx; - -/** - * An interface to read from the database within Convex query functions. - * - * The two entry points are {@link DatabaseReader.get}, which fetches a single - * document by its {@link Id}, or {@link DatabaseReader.query}, which starts - * building a query. - */ -export type DatabaseReader = GenericDatabaseReader; - -/** - * An interface to read from and write to the database within Convex mutation - * functions. - * - * Convex guarantees that all writes within a single mutation are - * executed atomically, so you never have to worry about partial writes leaving - * your data in an inconsistent state. See [the Convex Guide](https://docs.convex.dev/understanding/convex-fundamentals/functions#atomicity-and-optimistic-concurrency-control) - * for the guarantees Convex provides your functions. - */ -export type DatabaseWriter = GenericDatabaseWriter; diff --git a/example/convex/_generated/server.js b/example/convex/_generated/server.js deleted file mode 100644 index 4a21df4..0000000 --- a/example/convex/_generated/server.js +++ /dev/null @@ -1,90 +0,0 @@ -/* eslint-disable */ -/** - * Generated utilities for implementing server-side Convex query and mutation functions. - * - * THIS CODE IS AUTOMATICALLY GENERATED. - * - * To regenerate, run `npx convex dev`. - * @module - */ - -import { - actionGeneric, - httpActionGeneric, - queryGeneric, - mutationGeneric, - internalActionGeneric, - internalMutationGeneric, - internalQueryGeneric, - componentsGeneric, -} from "convex/server"; - -/** - * Define a query in this Convex app's public API. - * - * This function will be allowed to read your Convex database and will be accessible from the client. - * - * @param func - The query function. It receives a {@link QueryCtx} as its first argument. - * @returns The wrapped query. Include this as an `export` to name it and make it accessible. - */ -export const query = queryGeneric; - -/** - * Define a query that is only accessible from other Convex functions (but not from the client). - * - * This function will be allowed to read from your Convex database. It will not be accessible from the client. - * - * @param func - The query function. It receives a {@link QueryCtx} as its first argument. - * @returns The wrapped query. Include this as an `export` to name it and make it accessible. - */ -export const internalQuery = internalQueryGeneric; - -/** - * Define a mutation in this Convex app's public API. - * - * This function will be allowed to modify your Convex database and will be accessible from the client. - * - * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument. - * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible. - */ -export const mutation = mutationGeneric; - -/** - * Define a mutation that is only accessible from other Convex functions (but not from the client). - * - * This function will be allowed to modify your Convex database. It will not be accessible from the client. - * - * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument. - * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible. - */ -export const internalMutation = internalMutationGeneric; - -/** - * Define an action in this Convex app's public API. - * - * An action is a function which can execute any JavaScript code, including non-deterministic - * code and code with side-effects, like calling third-party services. - * They can be run in Convex's JavaScript environment or in Node.js using the "use node" directive. - * They can interact with the database indirectly by calling queries and mutations using the {@link ActionCtx}. - * - * @param func - The action. It receives an {@link ActionCtx} as its first argument. - * @returns The wrapped action. Include this as an `export` to name it and make it accessible. - */ -export const action = actionGeneric; - -/** - * Define an action that is only accessible from other Convex functions (but not from the client). - * - * @param func - The function. It receives an {@link ActionCtx} as its first argument. - * @returns The wrapped function. Include this as an `export` to name it and make it accessible. - */ -export const internalAction = internalActionGeneric; - -/** - * Define a Convex HTTP action. - * - * @param func - The function. It receives an {@link ActionCtx} as its first argument, and a `Request` object - * as its second. - * @returns The wrapped endpoint function. Route a URL path to this function in `convex/http.js`. - */ -export const httpAction = httpActionGeneric; diff --git a/example/convex/aggregate.test.ts b/example/convex/aggregate.test.ts index fdacf87..9d78cd3 100644 --- a/example/convex/aggregate.test.ts +++ b/example/convex/aggregate.test.ts @@ -4,13 +4,13 @@ import { convexTest } from "convex-test"; import { afterEach, beforeEach, describe, expect, test, vi } from "vitest"; import schema from "./schema"; import componentSchema from "../../src/component/schema"; -import migrationsSchema from "../node_modules/@convex-dev/migrations/src/component/schema"; -import { api, components, internal } from "./_generated/api"; +import migrationsSchema from "../../example/node_modules/@convex-dev/migrations/src/component/schema"; +import { api, components, internal } from "../../example/convex/_generated/api"; const modules = import.meta.glob("./**/*.ts"); const componentModules = import.meta.glob("../../src/component/**/*.ts"); const migrationsModules = import.meta.glob( - "../node_modules/@convex-dev/migrations/src/component/**/*.ts" + "../node_modules/@convex-dev/migrations/src/component/**/*.ts", ); describe("leaderboard", () => { @@ -20,7 +20,7 @@ describe("leaderboard", () => { t.registerComponent( "aggregateScoreByUser", componentSchema, - componentModules + componentModules, ); t.registerComponent("migrations", migrationsSchema, migrationsModules); // Reduce maxNodeSize so we can test complex trees with fewer items. @@ -77,26 +77,26 @@ describe("leaderboard", () => { await t.mutation(api.leaderboard.addScore, { name: "Sarah", score: 5 }); expect( - await t.query(api.leaderboard.scoreAtRank, { rank: 0 }) + await t.query(api.leaderboard.scoreAtRank, { rank: 0 }), ).toMatchObject({ name: "Sarah", score: 35 }); expect( - await t.query(api.leaderboard.scoreAtRank, { rank: 1 }) + await t.query(api.leaderboard.scoreAtRank, { rank: 1 }), ).toMatchObject({ name: "Lee", score: 30 }); expect( - await t.query(api.leaderboard.scoreAtRank, { rank: 5 }) + await t.query(api.leaderboard.scoreAtRank, { rank: 5 }), ).toMatchObject({ name: "Sujay", score: 10 }); expect( - await t.query(api.leaderboard.rankOfScore, { score: 35 }) + await t.query(api.leaderboard.rankOfScore, { score: 35 }), ).toStrictEqual(0); expect( - await t.query(api.leaderboard.rankOfScore, { score: 30 }) + await t.query(api.leaderboard.rankOfScore, { score: 30 }), ).toStrictEqual(1); expect( - await t.query(api.leaderboard.rankOfScore, { score: 10 }) + await t.query(api.leaderboard.rankOfScore, { score: 10 }), ).toStrictEqual(5); expect( - await t.query(api.leaderboard.rankOfScore, { score: 33 }) + await t.query(api.leaderboard.rankOfScore, { score: 33 }), ).toStrictEqual(1); const scoresInOrder = await t.query(api.leaderboard.scoresInOrder); diff --git a/example/convex/leaderboard.ts b/example/convex/leaderboard.ts index fe365ef..e4e33d0 100644 --- a/example/convex/leaderboard.ts +++ b/example/convex/leaderboard.ts @@ -3,9 +3,13 @@ */ import { TableAggregate } from "@convex-dev/aggregate"; -import { mutation, query, internalMutation } from "./_generated/server"; -import { components, internal } from "./_generated/api"; -import { DataModel } from "./_generated/dataModel"; +import { + mutation, + query, + internalMutation, +} from "../../example/convex/_generated/server"; +import { components, internal } from "../../example/convex/_generated/api"; +import { DataModel } from "../../example/convex/_generated/dataModel"; import { ConvexError, v } from "convex/values"; import { Migrations } from "@convex-dev/migrations"; @@ -49,7 +53,7 @@ export const clearAggregates = internalMutation({ // to backfill aggregates for existing leaderboard entries, if you created the // leaderboard before adding the aggregate components. export const runAggregateBackfill = migrations.runner( - internal.leaderboard.backfillAggregatesMigration + internal.leaderboard.backfillAggregatesMigration, ); export const addScore = mutation({ diff --git a/example/convex/photos.ts b/example/convex/photos.ts index 168481a..6da56f5 100644 --- a/example/convex/photos.ts +++ b/example/convex/photos.ts @@ -12,9 +12,9 @@ import { internalMutation as rawInternalMutation, mutation as rawMutation, query, -} from "./_generated/server"; -import { components } from "./_generated/api"; -import { DataModel } from "./_generated/dataModel"; +} from "../../example/convex/_generated/server"; +import { components } from "../../example/convex/_generated/api"; +import { DataModel } from "../../example/convex/_generated/dataModel"; import { v } from "convex/values"; import { customCtx, @@ -39,7 +39,7 @@ triggers.register("photos", photos.trigger()); const mutation = customMutation(rawMutation, customCtx(triggers.wrapDB)); const internalMutation = customMutation( rawInternalMutation, - customCtx(triggers.wrapDB) + customCtx(triggers.wrapDB), ); export const init = internalMutation({ @@ -84,7 +84,7 @@ export const pageOfPhotos = query({ const photoDocs = await ctx.db .query("photos") .withIndex("by_album_creation_time", (q) => - q.eq("album", album).gte("_creationTime", firstPhotoCreationTime) + q.eq("album", album).gte("_creationTime", firstPhotoCreationTime), ) .take(numItems); return photoDocs.map((doc) => doc.url); diff --git a/example/convex/shuffle.ts b/example/convex/shuffle.ts index 2c7758a..f708f93 100644 --- a/example/convex/shuffle.ts +++ b/example/convex/shuffle.ts @@ -4,9 +4,9 @@ */ import { TableAggregate } from "@convex-dev/aggregate"; -import { mutation, query } from "./_generated/server"; -import { components } from "./_generated/api"; -import { DataModel } from "./_generated/dataModel"; +import { mutation, query } from "../../example/convex/_generated/server"; +import { components } from "../../example/convex/_generated/api"; +import { DataModel } from "../../example/convex/_generated/dataModel"; import { ConvexError, v } from "convex/values"; import Rand from "rand-seed"; @@ -99,14 +99,14 @@ export const shufflePaginated = query({ const indexes = allIndexes.slice(offset, offset + numItems); const atIndexes = await Promise.all( - indexes.map((i) => randomize.at(ctx, i)) + indexes.map((i) => randomize.at(ctx, i)), ); return await Promise.all( atIndexes.map(async (atIndex) => { const doc = (await ctx.db.get(atIndex.id))!; return doc.title; - }) + }), ); }, }); diff --git a/example/convex/stats.ts b/example/convex/stats.ts index 759c5c8..4a02f4a 100644 --- a/example/convex/stats.ts +++ b/example/convex/stats.ts @@ -2,10 +2,10 @@ * Example of collecting statistics on data not tied to a Convex table. */ -import { mutation, query } from "./_generated/server"; +import { mutation, query } from "../../example/convex/_generated/server"; import { v } from "convex/values"; import { DirectAggregate } from "@convex-dev/aggregate"; -import { components } from "./_generated/api"; +import { components } from "../../example/convex/_generated/api"; const stats = new DirectAggregate<{ Key: number; diff --git a/example/convex/tsconfig.json b/example/convex/tsconfig.json index bfd2eaf..6fa874e 100644 --- a/example/convex/tsconfig.json +++ b/example/convex/tsconfig.json @@ -7,22 +7,18 @@ /* 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": ["ES2021", "dom", "ESNext.Array"], + "lib": ["ES2021", "dom"], "forceConsistentCasingInFileNames": true, - "allowSyntheticDefaultImports": true, "module": "ESNext", - "moduleResolution": "Bundler", "isolatedModules": true, - "noEmit": true, - /* This should only be used in this example. Real apps should not attempt - * to compile TypeScript because differences between tsconfig.json files can - * cause the code to be compiled differently. - */ - "customConditions": ["@convex-dev/component-source"] + "noEmit": true }, "include": ["./**/*"], "exclude": ["./_generated"] diff --git a/example/eslint.config.js b/example/eslint.config.js new file mode 100644 index 0000000..dc2e219 --- /dev/null +++ b/example/eslint.config.js @@ -0,0 +1,77 @@ +import js from "@eslint/js"; +import globals from "globals"; +import reactHooks from "eslint-plugin-react-hooks"; +import reactRefresh from "eslint-plugin-react-refresh"; +import tseslint from "typescript-eslint"; + +export default tseslint.config( + { + ignores: [ + "dist", + "eslint.config.js", + "convex/_generated", + "postcss.config.js", + "tailwind.config.js", + "vite.config.ts", + ], + }, + { + extends: [ + js.configs.recommended, + ...tseslint.configs.recommendedTypeChecked, + ], + files: ["**/*.{ts,tsx}"], + languageOptions: { + ecmaVersion: 2020, + globals: { + ...globals.browser, + ...globals.node, + }, + parserOptions: { + project: [ + "./tsconfig.node.json", + "./tsconfig.app.json", + "./convex/tsconfig.json", + ], + }, + }, + plugins: { + "react-hooks": reactHooks, + "react-refresh": reactRefresh, + }, + rules: { + ...reactHooks.configs.recommended.rules, + "react-refresh/only-export-components": [ + "warn", + { allowConstantExport: true }, + ], + // All of these overrides ease getting into + // TypeScript, and can be removed for stricter + // linting down the line. + + // Only warn on unused variables, and ignore variables starting with `_` + "@typescript-eslint/no-unused-vars": [ + "warn", + { varsIgnorePattern: "^_", argsIgnorePattern: "^_" }, + ], + + // Allow escaping the compiler + "@typescript-eslint/ban-ts-comment": "error", + + // Allow explicit `any`s + "@typescript-eslint/no-explicit-any": "off", + + // START: Allow implicit `any`s + "@typescript-eslint/no-unsafe-argument": "off", + "@typescript-eslint/no-unsafe-assignment": "off", + "@typescript-eslint/no-unsafe-call": "off", + "@typescript-eslint/no-unsafe-member-access": "off", + "@typescript-eslint/no-unsafe-return": "off", + // END: Allow implicit `any`s + + // Allow async functions without await + // for consistency (esp. Convex `handler`s) + "@typescript-eslint/require-await": "off", + }, + }, +); diff --git a/example/index.html b/example/index.html new file mode 100644 index 0000000..ac66f30 --- /dev/null +++ b/example/index.html @@ -0,0 +1,14 @@ + + + + + + + + Vite + React + TS + + +
+ + + diff --git a/example/package-lock.json b/example/package-lock.json index 49fbd43..53c2131 100644 --- a/example/package-lock.json +++ b/example/package-lock.json @@ -1,28 +1,38 @@ { - "name": "uses-component", + "name": "examples", "version": "0.0.0", - "lockfileVersion": 2, + "lockfileVersion": 3, "requires": true, "packages": { "": { - "name": "uses-component", + "name": "examples", "version": "0.0.0", "dependencies": { "@convex-dev/aggregate": "file:..", "@convex-dev/migrations": "^0.2.1", "convex": "^1.17.0", "convex-helpers": "^0.1.61", - "rand-seed": "^2.1.7" + "rand-seed": "^2.1.7", + "react": "^19.0.0", + "react-dom": "^19.0.0" }, "devDependencies": { - "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "^9.9.1", - "@typescript-eslint/eslint-plugin": "^8.4.0", - "@typescript-eslint/parser": "^8.4.0", - "convex-test": "^0.0.34", - "eslint": "^9.9.1", - "globals": "^15.9.0", - "typescript": "^5.5.0" + "@eslint/js": "^9.21.0", + "@tailwindcss/vite": "^4.0.14", + "@types/node": "^22.13.10", + "@types/react": "^19.0.10", + "@types/react-dom": "^19.0.4", + "@vitejs/plugin-react": "^4.3.4", + "eslint": "^9.21.0", + "eslint-plugin-react-hooks": "^5.1.0", + "eslint-plugin-react-refresh": "^0.4.19", + "globals": "^15.15.0", + "npm-run-all": "^4.1.5", + "prettier": "^3.5.3", + "tailwindcss": "^4.0.14", + "typescript": "~5.7.2", + "typescript-eslint": "^8.24.1", + "vite": "^6.2.0" } }, "..": { @@ -46,25 +56,323 @@ "convex": "~1.16.5 || >=1.17.0 <1.35.0" } }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", + "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.27.1", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.0.tgz", + "integrity": "sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.0.tgz", + "integrity": "sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.0", + "@babel/helper-compilation-targets": "^7.27.2", + "@babel/helper-module-transforms": "^7.27.3", + "@babel/helpers": "^7.27.6", + "@babel/parser": "^7.28.0", + "@babel/template": "^7.27.2", + "@babel/traverse": "^7.28.0", + "@babel/types": "^7.28.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/generator": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.0.tgz", + "integrity": "sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.28.0", + "@babel/types": "^7.28.0", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz", + "integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.27.2", + "@babel/helper-validator-option": "^7.27.1", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", + "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", + "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.27.1", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.27.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.27.3.tgz", + "integrity": "sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1", + "@babel/traverse": "^7.27.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.27.1.tgz", + "integrity": "sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", + "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", + "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.28.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.2.tgz", + "integrity": "sha512-/V9771t+EgXz62aCcyofnQhGM8DQACbRhvzKFsXKC9QM+5MadF8ZmIm0crDMaz3+o0h0zXfJnd4EhbYbxsrcFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz", + "integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-self": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.27.1.tgz", + "integrity": "sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-react-jsx-source": { + "version": "7.27.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.27.1.tgz", + "integrity": "sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", + "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/parser": "^7.27.2", + "@babel/types": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.0.tgz", + "integrity": "sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.27.1", + "@babel/generator": "^7.28.0", + "@babel/helper-globals": "^7.28.0", + "@babel/parser": "^7.28.0", + "@babel/template": "^7.27.2", + "@babel/types": "^7.28.0", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.28.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz", + "integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.27.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@convex-dev/aggregate": { "resolved": "..", "link": true }, "node_modules/@convex-dev/migrations": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@convex-dev/migrations/-/migrations-0.2.1.tgz", - "integrity": "sha512-n4vBPk3IURqvnpFR5wLs9cPeTlBmTTyvtbdE3Mda6CrbpBrEm9t6B9jmPkioqsi1PSS4ezg4yYd8qDj7n0Bo5A==", + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@convex-dev/migrations/-/migrations-0.2.9.tgz", + "integrity": "sha512-HfIv6/F8VbtJ1NVT2bQRTumJGdaqROl/+s5IOnubHm7vvgie0RjcfO6YiB7JoLFWwS19vjDQDKl63ihoA08zOA==", + "license": "Apache-2.0", "peerDependencies": { - "convex": "~1.16.5 || ~1.17.0" + "convex": "~1.16.5 || >=1.17.0 <1.35.0" } }, "node_modules/@esbuild/aix-ppc64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.0.tgz", - "integrity": "sha512-3sG8Zwa5fMcA9bgqB8AfWPQ+HFke6uD3h1s3RIwUNK8EG7a4buxvuFTs3j1IMs2NXAk9F30C/FF4vxRgQCcmoQ==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.4.tgz", + "integrity": "sha512-1VCICWypeQKhVbE9oW/sJaAmjLxhVqacdkvPLEjwlttjfwENRSClS8EjBz0KzRyFSCPDIkuXW34Je/vk7zdB7Q==", "cpu": [ "ppc64" ], + "license": "MIT", "optional": true, "os": [ "aix" @@ -74,12 +382,13 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.0.tgz", - "integrity": "sha512-+KuOHTKKyIKgEEqKbGTK8W7mPp+hKinbMBeEnNzjJGyFcWsfrXjSTNluJHCY1RqhxFurdD8uNXQDei7qDlR6+g==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.4.tgz", + "integrity": "sha512-QNdQEps7DfFwE3hXiU4BZeOV68HHzYwGd0Nthhd3uCkkEKK7/R6MTgM0P7H7FAs5pU/DIWsviMmEGxEoxIZ+ZQ==", "cpu": [ "arm" ], + "license": "MIT", "optional": true, "os": [ "android" @@ -89,12 +398,13 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.0.tgz", - "integrity": "sha512-EuHFUYkAVfU4qBdyivULuu03FhJO4IJN9PGuABGrFy4vUuzk91P2d+npxHcFdpUnfYKy0PuV+n6bKIpHOB3prQ==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.4.tgz", + "integrity": "sha512-bBy69pgfhMGtCnwpC/x5QhfxAz/cBgQ9enbtwjf6V9lnPI/hMyT9iWpR1arm0l3kttTr4L0KSLpKmLp/ilKS9A==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "android" @@ -104,12 +414,13 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.0.tgz", - "integrity": "sha512-WRrmKidLoKDl56LsbBMhzTTBxrsVwTKdNbKDalbEZr0tcsBgCLbEtoNthOW6PX942YiYq8HzEnb4yWQMLQuipQ==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.4.tgz", + "integrity": "sha512-TVhdVtQIFuVpIIR282btcGC2oGQoSfZfmBdTip2anCaVYcqWlZXGcdcKIUklfX2wj0JklNYgz39OBqh2cqXvcQ==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "android" @@ -119,12 +430,13 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.0.tgz", - "integrity": "sha512-YLntie/IdS31H54Ogdn+v50NuoWF5BDkEUFpiOChVa9UnKpftgwzZRrI4J132ETIi+D8n6xh9IviFV3eXdxfow==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.4.tgz", + "integrity": "sha512-Y1giCfM4nlHDWEfSckMzeWNdQS31BQGs9/rouw6Ub91tkK79aIMTH3q9xHvzH8d0wDru5Ci0kWB8b3up/nl16g==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "darwin" @@ -134,12 +446,13 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.0.tgz", - "integrity": "sha512-IMQ6eme4AfznElesHUPDZ+teuGwoRmVuuixu7sv92ZkdQcPbsNHzutd+rAfaBKo8YK3IrBEi9SLLKWJdEvJniQ==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.4.tgz", + "integrity": "sha512-CJsry8ZGM5VFVeyUYB3cdKpd/H69PYez4eJh1W/t38vzutdjEjtP7hB6eLKBoOdxcAlCtEYHzQ/PJ/oU9I4u0A==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "darwin" @@ -149,12 +462,13 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.0.tgz", - "integrity": "sha512-0muYWCng5vqaxobq6LB3YNtevDFSAZGlgtLoAc81PjUfiFz36n4KMpwhtAd4he8ToSI3TGyuhyx5xmiWNYZFyw==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.4.tgz", + "integrity": "sha512-yYq+39NlTRzU2XmoPW4l5Ifpl9fqSk0nAJYM/V/WUGPEFfek1epLHJIkTQM6bBs1swApjO5nWgvr843g6TjxuQ==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -164,12 +478,13 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.0.tgz", - "integrity": "sha512-XKDVu8IsD0/q3foBzsXGt/KjD/yTKBCIwOHE1XwiXmrRwrX6Hbnd5Eqn/WvDekddK21tfszBSrE/WMaZh+1buQ==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.4.tgz", + "integrity": "sha512-0FgvOJ6UUMflsHSPLzdfDnnBBVoCDtBTVyn/MrWloUNvq/5SFmh13l3dvgRPkDihRxb77Y17MbqbCAa2strMQQ==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -179,12 +494,13 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.0.tgz", - "integrity": "sha512-SEELSTEtOFu5LPykzA395Mc+54RMg1EUgXP+iw2SJ72+ooMwVsgfuwXo5Fn0wXNgWZsTVHwY2cg4Vi/bOD88qw==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.4.tgz", + "integrity": "sha512-kro4c0P85GMfFYqW4TWOpvmF8rFShbWGnrLqlzp4X1TNWjRY3JMYUfDCtOxPKOIY8B0WC8HN51hGP4I4hz4AaQ==", "cpu": [ "arm" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -194,12 +510,13 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.0.tgz", - "integrity": "sha512-j1t5iG8jE7BhonbsEg5d9qOYcVZv/Rv6tghaXM/Ug9xahM0nX/H2gfu6X6z11QRTMT6+aywOMA8TDkhPo8aCGw==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.4.tgz", + "integrity": "sha512-+89UsQTfXdmjIvZS6nUnOOLoXnkUTB9hR5QAeLrQdzOSWZvNSAXAtcRDHWtqAUtAmv7ZM1WPOOeSxDzzzMogiQ==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -209,12 +526,13 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.0.tgz", - "integrity": "sha512-P7O5Tkh2NbgIm2R6x1zGJJsnacDzTFcRWZyTTMgFdVit6E98LTxO+v8LCCLWRvPrjdzXHx9FEOA8oAZPyApWUA==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.4.tgz", + "integrity": "sha512-yTEjoapy8UP3rv8dB0ip3AfMpRbyhSN3+hY8mo/i4QXFeDxmiYbEKp3ZRjBKcOP862Ua4b1PDfwlvbuwY7hIGQ==", "cpu": [ "ia32" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -224,12 +542,13 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.0.tgz", - "integrity": "sha512-InQwepswq6urikQiIC/kkx412fqUZudBO4SYKu0N+tGhXRWUqAx+Q+341tFV6QdBifpjYgUndV1hhMq3WeJi7A==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.4.tgz", + "integrity": "sha512-NeqqYkrcGzFwi6CGRGNMOjWGGSYOpqwCjS9fvaUlX5s3zwOtn1qwg1s2iE2svBe4Q/YOG1q6875lcAoQK/F4VA==", "cpu": [ "loong64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -239,12 +558,13 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.0.tgz", - "integrity": "sha512-J9rflLtqdYrxHv2FqXE2i1ELgNjT+JFURt/uDMoPQLcjWQA5wDKgQA4t/dTqGa88ZVECKaD0TctwsUfHbVoi4w==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.4.tgz", + "integrity": "sha512-IcvTlF9dtLrfL/M8WgNI/qJYBENP3ekgsHbYUIzEzq5XJzzVEV/fXY9WFPfEEXmu3ck2qJP8LG/p3Q8f7Zc2Xg==", "cpu": [ "mips64el" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -254,12 +574,13 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.0.tgz", - "integrity": "sha512-cShCXtEOVc5GxU0fM+dsFD10qZ5UpcQ8AM22bYj0u/yaAykWnqXJDpd77ublcX6vdDsWLuweeuSNZk4yUxZwtw==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.4.tgz", + "integrity": "sha512-HOy0aLTJTVtoTeGZh4HSXaO6M95qu4k5lJcH4gxv56iaycfz1S8GO/5Jh6X4Y1YiI0h7cRyLi+HixMR+88swag==", "cpu": [ "ppc64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -269,12 +590,13 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.0.tgz", - "integrity": "sha512-HEtaN7Y5UB4tZPeQmgz/UhzoEyYftbMXrBCUjINGjh3uil+rB/QzzpMshz3cNUxqXN7Vr93zzVtpIDL99t9aRw==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.4.tgz", + "integrity": "sha512-i8JUDAufpz9jOzo4yIShCTcXzS07vEgWzyX3NH2G7LEFVgrLEhjwL3ajFE4fZI3I4ZgiM7JH3GQ7ReObROvSUA==", "cpu": [ "riscv64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -284,12 +606,13 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.0.tgz", - "integrity": "sha512-WDi3+NVAuyjg/Wxi+o5KPqRbZY0QhI9TjrEEm+8dmpY9Xir8+HE/HNx2JoLckhKbFopW0RdO2D72w8trZOV+Wg==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.4.tgz", + "integrity": "sha512-jFnu+6UbLlzIjPQpWCNh5QtrcNfMLjgIavnwPQAfoGx4q17ocOU9MsQ2QVvFxwQoWpZT8DvTLooTvmOQXkO51g==", "cpu": [ "s390x" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -299,12 +622,13 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.0.tgz", - "integrity": "sha512-a3pMQhUEJkITgAw6e0bWA+F+vFtCciMjW/LPtoj99MhVt+Mfb6bbL9hu2wmTZgNd994qTAEw+U/r6k3qHWWaOQ==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.4.tgz", + "integrity": "sha512-6e0cvXwzOnVWJHq+mskP8DNSrKBr1bULBvnFLpc1KY+d+irZSgZ02TGse5FsafKS5jg2e4pbvK6TPXaF/A6+CA==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "linux" @@ -313,13 +637,30 @@ "node": ">=18" } }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.4.tgz", + "integrity": "sha512-vUnkBYxZW4hL/ie91hSqaSNjulOnYXE1VSLusnvHg2u3jewJBz3YzB9+oCw8DABeVqZGg94t9tyZFoHma8gWZQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.0.tgz", - "integrity": "sha512-cRK+YDem7lFTs2Q5nEv/HHc4LnrfBCbH5+JHu6wm2eP+d8OZNoSMYgPZJq78vqQ9g+9+nMuIsAO7skzphRXHyw==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.4.tgz", + "integrity": "sha512-XAg8pIQn5CzhOB8odIcAm42QsOfa98SBeKUdo4xa8OvX8LbMZqEtgeWE9P/Wxt7MlG2QqvjGths+nq48TrUiKw==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "netbsd" @@ -329,12 +670,13 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.0.tgz", - "integrity": "sha512-suXjq53gERueVWu0OKxzWqk7NxiUWSUlrxoZK7usiF50C6ipColGR5qie2496iKGYNLhDZkPxBI3erbnYkU0rQ==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.4.tgz", + "integrity": "sha512-Ct2WcFEANlFDtp1nVAXSNBPDxyU+j7+tId//iHXU2f/lN5AmO4zLyhDcpR5Cz1r08mVxzt3Jpyt4PmXQ1O6+7A==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "openbsd" @@ -344,12 +686,13 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.0.tgz", - "integrity": "sha512-6p3nHpby0DM/v15IFKMjAaayFhqnXV52aEmv1whZHX56pdkK+MEaLoQWj+H42ssFarP1PcomVhbsR4pkz09qBg==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.4.tgz", + "integrity": "sha512-xAGGhyOQ9Otm1Xu8NT1ifGLnA6M3sJxZ6ixylb+vIUVzvvd6GOALpwQrYrtlPouMqd/vSbgehz6HaVk4+7Afhw==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "openbsd" @@ -359,12 +702,13 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.0.tgz", - "integrity": "sha512-BFelBGfrBwk6LVrmFzCq1u1dZbG4zy/Kp93w2+y83Q5UGYF1d8sCzeLI9NXjKyujjBBniQa8R8PzLFAUrSM9OA==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.4.tgz", + "integrity": "sha512-Mw+tzy4pp6wZEK0+Lwr76pWLjrtjmJyUB23tHKqEDP74R3q95luY/bXqXZeYl4NYlvwOqoRKlInQialgCKy67Q==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "sunos" @@ -374,12 +718,13 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.0.tgz", - "integrity": "sha512-lY6AC8p4Cnb7xYHuIxQ6iYPe6MfO2CC43XXKo9nBXDb35krYt7KGhQnOkRGar5psxYkircpCqfbNDB4uJbS2jQ==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.4.tgz", + "integrity": "sha512-AVUP428VQTSddguz9dO9ngb+E5aScyg7nOeJDrF1HPYu555gmza3bDGMPhmVXL8svDSoqPCsCPjb265yG/kLKQ==", "cpu": [ "arm64" ], + "license": "MIT", "optional": true, "os": [ "win32" @@ -389,12 +734,13 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.0.tgz", - "integrity": "sha512-7L1bHlOTcO4ByvI7OXVI5pNN6HSu6pUQq9yodga8izeuB1KcT2UkHaH6118QJwopExPn0rMHIseCTx1CRo/uNA==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.4.tgz", + "integrity": "sha512-i1sW+1i+oWvQzSgfRcxxG2k4I9n3O9NRqy8U+uugaT2Dy7kLO9Y7wI72haOahxceMX8hZAzgGou1FhndRldxRg==", "cpu": [ "ia32" ], + "license": "MIT", "optional": true, "os": [ "win32" @@ -404,12 +750,13 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.0.tgz", - "integrity": "sha512-Arm+WgUFLUATuoxCJcahGuk6Yj9Pzxd6l11Zb/2aAuv5kWWvvfhLFo2fni4uSK5vzlUdCGZ/BdV5tH8klj8p8g==", + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.4.tgz", + "integrity": "sha512-nOT2vZNw6hJ+z43oP1SPea/G/6AbN6X+bGNhNuq8NtRHy4wsMhw765IKLNmnjek7GvjWBYQ8Q5VBoYTFg9y1UQ==", "cpu": [ "x64" ], + "license": "MIT", "optional": true, "os": [ "win32" @@ -419,10 +766,11 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", - "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz", + "integrity": "sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==", "dev": true, + "license": "MIT", "dependencies": { "eslint-visitor-keys": "^3.4.3" }, @@ -436,22 +784,37 @@ "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/@eslint-community/regexpp": { "version": "4.12.1", "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", "dev": true, + "license": "MIT", "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, "node_modules/@eslint/config-array": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz", - "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==", + "version": "0.21.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.0.tgz", + "integrity": "sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==", "dev": true, + "license": "Apache-2.0", "dependencies": { - "@eslint/object-schema": "^2.1.4", + "@eslint/object-schema": "^2.1.6", "debug": "^4.3.1", "minimatch": "^3.1.2" }, @@ -459,20 +822,35 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@eslint/config-helpers": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.3.0.tgz", + "integrity": "sha512-ViuymvFmcJi04qdZeDc2whTHryouGcDlaxPqarTD0ZE10ISpxGUVZGZDx4w01upyIynL3iu6IXH2bS1NhclQMw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, "node_modules/@eslint/core": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.7.0.tgz", - "integrity": "sha512-xp5Jirz5DyPYlPiKat8jaq0EmYvDXKKpzTbxXMpT9eqlRJkRKIz9AGMdlvYjih+im+QlhWrpvVjl8IPC/lHlUw==", + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.15.1.tgz", + "integrity": "sha512-bkOp+iumZCCbt1K1CmWf0R9pM5yKpDv+ZXtvSyQpudrI9kuFLp+bM2WOPXImuD/ceQuaa8f5pj93Y7zyECIGNA==", "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@eslint/eslintrc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", - "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", "dev": true, + "license": "MIT", "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -496,6 +874,7 @@ "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=18" }, @@ -504,29 +883,36 @@ } }, "node_modules/@eslint/js": { - "version": "9.13.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.13.0.tgz", - "integrity": "sha512-IFLyoY4d72Z5y/6o/BazFBezupzI/taV8sGumxTAVw3lXG9A6md1Dc34T9s1FoD/an9pJH8RHbAxsaEbBed9lA==", + "version": "9.32.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.32.0.tgz", + "integrity": "sha512-BBpRFZK3eX6uMLKz8WxFOBIFFcGFJ/g8XuwjTHCqHROSIsopI+ddn/d5Cfh36+7+e5edVS8dbSHnBNhrLEX0zg==", "dev": true, + "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" } }, "node_modules/@eslint/object-schema": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", - "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, "node_modules/@eslint/plugin-kit": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.3.tgz", - "integrity": "sha512-2b/g5hRmpbb1o4GnTZax9N9m0FXzz9OV42ZzI4rDDMDuHUqigAiQCEWChBWCY4ztAGVRjoWT19v0yMmc5/L5kA==", + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.3.4.tgz", + "integrity": "sha512-Ul5l+lHEcw3L5+k8POx6r74mxEYKG5kOb6Xpy2gCRW6zweT6TEhAf8vhxGgjhqrd/VO/Dirhsb+1hNpD1ue9hw==", "dev": true, + "license": "Apache-2.0", "dependencies": { + "@eslint/core": "^0.15.1", "levn": "^0.4.1" }, "engines": { @@ -538,6 +924,7 @@ "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=18.18.0" } @@ -547,6 +934,7 @@ "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", "dev": true, + "license": "Apache-2.0", "dependencies": { "@humanfs/core": "^0.19.1", "@humanwhocodes/retry": "^0.3.0" @@ -555,11 +943,26 @@ "node": ">=18.18.0" } }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=12.22" }, @@ -569,10 +972,11 @@ } }, "node_modules/@humanwhocodes/retry": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", - "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", "dev": true, + "license": "Apache-2.0", "engines": { "node": ">=18.18" }, @@ -581,11 +985,64 @@ "url": "https://github.com/sponsors/nzakas" } }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.12", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz", + "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz", + "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.29", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz", + "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -599,6 +1056,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } @@ -608,6 +1066,7 @@ "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", "dev": true, + "license": "MIT", "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -616,916 +1075,2860 @@ "node": ">= 8" } }, - "node_modules/@types/estree": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", - "dev": true + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-beta.27", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.27.tgz", + "integrity": "sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==", + "dev": true, + "license": "MIT" }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.46.2.tgz", + "integrity": "sha512-Zj3Hl6sN34xJtMv7Anwb5Gu01yujyE/cLBDB2gnHTAHaWS1Z38L7kuSG+oAh0giZMqG060f/YBStXtMH6FvPMA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.12.2.tgz", - "integrity": "sha512-gQxbxM8mcxBwaEmWdtLCIGLfixBMHhQjBqR8sVWNTPpcj45WlYL2IObS/DNMLH1DBP0n8qz+aiiLTGfopPEebw==", + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.46.2.tgz", + "integrity": "sha512-nTeCWY83kN64oQ5MGz3CgtPx8NSOhC5lWtsjTs+8JAJNLcP3QbLCtDDgUKQc/Ro/frpMq4SHUaHN6AMltcEoLQ==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.12.2", - "@typescript-eslint/type-utils": "8.12.2", - "@typescript-eslint/utils": "8.12.2", - "@typescript-eslint/visitor-keys": "8.12.2", - "graphemer": "^1.4.0", - "ignore": "^5.3.1", - "natural-compare": "^1.4.0", - "ts-api-utils": "^1.3.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", - "eslint": "^8.57.0 || ^9.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } + "license": "MIT", + "optional": true, + "os": [ + "android" + ] }, - "node_modules/@typescript-eslint/parser": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.12.2.tgz", - "integrity": "sha512-MrvlXNfGPLH3Z+r7Tk+Z5moZAc0dzdVjTgUgwsdGweH7lydysQsnSww3nAmsq8blFuRD5VRlAr9YdEFw3e6PBw==", + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.46.2.tgz", + "integrity": "sha512-HV7bW2Fb/F5KPdM/9bApunQh68YVDU8sO8BvcW9OngQVN3HHHkw99wFupuUJfGR9pYLLAjcAOA6iO+evsbBaPQ==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "@typescript-eslint/scope-manager": "8.12.2", - "@typescript-eslint/types": "8.12.2", - "@typescript-eslint/typescript-estree": "8.12.2", - "@typescript-eslint/visitor-keys": "8.12.2", + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.46.2.tgz", + "integrity": "sha512-SSj8TlYV5nJixSsm/y3QXfhspSiLYP11zpfwp6G/YDXctf3Xkdnk4woJIF5VQe0of2OjzTt8EsxnJDCdHd2xMA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.46.2.tgz", + "integrity": "sha512-ZyrsG4TIT9xnOlLsSSi9w/X29tCbK1yegE49RYm3tu3wF1L/B6LVMqnEWyDB26d9Ecx9zrmXCiPmIabVuLmNSg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.46.2.tgz", + "integrity": "sha512-pCgHFoOECwVCJ5GFq8+gR8SBKnMO+xe5UEqbemxBpCKYQddRQMgomv1104RnLSg7nNvgKy05sLsY51+OVRyiVw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.46.2.tgz", + "integrity": "sha512-EtP8aquZ0xQg0ETFcxUbU71MZlHaw9MChwrQzatiE8U/bvi5uv/oChExXC4mWhjiqK7azGJBqU0tt5H123SzVA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.46.2.tgz", + "integrity": "sha512-qO7F7U3u1nfxYRPM8HqFtLd+raev2K137dsV08q/LRKRLEc7RsiDWihUnrINdsWQxPR9jqZ8DIIZ1zJJAm5PjQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.46.2.tgz", + "integrity": "sha512-3dRaqLfcOXYsfvw5xMrxAk9Lb1f395gkoBYzSFcc/scgRFptRXL9DOaDpMiehf9CO8ZDRJW2z45b6fpU5nwjng==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.46.2.tgz", + "integrity": "sha512-fhHFTutA7SM+IrR6lIfiHskxmpmPTJUXpWIsBXpeEwNgZzZZSg/q4i6FU4J8qOGyJ0TR+wXBwx/L7Ho9z0+uDg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.46.2.tgz", + "integrity": "sha512-i7wfGFXu8x4+FRqPymzjD+Hyav8l95UIZ773j7J7zRYc3Xsxy2wIn4x+llpunexXe6laaO72iEjeeGyUFmjKeA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.46.2.tgz", + "integrity": "sha512-B/l0dFcHVUnqcGZWKcWBSV2PF01YUt0Rvlurci5P+neqY/yMKchGU8ullZvIv5e8Y1C6wOn+U03mrDylP5q9Yw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.46.2.tgz", + "integrity": "sha512-32k4ENb5ygtkMwPMucAb8MtV8olkPT03oiTxJbgkJa7lJ7dZMr0GCFJlyvy+K8iq7F/iuOr41ZdUHaOiqyR3iQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.46.2.tgz", + "integrity": "sha512-t5B2loThlFEauloaQkZg9gxV05BYeITLvLkWOkRXogP4qHXLkWSbSHKM9S6H1schf/0YGP/qNKtiISlxvfmmZw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.46.2.tgz", + "integrity": "sha512-YKjekwTEKgbB7n17gmODSmJVUIvj8CX7q5442/CK80L8nqOUbMtf8b01QkG3jOqyr1rotrAnW6B/qiHwfcuWQA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.46.2.tgz", + "integrity": "sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.46.2.tgz", + "integrity": "sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.46.2.tgz", + "integrity": "sha512-wiJWMIpeaak/jsbaq2HMh/rzZxHVW1rU6coyeNNpMwk5isiPjSTx0a4YLSlYDwBH/WBvLz+EtsNqQScZTLJy3g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.46.2.tgz", + "integrity": "sha512-gBgaUDESVzMgWZhcyjfs9QFK16D8K6QZpwAaVNJxYDLHWayOta4ZMjGm/vsAEy3hvlS2GosVFlBlP9/Wb85DqQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.46.2.tgz", + "integrity": "sha512-CvUo2ixeIQGtF6WvuB87XWqPQkoFAFqW+HUo/WzHwuHDvIwZCtjdWXoYCcr06iKGydiqTclC4jU/TNObC/xKZg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@tailwindcss/node": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.11.tgz", + "integrity": "sha512-yzhzuGRmv5QyU9qLNg4GTlYI6STedBWRE7NjxP45CsFYYq9taI0zJXZBMqIC/c8fViNLhmrbpSFS57EoxUmD6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.3.0", + "enhanced-resolve": "^5.18.1", + "jiti": "^2.4.2", + "lightningcss": "1.30.1", + "magic-string": "^0.30.17", + "source-map-js": "^1.2.1", + "tailwindcss": "4.1.11" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.11.tgz", + "integrity": "sha512-Q69XzrtAhuyfHo+5/HMgr1lAiPP/G40OMFAnws7xcFEYqcypZmdW8eGXaOUIeOl1dzPJBPENXgbjsOyhg2nkrg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.4", + "tar": "^7.4.3" + }, + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.1.11", + "@tailwindcss/oxide-darwin-arm64": "4.1.11", + "@tailwindcss/oxide-darwin-x64": "4.1.11", + "@tailwindcss/oxide-freebsd-x64": "4.1.11", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.11", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.11", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.11", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.11", + "@tailwindcss/oxide-linux-x64-musl": "4.1.11", + "@tailwindcss/oxide-wasm32-wasi": "4.1.11", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.11", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.11" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.11.tgz", + "integrity": "sha512-3IfFuATVRUMZZprEIx9OGDjG3Ou3jG4xQzNTvjDoKmU9JdmoCohQJ83MYd0GPnQIu89YoJqvMM0G3uqLRFtetg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.11.tgz", + "integrity": "sha512-ESgStEOEsyg8J5YcMb1xl8WFOXfeBmrhAwGsFxxB2CxY9evy63+AtpbDLAyRkJnxLy2WsD1qF13E97uQyP1lfQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.11.tgz", + "integrity": "sha512-EgnK8kRchgmgzG6jE10UQNaH9Mwi2n+yw1jWmof9Vyg2lpKNX2ioe7CJdf9M5f8V9uaQxInenZkOxnTVL3fhAw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.11.tgz", + "integrity": "sha512-xdqKtbpHs7pQhIKmqVpxStnY1skuNh4CtbcyOHeX1YBE0hArj2romsFGb6yUmzkq/6M24nkxDqU8GYrKrz+UcA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.11.tgz", + "integrity": "sha512-ryHQK2eyDYYMwB5wZL46uoxz2zzDZsFBwfjssgB7pzytAeCCa6glsiJGjhTEddq/4OsIjsLNMAiMlHNYnkEEeg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.11.tgz", + "integrity": "sha512-mYwqheq4BXF83j/w75ewkPJmPZIqqP1nhoghS9D57CLjsh3Nfq0m4ftTotRYtGnZd3eCztgbSPJ9QhfC91gDZQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.11.tgz", + "integrity": "sha512-m/NVRFNGlEHJrNVk3O6I9ggVuNjXHIPoD6bqay/pubtYC9QIdAMpS+cswZQPBLvVvEF6GtSNONbDkZrjWZXYNQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.11.tgz", + "integrity": "sha512-YW6sblI7xukSD2TdbbaeQVDysIm/UPJtObHJHKxDEcW2exAtY47j52f8jZXkqE1krdnkhCMGqP3dbniu1Te2Fg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.11.tgz", + "integrity": "sha512-e3C/RRhGunWYNC3aSF7exsQkdXzQ/M+aYuZHKnw4U7KQwTJotnWsGOIVih0s2qQzmEzOFIJ3+xt7iq67K/p56Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.11.tgz", + "integrity": "sha512-Xo1+/GU0JEN/C/dvcammKHzeM6NqKovG+6921MR6oadee5XPBaKOumrJCXvopJ/Qb5TH7LX/UAywbqrP4lax0g==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@emnapi/wasi-threads": "^1.0.2", + "@napi-rs/wasm-runtime": "^0.2.11", + "@tybys/wasm-util": "^0.9.0", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.11.tgz", + "integrity": "sha512-UgKYx5PwEKrac3GPNPf6HVMNhUIGuUh4wlDFR2jYYdkX6pL/rn73zTq/4pzUm8fOjAn5L8zDeHp9iXmUGOXZ+w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.11.tgz", + "integrity": "sha512-YfHoggn1j0LK7wR82TOucWc5LDCguHnoS879idHekmmiR7g9HUtMw9MI0NHatS28u/Xlkfi9w5RJWgz2Dl+5Qg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/vite": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.11.tgz", + "integrity": "sha512-RHYhrR3hku0MJFRV+fN2gNbDNEh3dwKvY8XJvTxCSXeMOsCRSr+uKvDWQcbizrHgjML6ZmTE5OwMrl5wKcujCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tailwindcss/node": "4.1.11", + "@tailwindcss/oxide": "4.1.11", + "tailwindcss": "4.1.11" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6 || ^7" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.27.0.tgz", + "integrity": "sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.28.0", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.28.0.tgz", + "integrity": "sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.28.2" + } + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.17.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.17.0.tgz", + "integrity": "sha512-bbAKTCqX5aNVryi7qXVMi+OkB3w/OyblodicMbvE38blyAz7GxXf6XYhklokijuPwwVg9sDLKRxt0ZHXQwZVfQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.21.0" + } + }, + "node_modules/@types/react": { + "version": "19.1.9", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.9.tgz", + "integrity": "sha512-WmdoynAX8Stew/36uTSVMcLJJ1KRh6L3IZRx1PZ7qJtBqT3dYTgyDTx8H1qoRghErydW7xw9mSJ3wS//tCRpFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.1.7", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.7.tgz", + "integrity": "sha512-i5ZzwYpqjmrKenzkoLM2Ibzt6mAsM7pxB6BCIouEVVmgiqaMj1TjaK7hnA36hbW5aZv20kx7Lw6hWzPWg0Rurw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.0.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.38.0.tgz", + "integrity": "sha512-CPoznzpuAnIOl4nhj4tRr4gIPj5AfKgkiJmGQDaq+fQnRJTYlcBjbX3wbciGmpoPf8DREufuPRe1tNMZnGdanA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.38.0", + "@typescript-eslint/type-utils": "8.38.0", + "@typescript-eslint/utils": "8.38.0", + "@typescript-eslint/visitor-keys": "8.38.0", + "graphemer": "^1.4.0", + "ignore": "^7.0.0", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.38.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.38.0.tgz", + "integrity": "sha512-Zhy8HCvBUEfBECzIl1PKqF4p11+d0aUJS1GeUiuqK9WmOug8YCmC4h4bjyBvMyAMI9sbRczmrYL5lKg/YMbrcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.38.0", + "@typescript-eslint/types": "8.38.0", + "@typescript-eslint/typescript-estree": "8.38.0", + "@typescript-eslint/visitor-keys": "8.38.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/project-service": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.38.0.tgz", + "integrity": "sha512-dbK7Jvqcb8c9QfH01YB6pORpqX1mn5gDZc9n63Ak/+jD67oWXn3Gs0M6vddAN+eDXBCS5EmNWzbSxsn9SzFWWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/tsconfig-utils": "^8.38.0", + "@typescript-eslint/types": "^8.38.0", "debug": "^4.3.4" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.38.0.tgz", + "integrity": "sha512-WJw3AVlFFcdT9Ri1xs/lg8LwDqgekWXWhH3iAF+1ZM+QPd7oxQ6jvtW/JPwzAScxitILUIFs0/AnQ/UWHzbATQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.38.0", + "@typescript-eslint/visitor-keys": "8.38.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/tsconfig-utils": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.38.0.tgz", + "integrity": "sha512-Lum9RtSE3EroKk/bYns+sPOodqb2Fv50XOl/gMviMKNvanETUuUcC9ObRbzrJ4VSd2JalPqgSAavwrPiPvnAiQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.38.0.tgz", + "integrity": "sha512-c7jAvGEZVf0ao2z+nnz8BUaHZD09Agbh+DY7qvBQqLiz8uJzRgVPj5YvOh8I8uEiH8oIUGIfHzMwUcGVco/SJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.38.0", + "@typescript-eslint/typescript-estree": "8.38.0", + "@typescript-eslint/utils": "8.38.0", + "debug": "^4.3.4", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.38.0.tgz", + "integrity": "sha512-wzkUfX3plUqij4YwWaJyqhiPE5UCRVlFpKn1oCRn2O1bJ592XxWJj8ROQ3JD5MYXLORW84063z3tZTb/cs4Tyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.38.0.tgz", + "integrity": "sha512-fooELKcAKzxux6fA6pxOflpNS0jc+nOQEEOipXFNjSlBS6fqrJOVY/whSn70SScHrcJ2LDsxWrneFoWYSVfqhQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/project-service": "8.38.0", + "@typescript-eslint/tsconfig-utils": "8.38.0", + "@typescript-eslint/types": "8.38.0", + "@typescript-eslint/visitor-keys": "8.38.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.1.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/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==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz", + "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.38.0.tgz", + "integrity": "sha512-hHcMA86Hgt+ijJlrD8fX0j1j8w4C92zue/8LOPAFioIno+W0+L7KqE8QZKCcPGc/92Vs9x36w/4MPTJhqXdyvg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.7.0", + "@typescript-eslint/scope-manager": "8.38.0", + "@typescript-eslint/types": "8.38.0", + "@typescript-eslint/typescript-estree": "8.38.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.38.0.tgz", + "integrity": "sha512-pWrTcoFNWuwHlA9CvlfSsGWs14JxfN1TH25zM5L7o0pRLhsoZkDnTsXfQRJBEWJoV5DL0jf+Z+sxiud+K0mq1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.38.0", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.7.0.tgz", + "integrity": "sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.28.0", + "@babel/plugin-transform-react-jsx-self": "^7.27.1", + "@babel/plugin-transform-react-jsx-source": "^7.27.1", + "@rolldown/pluginutils": "1.0.0-beta.27", + "@types/babel__core": "^7.20.5", + "react-refresh": "^0.17.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "peerDependencies": { + "vite": "^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0" + } + }, + "node_modules/acorn": { + "version": "8.15.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", + "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "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==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", + "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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==", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.25.1", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz", + "integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001726", + "electron-to-chromium": "^1.5.173", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/call-bind": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "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", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "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==", + "dev": true, + "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/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001731", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001731.tgz", + "integrity": "sha512-lDdp2/wrOmTRWuoB5DpfNkC0rJDU8DqRa6nYL6HK6sytw70QMopt/NIc/9SM7ylItlBWfACXk0tEn37UWM/+mg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "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/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/convex": { + "version": "1.25.4", + "resolved": "https://registry.npmjs.org/convex/-/convex-1.25.4.tgz", + "integrity": "sha512-LiGZZTmbe5iHWwDOYfSA00w+uDM8kgLC0ohFJW0VgQlKcs8famHCE6yuplk4wwXyj9Lhb1+yMRfrAD2ZEquqHg==", + "license": "Apache-2.0", + "dependencies": { + "esbuild": "0.25.4", + "jwt-decode": "^4.0.0", + "prettier": "3.5.3" + }, + "bin": { + "convex": "bin/main.js" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=7.0.0" + }, + "peerDependencies": { + "@auth0/auth0-react": "^2.0.1", + "@clerk/clerk-react": "^4.12.8 || ^5.0.0", + "react": "^18.0.0 || ^19.0.0-0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@auth0/auth0-react": { + "optional": true + }, + "@clerk/clerk-react": { + "optional": true + }, + "react": { + "optional": true + } + } + }, + "node_modules/convex-helpers": { + "version": "0.1.100", + "resolved": "https://registry.npmjs.org/convex-helpers/-/convex-helpers-0.1.100.tgz", + "integrity": "sha512-In5VPKKlQdnv9WHpIKLXnLEKyHxaJYI0BXWTDJ27Ao6XUfpeiGPDGhOdqZ8y0DqTcQlDgmtSTmmttUv1fPWbdg==", + "license": "Apache-2.0", + "bin": { + "convex-helpers": "bin.cjs" + }, + "peerDependencies": { + "@standard-schema/spec": "^1.0.0", + "convex": "^1.13.0", + "hono": "^4.0.5", + "react": "^17.0.2 || ^18.0.0 || ^19.0.0", + "typescript": "^5.5", + "zod": "^3.22.4" + }, + "peerDependenciesMeta": { + "@standard-schema/spec": { + "optional": true + }, + "hono": { + "optional": true + }, + "react": { + "optional": true + }, + "typescript": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, + "node_modules/convex/node_modules/prettier": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz", + "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "dev": true, + "license": "MIT" + }, + "node_modules/data-view-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/data-view-byte-length": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/inspect-js" + } + }, + "node_modules/data-view-byte-offset": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-data-view": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/detect-libc": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", + "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.194", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.194.tgz", + "integrity": "sha512-SdnWJwSUot04UR51I2oPD8kuP2VI37/CADR1OHsFOUzZIvfWJBO6q11k5P/uKNyTT3cdOsnyjkrZ+DDShqYqJA==", + "dev": true, + "license": "ISC" + }, + "node_modules/enhanced-resolve": { + "version": "5.18.2", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.2.tgz", + "integrity": "sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.24.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.0.tgz", + "integrity": "sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", + "has-property-descriptors": "^1.0.2", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", + "is-callable": "^1.2.7", + "is-data-view": "^1.0.2", + "is-negative-zero": "^2.0.3", + "is-regex": "^1.2.1", + "is-set": "^2.0.3", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.1", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.4", + "object-keys": "^1.1.1", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.4", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "stop-iteration-iterator": "^1.1.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", + "string.prototype.trimstart": "^1.0.8", + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.19" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-to-primitive": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/esbuild": { + "version": "0.25.4", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.4.tgz", + "integrity": "sha512-8pgjLUcUjcgDg+2Q4NYXnPbo/vncAY4UmyaCm0jZevERqCHZIaWwdJHkf8XQtu4AxSKCdvrUbT0XUr1IdZzI8Q==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.4", + "@esbuild/android-arm": "0.25.4", + "@esbuild/android-arm64": "0.25.4", + "@esbuild/android-x64": "0.25.4", + "@esbuild/darwin-arm64": "0.25.4", + "@esbuild/darwin-x64": "0.25.4", + "@esbuild/freebsd-arm64": "0.25.4", + "@esbuild/freebsd-x64": "0.25.4", + "@esbuild/linux-arm": "0.25.4", + "@esbuild/linux-arm64": "0.25.4", + "@esbuild/linux-ia32": "0.25.4", + "@esbuild/linux-loong64": "0.25.4", + "@esbuild/linux-mips64el": "0.25.4", + "@esbuild/linux-ppc64": "0.25.4", + "@esbuild/linux-riscv64": "0.25.4", + "@esbuild/linux-s390x": "0.25.4", + "@esbuild/linux-x64": "0.25.4", + "@esbuild/netbsd-arm64": "0.25.4", + "@esbuild/netbsd-x64": "0.25.4", + "@esbuild/openbsd-arm64": "0.25.4", + "@esbuild/openbsd-x64": "0.25.4", + "@esbuild/sunos-x64": "0.25.4", + "@esbuild/win32-arm64": "0.25.4", + "@esbuild/win32-ia32": "0.25.4", + "@esbuild/win32-x64": "0.25.4" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.32.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.32.0.tgz", + "integrity": "sha512-LSehfdpgMeWcTZkWZVIJl+tkZ2nuSkyyB9C27MZqFWXuph7DvaowgcTvKqxvpLW1JZIk8PN7hFY3Rj9LQ7m7lg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.21.0", + "@eslint/config-helpers": "^0.3.0", + "@eslint/core": "^0.15.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.32.0", + "@eslint/plugin-kit": "^0.3.4", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.4.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" + "jiti": "*" }, "peerDependenciesMeta": { - "typescript": { + "jiti": { "optional": true } } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.12.2.tgz", - "integrity": "sha512-gPLpLtrj9aMHOvxJkSbDBmbRuYdtiEbnvO25bCMza3DhMjTQw0u7Y1M+YR5JPbMsXXnSPuCf5hfq0nEkQDL/JQ==", + "node_modules/eslint-plugin-react-hooks": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-5.2.0.tgz", + "integrity": "sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0" + } + }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.4.20", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.20.tgz", + "integrity": "sha512-XpbHQ2q5gUF8BGOX4dHe+71qoirYMhApEPZ7sfhF/dNnOF1UXnCMGZf79SFTBO7Bz5YEIT4TMieSlJBWhP9WBA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": ">=8.40" + } + }, + "node_modules/eslint-scope": { + "version": "8.4.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", + "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", + "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", + "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.15.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.12.2", - "@typescript-eslint/visitor-keys": "8.12.2" + "flatted": "^3.2.9", + "keyv": "^4.5.4" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=16" } }, - "node_modules/@typescript-eslint/type-utils": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.12.2.tgz", - "integrity": "sha512-bwuU4TAogPI+1q/IJSKuD4shBLc/d2vGcRT588q+jzayQyjVK2X6v/fbR4InY2U2sgf8MEvVCqEWUzYzgBNcGQ==", + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/for-each": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/typescript-estree": "8.12.2", - "@typescript-eslint/utils": "8.12.2", - "debug": "^4.3.4", - "ts-api-utils": "^1.3.0" + "is-callable": "^1.2.7" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@typescript-eslint/types": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.12.2.tgz", - "integrity": "sha512-VwDwMF1SZ7wPBUZwmMdnDJ6sIFk4K4s+ALKLP6aIQsISkPv8jhiw65sAK6SuWODN/ix+m+HgbYDkH+zLjrzvOA==", + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.12.2.tgz", - "integrity": "sha512-mME5MDwGe30Pq9zKPvyduyU86PH7aixwqYR2grTglAdB+AN8xXQ1vFGpYaUSJ5o5P/5znsSBeNcs5g5/2aQwow==", + "node_modules/function.prototype.name": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.12.2", - "@typescript-eslint/visitor-keys": "8.12.2", - "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "dev": true, + "license": "MIT", "dependencies": { - "brace-expansion": "^2.0.1" + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/@typescript-eslint/utils": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.12.2.tgz", - "integrity": "sha512-UTTuDIX3fkfAz6iSVa5rTuSfWIYZ6ATtEocQ/umkRSyC9O919lbZ8dcH7mysshrCdrAM03skJOEYaBugxN+M6A==", + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", "dev": true, + "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.12.2", - "@typescript-eslint/types": "8.12.2", - "@typescript-eslint/typescript-estree": "8.12.2" + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0" + "node": ">= 0.4" } }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.12.2.tgz", - "integrity": "sha512-PChz8UaKQAVNHghsHcPyx1OMHoFRUEA7rJSK/mDhdq85bk+PLsUHUBqTQTFt18VJZbmxBovM65fezlheQRsSDA==", + "node_modules/get-symbol-description": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", "dev": true, + "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.12.2", - "eslint-visitor-keys": "^3.4.3" + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">= 0.4" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/acorn": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", - "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "dev": true, - "bin": { - "acorn": "bin/acorn" + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" }, "engines": { - "node": ">=0.4.0" + "node": ">=10.13.0" } }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "node_modules/globals": { + "version": "15.15.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", + "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==", "dev": true, - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "node_modules/globalthis": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", + "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", "dev": true, + "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "define-properties": "^1.2.1", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "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==", - "dev": true - }, - "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==", - "dev": true + "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==", + "dev": true, + "license": "ISC" }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } + "license": "MIT" }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "node_modules/has-bigints": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", + "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", "dev": true, - "dependencies": { - "fill-range": "^7.1.1" - }, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "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==", "dev": true, + "license": "MIT", "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", "dev": true, + "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" + "es-define-property": "^1.0.0" }, "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/has-proto": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", "dev": true, + "license": "MIT", "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "node_modules/convex": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/convex/-/convex-1.17.0.tgz", - "integrity": "sha512-fNv5GYvkGYIUYbn8ANnJWabjVqbFoUfm8ExDxlWxeDZAuafPJmatVaQWHZ1k+oYD0pmnchrhmtmMV8mX7T0s9A==", - "dependencies": { - "esbuild": "0.23.0", - "jwt-decode": "^3.1.2", - "prettier": "3.2.5" - }, - "bin": { - "convex": "bin/main.js" + "dunder-proto": "^1.0.0" }, "engines": { - "node": ">=18.0.0", - "npm": ">=7.0.0" - }, - "peerDependencies": { - "@auth0/auth0-react": "^2.0.1", - "@clerk/clerk-react": "^4.12.8 || ^5.0.0", - "react": "^17.0.2 || ^18.0.0", - "react-dom": "^17.0.2 || ^18.0.0" - }, - "peerDependenciesMeta": { - "@auth0/auth0-react": { - "optional": true - }, - "@clerk/clerk-react": { - "optional": true - }, - "react": { - "optional": true - }, - "react-dom": { - "optional": true - } - } - }, - "node_modules/convex-helpers": { - "version": "0.1.63", - "resolved": "https://registry.npmjs.org/convex-helpers/-/convex-helpers-0.1.63.tgz", - "integrity": "sha512-SJZySPcu4G6zdtzw/Pr9mzhBDzPsghfHNB3L1Vtu9IICydJ3hj9iPNLnbFfH7Jm/4gmDpffTANpdRjMr5YXkKg==", - "bin": { - "convex-helpers": "bin.cjs" - }, - "peerDependencies": { - "convex": "^1.13.0", - "hono": "^4.0.5", - "react": "^17.0.2 || ^18.0.0", - "zod": "^3.22.4" + "node": ">= 0.4" }, - "peerDependenciesMeta": { - "hono": { - "optional": true - }, - "react": { - "optional": true - }, - "zod": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/convex-test": { - "version": "0.0.34", - "resolved": "https://registry.npmjs.org/convex-test/-/convex-test-0.0.34.tgz", - "integrity": "sha512-srntn1drKy0Aa8zzatvJ10ZJFVpBYvLWQrhTibdfnslQqNdzQV5Ui4XKFtmrEmqw+DjmeJATgvZHbLzhP7Dh4w==", + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "dev": true, - "peerDependencies": { - "convex": "^1.16.4" + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, + "license": "MIT", "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "has-symbols": "^1.0.3" }, "engines": { - "node": ">= 8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", "dev": true, + "license": "MIT", "dependencies": { - "ms": "^2.1.3" + "function-bind": "^1.1.2" }, "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } + "node": ">= 0.4" } }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true + "node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true, + "license": "ISC" }, - "node_modules/esbuild": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.0.tgz", - "integrity": "sha512-1lvV17H2bMYda/WaFb2jLPeHU3zml2k4/yagNMG8Q/YtfMjCwEUZa2eXXMgZTVSL5q1n4H7sQ0X6CdJDqqeCFA==", - "hasInstallScript": true, - "bin": { - "esbuild": "bin/esbuild" - }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.23.0", - "@esbuild/android-arm": "0.23.0", - "@esbuild/android-arm64": "0.23.0", - "@esbuild/android-x64": "0.23.0", - "@esbuild/darwin-arm64": "0.23.0", - "@esbuild/darwin-x64": "0.23.0", - "@esbuild/freebsd-arm64": "0.23.0", - "@esbuild/freebsd-x64": "0.23.0", - "@esbuild/linux-arm": "0.23.0", - "@esbuild/linux-arm64": "0.23.0", - "@esbuild/linux-ia32": "0.23.0", - "@esbuild/linux-loong64": "0.23.0", - "@esbuild/linux-mips64el": "0.23.0", - "@esbuild/linux-ppc64": "0.23.0", - "@esbuild/linux-riscv64": "0.23.0", - "@esbuild/linux-s390x": "0.23.0", - "@esbuild/linux-x64": "0.23.0", - "@esbuild/netbsd-x64": "0.23.0", - "@esbuild/openbsd-arm64": "0.23.0", - "@esbuild/openbsd-x64": "0.23.0", - "@esbuild/sunos-x64": "0.23.0", - "@esbuild/win32-arm64": "0.23.0", - "@esbuild/win32-ia32": "0.23.0", - "@esbuild/win32-x64": "0.23.0" + "node": ">= 4" } }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, "engines": { - "node": ">=10" + "node": ">=6" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/eslint": { - "version": "9.13.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.13.0.tgz", - "integrity": "sha512-EYZK6SX6zjFHST/HRytOdA/zE72Cq/bfw45LSyuwrdvcclb/gqV8RRQxywOBEWO2+WDpva6UZa4CcDeJKzUCFA==", + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/internal-slot": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", "dev": true, + "license": "MIT", "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.11.0", - "@eslint/config-array": "^0.18.0", - "@eslint/core": "^0.7.0", - "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "9.13.0", - "@eslint/plugin-kit": "^0.2.0", - "@humanfs/node": "^0.16.5", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.3.1", - "@types/estree": "^1.0.6", - "@types/json-schema": "^7.0.15", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.1.0", - "eslint-visitor-keys": "^4.1.0", - "espree": "^10.2.0", - "esquery": "^1.5.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" + "es-errors": "^1.3.0", + "hasown": "^2.0.2", + "side-channel": "^1.1.0" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } + "node": ">= 0.4" } }, - "node_modules/eslint-scope": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.1.0.tgz", - "integrity": "sha512-14dSvlhaVhKKsa9Fx1l8A17s7ah7Ef7wCakJ10LYk6+GYmP9yDti2oq2SEwcyndt6knfcZyhyxwY3i9yL78EQw==", + "node_modules/is-array-buffer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", "dev": true, + "license": "MIT", "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">= 0.4" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", "dev": true, + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node": ">= 0.4" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/eslint/node_modules/eslint-visitor-keys": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz", - "integrity": "sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==", + "node_modules/is-bigint": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", "dev": true, + "license": "MIT", + "dependencies": { + "has-bigints": "^1.0.2" + }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">= 0.4" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/espree": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.2.0.tgz", - "integrity": "sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g==", + "node_modules/is-boolean-object": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", "dev": true, + "license": "MIT", "dependencies": { - "acorn": "^8.12.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.1.0" + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">= 0.4" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/espree/node_modules/eslint-visitor-keys": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz", - "integrity": "sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==", + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", "dev": true, + "license": "MIT", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">= 0.4" }, "funding": { - "url": "https://opencollective.com/eslint" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", "dev": true, + "license": "MIT", "dependencies": { - "estraverse": "^5.1.0" + "hasown": "^2.0.2" }, "engines": { - "node": ">=0.10" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "node_modules/is-data-view": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", "dev": true, + "license": "MIT", "dependencies": { - "estraverse": "^5.2.0" + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "is-typed-array": "^1.1.13" }, "engines": { - "node": ">=4.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "node_modules/is-date-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" + }, "engines": { - "node": ">=4.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", "dev": true, + "license": "MIT", "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "call-bound": "^1.0.3" }, "engines": { - "node": ">=8.6.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "node_modules/is-generator-function": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", + "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", "dev": true, + "license": "MIT", "dependencies": { - "is-glob": "^4.0.1" + "call-bound": "^1.0.3", + "get-proto": "^1.0.0", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" }, "engines": { - "node": ">= 6" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "dev": true, + "license": "MIT", "dependencies": { - "reusify": "^1.0.4" + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" } }, - "node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "node_modules/is-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", "dev": true, - "dependencies": { - "flat-cache": "^4.0.0" - }, + "license": "MIT", "engines": { - "node": ">=16.0.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "node_modules/is-negative-zero": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", + "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", "dev": true, - "dependencies": { - "to-regex-range": "^5.0.1" + "license": "MIT", + "engines": { + "node": ">= 0.4" }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=0.12.0" } }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "node_modules/is-number-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", "dev": true, + "license": "MIT", "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" }, "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "node_modules/is-regex": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", "dev": true, + "license": "MIT", "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" }, "engines": { - "node": ">=16" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", "dev": true, - "dependencies": { - "is-glob": "^4.0.3" - }, + "license": "MIT", "engines": { - "node": ">=10.13.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/globals": { - "version": "15.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-15.11.0.tgz", - "integrity": "sha512-yeyNSjdbyVaWurlwCpcA6XNBrHTMIeDdj0/hnvX/OLJ9ekOXYbLsLinH/MucQyGvNnXhidTdNhTtJaffL2sMfw==", + "node_modules/is-shared-array-buffer": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, "engines": { - "node": ">=18" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "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==", + "node_modules/is-string": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" + }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "node_modules/is-symbol": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" + }, "engines": { - "node": ">= 4" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "node_modules/is-typed-array": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", "dev": true, + "license": "MIT", "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" + "which-typed-array": "^1.1.16" }, "engines": { - "node": ">=6" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", "dev": true, + "license": "MIT", "engines": { - "node": ">=0.8.19" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "node_modules/is-weakref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", "dev": true, + "license": "MIT", "dependencies": { - "is-extglob": "^2.1.1" + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", "dev": true, - "engines": { - "node": ">=0.12.0" - } + "license": "MIT" }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "dev": true, + "license": "ISC" + }, + "node_modules/jiti": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.5.1.tgz", + "integrity": "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" }, "node_modules/js-yaml": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, + "license": "MIT", "dependencies": { "argparse": "^2.0.1" }, @@ -1533,49 +3936,346 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true, + "license": "MIT" }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } }, "node_modules/jwt-decode": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", - "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz", + "integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==", + "license": "MIT", + "engines": { + "node": ">=18" + } }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", "dev": true, + "license": "MIT", "dependencies": { "json-buffer": "3.0.1" } }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lightningcss": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz", + "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-darwin-arm64": "1.30.1", + "lightningcss-darwin-x64": "1.30.1", + "lightningcss-freebsd-x64": "1.30.1", + "lightningcss-linux-arm-gnueabihf": "1.30.1", + "lightningcss-linux-arm64-gnu": "1.30.1", + "lightningcss-linux-arm64-musl": "1.30.1", + "lightningcss-linux-x64-gnu": "1.30.1", + "lightningcss-linux-x64-musl": "1.30.1", + "lightningcss-win32-arm64-msvc": "1.30.1", + "lightningcss-win32-x64-msvc": "1.30.1" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz", + "integrity": "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz", + "integrity": "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz", + "integrity": "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz", + "integrity": "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz", + "integrity": "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz", + "integrity": "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz", + "integrity": "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz", + "integrity": "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz", + "integrity": "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz", + "integrity": "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", "dev": true, + "license": "MIT", "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" }, "engines": { - "node": ">= 0.8.0" + "node": ">=4" } }, "node_modules/locate-path": { @@ -1583,6 +4283,7 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "dev": true, + "license": "MIT", "dependencies": { "p-locate": "^5.0.0" }, @@ -1597,13 +4298,54 @@ "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/magic-string": { + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/memorystream": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", + "dev": true, + "engines": { + "node": ">= 0.10.0" + } }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", "dev": true, + "license": "MIT", "engines": { "node": ">= 8" } @@ -1613,6 +4355,7 @@ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, + "license": "MIT", "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" @@ -1626,6 +4369,7 @@ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" }, @@ -1633,1579 +4377,1791 @@ "node": "*" } }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minizlib": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz", + "integrity": "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/mkdirp": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", + "dev": true, + "license": "MIT", + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true + "dev": true, + "license": "MIT" }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "node_modules/nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/node-releases": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", "dev": true, + "license": "MIT" + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" } }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/npm-run-all": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", + "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", "dev": true, + "license": "MIT", "dependencies": { - "yocto-queue": "^0.1.0" + "ansi-styles": "^3.2.1", + "chalk": "^2.4.1", + "cross-spawn": "^6.0.5", + "memorystream": "^0.3.1", + "minimatch": "^3.0.4", + "pidtree": "^0.3.0", + "read-pkg": "^3.0.0", + "shell-quote": "^1.6.1", + "string.prototype.padend": "^3.0.0" }, - "engines": { - "node": ">=10" + "bin": { + "npm-run-all": "bin/npm-run-all/index.js", + "run-p": "bin/run-p/index.js", + "run-s": "bin/run-s/index.js" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">= 4" } }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "node_modules/npm-run-all/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "dev": true, + "license": "MIT", "dependencies": { - "p-limit": "^3.0.2" + "color-convert": "^1.9.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=4" } }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "node_modules/npm-run-all/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", "dev": true, + "license": "MIT", "dependencies": { - "callsites": "^3.0.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" }, "engines": { - "node": ">=6" + "node": ">=4" } }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "node_modules/npm-run-all/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/npm-run-all/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/npm-run-all/node_modules/cross-spawn": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", + "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, "engines": { - "node": ">=8" + "node": ">=4.8" } }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "node_modules/npm-run-all/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8" + "node": ">=0.8.0" } }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "node_modules/npm-run-all/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", "dev": true, + "license": "MIT", "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "node": ">=4" } }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "node_modules/npm-run-all/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", "dev": true, + "license": "MIT", "engines": { - "node": ">= 0.8.0" + "node": ">=4" } }, - "node_modules/prettier": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", - "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "node_modules/npm-run-all/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" + "semver": "bin/semver" } }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "node_modules/npm-run-all/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^1.0.0" + }, "engines": { - "node": ">=6" + "node": ">=0.10.0" } }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "node_modules/npm-run-all/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/rand-seed": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/rand-seed/-/rand-seed-2.1.7.tgz", - "integrity": "sha512-Yaz75D2fTWtIr69iDd+PGwtQkFkqOIMQZl+W8U3NMR6F2a1UEk2FmnQkNd6Z1eNtL96Z5nznw5PKYk1Z9m6lxw==" + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "node_modules/npm-run-all/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, "engines": { "node": ">=4" } }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "node_modules/npm-run-all/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "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==", "dev": true, + "license": "MIT", "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "queue-microtask": "^1.2.2" + "license": "MIT", + "engines": { + "node": ">= 0.4" } }, - "node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "node_modules/object.assign": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", "dev": true, - "bin": { - "semver": "bin/semver.js" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", + "object-keys": "^1.1.1" }, "engines": { - "node": ">=10" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "dev": true, + "license": "MIT", "dependencies": { - "shebang-regex": "^3.0.0" + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" }, "engines": { - "node": ">=8" + "node": ">= 0.8.0" } }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, "engines": { - "node": ">=8" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, "engines": { - "node": ">=8" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "dev": true, + "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "p-limit": "^3.0.2" }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "dev": true, + "license": "MIT", "dependencies": { - "is-number": "^7.0.0" + "callsites": "^3.0.0" }, "engines": { - "node": ">=8.0" + "node": ">=6" } }, - "node_modules/ts-api-utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", - "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "node_modules/parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", "dev": true, - "engines": { - "node": ">=16" + "license": "MIT", + "dependencies": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" }, - "peerDependencies": { - "typescript": ">=4.2.0" + "engines": { + "node": ">=4" } }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "dev": true, - "dependencies": { - "prelude-ls": "^1.2.1" - }, + "license": "MIT", "engines": { - "node": ">= 0.8.0" + "node": ">=8" } }, - "node_modules/typescript": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", - "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, + "license": "MIT", "engines": { - "node": ">=14.17" + "node": ">=8" } }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "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==", "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } + "license": "MIT" }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "node_modules/path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", "dev": true, + "license": "MIT", "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" + "pify": "^3.0.0" }, "engines": { - "node": ">= 8" + "node": ">=4" } }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "dev": true, - "engines": { - "node": ">=0.10.0" - } + "license": "ISC" }, - "node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=8.6" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - } - }, - "dependencies": { - "@convex-dev/aggregate": { - "version": "file:..", - "requires": { - "@eslint/js": "^9.9.1", - "@fast-check/vitest": "^0.1.3", - "@types/node": "^18.17.0", - "@vitest/coverage-v8": "^2.1.1", - "convex-test": "^0.0.34", - "eslint": "^9.9.1", - "globals": "^15.9.0", - "prettier": "3.2.5", - "typescript": "~5.0.3", - "typescript-eslint": "^8.4.0", - "vitest": "^2.1.1" + "url": "https://github.com/sponsors/jonschlinkert" } }, - "@convex-dev/migrations": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/@convex-dev/migrations/-/migrations-0.2.1.tgz", - "integrity": "sha512-n4vBPk3IURqvnpFR5wLs9cPeTlBmTTyvtbdE3Mda6CrbpBrEm9t6B9jmPkioqsi1PSS4ezg4yYd8qDj7n0Bo5A==", - "requires": {} - }, - "@esbuild/aix-ppc64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.0.tgz", - "integrity": "sha512-3sG8Zwa5fMcA9bgqB8AfWPQ+HFke6uD3h1s3RIwUNK8EG7a4buxvuFTs3j1IMs2NXAk9F30C/FF4vxRgQCcmoQ==", - "optional": true - }, - "@esbuild/android-arm": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.0.tgz", - "integrity": "sha512-+KuOHTKKyIKgEEqKbGTK8W7mPp+hKinbMBeEnNzjJGyFcWsfrXjSTNluJHCY1RqhxFurdD8uNXQDei7qDlR6+g==", - "optional": true - }, - "@esbuild/android-arm64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.0.tgz", - "integrity": "sha512-EuHFUYkAVfU4qBdyivULuu03FhJO4IJN9PGuABGrFy4vUuzk91P2d+npxHcFdpUnfYKy0PuV+n6bKIpHOB3prQ==", - "optional": true - }, - "@esbuild/android-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.0.tgz", - "integrity": "sha512-WRrmKidLoKDl56LsbBMhzTTBxrsVwTKdNbKDalbEZr0tcsBgCLbEtoNthOW6PX942YiYq8HzEnb4yWQMLQuipQ==", - "optional": true - }, - "@esbuild/darwin-arm64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.0.tgz", - "integrity": "sha512-YLntie/IdS31H54Ogdn+v50NuoWF5BDkEUFpiOChVa9UnKpftgwzZRrI4J132ETIi+D8n6xh9IviFV3eXdxfow==", - "optional": true - }, - "@esbuild/darwin-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.0.tgz", - "integrity": "sha512-IMQ6eme4AfznElesHUPDZ+teuGwoRmVuuixu7sv92ZkdQcPbsNHzutd+rAfaBKo8YK3IrBEi9SLLKWJdEvJniQ==", - "optional": true - }, - "@esbuild/freebsd-arm64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.0.tgz", - "integrity": "sha512-0muYWCng5vqaxobq6LB3YNtevDFSAZGlgtLoAc81PjUfiFz36n4KMpwhtAd4he8ToSI3TGyuhyx5xmiWNYZFyw==", - "optional": true - }, - "@esbuild/freebsd-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.0.tgz", - "integrity": "sha512-XKDVu8IsD0/q3foBzsXGt/KjD/yTKBCIwOHE1XwiXmrRwrX6Hbnd5Eqn/WvDekddK21tfszBSrE/WMaZh+1buQ==", - "optional": true - }, - "@esbuild/linux-arm": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.0.tgz", - "integrity": "sha512-SEELSTEtOFu5LPykzA395Mc+54RMg1EUgXP+iw2SJ72+ooMwVsgfuwXo5Fn0wXNgWZsTVHwY2cg4Vi/bOD88qw==", - "optional": true - }, - "@esbuild/linux-arm64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.0.tgz", - "integrity": "sha512-j1t5iG8jE7BhonbsEg5d9qOYcVZv/Rv6tghaXM/Ug9xahM0nX/H2gfu6X6z11QRTMT6+aywOMA8TDkhPo8aCGw==", - "optional": true - }, - "@esbuild/linux-ia32": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.0.tgz", - "integrity": "sha512-P7O5Tkh2NbgIm2R6x1zGJJsnacDzTFcRWZyTTMgFdVit6E98LTxO+v8LCCLWRvPrjdzXHx9FEOA8oAZPyApWUA==", - "optional": true - }, - "@esbuild/linux-loong64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.0.tgz", - "integrity": "sha512-InQwepswq6urikQiIC/kkx412fqUZudBO4SYKu0N+tGhXRWUqAx+Q+341tFV6QdBifpjYgUndV1hhMq3WeJi7A==", - "optional": true - }, - "@esbuild/linux-mips64el": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.0.tgz", - "integrity": "sha512-J9rflLtqdYrxHv2FqXE2i1ELgNjT+JFURt/uDMoPQLcjWQA5wDKgQA4t/dTqGa88ZVECKaD0TctwsUfHbVoi4w==", - "optional": true - }, - "@esbuild/linux-ppc64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.0.tgz", - "integrity": "sha512-cShCXtEOVc5GxU0fM+dsFD10qZ5UpcQ8AM22bYj0u/yaAykWnqXJDpd77ublcX6vdDsWLuweeuSNZk4yUxZwtw==", - "optional": true - }, - "@esbuild/linux-riscv64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.0.tgz", - "integrity": "sha512-HEtaN7Y5UB4tZPeQmgz/UhzoEyYftbMXrBCUjINGjh3uil+rB/QzzpMshz3cNUxqXN7Vr93zzVtpIDL99t9aRw==", - "optional": true - }, - "@esbuild/linux-s390x": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.0.tgz", - "integrity": "sha512-WDi3+NVAuyjg/Wxi+o5KPqRbZY0QhI9TjrEEm+8dmpY9Xir8+HE/HNx2JoLckhKbFopW0RdO2D72w8trZOV+Wg==", - "optional": true - }, - "@esbuild/linux-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.0.tgz", - "integrity": "sha512-a3pMQhUEJkITgAw6e0bWA+F+vFtCciMjW/LPtoj99MhVt+Mfb6bbL9hu2wmTZgNd994qTAEw+U/r6k3qHWWaOQ==", - "optional": true - }, - "@esbuild/netbsd-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.0.tgz", - "integrity": "sha512-cRK+YDem7lFTs2Q5nEv/HHc4LnrfBCbH5+JHu6wm2eP+d8OZNoSMYgPZJq78vqQ9g+9+nMuIsAO7skzphRXHyw==", - "optional": true - }, - "@esbuild/openbsd-arm64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.0.tgz", - "integrity": "sha512-suXjq53gERueVWu0OKxzWqk7NxiUWSUlrxoZK7usiF50C6ipColGR5qie2496iKGYNLhDZkPxBI3erbnYkU0rQ==", - "optional": true - }, - "@esbuild/openbsd-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.0.tgz", - "integrity": "sha512-6p3nHpby0DM/v15IFKMjAaayFhqnXV52aEmv1whZHX56pdkK+MEaLoQWj+H42ssFarP1PcomVhbsR4pkz09qBg==", - "optional": true - }, - "@esbuild/sunos-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.0.tgz", - "integrity": "sha512-BFelBGfrBwk6LVrmFzCq1u1dZbG4zy/Kp93w2+y83Q5UGYF1d8sCzeLI9NXjKyujjBBniQa8R8PzLFAUrSM9OA==", - "optional": true - }, - "@esbuild/win32-arm64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.0.tgz", - "integrity": "sha512-lY6AC8p4Cnb7xYHuIxQ6iYPe6MfO2CC43XXKo9nBXDb35krYt7KGhQnOkRGar5psxYkircpCqfbNDB4uJbS2jQ==", - "optional": true - }, - "@esbuild/win32-ia32": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.0.tgz", - "integrity": "sha512-7L1bHlOTcO4ByvI7OXVI5pNN6HSu6pUQq9yodga8izeuB1KcT2UkHaH6118QJwopExPn0rMHIseCTx1CRo/uNA==", - "optional": true - }, - "@esbuild/win32-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.0.tgz", - "integrity": "sha512-Arm+WgUFLUATuoxCJcahGuk6Yj9Pzxd6l11Zb/2aAuv5kWWvvfhLFo2fni4uSK5vzlUdCGZ/BdV5tH8klj8p8g==", - "optional": true - }, - "@eslint-community/eslint-utils": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", - "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", + "node_modules/pidtree": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.1.tgz", + "integrity": "sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==", "dev": true, - "requires": { - "eslint-visitor-keys": "^3.4.3" + "license": "MIT", + "bin": { + "pidtree": "bin/pidtree.js" + }, + "engines": { + "node": ">=0.10" } }, - "@eslint-community/regexpp": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", - "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", - "dev": true - }, - "@eslint/config-array": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.18.0.tgz", - "integrity": "sha512-fTxvnS1sRMu3+JjXwJG0j/i4RT9u4qJ+lqS/yCGap4lH4zZGzQ7tu+xZqQmcMZq5OBZDL4QRxQzRjkWcGt8IVw==", + "node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", "dev": true, - "requires": { - "@eslint/object-schema": "^2.1.4", - "debug": "^4.3.1", - "minimatch": "^3.1.2" + "license": "MIT", + "engines": { + "node": ">=4" } }, - "@eslint/core": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.7.0.tgz", - "integrity": "sha512-xp5Jirz5DyPYlPiKat8jaq0EmYvDXKKpzTbxXMpT9eqlRJkRKIz9AGMdlvYjih+im+QlhWrpvVjl8IPC/lHlUw==", - "dev": true + "node_modules/possible-typed-array-names": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", + "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } }, - "@eslint/eslintrc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.1.0.tgz", - "integrity": "sha512-4Bfj15dVJdoy3RfZmmo86RK1Fwzn6SstsvK9JS+BaVKqC6QQQQyXekNaC+g+LKNgkQ+2VhGAzm6hO40AhMR3zQ==", + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", "dev": true, - "requires": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "dependencies": { - "globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" } }, - "@eslint/js": { - "version": "9.13.0", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.13.0.tgz", - "integrity": "sha512-IFLyoY4d72Z5y/6o/BazFBezupzI/taV8sGumxTAVw3lXG9A6md1Dc34T9s1FoD/an9pJH8RHbAxsaEbBed9lA==", - "dev": true - }, - "@eslint/object-schema": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.4.tgz", - "integrity": "sha512-BsWiH1yFGjXXS2yvrf5LyuoSIIbPrGUWob917o+BTKuZ7qJdxX8aJLRxs1fS9n6r7vESrq1OUqb68dANcFXuQQ==", - "dev": true - }, - "@eslint/plugin-kit": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.3.tgz", - "integrity": "sha512-2b/g5hRmpbb1o4GnTZax9N9m0FXzz9OV42ZzI4rDDMDuHUqigAiQCEWChBWCY4ztAGVRjoWT19v0yMmc5/L5kA==", + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, - "requires": { - "levn": "^0.4.1" + "license": "MIT", + "engines": { + "node": ">= 0.8.0" } }, - "@humanfs/core": { - "version": "0.19.1", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", - "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", - "dev": true - }, - "@humanfs/node": { - "version": "0.16.6", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", - "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "node_modules/prettier": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", + "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", "dev": true, - "requires": { - "@humanfs/core": "^0.19.1", - "@humanwhocodes/retry": "^0.3.0" + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true - }, - "@humanwhocodes/retry": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", - "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", - "dev": true - }, - "@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, - "requires": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" + "license": "MIT", + "engines": { + "node": ">=6" } }, - "@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true - }, - "@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", "dev": true, - "requires": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" + "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/rand-seed": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/rand-seed/-/rand-seed-2.1.7.tgz", + "integrity": "sha512-Yaz75D2fTWtIr69iDd+PGwtQkFkqOIMQZl+W8U3NMR6F2a1UEk2FmnQkNd6Z1eNtL96Z5nznw5PKYk1Z9m6lxw==", + "license": "MIT" + }, + "node_modules/react": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/react/-/react-19.1.1.tgz", + "integrity": "sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "@types/estree": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", - "dev": true - }, - "@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true + "node_modules/react-dom": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.1.1.tgz", + "integrity": "sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.26.0" + }, + "peerDependencies": { + "react": "^19.1.1" + } }, - "@typescript-eslint/eslint-plugin": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.12.2.tgz", - "integrity": "sha512-gQxbxM8mcxBwaEmWdtLCIGLfixBMHhQjBqR8sVWNTPpcj45WlYL2IObS/DNMLH1DBP0n8qz+aiiLTGfopPEebw==", + "node_modules/react-refresh": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", "dev": true, - "requires": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.12.2", - "@typescript-eslint/type-utils": "8.12.2", - "@typescript-eslint/utils": "8.12.2", - "@typescript-eslint/visitor-keys": "8.12.2", - "graphemer": "^1.4.0", - "ignore": "^5.3.1", - "natural-compare": "^1.4.0", - "ts-api-utils": "^1.3.0" + "license": "MIT", + "engines": { + "node": ">=0.10.0" } }, - "@typescript-eslint/parser": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.12.2.tgz", - "integrity": "sha512-MrvlXNfGPLH3Z+r7Tk+Z5moZAc0dzdVjTgUgwsdGweH7lydysQsnSww3nAmsq8blFuRD5VRlAr9YdEFw3e6PBw==", + "node_modules/read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", "dev": true, - "requires": { - "@typescript-eslint/scope-manager": "8.12.2", - "@typescript-eslint/types": "8.12.2", - "@typescript-eslint/typescript-estree": "8.12.2", - "@typescript-eslint/visitor-keys": "8.12.2", - "debug": "^4.3.4" + "license": "MIT", + "dependencies": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + }, + "engines": { + "node": ">=4" } }, - "@typescript-eslint/scope-manager": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.12.2.tgz", - "integrity": "sha512-gPLpLtrj9aMHOvxJkSbDBmbRuYdtiEbnvO25bCMza3DhMjTQw0u7Y1M+YR5JPbMsXXnSPuCf5hfq0nEkQDL/JQ==", + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", "dev": true, - "requires": { - "@typescript-eslint/types": "8.12.2", - "@typescript-eslint/visitor-keys": "8.12.2" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "@typescript-eslint/type-utils": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.12.2.tgz", - "integrity": "sha512-bwuU4TAogPI+1q/IJSKuD4shBLc/d2vGcRT588q+jzayQyjVK2X6v/fbR4InY2U2sgf8MEvVCqEWUzYzgBNcGQ==", + "node_modules/regexp.prototype.flags": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", "dev": true, - "requires": { - "@typescript-eslint/typescript-estree": "8.12.2", - "@typescript-eslint/utils": "8.12.2", - "debug": "^4.3.4", - "ts-api-utils": "^1.3.0" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-errors": "^1.3.0", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "@typescript-eslint/types": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.12.2.tgz", - "integrity": "sha512-VwDwMF1SZ7wPBUZwmMdnDJ6sIFk4K4s+ALKLP6aIQsISkPv8jhiw65sAK6SuWODN/ix+m+HgbYDkH+zLjrzvOA==", - "dev": true - }, - "@typescript-eslint/typescript-estree": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.12.2.tgz", - "integrity": "sha512-mME5MDwGe30Pq9zKPvyduyU86PH7aixwqYR2grTglAdB+AN8xXQ1vFGpYaUSJ5o5P/5znsSBeNcs5g5/2aQwow==", + "node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", "dev": true, - "requires": { - "@typescript-eslint/types": "8.12.2", - "@typescript-eslint/visitor-keys": "8.12.2", - "debug": "^4.3.4", - "fast-glob": "^3.3.2", - "is-glob": "^4.0.3", - "minimatch": "^9.0.4", - "semver": "^7.6.0", - "ts-api-utils": "^1.3.0" - }, + "license": "MIT", "dependencies": { - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0" - } - }, - "minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "requires": { - "brace-expansion": "^2.0.1" - } - } + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "@typescript-eslint/utils": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.12.2.tgz", - "integrity": "sha512-UTTuDIX3fkfAz6iSVa5rTuSfWIYZ6ATtEocQ/umkRSyC9O919lbZ8dcH7mysshrCdrAM03skJOEYaBugxN+M6A==", + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "dev": true, - "requires": { - "@eslint-community/eslint-utils": "^4.4.0", - "@typescript-eslint/scope-manager": "8.12.2", - "@typescript-eslint/types": "8.12.2", - "@typescript-eslint/typescript-estree": "8.12.2" + "license": "MIT", + "engines": { + "node": ">=4" } }, - "@typescript-eslint/visitor-keys": { - "version": "8.12.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.12.2.tgz", - "integrity": "sha512-PChz8UaKQAVNHghsHcPyx1OMHoFRUEA7rJSK/mDhdq85bk+PLsUHUBqTQTFt18VJZbmxBovM65fezlheQRsSDA==", + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", "dev": true, - "requires": { - "@typescript-eslint/types": "8.12.2", - "eslint-visitor-keys": "^3.4.3" + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" } }, - "acorn": { - "version": "8.14.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", - "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", - "dev": true - }, - "acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "node_modules/rollup": { + "version": "4.46.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.46.2.tgz", + "integrity": "sha512-WMmLFI+Boh6xbop+OAGo9cQ3OgX9MIg7xOQjn+pTCwOkk+FNDAeAemXkJ3HzDJrVXleLOFVa1ipuc1AmEx1Dwg==", "dev": true, - "requires": {} + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.46.2", + "@rollup/rollup-android-arm64": "4.46.2", + "@rollup/rollup-darwin-arm64": "4.46.2", + "@rollup/rollup-darwin-x64": "4.46.2", + "@rollup/rollup-freebsd-arm64": "4.46.2", + "@rollup/rollup-freebsd-x64": "4.46.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.46.2", + "@rollup/rollup-linux-arm-musleabihf": "4.46.2", + "@rollup/rollup-linux-arm64-gnu": "4.46.2", + "@rollup/rollup-linux-arm64-musl": "4.46.2", + "@rollup/rollup-linux-loongarch64-gnu": "4.46.2", + "@rollup/rollup-linux-ppc64-gnu": "4.46.2", + "@rollup/rollup-linux-riscv64-gnu": "4.46.2", + "@rollup/rollup-linux-riscv64-musl": "4.46.2", + "@rollup/rollup-linux-s390x-gnu": "4.46.2", + "@rollup/rollup-linux-x64-gnu": "4.46.2", + "@rollup/rollup-linux-x64-musl": "4.46.2", + "@rollup/rollup-win32-arm64-msvc": "4.46.2", + "@rollup/rollup-win32-ia32-msvc": "4.46.2", + "@rollup/rollup-win32-x64-msvc": "4.46.2", + "fsevents": "~2.3.2" + } }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "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", + "dependencies": { + "queue-microtask": "^1.2.2" } }, - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/safe-array-concat": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", + "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", "dev": true, - "requires": { - "color-convert": "^2.0.1" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "node_modules/safe-regex-test": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", "dev": true, - "requires": { - "fill-range": "^7.1.1" + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "is-regex": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true + "node_modules/scheduler": { + "version": "0.26.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.26.0.tgz", + "integrity": "sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==", + "license": "MIT" }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", "dev": true, - "requires": { - "color-name": "~1.1.4" + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" } }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true - }, - "convex": { - "version": "1.17.0", - "resolved": "https://registry.npmjs.org/convex/-/convex-1.17.0.tgz", - "integrity": "sha512-fNv5GYvkGYIUYbn8ANnJWabjVqbFoUfm8ExDxlWxeDZAuafPJmatVaQWHZ1k+oYD0pmnchrhmtmMV8mX7T0s9A==", - "requires": { - "esbuild": "0.23.0", - "jwt-decode": "^3.1.2", - "prettier": "3.2.5" + "node_modules/set-function-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", + "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" } }, - "convex-helpers": { - "version": "0.1.63", - "resolved": "https://registry.npmjs.org/convex-helpers/-/convex-helpers-0.1.63.tgz", - "integrity": "sha512-SJZySPcu4G6zdtzw/Pr9mzhBDzPsghfHNB3L1Vtu9IICydJ3hj9iPNLnbFfH7Jm/4gmDpffTANpdRjMr5YXkKg==", - "requires": {} + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } }, - "convex-test": { - "version": "0.0.34", - "resolved": "https://registry.npmjs.org/convex-test/-/convex-test-0.0.34.tgz", - "integrity": "sha512-srntn1drKy0Aa8zzatvJ10ZJFVpBYvLWQrhTibdfnslQqNdzQV5Ui4XKFtmrEmqw+DjmeJATgvZHbLzhP7Dh4w==", + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "dev": true, - "requires": {} + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } }, - "cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" + "license": "MIT", + "engines": { + "node": ">=8" } }, - "debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "node_modules/shell-quote": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", "dev": true, - "requires": { - "ms": "^2.1.3" + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true - }, - "esbuild": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.0.tgz", - "integrity": "sha512-1lvV17H2bMYda/WaFb2jLPeHU3zml2k4/yagNMG8Q/YtfMjCwEUZa2eXXMgZTVSL5q1n4H7sQ0X6CdJDqqeCFA==", - "requires": { - "@esbuild/aix-ppc64": "0.23.0", - "@esbuild/android-arm": "0.23.0", - "@esbuild/android-arm64": "0.23.0", - "@esbuild/android-x64": "0.23.0", - "@esbuild/darwin-arm64": "0.23.0", - "@esbuild/darwin-x64": "0.23.0", - "@esbuild/freebsd-arm64": "0.23.0", - "@esbuild/freebsd-x64": "0.23.0", - "@esbuild/linux-arm": "0.23.0", - "@esbuild/linux-arm64": "0.23.0", - "@esbuild/linux-ia32": "0.23.0", - "@esbuild/linux-loong64": "0.23.0", - "@esbuild/linux-mips64el": "0.23.0", - "@esbuild/linux-ppc64": "0.23.0", - "@esbuild/linux-riscv64": "0.23.0", - "@esbuild/linux-s390x": "0.23.0", - "@esbuild/linux-x64": "0.23.0", - "@esbuild/netbsd-x64": "0.23.0", - "@esbuild/openbsd-arm64": "0.23.0", - "@esbuild/openbsd-x64": "0.23.0", - "@esbuild/sunos-x64": "0.23.0", - "@esbuild/win32-arm64": "0.23.0", - "@esbuild/win32-ia32": "0.23.0", - "@esbuild/win32-x64": "0.23.0" - } - }, - "escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true + "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==", + "dev": true, + "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" + } }, - "eslint": { - "version": "9.13.0", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.13.0.tgz", - "integrity": "sha512-EYZK6SX6zjFHST/HRytOdA/zE72Cq/bfw45LSyuwrdvcclb/gqV8RRQxywOBEWO2+WDpva6UZa4CcDeJKzUCFA==", + "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==", "dev": true, - "requires": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.11.0", - "@eslint/config-array": "^0.18.0", - "@eslint/core": "^0.7.0", - "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "9.13.0", - "@eslint/plugin-kit": "^0.2.0", - "@humanfs/node": "^0.16.5", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.3.1", - "@types/estree": "^1.0.6", - "@types/json-schema": "^7.0.15", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.1.0", - "eslint-visitor-keys": "^4.1.0", - "espree": "^10.2.0", - "esquery": "^1.5.0", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "text-table": "^0.2.0" + "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==", + "dev": true, + "license": "MIT", "dependencies": { - "eslint-visitor-keys": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz", - "integrity": "sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==", - "dev": true - } + "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" } }, - "eslint-scope": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.1.0.tgz", - "integrity": "sha512-14dSvlhaVhKKsa9Fx1l8A17s7ah7Ef7wCakJ10LYk6+GYmP9yDti2oq2SEwcyndt6knfcZyhyxwY3i9yL78EQw==", + "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==", "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" + "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" } }, - "eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } }, - "espree": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/espree/-/espree-10.2.0.tgz", - "integrity": "sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g==", + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", "dev": true, - "requires": { - "acorn": "^8.12.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^4.1.0" - }, + "license": "Apache-2.0", "dependencies": { - "eslint-visitor-keys": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz", - "integrity": "sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==", - "dev": true - } + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" } }, - "esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", "dev": true, - "requires": { - "estraverse": "^5.1.0" - } + "license": "CC-BY-3.0" }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", "dev": true, - "requires": { - "estraverse": "^5.2.0" + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" } }, - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "node_modules/spdx-license-ids": { + "version": "3.0.21", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.21.tgz", + "integrity": "sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==", + "dev": true, + "license": "CC0-1.0" }, - "fast-glob": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", - "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "node_modules/stop-iteration-iterator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", + "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", "dev": true, - "requires": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, + "license": "MIT", "dependencies": { - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "requires": { - "is-glob": "^4.0.1" - } - } + "es-errors": "^1.3.0", + "internal-slot": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" } }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "node_modules/string.prototype.padend": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.6.tgz", + "integrity": "sha512-XZpspuSB7vJWhvJc9DLSlrXl1mcA2BdoY5jjnS135ydXqLoqhs96JjDtCkjJEQHvfqZIp9hBuBMgI589peyx9Q==", "dev": true, - "requires": { - "reusify": "^1.0.4" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.2", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "node_modules/string.prototype.trim": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", "dev": true, - "requires": { - "flat-cache": "^4.0.0" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "node_modules/string.prototype.trimend": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", "dev": true, - "requires": { - "to-regex-range": "^5.0.1" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "node_modules/string.prototype.trimstart": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", + "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", "dev": true, - "requires": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, - "requires": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" + "license": "MIT", + "engines": { + "node": ">=4" } }, - "flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true - }, - "glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, - "requires": { - "is-glob": "^4.0.3" + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "globals": { - "version": "15.11.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-15.11.0.tgz", - "integrity": "sha512-yeyNSjdbyVaWurlwCpcA6XNBrHTMIeDdj0/hnvX/OLJ9ekOXYbLsLinH/MucQyGvNnXhidTdNhTtJaffL2sMfw==", - "dev": true - }, - "graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true - }, - "import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "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==", "dev": true, - "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "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", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true, - "requires": { - "is-extglob": "^2.1.1" + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "node_modules/tailwindcss": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.11.tgz", + "integrity": "sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA==", + "dev": true, + "license": "MIT" }, - "js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "node_modules/tapable": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.2.tgz", + "integrity": "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==", "dev": true, - "requires": { - "argparse": "^2.0.1" + "license": "MIT", + "engines": { + "node": ">=6" } }, - "json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "jwt-decode": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", - "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==" - }, - "keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "node_modules/tar": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz", + "integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==", "dev": true, - "requires": { - "json-buffer": "3.0.1" + "license": "ISC", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.0.1", + "mkdirp": "^3.0.1", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" } }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "node_modules/tar/node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", "dev": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" } }, - "locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "node_modules/tinyglobby": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", + "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", "dev": true, - "requires": { - "p-locate": "^5.0.0" + "license": "MIT", + "dependencies": { + "fdir": "^6.4.4", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" } }, - "lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true - }, - "merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true - }, - "micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", + "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", "dev": true, - "requires": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } } }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", "dev": true, - "requires": { - "brace-expansion": "^1.1.7" + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } }, - "optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "node_modules/ts-api-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", "dev": true, - "requires": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" } }, - "p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "dev": true, - "requires": { - "yocto-queue": "^0.1.0" + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" } }, - "p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", "dev": true, - "requires": { - "p-limit": "^3.0.2" + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" } }, - "parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "node_modules/typed-array-byte-length": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", "dev": true, - "requires": { - "callsites": "^3.0.0" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true - }, - "prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true - }, - "prettier": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", - "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==" - }, - "punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true - }, - "queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true - }, - "rand-seed": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/rand-seed/-/rand-seed-2.1.7.tgz", - "integrity": "sha512-Yaz75D2fTWtIr69iDd+PGwtQkFkqOIMQZl+W8U3NMR6F2a1UEk2FmnQkNd6Z1eNtL96Z5nznw5PKYk1Z9m6lxw==" - }, - "resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true - }, - "reusify": { + "node_modules/typed-array-byte-offset": { "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true - }, - "run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", "dev": true, - "requires": { - "queue-microtask": "^1.2.2" + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "for-each": "^0.3.3", + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", - "dev": true - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "node_modules/typed-array-length": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", "dev": true, - "requires": { - "shebang-regex": "^3.0.0" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true + "node_modules/typescript": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", + "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", + "devOptional": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } }, - "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==", + "node_modules/typescript-eslint": { + "version": "8.38.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.38.0.tgz", + "integrity": "sha512-FsZlrYK6bPDGoLeZRuvx2v6qrM03I0U0SnfCLPs/XCCPCFD80xU9Pg09H/K+XFa68uJuZo7l/Xhs+eDRg2l3hg==", "dev": true, - "requires": { - "has-flag": "^4.0.0" + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.38.0", + "@typescript-eslint/parser": "8.38.0", + "@typescript-eslint/typescript-estree": "8.38.0", + "@typescript-eslint/utils": "8.38.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" } }, - "text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "node_modules/unbox-primitive": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", "dev": true, - "requires": { - "is-number": "^7.0.0" + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "ts-api-utils": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", - "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "node_modules/undici-types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", "dev": true, - "requires": {} + "license": "MIT" }, - "type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "node_modules/update-browserslist-db": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", "dev": true, - "requires": { - "prelude-ls": "^1.2.1" + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" } }, - "typescript": { - "version": "5.6.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.3.tgz", - "integrity": "sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw==", - "dev": true - }, - "uri-js": { + "node_modules/uri-js": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, - "requires": { + "license": "BSD-2-Clause", + "dependencies": { "punycode": "^2.1.0" } }, - "which": { + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/vite": { + "version": "6.3.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", + "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/fdir": { + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", + "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, - "requires": { + "license": "ISC", + "dependencies": { "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "word-wrap": { + "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" }, - "yocto-queue": { + "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } } } } diff --git a/example/package.json b/example/package.json index c72952d..70aa7a5 100644 --- a/example/package.json +++ b/example/package.json @@ -1,27 +1,42 @@ { - "name": "uses-component", + "name": "examples", "private": true, "version": "0.0.0", + "type": "module", "scripts": { - "dev": "convex dev --live-component-sources --typecheck-components", - "logs": "convex logs", - "lint": "tsc -p convex && eslint convex" + "dev": "npm-run-all --parallel dev:frontend dev:backend", + "dev:frontend": "vite --open", + "dev:backend": "convex dev --live-component-sources --typecheck-components", + "predev": "convex dev --until-success && convex dashboard", + "build": "tsc -b && vite build", + "lint": "tsc && eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", + "preview": "vite preview" }, "dependencies": { "@convex-dev/aggregate": "file:..", "@convex-dev/migrations": "^0.2.1", "convex": "^1.17.0", "convex-helpers": "^0.1.61", - "rand-seed": "^2.1.7" + "rand-seed": "^2.1.7", + "react": "^19.0.0", + "react-dom": "^19.0.0" }, "devDependencies": { - "@eslint/eslintrc": "^3.1.0", - "@eslint/js": "^9.9.1", - "@typescript-eslint/eslint-plugin": "^8.4.0", - "@typescript-eslint/parser": "^8.4.0", - "convex-test": "^0.0.34", - "eslint": "^9.9.1", - "globals": "^15.9.0", - "typescript": "^5.5.0" + "@eslint/js": "^9.21.0", + "@tailwindcss/vite": "^4.0.14", + "@types/node": "^22.13.10", + "@types/react": "^19.0.10", + "@types/react-dom": "^19.0.4", + "@vitejs/plugin-react": "^4.3.4", + "eslint": "^9.21.0", + "eslint-plugin-react-hooks": "^5.1.0", + "eslint-plugin-react-refresh": "^0.4.19", + "globals": "^15.15.0", + "npm-run-all": "^4.1.5", + "prettier": "^3.5.3", + "tailwindcss": "^4.0.14", + "typescript": "~5.7.2", + "typescript-eslint": "^8.24.1", + "vite": "^6.2.0" } } diff --git a/example/public/convex.svg b/example/public/convex.svg new file mode 100644 index 0000000..7d70c4d --- /dev/null +++ b/example/public/convex.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/example/src/App.tsx b/example/src/App.tsx new file mode 100644 index 0000000..64b4150 --- /dev/null +++ b/example/src/App.tsx @@ -0,0 +1,122 @@ +import { useMutation, useQuery } from "convex/react"; +import { api } from "../convex/_generated/api"; + +export default function App() { + return ( + <> +
+ Convex + React +
+
+

Convex + React

+ +
+ + ); +} + +function Content() { + const { viewer, numbers } = + useQuery(api.myFunctions.listNumbers, { + count: 10, + }) ?? {}; + const addNumber = useMutation(api.myFunctions.addNumber); + + if (viewer === undefined || numbers === undefined) { + return ( +
+

loading... (consider a loading skeleton)

+
+ ); + } + + return ( +
+

Welcome {viewer ?? "Anonymous"}!

+

+ Click the button below and open this page in another window - this data + is persisted in the Convex cloud database! +

+

+ +

+

+ Numbers:{" "} + {numbers?.length === 0 + ? "Click the button!" + : (numbers?.join(", ") ?? "...")} +

+

+ Edit{" "} + + convex/myFunctions.ts + {" "} + to change your backend +

+

+ Edit{" "} + + src/App.tsx + {" "} + to change your frontend +

+
+

Useful resources:

+
+
+ + +
+
+ + +
+
+
+
+ ); +} + +function ResourceCard({ + title, + description, + href, +}: { + title: string; + description: string; + href: string; +}) { + return ( +
+ + {title} + +

{description}

+
+ ); +} diff --git a/example/src/index.css b/example/src/index.css new file mode 100644 index 0000000..62c2b40 --- /dev/null +++ b/example/src/index.css @@ -0,0 +1,22 @@ +@import "tailwindcss"; + +@theme { + --color-light: #ffffff; + --color-dark: #171717; +} + +@media (prefers-color-scheme: dark) { + body { + color: var(--color-light); + background: var(--color-dark); + font-family: Arial, Helvetica, sans-serif; + } +} + +@media (prefers-color-scheme: light) { + body { + color: var(--color-dark); + background: var(--color-light); + font-family: Arial, Helvetica, sans-serif; + } +} diff --git a/example/src/main.tsx b/example/src/main.tsx new file mode 100644 index 0000000..4880906 --- /dev/null +++ b/example/src/main.tsx @@ -0,0 +1,14 @@ +import { StrictMode } from "react"; +import { createRoot } from "react-dom/client"; +import { ConvexProvider, ConvexReactClient } from "convex/react"; +import "./index.css"; +import App from "./App.tsx"; + +const convex = new ConvexReactClient(import.meta.env.VITE_CONVEX_URL as string); +createRoot(document.getElementById("root")!).render( + + + + + , +); diff --git a/example/src/vite-env.d.ts b/example/src/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/example/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/example/tsconfig.app.json b/example/tsconfig.app.json new file mode 100644 index 0000000..8267e1f --- /dev/null +++ b/example/tsconfig.app.json @@ -0,0 +1,31 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo", + "target": "ES2020", + "useDefineForClassFields": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + "jsx": "react-jsx", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true, + + /* Import paths */ + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["src"] +} diff --git a/example/tsconfig.json b/example/tsconfig.json new file mode 100644 index 0000000..1ffef60 --- /dev/null +++ b/example/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/example/tsconfig.node.json b/example/tsconfig.node.json new file mode 100644 index 0000000..db0becc --- /dev/null +++ b/example/tsconfig.node.json @@ -0,0 +1,24 @@ +{ + "compilerOptions": { + "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo", + "target": "ES2022", + "lib": ["ES2023"], + "module": "ESNext", + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "isolatedModules": true, + "moduleDetection": "force", + "noEmit": true, + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "noUncheckedSideEffectImports": true + }, + "include": ["vite.config.ts"] +} diff --git a/example/vite.config.ts b/example/vite.config.ts new file mode 100644 index 0000000..506e619 --- /dev/null +++ b/example/vite.config.ts @@ -0,0 +1,14 @@ +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; +import tailwindcss from "@tailwindcss/vite"; +import path from "path"; + +// https://vite.dev/config/ +export default defineConfig({ + plugins: [react(), tailwindcss()], + resolve: { + alias: { + "@": path.resolve(__dirname, "./src"), + }, + }, +}); From 268cb776530d6b3e6e4a47a67195c6f4ef81653e Mon Sep 17 00:00:00 2001 From: Mike Cann Date: Fri, 1 Aug 2025 11:04:52 +0800 Subject: [PATCH 03/77] fixed quotes issues --- example/convex/_generated/api.d.ts | 848 +++++++++++++++++++++++ example/convex/_generated/api.js | 23 + example/convex/_generated/dataModel.d.ts | 60 ++ example/convex/_generated/server.d.ts | 149 ++++ example/convex/_generated/server.js | 90 +++ package.json | 4 +- 6 files changed, 1172 insertions(+), 2 deletions(-) create mode 100644 example/convex/_generated/api.d.ts create mode 100644 example/convex/_generated/api.js create mode 100644 example/convex/_generated/dataModel.d.ts create mode 100644 example/convex/_generated/server.d.ts create mode 100644 example/convex/_generated/server.js diff --git a/example/convex/_generated/api.d.ts b/example/convex/_generated/api.d.ts new file mode 100644 index 0000000..28d8916 --- /dev/null +++ b/example/convex/_generated/api.d.ts @@ -0,0 +1,848 @@ +/* eslint-disable */ +/** + * Generated `api` utility. + * + * THIS CODE IS AUTOMATICALLY GENERATED. + * + * To regenerate, run `npx convex dev`. + * @module + */ + +import type * as leaderboard from "../leaderboard.js"; +import type * as photos from "../photos.js"; +import type * as shuffle from "../shuffle.js"; +import type * as stats from "../stats.js"; + +import type { + ApiFromModules, + FilterApi, + FunctionReference, +} from "convex/server"; + +/** + * A utility for referencing Convex functions in your app's API. + * + * Usage: + * ```js + * const myFunctionReference = api.myModule.myFunction; + * ``` + */ +declare const fullApi: ApiFromModules<{ + leaderboard: typeof leaderboard; + photos: typeof photos; + shuffle: typeof shuffle; + stats: typeof stats; +}>; +declare const fullApiWithMounts: typeof fullApi; + +export declare const api: FilterApi< + typeof fullApiWithMounts, + FunctionReference +>; +export declare const internal: FilterApi< + typeof fullApiWithMounts, + FunctionReference +>; + +export declare const components: { + aggregateByScore: { + btree: { + aggregateBetween: FunctionReference< + "query", + "internal", + { k1?: any; k2?: any; namespace?: any }, + { count: number; sum: number } + >; + atNegativeOffset: FunctionReference< + "query", + "internal", + { k1?: any; k2?: any; namespace?: any; offset: number }, + { k: any; s: number; v: any } + >; + atOffset: FunctionReference< + "query", + "internal", + { k1?: any; k2?: any; namespace?: any; offset: number }, + { k: any; s: number; v: any } + >; + get: FunctionReference< + "query", + "internal", + { key: any; namespace?: any }, + null | { k: any; s: number; v: any } + >; + offset: FunctionReference< + "query", + "internal", + { k1?: any; key: any; namespace?: any }, + number + >; + offsetUntil: FunctionReference< + "query", + "internal", + { k2?: any; key: any; namespace?: any }, + number + >; + paginate: FunctionReference< + "query", + "internal", + { + cursor?: string; + k1?: any; + k2?: any; + limit: number; + namespace?: any; + order: "asc" | "desc"; + }, + { + cursor: string; + isDone: boolean; + page: Array<{ k: any; s: number; v: any }>; + } + >; + paginateNamespaces: FunctionReference< + "query", + "internal", + { cursor?: string; limit: number }, + { cursor: string; isDone: boolean; page: Array } + >; + validate: FunctionReference< + "query", + "internal", + { namespace?: any }, + any + >; + }; + inspect: { + display: FunctionReference<"query", "internal", { namespace?: any }, any>; + dump: FunctionReference<"query", "internal", { namespace?: any }, string>; + inspectNode: FunctionReference< + "query", + "internal", + { namespace?: any; node?: string }, + null + >; + }; + public: { + clear: FunctionReference< + "mutation", + "internal", + { maxNodeSize?: number; namespace?: any; rootLazy?: boolean }, + null + >; + deleteIfExists: FunctionReference< + "mutation", + "internal", + { key: any; namespace?: any }, + any + >; + delete_: FunctionReference< + "mutation", + "internal", + { key: any; namespace?: any }, + null + >; + init: FunctionReference< + "mutation", + "internal", + { maxNodeSize?: number; namespace?: any; rootLazy?: boolean }, + null + >; + insert: FunctionReference< + "mutation", + "internal", + { key: any; namespace?: any; summand?: number; value: any }, + null + >; + makeRootLazy: FunctionReference< + "mutation", + "internal", + { namespace?: any }, + null + >; + replace: FunctionReference< + "mutation", + "internal", + { + currentKey: any; + namespace?: any; + newKey: any; + newNamespace?: any; + summand?: number; + value: any; + }, + null + >; + replaceOrInsert: FunctionReference< + "mutation", + "internal", + { + currentKey: any; + namespace?: any; + newKey: any; + newNamespace?: any; + summand?: number; + value: any; + }, + any + >; + }; + }; + aggregateScoreByUser: { + btree: { + aggregateBetween: FunctionReference< + "query", + "internal", + { k1?: any; k2?: any; namespace?: any }, + { count: number; sum: number } + >; + atNegativeOffset: FunctionReference< + "query", + "internal", + { k1?: any; k2?: any; namespace?: any; offset: number }, + { k: any; s: number; v: any } + >; + atOffset: FunctionReference< + "query", + "internal", + { k1?: any; k2?: any; namespace?: any; offset: number }, + { k: any; s: number; v: any } + >; + get: FunctionReference< + "query", + "internal", + { key: any; namespace?: any }, + null | { k: any; s: number; v: any } + >; + offset: FunctionReference< + "query", + "internal", + { k1?: any; key: any; namespace?: any }, + number + >; + offsetUntil: FunctionReference< + "query", + "internal", + { k2?: any; key: any; namespace?: any }, + number + >; + paginate: FunctionReference< + "query", + "internal", + { + cursor?: string; + k1?: any; + k2?: any; + limit: number; + namespace?: any; + order: "asc" | "desc"; + }, + { + cursor: string; + isDone: boolean; + page: Array<{ k: any; s: number; v: any }>; + } + >; + paginateNamespaces: FunctionReference< + "query", + "internal", + { cursor?: string; limit: number }, + { cursor: string; isDone: boolean; page: Array } + >; + validate: FunctionReference< + "query", + "internal", + { namespace?: any }, + any + >; + }; + inspect: { + display: FunctionReference<"query", "internal", { namespace?: any }, any>; + dump: FunctionReference<"query", "internal", { namespace?: any }, string>; + inspectNode: FunctionReference< + "query", + "internal", + { namespace?: any; node?: string }, + null + >; + }; + public: { + clear: FunctionReference< + "mutation", + "internal", + { maxNodeSize?: number; namespace?: any; rootLazy?: boolean }, + null + >; + deleteIfExists: FunctionReference< + "mutation", + "internal", + { key: any; namespace?: any }, + any + >; + delete_: FunctionReference< + "mutation", + "internal", + { key: any; namespace?: any }, + null + >; + init: FunctionReference< + "mutation", + "internal", + { maxNodeSize?: number; namespace?: any; rootLazy?: boolean }, + null + >; + insert: FunctionReference< + "mutation", + "internal", + { key: any; namespace?: any; summand?: number; value: any }, + null + >; + makeRootLazy: FunctionReference< + "mutation", + "internal", + { namespace?: any }, + null + >; + replace: FunctionReference< + "mutation", + "internal", + { + currentKey: any; + namespace?: any; + newKey: any; + newNamespace?: any; + summand?: number; + value: any; + }, + null + >; + replaceOrInsert: FunctionReference< + "mutation", + "internal", + { + currentKey: any; + namespace?: any; + newKey: any; + newNamespace?: any; + summand?: number; + value: any; + }, + any + >; + }; + }; + music: { + btree: { + aggregateBetween: FunctionReference< + "query", + "internal", + { k1?: any; k2?: any; namespace?: any }, + { count: number; sum: number } + >; + atNegativeOffset: FunctionReference< + "query", + "internal", + { k1?: any; k2?: any; namespace?: any; offset: number }, + { k: any; s: number; v: any } + >; + atOffset: FunctionReference< + "query", + "internal", + { k1?: any; k2?: any; namespace?: any; offset: number }, + { k: any; s: number; v: any } + >; + get: FunctionReference< + "query", + "internal", + { key: any; namespace?: any }, + null | { k: any; s: number; v: any } + >; + offset: FunctionReference< + "query", + "internal", + { k1?: any; key: any; namespace?: any }, + number + >; + offsetUntil: FunctionReference< + "query", + "internal", + { k2?: any; key: any; namespace?: any }, + number + >; + paginate: FunctionReference< + "query", + "internal", + { + cursor?: string; + k1?: any; + k2?: any; + limit: number; + namespace?: any; + order: "asc" | "desc"; + }, + { + cursor: string; + isDone: boolean; + page: Array<{ k: any; s: number; v: any }>; + } + >; + paginateNamespaces: FunctionReference< + "query", + "internal", + { cursor?: string; limit: number }, + { cursor: string; isDone: boolean; page: Array } + >; + validate: FunctionReference< + "query", + "internal", + { namespace?: any }, + any + >; + }; + inspect: { + display: FunctionReference<"query", "internal", { namespace?: any }, any>; + dump: FunctionReference<"query", "internal", { namespace?: any }, string>; + inspectNode: FunctionReference< + "query", + "internal", + { namespace?: any; node?: string }, + null + >; + }; + public: { + clear: FunctionReference< + "mutation", + "internal", + { maxNodeSize?: number; namespace?: any; rootLazy?: boolean }, + null + >; + deleteIfExists: FunctionReference< + "mutation", + "internal", + { key: any; namespace?: any }, + any + >; + delete_: FunctionReference< + "mutation", + "internal", + { key: any; namespace?: any }, + null + >; + init: FunctionReference< + "mutation", + "internal", + { maxNodeSize?: number; namespace?: any; rootLazy?: boolean }, + null + >; + insert: FunctionReference< + "mutation", + "internal", + { key: any; namespace?: any; summand?: number; value: any }, + null + >; + makeRootLazy: FunctionReference< + "mutation", + "internal", + { namespace?: any }, + null + >; + replace: FunctionReference< + "mutation", + "internal", + { + currentKey: any; + namespace?: any; + newKey: any; + newNamespace?: any; + summand?: number; + value: any; + }, + null + >; + replaceOrInsert: FunctionReference< + "mutation", + "internal", + { + currentKey: any; + namespace?: any; + newKey: any; + newNamespace?: any; + summand?: number; + value: any; + }, + any + >; + }; + }; + photos: { + btree: { + aggregateBetween: FunctionReference< + "query", + "internal", + { k1?: any; k2?: any; namespace?: any }, + { count: number; sum: number } + >; + atNegativeOffset: FunctionReference< + "query", + "internal", + { k1?: any; k2?: any; namespace?: any; offset: number }, + { k: any; s: number; v: any } + >; + atOffset: FunctionReference< + "query", + "internal", + { k1?: any; k2?: any; namespace?: any; offset: number }, + { k: any; s: number; v: any } + >; + get: FunctionReference< + "query", + "internal", + { key: any; namespace?: any }, + null | { k: any; s: number; v: any } + >; + offset: FunctionReference< + "query", + "internal", + { k1?: any; key: any; namespace?: any }, + number + >; + offsetUntil: FunctionReference< + "query", + "internal", + { k2?: any; key: any; namespace?: any }, + number + >; + paginate: FunctionReference< + "query", + "internal", + { + cursor?: string; + k1?: any; + k2?: any; + limit: number; + namespace?: any; + order: "asc" | "desc"; + }, + { + cursor: string; + isDone: boolean; + page: Array<{ k: any; s: number; v: any }>; + } + >; + paginateNamespaces: FunctionReference< + "query", + "internal", + { cursor?: string; limit: number }, + { cursor: string; isDone: boolean; page: Array } + >; + validate: FunctionReference< + "query", + "internal", + { namespace?: any }, + any + >; + }; + inspect: { + display: FunctionReference<"query", "internal", { namespace?: any }, any>; + dump: FunctionReference<"query", "internal", { namespace?: any }, string>; + inspectNode: FunctionReference< + "query", + "internal", + { namespace?: any; node?: string }, + null + >; + }; + public: { + clear: FunctionReference< + "mutation", + "internal", + { maxNodeSize?: number; namespace?: any; rootLazy?: boolean }, + null + >; + deleteIfExists: FunctionReference< + "mutation", + "internal", + { key: any; namespace?: any }, + any + >; + delete_: FunctionReference< + "mutation", + "internal", + { key: any; namespace?: any }, + null + >; + init: FunctionReference< + "mutation", + "internal", + { maxNodeSize?: number; namespace?: any; rootLazy?: boolean }, + null + >; + insert: FunctionReference< + "mutation", + "internal", + { key: any; namespace?: any; summand?: number; value: any }, + null + >; + makeRootLazy: FunctionReference< + "mutation", + "internal", + { namespace?: any }, + null + >; + replace: FunctionReference< + "mutation", + "internal", + { + currentKey: any; + namespace?: any; + newKey: any; + newNamespace?: any; + summand?: number; + value: any; + }, + null + >; + replaceOrInsert: FunctionReference< + "mutation", + "internal", + { + currentKey: any; + namespace?: any; + newKey: any; + newNamespace?: any; + summand?: number; + value: any; + }, + any + >; + }; + }; + stats: { + btree: { + aggregateBetween: FunctionReference< + "query", + "internal", + { k1?: any; k2?: any; namespace?: any }, + { count: number; sum: number } + >; + atNegativeOffset: FunctionReference< + "query", + "internal", + { k1?: any; k2?: any; namespace?: any; offset: number }, + { k: any; s: number; v: any } + >; + atOffset: FunctionReference< + "query", + "internal", + { k1?: any; k2?: any; namespace?: any; offset: number }, + { k: any; s: number; v: any } + >; + get: FunctionReference< + "query", + "internal", + { key: any; namespace?: any }, + null | { k: any; s: number; v: any } + >; + offset: FunctionReference< + "query", + "internal", + { k1?: any; key: any; namespace?: any }, + number + >; + offsetUntil: FunctionReference< + "query", + "internal", + { k2?: any; key: any; namespace?: any }, + number + >; + paginate: FunctionReference< + "query", + "internal", + { + cursor?: string; + k1?: any; + k2?: any; + limit: number; + namespace?: any; + order: "asc" | "desc"; + }, + { + cursor: string; + isDone: boolean; + page: Array<{ k: any; s: number; v: any }>; + } + >; + paginateNamespaces: FunctionReference< + "query", + "internal", + { cursor?: string; limit: number }, + { cursor: string; isDone: boolean; page: Array } + >; + validate: FunctionReference< + "query", + "internal", + { namespace?: any }, + any + >; + }; + inspect: { + display: FunctionReference<"query", "internal", { namespace?: any }, any>; + dump: FunctionReference<"query", "internal", { namespace?: any }, string>; + inspectNode: FunctionReference< + "query", + "internal", + { namespace?: any; node?: string }, + null + >; + }; + public: { + clear: FunctionReference< + "mutation", + "internal", + { maxNodeSize?: number; namespace?: any; rootLazy?: boolean }, + null + >; + deleteIfExists: FunctionReference< + "mutation", + "internal", + { key: any; namespace?: any }, + any + >; + delete_: FunctionReference< + "mutation", + "internal", + { key: any; namespace?: any }, + null + >; + init: FunctionReference< + "mutation", + "internal", + { maxNodeSize?: number; namespace?: any; rootLazy?: boolean }, + null + >; + insert: FunctionReference< + "mutation", + "internal", + { key: any; namespace?: any; summand?: number; value: any }, + null + >; + makeRootLazy: FunctionReference< + "mutation", + "internal", + { namespace?: any }, + null + >; + replace: FunctionReference< + "mutation", + "internal", + { + currentKey: any; + namespace?: any; + newKey: any; + newNamespace?: any; + summand?: number; + value: any; + }, + null + >; + replaceOrInsert: FunctionReference< + "mutation", + "internal", + { + currentKey: any; + namespace?: any; + newKey: any; + newNamespace?: any; + summand?: number; + value: any; + }, + any + >; + }; + }; + migrations: { + lib: { + cancel: FunctionReference< + "mutation", + "internal", + { name: string }, + { + batchSize?: number; + cursor?: string | null; + error?: string; + isDone: boolean; + latestEnd?: number; + latestStart: number; + name: string; + next?: Array; + processed: number; + state: "inProgress" | "success" | "failed" | "canceled" | "unknown"; + } + >; + cancelAll: FunctionReference< + "mutation", + "internal", + { sinceTs?: number }, + Array<{ + batchSize?: number; + cursor?: string | null; + error?: string; + isDone: boolean; + latestEnd?: number; + latestStart: number; + name: string; + next?: Array; + processed: number; + state: "inProgress" | "success" | "failed" | "canceled" | "unknown"; + }> + >; + clearAll: FunctionReference< + "mutation", + "internal", + { before?: number }, + null + >; + getStatus: FunctionReference< + "query", + "internal", + { limit?: number; names?: Array }, + Array<{ + batchSize?: number; + cursor?: string | null; + error?: string; + isDone: boolean; + latestEnd?: number; + latestStart: number; + name: string; + next?: Array; + processed: number; + state: "inProgress" | "success" | "failed" | "canceled" | "unknown"; + }> + >; + migrate: FunctionReference< + "mutation", + "internal", + { + batchSize?: number; + cursor?: string | null; + dryRun: boolean; + fnHandle: string; + name: string; + next?: Array<{ fnHandle: string; name: string }>; + }, + { + batchSize?: number; + cursor?: string | null; + error?: string; + isDone: boolean; + latestEnd?: number; + latestStart: number; + name: string; + next?: Array; + processed: number; + state: "inProgress" | "success" | "failed" | "canceled" | "unknown"; + } + >; + }; + }; +}; diff --git a/example/convex/_generated/api.js b/example/convex/_generated/api.js new file mode 100644 index 0000000..44bf985 --- /dev/null +++ b/example/convex/_generated/api.js @@ -0,0 +1,23 @@ +/* eslint-disable */ +/** + * Generated `api` utility. + * + * THIS CODE IS AUTOMATICALLY GENERATED. + * + * To regenerate, run `npx convex dev`. + * @module + */ + +import { anyApi, componentsGeneric } from "convex/server"; + +/** + * A utility for referencing Convex functions in your app's API. + * + * Usage: + * ```js + * const myFunctionReference = api.myModule.myFunction; + * ``` + */ +export const api = anyApi; +export const internal = anyApi; +export const components = componentsGeneric(); diff --git a/example/convex/_generated/dataModel.d.ts b/example/convex/_generated/dataModel.d.ts new file mode 100644 index 0000000..8541f31 --- /dev/null +++ b/example/convex/_generated/dataModel.d.ts @@ -0,0 +1,60 @@ +/* eslint-disable */ +/** + * Generated data model types. + * + * THIS CODE IS AUTOMATICALLY GENERATED. + * + * To regenerate, run `npx convex dev`. + * @module + */ + +import type { + DataModelFromSchemaDefinition, + DocumentByName, + TableNamesInDataModel, + SystemTableNames, +} from "convex/server"; +import type { GenericId } from "convex/values"; +import schema from "../schema.js"; + +/** + * The names of all of your Convex tables. + */ +export type TableNames = TableNamesInDataModel; + +/** + * The type of a document stored in Convex. + * + * @typeParam TableName - A string literal type of the table name (like "users"). + */ +export type Doc = DocumentByName< + DataModel, + TableName +>; + +/** + * An identifier for a document in Convex. + * + * Convex documents are uniquely identified by their `Id`, which is accessible + * on the `_id` field. To learn more, see [Document IDs](https://docs.convex.dev/using/document-ids). + * + * Documents can be loaded using `db.get(id)` in query and mutation functions. + * + * IDs are just strings at runtime, but this type can be used to distinguish them from other + * strings when type checking. + * + * @typeParam TableName - A string literal type of the table name (like "users"). + */ +export type Id = + GenericId; + +/** + * A type describing your Convex data model. + * + * This type includes information about what tables you have, the type of + * documents stored in those tables, and the indexes defined on them. + * + * This type is used to parameterize methods like `queryGeneric` and + * `mutationGeneric` to make them type-safe. + */ +export type DataModel = DataModelFromSchemaDefinition; diff --git a/example/convex/_generated/server.d.ts b/example/convex/_generated/server.d.ts new file mode 100644 index 0000000..b5c6828 --- /dev/null +++ b/example/convex/_generated/server.d.ts @@ -0,0 +1,149 @@ +/* eslint-disable */ +/** + * Generated utilities for implementing server-side Convex query and mutation functions. + * + * THIS CODE IS AUTOMATICALLY GENERATED. + * + * To regenerate, run `npx convex dev`. + * @module + */ + +import { + ActionBuilder, + AnyComponents, + HttpActionBuilder, + MutationBuilder, + QueryBuilder, + GenericActionCtx, + GenericMutationCtx, + GenericQueryCtx, + GenericDatabaseReader, + GenericDatabaseWriter, + FunctionReference, +} from "convex/server"; +import type { DataModel } from "./dataModel.js"; + +type GenericCtx = + | GenericActionCtx + | GenericMutationCtx + | GenericQueryCtx; + +/** + * Define a query in this Convex app's public API. + * + * This function will be allowed to read your Convex database and will be accessible from the client. + * + * @param func - The query function. It receives a {@link QueryCtx} as its first argument. + * @returns The wrapped query. Include this as an `export` to name it and make it accessible. + */ +export declare const query: QueryBuilder; + +/** + * Define a query that is only accessible from other Convex functions (but not from the client). + * + * This function will be allowed to read from your Convex database. It will not be accessible from the client. + * + * @param func - The query function. It receives a {@link QueryCtx} as its first argument. + * @returns The wrapped query. Include this as an `export` to name it and make it accessible. + */ +export declare const internalQuery: QueryBuilder; + +/** + * Define a mutation in this Convex app's public API. + * + * This function will be allowed to modify your Convex database and will be accessible from the client. + * + * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument. + * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible. + */ +export declare const mutation: MutationBuilder; + +/** + * Define a mutation that is only accessible from other Convex functions (but not from the client). + * + * This function will be allowed to modify your Convex database. It will not be accessible from the client. + * + * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument. + * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible. + */ +export declare const internalMutation: MutationBuilder; + +/** + * Define an action in this Convex app's public API. + * + * An action is a function which can execute any JavaScript code, including non-deterministic + * code and code with side-effects, like calling third-party services. + * They can be run in Convex's JavaScript environment or in Node.js using the "use node" directive. + * They can interact with the database indirectly by calling queries and mutations using the {@link ActionCtx}. + * + * @param func - The action. It receives an {@link ActionCtx} as its first argument. + * @returns The wrapped action. Include this as an `export` to name it and make it accessible. + */ +export declare const action: ActionBuilder; + +/** + * Define an action that is only accessible from other Convex functions (but not from the client). + * + * @param func - The function. It receives an {@link ActionCtx} as its first argument. + * @returns The wrapped function. Include this as an `export` to name it and make it accessible. + */ +export declare const internalAction: ActionBuilder; + +/** + * Define an HTTP action. + * + * This function will be used to respond to HTTP requests received by a Convex + * deployment if the requests matches the path and method where this action + * is routed. Be sure to route your action in `convex/http.js`. + * + * @param func - The function. It receives an {@link ActionCtx} as its first argument. + * @returns The wrapped function. Import this function from `convex/http.js` and route it to hook it up. + */ +export declare const httpAction: HttpActionBuilder; + +/** + * A set of services for use within Convex query functions. + * + * The query context is passed as the first argument to any Convex query + * function run on the server. + * + * This differs from the {@link MutationCtx} because all of the services are + * read-only. + */ +export type QueryCtx = GenericQueryCtx; + +/** + * A set of services for use within Convex mutation functions. + * + * The mutation context is passed as the first argument to any Convex mutation + * function run on the server. + */ +export type MutationCtx = GenericMutationCtx; + +/** + * A set of services for use within Convex action functions. + * + * The action context is passed as the first argument to any Convex action + * function run on the server. + */ +export type ActionCtx = GenericActionCtx; + +/** + * An interface to read from the database within Convex query functions. + * + * The two entry points are {@link DatabaseReader.get}, which fetches a single + * document by its {@link Id}, or {@link DatabaseReader.query}, which starts + * building a query. + */ +export type DatabaseReader = GenericDatabaseReader; + +/** + * An interface to read from and write to the database within Convex mutation + * functions. + * + * Convex guarantees that all writes within a single mutation are + * executed atomically, so you never have to worry about partial writes leaving + * your data in an inconsistent state. See [the Convex Guide](https://docs.convex.dev/understanding/convex-fundamentals/functions#atomicity-and-optimistic-concurrency-control) + * for the guarantees Convex provides your functions. + */ +export type DatabaseWriter = GenericDatabaseWriter; diff --git a/example/convex/_generated/server.js b/example/convex/_generated/server.js new file mode 100644 index 0000000..4a21df4 --- /dev/null +++ b/example/convex/_generated/server.js @@ -0,0 +1,90 @@ +/* eslint-disable */ +/** + * Generated utilities for implementing server-side Convex query and mutation functions. + * + * THIS CODE IS AUTOMATICALLY GENERATED. + * + * To regenerate, run `npx convex dev`. + * @module + */ + +import { + actionGeneric, + httpActionGeneric, + queryGeneric, + mutationGeneric, + internalActionGeneric, + internalMutationGeneric, + internalQueryGeneric, + componentsGeneric, +} from "convex/server"; + +/** + * Define a query in this Convex app's public API. + * + * This function will be allowed to read your Convex database and will be accessible from the client. + * + * @param func - The query function. It receives a {@link QueryCtx} as its first argument. + * @returns The wrapped query. Include this as an `export` to name it and make it accessible. + */ +export const query = queryGeneric; + +/** + * Define a query that is only accessible from other Convex functions (but not from the client). + * + * This function will be allowed to read from your Convex database. It will not be accessible from the client. + * + * @param func - The query function. It receives a {@link QueryCtx} as its first argument. + * @returns The wrapped query. Include this as an `export` to name it and make it accessible. + */ +export const internalQuery = internalQueryGeneric; + +/** + * Define a mutation in this Convex app's public API. + * + * This function will be allowed to modify your Convex database and will be accessible from the client. + * + * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument. + * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible. + */ +export const mutation = mutationGeneric; + +/** + * Define a mutation that is only accessible from other Convex functions (but not from the client). + * + * This function will be allowed to modify your Convex database. It will not be accessible from the client. + * + * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument. + * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible. + */ +export const internalMutation = internalMutationGeneric; + +/** + * Define an action in this Convex app's public API. + * + * An action is a function which can execute any JavaScript code, including non-deterministic + * code and code with side-effects, like calling third-party services. + * They can be run in Convex's JavaScript environment or in Node.js using the "use node" directive. + * They can interact with the database indirectly by calling queries and mutations using the {@link ActionCtx}. + * + * @param func - The action. It receives an {@link ActionCtx} as its first argument. + * @returns The wrapped action. Include this as an `export` to name it and make it accessible. + */ +export const action = actionGeneric; + +/** + * Define an action that is only accessible from other Convex functions (but not from the client). + * + * @param func - The function. It receives an {@link ActionCtx} as its first argument. + * @returns The wrapped function. Include this as an `export` to name it and make it accessible. + */ +export const internalAction = internalActionGeneric; + +/** + * Define a Convex HTTP action. + * + * @param func - The function. It receives an {@link ActionCtx} as its first argument, and a `Request` object + * as its second. + * @returns The wrapped endpoint function. Route a URL path to this function in `convex/http.js`. + */ +export const httpAction = httpActionGeneric; diff --git a/package.json b/package.json index 1b28e71..48b3d47 100644 --- a/package.json +++ b/package.json @@ -16,8 +16,8 @@ "type": "module", "scripts": { "build": "npm run build:esm && npm run build:cjs", - "build:esm": "tsc --project ./esm.json && echo '{\\n \"type\": \"module\"\\n}' > dist/esm/package.json", - "build:cjs": "tsc --project ./commonjs.json && echo '{\\n \"type\": \"commonjs\"\\n}' > dist/commonjs/package.json", + "build:esm": "tsc --project ./esm.json && node -e \"require('fs').writeFileSync('dist/esm/package.json', JSON.stringify({type:'module'}))\"", + "build:cjs": "tsc --project ./commonjs.json && node -e \"require('fs').writeFileSync('dist/commonjs/package.json', JSON.stringify({type:'commonjs'}))\"", "typecheck": "tsc --noEmit", "prepare": "npm run build", "test": "vitest run", From 9a20ce8349fb1d849880fc62b48d62c588590eaa Mon Sep 17 00:00:00 2001 From: Mike Cann Date: Fri, 1 Aug 2025 11:12:31 +0800 Subject: [PATCH 04/77] fixed typechecking failing on tests by excluding --- example/convex/aggregate.test.ts | 18 ++--- example/convex/tsconfig.json | 2 +- example/src/App.tsx | 107 ------------------------------ src/component/_generated/api.d.ts | 5 +- 4 files changed, 13 insertions(+), 119 deletions(-) diff --git a/example/convex/aggregate.test.ts b/example/convex/aggregate.test.ts index 9d78cd3..d476750 100644 --- a/example/convex/aggregate.test.ts +++ b/example/convex/aggregate.test.ts @@ -10,7 +10,7 @@ import { api, components, internal } from "../../example/convex/_generated/api"; const modules = import.meta.glob("./**/*.ts"); const componentModules = import.meta.glob("../../src/component/**/*.ts"); const migrationsModules = import.meta.glob( - "../node_modules/@convex-dev/migrations/src/component/**/*.ts", + "../node_modules/@convex-dev/migrations/src/component/**/*.ts" ); describe("leaderboard", () => { @@ -20,7 +20,7 @@ describe("leaderboard", () => { t.registerComponent( "aggregateScoreByUser", componentSchema, - componentModules, + componentModules ); t.registerComponent("migrations", migrationsSchema, migrationsModules); // Reduce maxNodeSize so we can test complex trees with fewer items. @@ -77,26 +77,26 @@ describe("leaderboard", () => { await t.mutation(api.leaderboard.addScore, { name: "Sarah", score: 5 }); expect( - await t.query(api.leaderboard.scoreAtRank, { rank: 0 }), + await t.query(api.leaderboard.scoreAtRank, { rank: 0 }) ).toMatchObject({ name: "Sarah", score: 35 }); expect( - await t.query(api.leaderboard.scoreAtRank, { rank: 1 }), + await t.query(api.leaderboard.scoreAtRank, { rank: 1 }) ).toMatchObject({ name: "Lee", score: 30 }); expect( - await t.query(api.leaderboard.scoreAtRank, { rank: 5 }), + await t.query(api.leaderboard.scoreAtRank, { rank: 5 }) ).toMatchObject({ name: "Sujay", score: 10 }); expect( - await t.query(api.leaderboard.rankOfScore, { score: 35 }), + await t.query(api.leaderboard.rankOfScore, { score: 35 }) ).toStrictEqual(0); expect( - await t.query(api.leaderboard.rankOfScore, { score: 30 }), + await t.query(api.leaderboard.rankOfScore, { score: 30 }) ).toStrictEqual(1); expect( - await t.query(api.leaderboard.rankOfScore, { score: 10 }), + await t.query(api.leaderboard.rankOfScore, { score: 10 }) ).toStrictEqual(5); expect( - await t.query(api.leaderboard.rankOfScore, { score: 33 }), + await t.query(api.leaderboard.rankOfScore, { score: 33 }) ).toStrictEqual(1); const scoresInOrder = await t.query(api.leaderboard.scoresInOrder); diff --git a/example/convex/tsconfig.json b/example/convex/tsconfig.json index 6fa874e..0f2d4fe 100644 --- a/example/convex/tsconfig.json +++ b/example/convex/tsconfig.json @@ -21,5 +21,5 @@ "noEmit": true }, "include": ["./**/*"], - "exclude": ["./_generated"] + "exclude": ["./_generated", "**/*.test.ts"] } diff --git a/example/src/App.tsx b/example/src/App.tsx index 64b4150..7f37a4e 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -9,114 +9,7 @@ export default function App() {

Convex + React

-
); } - -function Content() { - const { viewer, numbers } = - useQuery(api.myFunctions.listNumbers, { - count: 10, - }) ?? {}; - const addNumber = useMutation(api.myFunctions.addNumber); - - if (viewer === undefined || numbers === undefined) { - return ( -
-

loading... (consider a loading skeleton)

-
- ); - } - - return ( -
-

Welcome {viewer ?? "Anonymous"}!

-

- Click the button below and open this page in another window - this data - is persisted in the Convex cloud database! -

-

- -

-

- Numbers:{" "} - {numbers?.length === 0 - ? "Click the button!" - : (numbers?.join(", ") ?? "...")} -

-

- Edit{" "} - - convex/myFunctions.ts - {" "} - to change your backend -

-

- Edit{" "} - - src/App.tsx - {" "} - to change your frontend -

-
-

Useful resources:

-
-
- - -
-
- - -
-
-
-
- ); -} - -function ResourceCard({ - title, - description, - href, -}: { - title: string; - description: string; - href: string; -}) { - return ( -
- - {title} - -

{description}

-
- ); -} diff --git a/src/component/_generated/api.d.ts b/src/component/_generated/api.d.ts index 3e55ed2..1843f4f 100644 --- a/src/component/_generated/api.d.ts +++ b/src/component/_generated/api.d.ts @@ -11,13 +11,14 @@ import type * as btree from "../btree.js"; import type * as compare from "../compare.js"; import type * as inspect from "../inspect.js"; -import type * as public from "../public.js"; +import type * as public_ from "../public.js"; import type { ApiFromModules, FilterApi, FunctionReference, } from "convex/server"; + /** * A utility for referencing Convex functions in your app's API. * @@ -30,7 +31,7 @@ declare const fullApi: ApiFromModules<{ btree: typeof btree; compare: typeof compare; inspect: typeof inspect; - public: typeof public; + public: typeof public_; }>; export type Mounts = { btree: { From 24d23dc0d7bac6d4861c8801360cca8c93fd259c Mon Sep 17 00:00:00 2001 From: Mike Cann Date: Fri, 1 Aug 2025 11:17:21 +0800 Subject: [PATCH 05/77] using mantine instead of tailwind --- example/package-lock.json | 1238 ++++++++++++++++++++++++------------- example/package.json | 7 +- example/src/App.tsx | 24 +- example/src/index.css | 24 +- example/src/main.tsx | 29 +- example/vite.config.ts | 3 +- 6 files changed, 857 insertions(+), 468 deletions(-) diff --git a/example/package-lock.json b/example/package-lock.json index 53c2131..3dea92f 100644 --- a/example/package-lock.json +++ b/example/package-lock.json @@ -10,6 +10,11 @@ "dependencies": { "@convex-dev/aggregate": "file:..", "@convex-dev/migrations": "^0.2.1", + "@emotion/react": "^11.14.0", + "@emotion/styled": "^11.14.1", + "@mantine/core": "^8.2.2", + "@mantine/emotion": "^8.2.2", + "@mantine/hooks": "^8.2.2", "convex": "^1.17.0", "convex-helpers": "^0.1.61", "rand-seed": "^2.1.7", @@ -18,7 +23,6 @@ }, "devDependencies": { "@eslint/js": "^9.21.0", - "@tailwindcss/vite": "^4.0.14", "@types/node": "^22.13.10", "@types/react": "^19.0.10", "@types/react-dom": "^19.0.4", @@ -29,7 +33,6 @@ "globals": "^15.15.0", "npm-run-all": "^4.1.5", "prettier": "^3.5.3", - "tailwindcss": "^4.0.14", "typescript": "~5.7.2", "typescript-eslint": "^8.24.1", "vite": "^6.2.0" @@ -74,7 +77,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", "integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-validator-identifier": "^7.27.1", @@ -130,7 +132,6 @@ "version": "7.28.0", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.0.tgz", "integrity": "sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/parser": "^7.28.0", @@ -164,7 +165,6 @@ "version": "7.28.0", "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -174,7 +174,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz", "integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==", - "dev": true, "license": "MIT", "dependencies": { "@babel/traverse": "^7.27.1", @@ -216,7 +215,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -226,7 +224,6 @@ "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -260,7 +257,6 @@ "version": "7.28.0", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz", "integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==", - "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.28.0" @@ -304,11 +300,19 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/runtime": { + "version": "7.28.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.28.2.tgz", + "integrity": "sha512-KHp2IflsnGywDjBWDkR9iEqiWSpc8GIi0lgTT3mOElT0PP1tG26P4tmFI2YvAdzgq9RGyoHZQEIEdZy6Ec5xCA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/template": { "version": "7.27.2", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz", "integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -323,7 +327,6 @@ "version": "7.28.0", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.0.tgz", "integrity": "sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==", - "dev": true, "license": "MIT", "dependencies": { "@babel/code-frame": "^7.27.1", @@ -342,7 +345,6 @@ "version": "7.28.2", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz", "integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.27.1", @@ -365,6 +367,158 @@ "convex": "~1.16.5 || >=1.17.0 <1.35.0" } }, + "node_modules/@emotion/babel-plugin": { + "version": "11.13.5", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz", + "integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/serialize": "^1.3.3", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "license": "MIT" + }, + "node_modules/@emotion/cache": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.14.0.tgz", + "integrity": "sha512-L/B1lc/TViYk4DcpGxtAVbx0ZyiKM5ktoIyafGkH6zg/tj+mA+NE//aPYKG0k8kCHSHVJrpLpcAlOBEXQ3SavA==", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.9.0", + "@emotion/sheet": "^1.4.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==", + "license": "MIT" + }, + "node_modules/@emotion/is-prop-valid": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-1.3.1.tgz", + "integrity": "sha512-/ACwoqx7XQi9knQs/G0qKvv5teDMhD7bXYns9N/wM8ah8iNb8jZ2uNO0YOgiq2o2poIvVtJS2YALasQuMSQ7Kw==", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.9.0" + } + }, + "node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==", + "license": "MIT" + }, + "node_modules/@emotion/react": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.14.0.tgz", + "integrity": "sha512-O000MLDBDdk/EohJPFUqvnp4qnHeYkVP5B0xEG0D/L7cOKP9kefu2DXn8dj74cQfsEzUqh+sr1RzFqiL1o+PpA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/cache": "^11.14.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2", + "@emotion/weak-memoize": "^0.4.0", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz", + "integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==", + "license": "MIT", + "dependencies": { + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/unitless": "^0.10.0", + "@emotion/utils": "^1.4.2", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", + "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==", + "license": "MIT" + }, + "node_modules/@emotion/styled": { + "version": "11.14.1", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-11.14.1.tgz", + "integrity": "sha512-qEEJt42DuToa3gurlH4Qqc1kVpNq8wO8cJtDzU46TjlzWjDlsVyevtYCRijVq3SrHsROS+gVQ8Fnea108GnKzw==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.13.5", + "@emotion/is-prop-valid": "^1.3.0", + "@emotion/serialize": "^1.3.3", + "@emotion/use-insertion-effect-with-fallbacks": "^1.2.0", + "@emotion/utils": "^1.4.2" + }, + "peerDependencies": { + "@emotion/react": "^11.0.0-rc.0", + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/unitless": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", + "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==", + "license": "MIT" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz", + "integrity": "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz", + "integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==", + "license": "MIT" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.4.0.tgz", + "integrity": "sha512-snKqtPW01tN0ui7yu9rGv69aJXr/a/Ywvl11sUjNtEcRc+ng/mQriFL0wLXMef74iHa/EkftbDzU9F8iFbH+zg==", + "license": "MIT" + }, "node_modules/@esbuild/aix-ppc64": { "version": "0.25.4", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.4.tgz", @@ -919,6 +1073,59 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@floating-ui/core": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz", + "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.3.tgz", + "integrity": "sha512-uZA413QEpNuhtb3/iIKoYMSK07keHPYeXF02Zhd6e213j+d1NamLix/mCLxBUDW/Gx52sPH2m+chlUsyaBs/Ag==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.3", + "@floating-ui/utils": "^0.2.10" + } + }, + "node_modules/@floating-ui/react": { + "version": "0.26.28", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.26.28.tgz", + "integrity": "sha512-yORQuuAtVpiRjpMhdc0wJj06b9JFjrYF4qp96j++v2NBpbi6SEGF7donUJ3TMieerQ6qVkAv1tgr7L4r5roTqw==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.1.2", + "@floating-ui/utils": "^0.2.8", + "tabbable": "^6.0.0" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.5.tgz", + "integrity": "sha512-HDO/1/1oH9fjj4eLgegrlH3dklZpHtUYYFiVwMUwfGvk9jWDRWqkklA2/NFScknrcNSspbV868WjXORvreDX+Q==", + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "^1.7.3" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz", + "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==", + "license": "MIT" + }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -985,24 +1192,10 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@isaacs/fs-minipass": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", - "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^7.0.4" - }, - "engines": { - "node": ">=18.0.0" - } - }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.12", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz", "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", @@ -1013,7 +1206,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -1023,20 +1215,65 @@ "version": "1.5.4", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz", "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==", - "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.29", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz", "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@mantine/core": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@mantine/core/-/core-8.2.2.tgz", + "integrity": "sha512-+WnqII3zSD72F+7GLcRXZ/MyO4r7A4JM/yWkCSclxR4LeRQ5bd4HBRXkvXRMZP28UeL2b5X9Re2Sig3KVGDBeQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/react": "^0.26.28", + "clsx": "^2.1.1", + "react-number-format": "^5.4.3", + "react-remove-scroll": "^2.6.2", + "react-textarea-autosize": "8.5.9", + "type-fest": "^4.27.0" + }, + "peerDependencies": { + "@mantine/hooks": "8.2.2", + "react": "^18.x || ^19.x", + "react-dom": "^18.x || ^19.x" + } + }, + "node_modules/@mantine/emotion": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@mantine/emotion/-/emotion-8.2.2.tgz", + "integrity": "sha512-qPFGQh5o3HSz994xAslDvb3wdTRB+89a6CS9dM7tJJQHmJjKmOrDPj/UL37KNxFqrEI5ipXetCKeSJBmwpIRDQ==", + "license": "MIT", + "dependencies": { + "html-react-parser": "^5.1.18" + }, + "peerDependencies": { + "@emotion/cache": "^11.11.0", + "@emotion/react": "^11.11.4", + "@emotion/serialize": "^1.1.4", + "@emotion/utils": "^1.2.1", + "@mantine/core": "8.2.2", + "@mantine/hooks": "8.2.2", + "react": "^18.x || ^19.x", + "react-dom": "^18.x || ^19.x" + } + }, + "node_modules/@mantine/hooks": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@mantine/hooks/-/hooks-8.2.2.tgz", + "integrity": "sha512-fjt0+pc1UxJIIUswu4ur72qVH+/UoFxyYmqWexuHJTOvuB86M//KUvXpFyhJcTdEENBHg2k1fyMpWmgg1VOZ5w==", + "license": "MIT", + "peerDependencies": { + "react": "^18.x || ^19.x" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1362,283 +1599,6 @@ "win32" ] }, - "node_modules/@tailwindcss/node": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.11.tgz", - "integrity": "sha512-yzhzuGRmv5QyU9qLNg4GTlYI6STedBWRE7NjxP45CsFYYq9taI0zJXZBMqIC/c8fViNLhmrbpSFS57EoxUmD6Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@ampproject/remapping": "^2.3.0", - "enhanced-resolve": "^5.18.1", - "jiti": "^2.4.2", - "lightningcss": "1.30.1", - "magic-string": "^0.30.17", - "source-map-js": "^1.2.1", - "tailwindcss": "4.1.11" - } - }, - "node_modules/@tailwindcss/oxide": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.11.tgz", - "integrity": "sha512-Q69XzrtAhuyfHo+5/HMgr1lAiPP/G40OMFAnws7xcFEYqcypZmdW8eGXaOUIeOl1dzPJBPENXgbjsOyhg2nkrg==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "detect-libc": "^2.0.4", - "tar": "^7.4.3" - }, - "engines": { - "node": ">= 10" - }, - "optionalDependencies": { - "@tailwindcss/oxide-android-arm64": "4.1.11", - "@tailwindcss/oxide-darwin-arm64": "4.1.11", - "@tailwindcss/oxide-darwin-x64": "4.1.11", - "@tailwindcss/oxide-freebsd-x64": "4.1.11", - "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.11", - "@tailwindcss/oxide-linux-arm64-gnu": "4.1.11", - "@tailwindcss/oxide-linux-arm64-musl": "4.1.11", - "@tailwindcss/oxide-linux-x64-gnu": "4.1.11", - "@tailwindcss/oxide-linux-x64-musl": "4.1.11", - "@tailwindcss/oxide-wasm32-wasi": "4.1.11", - "@tailwindcss/oxide-win32-arm64-msvc": "4.1.11", - "@tailwindcss/oxide-win32-x64-msvc": "4.1.11" - } - }, - "node_modules/@tailwindcss/oxide-android-arm64": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.11.tgz", - "integrity": "sha512-3IfFuATVRUMZZprEIx9OGDjG3Ou3jG4xQzNTvjDoKmU9JdmoCohQJ83MYd0GPnQIu89YoJqvMM0G3uqLRFtetg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-darwin-arm64": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.11.tgz", - "integrity": "sha512-ESgStEOEsyg8J5YcMb1xl8WFOXfeBmrhAwGsFxxB2CxY9evy63+AtpbDLAyRkJnxLy2WsD1qF13E97uQyP1lfQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-darwin-x64": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.11.tgz", - "integrity": "sha512-EgnK8kRchgmgzG6jE10UQNaH9Mwi2n+yw1jWmof9Vyg2lpKNX2ioe7CJdf9M5f8V9uaQxInenZkOxnTVL3fhAw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-freebsd-x64": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.11.tgz", - "integrity": "sha512-xdqKtbpHs7pQhIKmqVpxStnY1skuNh4CtbcyOHeX1YBE0hArj2romsFGb6yUmzkq/6M24nkxDqU8GYrKrz+UcA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.11.tgz", - "integrity": "sha512-ryHQK2eyDYYMwB5wZL46uoxz2zzDZsFBwfjssgB7pzytAeCCa6glsiJGjhTEddq/4OsIjsLNMAiMlHNYnkEEeg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.11.tgz", - "integrity": "sha512-mYwqheq4BXF83j/w75ewkPJmPZIqqP1nhoghS9D57CLjsh3Nfq0m4ftTotRYtGnZd3eCztgbSPJ9QhfC91gDZQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-linux-arm64-musl": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.11.tgz", - "integrity": "sha512-m/NVRFNGlEHJrNVk3O6I9ggVuNjXHIPoD6bqay/pubtYC9QIdAMpS+cswZQPBLvVvEF6GtSNONbDkZrjWZXYNQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-linux-x64-gnu": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.11.tgz", - "integrity": "sha512-YW6sblI7xukSD2TdbbaeQVDysIm/UPJtObHJHKxDEcW2exAtY47j52f8jZXkqE1krdnkhCMGqP3dbniu1Te2Fg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-linux-x64-musl": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.11.tgz", - "integrity": "sha512-e3C/RRhGunWYNC3aSF7exsQkdXzQ/M+aYuZHKnw4U7KQwTJotnWsGOIVih0s2qQzmEzOFIJ3+xt7iq67K/p56Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-wasm32-wasi": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.11.tgz", - "integrity": "sha512-Xo1+/GU0JEN/C/dvcammKHzeM6NqKovG+6921MR6oadee5XPBaKOumrJCXvopJ/Qb5TH7LX/UAywbqrP4lax0g==", - "bundleDependencies": [ - "@napi-rs/wasm-runtime", - "@emnapi/core", - "@emnapi/runtime", - "@tybys/wasm-util", - "@emnapi/wasi-threads", - "tslib" - ], - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "^1.4.3", - "@emnapi/runtime": "^1.4.3", - "@emnapi/wasi-threads": "^1.0.2", - "@napi-rs/wasm-runtime": "^0.2.11", - "@tybys/wasm-util": "^0.9.0", - "tslib": "^2.8.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.11.tgz", - "integrity": "sha512-UgKYx5PwEKrac3GPNPf6HVMNhUIGuUh4wlDFR2jYYdkX6pL/rn73zTq/4pzUm8fOjAn5L8zDeHp9iXmUGOXZ+w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/oxide-win32-x64-msvc": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.11.tgz", - "integrity": "sha512-YfHoggn1j0LK7wR82TOucWc5LDCguHnoS879idHekmmiR7g9HUtMw9MI0NHatS28u/Xlkfi9w5RJWgz2Dl+5Qg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/vite": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.11.tgz", - "integrity": "sha512-RHYhrR3hku0MJFRV+fN2gNbDNEh3dwKvY8XJvTxCSXeMOsCRSr+uKvDWQcbizrHgjML6ZmTE5OwMrl5wKcujCw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@tailwindcss/node": "4.1.11", - "@tailwindcss/oxide": "4.1.11", - "tailwindcss": "4.1.11" - }, - "peerDependencies": { - "vite": "^5.2.0 || ^6 || ^7" - } - }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", @@ -1708,11 +1668,17 @@ "undici-types": "~6.21.0" } }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", + "license": "MIT" + }, "node_modules/@types/react": { "version": "19.1.9", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.9.tgz", "integrity": "sha512-WmdoynAX8Stew/36uTSVMcLJJ1KRh6L3IZRx1PZ7qJtBqT3dYTgyDTx8H1qoRghErydW7xw9mSJ3wS//tCRpFA==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "csstype": "^3.0.2" @@ -2148,6 +2114,21 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -2266,7 +2247,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -2310,14 +2290,13 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/chownr": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", - "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", - "dev": true, - "license": "BlueOak-1.0.0", + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", "engines": { - "node": ">=18" + "node": ">=6" } }, "node_modules/color-convert": { @@ -2437,6 +2416,58 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, + "node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "license": "MIT", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cosmiconfig/node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cosmiconfig/node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cosmiconfig/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", @@ -2456,7 +2487,6 @@ "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", - "dev": true, "license": "MIT" }, "node_modules/data-view-buffer": { @@ -2517,7 +2547,6 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", - "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -2580,10 +2609,85 @@ "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", "dev": true, "license": "Apache-2.0", + "optional": true, + "peer": true, "engines": { "node": ">=8" } }, + "node_modules/detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", + "license": "MIT" + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/dom-serializer/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", @@ -2606,25 +2710,22 @@ "dev": true, "license": "ISC" }, - "node_modules/enhanced-resolve": { - "version": "5.18.2", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.2.tgz", - "integrity": "sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, + "node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "license": "BSD-2-Clause", "engines": { - "node": ">=10.13.0" + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" } }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, "license": "MIT", "dependencies": { "is-arrayish": "^0.2.1" @@ -2820,7 +2921,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -3094,6 +3194,12 @@ "node": ">=8" } }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "license": "MIT" + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -3167,7 +3273,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -3239,6 +3344,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/get-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", @@ -3426,7 +3540,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -3435,6 +3548,15 @@ "node": ">= 0.4" } }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "license": "BSD-3-Clause", + "dependencies": { + "react-is": "^16.7.0" + } + }, "node_modules/hosted-git-info": { "version": "2.8.9", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", @@ -3442,6 +3564,56 @@ "dev": true, "license": "ISC" }, + "node_modules/html-dom-parser": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/html-dom-parser/-/html-dom-parser-5.1.1.tgz", + "integrity": "sha512-+o4Y4Z0CLuyemeccvGN4bAO20aauB2N9tFEAep5x4OW34kV4PTarBHm6RL02afYt2BMKcr0D2Agep8S3nJPIBg==", + "license": "MIT", + "dependencies": { + "domhandler": "5.0.3", + "htmlparser2": "10.0.0" + } + }, + "node_modules/html-react-parser": { + "version": "5.2.6", + "resolved": "https://registry.npmjs.org/html-react-parser/-/html-react-parser-5.2.6.tgz", + "integrity": "sha512-qcpPWLaSvqXi+TndiHbCa+z8qt0tVzjMwFGFBAa41ggC+ZA5BHaMIeMJla9g3VSp4SmiZb9qyQbmbpHYpIfPOg==", + "license": "MIT", + "dependencies": { + "domhandler": "5.0.3", + "html-dom-parser": "5.1.1", + "react-property": "2.0.2", + "style-to-js": "1.1.17" + }, + "peerDependencies": { + "@types/react": "0.14 || 15 || 16 || 17 || 18 || 19", + "react": "0.14 || 15 || 16 || 17 || 18 || 19" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/htmlparser2": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.0.0.tgz", + "integrity": "sha512-TwAZM+zE5Tq3lrEHvOlvwgj1XLWQCtaaibSN11Q+gGBAS7Y1uZSWwXXRe4iF6OXnaq1riyQAPFOBtYc77Mxq0g==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.2.1", + "entities": "^6.0.0" + } + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -3456,7 +3628,6 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "dev": true, "license": "MIT", "dependencies": { "parent-module": "^1.0.0", @@ -3479,6 +3650,12 @@ "node": ">=0.8.19" } }, + "node_modules/inline-style-parser": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.4.tgz", + "integrity": "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==", + "license": "MIT" + }, "node_modules/internal-slot": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", @@ -3516,7 +3693,6 @@ "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true, "license": "MIT" }, "node_modules/is-async-function": { @@ -3589,7 +3765,6 @@ "version": "2.16.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", - "dev": true, "license": "MIT", "dependencies": { "hasown": "^2.0.2" @@ -3912,6 +4087,8 @@ "integrity": "sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "bin": { "jiti": "lib/jiti-cli.mjs" } @@ -3920,7 +4097,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true, "license": "MIT" }, "node_modules/js-yaml": { @@ -3940,7 +4116,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true, "license": "MIT", "bin": { "jsesc": "bin/jsesc" @@ -3963,6 +4138,12 @@ "dev": true, "license": "MIT" }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "license": "MIT" + }, "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -4029,6 +4210,8 @@ "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==", "dev": true, "license": "MPL-2.0", + "optional": true, + "peer": true, "dependencies": { "detect-libc": "^2.0.3" }, @@ -4065,6 +4248,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -4086,6 +4270,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -4107,6 +4292,7 @@ "os": [ "freebsd" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -4128,6 +4314,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -4149,6 +4336,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -4170,6 +4358,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -4191,6 +4380,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -4212,6 +4402,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -4233,6 +4424,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -4254,6 +4446,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -4262,6 +4455,12 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" + }, "node_modules/load-json-file": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", @@ -4311,16 +4510,6 @@ "yallist": "^3.0.2" } }, - "node_modules/magic-string": { - "version": "0.30.17", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", - "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0" - } - }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", @@ -4377,50 +4566,10 @@ "node": "*" } }, - "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/minizlib": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz", - "integrity": "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==", - "dev": true, - "license": "MIT", - "dependencies": { - "minipass": "^7.1.2" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/mkdirp": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", - "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", - "dev": true, - "license": "MIT", - "bin": { - "mkdirp": "dist/cjs/src/bin.js" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, "license": "MIT" }, "node_modules/nanoid": { @@ -4779,7 +4928,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, "license": "MIT", "dependencies": { "callsites": "^3.0.0" @@ -4826,7 +4974,6 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, "license": "MIT" }, "node_modules/path-type": { @@ -4846,7 +4993,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, "license": "ISC" }, "node_modules/picomatch": { @@ -5008,6 +5154,28 @@ "react": "^19.1.1" } }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "license": "MIT" + }, + "node_modules/react-number-format": { + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/react-number-format/-/react-number-format-5.4.4.tgz", + "integrity": "sha512-wOmoNZoOpvMminhifQYiYSTCLUDOiUbBunrMrMjA+dV52sY+vck1S4UhR6PkgnoCquvvMSeJjErXZ4qSaWCliA==", + "license": "MIT", + "peerDependencies": { + "react": "^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0", + "react-dom": "^0.14 || ^15.0.0 || ^16.0.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/react-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/react-property/-/react-property-2.0.2.tgz", + "integrity": "sha512-+PbtI3VuDV0l6CleQMsx2gtK0JZbZKbpdu5ynr+lbsuvtmgbNcS3VM0tuY2QjFNOcWxvXeHjDpy42RO+4U2rug==", + "license": "MIT" + }, "node_modules/react-refresh": { "version": "0.17.0", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", @@ -5018,6 +5186,92 @@ "node": ">=0.10.0" } }, + "node_modules/react-remove-scroll": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.1.tgz", + "integrity": "sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==", + "license": "MIT", + "dependencies": { + "react-remove-scroll-bar": "^2.3.7", + "react-style-singleton": "^2.2.3", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.3" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-remove-scroll-bar": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", + "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", + "license": "MIT", + "dependencies": { + "react-style-singleton": "^2.2.2", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-style-singleton": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", + "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", + "license": "MIT", + "dependencies": { + "get-nonce": "^1.0.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-textarea-autosize": { + "version": "8.5.9", + "resolved": "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-8.5.9.tgz", + "integrity": "sha512-U1DGlIQN5AwgjTyOEnI1oCcMuEr1pv1qOtklB2l4nyMGbHzWrI0eFsYK0zos2YWqAolJyG0IWJaqWmWj5ETh0A==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.20.13", + "use-composed-ref": "^1.3.0", + "use-latest": "^1.2.1" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/read-pkg": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", @@ -5081,7 +5335,6 @@ "version": "1.22.10", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", - "dev": true, "license": "MIT", "dependencies": { "is-core-module": "^2.16.0", @@ -5102,7 +5355,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -5415,6 +5667,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -5576,6 +5837,30 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/style-to-js": { + "version": "1.1.17", + "resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.17.tgz", + "integrity": "sha512-xQcBGDxJb6jjFCTzvQtfiPn6YvvP2O8U1MDIPNfJQlWMYfktPy+iGsHE7cssjs7y84d9fQaK4UF3RIJaAHSoYA==", + "license": "MIT", + "dependencies": { + "style-to-object": "1.0.9" + } + }, + "node_modules/style-to-object": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.9.tgz", + "integrity": "sha512-G4qppLgKu/k6FwRpHiGiKPaPTFcG3g4wNVX/Qsfu+RqQM30E7Tyu/TEgxcL9PNLF5pdRLwQdE3YKKf+KF2Dzlw==", + "license": "MIT", + "dependencies": { + "inline-style-parser": "0.2.4" + } + }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", + "license": "MIT" + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -5593,7 +5878,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -5602,51 +5886,12 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/tailwindcss": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.11.tgz", - "integrity": "sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA==", - "dev": true, + "node_modules/tabbable": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.2.0.tgz", + "integrity": "sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==", "license": "MIT" }, - "node_modules/tapable": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.2.tgz", - "integrity": "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/tar": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz", - "integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==", - "dev": true, - "license": "ISC", - "dependencies": { - "@isaacs/fs-minipass": "^4.0.0", - "chownr": "^3.0.0", - "minipass": "^7.1.2", - "minizlib": "^3.0.1", - "mkdirp": "^3.0.1", - "yallist": "^5.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/tar/node_modules/yallist": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", - "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" - } - }, "node_modules/tinyglobby": { "version": "0.2.14", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", @@ -5718,6 +5963,12 @@ "typescript": ">=4.8.4" } }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -5731,6 +5982,18 @@ "node": ">= 0.8.0" } }, + "node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/typed-array-buffer": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", @@ -5914,6 +6177,94 @@ "punycode": "^2.1.0" } }, + "node_modules/use-callback-ref": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", + "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-composed-ref": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/use-composed-ref/-/use-composed-ref-1.4.0.tgz", + "integrity": "sha512-djviaxuOOh7wkj0paeO1Q/4wMZ8Zrnag5H6yBvzN7AKKe8beOaED9SF5/ByLqsku8NP4zQqsvM2u3ew/tJK8/w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-isomorphic-layout-effect": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.2.1.tgz", + "integrity": "sha512-tpZZ+EX0gaghDAiFR37hj5MgY6ZN55kLiPkJsKxBMZ6GZdOSPJXiOzPM984oPYZ5AnehYx5WQp1+ME8I/P/pRA==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-latest": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/use-latest/-/use-latest-1.3.0.tgz", + "integrity": "sha512-mhg3xdm9NaM8q+gLT8KryJPnRFOz1/5XPBhmDEVZK1webPzDjrPk7f/mbpeLqTgB9msytYWANxgALOCJKnLvcQ==", + "license": "MIT", + "dependencies": { + "use-isomorphic-layout-effect": "^1.1.1" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/use-sidecar": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", + "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", + "license": "MIT", + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -6150,6 +6501,21 @@ "dev": true, "license": "ISC" }, + "node_modules/yaml": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", + "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==", + "dev": true, + "license": "ISC", + "optional": true, + "peer": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/example/package.json b/example/package.json index 70aa7a5..1b5938d 100644 --- a/example/package.json +++ b/example/package.json @@ -15,6 +15,11 @@ "dependencies": { "@convex-dev/aggregate": "file:..", "@convex-dev/migrations": "^0.2.1", + "@emotion/react": "^11.14.0", + "@emotion/styled": "^11.14.1", + "@mantine/core": "^8.2.2", + "@mantine/emotion": "^8.2.2", + "@mantine/hooks": "^8.2.2", "convex": "^1.17.0", "convex-helpers": "^0.1.61", "rand-seed": "^2.1.7", @@ -23,7 +28,6 @@ }, "devDependencies": { "@eslint/js": "^9.21.0", - "@tailwindcss/vite": "^4.0.14", "@types/node": "^22.13.10", "@types/react": "^19.0.10", "@types/react-dom": "^19.0.4", @@ -34,7 +38,6 @@ "globals": "^15.15.0", "npm-run-all": "^4.1.5", "prettier": "^3.5.3", - "tailwindcss": "^4.0.14", "typescript": "~5.7.2", "typescript-eslint": "^8.24.1", "vite": "^6.2.0" diff --git a/example/src/App.tsx b/example/src/App.tsx index 7f37a4e..5793349 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -1,15 +1,23 @@ import { useMutation, useQuery } from "convex/react"; import { api } from "../convex/_generated/api"; +import { AppShell, Container, Title, Text } from "@mantine/core"; export default function App() { return ( - <> -
- Convex + React -
-
-

Convex + React

-
- + + + + Convex + React + + + + + + + Convex + React + + + + ); } diff --git a/example/src/index.css b/example/src/index.css index 62c2b40..2f4d6d9 100644 --- a/example/src/index.css +++ b/example/src/index.css @@ -1,22 +1,14 @@ -@import "tailwindcss"; +@import '@mantine/core/styles.css'; -@theme { +:root { --color-light: #ffffff; --color-dark: #171717; } -@media (prefers-color-scheme: dark) { - body { - color: var(--color-light); - background: var(--color-dark); - font-family: Arial, Helvetica, sans-serif; - } -} - -@media (prefers-color-scheme: light) { - body { - color: var(--color-dark); - background: var(--color-light); - font-family: Arial, Helvetica, sans-serif; - } +body { + color: var(--color-light); + background: var(--color-dark); + font-family: Arial, Helvetica, sans-serif; + margin: 0; + padding: 0; } diff --git a/example/src/main.tsx b/example/src/main.tsx index 4880906..2df4c02 100644 --- a/example/src/main.tsx +++ b/example/src/main.tsx @@ -1,14 +1,35 @@ import { StrictMode } from "react"; import { createRoot } from "react-dom/client"; import { ConvexProvider, ConvexReactClient } from "convex/react"; +import { MantineProvider } from "@mantine/core"; import "./index.css"; import App from "./App.tsx"; const convex = new ConvexReactClient(import.meta.env.VITE_CONVEX_URL as string); createRoot(document.getElementById("root")!).render( - - - - , + + + + + + ); diff --git a/example/vite.config.ts b/example/vite.config.ts index 506e619..2680889 100644 --- a/example/vite.config.ts +++ b/example/vite.config.ts @@ -1,11 +1,10 @@ import { defineConfig } from "vite"; import react from "@vitejs/plugin-react"; -import tailwindcss from "@tailwindcss/vite"; import path from "path"; // https://vite.dev/config/ export default defineConfig({ - plugins: [react(), tailwindcss()], + plugins: [react()], resolve: { alias: { "@": path.resolve(__dirname, "./src"), From 5cf57fa0bf8e1a68bfc6ec0a93507d4bf6cbee23 Mon Sep 17 00:00:00 2001 From: Mike Cann Date: Fri, 1 Aug 2025 11:30:42 +0800 Subject: [PATCH 06/77] wip --- example/package-lock.json | 21 ++- example/package.json | 4 +- example/src/App.tsx | 85 ++++++++- example/src/main.tsx | 1 - example/src/pages/HomePage.tsx | 85 +++++++++ example/src/pages/LeaderboardPage.tsx | 246 ++++++++++++++++++++++++++ example/src/pages/PhotosPage.tsx | 152 ++++++++++++++++ example/src/pages/ShufflePage.tsx | 187 ++++++++++++++++++++ example/src/pages/StatsPage.tsx | 179 +++++++++++++++++++ 9 files changed, 948 insertions(+), 12 deletions(-) create mode 100644 example/src/pages/HomePage.tsx create mode 100644 example/src/pages/LeaderboardPage.tsx create mode 100644 example/src/pages/PhotosPage.tsx create mode 100644 example/src/pages/ShufflePage.tsx create mode 100644 example/src/pages/StatsPage.tsx diff --git a/example/package-lock.json b/example/package-lock.json index 3dea92f..eeba1b1 100644 --- a/example/package-lock.json +++ b/example/package-lock.json @@ -19,7 +19,8 @@ "convex-helpers": "^0.1.61", "rand-seed": "^2.1.7", "react": "^19.0.0", - "react-dom": "^19.0.0" + "react-dom": "^19.0.0", + "type-route": "^1.1.0" }, "devDependencies": { "@eslint/js": "^9.21.0", @@ -3548,6 +3549,15 @@ "node": ">= 0.4" } }, + "node_modules/history": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/history/-/history-5.3.0.tgz", + "integrity": "sha512-ZqaKwjjrAYUYfLG+htGaIIZ4nioX2L70ZUMIFysS3xvBsSG4x/n1V6TXV3N8ZYNuFGlDirFg32T7B6WOUPDYcQ==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.7.6" + } + }, "node_modules/hoist-non-react-statics": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", @@ -5994,6 +6004,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/type-route": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/type-route/-/type-route-1.1.0.tgz", + "integrity": "sha512-MgM/N+R8wp2oMYZZvBerFvK1j8CloGnhnsgf2ZTarFJ9PUXiNwLTCR3SkN0Mj95IdNee00v9q2iBNlkB106I7w==", + "license": "MIT", + "dependencies": { + "history": "^5.3.0" + } + }, "node_modules/typed-array-buffer": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", diff --git a/example/package.json b/example/package.json index 1b5938d..bf227cb 100644 --- a/example/package.json +++ b/example/package.json @@ -7,6 +7,7 @@ "dev": "npm-run-all --parallel dev:frontend dev:backend", "dev:frontend": "vite --open", "dev:backend": "convex dev --live-component-sources --typecheck-components", + "dev:ts": "tsc -b -w", "predev": "convex dev --until-success && convex dashboard", "build": "tsc -b && vite build", "lint": "tsc && eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", @@ -24,7 +25,8 @@ "convex-helpers": "^0.1.61", "rand-seed": "^2.1.7", "react": "^19.0.0", - "react-dom": "^19.0.0" + "react-dom": "^19.0.0", + "type-route": "^1.1.0" }, "devDependencies": { "@eslint/js": "^9.21.0", diff --git a/example/src/App.tsx b/example/src/App.tsx index 5793349..d4bcd4c 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -1,21 +1,88 @@ -import { useMutation, useQuery } from "convex/react"; -import { api } from "../convex/_generated/api"; -import { AppShell, Container, Title, Text } from "@mantine/core"; +import { + AppShell, + Container, + Text, + NavLink, + Group, + Stack, +} from "@mantine/core"; +import { useState } from "react"; +import { HomePage } from "./pages/HomePage"; +import { LeaderboardPage } from "./pages/LeaderboardPage"; +import { PhotosPage } from "./pages/PhotosPage"; +import { ShufflePage } from "./pages/ShufflePage"; +import { StatsPage } from "./pages/StatsPage"; + +type Page = "home" | "leaderboard" | "photos" | "shuffle" | "stats"; export default function App() { + const [currentPage, setCurrentPage] = useState("home"); + + const renderPage = () => { + switch (currentPage) { + case "home": + return ; + case "leaderboard": + return ; + case "photos": + return ; + case "shuffle": + return ; + case "stats": + return ; + default: + return ; + } + }; + return ( - - Convex + React - + + + Convex Aggregate Demo + + + + + setCurrentPage("home")} + c="white" + /> + setCurrentPage("leaderboard")} + c="white" + /> + setCurrentPage("photos")} + c="white" + /> + setCurrentPage("shuffle")} + c="white" + /> + setCurrentPage("stats")} + c="white" + /> + + + - - Convex + React - + {renderPage()} diff --git a/example/src/main.tsx b/example/src/main.tsx index 2df4c02..eb7ed0e 100644 --- a/example/src/main.tsx +++ b/example/src/main.tsx @@ -10,7 +10,6 @@ createRoot(document.getElementById("root")!).render( + + Convex Aggregate Demo + + + + Explore the power of Convex Aggregate component with these interactive + examples + + + + + + + Leaderboard + + + Game scores with rankings, averages, and user statistics + + Score Aggregation + + + + + + + Photos + + + Offset-based pagination for photo galleries + + Pagination + + + + + + + Shuffle + + + Random selection and shuffled music playlists + + Random Access + + + + + + + Stats + + + Direct aggregation without table dependencies + + Direct Aggregation + + + + + + + + What is Convex Aggregate? + + + The Aggregate component provides O(log(n))-time lookups for + counting, summing, and ranking data. It's perfect for leaderboards, + pagination, random access, and statistical calculations without the + O(n) complexity of traditional approaches. + + + Each example demonstrates different aggregation patterns and use + cases that showcase the component's capabilities for efficient data + analysis and retrieval. + + + + + ); +} diff --git a/example/src/pages/LeaderboardPage.tsx b/example/src/pages/LeaderboardPage.tsx new file mode 100644 index 0000000..9e809e4 --- /dev/null +++ b/example/src/pages/LeaderboardPage.tsx @@ -0,0 +1,246 @@ +import { useMutation, useQuery } from "convex/react"; +import { api } from "../../convex/_generated/api"; +import { + Title, + Text, + Card, + Stack, + Group, + TextInput, + NumberInput, + Button, + Table, + Badge, + Alert, +} from "@mantine/core"; +import { useState } from "react"; + +export function LeaderboardPage() { + const [playerName, setPlayerName] = useState(""); + const [score, setScore] = useState(""); + const [searchScore, setSearchScore] = useState(""); + const [searchPlayer, setSearchPlayer] = useState(""); + + // Queries + const scores = useQuery(api.leaderboard.scoresInOrder); + const totalCount = useQuery(api.leaderboard.countScores); + const totalSum = useQuery(api.leaderboard.sumNumbers); + + // Mutations + const addScore = useMutation(api.leaderboard.addScore); + const removeScore = useMutation(api.leaderboard.removeScore); + + // Computed queries + const rankOfScore = useQuery( + api.leaderboard.rankOfScore, + searchScore !== "" ? { score: searchScore } : "skip" + ); + const userAverage = useQuery( + api.leaderboard.userAverageScore, + searchPlayer ? { name: searchPlayer } : "skip" + ); + const userHighScore = useQuery( + api.leaderboard.userHighScore, + searchPlayer ? { name: searchPlayer } : "skip" + ); + + const handleAddScore = () => { + if (playerName && score !== "") { + addScore({ name: playerName, score: score }) + .then(() => { + setPlayerName(""); + setScore(""); + }) + .catch(console.error); + } + }; + + const handleRemoveScore = (id: string) => { + removeScore({ id: id as any }).catch(console.error); + }; + + const handleScoreChange = (value: number | string) => { + setScore(value === "" ? "" : (value as number)); + }; + + const handleSearchScoreChange = (value: number | string) => { + setSearchScore(value === "" ? "" : (value as number)); + }; + + return ( + + + Leaderboard Demo + + + + Add scores and explore aggregation features like rankings, averages, and + statistics + + + {/* Add Score Section */} + + + + Add New Score + + + setPlayerName(e.target.value)} + placeholder="Enter player name" + style={{ flex: 1 }} + /> + + + + + + + {/* Statistics Section */} + + + + + Total Scores + + + {totalCount ?? "Loading..."} + + + + + + + Total Sum + + + {totalSum ?? "Loading..."} + + + + + + + Average Score + + + {totalCount && totalSum + ? (totalSum / totalCount).toFixed(2) + : "Loading..."} + + + + + + {/* Search Section */} + + + + Search & Analysis + + + + + + Find Rank of Score + + + + + Rank: {rankOfScore !== undefined ? rankOfScore + 1 : "N/A"} + + + + + + + Player Statistics + + + setSearchPlayer(e.target.value)} + placeholder="Enter player name" + style={{ flex: 1 }} + /> + + + Avg: {userAverage ? userAverage.toFixed(2) : "N/A"} + + + High: {userHighScore ?? "N/A"} + + + + + + + + + {/* Leaderboard Table */} + + + + Current Leaderboard + + + {scores && scores.length > 0 ? ( + + + + Rank + Player + Score + Actions + + + + {scores.map((score, index) => ( + + {index + 1} + {score.split(": ")[0]} + {score.split(": ")[1]} + + + + + ))} + +
+ ) : ( + + Add some scores to see the leaderboard! + + )} +
+
+
+ ); +} diff --git a/example/src/pages/PhotosPage.tsx b/example/src/pages/PhotosPage.tsx new file mode 100644 index 0000000..8e10190 --- /dev/null +++ b/example/src/pages/PhotosPage.tsx @@ -0,0 +1,152 @@ +import { useMutation, useQuery } from "convex/react"; +import { api } from "../../convex/_generated/api"; +import { + Title, + Text, + Card, + Stack, + Group, + TextInput, + Button, + Image, + Pagination, + Alert, +} from "@mantine/core"; +import { useState } from "react"; + +export function PhotosPage() { + const [album, setAlbum] = useState(""); + const [url, setUrl] = useState(""); + const [currentPage, setCurrentPage] = useState(1); + const [pageSize] = useState(5); + + // Queries + const photos = useQuery(api.photos.pageOfPhotos, { + album: album || "default", + offset: (currentPage - 1) * pageSize, + numItems: pageSize, + }); + + // Mutations + const addPhoto = useMutation(api.photos.addPhoto); + + const handleAddPhoto = () => { + if (album && url) { + addPhoto({ album, url }) + .then(() => { + setAlbum(""); + setUrl(""); + }) + .catch(console.error); + } + }; + + return ( + + + Photos Demo + + + + Offset-based pagination for photo galleries with efficient O(log(n)) + lookups + + + {/* Add Photo Section */} + + + + Add New Photo + + + setAlbum(e.target.value)} + placeholder="Enter album name" + style={{ flex: 1 }} + /> + setUrl(e.target.value)} + placeholder="Enter photo URL" + style={{ flex: 1 }} + /> + + + + + + {/* Photo Gallery Section */} + + + + Photo Gallery + + + {photos && photos.length > 0 ? ( + + + {photos.map((photoUrl, index) => ( + + {`Photo + + Photo {index + 1} + + + ))} + + + + + + + ) : ( + + Add some photos to see the gallery! + + )} + + + + {/* Info Section */} + + + + How It Works + + + This demo uses Convex Aggregate to implement efficient offset-based + pagination. Instead of scanning through all photos to find the ones + on a specific page, the aggregate component provides O(log(n)) + lookup time to jump directly to any page of results. + + + Each photo is stored with its creation time as the sort key, + allowing the aggregate to quickly calculate which photos belong on + each page without loading all data into memory. + + + + + ); +} diff --git a/example/src/pages/ShufflePage.tsx b/example/src/pages/ShufflePage.tsx new file mode 100644 index 0000000..a627758 --- /dev/null +++ b/example/src/pages/ShufflePage.tsx @@ -0,0 +1,187 @@ +import { useMutation, useQuery } from "convex/react"; +import { api } from "../../convex/_generated/api"; +import { + Title, + Text, + Card, + Stack, + Group, + TextInput, + Button, + Badge, + Alert, + List, +} from "@mantine/core"; +import { useState } from "react"; + +export function ShufflePage() { + const [title, setTitle] = useState(""); + const [seed, setSeed] = useState("music"); + const [currentPage, setCurrentPage] = useState(1); + const [pageSize] = useState(5); + + // Queries + const randomMusic = useQuery(api.shuffle.getRandomMusicTitle, { + cacheBuster: Date.now(), + }); + const shuffledMusic = useQuery(api.shuffle.shufflePaginated, { + offset: (currentPage - 1) * pageSize, + numItems: pageSize, + seed, + }); + + // Mutations + const addMusic = useMutation(api.shuffle.addMusic); + + const handleAddMusic = () => { + if (title) { + addMusic({ title }) + .then(() => { + setTitle(""); + }) + .catch(console.error); + } + }; + + return ( + + + Shuffle Demo + + + + Random selection and shuffled music playlists with O(log(n)) random + access + + + {/* Add Music Section */} + + + + Add New Music + + + setTitle(e.target.value)} + placeholder="Enter song title" + style={{ flex: 1 }} + /> + + + + + + {/* Random Selection Section */} + + + + Random Selection + + + + + Current Random Song + + + {randomMusic ?? "Loading..."} + + + + + + + + {/* Shuffled Playlist Section */} + + + + Shuffled Playlist + + + + setSeed(e.target.value)} + placeholder="Enter seed for shuffle" + style={{ flex: 1 }} + /> + + + + {shuffledMusic && shuffledMusic.length > 0 ? ( + + + {shuffledMusic.map((song, index) => ( + + {song} + + ))} + + + + + Page {currentPage} + + + + ) : ( + + Add some music to see the shuffled playlist! + + )} + + + + {/* Info Section */} + + + + How It Works + + + This demo uses Convex Aggregate with a null sort key to enable + efficient random access to any item in the collection. The aggregate + maintains the order of documents by their internal IDs, which are + effectively random. + + + Random selection uses the aggregate's random() method to pick any + item in O(log(n)) time. The shuffled playlist uses a seeded random + number generator to create a deterministic shuffle that can be + paginated through. + + + Changing the seed creates a completely different shuffle order, + while keeping the same seed ensures consistent pagination through + the shuffled list. + + + + + ); +} diff --git a/example/src/pages/StatsPage.tsx b/example/src/pages/StatsPage.tsx new file mode 100644 index 0000000..032400b --- /dev/null +++ b/example/src/pages/StatsPage.tsx @@ -0,0 +1,179 @@ +import { useMutation, useQuery } from "convex/react"; +import { api } from "../../convex/_generated/api"; +import { + Title, + Text, + Card, + Stack, + Group, + NumberInput, + Button, + Alert, +} from "@mantine/core"; +import { useState } from "react"; + +export function StatsPage() { + const [latency, setLatency] = useState(""); + + // Queries + const stats = useQuery(api.stats.getStats); + + // Mutations + const reportLatency = useMutation(api.stats.reportLatency); + + const handleReportLatency = () => { + if (latency !== "") { + reportLatency({ latency: latency }) + .then(() => { + setLatency(""); + }) + .catch(console.error); + } + }; + + const handleLatencyChange = (value: number | string) => { + setLatency(value === "" ? "" : typeof value === "number" ? value : ""); + }; + + return ( + + + Stats Demo + + + + Direct aggregation without table dependencies - perfect for analytics + and metrics + + + {/* Add Latency Section */} + + + + Report Latency + + + + + + + + + {/* Statistics Display */} + + + + Latency Statistics + + + {stats ? ( + + + + + Mean + + + {stats.mean.toFixed(2)} ms + + + + + + + Median + + + {stats.median.toFixed(2)} ms + + + + + + + 75th Percentile + + + {stats.p75.toFixed(2)} ms + + + + + + + 95th Percentile + + + {stats.p95.toFixed(2)} ms + + + + + + + Min + + + {stats.min.toFixed(2)} ms + + + + + + + Max + + + {stats.max.toFixed(2)} ms + + + + + ) : ( + + Report some latency values to see the statistics! + + )} + + + + {/* Info Section */} + + + + How It Works + + + This demo uses DirectAggregate, which allows you to aggregate data + that isn't stored in a Convex table. This is perfect for analytics, + metrics, and temporary data that you want to aggregate efficiently. + + + Unlike TableAggregate, DirectAggregate gives you full control over + when data is inserted, updated, or deleted. You handle all the + operations yourself, making it ideal for complex aggregation + scenarios. + + + The aggregate still provides O(log(n)) performance for counting, + summing, and finding min/max values, but without the automatic table + synchronization. + + + + + ); +} From 8f2c3280a1223aace7deb8e92aa4fb569028d21e Mon Sep 17 00:00:00 2001 From: Mike Cann Date: Fri, 1 Aug 2025 11:44:09 +0800 Subject: [PATCH 07/77] wip example ui --- example/convex/leaderboard.ts | 11 ++----- example/convex/photos.ts | 4 +-- example/convex/shuffle.ts | 11 +++---- example/convex/stats.ts | 5 ++- example/src/App.tsx | 60 ++++++++++++++++------------------- example/src/main.tsx | 5 ++- example/src/routes.ts | 9 ++++++ example/src/utils/utils.ts | 6 ++++ example/tsconfig.app.json | 4 +-- 9 files changed, 60 insertions(+), 55 deletions(-) create mode 100644 example/src/routes.ts create mode 100644 example/src/utils/utils.ts diff --git a/example/convex/leaderboard.ts b/example/convex/leaderboard.ts index e4e33d0..da41055 100644 --- a/example/convex/leaderboard.ts +++ b/example/convex/leaderboard.ts @@ -53,7 +53,7 @@ export const clearAggregates = internalMutation({ // to backfill aggregates for existing leaderboard entries, if you created the // leaderboard before adding the aggregate components. export const runAggregateBackfill = migrations.runner( - internal.leaderboard.backfillAggregatesMigration, + internal.leaderboard.backfillAggregatesMigration ); export const addScore = mutation({ @@ -142,9 +142,7 @@ export const userAverageScore = query({ const count = await aggregateScoreByUser.count(ctx, { bounds: { prefix: [args.name] }, }); - if (!count) { - throw new ConvexError("no scores for " + args.name); - } + if (!count) return null; const sum = await aggregateScoreByUser.sum(ctx, { bounds: { prefix: [args.name] }, }); @@ -156,14 +154,11 @@ export const userHighScore = query({ args: { name: v.string(), }, - returns: v.number(), handler: async (ctx, args) => { const item = await aggregateScoreByUser.max(ctx, { bounds: { prefix: [args.name] }, }); - if (!item) { - throw new ConvexError("no scores for " + args.name); - } + if (!item) return null; return item.sumValue; }, }); diff --git a/example/convex/photos.ts b/example/convex/photos.ts index 6da56f5..632343c 100644 --- a/example/convex/photos.ts +++ b/example/convex/photos.ts @@ -39,7 +39,7 @@ triggers.register("photos", photos.trigger()); const mutation = customMutation(rawMutation, customCtx(triggers.wrapDB)); const internalMutation = customMutation( rawInternalMutation, - customCtx(triggers.wrapDB), + customCtx(triggers.wrapDB) ); export const init = internalMutation({ @@ -84,7 +84,7 @@ export const pageOfPhotos = query({ const photoDocs = await ctx.db .query("photos") .withIndex("by_album_creation_time", (q) => - q.eq("album", album).gte("_creationTime", firstPhotoCreationTime), + q.eq("album", album).gte("_creationTime", firstPhotoCreationTime) ) .take(numItems); return photoDocs.map((doc) => doc.url); diff --git a/example/convex/shuffle.ts b/example/convex/shuffle.ts index f708f93..82d12f5 100644 --- a/example/convex/shuffle.ts +++ b/example/convex/shuffle.ts @@ -7,7 +7,7 @@ import { TableAggregate } from "@convex-dev/aggregate"; import { mutation, query } from "../../example/convex/_generated/server"; import { components } from "../../example/convex/_generated/api"; import { DataModel } from "../../example/convex/_generated/dataModel"; -import { ConvexError, v } from "convex/values"; +import { v } from "convex/values"; import Rand from "rand-seed"; const randomize = new TableAggregate<{ @@ -46,12 +46,9 @@ export const getRandomMusicTitle = query({ args: { cacheBuster: v.optional(v.number()), }, - returns: v.string(), handler: async (ctx) => { const randomMusic = await randomize.random(ctx); - if (!randomMusic) { - throw new ConvexError("no music"); - } + if (!randomMusic) return null; const doc = (await ctx.db.get(randomMusic.id))!; return doc.title; }, @@ -99,14 +96,14 @@ export const shufflePaginated = query({ const indexes = allIndexes.slice(offset, offset + numItems); const atIndexes = await Promise.all( - indexes.map((i) => randomize.at(ctx, i)), + indexes.map((i) => randomize.at(ctx, i)) ); return await Promise.all( atIndexes.map(async (atIndex) => { const doc = (await ctx.db.get(atIndex.id))!; return doc.title; - }), + }) ); }, }); diff --git a/example/convex/stats.ts b/example/convex/stats.ts index 4a02f4a..b196011 100644 --- a/example/convex/stats.ts +++ b/example/convex/stats.ts @@ -30,9 +30,8 @@ export const getStats = query({ args: {}, handler: async (ctx) => { const count = await stats.count(ctx); - if (count === 0) { - throw new Error("No data"); - } + if (count === 0) return null; + const mean = (await stats.sum(ctx)) / count; const median = (await stats.at(ctx, Math.floor(count / 2))).key; const p75 = (await stats.at(ctx, Math.floor(count * 0.75))).key; diff --git a/example/src/App.tsx b/example/src/App.tsx index d4bcd4c..da68188 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -6,34 +6,16 @@ import { Group, Stack, } from "@mantine/core"; -import { useState } from "react"; import { HomePage } from "./pages/HomePage"; import { LeaderboardPage } from "./pages/LeaderboardPage"; import { PhotosPage } from "./pages/PhotosPage"; import { ShufflePage } from "./pages/ShufflePage"; import { StatsPage } from "./pages/StatsPage"; - -type Page = "home" | "leaderboard" | "photos" | "shuffle" | "stats"; +import { routes, useRoute } from "./routes"; +import { exhaustiveCheck } from "./utils/utils"; export default function App() { - const [currentPage, setCurrentPage] = useState("home"); - - const renderPage = () => { - switch (currentPage) { - case "home": - return ; - case "leaderboard": - return ; - case "photos": - return ; - case "shuffle": - return ; - case "stats": - return ; - default: - return ; - } - }; + const route = useRoute(); return ( @@ -49,32 +31,32 @@ export default function App() { setCurrentPage("home")} + active={route.name === "home"} + onClick={() => routes.home().push()} c="white" /> setCurrentPage("leaderboard")} + active={route.name === "leaderboard"} + onClick={() => routes.leaderboard().push()} c="white" /> setCurrentPage("photos")} + active={route.name === "photos"} + onClick={() => routes.photos().push()} c="white" /> setCurrentPage("shuffle")} + active={route.name === "shuffle"} + onClick={() => routes.shuffle().push()} c="white" /> setCurrentPage("stats")} + active={route.name === "stats"} + onClick={() => routes.stats().push()} c="white" /> @@ -82,9 +64,23 @@ export default function App() { - {renderPage()} + ); } + +function Routes() { + const route = useRoute(); + + if (route.name === "home") return ; + if (route.name === "leaderboard") return ; + if (route.name === "photos") return ; + if (route.name === "shuffle") return ; + if (route.name === "stats") return ; + + if (route.name == false) return ; + + exhaustiveCheck(route); +} diff --git a/example/src/main.tsx b/example/src/main.tsx index eb7ed0e..701e2aa 100644 --- a/example/src/main.tsx +++ b/example/src/main.tsx @@ -4,6 +4,7 @@ import { ConvexProvider, ConvexReactClient } from "convex/react"; import { MantineProvider } from "@mantine/core"; import "./index.css"; import App from "./App.tsx"; +import { RouteProvider } from "./routes.ts"; const convex = new ConvexReactClient(import.meta.env.VITE_CONVEX_URL as string); createRoot(document.getElementById("root")!).render( @@ -27,7 +28,9 @@ createRoot(document.getElementById("root")!).render( }} > - + + +
diff --git a/example/src/routes.ts b/example/src/routes.ts new file mode 100644 index 0000000..babe175 --- /dev/null +++ b/example/src/routes.ts @@ -0,0 +1,9 @@ +import { createRouter, defineRoute } from "type-route"; + +export const { RouteProvider, useRoute, routes } = createRouter({ + home: defineRoute("/"), + leaderboard: defineRoute("/leaderboard"), + photos: defineRoute("/photos"), + shuffle: defineRoute("/shuffle"), + stats: defineRoute("/stats"), +}); diff --git a/example/src/utils/utils.ts b/example/src/utils/utils.ts new file mode 100644 index 0000000..db61b34 --- /dev/null +++ b/example/src/utils/utils.ts @@ -0,0 +1,6 @@ +export function exhaustiveCheck(param: never): never { + // eslint-disable-next-line @typescript-eslint/restrict-template-expressions + throw new Error(`Exhaustive check failed: ${param}`); +} + +export const iife = (fn: () => T): T => fn(); diff --git a/example/tsconfig.app.json b/example/tsconfig.app.json index 8267e1f..52336d7 100644 --- a/example/tsconfig.app.json +++ b/example/tsconfig.app.json @@ -17,8 +17,8 @@ /* Linting */ "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, + "noUnusedLocals": false, + "noUnusedParameters": false, "noFallthroughCasesInSwitch": true, "noUncheckedSideEffectImports": true, From 3b01e654be791f3c3430b63cfa2c222b610186fd Mon Sep 17 00:00:00 2001 From: Mike Cann Date: Fri, 1 Aug 2025 11:52:48 +0800 Subject: [PATCH 08/77] fixing error in this example --- example/convex/photos.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/example/convex/photos.ts b/example/convex/photos.ts index 632343c..a2f756d 100644 --- a/example/convex/photos.ts +++ b/example/convex/photos.ts @@ -78,6 +78,13 @@ export const pageOfPhotos = query({ }, returns: v.array(v.string()), handler: async (ctx, { offset, numItems, album }) => { + // Check if the album has any photos first + const firstPhoto = await ctx.db + .query("photos") + .withIndex("by_album_creation_time", (q) => q.eq("album", album)) + .first(); + if (!firstPhoto) return []; + const { key: firstPhotoCreationTime } = await photos.at(ctx, offset, { namespace: album, }); From 3b7eae2ff0acfad73684c7df8ff161e96c391a3c Mon Sep 17 00:00:00 2001 From: Mike Cann Date: Fri, 1 Aug 2025 11:55:45 +0800 Subject: [PATCH 09/77] wip design --- example/src/App.tsx | 17 +++++++++++++---- example/src/pages/PhotosPage.tsx | 17 ++++++++++------- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/example/src/App.tsx b/example/src/App.tsx index da68188..7830182 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -18,7 +18,12 @@ export default function App() { const route = useRoute(); return ( - + @@ -27,7 +32,7 @@ export default function App() { - + - + - + diff --git a/example/src/pages/PhotosPage.tsx b/example/src/pages/PhotosPage.tsx index 8e10190..bf35005 100644 --- a/example/src/pages/PhotosPage.tsx +++ b/example/src/pages/PhotosPage.tsx @@ -11,6 +11,7 @@ import { Image, Pagination, Alert, + SimpleGrid, } from "@mantine/core"; import { useState } from "react"; @@ -58,29 +59,28 @@ export function PhotosPage() { Add New Photo - + setAlbum(e.target.value)} placeholder="Enter album name" - style={{ flex: 1 }} /> setUrl(e.target.value)} placeholder="Enter photo URL" - style={{ flex: 1 }} /> - + @@ -93,9 +93,12 @@ export function PhotosPage() { {photos && photos.length > 0 ? ( - + {photos.map((photoUrl, index) => ( - + {`Photo ))} - + Date: Fri, 1 Aug 2025 12:00:26 +0800 Subject: [PATCH 10/77] added some nicer styling --- example/package-lock.json | 27 ++++++++++++++++ example/package.json | 1 + example/src/App.tsx | 12 +++++++ example/src/main.tsx | 38 +++++++++++----------- example/src/pages/HomePage.tsx | 52 ++++++++++++++++++++++--------- example/src/pages/PhotosPage.tsx | 10 ++++-- example/src/pages/ShufflePage.tsx | 19 +++++++---- 7 files changed, 116 insertions(+), 43 deletions(-) diff --git a/example/package-lock.json b/example/package-lock.json index eeba1b1..2c85617 100644 --- a/example/package-lock.json +++ b/example/package-lock.json @@ -15,6 +15,7 @@ "@mantine/core": "^8.2.2", "@mantine/emotion": "^8.2.2", "@mantine/hooks": "^8.2.2", + "@tabler/icons-react": "^3.34.1", "convex": "^1.17.0", "convex-helpers": "^0.1.61", "rand-seed": "^2.1.7", @@ -1600,6 +1601,32 @@ "win32" ] }, + "node_modules/@tabler/icons": { + "version": "3.34.1", + "resolved": "https://registry.npmjs.org/@tabler/icons/-/icons-3.34.1.tgz", + "integrity": "sha512-9gTnUvd7Fd/DmQgr3MKY+oJLa1RfNsQo8c/ir3TJAWghOuZXodbtbVp0QBY2DxWuuvrSZFys0HEbv1CoiI5y6A==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/codecalm" + } + }, + "node_modules/@tabler/icons-react": { + "version": "3.34.1", + "resolved": "https://registry.npmjs.org/@tabler/icons-react/-/icons-react-3.34.1.tgz", + "integrity": "sha512-Ld6g0NqOO05kyyHsfU8h787PdHBm7cFmOycQSIrGp45XcXYDuOK2Bs0VC4T2FWSKZ6bx5g04imfzazf/nqtk1A==", + "license": "MIT", + "dependencies": { + "@tabler/icons": "3.34.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/codecalm" + }, + "peerDependencies": { + "react": ">= 16" + } + }, "node_modules/@types/babel__core": { "version": "7.20.5", "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", diff --git a/example/package.json b/example/package.json index bf227cb..4345523 100644 --- a/example/package.json +++ b/example/package.json @@ -21,6 +21,7 @@ "@mantine/core": "^8.2.2", "@mantine/emotion": "^8.2.2", "@mantine/hooks": "^8.2.2", + "@tabler/icons-react": "^3.34.1", "convex": "^1.17.0", "convex-helpers": "^0.1.61", "rand-seed": "^2.1.7", diff --git a/example/src/App.tsx b/example/src/App.tsx index 7830182..ebbffdc 100644 --- a/example/src/App.tsx +++ b/example/src/App.tsx @@ -6,6 +6,13 @@ import { Group, Stack, } from "@mantine/core"; +import { + IconHome, + IconTrophy, + IconPhoto, + IconArrowsShuffle, + IconChartPie, +} from "@tabler/icons-react"; import { HomePage } from "./pages/HomePage"; import { LeaderboardPage } from "./pages/LeaderboardPage"; import { PhotosPage } from "./pages/PhotosPage"; @@ -36,30 +43,35 @@ export default function App() { } active={route.name === "home"} onClick={() => routes.home().push()} c="white" /> } active={route.name === "leaderboard"} onClick={() => routes.leaderboard().push()} c="white" /> } active={route.name === "photos"} onClick={() => routes.photos().push()} c="white" /> } active={route.name === "shuffle"} onClick={() => routes.shuffle().push()} c="white" /> } active={route.name === "stats"} onClick={() => routes.stats().push()} c="white" diff --git a/example/src/main.tsx b/example/src/main.tsx index 701e2aa..aa946da 100644 --- a/example/src/main.tsx +++ b/example/src/main.tsx @@ -1,32 +1,32 @@ import { StrictMode } from "react"; import { createRoot } from "react-dom/client"; import { ConvexProvider, ConvexReactClient } from "convex/react"; -import { MantineProvider } from "@mantine/core"; +import { MantineProvider, createTheme } from "@mantine/core"; import "./index.css"; import App from "./App.tsx"; import { RouteProvider } from "./routes.ts"; +const theme = createTheme({ + colors: { + dark: [ + "#C1C2C5", + "#A6A7AB", + "#909296", + "#5C5F66", + "#373A40", + "#2C2E33", + "#25262B", + "#1A1B1E", + "#141517", + "#101113", + ], + }, +}); + const convex = new ConvexReactClient(import.meta.env.VITE_CONVEX_URL as string); createRoot(document.getElementById("root")!).render( - + diff --git a/example/src/pages/HomePage.tsx b/example/src/pages/HomePage.tsx index 379c3c3..fcebaec 100644 --- a/example/src/pages/HomePage.tsx +++ b/example/src/pages/HomePage.tsx @@ -1,11 +1,21 @@ import { Title, Text, Card, Stack, Group, Badge } from "@mantine/core"; +import { + IconHome, + IconTrophy, + IconPhoto, + IconArrowsShuffle, + IconChartPie, +} from "@tabler/icons-react"; export function HomePage() { return ( - - Convex Aggregate Demo - + + + + Convex Aggregate Demo + + Explore the power of Convex Aggregate component with these interactive @@ -15,9 +25,12 @@ export function HomePage() { - - Leaderboard - + + + + Leaderboard + + Game scores with rankings, averages, and user statistics @@ -27,9 +40,12 @@ export function HomePage() { - - Photos - + + + + Photos + + Offset-based pagination for photo galleries @@ -39,9 +55,12 @@ export function HomePage() { - - Shuffle - + + + + Shuffle + + Random selection and shuffled music playlists @@ -51,9 +70,12 @@ export function HomePage() { - - Stats - + + + + Stats + + Direct aggregation without table dependencies diff --git a/example/src/pages/PhotosPage.tsx b/example/src/pages/PhotosPage.tsx index bf35005..f14d7a4 100644 --- a/example/src/pages/PhotosPage.tsx +++ b/example/src/pages/PhotosPage.tsx @@ -13,6 +13,7 @@ import { Alert, SimpleGrid, } from "@mantine/core"; +import { IconPhoto } from "@tabler/icons-react"; import { useState } from "react"; export function PhotosPage() { @@ -44,9 +45,12 @@ export function PhotosPage() { return ( - - Photos Demo - + + + + Photos Demo + + Offset-based pagination for photo galleries with efficient O(log(n)) diff --git a/example/src/pages/ShufflePage.tsx b/example/src/pages/ShufflePage.tsx index a627758..cc61d1e 100644 --- a/example/src/pages/ShufflePage.tsx +++ b/example/src/pages/ShufflePage.tsx @@ -12,6 +12,7 @@ import { Alert, List, } from "@mantine/core"; +import { IconArrowsShuffle, IconMusic } from "@tabler/icons-react"; import { useState } from "react"; export function ShufflePage() { @@ -45,9 +46,12 @@ export function ShufflePage() { return ( - - Shuffle Demo - + + + + Shuffle Demo + + Random selection and shuffled music playlists with O(log(n)) random @@ -57,9 +61,12 @@ export function ShufflePage() { {/* Add Music Section */} - - Add New Music - + + + + Add New Music + + Date: Fri, 1 Aug 2025 12:04:35 +0800 Subject: [PATCH 11/77] wip --- example/convex/leaderboard.ts | 23 +++++--- example/eslint.config.js | 77 --------------------------- example/src/pages/LeaderboardPage.tsx | 61 +++++++++++++-------- example/src/pages/StatsPage.tsx | 10 ++-- 4 files changed, 63 insertions(+), 108 deletions(-) delete mode 100644 example/eslint.config.js diff --git a/example/convex/leaderboard.ts b/example/convex/leaderboard.ts index da41055..bb092cb 100644 --- a/example/convex/leaderboard.ts +++ b/example/convex/leaderboard.ts @@ -10,7 +10,7 @@ import { } from "../../example/convex/_generated/server"; import { components, internal } from "../../example/convex/_generated/api"; import { DataModel } from "../../example/convex/_generated/dataModel"; -import { ConvexError, v } from "convex/values"; +import { v } from "convex/values"; import { Migrations } from "@convex-dev/migrations"; export const migrations = new Migrations(components.migrations); @@ -103,22 +103,33 @@ export const scoreAtRank = query({ }); export const scoresInOrder = query({ + returns: v.array( + v.union( + v.object({ + _id: v.id("leaderboard"), + name: v.string(), + score: v.number(), + _creationTime: v.number(), + }), + v.string() + ) + ), handler: async (ctx) => { let count = 0; - const lines = []; - for await (const { id, key } of aggregateByScore.iter(ctx, { + const scores = []; + for await (const { id, key: _key } of aggregateByScore.iter(ctx, { bounds: undefined, order: "desc", })) { if (count >= 200) { - lines.push("..."); + scores.push("..."); break; } const doc = (await ctx.db.get(id))!; - lines.push(`${doc.name}: ${key}`); + scores.push(doc); count += 1; } - return lines; + return scores; }, }); diff --git a/example/eslint.config.js b/example/eslint.config.js deleted file mode 100644 index dc2e219..0000000 --- a/example/eslint.config.js +++ /dev/null @@ -1,77 +0,0 @@ -import js from "@eslint/js"; -import globals from "globals"; -import reactHooks from "eslint-plugin-react-hooks"; -import reactRefresh from "eslint-plugin-react-refresh"; -import tseslint from "typescript-eslint"; - -export default tseslint.config( - { - ignores: [ - "dist", - "eslint.config.js", - "convex/_generated", - "postcss.config.js", - "tailwind.config.js", - "vite.config.ts", - ], - }, - { - extends: [ - js.configs.recommended, - ...tseslint.configs.recommendedTypeChecked, - ], - files: ["**/*.{ts,tsx}"], - languageOptions: { - ecmaVersion: 2020, - globals: { - ...globals.browser, - ...globals.node, - }, - parserOptions: { - project: [ - "./tsconfig.node.json", - "./tsconfig.app.json", - "./convex/tsconfig.json", - ], - }, - }, - plugins: { - "react-hooks": reactHooks, - "react-refresh": reactRefresh, - }, - rules: { - ...reactHooks.configs.recommended.rules, - "react-refresh/only-export-components": [ - "warn", - { allowConstantExport: true }, - ], - // All of these overrides ease getting into - // TypeScript, and can be removed for stricter - // linting down the line. - - // Only warn on unused variables, and ignore variables starting with `_` - "@typescript-eslint/no-unused-vars": [ - "warn", - { varsIgnorePattern: "^_", argsIgnorePattern: "^_" }, - ], - - // Allow escaping the compiler - "@typescript-eslint/ban-ts-comment": "error", - - // Allow explicit `any`s - "@typescript-eslint/no-explicit-any": "off", - - // START: Allow implicit `any`s - "@typescript-eslint/no-unsafe-argument": "off", - "@typescript-eslint/no-unsafe-assignment": "off", - "@typescript-eslint/no-unsafe-call": "off", - "@typescript-eslint/no-unsafe-member-access": "off", - "@typescript-eslint/no-unsafe-return": "off", - // END: Allow implicit `any`s - - // Allow async functions without await - // for consistency (esp. Convex `handler`s) - "@typescript-eslint/require-await": "off", - }, - }, -); diff --git a/example/src/pages/LeaderboardPage.tsx b/example/src/pages/LeaderboardPage.tsx index 9e809e4..e9a0892 100644 --- a/example/src/pages/LeaderboardPage.tsx +++ b/example/src/pages/LeaderboardPage.tsx @@ -13,6 +13,7 @@ import { Badge, Alert, } from "@mantine/core"; +import { IconTrophy } from "@tabler/icons-react"; import { useState } from "react"; export function LeaderboardPage() { @@ -55,9 +56,7 @@ export function LeaderboardPage() { } }; - const handleRemoveScore = (id: string) => { - removeScore({ id: id as any }).catch(console.error); - }; + const handleRemoveScore = (id: string) => {}; const handleScoreChange = (value: number | string) => { setScore(value === "" ? "" : (value as number)); @@ -69,9 +68,12 @@ export function LeaderboardPage() { return ( - - Leaderboard Demo - + + + + Leaderboard Demo + + Add scores and explore aggregation features like rankings, averages, and @@ -216,22 +218,37 @@ export function LeaderboardPage() { - {scores.map((score, index) => ( - - {index + 1} - {score.split(": ")[0]} - {score.split(": ")[1]} - - - - - ))} + {scores.map((score, index) => { + // Handle the "..." truncation string case + if (typeof score === "string") { + return ( + + + {score} + + + ); + } + + return ( + + {index + 1} + {score.name} + {score.score} + + + + + ); + })} ) : ( diff --git a/example/src/pages/StatsPage.tsx b/example/src/pages/StatsPage.tsx index 032400b..041f85c 100644 --- a/example/src/pages/StatsPage.tsx +++ b/example/src/pages/StatsPage.tsx @@ -10,6 +10,7 @@ import { Button, Alert, } from "@mantine/core"; +import { IconChartPie } from "@tabler/icons-react"; import { useState } from "react"; export function StatsPage() { @@ -37,9 +38,12 @@ export function StatsPage() { return ( - - Stats Demo - + + + + Stats Demo + + Direct aggregation without table dependencies - perfect for analytics From 7295039c1d61db96f9f27f681f09da042f59d769 Mon Sep 17 00:00:00 2001 From: Mike Cann Date: Fri, 1 Aug 2025 12:23:10 +0800 Subject: [PATCH 12/77] tidy --- example/eslint.config.js | 78 +++++++++++++++++++++++++++ example/src/pages/LeaderboardPage.tsx | 43 ++++++--------- example/src/pages/PhotosPage.tsx | 24 ++++----- example/src/pages/ShufflePage.tsx | 22 ++++---- example/src/pages/StatsPage.tsx | 32 +++++------ 5 files changed, 127 insertions(+), 72 deletions(-) create mode 100644 example/eslint.config.js diff --git a/example/eslint.config.js b/example/eslint.config.js new file mode 100644 index 0000000..228e490 --- /dev/null +++ b/example/eslint.config.js @@ -0,0 +1,78 @@ +@ -1,77 +0,0 @@ +import js from "@eslint/js"; +import globals from "globals"; +import reactHooks from "eslint-plugin-react-hooks"; +import reactRefresh from "eslint-plugin-react-refresh"; +import tseslint from "typescript-eslint"; + +export default tseslint.config( + { + ignores: [ + "dist", + "eslint.config.js", + "convex/_generated", + "postcss.config.js", + "tailwind.config.js", + "vite.config.ts", + ], + }, + { + extends: [ + js.configs.recommended, + ...tseslint.configs.recommendedTypeChecked, + ], + files: ["**/*.{ts,tsx}"], + languageOptions: { + ecmaVersion: 2020, + globals: { + ...globals.browser, + ...globals.node, + }, + parserOptions: { + project: [ + "./tsconfig.node.json", + "./tsconfig.app.json", + "./convex/tsconfig.json", + ], + }, + }, + plugins: { + "react-hooks": reactHooks, + "react-refresh": reactRefresh, + }, + rules: { + ...reactHooks.configs.recommended.rules, + "react-refresh/only-export-components": [ + "warn", + { allowConstantExport: true }, + ], + // All of these overrides ease getting into + // TypeScript, and can be removed for stricter + // linting down the line. + + // Only warn on unused variables, and ignore variables starting with `_` + "@typescript-eslint/no-unused-vars": [ + "warn", + { varsIgnorePattern: "^_", argsIgnorePattern: "^_" }, + ], + + // Allow escaping the compiler + "@typescript-eslint/ban-ts-comment": "error", + + // Allow explicit `any`s + "@typescript-eslint/no-explicit-any": "off", + + // START: Allow implicit `any`s + "@typescript-eslint/no-unsafe-argument": "off", + "@typescript-eslint/no-unsafe-assignment": "off", + "@typescript-eslint/no-unsafe-call": "off", + "@typescript-eslint/no-unsafe-member-access": "off", + "@typescript-eslint/no-unsafe-return": "off", + // END: Allow implicit `any`s + + // Allow async functions without await + // for consistency (esp. Convex `handler`s) + "@typescript-eslint/require-await": "off", + }, + }, +); \ No newline at end of file diff --git a/example/src/pages/LeaderboardPage.tsx b/example/src/pages/LeaderboardPage.tsx index e9a0892..ee20412 100644 --- a/example/src/pages/LeaderboardPage.tsx +++ b/example/src/pages/LeaderboardPage.tsx @@ -22,16 +22,13 @@ export function LeaderboardPage() { const [searchScore, setSearchScore] = useState(""); const [searchPlayer, setSearchPlayer] = useState(""); - // Queries const scores = useQuery(api.leaderboard.scoresInOrder); const totalCount = useQuery(api.leaderboard.countScores); const totalSum = useQuery(api.leaderboard.sumNumbers); - // Mutations const addScore = useMutation(api.leaderboard.addScore); const removeScore = useMutation(api.leaderboard.removeScore); - // Computed queries const rankOfScore = useQuery( api.leaderboard.rankOfScore, searchScore !== "" ? { score: searchScore } : "skip" @@ -45,27 +42,6 @@ export function LeaderboardPage() { searchPlayer ? { name: searchPlayer } : "skip" ); - const handleAddScore = () => { - if (playerName && score !== "") { - addScore({ name: playerName, score: score }) - .then(() => { - setPlayerName(""); - setScore(""); - }) - .catch(console.error); - } - }; - - const handleRemoveScore = (id: string) => {}; - - const handleScoreChange = (value: number | string) => { - setScore(value === "" ? "" : (value as number)); - }; - - const handleSearchScoreChange = (value: number | string) => { - setSearchScore(value === "" ? "" : (value as number)); - }; - return ( @@ -97,13 +73,24 @@ export function LeaderboardPage() { + setScore(value === "" ? "" : (value as number)) + } placeholder="Enter score" min={0} style={{ flex: 1 }} /> diff --git a/example/src/utils/errors.ts b/example/src/utils/errors.ts new file mode 100644 index 0000000..4154a7c --- /dev/null +++ b/example/src/utils/errors.ts @@ -0,0 +1,31 @@ +import { useCallback } from "react"; +import { notifications } from "@mantine/notifications"; +import { iife } from "./utils"; + +export const useApiErrorHandler = () => { + return useCallback((error: any, title?: string) => { + const message = iife(() => { + if (error && typeof error === "object") { + if ("message" in error && typeof error.message === "string") { + return error.message; + } else if ( + "error" in error && + typeof error.error === "object" && + error.error && + "message" in error.error && + typeof error.error.message === "string" + ) { + return error.error.message; + } + } + return "An unexpected error occurred"; + }); + + console.error(`APIError${title ? `from ${title}` : ""}: `, message); + notifications.show({ + title: "Error", + message, + color: "red", + }); + }, []); +}; From 46c243a3f06f3d51c43d23aefc7c44b3fce2d6cb Mon Sep 17 00:00:00 2001 From: Mike Cann Date: Fri, 1 Aug 2025 14:44:15 +0800 Subject: [PATCH 17/77] wip resetting --- example/convex/_generated/api.d.ts | 2 + example/convex/crons.ts | 98 +++++++++++++++++++++++++++ example/convex/leaderboard.ts | 70 +++++++++++++++++++ example/convex/photos.ts | 23 +++++++ example/convex/shuffle.ts | 26 ++++++- example/convex/stats.ts | 20 +++++- example/src/pages/LeaderboardPage.tsx | 17 +++++ 7 files changed, 254 insertions(+), 2 deletions(-) create mode 100644 example/convex/crons.ts diff --git a/example/convex/_generated/api.d.ts b/example/convex/_generated/api.d.ts index 28d8916..c3f33ed 100644 --- a/example/convex/_generated/api.d.ts +++ b/example/convex/_generated/api.d.ts @@ -8,6 +8,7 @@ * @module */ +import type * as crons from "../crons.js"; import type * as leaderboard from "../leaderboard.js"; import type * as photos from "../photos.js"; import type * as shuffle from "../shuffle.js"; @@ -28,6 +29,7 @@ import type { * ``` */ declare const fullApi: ApiFromModules<{ + crons: typeof crons; leaderboard: typeof leaderboard; photos: typeof photos; shuffle: typeof shuffle; diff --git a/example/convex/crons.ts b/example/convex/crons.ts new file mode 100644 index 0000000..72d9da1 --- /dev/null +++ b/example/convex/crons.ts @@ -0,0 +1,98 @@ +import { cronJobs } from "convex/server"; +import { api, internal } from "./_generated/api"; +import { internalAction, internalMutation } from "./_generated/server"; +import { v } from "convex/values"; + +export const resetAllData = internalMutation({ + args: {}, + returns: v.null(), + handler: async (ctx) => { + await ctx.runMutation(internal.leaderboard.resetLeaderboard); + await ctx.runMutation(internal.photos.resetPhotos); + await ctx.runMutation(internal.shuffle.resetShuffle); + await ctx.runMutation(internal.stats.resetStats); + + await ctx.runMutation(internal.crons.seedInitialData); + + return null; + }, +}); + +/** + * Seed some initial data after reset. + * This directly inserts data since aggregates have been cleared. + * The aggregates will be rebuilt through triggers when data is accessed. + */ +export const seedInitialData = internalMutation({ + args: {}, + returns: v.null(), + handler: async (ctx) => { + // Add some initial music directly + const initialMusic = [ + "Bohemian Rhapsody - Queen", + "Stairway to Heaven - Led Zeppelin", + "Hotel California - Eagles", + "Imagine - John Lennon", + "Sweet Child O' Mine - Guns N' Roses", + ]; + + for (const title of initialMusic) { + await ctx.db.insert("music", { title }); + } + + // Add some initial photos directly + const initialPhotos = [ + { + album: "Nature", + url: "https://images.unsplash.com/photo-1506905925346-21bda4d32df4", + }, + { + album: "Nature", + url: "https://images.unsplash.com/photo-1441974231531-c6227db76b6e", + }, + { + album: "Cities", + url: "https://images.unsplash.com/photo-1449824913935-59a10b8d2000", + }, + { + album: "Cities", + url: "https://images.unsplash.com/photo-1444723121867-7a241cacace9", + }, + { + album: "People", + url: "https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d", + }, + ]; + + for (const photo of initialPhotos) { + await ctx.db.insert("photos", photo); + } + + // Add a few initial leaderboard scores directly + const initialScores = [ + { name: "Demo Player", score: 1000 }, + { name: "Test User", score: 750 }, + { name: "Sample Gamer", score: 500 }, + ]; + + for (const score of initialScores) { + await ctx.db.insert("leaderboard", score); + } + + console.log("Initial data seeded - aggregates will rebuild when accessed"); + return null; + }, +}); + +// Create and configure the cron job +const crons = cronJobs(); + +// Run data reset every 24 hours (at midnight) +crons.interval( + "daily data reset", + { hours: 24 }, + internal.crons.resetAllData, + {} +); + +export default crons; diff --git a/example/convex/leaderboard.ts b/example/convex/leaderboard.ts index bb092cb..77dd41c 100644 --- a/example/convex/leaderboard.ts +++ b/example/convex/leaderboard.ts @@ -49,6 +49,27 @@ export const clearAggregates = internalMutation({ }, }); +export const resetLeaderboard = internalMutation({ + args: {}, + returns: v.null(), + handler: async (ctx) => { + console.log("Resetting leaderboard..."); + + // Clear table first to avoid race conditions + const leaderboardDocs = await ctx.db.query("leaderboard").collect(); + for (const doc of leaderboardDocs) { + await ctx.db.delete(doc._id); + } + + // Then clear aggregates + await aggregateByScore.clear(ctx); + await aggregateScoreByUser.clear(ctx); + + console.log("Leaderboard reset complete"); + return null; + }, +}); + // This is what you can run, from the Convex dashboard or with `npx convex run`, // to backfill aggregates for existing leaderboard entries, if you created the // leaderboard before adding the aggregate components. @@ -179,3 +200,52 @@ export const sumNumbers = query({ return await aggregateScoreByUser.sum(ctx); }, }); + +export const add100MockScores = mutation({ + args: {}, + returns: v.null(), + handler: async (ctx) => { + const playerNames = [ + "Alex", + "Jordan", + "Casey", + "Morgan", + "Riley", + "Avery", + "Quinn", + "Blake", + "Orion", + ]; + + const mockScores = []; + for (let i = 0; i < 100; i++) { + const randomName = + playerNames[Math.floor(Math.random() * playerNames.length)]; + // Generate scores with some variety - mostly between 100-1000, with some outliers + let score; + const rand = Math.random(); + if (rand < 0.1) { + // 10% chance for very high scores (1000-5000) + score = Math.floor(Math.random() * 4000) + 1000; + } else if (rand < 0.2) { + // 10% chance for low scores (10-100) + score = Math.floor(Math.random() * 90) + 10; + } else { + // 80% chance for normal scores (100-1000) + score = Math.floor(Math.random() * 900) + 100; + } + + mockScores.push({ name: randomName, score }); + } + + // Insert all scores and update aggregates + for (const mockScore of mockScores) { + const id = await ctx.db.insert("leaderboard", mockScore); + const doc = await ctx.db.get(id); + await aggregateByScore.insert(ctx, doc!); + await aggregateScoreByUser.insert(ctx, doc!); + } + + return null; + }, +}); diff --git a/example/convex/photos.ts b/example/convex/photos.ts index a2f756d..69f9bd2 100644 --- a/example/convex/photos.ts +++ b/example/convex/photos.ts @@ -55,6 +55,29 @@ export const init = internalMutation({ }, }); +export const resetPhotos = internalMutation({ + args: {}, + returns: v.null(), + handler: async (ctx) => { + console.log("Resetting photos..."); + + // Clear table first to avoid race conditions with queries + const photosDocs = await ctx.db.query("photos").collect(); + for (const doc of photosDocs) { + await ctx.db.delete(doc._id); + } + + // Then clear and reinitialize the aggregate + await photos.clearAll(ctx, { + maxNodeSize: 4, + rootLazy: false, + }); + + console.log("Photos reset complete"); + return null; + }, +}); + export const addPhoto = mutation({ args: { album: v.string(), diff --git a/example/convex/shuffle.ts b/example/convex/shuffle.ts index 82d12f5..8508c32 100644 --- a/example/convex/shuffle.ts +++ b/example/convex/shuffle.ts @@ -4,7 +4,11 @@ */ import { TableAggregate } from "@convex-dev/aggregate"; -import { mutation, query } from "../../example/convex/_generated/server"; +import { + mutation, + query, + internalMutation, +} from "../../example/convex/_generated/server"; import { components } from "../../example/convex/_generated/api"; import { DataModel } from "../../example/convex/_generated/dataModel"; import { v } from "convex/values"; @@ -42,6 +46,26 @@ export const removeMusic = mutation({ }, }); +export const resetShuffle = internalMutation({ + args: {}, + returns: v.null(), + handler: async (ctx) => { + console.log("Resetting shuffle/music..."); + + // Clear table first to avoid race conditions + const musicDocs = await ctx.db.query("music").collect(); + for (const doc of musicDocs) { + await ctx.db.delete(doc._id); + } + + // Then clear the aggregate + await randomize.clear(ctx); + + console.log("Shuffle/music reset complete"); + return null; + }, +}); + export const getRandomMusicTitle = query({ args: { cacheBuster: v.optional(v.number()), diff --git a/example/convex/stats.ts b/example/convex/stats.ts index b196011..7eb45ba 100644 --- a/example/convex/stats.ts +++ b/example/convex/stats.ts @@ -2,7 +2,11 @@ * Example of collecting statistics on data not tied to a Convex table. */ -import { mutation, query } from "../../example/convex/_generated/server"; +import { + mutation, + query, + internalMutation, +} from "../../example/convex/_generated/server"; import { v } from "convex/values"; import { DirectAggregate } from "@convex-dev/aggregate"; import { components } from "../../example/convex/_generated/api"; @@ -26,6 +30,20 @@ export const reportLatency = mutation({ }, }); +export const resetStats = internalMutation({ + args: {}, + returns: v.null(), + handler: async (ctx) => { + console.log("Resetting stats..."); + + // Clear the direct aggregate + await stats.clear(ctx); + + console.log("Stats reset complete"); + return null; + }, +}); + export const getStats = query({ args: {}, handler: async (ctx) => { diff --git a/example/src/pages/LeaderboardPage.tsx b/example/src/pages/LeaderboardPage.tsx index 8aaca5e..16b89e2 100644 --- a/example/src/pages/LeaderboardPage.tsx +++ b/example/src/pages/LeaderboardPage.tsx @@ -24,6 +24,7 @@ export function LeaderboardPage() { const [score, setScore] = useState(""); const [searchScore, setSearchScore] = useState(""); const [searchPlayer, setSearchPlayer] = useState(""); + const [isAddingMockScores, setIsAddingMockScores] = useState(false); const scores = useQuery(api.leaderboard.scoresInOrder); const totalCount = useQuery(api.leaderboard.countScores); @@ -31,6 +32,7 @@ export function LeaderboardPage() { const addScore = useMutation(api.leaderboard.addScore); const removeScore = useMutation(api.leaderboard.removeScore); + const addMockScores = useMutation(api.leaderboard.add100MockScores); const rankOfScore = useQuery( api.leaderboard.rankOfScore, @@ -99,6 +101,21 @@ export function LeaderboardPage() { > Add Score + From 451cbce7c9b8d75134efef6e4cc757b99931fa19 Mon Sep 17 00:00:00 2001 From: Mike Cann Date: Fri, 1 Aug 2025 15:09:28 +0800 Subject: [PATCH 18/77] clearing issue? --- example/convex/crons.ts | 101 ++++++++++++++++------------------ example/convex/leaderboard.ts | 25 ++++----- example/convex/photos.ts | 56 +++++++------------ example/convex/shuffle.ts | 23 +++++--- 4 files changed, 95 insertions(+), 110 deletions(-) diff --git a/example/convex/crons.ts b/example/convex/crons.ts index 72d9da1..8d37bea 100644 --- a/example/convex/crons.ts +++ b/example/convex/crons.ts @@ -2,18 +2,27 @@ import { cronJobs } from "convex/server"; import { api, internal } from "./_generated/api"; import { internalAction, internalMutation } from "./_generated/server"; import { v } from "convex/values"; +import { resetWithoutTriggers } from "./photos"; export const resetAllData = internalMutation({ args: {}, returns: v.null(), handler: async (ctx) => { - await ctx.runMutation(internal.leaderboard.resetLeaderboard); - await ctx.runMutation(internal.photos.resetPhotos); - await ctx.runMutation(internal.shuffle.resetShuffle); - await ctx.runMutation(internal.stats.resetStats); + console.log("Starting daily data reset..."); - await ctx.runMutation(internal.crons.seedInitialData); + await ctx.runMutation(internal.photos.resetWithoutTriggers); + // Reset all modules in parallel for better performance + // await Promise.all([ + // ctx.runMutation(internal.leaderboard.resetLeaderboard), + // ctx.runMutation(internal.shuffle.resetShuffle), + // ctx.runMutation(internal.stats.resetStats), + // ]); + + // // Seed some initial data + // await ctx.runMutation(internal.crons.seedInitialData); + + console.log("Daily data reset completed successfully!"); return null; }, }); @@ -27,57 +36,43 @@ export const seedInitialData = internalMutation({ args: {}, returns: v.null(), handler: async (ctx) => { - // Add some initial music directly - const initialMusic = [ - "Bohemian Rhapsody - Queen", - "Stairway to Heaven - Led Zeppelin", - "Hotel California - Eagles", - "Imagine - John Lennon", - "Sweet Child O' Mine - Guns N' Roses", - ]; - - for (const title of initialMusic) { - await ctx.db.insert("music", { title }); - } - - // Add some initial photos directly - const initialPhotos = [ - { - album: "Nature", - url: "https://images.unsplash.com/photo-1506905925346-21bda4d32df4", - }, - { - album: "Nature", - url: "https://images.unsplash.com/photo-1441974231531-c6227db76b6e", - }, - { - album: "Cities", - url: "https://images.unsplash.com/photo-1449824913935-59a10b8d2000", - }, - { - album: "Cities", - url: "https://images.unsplash.com/photo-1444723121867-7a241cacace9", - }, - { - album: "People", - url: "https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d", - }, - ]; + // await ctx.runMutation(internal.shuffle.addAllMusic, { + // titles: [ + // "Bohemian Rhapsody - Queen", + // "Stairway to Heaven - Led Zeppelin", + // "Hotel California - Eagles", + // "Imagine - John Lennon", + // "Sweet Child O' Mine - Guns N' Roses", + // ], + // }); - for (const photo of initialPhotos) { - await ctx.db.insert("photos", photo); - } + // // Add some initial photos directly + // const initialPhotos = [ + // { + // album: "Nature", + // url: "https://images.unsplash.com/photo-1506905925346-21bda4d32df4", + // }, + // { + // album: "Nature", + // url: "https://images.unsplash.com/photo-1441974231531-c6227db76b6e", + // }, + // { + // album: "Cities", + // url: "https://images.unsplash.com/photo-1449824913935-59a10b8d2000", + // }, + // { + // album: "Cities", + // url: "https://images.unsplash.com/photo-1444723121867-7a241cacace9", + // }, + // { + // album: "People", + // url: "https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d", + // }, + // ]; - // Add a few initial leaderboard scores directly - const initialScores = [ - { name: "Demo Player", score: 1000 }, - { name: "Test User", score: 750 }, - { name: "Sample Gamer", score: 500 }, - ]; + // for (const photo of initialPhotos) await ctx.db.insert("photos", photo); - for (const score of initialScores) { - await ctx.db.insert("leaderboard", score); - } + // await ctx.runMutation(api.leaderboard.add100MockScores); console.log("Initial data seeded - aggregates will rebuild when accessed"); return null; diff --git a/example/convex/leaderboard.ts b/example/convex/leaderboard.ts index 77dd41c..9cf6071 100644 --- a/example/convex/leaderboard.ts +++ b/example/convex/leaderboard.ts @@ -7,6 +7,7 @@ import { mutation, query, internalMutation, + MutationCtx, } from "../../example/convex/_generated/server"; import { components, internal } from "../../example/convex/_generated/api"; import { DataModel } from "../../example/convex/_generated/dataModel"; @@ -41,13 +42,12 @@ export const backfillAggregatesMigration = migrations.define({ }, }); -export const clearAggregates = internalMutation({ - args: {}, - handler: async (ctx) => { - await aggregateByScore.clear(ctx); - await aggregateScoreByUser.clear(ctx); - }, -}); +const _clearAggregates = async (ctx: MutationCtx) => { + await aggregateByScore.clear(ctx); + await aggregateScoreByUser.clear(ctx); +}; + +export const clearAggregates = internalMutation(_clearAggregates); export const resetLeaderboard = internalMutation({ args: {}, @@ -55,15 +55,12 @@ export const resetLeaderboard = internalMutation({ handler: async (ctx) => { console.log("Resetting leaderboard..."); - // Clear table first to avoid race conditions + // Clear docs const leaderboardDocs = await ctx.db.query("leaderboard").collect(); - for (const doc of leaderboardDocs) { - await ctx.db.delete(doc._id); - } + for (const doc of leaderboardDocs) await ctx.db.delete(doc._id); - // Then clear aggregates - await aggregateByScore.clear(ctx); - await aggregateScoreByUser.clear(ctx); + // Reset aggregate + await _clearAggregates(ctx); console.log("Leaderboard reset complete"); return null; diff --git a/example/convex/photos.ts b/example/convex/photos.ts index 69f9bd2..a013d36 100644 --- a/example/convex/photos.ts +++ b/example/convex/photos.ts @@ -37,47 +37,12 @@ const triggers = new Triggers(); triggers.register("photos", photos.trigger()); const mutation = customMutation(rawMutation, customCtx(triggers.wrapDB)); + const internalMutation = customMutation( rawInternalMutation, customCtx(triggers.wrapDB) ); -export const init = internalMutation({ - args: {}, - handler: async (ctx) => { - // rootLazy can be false because the table doesn't change much, and this - // makes aggregates faster (this is entirely optional). - // Also reducing node size uses less bandwidth, since nodes are smaller. - await photos.clearAll(ctx, { - maxNodeSize: 4, - rootLazy: false, - }); - }, -}); - -export const resetPhotos = internalMutation({ - args: {}, - returns: v.null(), - handler: async (ctx) => { - console.log("Resetting photos..."); - - // Clear table first to avoid race conditions with queries - const photosDocs = await ctx.db.query("photos").collect(); - for (const doc of photosDocs) { - await ctx.db.delete(doc._id); - } - - // Then clear and reinitialize the aggregate - await photos.clearAll(ctx, { - maxNodeSize: 4, - rootLazy: false, - }); - - console.log("Photos reset complete"); - return null; - }, -}); - export const addPhoto = mutation({ args: { album: v.string(), @@ -120,3 +85,22 @@ export const pageOfPhotos = query({ return photoDocs.map((doc) => doc.url); }, }); + +// ----- + +export const resetWithoutTriggers = rawInternalMutation({ + args: {}, + handler: async (ctx) => { + // Just delete table records - triggers will automatically keep aggregate in sync + const photosDocs = await ctx.db.query("photos").collect(); + for (const doc of photosDocs) await ctx.db.delete(doc._id); + + // rootLazy can be false because the table doesn't change much, and this + // makes aggregates faster (this is entirely optional). + // Also reducing node size uses less bandwidth, since nodes are smaller. + await photos.clearAll(ctx, { + maxNodeSize: 4, + rootLazy: false, + }); + }, +}); diff --git a/example/convex/shuffle.ts b/example/convex/shuffle.ts index 8508c32..02a8348 100644 --- a/example/convex/shuffle.ts +++ b/example/convex/shuffle.ts @@ -8,6 +8,7 @@ import { mutation, query, internalMutation, + MutationCtx, } from "../../example/convex/_generated/server"; import { components } from "../../example/convex/_generated/api"; import { DataModel } from "../../example/convex/_generated/dataModel"; @@ -22,16 +23,24 @@ const randomize = new TableAggregate<{ sortKey: () => null, }); +const _addMusic = async (ctx: MutationCtx, { title }: { title: string }) => { + const id = await ctx.db.insert("music", { title }); + const doc = (await ctx.db.get(id))!; + await randomize.insert(ctx, doc); + return id; +}; + export const addMusic = mutation({ + args: { title: v.string() }, + handler: _addMusic, +}); + +export const addAllMusic = internalMutation({ args: { - title: v.string(), + titles: v.array(v.string()), }, - returns: v.id("music"), - handler: async (ctx, args) => { - const id = await ctx.db.insert("music", { title: args.title }); - const doc = (await ctx.db.get(id))!; - await randomize.insert(ctx, doc); - return id; + handler: async (ctx, { titles }) => { + await Promise.all(titles.map((title) => _addMusic(ctx, { title }))); }, }); From b6359f5365101817e99ee0817c7f8b297aba2536 Mon Sep 17 00:00:00 2001 From: Mike Cann Date: Fri, 1 Aug 2025 15:46:28 +0800 Subject: [PATCH 19/77] tests pass but ts failing --- src/client/_generated/_ignore.ts | 1 + src/client/index.test.ts | 59 ++++++++++++++++++++++++++++++++ src/client/setup.test.ts | 33 ++++++++++++++++++ 3 files changed, 93 insertions(+) create mode 100644 src/client/_generated/_ignore.ts create mode 100644 src/client/index.test.ts create mode 100644 src/client/setup.test.ts diff --git a/src/client/_generated/_ignore.ts b/src/client/_generated/_ignore.ts new file mode 100644 index 0000000..ad54e81 --- /dev/null +++ b/src/client/_generated/_ignore.ts @@ -0,0 +1 @@ +// This is only here so convex-test can detect a _generated folder diff --git a/src/client/index.test.ts b/src/client/index.test.ts new file mode 100644 index 0000000..44f0ef4 --- /dev/null +++ b/src/client/index.test.ts @@ -0,0 +1,59 @@ +import { describe, expect, test } from "vitest"; +import { TableAggregate } from "./index.js"; +import { initConvexTest, components } from "./setup.test.js"; +import { defineSchema, defineTable } from "convex/server"; +import { v } from "convex/values"; + +const schema = defineSchema({ + testItems: defineTable({ + name: v.string(), + value: v.number(), + }), +}); + +describe("TableAggregate", () => { + test("should count zero items in empty table", async () => { + const t = initConvexTest(schema); + + const aggregate = new TableAggregate(components.aggregate, { + sortKey: (doc) => doc.value, + }); + + const result = await t.run(async (ctx) => { + return await aggregate.count(ctx); + }); + + }); + + test("should count two items after inserting two documents", async () => { + const t = initConvexTest(schema); + + const aggregate = new TableAggregate(components.aggregate, { + sortKey: (doc) => doc.value, + }); + + await t.run(async (ctx) => { + // Insert first document + const id1 = await ctx.db.insert("testItems", { + name: "first", + value: 10, + }); + const doc1 = await ctx.db.get(id1); + await aggregate.insert(ctx, doc1!); + + // Insert second document + const id2 = await ctx.db.insert("testItems", { + name: "second", + value: 20, + }); + const doc2 = await ctx.db.get(id2); + await aggregate.insert(ctx, doc2!); + }); + + const result = await t.run(async (ctx: any) => { + return await aggregate.count(ctx); + }); + + expect(result).toBe(2); + }); +}); diff --git a/src/client/setup.test.ts b/src/client/setup.test.ts new file mode 100644 index 0000000..94efb67 --- /dev/null +++ b/src/client/setup.test.ts @@ -0,0 +1,33 @@ +/// + +import { test } from "vitest"; +import { convexTest } from "convex-test"; + +export const modules = import.meta.glob("./**/*.*s"); + +import { + defineSchema, + type GenericSchema, + type SchemaDefinition, +} from "convex/server"; +import { type UsedAPI } from "./index.js"; +import { componentsGeneric } from "convex/server"; + +export { componentSchema }; +import componentSchema from "../component/schema.js"; + +export const componentModules = import.meta.glob("../component/**/*.ts"); + +export function initConvexTest< + Schema extends SchemaDefinition, +>(schema?: Schema) { + const t = convexTest(schema ?? defineSchema({}), modules); + t.registerComponent("aggregate", componentSchema, componentModules); + return t; +} + +export const components = componentsGeneric() as unknown as { + aggregate: UsedAPI; +}; + +test("setup", () => {}); From 6ec7a5c352603ff8e49beb397fc1f3341f58e566 Mon Sep 17 00:00:00 2001 From: Mike Cann Date: Fri, 1 Aug 2025 15:47:39 +0800 Subject: [PATCH 20/77] removing any --- src/client/index.test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/client/index.test.ts b/src/client/index.test.ts index 44f0ef4..20e02a6 100644 --- a/src/client/index.test.ts +++ b/src/client/index.test.ts @@ -23,6 +23,7 @@ describe("TableAggregate", () => { return await aggregate.count(ctx); }); + expect(result).toBe(0); }); test("should count two items after inserting two documents", async () => { @@ -50,7 +51,7 @@ describe("TableAggregate", () => { await aggregate.insert(ctx, doc2!); }); - const result = await t.run(async (ctx: any) => { + const result = await t.run(async (ctx) => { return await aggregate.count(ctx); }); From d27f76aab61c956f38e2cff71d2766f268818ea4 Mon Sep 17 00:00:00 2001 From: Mike Cann Date: Fri, 1 Aug 2025 15:50:05 +0800 Subject: [PATCH 21/77] fixed tests --- src/client/setup.test.ts | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/client/setup.test.ts b/src/client/setup.test.ts index 94efb67..a4a3da6 100644 --- a/src/client/setup.test.ts +++ b/src/client/setup.test.ts @@ -5,11 +5,7 @@ import { convexTest } from "convex-test"; export const modules = import.meta.glob("./**/*.*s"); -import { - defineSchema, - type GenericSchema, - type SchemaDefinition, -} from "convex/server"; +import { type GenericSchema, type SchemaDefinition } from "convex/server"; import { type UsedAPI } from "./index.js"; import { componentsGeneric } from "convex/server"; @@ -20,8 +16,8 @@ export const componentModules = import.meta.glob("../component/**/*.ts"); export function initConvexTest< Schema extends SchemaDefinition, ->(schema?: Schema) { - const t = convexTest(schema ?? defineSchema({}), modules); +>(schema: Schema) { + const t = convexTest(schema, modules); t.registerComponent("aggregate", componentSchema, componentModules); return t; } From 639b40e382189f612c7541bf04bb3c7695fb73f4 Mon Sep 17 00:00:00 2001 From: Mike Cann Date: Mon, 4 Aug 2025 07:36:37 +0800 Subject: [PATCH 22/77] added a couple of basic tests --- src/client/index.test.ts | 18 +++++++++++++++--- src/client/setup.test.ts | 16 ++-------------- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/client/index.test.ts b/src/client/index.test.ts index 20e02a6..f2d844e 100644 --- a/src/client/index.test.ts +++ b/src/client/index.test.ts @@ -1,8 +1,14 @@ import { describe, expect, test } from "vitest"; import { TableAggregate } from "./index.js"; -import { initConvexTest, components } from "./setup.test.js"; +import { + components, + componentSchema, + componentModules, + modules, +} from "./setup.test.js"; import { defineSchema, defineTable } from "convex/server"; import { v } from "convex/values"; +import { convexTest } from "convex-test"; const schema = defineSchema({ testItems: defineTable({ @@ -11,9 +17,15 @@ const schema = defineSchema({ }), }); +function setupTest() { + const t = convexTest(schema, modules); + t.registerComponent("aggregate", componentSchema, componentModules); + return t; +} + describe("TableAggregate", () => { test("should count zero items in empty table", async () => { - const t = initConvexTest(schema); + const t = setupTest(); const aggregate = new TableAggregate(components.aggregate, { sortKey: (doc) => doc.value, @@ -27,7 +39,7 @@ describe("TableAggregate", () => { }); test("should count two items after inserting two documents", async () => { - const t = initConvexTest(schema); + const t = setupTest(); const aggregate = new TableAggregate(components.aggregate, { sortKey: (doc) => doc.value, diff --git a/src/client/setup.test.ts b/src/client/setup.test.ts index a4a3da6..a4ce246 100644 --- a/src/client/setup.test.ts +++ b/src/client/setup.test.ts @@ -1,27 +1,15 @@ /// import { test } from "vitest"; -import { convexTest } from "convex-test"; export const modules = import.meta.glob("./**/*.*s"); +export { componentSchema }; +export const componentModules = import.meta.glob("../component/**/*.ts"); -import { type GenericSchema, type SchemaDefinition } from "convex/server"; import { type UsedAPI } from "./index.js"; import { componentsGeneric } from "convex/server"; - -export { componentSchema }; import componentSchema from "../component/schema.js"; -export const componentModules = import.meta.glob("../component/**/*.ts"); - -export function initConvexTest< - Schema extends SchemaDefinition, ->(schema: Schema) { - const t = convexTest(schema, modules); - t.registerComponent("aggregate", componentSchema, componentModules); - return t; -} - export const components = componentsGeneric() as unknown as { aggregate: UsedAPI; }; From acc1fc2dfeaa8e60a640d9853acdcca833408423 Mon Sep 17 00:00:00 2001 From: Mike Cann Date: Mon, 4 Aug 2025 08:21:34 +0800 Subject: [PATCH 23/77] replicated the clearAll issue --- package.json | 2 ++ src/client/index.test.ts | 42 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/package.json b/package.json index 1b28e71..61d6fa8 100644 --- a/package.json +++ b/package.json @@ -19,8 +19,10 @@ "build:esm": "tsc --project ./esm.json && echo '{\\n \"type\": \"module\"\\n}' > dist/esm/package.json", "build:cjs": "tsc --project ./commonjs.json && echo '{\\n \"type\": \"commonjs\"\\n}' > dist/commonjs/package.json", "typecheck": "tsc --noEmit", + "dev:ts": "tsc --watch --noEmit", "prepare": "npm run build", "test": "vitest run", + "dev:test": "vitest run", "test:debug": "vitest --inspect-brk --no-file-parallelism", "test:coverage": "vitest run --coverage --coverage.reporter=text" }, diff --git a/src/client/index.test.ts b/src/client/index.test.ts index f2d844e..4d2b573 100644 --- a/src/client/index.test.ts +++ b/src/client/index.test.ts @@ -69,4 +69,46 @@ describe("TableAggregate", () => { expect(result).toBe(2); }); + + describe("clearAll", () => { + test("should clear all data when called on empty aggregate", async () => { + const t = setupTest(); + + const aggregate = new TableAggregate(components.aggregate, { + sortKey: (doc) => doc.value, + }); + + await t.run(async (ctx) => { + await aggregate.clearAll(ctx); + }); + + const result = await t.run(async (ctx) => { + return await aggregate.count(ctx); + }); + + expect(result).toBe(0); + }); + + test("should clear twice all data when called on empty aggregate", async () => { + const t = setupTest(); + + const aggregate = new TableAggregate(components.aggregate, { + sortKey: (doc) => doc.value, + }); + + await t.run(async (ctx) => { + await aggregate.clearAll(ctx); + }); + + await t.run(async (ctx) => { + await aggregate.clearAll(ctx); + }); + + const result = await t.run(async (ctx) => { + return await aggregate.count(ctx); + }); + + expect(result).toBe(0); + }); + }); }); From f763dc5e561812e53cb38f217aebf5b2359bf6cf Mon Sep 17 00:00:00 2001 From: Mike Cann Date: Mon, 4 Aug 2025 08:24:12 +0800 Subject: [PATCH 24/77] fixed clear issue --- src/client/index.ts | 11 +++++++++-- src/component/btree.ts | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/client/index.ts b/src/client/index.ts index 32714ce..50627d2 100644 --- a/src/client/index.ts +++ b/src/client/index.ts @@ -474,7 +474,12 @@ export class Aggregate< opts?: { maxNodeSize?: number; rootLazy?: boolean } ): Promise { for await (const namespace of this.iterNamespaces(ctx)) { - await this.clear(ctx, { ...opts, namespace }); + // Convert null back to undefined for the default namespace + const actualNamespace = namespace === null ? undefined : namespace; + await this.clear(ctx, { + ...opts, + namespace: actualNamespace as Namespace, + }); } // In case there are no namespaces, make sure we create at least one tree, // at namespace=undefined. This is where the default settings are stored. @@ -483,7 +488,9 @@ export class Aggregate< async makeAllRootsLazy(ctx: RunMutationCtx & RunQueryCtx): Promise { for await (const namespace of this.iterNamespaces(ctx)) { - await this.makeRootLazy(ctx, namespace); + // Convert null back to undefined for the default namespace + const actualNamespace = namespace === null ? undefined : namespace; + await this.makeRootLazy(ctx, actualNamespace as Namespace); } } } diff --git a/src/component/btree.ts b/src/component/btree.ts index b3f24b5..8ac8f9d 100644 --- a/src/component/btree.ts +++ b/src/component/btree.ts @@ -1136,7 +1136,7 @@ export async function paginateNamespacesHandler( } const isDone = trees.length < args.limit; return { - page: trees.map((t) => t.namespace), + page: trees.map((t) => t.namespace ?? null), cursor: isDone ? "endcursor" : trees[trees.length - 1]._id, isDone, }; From d83690963fdff10fbe2b477b6c8e476750598dc3 Mon Sep 17 00:00:00 2001 From: Mike Cann Date: Mon, 4 Aug 2025 08:54:19 +0800 Subject: [PATCH 25/77] tidy tests a bit more --- package.json | 2 +- src/client/index.test.ts | 154 +++++++++++++++++++++++++++------------ 2 files changed, 109 insertions(+), 47 deletions(-) diff --git a/package.json b/package.json index 61d6fa8..24d950d 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "dev:ts": "tsc --watch --noEmit", "prepare": "npm run build", "test": "vitest run", - "dev:test": "vitest run", + "dev:test": "vitest", "test:debug": "vitest --inspect-brk --no-file-parallelism", "test:coverage": "vitest run --coverage --coverage.reporter=text" }, diff --git a/src/client/index.test.ts b/src/client/index.test.ts index 4d2b573..159d445 100644 --- a/src/client/index.test.ts +++ b/src/client/index.test.ts @@ -1,4 +1,4 @@ -import { describe, expect, test } from "vitest"; +import { afterEach, beforeEach, describe, expect, test, vi } from "vitest"; import { TableAggregate } from "./index.js"; import { components, @@ -23,64 +23,86 @@ function setupTest() { return t; } -describe("TableAggregate", () => { - test("should count zero items in empty table", async () => { - const t = setupTest(); +type ConvexTest = ReturnType; - const aggregate = new TableAggregate(components.aggregate, { +describe("TableAggregate", () => { + describe("count", () => { + let t: ConvexTest; + let aggregate = new TableAggregate(components.aggregate, { sortKey: (doc) => doc.value, }); - const result = await t.run(async (ctx) => { - return await aggregate.count(ctx); + beforeEach(() => { + t = setupTest(); + aggregate = new TableAggregate(components.aggregate, { + sortKey: (doc) => doc.value, + }); }); - expect(result).toBe(0); - }); - - test("should count two items after inserting two documents", async () => { - const t = setupTest(); + const exec = async (_aggregate = aggregate) => { + return await t.run(async (ctx) => { + return await _aggregate.count(ctx); + }); + }; - const aggregate = new TableAggregate(components.aggregate, { - sortKey: (doc) => doc.value, + test("should count zero items in empty table", async () => { + const result = await exec(); + expect(result).toBe(0); }); - await t.run(async (ctx) => { - // Insert first document - const id1 = await ctx.db.insert("testItems", { - name: "first", - value: 10, - }); - const doc1 = await ctx.db.get(id1); - await aggregate.insert(ctx, doc1!); - - // Insert second document - const id2 = await ctx.db.insert("testItems", { - name: "second", - value: 20, + test("should count two items after inserting two documents", async () => { + await t.run(async (ctx) => { + // Insert first document + const id1 = await ctx.db.insert("testItems", { + name: "first", + value: 10, + }); + const doc1 = await ctx.db.get(id1); + await aggregate.insert(ctx, doc1!); + + // Insert second document + const id2 = await ctx.db.insert("testItems", { + name: "second", + value: 20, + }); + const doc2 = await ctx.db.get(id2); + await aggregate.insert(ctx, doc2!); }); - const doc2 = await ctx.db.get(id2); - await aggregate.insert(ctx, doc2!); - }); - const result = await t.run(async (ctx) => { - return await aggregate.count(ctx); + const result = await exec(); + expect(result).toBe(2); }); - - expect(result).toBe(2); }); describe("clearAll", () => { - test("should clear all data when called on empty aggregate", async () => { - const t = setupTest(); + let t: ConvexTest; + let aggregate = new TableAggregate(components.aggregate, { + sortKey: (doc) => doc.value, + }); - const aggregate = new TableAggregate(components.aggregate, { + beforeEach(() => { + vi.useFakeTimers(); + t = setupTest(); + aggregate = new TableAggregate(components.aggregate, { sortKey: (doc) => doc.value, }); + }); + afterEach(() => { + vi.useRealTimers(); + }); + + const exec = async (_aggregate = aggregate) => { await t.run(async (ctx) => { - await aggregate.clearAll(ctx); + await _aggregate.clearAll(ctx); }); + // Wait for scheduled cleanup functions to complete + // if we dont do this vitest will hang + await t.finishAllScheduledFunctions(vi.runAllTimers); + }; + + test("should clear all data when called on empty aggregate", async () => { + await exec(); const result = await t.run(async (ctx) => { return await aggregate.count(ctx); @@ -90,25 +112,65 @@ describe("TableAggregate", () => { }); test("should clear twice all data when called on empty aggregate", async () => { - const t = setupTest(); + await exec(); - const aggregate = new TableAggregate(components.aggregate, { - sortKey: (doc) => doc.value, + // This used to error, but now it doesn't + await exec(); + + const result = await t.run(async (ctx) => { + return await aggregate.count(ctx); }); + expect(result).toBe(0); + }); + + test("should clear all data after inserting documents", async () => { + // Insert some test documents await t.run(async (ctx) => { - await aggregate.clearAll(ctx); + const id1 = await ctx.db.insert("testItems", { + name: "first", + value: 10, + }); + const doc1 = await ctx.db.get(id1); + await aggregate.insert(ctx, doc1!); + + const id2 = await ctx.db.insert("testItems", { + name: "second", + value: 20, + }); + const doc2 = await ctx.db.get(id2); + await aggregate.insert(ctx, doc2!); + + const id3 = await ctx.db.insert("testItems", { + name: "third", + value: 30, + }); + const doc3 = await ctx.db.get(id3); + await aggregate.insert(ctx, doc3!); }); - await t.run(async (ctx) => { - await aggregate.clearAll(ctx); + // Verify data exists + const countBefore = await t.run(async (ctx) => { + return await aggregate.count(ctx); }); + expect(countBefore).toBe(3); - const result = await t.run(async (ctx) => { + // Clear all data + await exec(); + + // Verify data is cleared + const countAfter = await t.run(async (ctx) => { return await aggregate.count(ctx); }); + expect(countAfter).toBe(0); - expect(result).toBe(0); + // Verify we can call clearAll again without errors + await exec(); + + const countAfterSecondClear = await t.run(async (ctx) => { + return await aggregate.count(ctx); + }); + expect(countAfterSecondClear).toBe(0); }); }); }); From e7cee5f7d3eac9b7fb9d73f2323f3022b11f8a98 Mon Sep 17 00:00:00 2001 From: Mike Cann Date: Mon, 4 Aug 2025 09:35:06 +0800 Subject: [PATCH 26/77] tidied up vron --- example/convex/crons.ts | 150 +++++++++++++++++++--------------- example/convex/leaderboard.ts | 86 +++++++++---------- example/convex/photos.ts | 19 ++++- example/convex/shuffle.ts | 60 +++++++------- example/convex/stats.ts | 48 +++++++---- 5 files changed, 212 insertions(+), 151 deletions(-) diff --git a/example/convex/crons.ts b/example/convex/crons.ts index 8d37bea..ac1329d 100644 --- a/example/convex/crons.ts +++ b/example/convex/crons.ts @@ -1,80 +1,102 @@ import { cronJobs } from "convex/server"; import { api, internal } from "./_generated/api"; -import { internalAction, internalMutation } from "./_generated/server"; +import { internalMutation } from "./_generated/server"; import { v } from "convex/values"; -import { resetWithoutTriggers } from "./photos"; -export const resetAllData = internalMutation({ +export const resetAndSeed = internalMutation({ args: {}, returns: v.null(), handler: async (ctx) => { console.log("Starting daily data reset..."); - await ctx.runMutation(internal.photos.resetWithoutTriggers); - // Reset all modules in parallel for better performance - // await Promise.all([ - // ctx.runMutation(internal.leaderboard.resetLeaderboard), + // Reset all modules in parallel + await Promise.all([ + ctx.runMutation(internal.leaderboard.resetAll), + ctx.runMutation(internal.photos.resetAll), + ctx.runMutation(internal.shuffle.resetAll), + ctx.runMutation(internal.stats.resetAll), + ]); - // ctx.runMutation(internal.shuffle.resetShuffle), - // ctx.runMutation(internal.stats.resetStats), - // ]); + await ctx.runMutation(api.leaderboard.add100MockScores); - // // Seed some initial data - // await ctx.runMutation(internal.crons.seedInitialData); + // Add some initial photos + await ctx.runMutation(internal.photos.addPhotos, { + photos: [ + { + album: "Nature", + url: "https://images.unsplash.com/photo-1506905925346-21bda4d32df4", + }, + { + album: "Nature", + url: "https://images.unsplash.com/photo-1441974231531-c6227db76b6e", + }, + { + album: "Cities", + url: "https://images.unsplash.com/photo-1449824913935-59a10b8d2000", + }, + { + album: "Cities", + url: "https://images.unsplash.com/photo-1444723121867-7a241cacace9", + }, + { + album: "People", + url: "https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d", + }, + ], + }); - console.log("Daily data reset completed successfully!"); - return null; - }, -}); + await ctx.runMutation(internal.shuffle.addAll, { + titles: [ + "Bohemian Rhapsody - Queen", + "Stairway to Heaven - Led Zeppelin", + "Hotel California - Eagles", + "Imagine - John Lennon", + "Sweet Child O' Mine - Guns N' Roses", + "Smells Like Teen Spirit - Nirvana", + "Hey Jude - The Beatles", + "Like a Rolling Stone - Bob Dylan", + "Billie Jean - Michael Jackson", + "Comfortably Numb - Pink Floyd", + "Let It Be - The Beatles", + "Wonderwall - Oasis", + "Purple Rain - Prince", + "Yesterday - The Beatles", + "Losing My Religion - R.E.M.", + "Hallelujah - Jeff Buckley", + "No Woman, No Cry - Bob Marley", + "Livin' on a Prayer - Bon Jovi", + "Every Breath You Take - The Police", + "Africa - Toto", + "Don't Stop Believin' - Journey", + "Back in Black - AC/DC", + "Wish You Were Here - Pink Floyd", + "November Rain - Guns N' Roses", + "One - U2", + "Paint It Black - The Rolling Stones", + "Creep - Radiohead", + "Enter Sandman - Metallica", + "With or Without You - U2", + "Heroes - David Bowie", + "Blackbird - The Beatles", + "Nothing Else Matters - Metallica", + "Space Oddity - David Bowie", + "Under Pressure - Queen & David Bowie", + "Sultans of Swing - Dire Straits", + "Imagine Dragons - Radioactive", + ], + }); -/** - * Seed some initial data after reset. - * This directly inserts data since aggregates have been cleared. - * The aggregates will be rebuilt through triggers when data is accessed. - */ -export const seedInitialData = internalMutation({ - args: {}, - returns: v.null(), - handler: async (ctx) => { - // await ctx.runMutation(internal.shuffle.addAllMusic, { - // titles: [ - // "Bohemian Rhapsody - Queen", - // "Stairway to Heaven - Led Zeppelin", - // "Hotel California - Eagles", - // "Imagine - John Lennon", - // "Sweet Child O' Mine - Guns N' Roses", - // ], - // }); - - // // Add some initial photos directly - // const initialPhotos = [ - // { - // album: "Nature", - // url: "https://images.unsplash.com/photo-1506905925346-21bda4d32df4", - // }, - // { - // album: "Nature", - // url: "https://images.unsplash.com/photo-1441974231531-c6227db76b6e", - // }, - // { - // album: "Cities", - // url: "https://images.unsplash.com/photo-1449824913935-59a10b8d2000", - // }, - // { - // album: "Cities", - // url: "https://images.unsplash.com/photo-1444723121867-7a241cacace9", - // }, - // { - // album: "People", - // url: "https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d", - // }, - // ]; - - // for (const photo of initialPhotos) await ctx.db.insert("photos", photo); + await ctx.runMutation(api.stats.addLatencies, { + latencies: (() => { + const latencies = new Set() + while (latencies.size < 55) { + latencies.add(Math.floor(Math.random() * 1000) + 50) + } + return Array.from(latencies) + })(), + }); - // await ctx.runMutation(api.leaderboard.add100MockScores); - - console.log("Initial data seeded - aggregates will rebuild when accessed"); + console.log("Daily data reset completed successfully!"); return null; }, }); @@ -86,7 +108,7 @@ const crons = cronJobs(); crons.interval( "daily data reset", { hours: 24 }, - internal.crons.resetAllData, + internal.crons.resetAndSeed, {} ); diff --git a/example/convex/leaderboard.ts b/example/convex/leaderboard.ts index 9cf6071..38a65e0 100644 --- a/example/convex/leaderboard.ts +++ b/example/convex/leaderboard.ts @@ -33,47 +33,6 @@ const aggregateScoreByUser = new TableAggregate<{ sumValue: (doc) => doc.score, }); -export const backfillAggregatesMigration = migrations.define({ - table: "leaderboard", - migrateOne: async (ctx, doc) => { - await aggregateByScore.insertIfDoesNotExist(ctx, doc); - await aggregateScoreByUser.insertIfDoesNotExist(ctx, doc); - console.log("backfilled", doc.name, doc.score); - }, -}); - -const _clearAggregates = async (ctx: MutationCtx) => { - await aggregateByScore.clear(ctx); - await aggregateScoreByUser.clear(ctx); -}; - -export const clearAggregates = internalMutation(_clearAggregates); - -export const resetLeaderboard = internalMutation({ - args: {}, - returns: v.null(), - handler: async (ctx) => { - console.log("Resetting leaderboard..."); - - // Clear docs - const leaderboardDocs = await ctx.db.query("leaderboard").collect(); - for (const doc of leaderboardDocs) await ctx.db.delete(doc._id); - - // Reset aggregate - await _clearAggregates(ctx); - - console.log("Leaderboard reset complete"); - return null; - }, -}); - -// This is what you can run, from the Convex dashboard or with `npx convex run`, -// to backfill aggregates for existing leaderboard entries, if you created the -// leaderboard before adding the aggregate components. -export const runAggregateBackfill = migrations.runner( - internal.leaderboard.backfillAggregatesMigration -); - export const addScore = mutation({ args: { name: v.string(), @@ -246,3 +205,48 @@ export const add100MockScores = mutation({ return null; }, }); + +// ---- migrations ---- + +export const backfillAggregatesMigration = migrations.define({ + table: "leaderboard", + migrateOne: async (ctx, doc) => { + await aggregateByScore.insertIfDoesNotExist(ctx, doc); + await aggregateScoreByUser.insertIfDoesNotExist(ctx, doc); + console.log("backfilled", doc.name, doc.score); + }, +}); + +// This is what you can run, from the Convex dashboard or with `npx convex run`, +// to backfill aggregates for existing leaderboard entries, if you created the +// leaderboard before adding the aggregate components. +export const runAggregateBackfill = migrations.runner( + internal.leaderboard.backfillAggregatesMigration +); + +// ---- internal ---- + +const _clearAggregates = async (ctx: MutationCtx) => { + await aggregateByScore.clear(ctx); + await aggregateScoreByUser.clear(ctx); +}; + +export const clearAggregates = internalMutation(_clearAggregates); + +export const resetAll = internalMutation({ + args: {}, + returns: v.null(), + handler: async (ctx) => { + console.log("Resetting leaderboard..."); + + // Clear docs + const leaderboardDocs = await ctx.db.query("leaderboard").collect(); + for (const doc of leaderboardDocs) await ctx.db.delete(doc._id); + + // Reset aggregate + await _clearAggregates(ctx); + + console.log("Leaderboard reset complete"); + return null; + }, +}); diff --git a/example/convex/photos.ts b/example/convex/photos.ts index a013d36..4239a5b 100644 --- a/example/convex/photos.ts +++ b/example/convex/photos.ts @@ -13,7 +13,7 @@ import { mutation as rawMutation, query, } from "../../example/convex/_generated/server"; -import { components } from "../../example/convex/_generated/api"; +import { api, components } from "../../example/convex/_generated/api"; import { DataModel } from "../../example/convex/_generated/dataModel"; import { v } from "convex/values"; import { @@ -86,9 +86,9 @@ export const pageOfPhotos = query({ }, }); -// ----- +// ----- internal ----- -export const resetWithoutTriggers = rawInternalMutation({ +export const resetAll = internalMutation({ args: {}, handler: async (ctx) => { // Just delete table records - triggers will automatically keep aggregate in sync @@ -104,3 +104,16 @@ export const resetWithoutTriggers = rawInternalMutation({ }); }, }); + +export const addPhotos = internalMutation({ + args: { + photos: v.array(v.object({ album: v.string(), url: v.string() })), + }, + handler: async (ctx, { photos }) => { + await Promise.all( + photos.map((photo) => + ctx.db.insert("photos", { album: photo.album, url: photo.url }) + ) + ); + }, +}); diff --git a/example/convex/shuffle.ts b/example/convex/shuffle.ts index 02a8348..23c28e4 100644 --- a/example/convex/shuffle.ts +++ b/example/convex/shuffle.ts @@ -35,15 +35,6 @@ export const addMusic = mutation({ handler: _addMusic, }); -export const addAllMusic = internalMutation({ - args: { - titles: v.array(v.string()), - }, - handler: async (ctx, { titles }) => { - await Promise.all(titles.map((title) => _addMusic(ctx, { title }))); - }, -}); - export const removeMusic = mutation({ args: { id: v.id("music"), @@ -55,26 +46,6 @@ export const removeMusic = mutation({ }, }); -export const resetShuffle = internalMutation({ - args: {}, - returns: v.null(), - handler: async (ctx) => { - console.log("Resetting shuffle/music..."); - - // Clear table first to avoid race conditions - const musicDocs = await ctx.db.query("music").collect(); - for (const doc of musicDocs) { - await ctx.db.delete(doc._id); - } - - // Then clear the aggregate - await randomize.clear(ctx); - - console.log("Shuffle/music reset complete"); - return null; - }, -}); - export const getRandomMusicTitle = query({ args: { cacheBuster: v.optional(v.number()), @@ -149,3 +120,34 @@ function shuffle(array: T[], rand: Rand): T[] { } return array; } + +// ----- internal ----- + +export const resetAll = internalMutation({ + args: {}, + returns: v.null(), + handler: async (ctx) => { + console.log("Resetting shuffle/music..."); + + // Clear table first to avoid race conditions + const musicDocs = await ctx.db.query("music").collect(); + for (const doc of musicDocs) { + await ctx.db.delete(doc._id); + } + + // Then clear the aggregate + await randomize.clearAll(ctx); + + console.log("Shuffle/music reset complete"); + return null; + }, +}); + +export const addAll = internalMutation({ + args: { + titles: v.array(v.string()), + }, + handler: async (ctx, { titles }) => { + await Promise.all(titles.map((title) => _addMusic(ctx, { title }))); + }, +}); diff --git a/example/convex/stats.ts b/example/convex/stats.ts index 7eb45ba..f8524a4 100644 --- a/example/convex/stats.ts +++ b/example/convex/stats.ts @@ -30,20 +30,6 @@ export const reportLatency = mutation({ }, }); -export const resetStats = internalMutation({ - args: {}, - returns: v.null(), - handler: async (ctx) => { - console.log("Resetting stats..."); - - // Clear the direct aggregate - await stats.clear(ctx); - - console.log("Stats reset complete"); - return null; - }, -}); - export const getStats = query({ args: {}, handler: async (ctx) => { @@ -66,3 +52,37 @@ export const getStats = query({ }; }, }); + +// ----- internal ----- + +export const resetAll = internalMutation({ + args: {}, + returns: v.null(), + handler: async (ctx) => { + console.log("Resetting stats..."); + + // Clear the direct aggregate + await stats.clear(ctx); + + console.log("Stats reset complete"); + return null; + }, +}); + +export const addLatencies = mutation({ + args: { + latencies: v.array(v.number()), + }, + returns: v.null(), + handler: async (ctx, { latencies }) => { + await Promise.all( + latencies.map((latency) => + stats.insert(ctx, { + key: latency, + id: new Date().toISOString(), + sumValue: latency, + }) + ) + ); + }, +}); From 1e053a521ecf60e1dcaeb74aee74bdb6bbd43dbb Mon Sep 17 00:00:00 2001 From: Mike Cann Date: Mon, 4 Aug 2025 10:52:16 +0800 Subject: [PATCH 27/77] improved photos examepl --- example/convex/photos.ts | 41 +++ example/convex/shuffle.ts | 23 +- example/src/pages/PhotosPage.tsx | 402 +++++++++++++++++++++------- example/src/pages/ShufflePage.tsx | 37 ++- example/src/utils/useStableQuery.ts | 92 +++++++ 5 files changed, 479 insertions(+), 116 deletions(-) create mode 100644 example/src/utils/useStableQuery.ts diff --git a/example/convex/photos.ts b/example/convex/photos.ts index 4239a5b..93d524b 100644 --- a/example/convex/photos.ts +++ b/example/convex/photos.ts @@ -54,9 +54,49 @@ export const addPhoto = mutation({ }, }); +/** + * Get the total count of photos in an album - demonstrates O(log(n)) count operation + */ +export const photoCount = query({ + args: { album: v.string() }, + returns: v.number(), + handler: async (ctx, { album }) => { + // @ts-ignore - namespace should work without bounds + return await photos.count(ctx, { namespace: album }); + }, +}); + +/** + * Get all available albums - useful for the UI + */ +export const availableAlbums = query({ + args: {}, + returns: v.array(v.object({ name: v.string(), count: v.number() })), + handler: async (ctx) => { + // Get unique albums from the photos table + const allPhotos = await ctx.db.query("photos").collect(); + const albumNames = [...new Set(allPhotos.map((photo) => photo.album))]; + + // Get count for each album using the aggregate + const albumsWithCounts = await Promise.all( + albumNames.map(async (album) => ({ + name: album, + // @ts-ignore - namespace should work without bounds + count: await photos.count(ctx, { namespace: album }), + })) + ); + + return albumsWithCounts.sort((a, b) => a.name.localeCompare(b.name)); + }, +}); + /** * Call this with {offset:0, numItems:10} to get the first page of photos, * then {offset:10, numItems:10} to get the second page, etc. + * + * This demonstrates the key feature: O(log(n)) offset-based pagination! + * Instead of scanning through all photos to find page N, we use the aggregate + * to jump directly to the right position. */ export const pageOfPhotos = query({ args: { @@ -73,6 +113,7 @@ export const pageOfPhotos = query({ .first(); if (!firstPhoto) return []; + // This is the magic! photos.at() gives us O(log(n)) lookup to any position const { key: firstPhotoCreationTime } = await photos.at(ctx, offset, { namespace: album, }); diff --git a/example/convex/shuffle.ts b/example/convex/shuffle.ts index 23c28e4..29972e1 100644 --- a/example/convex/shuffle.ts +++ b/example/convex/shuffle.ts @@ -76,7 +76,14 @@ export const shufflePaginated = query({ numItems: v.number(), seed: v.string(), }, - returns: v.array(v.string()), + returns: v.object({ + items: v.array(v.string()), + totalCount: v.number(), + totalPages: v.number(), + currentPage: v.number(), + hasNextPage: v.boolean(), + hasPrevPage: v.boolean(), + }), handler: async (ctx, { offset, numItems, seed }) => { const count = await randomize.count(ctx); // `rand` is a seeded pseudo-random number generator. @@ -103,12 +110,24 @@ export const shufflePaginated = query({ indexes.map((i) => randomize.at(ctx, i)) ); - return await Promise.all( + const items = await Promise.all( atIndexes.map(async (atIndex) => { const doc = (await ctx.db.get(atIndex.id))!; return doc.title; }) ); + + const totalPages = Math.ceil(count / numItems); + const currentPage = Math.floor(offset / numItems) + 1; + + return { + items, + totalCount: count, + totalPages, + currentPage, + hasNextPage: offset + numItems < count, + hasPrevPage: offset > 0, + }; }, }); diff --git a/example/src/pages/PhotosPage.tsx b/example/src/pages/PhotosPage.tsx index d6ff810..31cacbc 100644 --- a/example/src/pages/PhotosPage.tsx +++ b/example/src/pages/PhotosPage.tsx @@ -12,145 +12,339 @@ import { Pagination, Alert, SimpleGrid, + Badge, + Select, + Code, + Paper, + List, + ThemeIcon, + Divider, + Grid, } from "@mantine/core"; -import { IconPhoto } from "@tabler/icons-react"; -import { useState } from "react"; +import { + IconPhoto, + IconRocket, + IconDatabase, + IconChartBar, + IconBolt, + IconInfoCircle, +} from "@tabler/icons-react"; +import { useState, useEffect } from "react"; import { useApiErrorHandler } from "@/utils/errors"; export function PhotosPage() { const onApiError = useApiErrorHandler(); - const [album, setAlbum] = useState(""); + const [selectedAlbum, setSelectedAlbum] = useState("Nature"); + const [newAlbum, setNewAlbum] = useState(""); const [url, setUrl] = useState(""); const [currentPage, setCurrentPage] = useState(1); - const [pageSize] = useState(5); + const [pageSize] = useState(6); + + // Get available albums with counts + const albums = useQuery(api.photos.availableAlbums); + // Get photos for current page const photos = useQuery(api.photos.pageOfPhotos, { - album: album || "default", + album: selectedAlbum, offset: (currentPage - 1) * pageSize, numItems: pageSize, }); + // Get total count for pagination + const totalPhotos = useQuery(api.photos.photoCount, { album: selectedAlbum }); + const addPhoto = useMutation(api.photos.addPhoto); + // Reset to page 1 when album changes + useEffect(() => { + setCurrentPage(1); + }, [selectedAlbum]); + + const totalPages = totalPhotos ? Math.ceil(totalPhotos / pageSize) : 0; + return ( + {/* Header */} - Photos Demo + Offset-Based Pagination Demo + + O(log n) Performance + - - Offset-based pagination for photo galleries with efficient O(log(n)) - lookups + + Efficient photo gallery pagination using Convex Aggregate component - {/* Add Photo Section */} - - - - Add New Photo - - - setAlbum(e.target.value)} - placeholder="Enter album name" - /> - setUrl(e.target.value)} - placeholder="Enter photo URL" - /> - - - + {/* Quick explanation */} + + + + + + + + Traditional:{" "} + + O(n) + {" "} + - Scans all items to skip + + + + + + + + Aggregate:{" "} + + O(log n) + {" "} + - Jumps directly to any page + + + - {/* Photo Gallery Section */} - - - - Photo Gallery - - - {photos && photos.length > 0 ? ( - - - {photos.map((photoUrl, index) => ( - - {`Photo + {/* Left Column - Photo Gallery */} + + + {/* Album Selection & Live Stats */} + + + + + Browse Albums: + + {albums && ( + value && setSelectedAlbum(value)} - data={albums.map((album) => ({ - value: album.name, - label: `${album.name} (${album.count} photos)`, - }))} - style={{ minWidth: 200 }} - /> - )} - + {/* Quick explanation */} + + + + + + + + Traditional:{" "} + + O(n) + {" "} + - Scans all items to skip + + + + + + + + Aggregate:{" "} + + O(log n) + {" "} + - Jumps directly to any page + + + + - {totalPhotos !== undefined && ( - - - - - - - Total photos in {selectedAlbum}:{" "} - {totalPhotos} - - - - - - - - Page {currentPage} of {totalPages}{" "} - O(log n) - - + + {/* Left Column - Photo Gallery */} + + + {/* Album Selection & Live Stats */} + + + + + Browse Albums: + + {albums && ( + value && setPageSize(parseInt(value))} + data={[ + { value: "5", label: "5 per page" }, + { value: "10", label: "10 per page" }, + { value: "20", label: "20 per page" }, + { value: "50", label: "50 per page" }, + ]} + size="sm" + w={120} + /> + + + {totalScores !== undefined && ( + + + Total scores: {totalScores} + + + Page {currentPage} of {totalPages}{" "} + + O(log n) + + + + )} + - return ( + {scores && scores.length > 0 ? ( + + + + + Rank + Player + Score + Actions + + + + {scores.map((score, index) => ( - {index + 1} + + {(currentPage - 1) * pageSize + index + 1} + {score.name} {score.score} @@ -55,10 +117,22 @@ export function LeaderboardTable() { - ); - })} - -
+ ))} + + + + {totalPages > 1 && ( + + + + )} +
) : ( Add some scores to see the leaderboard! From bed4d387da38e27de69dc25ee98c570f848bd128 Mon Sep 17 00:00:00 2001 From: Mike Cann Date: Wed, 6 Aug 2025 14:00:16 +0800 Subject: [PATCH 56/77] better leaderboard layout --- .../src/pages/leaderboard/AddScoreSection.tsx | 19 +-- .../pages/leaderboard/LeaderboardAside.tsx | 19 +++ .../src/pages/leaderboard/LeaderboardPage.tsx | 121 ++++++++---------- .../pages/leaderboard/LeaderboardTable.tsx | 5 +- .../leaderboard/SearchAnalysisSection.tsx | 12 +- .../pages/leaderboard/StatisticsSection.tsx | 22 ++-- 6 files changed, 102 insertions(+), 96 deletions(-) create mode 100644 example/src/pages/leaderboard/LeaderboardAside.tsx diff --git a/example/src/pages/leaderboard/AddScoreSection.tsx b/example/src/pages/leaderboard/AddScoreSection.tsx index 61e5c85..9ac1b9f 100644 --- a/example/src/pages/leaderboard/AddScoreSection.tsx +++ b/example/src/pages/leaderboard/AddScoreSection.tsx @@ -8,6 +8,7 @@ import { TextInput, NumberInput, Button, + Paper, } from "@mantine/core"; import { useState } from "react"; import { useApiErrorHandler } from "@/utils/errors"; @@ -22,18 +23,18 @@ export function AddScoreSection() { const addMockScores = useMutation(api.leaderboard.add100MockScores); return ( - + - + <Title order={3} c="white"> Add New Score - + setPlayerName(e.target.value)} placeholder="Enter player name" - style={{ flex: 1 }} + size="sm" /> @@ -71,13 +72,13 @@ export function AddScoreSection() { disabled={isAddingMockScores} color="blue" variant="outline" - style={{ alignSelf: "end" }} loading={isAddingMockScores} + size="sm" > Add 100 Mock Scores - +
-
+ ); } diff --git a/example/src/pages/leaderboard/LeaderboardAside.tsx b/example/src/pages/leaderboard/LeaderboardAside.tsx new file mode 100644 index 0000000..bb870a4 --- /dev/null +++ b/example/src/pages/leaderboard/LeaderboardAside.tsx @@ -0,0 +1,19 @@ +import { Stack } from "@mantine/core"; +import { AddScoreSection } from "./AddScoreSection"; +import { StatisticsSection } from "./StatisticsSection"; + +export function LeaderboardAside() { + return ( + + + + + ); +} diff --git a/example/src/pages/leaderboard/LeaderboardPage.tsx b/example/src/pages/leaderboard/LeaderboardPage.tsx index e0869a9..a544106 100644 --- a/example/src/pages/leaderboard/LeaderboardPage.tsx +++ b/example/src/pages/leaderboard/LeaderboardPage.tsx @@ -7,6 +7,8 @@ import { Badge, Anchor, ThemeIcon, + AppShell, + Container, } from "@mantine/core"; import { IconTrophy, @@ -19,80 +21,67 @@ import { AddScoreSection } from "./AddScoreSection"; import { StatisticsSection } from "./StatisticsSection"; import { SearchAnalysisSection } from "./SearchAnalysisSection"; import { LeaderboardTable } from "./LeaderboardTable"; +import { BTreeAside } from "../btree/index"; +import { LeaderboardAside } from "./LeaderboardAside"; export function LeaderboardPage() { return ( - - - - - - Leaderboard Demo - - - - - Lightning-fast leaderboards with instant rankings, statistics, and - user analytics using Convex Aggregate - - - - - - - - View the source: - - - convex/leaderboard.ts - - - - - - {/* Quick explanation */} - - - - - - - - Traditional:{" "} - - O(n) - {" "} - - Scan all scores to find rankings - - - - - - - - Aggregate:{" "} - - O(log n) - {" "} - - Find any ranking instantly - - + + + + } + appShellProps={{ + aside: { + width: 300, + breakpoint: "md", + collapsed: { + desktop: false, + mobile: true, + }, + }, + }} + > + + + + + + Leaderboard Demo + - - + + Lightning-fast leaderboards with instant rankings, statistics, and + user analytics using Convex Aggregate + - + + + + + + View the source: + + + convex/leaderboard.ts + + + + - + - - + +
+ ); } diff --git a/example/src/pages/leaderboard/LeaderboardTable.tsx b/example/src/pages/leaderboard/LeaderboardTable.tsx index d7d7f70..b55284d 100644 --- a/example/src/pages/leaderboard/LeaderboardTable.tsx +++ b/example/src/pages/leaderboard/LeaderboardTable.tsx @@ -67,7 +67,7 @@ export function LeaderboardTable() { { value: "50", label: "50 per page" }, ]} size="sm" - w={120} + w={150} />
@@ -78,9 +78,6 @@ export function LeaderboardTable() {
Page {currentPage} of {totalPages}{" "} - - O(log n) -
)} diff --git a/example/src/pages/leaderboard/SearchAnalysisSection.tsx b/example/src/pages/leaderboard/SearchAnalysisSection.tsx index 4108cea..1dd3481 100644 --- a/example/src/pages/leaderboard/SearchAnalysisSection.tsx +++ b/example/src/pages/leaderboard/SearchAnalysisSection.tsx @@ -41,8 +41,8 @@ export function SearchAnalysisSection() { Search & Analysis - - + + Find Rank of Score @@ -56,13 +56,13 @@ export function SearchAnalysisSection() { min={0} style={{ flex: 1 }} /> - + Rank: {rankOfScore !== undefined ? rankOfScore + 1 : "N/A"} - + Player Statistics @@ -73,14 +73,14 @@ export function SearchAnalysisSection() { placeholder="Enter player name" style={{ flex: 1 }} /> - + Avg: {userAverage ? userAverage.toFixed(2) : "N/A"} High: {userHighScore ?? "N/A"} - +
diff --git a/example/src/pages/leaderboard/StatisticsSection.tsx b/example/src/pages/leaderboard/StatisticsSection.tsx index 5d744b6..4622d2e 100644 --- a/example/src/pages/leaderboard/StatisticsSection.tsx +++ b/example/src/pages/leaderboard/StatisticsSection.tsx @@ -7,39 +7,39 @@ export function StatisticsSection() { const totalSum = useQuery(api.leaderboard.sumNumbers); return ( - - + + - + Total Scores - + <Title order={3} c="white"> {totalCount ?? "Loading..."} - + - + Total Sum - + <Title order={3} c="white"> {totalSum ?? "Loading..."} - + - + Average Score - + <Title order={3} c="white"> {totalCount && totalSum ? (totalSum / totalCount).toFixed(2) : "Loading..."} - + ); } From 455e13d956dcdf6ea55df3c2ec97bad8737d1e54 Mon Sep 17 00:00:00 2001 From: Mike Cann Date: Wed, 6 Aug 2025 14:50:06 +0800 Subject: [PATCH 57/77] small refactors --- example/convex/leaderboard.ts | 41 +++++++++++++---- example/src/common/StatsGrid.tsx | 14 +++--- .../leaderboard/SearchAnalysisSection.tsx | 40 ++++++++-------- .../pages/leaderboard/StatisticsSection.tsx | 6 +-- example/src/pages/photos/PhotosPage.tsx | 46 +------------------ example/src/pages/shuffle/ShufflePage.tsx | 30 ------------ 6 files changed, 65 insertions(+), 112 deletions(-) diff --git a/example/convex/leaderboard.ts b/example/convex/leaderboard.ts index 975184a..94990cb 100644 --- a/example/convex/leaderboard.ts +++ b/example/convex/leaderboard.ts @@ -79,6 +79,22 @@ export const scoreAtRank = query({ }, }); +export const pageOfScores = query({ + args: { + offset: v.number(), + numItems: v.number(), + }, + handler: async (ctx, { offset, numItems }) => { + const scores = await ctx.db + .query("leaderboard") + .orderBy("score", "desc") + .skip(offset) + .take(numItems); + + return scores; + }, +}); + export const pageOfScores = query({ args: { offset: v.number(), @@ -166,15 +182,24 @@ export const add100MockScores = mutation({ returns: v.null(), handler: async (ctx) => { const playerNames = [ - "Alex", + "Jamie", + "James", + "Indy", + "Gautam", + "Nipunn", + "Emma", + "Tom", + "Rebecca", + "Ian", "Jordan", - "Casey", - "Morgan", - "Riley", - "Avery", - "Quinn", - "Blake", - "Orion", + "Abhi", + "Wayne", + "Ari", + "Christina", + "Liz", + "Mike", + "Geoffry", + "Nicolas", ]; const mockScores = []; diff --git a/example/src/common/StatsGrid.tsx b/example/src/common/StatsGrid.tsx index 4dcfb0c..0c7ee12 100644 --- a/example/src/common/StatsGrid.tsx +++ b/example/src/common/StatsGrid.tsx @@ -35,7 +35,7 @@ export function StatsGrid({ return ( - + Count @@ -45,7 +45,7 @@ export function StatsGrid({ - + Mean @@ -55,7 +55,7 @@ export function StatsGrid({ - + Median @@ -65,7 +65,7 @@ export function StatsGrid({ - + 75th Percentile @@ -75,7 +75,7 @@ export function StatsGrid({ - + 95th Percentile @@ -85,7 +85,7 @@ export function StatsGrid({ - + Min @@ -95,7 +95,7 @@ export function StatsGrid({ - + Max diff --git a/example/src/pages/leaderboard/SearchAnalysisSection.tsx b/example/src/pages/leaderboard/SearchAnalysisSection.tsx index 1dd3481..9fe9df4 100644 --- a/example/src/pages/leaderboard/SearchAnalysisSection.tsx +++ b/example/src/pages/leaderboard/SearchAnalysisSection.tsx @@ -42,26 +42,6 @@ export function SearchAnalysisSection() { - - - Find Rank of Score - - - - setSearchScore(value === "" ? "" : (value as number)) - } - placeholder="Enter score" - min={0} - style={{ flex: 1 }} - /> - - Rank: {rankOfScore !== undefined ? rankOfScore + 1 : "N/A"} - - - - Player Statistics @@ -83,6 +63,26 @@ export function SearchAnalysisSection() { + + + + Find Rank of Score + + + + setSearchScore(value === "" ? "" : (value as number)) + } + placeholder="Enter score" + min={0} + style={{ flex: 1 }} + /> + + Rank: {rankOfScore !== undefined ? rankOfScore + 1 : "N/A"} + + + diff --git a/example/src/pages/leaderboard/StatisticsSection.tsx b/example/src/pages/leaderboard/StatisticsSection.tsx index 4622d2e..3780e4f 100644 --- a/example/src/pages/leaderboard/StatisticsSection.tsx +++ b/example/src/pages/leaderboard/StatisticsSection.tsx @@ -9,7 +9,7 @@ export function StatisticsSection() { return ( - + Total Scores @@ -19,7 +19,7 @@ export function StatisticsSection() { - + Total Sum @@ -29,7 +29,7 @@ export function StatisticsSection() { - + Average Score diff --git a/example/src/pages/photos/PhotosPage.tsx b/example/src/pages/photos/PhotosPage.tsx index 0060752..2b6d531 100644 --- a/example/src/pages/photos/PhotosPage.tsx +++ b/example/src/pages/photos/PhotosPage.tsx @@ -113,7 +113,8 @@ export function PhotosPage() { - Efficient photo gallery pagination using Convex Aggregate component + Shows now you can use Namespaces to efficiently segment your + aggregates @@ -135,36 +136,6 @@ export function PhotosPage() { - {/* Quick explanation */} - - - - - - - - Traditional:{" "} - - O(n) - {" "} - - Scans all items to skip - - - - - - - - Aggregate:{" "} - - O(log n) - {" "} - - Jumps directly to any page - - - - - {/* Left Column - Photo Gallery */} @@ -206,7 +177,6 @@ export function PhotosPage() { Page {currentPage} of {totalPages}{" "} - O(log n) @@ -351,18 +321,6 @@ export function PhotosPage() { > {isRandomMode ? "Add Random Photo" : "Add Photo"} - - } - > - - Add a photo to an existing album and watch the count - update instantly! The aggregate component automatically - maintains all the metadata needed for fast pagination. - - diff --git a/example/src/pages/shuffle/ShufflePage.tsx b/example/src/pages/shuffle/ShufflePage.tsx index 48a00c0..d76d930 100644 --- a/example/src/pages/shuffle/ShufflePage.tsx +++ b/example/src/pages/shuffle/ShufflePage.tsx @@ -102,36 +102,6 @@ export function ShufflePage() { - {/* Quick explanation */} - - - - - - - - Traditional:{" "} - - O(n) - {" "} - - Scan all items for random access - - - - - - - - Aggregate:{" "} - - O(log n) - {" "} - - Jump directly to any random position - - - - - {/* Left Column - Music Demo */} From 1f032a74c6052d1d9d61f9a3e397912c7f74fb92 Mon Sep 17 00:00:00 2001 From: Mike Cann Date: Wed, 6 Aug 2025 15:35:10 +0800 Subject: [PATCH 58/77] suffle page aside --- example/convex/leaderboard.ts | 16 - example/src/common/CodeLinkButton.tsx | 38 ++ example/src/common/CommonAppShell.tsx | 1 + example/src/common/PageHeader.tsx | 33 ++ .../src/pages/leaderboard/LeaderboardPage.tsx | 61 +-- example/src/pages/photos/PhotosPage.tsx | 40 +- example/src/pages/shuffle/AddMusicSection.tsx | 64 +++ example/src/pages/shuffle/CodeModal.tsx | 34 ++ .../src/pages/shuffle/RandomSongPicker.tsx | 68 +++ example/src/pages/shuffle/ShuffleAside.tsx | 17 + example/src/pages/shuffle/ShufflePage.tsx | 389 +++--------------- example/src/pages/shuffle/ShufflePlaylist.tsx | 134 ++++++ example/src/pages/shuffle/ShuffleStats.tsx | 32 ++ example/src/pages/stats/StatsPage.tsx | 41 +- 14 files changed, 510 insertions(+), 458 deletions(-) create mode 100644 example/src/common/CodeLinkButton.tsx create mode 100644 example/src/common/PageHeader.tsx create mode 100644 example/src/pages/shuffle/AddMusicSection.tsx create mode 100644 example/src/pages/shuffle/CodeModal.tsx create mode 100644 example/src/pages/shuffle/RandomSongPicker.tsx create mode 100644 example/src/pages/shuffle/ShuffleAside.tsx create mode 100644 example/src/pages/shuffle/ShufflePlaylist.tsx create mode 100644 example/src/pages/shuffle/ShuffleStats.tsx diff --git a/example/convex/leaderboard.ts b/example/convex/leaderboard.ts index 94990cb..bdb6dfd 100644 --- a/example/convex/leaderboard.ts +++ b/example/convex/leaderboard.ts @@ -79,22 +79,6 @@ export const scoreAtRank = query({ }, }); -export const pageOfScores = query({ - args: { - offset: v.number(), - numItems: v.number(), - }, - handler: async (ctx, { offset, numItems }) => { - const scores = await ctx.db - .query("leaderboard") - .orderBy("score", "desc") - .skip(offset) - .take(numItems); - - return scores; - }, -}); - export const pageOfScores = query({ args: { offset: v.number(), diff --git a/example/src/common/CodeLinkButton.tsx b/example/src/common/CodeLinkButton.tsx new file mode 100644 index 0000000..b283bc4 --- /dev/null +++ b/example/src/common/CodeLinkButton.tsx @@ -0,0 +1,38 @@ +import { ActionIcon, Tooltip } from "@mantine/core"; +import { IconCode } from "@tabler/icons-react"; + +interface CodeLinkButtonProps { + /** The filename to link to (e.g., "leaderboard.ts", "stats.ts") */ + filename: string; + /** Optional tooltip text. Defaults to "View source code" */ + tooltip?: string; +} + +export function CodeLinkButton({ + filename, + tooltip = "View source code", +}: CodeLinkButtonProps) { + const href = `https://github.com/get-convex/aggregate/blob/main/example/convex/${filename}`; + + return ( + + + + + + ); +} diff --git a/example/src/common/CommonAppShell.tsx b/example/src/common/CommonAppShell.tsx index 632a83b..570805b 100644 --- a/example/src/common/CommonAppShell.tsx +++ b/example/src/common/CommonAppShell.tsx @@ -32,6 +32,7 @@ export function CommonAppShell(props: CommonAppShellProps) { ) : ( diff --git a/example/src/common/PageHeader.tsx b/example/src/common/PageHeader.tsx new file mode 100644 index 0000000..d19903e --- /dev/null +++ b/example/src/common/PageHeader.tsx @@ -0,0 +1,33 @@ +import { Title, Text, Stack, Group } from "@mantine/core"; +import { ReactNode } from "react"; +import { CodeLinkButton } from "./CodeLinkButton"; + +interface PageHeaderProps { + title: string; + description: string; + icon: ReactNode; + filename: string; +} + +export function PageHeader({ + title, + description, + icon, + filename, +}: PageHeaderProps) { + return ( + + + {icon} + + {title} + + + + + {description} + + + + ); +} diff --git a/example/src/pages/leaderboard/LeaderboardPage.tsx b/example/src/pages/leaderboard/LeaderboardPage.tsx index a544106..f187acd 100644 --- a/example/src/pages/leaderboard/LeaderboardPage.tsx +++ b/example/src/pages/leaderboard/LeaderboardPage.tsx @@ -1,22 +1,7 @@ -import { - Title, - Text, - Card, - Stack, - Group, - Badge, - Anchor, - ThemeIcon, - AppShell, - Container, -} from "@mantine/core"; -import { - IconTrophy, - IconCode, - IconBolt, - IconRocket, -} from "@tabler/icons-react"; +import { Stack, AppShell, Container } from "@mantine/core"; +import { IconTrophy } from "@tabler/icons-react"; import { CommonAppShell } from "../../common/CommonAppShell"; +import { PageHeader } from "../../common/PageHeader"; import { AddScoreSection } from "./AddScoreSection"; import { StatisticsSection } from "./StatisticsSection"; import { SearchAnalysisSection } from "./SearchAnalysisSection"; @@ -44,38 +29,14 @@ export function LeaderboardPage() { }, }} > - - - - - - Leaderboard Demo - - - - - Lightning-fast leaderboards with instant rankings, statistics, and - user analytics using Convex Aggregate - - - - - - - - View the source: - - - convex/leaderboard.ts - - - - + + + } + filename="leaderboard.ts" + /> diff --git a/example/src/pages/photos/PhotosPage.tsx b/example/src/pages/photos/PhotosPage.tsx index 2b6d531..c2d055d 100644 --- a/example/src/pages/photos/PhotosPage.tsx +++ b/example/src/pages/photos/PhotosPage.tsx @@ -16,7 +16,6 @@ import { Select, ThemeIcon, Grid, - Anchor, ActionIcon, Loader, } from "@mantine/core"; @@ -27,7 +26,6 @@ import { IconChartBar, IconBolt, IconInfoCircle, - IconCode, IconDice, IconEdit, } from "@tabler/icons-react"; @@ -35,6 +33,7 @@ import { useState, useEffect } from "react"; import { useApiErrorHandler } from "@/utils/errors"; import { CommonAppShell } from "@/common/CommonAppShell"; import { useRicherStableQuery } from "../../utils/useStableQuery"; +import { PageHeader } from "../../common/PageHeader"; export function PhotosPage() { const onApiError = useApiErrorHandler(); @@ -104,37 +103,12 @@ export function PhotosPage() { return ( - {/* Header */} - - - - Offset-Based Pagination Demo - - - - - Shows now you can use Namespaces to efficiently segment your - aggregates - - - - - - - - View the source: - - - convex/photos.ts - - - - + } + filename="photos.ts" + /> {/* Left Column - Photo Gallery */} diff --git a/example/src/pages/shuffle/AddMusicSection.tsx b/example/src/pages/shuffle/AddMusicSection.tsx new file mode 100644 index 0000000..490e1a7 --- /dev/null +++ b/example/src/pages/shuffle/AddMusicSection.tsx @@ -0,0 +1,64 @@ +import { useMutation } from "convex/react"; +import { api } from "../../../convex/_generated/api"; +import { + Card, + Stack, + Group, + Title, + Text, + TextInput, + Button, + Alert, +} from "@mantine/core"; +import { IconMusic, IconInfoCircle } from "@tabler/icons-react"; +import { useState } from "react"; +import { useApiErrorHandler } from "@/utils/errors"; + +export function AddMusicSection() { + const onApiError = useApiErrorHandler(); + const [title, setTitle] = useState(""); + const addMusic = useMutation(api.shuffle.addMusic); + + const handleAddMusic = () => { + if (!title) return; + addMusic({ title }) + .then(() => { + setTitle(""); + }) + .catch(onApiError); + }; + return ( + + + + + + Add Music + + + + Watch the count update instantly! ⚡ + + + setTitle(e.target.value)} + placeholder="e.g., Bohemian Rhapsody - Queen" + size="sm" + /> + + + }> + + Add songs and watch the random picker and shuffle work instantly! + The aggregate maintains perfect performance even with thousands of + songs. + + + + + ); +} diff --git a/example/src/pages/shuffle/CodeModal.tsx b/example/src/pages/shuffle/CodeModal.tsx new file mode 100644 index 0000000..4c37f2d --- /dev/null +++ b/example/src/pages/shuffle/CodeModal.tsx @@ -0,0 +1,34 @@ +import { Modal, Stack, Text, Code } from "@mantine/core"; + +interface CodeModalProps { + opened: boolean; + onClose: () => void; +} + +export function CodeModal({ opened, onClose }: CodeModalProps) { + return ( + + + + This code snippet shows how to get a random song using the Convex + Aggregate: + + + {`const randomMusic = await randomize.random(ctx); +if (!randomMusic) return null; +const doc = (await ctx.db.get(randomMusic.id))!; +return doc.title;`} + + + From: convex/shuffle.ts -{" "} + getRandomMusicTitle handler + + + + ); +} diff --git a/example/src/pages/shuffle/RandomSongPicker.tsx b/example/src/pages/shuffle/RandomSongPicker.tsx new file mode 100644 index 0000000..6f7fb26 --- /dev/null +++ b/example/src/pages/shuffle/RandomSongPicker.tsx @@ -0,0 +1,68 @@ +import { + Card, + Stack, + Group, + Title, + Text, + Badge, + Button, + ActionIcon, +} from "@mantine/core"; +import { IconRefresh, IconCode } from "@tabler/icons-react"; + +interface RandomSongPickerProps { + randomMusic: string | null | undefined; + onRefresh: () => void; + onShowCode: () => void; +} + +export function RandomSongPicker({ + randomMusic, + onRefresh, + onShowCode, +}: RandomSongPickerProps) { + return ( + + + + + + + Random Song Picker + + + + + + + + Get any random song in O(log n) time - no matter how many songs you + have! + + + + + + Current Random Song + + + {randomMusic || "Loading..."} + + + + + + + ); +} diff --git a/example/src/pages/shuffle/ShuffleAside.tsx b/example/src/pages/shuffle/ShuffleAside.tsx new file mode 100644 index 0000000..28bda76 --- /dev/null +++ b/example/src/pages/shuffle/ShuffleAside.tsx @@ -0,0 +1,17 @@ +import { Stack } from "@mantine/core"; +import { AddMusicSection } from "./AddMusicSection"; + +export function ShuffleAside() { + return ( + + + + ); +} diff --git a/example/src/pages/shuffle/ShufflePage.tsx b/example/src/pages/shuffle/ShufflePage.tsx index d76d930..46c77bb 100644 --- a/example/src/pages/shuffle/ShufflePage.tsx +++ b/example/src/pages/shuffle/ShufflePage.tsx @@ -1,48 +1,18 @@ -import { useMutation, useQuery } from "convex/react"; +import { useQuery } from "convex/react"; import { api } from "../../../convex/_generated/api"; -import { - Title, - Text, - Card, - Stack, - Group, - TextInput, - Button, - Badge, - Alert, - List, - ThemeIcon, - Code, - Paper, - Grid, - Divider, - Anchor, - ActionIcon, - Modal, -} from "@mantine/core"; -import { - IconArrowsShuffle, - IconMusic, - IconRocket, - IconDatabase, - IconChartBar, - IconBolt, - IconInfoCircle, - IconRefresh, - IconCode, -} from "@tabler/icons-react"; +import { Stack, AppShell, Container } from "@mantine/core"; +import { IconArrowsShuffle } from "@tabler/icons-react"; import { useState } from "react"; -import { useApiErrorHandler } from "@/utils/errors"; -import { - useStableQuery, - useRicherStableQuery, -} from "../../utils/useStableQuery"; +import { useRicherStableQuery } from "../../utils/useStableQuery"; import { CommonAppShell } from "@/common/CommonAppShell"; +import { PageHeader } from "../../common/PageHeader"; +import { ShuffleStats } from "./ShuffleStats"; +import { RandomSongPicker } from "./RandomSongPicker"; +import { ShufflePlaylist } from "./ShufflePlaylist"; +import { ShuffleAside } from "./ShuffleAside"; +import { CodeModal } from "./CodeModal"; export function ShufflePage() { - const onApiError = useApiErrorHandler(); - - const [title, setTitle] = useState(""); const [seed, setSeed] = useState("music"); const [currentPage, setCurrentPage] = useState(1); const [pageSize] = useState(5); @@ -65,293 +35,60 @@ export function ShufflePage() { } ); - const addMusic = useMutation(api.shuffle.addMusic); - return ( - - - {/* Header */} - - - - Random Access & Shuffle Demo - - - - - Efficient random selection and deterministic shuffling using Convex - Aggregate - - - - - - - - View the source: - - - convex/shuffle.ts - - - - - - - {/* Left Column - Music Demo */} - - - {/* Live Stats */} - - - - - - - - Total songs in library:{" "} - {totalMusic ?? 0} - - - - - - - - Random access: O(log n) - - - - - - {/* Random Selection */} - - - - - - - Random Song Picker - - - setCodeModalOpened(true)} - > - - - - - Get any random song in O(log n) time - no matter how many - songs you have! - - - - - - Current Random Song - - - {randomMusic ?? "Loading..."} - - - - - - - - {/* Shuffled Playlist */} - - - - - - Deterministic Shuffle - - - - Same seed = same shuffle order. Change the seed for a - completely different shuffle! - - - - setSeed(e.target.value)} - placeholder="Enter seed for shuffle" - style={{ flex: 1 }} - size="sm" - /> - - - - {shuffledMusicResult && - shuffledMusicResult.items.length > 0 ? ( - - - - Shuffled playlist ({shuffledMusicResult.totalCount}{" "} - songs) - - - Page {shuffledMusicResult.currentPage} of{" "} - {shuffledMusicResult.totalPages} - - - - - {shuffledMusicResult.items.map((song, index) => ( - - - - {(currentPage - 1) * pageSize + index + 1} - - {song} - - - ))} - - - - - - - - ) : ( - } - > - Add some music to see the shuffled playlist! - - )} - - - - - - {/* Right Column - Add Music */} - - - - - - - - Add Music - - - - Watch the count update instantly! ⚡ - - - setTitle(e.target.value)} - placeholder="e.g., Bohemian Rhapsody - Queen" - size="sm" - /> - - - } - > - - Add songs and watch the random picker and shuffle work - instantly! The aggregate maintains perfect performance - even with thousands of songs. - - - - - - - - - {/* Code Modal */} - setCodeModalOpened(false)} - title="Random Song Picker Implementation" - size="lg" - > - - - This code snippet shows how to get a random song using the Convex - Aggregate: - - - {`const randomMusic = await randomize.random(ctx); -if (!randomMusic) return null; -const doc = (await ctx.db.get(randomMusic.id))!; -return doc.title;`} - - - From: convex/shuffle.ts -{" "} - getRandomMusicTitle handler - - - - + + + + } + appShellProps={{ + aside: { + width: 300, + breakpoint: "md", + collapsed: { + desktop: false, + mobile: true, + }, + }, + }} + > + + + } + filename="shuffle.ts" + /> + + + + setCacheBuster((prev) => prev + 1)} + onShowCode={() => setCodeModalOpened(true)} + /> + + setCurrentPage(1)} + onPreviousPage={() => setCurrentPage(currentPage - 1)} + onNextPage={() => setCurrentPage(currentPage + 1)} + /> + + + + setCodeModalOpened(false)} + /> ); } diff --git a/example/src/pages/shuffle/ShufflePlaylist.tsx b/example/src/pages/shuffle/ShufflePlaylist.tsx new file mode 100644 index 0000000..2de29f2 --- /dev/null +++ b/example/src/pages/shuffle/ShufflePlaylist.tsx @@ -0,0 +1,134 @@ +import { + Card, + Stack, + Group, + Title, + Text, + TextInput, + Button, + List, + Badge, + Alert, +} from "@mantine/core"; +import { IconArrowsShuffle, IconInfoCircle } from "@tabler/icons-react"; + +interface ShuffledMusicResult { + items: string[]; + totalCount: number; + currentPage: number; + totalPages: number; + hasPrevPage: boolean; + hasNextPage: boolean; +} + +interface ShufflePlaylistProps { + seed: string; + onSeedChange: (seed: string) => void; + currentPage: number; + pageSize: number; + shuffledMusicResult: ShuffledMusicResult | undefined; + isLoading: boolean; + onNewShuffle: () => void; + onPreviousPage: () => void; + onNextPage: () => void; +} + +export function ShufflePlaylist({ + seed, + onSeedChange, + currentPage, + pageSize, + shuffledMusicResult, + isLoading, + onNewShuffle, + onPreviousPage, + onNextPage, +}: ShufflePlaylistProps) { + return ( + + + + + + Deterministic Shuffle + + + + Same seed = same shuffle order. Change the seed for a completely + different shuffle! + + + + onSeedChange(e.target.value)} + placeholder="Enter seed for shuffle" + style={{ flex: 1 }} + size="sm" + /> + + + + {shuffledMusicResult && shuffledMusicResult.items.length > 0 ? ( + + + + Shuffled playlist ({shuffledMusicResult.totalCount} songs) + + + Page {shuffledMusicResult.currentPage} of{" "} + {shuffledMusicResult.totalPages} + + + + + {shuffledMusicResult.items.map((song, index) => ( + + + + {(currentPage - 1) * pageSize + index + 1} + + {song} + + + ))} + + + + + + + + ) : ( + }> + Add some music to see the shuffled playlist! + + )} + + + ); +} diff --git a/example/src/pages/shuffle/ShuffleStats.tsx b/example/src/pages/shuffle/ShuffleStats.tsx new file mode 100644 index 0000000..a8bae1a --- /dev/null +++ b/example/src/pages/shuffle/ShuffleStats.tsx @@ -0,0 +1,32 @@ +import { Card, Group, Text, Badge, ThemeIcon } from "@mantine/core"; +import { IconChartBar, IconBolt } from "@tabler/icons-react"; + +interface ShuffleStatsProps { + totalMusic: number | undefined; +} + +export function ShuffleStats({ totalMusic }: ShuffleStatsProps) { + return ( + + + + + + + + Total songs in library:{" "} + {totalMusic ?? 0} + + + + + + + + Random access: O(log n) + + + + + ); +} diff --git a/example/src/pages/stats/StatsPage.tsx b/example/src/pages/stats/StatsPage.tsx index a918130..4659c89 100644 --- a/example/src/pages/stats/StatsPage.tsx +++ b/example/src/pages/stats/StatsPage.tsx @@ -2,7 +2,6 @@ import { useMutation, useQuery } from "convex/react"; import { api } from "../../../convex/_generated/api"; import { Title, - Text, Card, Stack, Group, @@ -10,12 +9,12 @@ import { Button, Alert, SimpleGrid, - Anchor, } from "@mantine/core"; -import { IconChartPie, IconCode } from "@tabler/icons-react"; +import { IconChartPie } from "@tabler/icons-react"; import { useState } from "react"; import { StatsGrid } from "../../common/StatsGrid"; import { CommonAppShell } from "@/common/CommonAppShell"; +import { PageHeader } from "../../common/PageHeader"; export function StatsPage() { const [latency, setLatency] = useState(""); @@ -27,36 +26,12 @@ export function StatsPage() { return ( - - - - Stats Demo - - - - - Direct aggregation without table dependencies - perfect for analytics - and metrics - - - - - - - - View the source: - - - convex/stats.ts - - - - + } + filename="stats.ts" + /> {/* Add Latency Section */} From 66ddd9f2dd411274182707112da21fabacf041f5 Mon Sep 17 00:00:00 2001 From: Mike Cann Date: Wed, 6 Aug 2025 15:43:37 +0800 Subject: [PATCH 59/77] better splitting up of the components with asides --- example/src/pages/photos/AddPhotosSection.tsx | 132 +++++++ .../src/pages/photos/AlbumBrowserSection.tsx | 77 +++++ .../src/pages/photos/PhotoGallerySection.tsx | 86 +++++ example/src/pages/photos/PhotosAside.tsx | 21 ++ example/src/pages/photos/PhotosPage.tsx | 322 +++--------------- .../src/pages/stats/ReportLatencySection.tsx | 52 +++ example/src/pages/stats/StatsAside.tsx | 17 + .../src/pages/stats/StatsDisplaySection.tsx | 26 ++ example/src/pages/stats/StatsPage.tsx | 115 ++----- 9 files changed, 496 insertions(+), 352 deletions(-) create mode 100644 example/src/pages/photos/AddPhotosSection.tsx create mode 100644 example/src/pages/photos/AlbumBrowserSection.tsx create mode 100644 example/src/pages/photos/PhotoGallerySection.tsx create mode 100644 example/src/pages/photos/PhotosAside.tsx create mode 100644 example/src/pages/stats/ReportLatencySection.tsx create mode 100644 example/src/pages/stats/StatsAside.tsx create mode 100644 example/src/pages/stats/StatsDisplaySection.tsx diff --git a/example/src/pages/photos/AddPhotosSection.tsx b/example/src/pages/photos/AddPhotosSection.tsx new file mode 100644 index 0000000..fda655b --- /dev/null +++ b/example/src/pages/photos/AddPhotosSection.tsx @@ -0,0 +1,132 @@ +import { useMutation } from "convex/react"; +import { api } from "../../../convex/_generated/api"; +import { + Card, + Stack, + Group, + Title, + Text, + TextInput, + Button, + ActionIcon, +} from "@mantine/core"; +import { IconDatabase, IconDice, IconEdit } from "@tabler/icons-react"; +import { useState } from "react"; +import { useApiErrorHandler } from "@/utils/errors"; + +interface AddPhotosSectionProps { + onPhotoAdded: (album: string) => void; +} + +export function AddPhotosSection({ onPhotoAdded }: AddPhotosSectionProps) { + const onApiError = useApiErrorHandler(); + const [newAlbum, setNewAlbum] = useState(""); + const [url, setUrl] = useState(""); + const [isRandomMode, setIsRandomMode] = useState(true); + + const addPhoto = useMutation(api.photos.addPhoto); + + // Array of known valid Unsplash photo URLs + const validPhotoUrls = [ + "https://images.unsplash.com/photo-1506905925346-21bda4d32df4", + "https://images.unsplash.com/photo-1441974231531-c6227db76b6e", + "https://images.unsplash.com/photo-1449824913935-59a10b8d2000", + "https://images.unsplash.com/photo-1444723121867-7a241cacace9", + "https://images.unsplash.com/photo-1507003211169-0a1dd7228f2d", + "https://images.unsplash.com/photo-1518837695005-2083093ee35b", + "https://images.unsplash.com/photo-1500648767791-00dcc994a43e", + "https://images.unsplash.com/photo-1472214103451-9374bd1c798e", + "https://images.unsplash.com/photo-1469474968028-56623f02e42e", + "https://images.unsplash.com/photo-1426604966848-d7adac402bff", + "https://images.unsplash.com/photo-1501594907352-04cda38ebc29", + "https://images.unsplash.com/photo-1493246507139-91e8fad9978e", + "https://images.unsplash.com/photo-1506905925346-21bda4d32df4", + "https://images.unsplash.com/photo-1519904981063-b0cf448d479e", + "https://images.unsplash.com/photo-1511593358241-7eea1f3c84e5", + "https://images.unsplash.com/photo-1418065460487-3956ef138493", + "https://images.unsplash.com/photo-1470071459604-3b5ec3a7fe05", + "https://images.unsplash.com/photo-1551698618-1dfe5d97d256", + "https://images.unsplash.com/photo-1477346611705-65d1883cee1e", + "https://images.unsplash.com/photo-1540206395-68808572332f", + ]; + + // Function to pick a random photo from the valid URLs array + const generateRandomPhotoUrl = () => { + const randomIndex = Math.floor(Math.random() * validPhotoUrls.length); + return validPhotoUrls[randomIndex]; + }; + + const handleAddPhoto = () => { + if (!newAlbum) return; + + const photoUrl = isRandomMode ? generateRandomPhotoUrl() : url; + if (!photoUrl) return; + + addPhoto({ album: newAlbum, url: photoUrl }) + .then(() => { + if (!isRandomMode) setUrl(""); + // Notify parent that a photo was added to this album + onPhotoAdded(newAlbum); + }) + .catch(onApiError); + }; + + return ( + + + + + + Add Photos + + + + Watch counts update instantly! ⚡ + + + setNewAlbum(e.target.value)} + placeholder="e.g., Nature, Cities, People" + size="sm" + /> + setUrl(e.target.value)} + placeholder={ + isRandomMode + ? "Random photo will be generated" + : "https://images.unsplash.com/..." + } + disabled={isRandomMode} + size="sm" + rightSection={ + setIsRandomMode(!isRandomMode)} + title={ + isRandomMode + ? "Switch to manual URL input" + : "Switch to random photo" + } + > + {isRandomMode ? : } + + } + rightSectionPointerEvents="all" + /> + + + + ); +} diff --git a/example/src/pages/photos/AlbumBrowserSection.tsx b/example/src/pages/photos/AlbumBrowserSection.tsx new file mode 100644 index 0000000..a4e8a34 --- /dev/null +++ b/example/src/pages/photos/AlbumBrowserSection.tsx @@ -0,0 +1,77 @@ +import { useQuery } from "convex/react"; +import { api } from "../../../convex/_generated/api"; +import { + Card, + Stack, + Group, + Text, + Select, + Badge, + ThemeIcon, +} from "@mantine/core"; +import { IconChartBar, IconBolt } from "@tabler/icons-react"; + +interface AlbumBrowserSectionProps { + selectedAlbum: string; + onAlbumChange: (album: string) => void; + currentPage: number; + totalPages: number; +} + +export function AlbumBrowserSection({ + selectedAlbum, + onAlbumChange, + currentPage, + totalPages, +}: AlbumBrowserSectionProps) { + // Get available albums with counts + const albums = useQuery(api.photos.availableAlbums); + + // Get total count for the selected album + const totalPhotos = useQuery(api.photos.photoCount, { album: selectedAlbum }); + + return ( + + + + + Browse Albums: + + {albums && ( + value && setSelectedAlbum(value)} - data={albums.map((album) => ({ - value: album.name, - label: `${album.name} (${album.count} photos)`, - }))} - style={{ minWidth: 200 }} - /> - )} - - - {totalPhotos !== undefined && ( - - - - - - - Total photos in {selectedAlbum}:{" "} - {totalPhotos} - - - - - - - - Page {currentPage} of {totalPages}{" "} - - - - )} - - - - {/* Photo Gallery */} - - - - Photo Gallery - - {isLoading && } - - - {photos && photos.length > 0 ? ( - - - {photos.map((photoUrl, index) => ( - - {`Photo - - #{(currentPage - 1) * pageSize + index + 1} - - - ))} - - - {totalPages > 1 && ( - - - - )} - - ) : ( - } - > - Switch to a different album or add some photos to get - started! - - )} - - - - - {/* Right Column - Add Photos */} - - - {/* Add Photos - Watch it update live! */} - - - - - - Add Photos - - - - Watch counts update instantly! ⚡ - - - setNewAlbum(e.target.value)} - placeholder="e.g., Nature, Cities, People" - size="sm" - /> - setUrl(e.target.value)} - placeholder={ - isRandomMode - ? "Random photo will be generated" - : "https://images.unsplash.com/..." - } - disabled={isRandomMode} - size="sm" - rightSection={ - setIsRandomMode(!isRandomMode)} - title={ - isRandomMode - ? "Switch to manual URL input" - : "Switch to random photo" - } - > - {isRandomMode ? ( - - ) : ( - - )} - - } - rightSectionPointerEvents="all" - /> - - - - - - - + + + + } + appShellProps={{ + aside: { + width: 300, + breakpoint: "md", + collapsed: { + desktop: false, + mobile: true, + }, + }, + }} + > + + + } + filename="photos.ts" + /> + + + + + + ); } diff --git a/example/src/pages/stats/ReportLatencySection.tsx b/example/src/pages/stats/ReportLatencySection.tsx new file mode 100644 index 0000000..d0a1d66 --- /dev/null +++ b/example/src/pages/stats/ReportLatencySection.tsx @@ -0,0 +1,52 @@ +import { useMutation } from "convex/react"; +import { api } from "../../../convex/_generated/api"; +import { Card, Stack, Title, Group, NumberInput, Button } from "@mantine/core"; +import { useState } from "react"; + +export function ReportLatencySection() { + const [latency, setLatency] = useState(""); + + const reportLatency = useMutation(api.stats.reportLatency); + + const handleReportLatency = () => { + if (latency !== "") { + reportLatency({ latency: latency }) + .then(() => { + setLatency(""); + }) + .catch(console.error); + } + }; + + return ( + + + + Report Latency + + + + setLatency( + value === "" ? "" : typeof value === "number" ? value : "" + ) + } + placeholder="Enter latency value" + min={0} + size="sm" + /> + + + + + ); +} diff --git a/example/src/pages/stats/StatsAside.tsx b/example/src/pages/stats/StatsAside.tsx new file mode 100644 index 0000000..edf49a9 --- /dev/null +++ b/example/src/pages/stats/StatsAside.tsx @@ -0,0 +1,17 @@ +import { Stack } from "@mantine/core"; +import { ReportLatencySection } from "./ReportLatencySection"; + +export function StatsAside() { + return ( + + + + ); +} diff --git a/example/src/pages/stats/StatsDisplaySection.tsx b/example/src/pages/stats/StatsDisplaySection.tsx new file mode 100644 index 0000000..886cdc1 --- /dev/null +++ b/example/src/pages/stats/StatsDisplaySection.tsx @@ -0,0 +1,26 @@ +import { useQuery } from "convex/react"; +import { api } from "../../../convex/_generated/api"; +import { Card, Stack, Title, Alert } from "@mantine/core"; +import { StatsGrid } from "../../common/StatsGrid"; + +export function StatsDisplaySection() { + const stats = useQuery(api.stats.getStats); + + return ( + + + + Latency Statistics + + + {stats ? ( + + ) : ( + + Report some latency values to see the statistics! + + )} + + + ); +} diff --git a/example/src/pages/stats/StatsPage.tsx b/example/src/pages/stats/StatsPage.tsx index 4659c89..5282c4f 100644 --- a/example/src/pages/stats/StatsPage.tsx +++ b/example/src/pages/stats/StatsPage.tsx @@ -1,93 +1,42 @@ -import { useMutation, useQuery } from "convex/react"; -import { api } from "../../../convex/_generated/api"; -import { - Title, - Card, - Stack, - Group, - NumberInput, - Button, - Alert, - SimpleGrid, -} from "@mantine/core"; +import { Stack, AppShell, Container } from "@mantine/core"; import { IconChartPie } from "@tabler/icons-react"; -import { useState } from "react"; -import { StatsGrid } from "../../common/StatsGrid"; import { CommonAppShell } from "@/common/CommonAppShell"; import { PageHeader } from "../../common/PageHeader"; +import { StatsDisplaySection } from "./StatsDisplaySection"; +import { StatsAside } from "./StatsAside"; export function StatsPage() { - const [latency, setLatency] = useState(""); - - const stats = useQuery(api.stats.getStats); - - const reportLatency = useMutation(api.stats.reportLatency); - return ( - - - } - filename="stats.ts" - /> - - {/* Add Latency Section */} - - - - Report Latency - - - - setLatency( - value === "" ? "" : typeof value === "number" ? value : "" - ) - } - placeholder="Enter latency value" - min={0} - style={{ flex: 1 }} - /> - - - - - - {/* Statistics Display */} - - - - Latency Statistics - + + + + } + appShellProps={{ + aside: { + width: 300, + breakpoint: "md", + collapsed: { + desktop: false, + mobile: true, + }, + }, + }} + > + + + } + filename="stats.ts" + /> - {stats ? ( - - ) : ( - - Report some latency values to see the statistics! - - )} - - - + + + ); } From 9339ee1ce81e88f202210c3f8751826bb8794938 Mon Sep 17 00:00:00 2001 From: Mike Cann Date: Wed, 6 Aug 2025 15:44:15 +0800 Subject: [PATCH 60/77] bounds optional --- example/convex/leaderboard.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/example/convex/leaderboard.ts b/example/convex/leaderboard.ts index bdb6dfd..1de2242 100644 --- a/example/convex/leaderboard.ts +++ b/example/convex/leaderboard.ts @@ -90,7 +90,6 @@ export const pageOfScores = query({ let skipped = 0; for await (const { id, key: _key } of aggregateByScore.iter(ctx, { - bounds: undefined, order: "desc", })) { // Skip items until we reach the offset From 7d6f1f99937f1c355d43336560d0b71428e893ca Mon Sep 17 00:00:00 2001 From: Mike Cann Date: Wed, 6 Aug 2025 15:51:43 +0800 Subject: [PATCH 61/77] tidy up the page lookup --- example/convex/leaderboard.ts | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/example/convex/leaderboard.ts b/example/convex/leaderboard.ts index 1de2242..b0c8fa3 100644 --- a/example/convex/leaderboard.ts +++ b/example/convex/leaderboard.ts @@ -89,9 +89,7 @@ export const pageOfScores = query({ let count = 0; let skipped = 0; - for await (const { id, key: _key } of aggregateByScore.iter(ctx, { - order: "desc", - })) { + for await (const item of aggregateByScore.iter(ctx, { order: "desc" })) { // Skip items until we reach the offset if (skipped < offset) { skipped += 1; @@ -99,11 +97,9 @@ export const pageOfScores = query({ } // Stop when we have enough items - if (count >= numItems) { - break; - } + if (count >= numItems) break; - const doc = await ctx.db.get(id); + const doc = await ctx.db.get(item.id); if (!doc) continue; scores.push(doc); count += 1; From fc5547d8ed9da12ddb5c1f6b6c5206f88fe9ba00 Mon Sep 17 00:00:00 2001 From: Mike Cann Date: Thu, 7 Aug 2025 12:00:07 +0800 Subject: [PATCH 62/77] tidied up a couple of things --- example/convex/crons.ts | 2 +- example/convex/leaderboard.ts | 47 +++++++------------ example/convex/schema.ts | 2 +- .../src/pages/leaderboard/AddScoreSection.tsx | 4 +- 4 files changed, 22 insertions(+), 33 deletions(-) diff --git a/example/convex/crons.ts b/example/convex/crons.ts index 77440a0..53aae6e 100644 --- a/example/convex/crons.ts +++ b/example/convex/crons.ts @@ -18,7 +18,7 @@ export const resetAndSeed = internalMutation({ ctx.runMutation(internal.btree.resetAll), ]); - await ctx.runMutation(api.leaderboard.add100MockScores); + await ctx.runMutation(api.leaderboard.addMockScores, { count: 500 }); // Add some initial photos await ctx.runMutation(internal.photos.addPhotos, { diff --git a/example/convex/leaderboard.ts b/example/convex/leaderboard.ts index b0c8fa3..5c0de72 100644 --- a/example/convex/leaderboard.ts +++ b/example/convex/leaderboard.ts @@ -14,16 +14,14 @@ import { DataModel } from "../../example/convex/_generated/dataModel"; import { v } from "convex/values"; import { Migrations } from "@convex-dev/migrations"; -export const migrations = new Migrations(components.migrations); -export const run = migrations.runner(); - const aggregateByScore = new TableAggregate<{ Key: number; DataModel: DataModel; TableName: "leaderboard"; }>(components.aggregateByScore, { - sortKey: (doc) => doc.score, + sortKey: (doc) => -doc.score, }); + const aggregateScoreByUser = new TableAggregate<{ Key: [string, number]; DataModel: DataModel; @@ -85,27 +83,13 @@ export const pageOfScores = query({ numItems: v.number(), }, handler: async (ctx, { offset, numItems }) => { - const scores = []; - let count = 0; - let skipped = 0; - - for await (const item of aggregateByScore.iter(ctx, { order: "desc" })) { - // Skip items until we reach the offset - if (skipped < offset) { - skipped += 1; - continue; - } - - // Stop when we have enough items - if (count >= numItems) break; - - const doc = await ctx.db.get(item.id); - if (!doc) continue; - scores.push(doc); - count += 1; - } + const firstInPage = await aggregateByScore.at(ctx, offset); - return scores; + return await ctx.db + .query("leaderboard") + .withIndex("by_score", (q) => q.lte("score", -firstInPage.key)) + .order("desc") + .take(numItems); }, }); @@ -117,7 +101,7 @@ export const rankOfScore = query({ score: v.number(), }, handler: async (ctx, args) => { - return await aggregateByScore.indexOf(ctx, args.score, { order: "desc" }); + return await aggregateByScore.indexOf(ctx, -args.score); }, }); @@ -156,10 +140,12 @@ export const sumNumbers = query({ }, }); -export const add100MockScores = mutation({ - args: {}, +export const addMockScores = mutation({ + args: { + count: v.number(), + }, returns: v.null(), - handler: async (ctx) => { + handler: async (ctx, args) => { const playerNames = [ "Jamie", "James", @@ -182,7 +168,7 @@ export const add100MockScores = mutation({ ]; const mockScores = []; - for (let i = 0; i < 100; i++) { + for (let i = 0; i < args.count; i++) { const randomName = playerNames[Math.floor(Math.random() * playerNames.length)]; // Generate scores with some variety - mostly between 100-1000, with some outliers @@ -216,6 +202,9 @@ export const add100MockScores = mutation({ // ---- migrations ---- +export const migrations = new Migrations(components.migrations); +export const run = migrations.runner(); + export const backfillAggregatesMigration = migrations.define({ table: "leaderboard", migrateOne: async (ctx, doc) => { diff --git a/example/convex/schema.ts b/example/convex/schema.ts index e198b0f..a2cfcb1 100644 --- a/example/convex/schema.ts +++ b/example/convex/schema.ts @@ -5,7 +5,7 @@ export default defineSchema({ leaderboard: defineTable({ name: v.string(), score: v.number(), - }), + }).index("by_score", ["score"]), music: defineTable({ title: v.string(), }), diff --git a/example/src/pages/leaderboard/AddScoreSection.tsx b/example/src/pages/leaderboard/AddScoreSection.tsx index 9ac1b9f..95d81af 100644 --- a/example/src/pages/leaderboard/AddScoreSection.tsx +++ b/example/src/pages/leaderboard/AddScoreSection.tsx @@ -20,7 +20,7 @@ export function AddScoreSection() { const [isAddingMockScores, setIsAddingMockScores] = useState(false); const addScore = useMutation(api.leaderboard.addScore); - const addMockScores = useMutation(api.leaderboard.add100MockScores); + const addMockScores = useMutation(api.leaderboard.addMockScores); return ( @@ -65,7 +65,7 @@ export function AddScoreSection() { - - + ))} diff --git a/example/src/pages/leaderboard/LeaderboardTableRow.tsx b/example/src/pages/leaderboard/LeaderboardTableRow.tsx new file mode 100644 index 0000000..dcc64f9 --- /dev/null +++ b/example/src/pages/leaderboard/LeaderboardTableRow.tsx @@ -0,0 +1,139 @@ +import { useState } from "react"; +import { useMutation } from "convex/react"; +import { api } from "../../../convex/_generated/api"; +import { + Table, + Button, + ActionIcon, + Group, + TextInput, + NumberInput, +} from "@mantine/core"; +import { IconEdit, IconCheck, IconX, IconTrash } from "@tabler/icons-react"; +import { useApiErrorHandler } from "@/utils/errors"; +import { Id } from "../../../convex/_generated/dataModel"; + +interface LeaderboardTableRowProps { + score: { + _id: Id<"leaderboard">; + name: string; + score: number; + }; + rank: number; + onRemove: (id: Id<"leaderboard">) => void; +} + +export function LeaderboardTableRow({ + score, + rank, + onRemove, +}: LeaderboardTableRowProps) { + const [isEditing, setIsEditing] = useState(false); + const [editName, setEditName] = useState(score.name); + const [editScore, setEditScore] = useState(score.score); + + const onApiError = useApiErrorHandler(); + const updateScore = useMutation(api.leaderboard.updateScore); + + const handleEdit = () => { + setEditName(score.name); + setEditScore(score.score); + setIsEditing(true); + }; + + if (isEditing) { + return ( + + {rank} + + setEditName(event.currentTarget.value)} + size="xs" + placeholder="Player name" + w="100%" + maw={120} + styles={{ + input: { backgroundColor: "var(--mantine-color-dark-6)" }, + }} + /> + + + setEditScore(Number(value) || 0)} + size="xs" + placeholder="Score" + min={0} + w="100%" + maw={80} + styles={{ + input: { backgroundColor: "var(--mantine-color-dark-6)" }, + }} + /> + + + + { + if (editName.trim() === "" || editScore === null) return; + + await updateScore({ + id: score._id, + name: editName.trim(), + score: editScore, + }).catch(onApiError); + + setIsEditing(false); + }} + disabled={editName.trim() === "" || editScore === null} + > + + + { + setEditName(score.name); + setEditScore(score.score); + setIsEditing(false); + }} + > + + + + + + ); + } + + return ( + + {rank} + {score.name} + {score.score} + + + + + + onRemove(score._id)} + > + + + + + + ); +} From 32059b3a63f913210d4fac4fb6bff454f90af65a Mon Sep 17 00:00:00 2001 From: Mike Cann Date: Thu, 7 Aug 2025 13:02:54 +0800 Subject: [PATCH 64/77] polishing with a convex logo --- example/src/common/AppShellHeader.tsx | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/example/src/common/AppShellHeader.tsx b/example/src/common/AppShellHeader.tsx index 228333c..b25b551 100644 --- a/example/src/common/AppShellHeader.tsx +++ b/example/src/common/AppShellHeader.tsx @@ -1,12 +1,15 @@ -import { Text, Group, Button } from "@mantine/core"; +import { Text, Group, Button, Image } from "@mantine/core"; import { IconBrandGithub, IconExternalLink } from "@tabler/icons-react"; export function AppShellHeader() { return ( - - Convex Aggregate Demo - + + Convex Logo + + Convex Aggregate Demo + +