+ )}
{/* Wrap content with CopyableContent */}
@@ -36,14 +40,37 @@ export default async function DocsPage({params: {slug = []}}: PageProps) {
);
}
-export async function generateMetadata({params: {slug = []}}: PageProps) {
- const pathName = slug.join('/');
+export async function generateMetadata({params}: PageProps) {
+ const {slug: slugParams} = await params;
+ const pathName = slugParams.join('/');
const res = await getDocsForSlug(pathName);
if (!res) return null;
const {frontmatter} = res;
- return {title: frontmatter.title, description: frontmatter.description};
+
+ const encode = (str: string | undefined) => {
+ if (!str) return '';
+ return encodeURIComponent(str);
+ };
+
+ const ogImageUrl = `/api/og?title=${encode(frontmatter.title)}&subtitle=${encode(frontmatter.description)}`;
+
+ return {
+ title: frontmatter.title,
+ description: frontmatter.description,
+ openGraph: {
+ title: frontmatter.title,
+ description: frontmatter.description,
+ images: ogImageUrl,
+ },
+ twitter: {
+ card: 'summary_large_image',
+ title: frontmatter.title,
+ description: frontmatter.description,
+ images: ogImageUrl,
+ },
+ };
}
export function generateStaticParams() {
- return page_routes.map(item => ({slug: item.href.split('/').slice(1)}));
+ return getAllPageSlugs();
}
diff --git a/app/docs/layout.tsx b/app/docs/layout.tsx
index 16ab553d..ed8772cd 100644
--- a/app/docs/layout.tsx
+++ b/app/docs/layout.tsx
@@ -1,5 +1,10 @@
import {Leftbar} from '@/components/leftbar';
+// Force this layout to be fully static at build time and restrict to generated params
+export const dynamic = 'force-static';
+export const dynamicParams = false;
+export const revalidate = false;
+
export default function DocsLayout({
children,
}: Readonly<{
diff --git a/app/fonts/muoto-bold.woff b/app/fonts/muoto-bold.woff
new file mode 100644
index 00000000..4fc3690c
Binary files /dev/null and b/app/fonts/muoto-bold.woff differ
diff --git a/app/fonts/muoto-regular.woff b/app/fonts/muoto-regular.woff
new file mode 100644
index 00000000..fee53a01
Binary files /dev/null and b/app/fonts/muoto-regular.woff differ
diff --git a/app/page.tsx b/app/page.tsx
index 28fd1d44..d08bd515 100644
--- a/app/page.tsx
+++ b/app/page.tsx
@@ -155,9 +155,9 @@ export default function Home() {
server-rendered web app.
- Zero is currently in public alpha. It's got a few rough edges, and you
- have to deploy it yourself, but it's already remarkably fun. We're
- using it ourselves for Zero's{' '}
+ Zero is currently in public alpha. It's got a few rough edges, and
+ you have to deploy it yourself, but it's already remarkably fun.
+ We're using it ourselves for Zero's{' '}
official bug tracker
{' '}
@@ -170,7 +170,7 @@ export default function Home() {
diff --git a/assets/search-index.json b/assets/search-index.json
index b643b8bb..80e4c990 100644
--- a/assets/search-index.json
+++ b/assets/search-index.json
@@ -3,14 +3,14 @@
"id": "0-add-to-existing-project",
"title": "Add to Existing Project",
"url": "/docs/add-to-existing-project",
- "content": "Zero integrates easily into most JavaScript or TypeScript projects, whether you're using React, Vue, Svelte, Solid, or vanilla JavaScript. Prerequisites A PostgreSQL database with Write-Ahead Logging (WAL) enabled. See Connecting to Postgres for setup instructions. If you are using TypeScript ensure that strictNullChecks is set to true in tsconfig.json. If this is not set then the advanced types Zero uses do not work as expected. Installation Install the Zero package: ```bash npm install @rocicorp/zero ``` Zero's server component depends on @rocicorp/zero-sqlite3, which contains a binary that requires running a postinstall script. Most alternative package managers (non-npm) disable these scripts by default for security reasons. Here's how to enable installation for common alternatives: pnpm For pnpm, either: Run pnpm approve-builds to approve all build scripts, or Add the specific dependency to your package.json: ```json \"pnpm\": { \"onlyBuiltDependencies\": [ \"@rocicorp/zero-sqlite3\" ] } ``` Bun For Bun, add the dependency to your trusted dependencies list: ```json \"trustedDependencies\": [ \"@rocicorp/zero-sqlite3\" ], ``` Environment Variables Configure Zero by creating a .env file in your project root: ```bash ZERO_UPSTREAM_DB=\"postgresql://user:password@127.0.0.1/postgres\" ZERO_REPLICA_FILE=\"/tmp/sync-replica.db\" ``` Replace the placeholders with your database connection details. For more options, see configuration options. Starting the Server Start the Zero server using the CLI: ```bash npx zero-cache-dev ``` The server runs on port 4848 by default. To verify, open http://localhost:4848 in your browser. If everything is configured correctly, you'll see \"OK\". Defining Your Schema Define your data model schema as described in the Zero schema documentation. Example: ```ts // schema.ts import {createSchema, table, string} from '@rocicorp/zero'; const message = table('message') .columns({ id: string(), body: string(), }) .primaryKey('id'); export const schema = createSchema({ tables: [message], }); export type Schema = typeof schema; ``` If you're using Prisma or Drizzle, you can convert their schemas to Zero schemas using tools listed in the community section. Permissions Update schema.ts to include permissions for your tables. For example, to allow all users to read and write to the message table, add the following: ```ts // schema.ts import {ANYONE_CAN_DO_ANYTHING, definePermissions} from '@rocicorp/zero'; export const permissions = definePermissions(schema, () => ({ message: ANYONE_CAN_DO_ANYTHING, })); ``` For more details, see permissions. Creating a Zero Instance To create a Zero client instance: ```js import {Zero} from '@rocicorp/zero'; const z = new Zero({ userID: 'anon', server: 'http://localhost:4848', schema, }); ``` In production, avoid hardcoding the server URL. Use environment variables like import.meta.env.VITE\\_PUBLIC\\_SERVER or process.env.NEXT\\_PUBLIC\\_SERVER. Reading Data To read data, use the materialize method on a Query from the Zero instance. This creates a materialized view that listens for real-time updates to the data: ```js const view = z.query.message.materialize(); view.addListener(data => console.log('Data updated:', data)); ``` When the view is no longer needed, ensure you clean up by destroying it: ```js view.destroy(); ``` For more details, see Reading Data with ZQL. React React developers can use the useZero hook for seamless integration. See Integrations React for more details. SolidJS For SolidJS, use the createZero function instead of new Zero. Refer to Integrations SolidJS for additional information. Other Frameworks For other frameworks, see the UI frameworks documentation. Writing Data Zero supports both simple and advanced data mutations. For basic use cases, use the CRUD mutator: ```ts z.mutate.message.insert({id: nanoid(), body: 'Hello World!'}); ``` For more complex scenarios, such as custom business logic, use custom mutators to define tailored mutation behavior. Server-Side Rendering (SSR) Zero does not yet support SSR. See SSR for details on disabling SSR for your framework. Deployment Ensure all .env variables are set in the production environment. For Zero cache deployment, see Deployment. For frontend deployment, consult your framework's documentation.",
+ "content": "Zero integrates easily into most JavaScript or TypeScript projects, whether you're using React, Vue, Svelte, Solid, or vanilla JavaScript. Prerequisites A PostgreSQL database with Write-Ahead Logging (WAL) enabled. See Connecting to Postgres for setup instructions. If you are using TypeScript ensure that strictNullChecks is set to true in tsconfig.json. If this is not set then the advanced types Zero uses do not work as expected. Installation Install the Zero package: npm install @rocicorp/zero Zero's server component depends on @rocicorp/zero-sqlite3, which contains a binary that requires running a postinstall script. Most alternative package managers (non-npm) disable these scripts by default for security reasons. Here's how to enable installation for common alternatives: pnpm For pnpm, either: Run pnpm approve-builds to approve all build scripts, or Add the specific dependency to your package.json: \"pnpm\": { \"onlyBuiltDependencies\": [ \"@rocicorp/zero-sqlite3\" ] } Bun For Bun, add the dependency to your trusted dependencies list: \"trustedDependencies\": [ \"@rocicorp/zero-sqlite3\" ], Environment Variables Configure Zero by creating a .env file in your project root: ZERO_UPSTREAM_DB=\"postgresql://user:password@127.0.0.1/postgres\" ZERO_REPLICA_FILE=\"/tmp/sync-replica.db\" Replace the placeholders with your database connection details. For more options, see configuration options. Starting the Server Start the Zero server using the CLI: npx zero-cache-dev The server runs on port 4848 by default. To verify, open http://localhost:4848 in your browser. If everything is configured correctly, you'll see \"OK\". Defining Your Schema Define your data model schema as described in the Zero schema documentation. Example: // schema.ts import {createSchema, table, string} from '@rocicorp/zero'; const message = table('message') .columns({ id: string(), body: string(), }) .primaryKey('id'); export const schema = createSchema({ tables: [message], }); export type Schema = typeof schema; If you're using Prisma or Drizzle, you can convert their schemas to Zero schemas using tools listed in the community section. Permissions Update schema.ts to include permissions for your tables. For example, to allow all users to read and write to the message table, add the following: // schema.ts import {ANYONE_CAN_DO_ANYTHING, definePermissions} from '@rocicorp/zero'; export const permissions = definePermissions(schema, () => ({ message: ANYONE_CAN_DO_ANYTHING, })); For more details, see permissions. Creating a Zero Instance To create a Zero client instance: import {Zero} from '@rocicorp/zero'; const z = new Zero({ userID: 'anon', server: 'http://localhost:4848', schema, }); In production, avoid hardcoding the server URL. Use environment variables like import.meta.env.VITE\\_PUBLIC\\_SERVER or process.env.NEXT\\_PUBLIC\\_SERVER. Reading Data To read data, use the materialize method on a Query from the Zero instance. This creates a materialized view that listens for real-time updates to the data: const view = z.query.message.materialize(); view.addListener(data => console.log('Data updated:', data)); When the view is no longer needed, ensure you clean up by destroying it: view.destroy(); For more details, see Reading Data with ZQL. React React developers can use the useZero hook for seamless integration. See Integrations React for more details. SolidJS For SolidJS, use the createZero function instead of new Zero. Refer to Integrations SolidJS for additional information. Other Frameworks For other frameworks, see the UI frameworks documentation. Writing Data Zero supports both simple and advanced data mutations. For basic use cases, use the CRUD mutator: z.mutate.message.insert({id: nanoid(), body: 'Hello World!'}); For more complex scenarios, such as custom business logic, use custom mutators to define tailored mutation behavior. Server-Side Rendering (SSR) Zero does not yet support SSR. See SSR for details on disabling SSR for your framework. Deployment Ensure all .env variables are set in the production environment. For Zero cache deployment, see Deployment. For frontend deployment, consult your framework's documentation.",
"headings": []
},
{
"id": "1-auth",
"title": "Authentication",
"url": "/docs/auth",
- "content": "Zero uses a JWT-based flow to authenticate connections to zero-cache. Frontend During login: Your API server creates a JWT and sends it to your client. Your client constructs a Zero instance with this token by passing it to the auth option. ```ts const zero = new Zero({ ..., auth: token, // your JWT userID, // this must match the `sub` field from `token` }); ``` Server For zero-cache to be able to verify the JWT, one of the following environment variables needs to be set: ZERO\\_AUTH\\_SECRET - If your API server uses a symmetric key (secret) to create JWTs then this is that same key. ZERO\\_AUTH\\_JWK - If your API server uses a private key to create JWTs then this is the corresponding public key, in JWK format. ZERO\\_AUTH\\_JWKS\\_URL - Many auth providers host the public keys used to verify the JWTs they create at a public URL. If you use a provider that does this, or you publish your own keys publicly, set this to that URL. Refresh The auth parameter to Zero can also be a function: ```ts const zero = new Zero({ ..., auth: async () => { const token = await fetchNewToken(); return token; }, userID, }); ``` In this case, Zero will call this function to get a new JWT if verification fails. Client-Side Data Storage Zero stores client-side data in IndexedDB by default, but this is customizable with the kvStore parameter: ```ts const zero = new Zero({ // Store data in React Native's SQLite database // See https://github.com/Braden1996/react-native-replicache kvStore: createReplicacheReactNativeOPSQLiteKVStore, }); const zero = new Zero({ // Store data in memory, it disappears on refresh kvStore: 'mem', }); ``` Because multiple users can share the same browser, Zero requires that you provide a userID parameter on construction: ```ts const zero = new Zero({ ..., userID: \"user-123\", }); ``` Zero stores each user's data in a different IndexedDB instance. This allows users to quickly switch between multiple users and accounts without resyncing. \\ cmp(decodedJWT.role, '=', 'admin'); ``` See the permissions section for more details. Examples See zbugs or hello-zero.",
+ "content": "Zero uses a JWT-based flow to authenticate connections to zero-cache. Frontend During login: Your API server creates a JWT and sends it to your client. Your client constructs a Zero instance with this token by passing it to the auth option. const zero = new Zero({ ..., auth: token, // your JWT userID, // this must match the `sub` field from `token` }); Server For zero-cache to be able to verify the JWT, one of the following environment variables needs to be set: ZERO\\_AUTH\\_SECRET - If your API server uses a symmetric key (secret) to create JWTs then this is that same key. ZERO\\_AUTH\\_JWK - If your API server uses a private key to create JWTs then this is the corresponding public key, in JWK format. ZERO\\_AUTH\\_JWKS\\_URL - Many auth providers host the public keys used to verify the JWTs they create at a public URL. If you use a provider that does this, or you publish your own keys publicly, set this to that URL. Refresh The auth parameter to Zero can also be a function: const zero = new Zero({ ..., auth: async () => { const token = await fetchNewToken(); return token; }, userID, }); In this case, Zero will call this function to get a new JWT if verification fails. Client-Side Data Storage Zero stores client-side data in IndexedDB by default, but this is customizable with the kvStore parameter: const zero = new Zero({ // Store data in React Native's SQLite database // See https://github.com/Braden1996/react-native-replicache kvStore: createReplicacheReactNativeOPSQLiteKVStore, }); const zero = new Zero({ // Store data in memory, it disappears on refresh kvStore: 'mem', }); Because multiple users can share the same browser, Zero requires that you provide a userID parameter on construction: const zero = new Zero({ ..., userID: \"user-123\", }); Zero stores each user's data in a different IndexedDB instance. This allows users to quickly switch between multiple users and accounts without resyncing. \\ cmp(decodedJWT.role, '=', 'admin'); See the permissions section for more details. Examples See zbugs or hello-zero.",
"headings": []
},
{
@@ -24,77 +24,77 @@
"id": "3-connecting-to-postgres",
"title": "Connecting to Postgres",
"url": "/docs/connecting-to-postgres",
- "content": "In the future, Zero will work with many different backend databases. Today only Postgres is supported. Specifically, Zero requires Postgres v15.0 or higher, and support for logical replication. Here are some common Postgres options and what we know about their support level: | Postgres | Support Status | | --------------------------------- | ------------------------------------------------------------------------------------------------ | | AWS RDS | β | | AWS Aurora | β v15.6+ | | Google Cloud SQL | β See notes below | | Fly.io Postgres | β See notes below | | Neon | β See notes below | | Postgres.app | β | | postgres:16.2-alpine docker image | β | | Supabase | β See notes below | | PlanetScale for Postgres | π€·ββοΈ No event triggers, see notes below | | Render | π€·ββοΈ No event triggers | | Heroku | π€·ββοΈ No event triggers | Event Triggers Zero uses Postgres βEvent Triggersβ when possible to implement high-quality, efficient schema migration. Some hosted Postgres providers donβt provide access to Event Triggers. Zero still works out of the box with these providers, but for correctness, any schema change triggers a full reset of all server-side and client-side state. For small databases (< 10GB) this can be OK, but for bigger databases we recommend choosing a provider that grants access to Event Triggers. Configuration WAL Level The Postgres wal\\_level config parameter has to be set to logical. You can check what level your pg has with this command: ```bash psql -c 'SHOW wal_level' ``` If it doesnβt output logical then you need to change the wal level. To do this, run: ```bash psql -c \"ALTER SYSTEM SET wal_level = 'logical';\" ``` Then restart Postgres. On most pg systems you can do this like so: ```bash data_dir=$(psql -t -A -c 'SHOW data_directory') pg_ctl -D \"$data_dir\" restart ``` After your server restarts, show the wal\\_level again to ensure it has changed: ```bash psql -c 'SHOW wal_level' ``` Bounding WAL Size For development databases, you can set a max\\_slot\\_wal\\_keep\\_size value in Postgres. This will help limit the amount of WAL kept around. This is a configuration parameter that bounds the amount of WAL kept around for replication slots, and invalidates the slots that are too far behind. zero-cache will automatically detect if the replication slot has been invalidated and re-sync replicas from scratch. This configuration can cause problems like slot has been invalidated because it exceeded the maximum reserved size and is not recommended for production databases. Provider-Specific Notes Google Cloud SQL To use Google Cloud SQL you must manually create a PUBLICATION and specify that publication name in the App Publications option when running zero-cache. (Google Cloud SQL does not provide sufficient permissions for zero-cache to create its default publication.) Fly.io Fly does not support TLS on their internal networks. If you run both zero-cache and Postgres on Fly, you need to stop zero-cache from trying to use TLS to talk to Postgres. You can do this by adding the sslmode=disable query parameter to your connection strings from zero-cache. Supabase In order to connect to Supabase you must use the \"Direct Connection\" style connection string, not the pooler: This is because Zero sets up a logical replication slot, which is only supported with a direct connection. Additionally, you may need to assign an IPv4 address to your Supabase instance: This will be required if you cannot use IPv6 from wherever zero-cache is running. Most cloud providers support IPv6, but some do not. For example, if you are running zero-cache in AWS, it is possible to use IPv6 but difficult. IPv4 addresses are only supported on the Pro plan and are an extra $4/month. PlanetScale for Postgres PlanetScale doesn't support event triggers yet, but they say this is something they are working on. PlanetScale also doesn't support creating publications with the FOR ALL TABLES clause. Zero typically uses this to create an initial default publication during setup. You can workaround this by creating a publication explicitly listing the tables you want to replicate. Neon Neon fully supports Zero, but you should be aware of how Neon's pricing model and Zero interact. Because Zero keeps an open connection to Postgres to replicate changes, as long as zero-cache is running, Postgres will be running and you will be charged by Neon. For production databases that have enough usage to always be running anyway, this is fine. But for smaller applications that would otherwise not always be running, this can create a surprisingly high bill. You may want to choose a provider that charge a flat monthly rate instead. Also some users choose Neon because they hope to use branching for previews. Note that Zero doesn't support this usage model well yet, and if not done with care, Zero can end up keeping each Neon preview branch running too π³. We are actively working on better preview support.",
+ "content": "In the future, Zero will work with many different backend databases. Today only Postgres is supported. Specifically, Zero requires Postgres v15.0 or higher, and support for logical replication. Here are some common Postgres options and what we know about their support level: | Postgres | Support Status | | --------------------------------- | ------------------------------------------------------------------------------------------------ | | AWS RDS | β | | AWS Aurora | β v15.6+ | | Google Cloud SQL | β See notes below | | Fly.io Postgres | β See notes below | | Neon | β See notes below | | Postgres.app | β | | postgres:16.2-alpine docker image | β | | Supabase | β See notes below | | PlanetScale for Postgres | π€·ββοΈ No event triggers, see notes below | | Render | π€·ββοΈ No event triggers | | Heroku | π€·ββοΈ No event triggers | Event Triggers Zero uses Postgres βEvent Triggersβ when possible to implement high-quality, efficient schema migration. Some hosted Postgres providers donβt provide access to Event Triggers. Zero still works out of the box with these providers, but for correctness, any schema change triggers a full reset of all server-side and client-side state. For small databases (< 10GB) this can be OK, but for bigger databases we recommend choosing a provider that grants access to Event Triggers. Configuration WAL Level The Postgres wal\\_level config parameter has to be set to logical. You can check what level your pg has with this command: psql -c 'SHOW wal_level' If it doesnβt output logical then you need to change the wal level. To do this, run: psql -c \"ALTER SYSTEM SET wal_level = 'logical';\" Then restart Postgres. On most pg systems you can do this like so: data_dir=$(psql -t -A -c 'SHOW data_directory') pg_ctl -D \"$data_dir\" restart After your server restarts, show the wal\\_level again to ensure it has changed: psql -c 'SHOW wal_level' Bounding WAL Size For development databases, you can set a max\\_slot\\_wal\\_keep\\_size value in Postgres. This will help limit the amount of WAL kept around. This is a configuration parameter that bounds the amount of WAL kept around for replication slots, and invalidates the slots that are too far behind. zero-cache will automatically detect if the replication slot has been invalidated and re-sync replicas from scratch. This configuration can cause problems like slot has been invalidated because it exceeded the maximum reserved size and is not recommended for production databases. Provider-Specific Notes Google Cloud SQL To use Google Cloud SQL you must manually create a PUBLICATION and specify that publication name in the App Publications option when running zero-cache. (Google Cloud SQL does not provide sufficient permissions for zero-cache to create its default publication.) Fly.io Fly does not support TLS on their internal networks. If you run both zero-cache and Postgres on Fly, you need to stop zero-cache from trying to use TLS to talk to Postgres. You can do this by adding the sslmode=disable query parameter to your connection strings from zero-cache. Supabase In order to connect to Supabase you must use the \"Direct Connection\" style connection string, not the pooler: This is because Zero sets up a logical replication slot, which is only supported with a direct connection. Additionally, you may need to assign an IPv4 address to your Supabase instance: This will be required if you cannot use IPv6 from wherever zero-cache is running. Most cloud providers support IPv6, but some do not. For example, if you are running zero-cache in AWS, it is possible to use IPv6 but difficult. IPv4 addresses are only supported on the Pro plan and are an extra $4/month. PlanetScale for Postgres PlanetScale doesn't support event triggers yet, but they say this is something they are working on. PlanetScale also doesn't support creating publications with the FOR ALL TABLES clause. Zero typically uses this to create an initial default publication during setup. You can workaround this by creating a publication explicitly listing the tables you want to replicate. Neon Neon fully supports Zero, but you should be aware of how Neon's pricing model and Zero interact. Because Zero keeps an open connection to Postgres to replicate changes, as long as zero-cache is running, Postgres will be running and you will be charged by Neon. For production databases that have enough usage to always be running anyway, this is fine. But for smaller applications that would otherwise not always be running, this can create a surprisingly high bill. You may want to choose a provider that charge a flat monthly rate instead. Also some users choose Neon because they hope to use branching for previews. Note that Zero doesn't support this usage model well yet, and if not done with care, Zero can end up keeping each Neon preview branch running too π³. We are actively working on better preview support.",
"headings": []
},
{
"id": "4-custom-mutators",
"title": "Custom Mutators",
"url": "/docs/custom-mutators",
- "content": "Custom Mutators are a new way to write data in Zero that is much more powerful than the original \"CRUD\" mutator API. Instead of having only the few built-in insert/update/delete write operations for each table, custom mutators allow you to create your own write operations using arbitrary code. This makes it possible to do things that are impossible or awkward with other sync engines. For example, you can create custom mutators that: Perform arbitrary server-side validation Enforce fine-grained permissions Send email notifications Query LLMs Use Yjs for collaborative editing β¦ and much, much more β custom mutators are just code, and they can do anything code can do! Despite their increased power, custom mutators still participate fully in sync. They execute instantly on the local device, immediately updating all active queries. They are then synced in the background to the server and to other clients. \\ 100) { throw new Error(`Title is too long`); } await tx.mutate.issue.update({id, title}); } ``` Each custom mutator gets two implementations: one on the client and one on the server. The client implementation must be written in TypeScript against the Zero Transaction interface, using ZQL for reads and a CRUD-style API for writes. The server implementation runs on your server, in your push endpoint, against your database. In principle, it can be written in any language and use any data access library. For example you could have the following Go-based server implementation of the same mutator: ```go func updateIssueOnServer(tx *sql.Tx, id string, title string) error { // Validate title length. if len(title) > 100 { return errors.New(\"Title is too long\") } _, err := tx.Exec(\"UPDATE issue SET title = $1 WHERE id = $2\", title, id) return err } ``` In practice however, most Zero apps use TypeScript on the server. For these users we provide a handy ServerTransaction that implements ZQL against Postgres, so that you can share code between client and server mutators naturally. So on a TypeScript server, that server mutator can just be: ```ts async function updateIssueOnServer( tx: ServerTransaction, {id, title}, {id: string, title: string}, ) { // Delegate to client mutator. // The `ServerTransaction` here has a different implementation // that runs the same ZQL queries against Postgres! await updateIssue(tx, {id, title}); } ``` Reusing ZQL on the server is a handy β and we expect frequently used β option, but not a requirement. Server Authority You may be wondering what happens if the client and server mutators implementations don't match. Zero is an example of a server-authoritative sync engine. This means that the server mutator always takes precedence over the client mutator. The result from the client mutator is considered speculative and is discarded as soon as the result from the server mutator is known. This is a very useful feature: it enables server-side validation, permissions, and other server-specific logic. Imagine that you wanted to use an LLM to detect whether an issue update is spammy, rather than a simple length check. We can just add that to our server mutator: ```ts async function updateIssueOnServer( tx: ServerTransaction, {id, title}: {id: string; title: string}, ) { const response = await llamaSession.prompt( `Is this title update likely spam?\\n\\n${title}\\n\\nResponse \"yes\" or \"no\"`, ); if (/yes/i.test(response)) { throw new Error(`Title is likely spam`); } // delegate rest of implementation to client mutator await updateIssue(tx, {id, title}); } ``` If the server detects that the mutation is spammy, the client will see the error message and the mutation will be rolled back. If the server mutator succeeds, the client mutator will be rolled back and the server result will be applied. Life of a Mutation Now that we understand what client and server mutations are, let's walk through how they work together with Zero to sync changes from a source client to the server and then other clients: When you call a custom mutator on the client, Zero runs your client-side mutator immediately on the local device, updating all active queries instantly. In the background, Zero then sends a mutation (a record of the mutator having run with certain arguments) to your server's push endpoint. Your push endpoint runs the push protocol, executing the server-side mutator in a transaction against your database and recording the fact that the mutation ran. Optionally, you use our PushProcessor class to handle this for you, but you can also implement it yourself. The changes to the database are replicated to zero-cache as normal. zero-cache calculates the updates to active queries and sends rows that have changed to each client. It also sends information about the mutations that have been applied to the database. Clients receive row updates and apply them to their local cache. Any pending mutations which have been applied to the server have their local effects rolled back. Client-side queries are updated and the user sees the changes. Using Custom Mutators Registering Client Mutators By convention, the client mutators are defined with a function called createMutators in a file called mutators.ts: ```ts // mutators.ts import {CustomMutatorDefs} from '@rocicorp/zero'; import {schema} from './schema'; export function createMutators() { return { issue: { update: async (tx, {id, title}: {id: string; title: string}) => { // Validate title length. Legacy issues are exempt. if (title.length > 100) { throw new Error(`Title is too long`); } await tx.mutate.issue.update({id, title}); }, }, } as const satisfies CustomMutatorDefs; } ``` The mutators.ts convention allows mutator implementations to be easily reused server-side. The createMutators function convention is used so that we can pass authentication information in to implement permissions. You are free to make different code layout choices β the only real requirement is that you register your map of mutators in the Zero constructor: ```ts // main.tsx import {Zero} from '@rocicorp/zero'; import {schema} from './schema'; import {createMutators} from './mutators'; const zero = new Zero({ schema, mutators: createMutators(), }); ``` Write Data on the Client The Transaction interface passed to client mutators exposes the same mutate API as the existing CRUD-style mutators: ```ts async function myMutator(tx: Transaction) { // Insert a new issue await tx.mutate.issue.insert({ id: 'issue-123', title: 'New title', description: 'New description', }); // Upsert a new issue await tx.mutate.issue.upsert({ id: 'issue-123', title: 'New title', description: 'New description', }); // Update an issue await tx.mutate.issue.update({ id: 'issue-123', title: 'New title', }); // Delete an issue await tx.mutate.issue.delete({ id: 'issue-123', }); } ``` See the CRUD docs for detailed semantics on these methods. Read Data on the Client You can read data within a client mutator using ZQL: ```ts export function createMutators() { return { issue: { update: async (tx, {id, title}: {id: string; title: string}) => { // Read existing issue const prev = await tx.query.issue.where('id', id).one(); // Validate title length. Legacy issues are exempt. if (!prev.isLegacy && title.length > 100) { throw new Error(`Title is too long`); } await tx.mutate.issue.update({id, title}); }, }, } as const satisfies CustomMutatorDefs; } ``` You have the full power of ZQL at your disposal, including relationships, filters, ordering, and limits. Reads and writes within a mutator are transactional, meaning that the datastore is guaranteed to not change while your mutator is running. And if the mutator throws, the entire mutation is rolled back. This parameter isn't supported within mutators, because waiting for server results makes no sense in an optimistic mutation β it defeats the purpose of running optimistically to begin with. When a mutator runs on the client (tx.location === \"client\"), ZQL reads only return data already cached on the client. When mutators run on the server (tx.location === \"server\"), ZQL reads always return all data. You can use run() within custom mutators, but the type argument does nothing. In the future, passing type in this situation will throw an error. Invoking Client Mutators Once you have registered your client mutators, you can call them from your client-side application: ```ts zero.mutate.issue.update({ id: 'issue-123', title: 'New title', }); ``` The result of a call to a mutator is a Promise. You do not usually need to await this promise as Zero mutators run very fast, usually completing in a tiny fraction of one frame. However because mutators ocassionally need to access browser storage, they are technically async. Reading a row that was written by a mutator immediately after it is written may not return the new data, because the mutator may not have completed writing to storage yet. Waiting for Mutator Result We typically recommend that you \"fire and forget\" mutators. Optimistic mutations make sense when the common case is that a mutation succeeds. If a mutation frequently fails, then showing the user an optimistic result doesn't make sense, because it will likely be wrong. That said there are cases where it is useful to know when a write succeeded on either the client or server. One example is if you need to read a row directly after writing it. Zero's local writes are very fast (almost always < 1 frame), but because Zero is backed by IndexedDB, writes are still technically asynchronous and reads directly after a write may not return the new data. You can use the .client promise in this case to wait for a write to complete on the client side: ```ts try { const write = zero.mutate.issue.update({ id: 'issue-123', title: 'New title', }); // issue-123 not guaranteed to be present here. read1 may be undefined. const read1 = await zero.query.issue.where('id', 'issue-123').one(); // Await client write β almost always less than 1 frame, and same // macrotask, so no browser paint will occur here. await write.client; // issue-123 definitely can be read now. const read2 = await zero.query.issue.where('id', 'issue-123').one(); } catch (e) { console.error('Mutator failed on client', e); } ``` You can also wait for the server write to succeed: ```ts try { await zero.mutate.issue.update({ id: 'issue-123', title: 'New title', }).server; // issue-123 is written to server } catch (e) { console.error('Mutator failed on client or server', e); } ``` If the client-side mutator fails, the .server promise is also rejected with the same error. You don't have to listen to both promises, the server promise covers both cases. Setting Up the Server You will need a server somewhere you can run an endpoint on. This is typically a serverless function on a platform like Vercel or AWS but can really be anything. Set the push URL with the ZERO\\_PUSH\\_URL env var or --push-url. If there is per-client configuration you need to send to the push endpoint, you can do that with push.queryParams: ```ts const z = new Zero({ push: { queryParams: { workspaceID: '42', }, }, }); ``` The push endpoint receives a PushRequest as input describing one or more mutations to apply to the backend, and must return a PushResponse describing the results of those mutations. If you are implementing your server in TypeScript, you can use the PushProcessor class to trivially implement this endpoint. Hereβs an example in a Hono app: ```ts import {Hono} from 'hono'; import {handle} from 'hono/vercel'; import { PushProcessor, ZQLDatabase, PostgresJSConnection, } from '@rocicorp/zero/pg'; import postgres from 'postgres'; import {schema} from '../shared/schema'; import {createMutators} from '../shared/mutators'; // PushProcessor is provided by Zero to encapsulate a standard // implementation of the push protocol. const processor = new PushProcessor( new ZQLDatabase( new PostgresJSConnection(postgres(process.env.ZERO_UPSTREAM_DB! as string)), schema, ), ); export const app = new Hono().basePath('/api'); app.post('/push', async c => { const result = await processor.process(createMutators(), c.req.raw); return await c.json(result); }); export default handle(app); ``` PushProcessor depends on an abstract Database. This allows it to implement the push algorithm against any database. @rocicorp/zero/pg includes a ZQLDatabase implementation of this interface backed by Postgres. The implementation allows the same mutator functions to run on client and server, by providing an implementation of the ZQL APIs that custom mutators run on the client. ZQLDatabase in turn relies on an abstract DBConnection that provides raw access to a Postgres database. This allows you to use any Postgres library you like, as long as you provide a DBConnection implementation for it. The PostgresJSConnection class implements DBConnection for the excellent postgres.js library to connect to Postgres. To reuse the client mutators exactly as-is on the server just pass the result of the same createMutators function to PushProcessor. Server Error Handling The PushProcessor in @rocicorp/zero/pg skips any mutations that throw: ```ts app.post('/push', async c => { const result = await processor.process({ issue: { update: async (tx, data) => { // The mutation is skipped and the next mutation runs as normal. throw new Error('bonk'); }, }, }, ...); return await c.json(result); }) ``` PushProcessor catches such errors and turns them into a structured response that gets sent back to the client. You can recover the errors and show UI if you want. It is also of course possible for the entire push endpoint to return an HTTP error, or to not reply at all: ```ts app.post('/push', async c => { // This will cause the client to resend all queued mutations. throw new Error('zonk'); const result = await processor.process({ // ... }, ...); return await c.json(result); }) ``` If Zero recieves any response from the push endpoint other than HTTP 200, 401, or 403, it will disconnect, wait a few moments, reconnect, and then retry all unprocessed mutations. If Zero receives HTTP 401 or 403, the client refreshes the auth token if possible, then retries all queued mutations. If you want a different behavior, it is possible to implement your own PushProcessor and handle errors differently. Server-Specific Code To implement server-specific code, just run different mutators in your push endpoint! An approach we like is to create a separate server-mutators.ts file that wraps the client mutators: ```ts // server-mutators.ts import {CustomMutatorDefs} from '@rocicorp/zero'; import {schema} from './schema'; export function createMutators( clientMutators: CustomMutatorDefs, ) { return { // Reuse all client mutators except the ones in `issue` ...clientMutators, issue: { // Reuse all issue mutators except `update` ...clientMutators.issue, update: async (tx, {id, title}: {id: string; title: string}) => { // Call the shared mutator first await clientMutators.issue.update(tx, {id, title}); // Record a history of this operation happening in an audit // log table. await tx.mutate.auditLog.insert({ // Assuming you have an audit log table with fields for // `issueId`, `action`, and `timestamp`. issueId: id, action: 'update-title', timestamp: new Date().toISOString(), }); }, }, } as const satisfies CustomMutatorDefs; } ``` For simple things, we also expose a location field on the transaction object that you can use to branch your code: ```ts myMutator: (tx) => { if (tx.location === 'client') { // Client-side code } else { // Server-side code } }, ``` Permissions Because custom mutators are just arbitrary TypeScript functions, there is no need for a special permissions system. Therefore, you won't use Zero's write permissions when you use custom mutators. We hope to build custom queries next β a read analog to custom mutators. If we succeed, Zero's permission system will go away completely π€―. In order to do permission checks, you'll need to know what user is making the request. You can pass this information to your mutators by adding a AuthData parameter to the createMutators function: ```ts type AuthData = { sub: string; }; export function createMutators(authData: AuthData | undefined) { return { issue: { launchMissiles: async (tx, args: {target: string}) => { if (!authData) { throw new Error('Users must be logged in to launch missiles'); } const hasPermission = await tx.query.user .where('id', authData.sub) .whereExists('permissions', q => q.where('name', 'launch-missiles')) .one(); if (!hasPermission) { throw new Error('User does not have permission to launch missiles'); } }, }, } as const satisfies CustomMutatorDefs; } ``` The AuthData parameter can be any data required for authorization, but is typically just the decoded JWT: ```ts // app.tsx const zero = new Zero({ schema, auth: encodedJWT, mutators: createMutators(decodedJWT), }); // hono-server.ts const processor = new PushProcessor( schema, connectionProvider(postgres(process.env.ZERO_UPSTREAM_DB as string)), ); processor.process( createMutators(decodedJWT), c.req.query(), await c.req.json(), ); ``` Dropping Down to Raw SQL The ServerTransaction interface has a dbTransaction property that exposes the underlying database connection. This allows you to run raw SQL queries directly against the database. This is useful for complex queries, or for using Postgres features that Zero doesn't support yet: ```ts markAllAsRead: async(tx: Transaction, {userId: string}) { // shared stuff ... if (tx.location === 'server') { // `tx` is now narrowed to `ServerTransaction`. // Do special server-only stuff with raw SQL. await tx.dbTransaction.query( ` UPDATE notification SET read = true WHERE user_id = $1 `, [userId], ); } } ``` As a convenience we also expose a special CustomMutatorDefs for use with server-mutators.ts that sets all the mutators to ServerTransaction by default: ```ts // server-mutators.ts import type { CustomMutatorDefs, // Special server-side CustomMutatorDefs PostgresJSTransaction, ServerTransaction, } from '@rocicorp/zero/pg'; import {Schema} from './schema'; export function createMutators(clientMutators: CustomMutatorDefs) { return { // Reuse all client mutators except the ones in `issue` ...clientMutators, issue: { // Reuse all issue mutators except `update` ...clientMutators.issue, markAllAsRead: async (tx, {userId: string}) { // No narrowing necessary β tx is already a `ServerTransaction` // assert(tx.location === 'server'); await tx.dbTransaction.query( ` UPDATE notification SET read = true WHERE user_id = $1 `, [userId], ); }, } } as const satisfies CustomMutatorDefs< ServerTransaction >; } ``` Notifications and Async Work It is bad practice to hold open database transactions while talking over the network, for example to send notifications. Instead, you should let the db transaction commit and do the work asynchronously. There is no specific support for this in custom mutators, but since mutators are just code, itβs easy to do: ```ts // server-mutators.ts export function createMutators( authData: AuthData, asyncTasks: Array<() => Promise>, ) { return { issue: { update: async (tx, {id, title}: {id: string; title: string}) => { await tx.mutate.issue.update({id, title}); asyncTasks.push(async () => { await sendEmailToSubscribers(args.id); }); }, }, } as const satisfies CustomMutatorDefs; } ``` Then in your push handler: ```ts app.post('/push', async c => { const asyncTasks: Array<() => Promise> = []; const result = await processor.process( createMutators(authData, asyncTasks), c.req.query(), await c.req.json(), ); await Promise.all(asyncTasks.map(task => task())); return await c.json(result); }); ``` Custom Database Connections You can implement an adapter to a different Postgres library, or even a different database entirely. To do so, provide a connectionProvider to PushProcessor that returns a different DBConnection implementation. For an example implementation, see the postgres implementation. Custom Push Implementation You can manually implement the push protocol in any programming language. This will be documented in the future, but you can refer to the PushProcessor source code for an example for now. Examples Zbugs uses custom mutators for all mutations, write permissions, and notifications. hello-zero-solid uses custom mutators for all mutations, and for permissions.",
+ "content": "Custom Mutators are a new way to write data in Zero that is much more powerful than the original \"CRUD\" mutator API. Instead of having only the few built-in insert/update/delete write operations for each table, custom mutators allow you to create your own write operations using arbitrary code. This makes it possible to do things that are impossible or awkward with other sync engines. For example, you can create custom mutators that: Perform arbitrary server-side validation Enforce fine-grained permissions Send email notifications Query LLMs Use Yjs for collaborative editing β¦ and much, much more β custom mutators are just code, and they can do anything code can do! Despite their increased power, custom mutators still participate fully in sync. They execute instantly on the local device, immediately updating all active queries. They are then synced in the background to the server and to other clients. \\ 100) { throw new Error(`Title is too long`); } await tx.mutate.issue.update({id, title}); } Each custom mutator gets two implementations: one on the client and one on the server. The client implementation must be written in TypeScript against the Zero Transaction interface, using ZQL for reads and a CRUD-style API for writes. The server implementation runs on your server, in your push endpoint, against your database. In principle, it can be written in any language and use any data access library. For example you could have the following Go-based server implementation of the same mutator: func updateIssueOnServer(tx *sql.Tx, id string, title string) error { // Validate title length. if len(title) > 100 { return errors.New(\"Title is too long\") } _, err := tx.Exec(\"UPDATE issue SET title = $1 WHERE id = $2\", title, id) return err } In practice however, most Zero apps use TypeScript on the server. For these users we provide a handy ServerTransaction that implements ZQL against Postgres, so that you can share code between client and server mutators naturally. So on a TypeScript server, that server mutator can just be: async function updateIssueOnServer( tx: ServerTransaction, {id, title}, {id: string, title: string}, ) { // Delegate to client mutator. // The `ServerTransaction` here has a different implementation // that runs the same ZQL queries against Postgres! await updateIssue(tx, {id, title}); } Reusing ZQL on the server is a handy β and we expect frequently used β option, but not a requirement. Server Authority You may be wondering what happens if the client and server mutators implementations don't match. Zero is an example of a server-authoritative sync engine. This means that the server mutator always takes precedence over the client mutator. The result from the client mutator is considered speculative and is discarded as soon as the result from the server mutator is known. This is a very useful feature: it enables server-side validation, permissions, and other server-specific logic. Imagine that you wanted to use an LLM to detect whether an issue update is spammy, rather than a simple length check. We can just add that to our server mutator: async function updateIssueOnServer( tx: ServerTransaction, {id, title}: {id: string; title: string}, ) { const response = await llamaSession.prompt( `Is this title update likely spam?\\n\\n${title}\\n\\nResponse \"yes\" or \"no\"`, ); if (/yes/i.test(response)) { throw new Error(`Title is likely spam`); } // delegate rest of implementation to client mutator await updateIssue(tx, {id, title}); } If the server detects that the mutation is spammy, the client will see the error message and the mutation will be rolled back. If the server mutator succeeds, the client mutator will be rolled back and the server result will be applied. Life of a Mutation Now that we understand what client and server mutations are, let's walk through how they work together with Zero to sync changes from a source client to the server and then other clients: When you call a custom mutator on the client, Zero runs your client-side mutator immediately on the local device, updating all active queries instantly. In the background, Zero then sends a mutation (a record of the mutator having run with certain arguments) to your server's push endpoint. Your push endpoint runs the push protocol, executing the server-side mutator in a transaction against your database and recording the fact that the mutation ran. Optionally, you use our PushProcessor class to handle this for you, but you can also implement it yourself. The changes to the database are replicated to zero-cache as normal. zero-cache calculates the updates to active queries and sends rows that have changed to each client. It also sends information about the mutations that have been applied to the database. Clients receive row updates and apply them to their local cache. Any pending mutations which have been applied to the server have their local effects rolled back. Client-side queries are updated and the user sees the changes. Using Custom Mutators Registering Client Mutators By convention, the client mutators are defined with a function called createMutators in a file called mutators.ts: // mutators.ts import {CustomMutatorDefs} from '@rocicorp/zero'; import {schema} from './schema'; export function createMutators() { return { issue: { update: async (tx, {id, title}: {id: string; title: string}) => { // Validate title length. Legacy issues are exempt. if (title.length > 100) { throw new Error(`Title is too long`); } await tx.mutate.issue.update({id, title}); }, }, } as const satisfies CustomMutatorDefs; } The mutators.ts convention allows mutator implementations to be easily reused server-side. The createMutators function convention is used so that we can pass authentication information in to implement permissions. You are free to make different code layout choices β the only real requirement is that you register your map of mutators in the Zero constructor: // main.tsx import {Zero} from '@rocicorp/zero'; import {schema} from './schema'; import {createMutators} from './mutators'; const zero = new Zero({ schema, mutators: createMutators(), }); Write Data on the Client The Transaction interface passed to client mutators exposes the same mutate API as the existing CRUD-style mutators: async function myMutator(tx: Transaction) { // Insert a new issue await tx.mutate.issue.insert({ id: 'issue-123', title: 'New title', description: 'New description', }); // Upsert a new issue await tx.mutate.issue.upsert({ id: 'issue-123', title: 'New title', description: 'New description', }); // Update an issue await tx.mutate.issue.update({ id: 'issue-123', title: 'New title', }); // Delete an issue await tx.mutate.issue.delete({ id: 'issue-123', }); } See the CRUD docs for detailed semantics on these methods. Read Data on the Client You can read data within a client mutator using ZQL: export function createMutators() { return { issue: { update: async (tx, {id, title}: {id: string; title: string}) => { // Read existing issue const prev = await tx.query.issue.where('id', id).one(); // Validate title length. Legacy issues are exempt. if (!prev.isLegacy && title.length > 100) { throw new Error(`Title is too long`); } await tx.mutate.issue.update({id, title}); }, }, } as const satisfies CustomMutatorDefs; } You have the full power of ZQL at your disposal, including relationships, filters, ordering, and limits. Reads and writes within a mutator are transactional, meaning that the datastore is guaranteed to not change while your mutator is running. And if the mutator throws, the entire mutation is rolled back. This parameter isn't supported within mutators, because waiting for server results makes no sense in an optimistic mutation β it defeats the purpose of running optimistically to begin with. When a mutator runs on the client (tx.location === \"client\"), ZQL reads only return data already cached on the client. When mutators run on the server (tx.location === \"server\"), ZQL reads always return all data. You can use run() within custom mutators, but the type argument does nothing. In the future, passing type in this situation will throw an error. Invoking Client Mutators Once you have registered your client mutators, you can call them from your client-side application: zero.mutate.issue.update({ id: 'issue-123', title: 'New title', }); The result of a call to a mutator is a Promise. You do not usually need to await this promise as Zero mutators run very fast, usually completing in a tiny fraction of one frame. However because mutators ocassionally need to access browser storage, they are technically async. Reading a row that was written by a mutator immediately after it is written may not return the new data, because the mutator may not have completed writing to storage yet. Waiting for Mutator Result We typically recommend that you \"fire and forget\" mutators. Optimistic mutations make sense when the common case is that a mutation succeeds. If a mutation frequently fails, then showing the user an optimistic result doesn't make sense, because it will likely be wrong. That said there are cases where it is useful to know when a write succeeded on either the client or server. One example is if you need to read a row directly after writing it. Zero's local writes are very fast (almost always < 1 frame), but because Zero is backed by IndexedDB, writes are still technically asynchronous and reads directly after a write may not return the new data. You can use the .client promise in this case to wait for a write to complete on the client side: try { const write = zero.mutate.issue.insert({ id: 'issue-123', title: 'New title', }); // issue-123 not guaranteed to be present here. read1 may be undefined. const read1 = await zero.query.issue.where('id', 'issue-123').one(); // Await client write β almost always less than 1 frame, and same // macrotask, so no browser paint will occur here. await write.client; // issue-123 definitely can be read now. const read2 = await zero.query.issue.where('id', 'issue-123').one(); } catch (e) { console.error('Mutator failed on client', e); } You can also wait for the server write to succeed: try { const write = zero.mutate.issue.insert({ id: 'issue-123', title: 'New title', }); await write.client; // optimistic write guaranteed to be present here, but not // server write. const read1 = await zero.query.issue.where('id', 'issue-123').one(); // Await server write β this involves a round-trip. await write.server; // issue-123 is written to server and any results are // syned to this client. // read2 could potentially be undefined here, for example if the // server mutator rejected the write. const read2 = await zero.query.issue.where('id', 'issue-123').one(); } catch (e) { console.error('Mutator failed on client or server', e); } If the client-side mutator fails, the .server promise is also rejected with the same error. You don't have to listen to both promises, the server promise covers both cases. Setting Up the Server You will need a server somewhere you can run an endpoint on. This is typically a serverless function on a platform like Vercel or AWS but can really be anything. Configure the push endpoint with the push.url parameter in your Zero constructor: const zero = new Zero({ push: { url: 'https://zero.my-server.com/push', }, }); You will also need to enable the server to be used as a push endpoint with the ZERO\\_PUSH\\_URL environment variable or --push-url flag: ZERO_PUSH_URL=https://*.my-server.com/push The ZERO\\_PUSH\\_URL parameter accepts wildcards, enabling the client to pass runtime configuration to the push endpoint or to use a different push endpoint, e.g., for previews. See the config docs for the full syntax. The push endpoint receives a PushRequest as input describing one or more mutations to apply to the backend, and must return a PushResponse describing the results of those mutations. If you are implementing your server in TypeScript, you can use the PushProcessor class to trivially implement this endpoint. Hereβs an example in a Hono app: import {Hono} from 'hono'; import {handle} from 'hono/vercel'; import { PushProcessor, ZQLDatabase, PostgresJSConnection, } from '@rocicorp/zero/pg'; import postgres from 'postgres'; import {schema} from '../shared/schema'; import {createMutators} from '../shared/mutators'; // PushProcessor is provided by Zero to encapsulate a standard // implementation of the push protocol. const processor = new PushProcessor( new ZQLDatabase( new PostgresJSConnection(postgres(process.env.ZERO_UPSTREAM_DB! as string)), schema, ), ); export const app = new Hono().basePath('/api'); app.post('/push', async c => { const result = await processor.process(createMutators(), c.req.raw); return await c.json(result); }); export default handle(app); PushProcessor depends on an abstract Database. This allows it to implement the push algorithm against any database. @rocicorp/zero/pg includes a ZQLDatabase implementation of this interface backed by Postgres. The implementation allows the same mutator functions to run on client and server, by providing an implementation of the ZQL APIs that custom mutators run on the client. ZQLDatabase in turn relies on an abstract DBConnection that provides raw access to a Postgres database. This allows you to use any Postgres library you like, as long as you provide a DBConnection implementation for it. The PostgresJSConnection class implements DBConnection for the excellent postgres.js library to connect to Postgres. To reuse the client mutators exactly as-is on the server just pass the result of the same createMutators function to PushProcessor. Server Error Handling The PushProcessor in @rocicorp/zero/pg skips any mutations that throw: app.post('/push', async c => { const result = await processor.process({ issue: { update: async (tx, data) => { // The mutation is skipped and the next mutation runs as normal. throw new Error('bonk'); }, }, }, ...); return await c.json(result); }) PushProcessor catches such errors and turns them into a structured response that gets sent back to the client. You can recover the errors and show UI if you want. It is also of course possible for the entire push endpoint to return an HTTP error, or to not reply at all: app.post('/push', async c => { // This will cause the client to resend all queued mutations. throw new Error('zonk'); const result = await processor.process({ // ... }, ...); return await c.json(result); }) If Zero recieves any response from the push endpoint other than HTTP 200, 401, or 403, it will disconnect, wait a few moments, reconnect, and then retry all unprocessed mutations. If Zero receives HTTP 401 or 403, the client refreshes the auth token if possible, then retries all queued mutations. If you want a different behavior, it is possible to implement your own PushProcessor and handle errors differently. Server-Specific Code To implement server-specific code, just run different mutators in your push endpoint! An approach we like is to create a separate server-mutators.ts file that wraps the client mutators: // server-mutators.ts import {CustomMutatorDefs} from '@rocicorp/zero'; import {schema} from './schema'; export function createMutators( clientMutators: CustomMutatorDefs, ) { return { // Reuse all client mutators except the ones in `issue` ...clientMutators, issue: { // Reuse all issue mutators except `update` ...clientMutators.issue, update: async (tx, {id, title}: {id: string; title: string}) => { // Call the shared mutator first await clientMutators.issue.update(tx, {id, title}); // Record a history of this operation happening in an audit // log table. await tx.mutate.auditLog.insert({ // Assuming you have an audit log table with fields for // `issueId`, `action`, and `timestamp`. issueId: id, action: 'update-title', timestamp: new Date().toISOString(), }); }, }, } as const satisfies CustomMutatorDefs; } For simple things, we also expose a location field on the transaction object that you can use to branch your code: myMutator: (tx) => { if (tx.location === 'client') { // Client-side code } else { // Server-side code } }, Permissions Because custom mutators are just arbitrary TypeScript functions, there is no need for a special permissions system. Therefore, you won't use Zero's write permissions when you use custom mutators. We hope to build custom queries next β a read analog to custom mutators. If we succeed, Zero's permission system will go away completely π€―. In order to do permission checks, you'll need to know what user is making the request. You can pass this information to your mutators by adding a AuthData parameter to the createMutators function: type AuthData = { sub: string; }; export function createMutators(authData: AuthData | undefined) { return { issue: { launchMissiles: async (tx, args: {target: string}) => { if (!authData) { throw new Error('Users must be logged in to launch missiles'); } const hasPermission = await tx.query.user .where('id', authData.sub) .whereExists('permissions', q => q.where('name', 'launch-missiles')) .one(); if (!hasPermission) { throw new Error('User does not have permission to launch missiles'); } }, }, } as const satisfies CustomMutatorDefs; } The AuthData parameter can be any data required for authorization, but is typically just the decoded JWT: // app.tsx const zero = new Zero({ schema, auth: encodedJWT, mutators: createMutators(decodedJWT), }); // hono-server.ts const processor = new PushProcessor( schema, connectionProvider(postgres(process.env.ZERO_UPSTREAM_DB as string)), ); processor.process( createMutators(decodedJWT), c.req.query(), await c.req.json(), ); Dropping Down to Raw SQL The ServerTransaction interface has a dbTransaction property that exposes the underlying database connection. This allows you to run raw SQL queries directly against the database. This is useful for complex queries, or for using Postgres features that Zero doesn't support yet: markAllAsRead: async(tx: Transaction, {userId: string}) { // shared stuff ... if (tx.location === 'server') { // `tx` is now narrowed to `ServerTransaction`. // Do special server-only stuff with raw SQL. await tx.dbTransaction.query( ` UPDATE notification SET read = true WHERE user_id = $1 `, [userId], ); } } As a convenience we also expose a special CustomMutatorDefs for use with server-mutators.ts that sets all the mutators to ServerTransaction by default: // server-mutators.ts import type { CustomMutatorDefs, // Special server-side CustomMutatorDefs PostgresJSTransaction, ServerTransaction, } from '@rocicorp/zero/pg'; import {Schema} from './schema'; export function createMutators(clientMutators: CustomMutatorDefs) { return { // Reuse all client mutators except the ones in `issue` ...clientMutators, issue: { // Reuse all issue mutators except `update` ...clientMutators.issue, markAllAsRead: async (tx, {userId: string}) { // No narrowing necessary β tx is already a `ServerTransaction` // assert(tx.location === 'server'); await tx.dbTransaction.query( ` UPDATE notification SET read = true WHERE user_id = $1 `, [userId], ); }, } } as const satisfies CustomMutatorDefs< ServerTransaction >; } Notifications and Async Work It is bad practice to hold open database transactions while talking over the network, for example to send notifications. Instead, you should let the db transaction commit and do the work asynchronously. There is no specific support for this in custom mutators, but since mutators are just code, itβs easy to do: // server-mutators.ts export function createMutators( authData: AuthData, asyncTasks: Array<() => Promise>, ) { return { issue: { update: async (tx, {id, title}: {id: string; title: string}) => { await tx.mutate.issue.update({id, title}); asyncTasks.push(async () => { await sendEmailToSubscribers(args.id); }); }, }, } as const satisfies CustomMutatorDefs; } Then in your push handler: app.post('/push', async c => { const asyncTasks: Array<() => Promise> = []; const result = await processor.process( createMutators(authData, asyncTasks), c.req.query(), await c.req.json(), ); await Promise.all(asyncTasks.map(task => task())); return await c.json(result); }); Custom Database Connections You can implement an adapter to a different Postgres library, or even a different database entirely. To do so, provide a connectionProvider to PushProcessor that returns a different DBConnection implementation. For an example implementation, see the postgres implementation. Custom Push Implementation You can manually implement the push protocol in any programming language. This will be documented in the future, but you can refer to the PushProcessor source code for an example for now. Examples Zbugs uses custom mutators for all mutations, write permissions, and notifications. hello-zero-solid uses custom mutators for all mutations and for permissions.",
"headings": []
},
{
"id": "5-debug/inspector",
"title": "Inspector API",
"url": "/docs/debug/inspector",
- "content": "The Zero instance provides an API to gather information about the client's current state, such as: All active queries Query TTL Active clients Client database contents This can help figuring out why you hit loading states, how many queries are active at a time, if you have any resource leaks due to failing to clean up queries or if expected data is missing on the client. Creating an Inspector Each Zero instance has an inspect method that will return the inspector. The inspect method is asynchronous because it performs lazy loading of inspect-only related code. For convenience, the active Zero instance is automatically exposed at \\_\\_zero, so you can access the inspector in the console like this: ```ts const inspector = await __zero.inspect(); ``` If you are using React, you can use React.lazy to dynamically load components that depend on the inspect API. Once you have an inspector you can inspect the current client and client group. For example to see active queries for the current client: ```ts console.table(await inspector.client.queries()); ``` To inspect other clients within the group: ```ts const allClients = await inspector.clients(); ``` Dumping Data In addition to information about queries, you can see the contents of the client side database. ```ts const inspector = await zero.inspect(); const client = inspector.client; // All raw k/v data currently synced to client console.log('client map:'); console.log(await client.map()); // kv table extracted into tables // This is same info that is in z.query[tableName].run() for (const tableName of Object.keys(schema.tables)) { console.log(`table ${tableName}:`); console.table(await client.rows(tableName)); } ```",
+ "content": "The Zero instance provides an API to gather information about the client's current state, such as: All active queries Query TTL Active clients Client database contents This can help figuring out why you hit loading states, how many queries are active at a time, if you have any resource leaks due to failing to clean up queries or if expected data is missing on the client. Creating an Inspector Each Zero instance has an inspect method that will return the inspector. The inspect method is asynchronous because it performs lazy loading of inspect-only related code. For convenience, the active Zero instance is automatically exposed at \\_\\_zero, so you can access the inspector in the console like this: const inspector = await __zero.inspect(); If you are using React, you can use React.lazy to dynamically load components that depend on the inspect API. Once you have an inspector you can inspect the current client and client group. For example to see active queries for the current client: console.table(await inspector.client.queries()); To inspect other clients within the group: const allClients = await inspector.clients(); Dumping Data In addition to information about queries, you can see the contents of the client side database. const inspector = await zero.inspect(); const client = inspector.client; // All raw k/v data currently synced to client console.log('client map:'); console.log(await client.map()); // kv table extracted into tables // This is same info that is in z.query[tableName].run() for (const tableName of Object.keys(schema.tables)) { console.log(`table ${tableName}:`); console.table(await client.rows(tableName)); }",
"headings": []
},
{
"id": "6-debug/otel",
"title": "OpenTelemetry",
"url": "/docs/debug/otel",
- "content": "The zero-cache service embeds the JavaScript OTLP Exporter and can send logs, traces, and metrics to any standard otel collector. To enable otel, set the following environment variables then run zero-cache as normal: ```sh OTEL_EXPORTER_OTLP_ENDPOINT=\"\" OTEL_EXPORTER_OTLP_HEADERS=\"\" OTEL_RESOURCE_ATTRIBUTES=\"\" OTEL_NODE_RESOURCE_DETECTORS=\"env,host,os\" ``` Grafana Cloud Walkthrough Here are instructions to setup Grafana Cloud, but the setup for other otel collectors should be similar. Sign up for Grafana Cloud (Free Tier) Click Connections > Add Connection in the left sidebar add-connection Search for \"OpenTelemetry\" and select it Click \"Quickstart\" quickstart Select \"JavaScript\" javascript Create a new token Copy the environment variables into your .env file or similar copy-env Start zero-cache Look for logs under \"Drilldown\" > \"Logs\" in left sidebar",
+ "content": "The zero-cache service embeds the JavaScript OTLP Exporter and can send logs, traces, and metrics to any standard otel collector. To enable otel, set the following environment variables then run zero-cache as normal: OTEL_EXPORTER_OTLP_ENDPOINT=\"\" OTEL_EXPORTER_OTLP_HEADERS=\"\" OTEL_RESOURCE_ATTRIBUTES=\"\" OTEL_NODE_RESOURCE_DETECTORS=\"env,host,os\" Grafana Cloud Walkthrough Here are instructions to setup Grafana Cloud, but the setup for other otel collectors should be similar. Sign up for Grafana Cloud (Free Tier) Click Connections > Add Connection in the left sidebar add-connection Search for \"OpenTelemetry\" and select it Click \"Quickstart\" quickstart Select \"JavaScript\" javascript Create a new token Copy the environment variables into your .env file or similar copy-env Start zero-cache Look for logs under \"Drilldown\" > \"Logs\" in left sidebar",
"headings": []
},
{
"id": "7-debug/permissions",
"title": "Debugging Permissions",
"url": "/docs/debug/permissions",
- "content": "Given that permissions are defined in their own file and internally applied to queries, it might be hard to figure out if or why a permission check is failing. Read Permissions You can use the analyze-query utility with the --apply-permissions flag to see the complete query Zero runs, including read permissions. ```bash npx analyze-query --schema-path='./shared/schema.ts' --query='issue.related(\"comments\")' --apply-permissions --auth-data='{\"userId\":\"user-123\"}' ``` If the result looks right, the problem may be that Zero is not receiving the AuthData that you think it is. You can retrieve a query hash from websocket or server logs, then ask Zero for the details on that specific query. Run this command with the same environment you run zero-cache with. It will use your upstream or cvr configuration to look up the query hash in the cvr database. ```bash npx analyze-query --schema-path='./shared/schema.ts' --hash='3rhuw19xt9vry' --apply-permissions --auth-data='{\"userId\":\"user-123\"}' ``` Write Permissions Look for a WARN level log in the output from zero-cache like this: ``` Permission check failed for {\"op\":\"update\",\"tableName\":\"message\",...}, action update, phase preMutation, authData: {...}, rowPolicies: [...], cellPolicies: [] ``` Zero prints the row, auth data, and permission policies that was applied to any failed writes.",
+ "content": "Given that permissions are defined in their own file and internally applied to queries, it might be hard to figure out if or why a permission check is failing. Read Permissions You can use the analyze-query utility with the --apply-permissions flag to see the complete query Zero runs, including read permissions. npx analyze-query --schema-path='./shared/schema.ts' --query='issue.related(\"comments\")' --apply-permissions --auth-data='{\"userId\":\"user-123\"}' If the result looks right, the problem may be that Zero is not receiving the AuthData that you think it is. You can retrieve a query hash from websocket or server logs, then ask Zero for the details on that specific query. Run this command with the same environment you run zero-cache with. It will use your upstream or cvr configuration to look up the query hash in the cvr database. npx analyze-query --schema-path='./shared/schema.ts' --hash='3rhuw19xt9vry' --apply-permissions --auth-data='{\"userId\":\"user-123\"}' Write Permissions Look for a WARN level log in the output from zero-cache like this: Permission check failed for {\"op\":\"update\",\"tableName\":\"message\",...}, action update, phase preMutation, authData: {...}, rowPolicies: [...], cellPolicies: [] Zero prints the row, auth data, and permission policies that was applied to any failed writes.",
"headings": []
},
{
"id": "8-debug/query-asts",
"title": "Query ASTs",
"url": "/docs/debug/query-asts",
- "content": "An AST (Abstract Syntax Tree) is a representation of a query that is used internally by Zero. It is not meant to be human readable, but it sometimes shows up in logs and other places. If you need to read one of these, save the AST to a json file. Then run the following command: ```bash cat ast.json | npx ast-to-zql ``` The returned ZQL query will be using server names, rather than client names, to identify columns and tables. If you provide the schema file as an option you will get mapped back to client names: ```bash cat ast.json | npx ast-to-zql --schema schema.ts ``` This comes into play if, in your schema.ts, you use the from feature to have different names on the client than your backend DB.",
+ "content": "An AST (Abstract Syntax Tree) is a representation of a query that is used internally by Zero. It is not meant to be human readable, but it sometimes shows up in logs and other places. If you need to read one of these, save the AST to a json file. Then run the following command: cat ast.json | npx ast-to-zql The returned ZQL query will be using server names, rather than client names, to identify columns and tables. If you provide the schema file as an option you will get mapped back to client names: cat ast.json | npx ast-to-zql --schema schema.ts This comes into play if, in your schema.ts, you use the from feature to have different names on the client than your backend DB.",
"headings": []
},
{
"id": "9-debug/replication",
"title": "Replication",
"url": "/docs/debug/replication",
- "content": "Resetting During development we all do strange things (unsafely changing schemas, removing files, etc.). If the replica ever gets wedged (stops replicating, acts strange) you can wipe it and start over. If you copied your setup from hello-zero or hello-zero-solid, you can also run npm run dev:clean Otherwise you can run rm /tmp/my-zero-replica.db\\* (see your .env file for the replica file location) to clear the contents of the replica. It is always safe to wipe the replica. Wiping will have no impact on your upstream database. Downstream zero-clients will get re-synced when they connect. Inspecting For data to be synced to the client it must first be replicated to zero-cache. You can check the contents of zero-cache via: ```bash $ npx @rocicorp/zero-sqlite3 /tmp/my-zero-replica.db ``` To inspect your Zero database, you have two options: Use our pre-compiled SQLite build @rocicorp/zero-sqlite3 as described above Build SQLite from the SQLite bedrock branch yourself This will drop you into a sqlite3 shell with which you can use to explore the contents of the replica. ```sql sqlite> .tables _zero.changeLog emoji viewState _zero.replicationConfig issue zero.permissions _zero.replicationState issueLabel zero.schemaVersions _zero.runtimeEvents label zero_0.clients _zero.versionHistory user comment userPref sqlite> .mode qbox sqlite> SELECT * FROM label; βββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββ¬βββββββββββββ β id β name β _0_version β βββββββββββββββββββββββββββΌβββββββββββββββββββββββββββΌβββββββββββββ€ β 'ic_g-DZTYDApZR_v7Cdcy' β 'bug' β '4ehreg' β ... ``` Miscellaneous If you see FATAL: sorry, too many clients already in logs, itβs because you have two zero-cache instances running against dev. One is probably in a background tab somewhere. In production, zero-cache can run horizontally scaled but on dev it doesnβt run in the config that allows that.",
+ "content": "Resetting During development we all do strange things (unsafely changing schemas, removing files, etc.). If the replica ever gets wedged (stops replicating, acts strange) you can wipe it and start over. If you copied your setup from hello-zero or hello-zero-solid, you can also run npm run dev:clean Otherwise you can run rm /tmp/my-zero-replica.db\\* (see your .env file for the replica file location) to clear the contents of the replica. It is always safe to wipe the replica. Wiping will have no impact on your upstream database. Downstream zero-clients will get re-synced when they connect. Inspecting For data to be synced to the client it must first be replicated to zero-cache. You can check the contents of zero-cache via: $ npx @rocicorp/zero-sqlite3 /tmp/my-zero-replica.db To inspect your Zero database, you have two options: Use our pre-compiled SQLite build @rocicorp/zero-sqlite3 as described above Build SQLite from the SQLite bedrock branch yourself This will drop you into a sqlite3 shell with which you can use to explore the contents of the replica. sqlite> .tables _zero.changeLog emoji viewState _zero.replicationConfig issue zero.permissions _zero.replicationState issueLabel zero.schemaVersions _zero.runtimeEvents label zero_0.clients _zero.versionHistory user comment userPref sqlite> .mode qbox sqlite> SELECT * FROM label; βββββββββββββββββββββββββββ¬βββββββββββββββββββββββββββ¬βββββββββββββ β id β name β _0_version β βββββββββββββββββββββββββββΌβββββββββββββββββββββββββββΌβββββββββββββ€ β 'ic_g-DZTYDApZR_v7Cdcy' β 'bug' β '4ehreg' β ... Miscellaneous If you see FATAL: sorry, too many clients already in logs, itβs because you have two zero-cache instances running against dev. One is probably in a background tab somewhere. In production, zero-cache can run horizontally scaled but on dev it doesnβt run in the config that allows that.",
"headings": []
},
{
"id": "10-debug/slow-queries",
"title": "Slow Queries",
"url": "/docs/debug/slow-queries",
- "content": "In the zero-cache logs, you may see statements indicating a query is slow: ```shell { \"level\": \"DEBUG\", \"worker\": \"syncer\", \"component\": \"view-syncer\", \"hydrationTimeMs\": 1339, \"message\": \"Total rows considered: 146\" }, ``` or: ```shell hash=3rhuw19xt9vry transformationHash=1nv7ot74gxfl7 Slow query materialization 325.46865100000286 ``` Or, you may just notice queries taking longer than expected in the UI. Here are some tips to help debug such slow queries. Check ttl If you are seeing unexpected UI flicker when moving between views, it is likely that the queries backing these views have the default ttl of never. Set the ttl to something like 5m to keep data cached across navigations. You may alternately want to preload some data at app startup. Conversely, if you are setting ttl to long values, then it can happen that you have many backgrounded queries still running that the app is not using. You can see which queries are running using the inspector. Ensure that only expected queries are running. See long TTLs for more information. Check Storage zero-cache is effectively a database. It requires fast (low latency and high bandwidth) disk access to perform well. If you're running on network attached storage with high latency, or on AWS with low IOPS, then this is the most likely culprit. The default deployment of Zero currently uses Fargate which scales IOPS with vCPU. Increasing the vCPU will increase storage throughput and likely resolve the issue. Fly.io provides physically attached SSDs, even for their smallest VMs. Deploying zero-cache there (or any other provider that offers physically attached SSDs) is another option. Locality If you see log lines like: ```shell flushed cvr ... (124ms) ``` this indicates that zero-cache is likely deployed too far away from your CVR database. If you did not configure a CVR database URL then this will be your product's Postgres DB. A slow CVR flush can slow down Zero, since it must complete the flush before sending query result(s) to clients. Try moving zero-cache to be deployed as close as possible to the CVR database. Query Plan If neither (1) nor (2) is a problem, then the query itself is the most likely culprit. The @rocicorp/zero package ships with a query analyzer to help debug this. The analyzer should be run in the directory that contains the .env file for zero-cache as it will use the .env file to find your replica. Example: ```shell npx analyze-query \\ --schema-path=./shared/schema.ts \\ --query='issue.related(\"comments\")' ``` This will output the query plan and time to execute each phase of that plan. Note that query performance can also be affected by read permissions. See Debugging Permissions for information on how to analyze queries with read permissions applied. /statz zero-cache makes some internal health statistics available via the /statz endpoint of zero-cache. In order to access this, you must configure an admin password.",
+ "content": "In the zero-cache logs, you may see statements indicating a query is slow: { \"level\": \"DEBUG\", \"worker\": \"syncer\", \"component\": \"view-syncer\", \"hydrationTimeMs\": 1339, \"message\": \"Total rows considered: 146\" }, or: hash=3rhuw19xt9vry transformationHash=1nv7ot74gxfl7 Slow query materialization 325.46865100000286 Or, you may just notice queries taking longer than expected in the UI. Here are some tips to help debug such slow queries. Check ttl If you are seeing unexpected UI flicker when moving between views, it is likely that the queries backing these views have the default ttl of never. Set the ttl to something like 5m to keep data cached across navigations. You may alternately want to preload some data at app startup. Conversely, if you are setting ttl to long values, then it can happen that you have many backgrounded queries still running that the app is not using. You can see which queries are running using the inspector. Ensure that only expected queries are running. See long TTLs for more information. Check Storage zero-cache is effectively a database. It requires fast (low latency and high bandwidth) disk access to perform well. If you're running on network attached storage with high latency, or on AWS with low IOPS, then this is the most likely culprit. The default deployment of Zero currently uses Fargate which scales IOPS with vCPU. Increasing the vCPU will increase storage throughput and likely resolve the issue. Fly.io provides physically attached SSDs, even for their smallest VMs. Deploying zero-cache there (or any other provider that offers physically attached SSDs) is another option. Locality If you see log lines like: flushed cvr ... (124ms) this indicates that zero-cache is likely deployed too far away from your CVR database. If you did not configure a CVR database URL then this will be your product's Postgres DB. A slow CVR flush can slow down Zero, since it must complete the flush before sending query result(s) to clients. Try moving zero-cache to be deployed as close as possible to the CVR database. Query Plan If neither (1) nor (2) is a problem, then the query itself is the most likely culprit. The @rocicorp/zero package ships with a query analyzer to help debug this. The analyzer should be run in the directory that contains the .env file for zero-cache as it will use the .env file to find your replica. Example: npx analyze-query \\ --schema-path=./shared/schema.ts \\ --query='issue.related(\"comments\")' This will output the query plan and time to execute each phase of that plan. Note that query performance can also be affected by read permissions. See Debugging Permissions for information on how to analyze queries with read permissions applied. /statz zero-cache makes some internal health statistics available via the /statz endpoint of zero-cache. In order to access this, you must configure an admin password.",
"headings": []
},
{
"id": "11-deployment",
"title": "Deploying Zero",
"url": "/docs/deployment",
- "content": "To deploy a Zero app, you need to: Deploy your backend database. Most standard Postgres hosts work with Zero. Deploy zero-cache. We provide a Docker image that can work with most Docker hosts. Deploy your frontend. You can use any hosting service like Vercel or Netlify. This page describes how to deploy zero-cache. Architecture zero-cache is a horizontally scalable, stateful web service that maintains a SQLite replica of your Postgres database. It uses this replica to sync ZQL queries to clients over WebSockets. You don't have to know the details of how zero-cache works to run it, but it helps to know the basic structure. A running zero-cache is composed of a single replication-manager node and multiple view-syncer nodes. It also depends on Postgres, S3, and attached SSD storage. Upstream: Your application's Postgres database. Change DB: A Postgres DB used by Zero to store a recent subset of the Postgres replication log. CVR DB: A Postgres DB used by Zero to store Client View Records (CVRs). CVRs track the state of each synced client. We allow separate DBs so that they can be scaled and tuned independently if desired. S3: Stores a canonical copy of the SQLite replica. File System: Used by both node types to store local copies of the SQLite replica. Can be ephemeral β Zero will re-initialize from S3 on startup. Recommended to use attached SSD storage for best performance. Replication Manager: Serves as the single consumer of the Postgres replication log. Stores a recent subset of the Postgres changelog in the Change DB for catching up ViewSyncers when they initialize. Also maintains the canonical replica, which ViewSyncers initialize from. View Syncers: Handle WebSocket connections from clients and run ZQL queries. Updates CVR DB with the latest state of each client as queries run. Uses CVR DB on client connection to compute the initial diff to catch clients up. Topology You should deploy zero-cache close to your database because the mutation implementation is chatty. In the future, mutations will move out of zero-cache. When that happens you can deploy zero-cache geographically distributed and it will double as a read-replica. Updating When run with multiple View Syncer nodes, zero-cache supports rolling, downtime-free updates. A new Replication Manager takes over the replication stream from the old Replication Manager, and connections from the old View Syncers are gradually drained and absorbed by active View Syncers. Client/Server Version Compatibility Servers are compatible with any client of same major version, and with clients one major version back. So for example: Server 0.2.\\* is compatible with client 0.2.\\* Server 0.2.\\* is compatible with client 0.1.\\* Server 2.\\*.\\* is compatible with client 2.\\*.\\* Server 2.\\*.\\* is compatible with client 1.\\*.\\* To upgrade Zero to a new major version, first deploy the new zero-cache, then the new frontend. Configuration The zero-cache image is configured via environment variables. See zero-cache Config for available options. Guide: Multi-Node on SST+AWS SST is our recommended way to deploy Zero. The setup below costs about $35/month. You can scale it up or down as needed by adjusting the amount of vCPUs and memory in each task. Setup Upstream Create an upstream Postgres database server somewhere. See Connecting to Postgres for details. Populate the schema and any initial data for your application. Setup AWS See AWS setup guide. The end result should be that you have a dev profile and SSO session defined in your ~/.aws/config file. Initialize SST ```bash npx sst init --yes ``` Choose \"aws\" for where to deploy. Then overwite /sst.config.ts with the following code: ```ts /* eslint-disable */ /// import {execSync} from 'child_process'; export default $config({ app(input) { return { name: 'hello-zero', removal: input?.stage === 'production' ? 'retain' : 'remove', home: 'aws', region: process.env.AWS_REGION || 'us-east-1', providers: { command: true, }, }; }, async run() { const zeroVersion = execSync('cat package.json | jq '.dependencies[\"@rocicorp/zero\"]') .toString() .trim(); // S3 Bucket const replicationBucket = new sst.aws.Bucket(`replication-bucket`); // VPC Configuration const vpc = new sst.aws.Vpc(`vpc`, { az: 2, }); // ECS Cluster const cluster = new sst.aws.Cluster(`cluster`, { vpc, }); const conn = new sst.Secret('PostgresConnectionString'); const zeroAuthSecret = new sst.Secret('ZeroAuthSecret'); // Common environment variables const commonEnv = { ZERO_PUSH_URL: '', // Your push api url when using custom mutators ZERO_UPSTREAM_DB: conn.value, ZERO_CVR_DB: conn.value, ZERO_CHANGE_DB: conn.value, ZERO_AUTH_SECRET: zeroAuthSecret.value, ZERO_REPLICA_FILE: 'sync-replica.db', ZERO_IMAGE_URL: `rocicorp/zero:${zeroVersion}`, ZERO_CVR_MAX_CONNS: '10', ZERO_UPSTREAM_MAX_CONNS: '10', }; // Replication Manager Service const replicationManager = cluster.addService(`replication-manager`, { cpu: '0.5 vCPU', memory: '1 GB', architecture: 'arm64', image: commonEnv.ZERO_IMAGE_URL, link: [replicationBucket], wait: true, health: { command: ['CMD-SHELL', 'curl -f http://localhost:4849/ || exit 1'], interval: '5 seconds', retries: 3, startPeriod: '300 seconds', }, environment: { ...commonEnv, ZERO_LITESTREAM_BACKUP_URL: $interpolate`s3://${replicationBucket.name}/backup`, ZERO_NUM_SYNC_WORKERS: '0', }, transform: { target: { healthCheck: { enabled: true, path: '/keepalive', protocol: 'HTTP', interval: 5, healthyThreshold: 2, timeout: 3, }, }, }, }); // View Syncer Service const viewSyncer = cluster.addService( `view-syncer`, { cpu: '1 vCPU', memory: '2 GB', architecture: 'arm64', image: commonEnv.ZERO_IMAGE_URL, link: [replicationBucket], health: { command: ['CMD-SHELL', 'curl -f http://localhost:4848/ || exit 1'], interval: '5 seconds', retries: 3, startPeriod: '300 seconds', }, environment: { ...commonEnv, ZERO_CHANGE_STREAMER_MODE: 'discover', }, logging: { retention: '1 month', }, transform: { target: { healthCheck: { enabled: true, path: '/keepalive', protocol: 'HTTP', interval: 5, healthyThreshold: 2, timeout: 3, }, stickiness: { enabled: true, type: 'lb_cookie', cookieDuration: 120, }, }, }, }, { // Wait for replication-manager to come up first, for breaking changes // to replication-manager interface. dependsOn: [replicationManager], }, ); // Permissions deployment // Note: this setup requires your CI/CD pipeline to have access to your // Postgres database. If you do not want to do this, you can also use // `npx zero-deploy-permissions --output-format=sql` during build to // generate a permissions.sql file, then run that file as part of your // deployment within your VPC. See hello-zero-solid for an example: // https://github.com/rocicorp/hello-zero-solid/blob/main/sst.config.ts#L141 new command.local.Command( 'zero-deploy-permissions', { create: `npx zero-deploy-permissions -p ../../src/schema.ts`, // Run the Command on every deploy ... triggers: [Date.now()], environment: { ZERO_UPSTREAM_DB: commonEnv.ZERO_UPSTREAM_DB, }, }, // after the view-syncer is deployed. {dependsOn: viewSyncer}, ); }, }); ``` Set SST Secrets Configure SST with your Postgres connection string and Zero Auth Secret. Note that if you use JWT-based auth, you'll need to change the environment variables in the sst.config.ts file above, then set a different secret here. ```bash npx sst secret set PostgresConnectionString \"YOUR-PG-CONN-STRING\" npx sst secret set ZeroAuthSecret \"YOUR-ZERO-AUTH-SECRET\" ``` Deploy ```bash npx sst deploy ``` This takes about 5-10 minutes. If successful, you should see a URL for the view-syncer service. This is the URL to pass to the server parameter of the Zero constructor on the client. If unsuccessful, you can get detailed logs with npx sst deploy --verbose. Come find us on Discord and we'll help get you sorted out. Guide: Single-Node on Fly.io Let's deploy the Quickstart app to Fly.io. We'll use Fly.io for both the database and zero-cache. Setup Quickstart Go through the Quickstart guide to get the app running locally. Setup Fly.io Create an account on Fly.io and install the Fly CLI. Create Postgres app ```bash INITIALS=aa PG_APP_NAME=$INITIALS-zstart-pg PG_PASSWORD=\"$(head -c 256 /dev/urandom | od -An -t x1 | tr -d ' \\n' | tr -dc 'a-zA-Z' | head -c 16)\" fly postgres create \\ --name $PG_APP_NAME \\ --region lax \\ --initial-cluster-size 1 \\ --vm-size shared-cpu-2x \\ --volume-size 40 \\ --password=$PG_PASSWORD ``` Seed Upstream database Populate the database with initial data and set its wal\\_level to logical to support replication to zero-cache. Then restart the database to apply the changes. ```bash (cat ./docker/seed.sql; echo \"\\q\") | fly pg connect -a $PG_APP_NAME echo \"ALTER SYSTEM SET wal_level = logical; \\q\" | fly pg connect -a $PG_APP_NAME fly postgres restart --app $PG_APP_NAME ``` Create zero-cache Fly.io app ```bash CACHE_APP_NAME=$INITIALS-zstart-cache fly app create $CACHE_APP_NAME ``` Publish zero-cache Create a fly.toml file. ```bash CONNECTION_STRING=\"postgres://postgres:$PG_PASSWORD@$PG_APP_NAME.flycast:5432\" ZERO_VERSION=$(npm list @rocicorp/zero | grep @rocicorp/zero | cut -f 3 -d @) cat < fly.toml app = \"$CACHE_APP_NAME\" primary_region = 'lax' [build] image = \"registry.hub.docker.com/rocicorp/zero:${ZERO_VERSION}\" [http_service] internal_port = 4848 force_https = true auto_stop_machines = 'off' min_machines_running = 1 [[http_service.checks]] grace_period = \"10s\" interval = \"30s\" method = \"GET\" timeout = \"5s\" path = \"/\" [[vm]] memory = '2gb' cpu_kind = 'shared' cpus = 2 [mounts] source = \"sqlite_db\" destination = \"/data\" [env] ZERO_REPLICA_FILE = \"/data/sync-replica.db\" ZERO_UPSTREAM_DB=\"${CONNECTION_STRING}/zstart?sslmode=disable\" ZERO_CVR_DB=\"${CONNECTION_STRING}/zstart_cvr?sslmode=disable\" ZERO_CHANGE_DB=\"${CONNECTION_STRING}/zstart_cdb?sslmode=disable\" ZERO_PUSH_URL=\"\" ZERO_AUTH_SECRET=\"secretkey\" LOG_LEVEL = \"debug\" EOF ``` Then publish zero-cache: ```bash fly deploy ``` Deploy Permissions Now zero-cache is running on Fly.io, but there are no permissions. If you run the app against this zero-cache, you'll see that no data is returned from any query. To fix this, deploy your permissions: ```bash npx zero-deploy-permissions --schema-path='./src/schema.ts' --output-file='/tmp/permissions.sql' (cat /tmp/permissions.sql; echo \"\\q\") | fly pg connect -a $PG_APP_NAME -d zstart ``` You will need to redo this step every time you change your app's permissions, likely as part of your CI/CD pipeline. Use Remote zero-cache ```bash VITE_PUBLIC_SERVER=\"https://${CACHE_APP_NAME}.fly.dev/\" npm run dev:ui ``` Now restart the frontend to pick up the env change, and refresh the app. You can stop your local database and zero-cache as we're not using them anymore. Open the web inspector to verify the app is talking to the remote zero-cache! You can deploy the frontend to any standard hosting service like Vercel or Netlify, or even to Fly.io! Deploy Frontend to Vercel If you've followed the above guide and deployed zero-cache to fly, you can simply run: ```sh vercel deploy --prod \\ -e ZERO_AUTH_SECRET=\"secretkey\" \\ -e VITE_PUBLIC_SERVER='https://${CACHE_APP_NAME}.fly.dev/' ``` to deploy your frontend to Vercel. Explaining the arguments above -- ZERO\\_AUTH\\_SECRET - The secret to create and verify JWTs. This is the same secret that was used when deploying zero-cache to fly. VITE\\_PUBLIC\\_SERVER - The URL the frontend will call to talk to the zero-cache server. This is the URL of the fly app. Guide: Multi-Node on Raw AWS S3 Bucket Create an S3 bucket. zero-cache uses S3 to backup its SQLite replica so that it survives task restarts. Fargate Services Run zero-cache as two Fargate services (using the same rocicorp/zero docker image): replication-manager zero-cache config: ZERO\\_LITESTREAM\\_BACKUP\\_URL=s3://{bucketName}/{generation} ZERO\\_NUM\\_SYNC\\_WORKERS=0 Task count: 1 view-syncer zero-cache config: ZERO\\_CHANGE\\_STREAMER\\_MODE=discover Task count: N You can also use dynamic scaling Notes Standard rolling restarts are fine for both services Set ZERO\\_CVR\\_MAX\\_CONNS and ZERO\\_UPSTREAM\\_MAX\\_CONNS appropriately so that the total connections from both running and updating view-syncers (e.g. DesiredCount \\* MaximumPercent) do not exceed your databaseβs max\\_connections. The {generation} component of the s3://{bucketName}/{generation} URL is an arbitrary path component that can be modified to reset the replica (e.g. a date, a number, etc.). Setting this to a new path is the multi-node equivalent of deleting the replica file to resync. Note: zero-cache does not manage cleanup of old generations. The replication-manager serves requests on port 4849. Routing from the view-syncer to the http://{replication-manager} is handled internally by storing data in the changedb. Fargate ephemeral storage is used for the replica. The default size is 20GB. This can be increased up to 200GB Allocate at least twice the size of the database to support the internal VACUUM operation. Guide: $PLATFORM Where should we deploy Zero next?? Let us know on Discord!",
+ "content": "To deploy a Zero app, you need to: Deploy your backend database. Most standard Postgres hosts work with Zero. Deploy zero-cache. We provide a Docker image that can work with most Docker hosts. Deploy your frontend. You can use any hosting service like Vercel or Netlify. This page describes how to deploy zero-cache. Architecture zero-cache is a horizontally scalable, stateful web service that maintains a SQLite replica of your Postgres database. It uses this replica to sync ZQL queries to clients over WebSockets. You don't have to know the details of how zero-cache works to run it, but it helps to know the basic structure. A running zero-cache is composed of a single replication-manager node and multiple view-syncer nodes. It also depends on Postgres, S3, and attached SSD storage. Upstream: Your application's Postgres database. Change DB: A Postgres DB used by Zero to store a recent subset of the Postgres replication log. CVR DB: A Postgres DB used by Zero to store Client View Records (CVRs). CVRs track the state of each synced client. We allow separate DBs so that they can be scaled and tuned independently if desired. S3: Stores a canonical copy of the SQLite replica. File System: Used by both node types to store local copies of the SQLite replica. Can be ephemeral β Zero will re-initialize from S3 on startup. Recommended to use attached SSD storage for best performance. Replication Manager: Serves as the single consumer of the Postgres replication log. Stores a recent subset of the Postgres changelog in the Change DB for catching up ViewSyncers when they initialize. Also maintains the canonical replica, which ViewSyncers initialize from. View Syncers: Handle WebSocket connections from clients and run ZQL queries. Updates CVR DB with the latest state of each client as queries run. Uses CVR DB on client connection to compute the initial diff to catch clients up. Topology You should deploy zero-cache close to your database because the mutation implementation is chatty. In the future, mutations will move out of zero-cache. When that happens you can deploy zero-cache geographically distributed and it will double as a read-replica. Updating When run with multiple View Syncer nodes, zero-cache supports rolling, downtime-free updates. A new Replication Manager takes over the replication stream from the old Replication Manager, and connections from the old View Syncers are gradually drained and absorbed by active View Syncers. Client/Server Version Compatibility Servers are compatible with any client of same major version, and with clients one major version back. So for example: Server 0.2.\\* is compatible with client 0.2.\\* Server 0.2.\\* is compatible with client 0.1.\\* Server 2.\\*.\\* is compatible with client 2.\\*.\\* Server 2.\\*.\\* is compatible with client 1.\\*.\\* To upgrade Zero to a new major version, first deploy the new zero-cache, then the new frontend. Configuration The zero-cache image is configured via environment variables. See zero-cache Config for available options. Guide: Multi-Node on SST+AWS SST is our recommended way to deploy Zero. The setup below costs about $35/month. You can scale it up or down as needed by adjusting the amount of vCPUs and memory in each task. Setup Upstream Create an upstream Postgres database server somewhere. See Connecting to Postgres for details. Populate the schema and any initial data for your application. Setup AWS See AWS setup guide. The end result should be that you have a dev profile and SSO session defined in your ~/.aws/config file. Initialize SST npx sst init --yes Choose \"aws\" for where to deploy. Then overwite /sst.config.ts with the following code: /* eslint-disable */ /// import {execSync} from 'child_process'; export default $config({ app(input) { return { name: 'hello-zero', removal: input?.stage === 'production' ? 'retain' : 'remove', home: 'aws', region: process.env.AWS_REGION || 'us-east-1', providers: { command: true, }, }; }, async run() { const zeroVersion = execSync('cat package.json | jq '.dependencies[\"@rocicorp/zero\"]') .toString() .trim(); // S3 Bucket const replicationBucket = new sst.aws.Bucket(`replication-bucket`); // VPC Configuration const vpc = new sst.aws.Vpc(`vpc`, { az: 2, }); // ECS Cluster const cluster = new sst.aws.Cluster(`cluster`, { vpc, }); const conn = new sst.Secret('PostgresConnectionString'); const zeroAuthSecret = new sst.Secret('ZeroAuthSecret'); // Common environment variables const commonEnv = { ZERO_PUSH_URL: '', // Your push api url when using custom mutators ZERO_UPSTREAM_DB: conn.value, ZERO_CVR_DB: conn.value, ZERO_CHANGE_DB: conn.value, ZERO_AUTH_SECRET: zeroAuthSecret.value, ZERO_REPLICA_FILE: 'sync-replica.db', ZERO_IMAGE_URL: `rocicorp/zero:${zeroVersion}`, ZERO_CVR_MAX_CONNS: '10', ZERO_UPSTREAM_MAX_CONNS: '10', }; // Replication Manager Service const replicationManager = cluster.addService(`replication-manager`, { cpu: '0.5 vCPU', memory: '1 GB', architecture: 'arm64', image: commonEnv.ZERO_IMAGE_URL, link: [replicationBucket], wait: true, health: { command: ['CMD-SHELL', 'curl -f http://localhost:4849/ || exit 1'], interval: '5 seconds', retries: 3, startPeriod: '300 seconds', }, environment: { ...commonEnv, ZERO_LITESTREAM_BACKUP_URL: $interpolate`s3://${replicationBucket.name}/backup`, ZERO_NUM_SYNC_WORKERS: '0', }, loadBalancer: { public: false, ports: [ { listen: '80/http', forward: '4849/http', }, ], }, transform: { service: { // e.g. extend the grace period for initial sync of large databases healthCheckGracePeriodSeconds: 600, } target: { healthCheck: { enabled: true, path: '/keepalive', protocol: 'HTTP', interval: 5, healthyThreshold: 2, timeout: 3, }, }, }, }); // View Syncer Service const viewSyncer = cluster.addService( `view-syncer`, { cpu: '1 vCPU', memory: '2 GB', architecture: 'arm64', image: commonEnv.ZERO_IMAGE_URL, link: [replicationBucket], health: { command: ['CMD-SHELL', 'curl -f http://localhost:4848/ || exit 1'], interval: '5 seconds', retries: 3, startPeriod: '300 seconds', }, environment: { ...commonEnv, ZERO_CHANGE_STREAMER_URI: replicationManager.url, }, loadBalancer: { ports: [ { listen: '80/http', forward: '4848/http', }, ], }, logging: { retention: '1 month', }, transform: { service: { // e.g. extend the grace period for initial sync of large databases healthCheckGracePeriodSeconds: 600, } target: { healthCheck: { enabled: true, path: '/keepalive', protocol: 'HTTP', interval: 5, healthyThreshold: 2, timeout: 3, }, stickiness: { enabled: true, type: 'lb_cookie', cookieDuration: 120, }, }, }, }, ); // Permissions deployment // Note: this setup requires your CI/CD pipeline to have access to your // Postgres database. If you do not want to do this, you can also use // `npx zero-deploy-permissions --output-format=sql` during build to // generate a permissions.sql file, then run that file as part of your // deployment within your VPC. See hello-zero-solid for an example: // https://github.com/rocicorp/hello-zero-solid/blob/main/sst.config.ts#L141 new command.local.Command( 'zero-deploy-permissions', { create: `npx zero-deploy-permissions -p ../../src/schema.ts`, // Run the Command on every deploy ... triggers: [Date.now()], environment: { ZERO_UPSTREAM_DB: commonEnv.ZERO_UPSTREAM_DB, }, }, // after the view-syncer is deployed. {dependsOn: viewSyncer}, ); }, }); Set SST Secrets Configure SST with your Postgres connection string and Zero Auth Secret. Note that if you use JWT-based auth, you'll need to change the environment variables in the sst.config.ts file above, then set a different secret here. npx sst secret set PostgresConnectionString \"YOUR-PG-CONN-STRING\" npx sst secret set ZeroAuthSecret \"YOUR-ZERO-AUTH-SECRET\" Deploy npx sst deploy This takes about 5-10 minutes. If successful, you should see a URL for the view-syncer service. This is the URL to pass to the server parameter of the Zero constructor on the client. If unsuccessful, you can get detailed logs with npx sst deploy --verbose. Come find us on Discord and we'll help get you sorted out. Guide: Single-Node on Fly.io Let's deploy the Quickstart app to Fly.io. We'll use Fly.io for both the database and zero-cache. Setup Quickstart Go through the Quickstart guide to get the app running locally. Setup Fly.io Create an account on Fly.io and install the Fly CLI. Create Postgres app INITIALS=aa PG_APP_NAME=$INITIALS-zstart-pg PG_PASSWORD=\"$(head -c 256 /dev/urandom | od -An -t x1 | tr -d ' \\n' | tr -dc 'a-zA-Z' | head -c 16)\" fly postgres create \\ --name $PG_APP_NAME \\ --region lax \\ --initial-cluster-size 1 \\ --vm-size shared-cpu-2x \\ --volume-size 40 \\ --password=$PG_PASSWORD Seed Upstream database Populate the database with initial data and set its wal\\_level to logical to support replication to zero-cache. Then restart the database to apply the changes. (cat ./docker/seed.sql; echo \"\\q\") | fly pg connect -a $PG_APP_NAME echo \"ALTER SYSTEM SET wal_level = logical; \\q\" | fly pg connect -a $PG_APP_NAME fly postgres restart --app $PG_APP_NAME Create zero-cache Fly.io app CACHE_APP_NAME=$INITIALS-zstart-cache fly app create $CACHE_APP_NAME Publish zero-cache Create a fly.toml file. CONNECTION_STRING=\"postgres://postgres:$PG_PASSWORD@$PG_APP_NAME.flycast:5432\" ZERO_VERSION=$(npm list @rocicorp/zero | grep @rocicorp/zero | cut -f 3 -d @) cat < fly.toml app = \"$CACHE_APP_NAME\" primary_region = 'lax' [build] image = \"registry.hub.docker.com/rocicorp/zero:${ZERO_VERSION}\" [http_service] internal_port = 4848 force_https = true auto_stop_machines = 'off' min_machines_running = 1 [[http_service.checks]] grace_period = \"10s\" interval = \"30s\" method = \"GET\" timeout = \"5s\" path = \"/\" [[vm]] memory = '2gb' cpu_kind = 'shared' cpus = 2 [mounts] source = \"sqlite_db\" destination = \"/data\" [env] ZERO_REPLICA_FILE = \"/data/sync-replica.db\" ZERO_UPSTREAM_DB=\"${CONNECTION_STRING}/zstart?sslmode=disable\" ZERO_CVR_DB=\"${CONNECTION_STRING}/zstart_cvr?sslmode=disable\" ZERO_CHANGE_DB=\"${CONNECTION_STRING}/zstart_cdb?sslmode=disable\" ZERO_PUSH_URL=\"\" ZERO_AUTH_SECRET=\"secretkey\" LOG_LEVEL = \"debug\" EOF Then publish zero-cache: fly deploy Deploy Permissions Now zero-cache is running on Fly.io, but there are no permissions. If you run the app against this zero-cache, you'll see that no data is returned from any query. To fix this, deploy your permissions: npx zero-deploy-permissions --schema-path='./src/schema.ts' --output-file='/tmp/permissions.sql' (cat /tmp/permissions.sql; echo \"\\q\") | fly pg connect -a $PG_APP_NAME -d zstart You will need to redo this step every time you change your app's permissions, likely as part of your CI/CD pipeline. Use Remote zero-cache VITE_PUBLIC_SERVER=\"https://${CACHE_APP_NAME}.fly.dev/\" npm run dev:ui Now restart the frontend to pick up the env change, and refresh the app. You can stop your local database and zero-cache as we're not using them anymore. Open the web inspector to verify the app is talking to the remote zero-cache! You can deploy the frontend to any standard hosting service like Vercel or Netlify, or even to Fly.io! Deploy Frontend to Vercel If you've followed the above guide and deployed zero-cache to fly, you can simply run: vercel deploy --prod \\ -e ZERO_AUTH_SECRET=\"secretkey\" \\ -e VITE_PUBLIC_SERVER='https://${CACHE_APP_NAME}.fly.dev/' to deploy your frontend to Vercel. Explaining the arguments above -- ZERO\\_AUTH\\_SECRET - The secret to create and verify JWTs. This is the same secret that was used when deploying zero-cache to fly. VITE\\_PUBLIC\\_SERVER - The URL the frontend will call to talk to the zero-cache server. This is the URL of the fly app. Guide: Multi-Node on Raw AWS S3 Bucket Create an S3 bucket. zero-cache uses S3 to backup its SQLite replica so that it survives task restarts. Fargate Services Run zero-cache as two Fargate services (using the same rocicorp/zero docker image): replication-manager zero-cache config: ZERO\\_LITESTREAM\\_BACKUP\\_URL=s3://{bucketName}/{generation} ZERO\\_NUM\\_SYNC\\_WORKERS=0 Task count: 1 view-syncer zero-cache config: ZERO\\_CHANGE\\_STREAMER\\_URI=http://{replication-manager} Task count: N You can also use dynamic scaling Notes Standard rolling restarts are fine for both services Set ZERO\\_CVR\\_MAX\\_CONNS and ZERO\\_UPSTREAM\\_MAX\\_CONNS appropriately so that the total connections from both running and updating view-syncers (e.g. DesiredCount \\* MaximumPercent) do not exceed your databaseβs max\\_connections. The {generation} component of the s3://{bucketName}/{generation} URL is an arbitrary path component that can be modified to reset the replica (e.g. a date, a number, etc.). Setting this to a new path is the multi-node equivalent of deleting the replica file to resync. Note: zero-cache does not manage cleanup of old generations. The replication-manager serves requests on port 4849. Routing from the view-syncer to the http://{replication-manager} can be achieved using the following mechanisms (in order of preference): An internal load balancer Service Connect Service Discovery Fargate ephemeral storage is used for the replica. The default size is 20GB. This can be increased up to 200GB Allocate at least twice the size of the database to support the internal VACUUM operation. Guide: $PLATFORM Where should we deploy Zero next?? Let us know on Discord!",
"headings": []
},
{
"id": "12-errors",
"title": "Error Handling",
"url": "/docs/errors",
- "content": "Errors from mutators and queries are thrown in response to method calls where possible, but many Zero errors occur asynchronously, during sync. You can catch these errors with the onError constructor parameter: ```ts const z = new Zero({ upstream: 'https://my-upstream-db.com', onError: (msg, ...rest) => { reportToSentry('Zero error:', msg, ...rest); }, }); ``` You can use this to send errors to Sentry, show custom UI, etc. The first parameter to onError is a descriptive message. Additional parameters provide more detail, for example an Error object (with a stack), or a JSON object.",
+ "content": "Errors from mutators and queries are thrown in response to method calls where possible, but many Zero errors occur asynchronously, during sync. You can catch these errors with the onError constructor parameter: const z = new Zero({ upstream: 'https://my-upstream-db.com', onError: (msg, ...rest) => { reportToSentry('Zero error:', msg, ...rest); }, }); You can use this to send errors to Sentry, show custom UI, etc. The first parameter to onError is a descriptive message. Additional parameters provide more detail, for example an Error object (with a stack), or a JSON object.",
"headings": []
},
{
"id": "13-introduction",
"title": "Welcome to Zero Alpha",
"url": "/docs/introduction",
- "content": "Zero is a new kind of sync engine powered by queries. Rather than syncing entire tables to the client, or using static rules to carefully specify what to sync, you just write queries directly in your client code. Queries can access the entire backend database. Zero caches the data for queries locally on the device, and reuses that data automatically to answer future queries whenever possible. For typical applications, the result is that almost all queries are answered locally, instantly. It feels like you have access to the entire backend database directly from the client in memory. Occasionally, when you do a more specific query, Zero falls back to the server. But this happens automatically without any extra work required. Zero is made possible by a custom streaming query engine we built called ZQL, which uses Incremental View Maintenance on both client and server to efficiently keep large, complex queries up to date. Status Zero is in alpha. There are still some rough edges, and to run it, you need to deploy it yourself to AWS or similar. Even so, Zero is already quite fun to work with. We are using it ourselves to build our very own Linear-style bug tracker. We find that Zero is already much more productive than alternatives, even having to occasionally work around a missing feature. If you are building a new web app that needs to be fast and reactive, and can do the deployment yourself, it's a great time to get started with Zero. We're working toward a beta release and full production readiness this year.",
+ "content": "Zero is a new kind of sync engine powered by queries. Rather than syncing entire tables to the client, or using static rules to carefully specify what to sync, you just write queries directly in your client code. Queries can access the entire backend database. Zero caches the data for queries locally on the device, and reuses that data automatically to answer future queries whenever possible. For typical applications, the result is that almost all queries are answered locally, instantly. It feels like you have access to the entire backend database directly from the client in memory. Occasionally, when you do a more specific query, Zero falls back to the server. But this happens automatically without any extra work required. Zero is made possible by a custom streaming query engine we built called ZQL, which uses Incremental View Maintenance on both client and server to efficiently keep large, complex queries up to date.",
"headings": []
},
{
@@ -108,7 +108,7 @@
"id": "15-offline",
"title": "Offline",
"url": "/docs/offline",
- "content": "Zero currently supports offline reads, but not writes. We plan to support offline writes in the future, but we don't have a timeline for that yet. The lack of offline writes is often surprising to people familiar with sync engines, because offline is usually touted as something that comes for free with these tools. This page explains why Zero doesn't currently support offline writes, how we recommend you handle connectivity loss, and our future plans in this area. Offline Writes are a UX Problem While Zero can technically queue offline writes and replay them when reconnected (this happens by default in any sync engine, and is what Zero does today), that fact doesn't make supporting offline writes much easier. That's because a really hard part of offline writes is in handling conflicts, and no software tool can make that problem go away. For example, imagine two users are editing an article about cats. One goes offline and does a bunch of work on the article, while the other decides that the article should actually be about dogs and rewrites it. When the offline user reconnects, there is no way that any software algorithm can automatically resolve their conflict. One or the other of them is going to be upset. And while the above example may sound extreme, you can construct similar situations with the majority of common applications. Just take your own application and ask yourself what should really happen if one user takes their device offline for a week and makes arbitrarily complex changes while other users are working online. People who work on sync engines and related tools often say that offline is just extreme lag, but that's only true at a technical level. At a human level, being \"offline\" for a few seconds is very different from being offline for a few hours. The difference is how much knowledge you have about what your collaborators are doing, and how much of your work can be lost. The only way to support offline writes in general is to either: Make the logical datamodel append-only (i.e., users can create and mark tasks done, but cannot edit or delete them). Support custom UX to allow users to fork and merge conflicts when they occur. Only support editing from a single device. None of these is free. Buiding a good offline UX is a lot of work, and most of that work is borne by application developers. β¦ And a Schema Problem But it's not just users that can diverge from each other. The server software and database schema can also diverge arbitrarily far from the client while the client is disconnected. When the client comes back online, the changes made may no longer be processable by the application, or may have a different effect than the user intended. So to support long offline periods, the server must also maintain backward compatibility with clients indefinitely. Similarly, the server can never reject an offline write (i.e., due to validation) because that could lead to a user losing huge amounts of work. β¦ And a Sync Engine Problem Supporting offline writes also requires work in the sync engine. In Zero, there are a few specific impacts: The Zero client itself can get out of date while offline. On reconnect, the app might reload with a new version of the client. This new version must be able to read and process old data from arbitrarily long ago. An arbitrarily large number of pending mutations can be built up. These mutations must be replayed on reconnect, which can take a long time. When processing mutations on server we must consider what should happen if the database or application server are temporarily unavailable. We need to treat that kind of error differently from a validation error. These problems are surmountable, but significant effort. Their solutions might also be in tension with other goals of the sync engine, like online performance and scalability. These tradeoffs will take time to work through. Zero's Position For all of the above reasons, we plan to disable offline writes in Zero for beta. When the Zero client loses connection to zero-cache for several minutes (or when zero-cache cannot reach the customer API server), it will enter a special offline mode. In this mode, all writes to Zero will throw. While we recognize that offline writes would be useful for some applications, the reality is that for most of the apps we want to support, the user is online the vast majority of the time and the cost to support offline is extremely high. There is simply more value in making the online experience great first. We would like to revisit this in the future and really think through how to design APIs and patterns that allow developers to make successful offline-enabled apps. But it's not our priority right now. Dealing with Offline Today Until Zero disables offline writes automatically, we recomment using the onOnlineChange parameter to the Zero constructor to detect connection loss and disable editing manually in your UI. Even More Information Lies I was Told About Collaborative Editing: a detailed overview of the challenges around offline writes in any collaborative editing system. This Zero Discord thread covers some challenges specifically in the context of Zero. Patchwork by Ink & Switch is new and interesting research around how to support offline writes well in collaborative systems.",
+ "content": "Zero currently supports offline reads, but not writes. We plan to support offline writes in the future, but we don't have a timeline for that yet. The lack of offline writes is often surprising to people familiar with sync engines, because offline is usually touted as something that comes for free with these tools. This page explains why Zero doesn't currently support offline writes, how we recommend you handle connectivity loss, and our future plans in this area. Offline Writes are a UX Problem While Zero can technically queue offline writes and replay them when reconnected (this happens by default in any sync engine, and is what Zero does today), that fact doesn't make supporting offline writes much easier. That's because a really hard part of offline writes is in handling conflicts, and no software tool can make that problem go away. For example, imagine two users are editing an article about cats. One goes offline and does a bunch of work on the article, while the other decides that the article should actually be about dogs and rewrites it. When the offline user reconnects, there is no way that any software algorithm can automatically resolve their conflict. One or the other of them is going to be upset. And while the above example may sound extreme, you can construct similar situations with the majority of common applications. Just take your own application and ask yourself what should really happen if one user takes their device offline for a week and makes arbitrarily complex changes while other users are working online. People who work on sync engines and related tools often say that offline is just extreme lag, but that's only true at a technical level. At a human level, being \"offline\" for a few seconds is very different from being offline for a few hours. The difference is how much knowledge you have about what your collaborators are doing, and how much of your work can be lost. The only way to support offline writes in general is to either: Make the logical datamodel append-only (i.e., users can create and mark tasks done, but cannot edit or delete them). Support custom UX to allow users to fork and merge conflicts when they occur. Only support editing from a single device. None of these is free. Buiding a good offline UX is a lot of work, and most of that work is borne by application developers. β¦ And a Schema Problem But it's not just users that can diverge from each other. The server software and database schema can also diverge arbitrarily far from the client while the client is disconnected. When the client comes back online, the changes made may no longer be processable by the application, or may have a different effect than the user intended. So to support long offline periods, the server must also maintain backward compatibility with clients indefinitely. Similarly, the server can never reject an offline write (i.e., due to validation) because that could lead to a user losing huge amounts of work. β¦ And a Sync Engine Problem Supporting offline writes also requires work in the sync engine. In Zero, there are a few specific impacts: The Zero client itself can get out of date while offline. On reconnect, the app might reload with a new version of the client. This new version must be able to read and process old data from arbitrarily long ago. An arbitrarily large number of pending mutations can be built up. These mutations must be replayed on reconnect, which can take a long time. When processing mutations on server we must consider what should happen if the database or application server are temporarily unavailable. We need to treat that kind of error differently from a validation error. These problems are surmountable, but significant effort. Their solutions might also be in tension with other goals of the sync engine, like online performance and scalability. These tradeoffs will take time to work through. Zero's Position For all of the above reasons, we plan to disable offline writes in Zero for beta. When the Zero client loses connection to zero-cache for several minutes (or when zero-cache cannot reach the customer API server), it will enter a special offline mode. In this mode, all writes to Zero will throw. While we recognize that offline writes would be useful for some applications, the reality is that for most of the apps we want to support, the user is online the vast majority of the time and the cost to support offline is extremely high. There is simply more value in making the online experience great first. We would like to revisit this in the future and really think through how to design APIs and patterns that allow developers to make successful offline-enabled apps. But it's not our priority right now. Dealing with Offline Today Until Zero disables offline writes automatically, use useZeroOnline to detect connection loss and manually disable writes in your UI: const {online} = useZeroOnline(); return ; ... or use the underlying zero.onOnline event: const unsubscribe = zero.onOnline(online => { console.log('Online:', online); }); Even More Information Lies I was Told About Collaborative Editing: a detailed overview of the challenges around offline writes in any collaborative editing system. This Zero Discord thread covers some challenges specifically in the context of Zero. Patchwork by Ink & Switch is new and interesting research around how to support offline writes well in collaborative systems.",
"headings": []
},
{
@@ -119,199 +119,199 @@
"headings": []
},
{
- "id": "17-overview",
- "title": "Concepts (How Zero Works)",
- "url": "/docs/overview",
- "content": "",
- "headings": []
- },
- {
- "id": "18-permissions",
+ "id": "17-permissions",
"title": "Permissions",
"url": "/docs/permissions",
- "content": "Permissions are expressed using ZQL and run automatically with every read and write. Permissions are currently row based. Zero will eventually also have column permissions. Define Permissions Permissions are defined in schema.ts using the definePermissions function. Here's an example of limiting reads to members of an organization and deletes to only the creator of an issue: ```ts // The decoded value of your JWT. type AuthData = { // The logged-in user. sub: string; }; export const permissions = definePermissions(schema, () => { // Checks if the user exists in a related organization const allowIfInOrganization = ( authData: AuthData, eb: ExpressionBuilder, ) => eb.exists('organization', q => q.whereExists('user', q => q.where('id', authData.sub)), ); // Checks if the user is the creator const allowIfIssueCreator = ( authData: AuthData, {cmp}: ExpressionBuilder, ) => cmp('creatorID', authData.sub); return { issue: { row: { select: [allowIfInOrganization], delete: [allowIfIssueCreator], }, }, } satisfies PermissionsConfig; }); ``` definePermission returns a policy object for each table in the schema. Each policy defines a ruleset for the operations that are possible on a table: select, insert, update, and delete. Access is Denied by Default If you don't specify any rules for an operation, it is denied by default. This is an important safety feature that helps ensure data isn't accidentally exposed. To enable full access to an action (i.e., during development) use the ANYONE\\_CAN helper: ```ts import {ANYONE_CAN} from '@rocicorp/zero'; const permissions = definePermissions(schema, () => { return { issue: { row: { select: ANYONE_CAN, // Other operations are denied by default. }, }, // Other tables are denied by default. } satisfies PermissionsConfig; }); ``` To do this for all actions, use ANYONE\\_CAN\\_DO\\_ANYTHING: ```ts import {ANYONE_CAN_DO_ANYTHING} from '@rocicorp/zero'; const permissions = definePermissions(schema, () => { return { // All operations on issue are allowed to all users. issue: ANYONE_CAN_DO_ANYTHING, // Other tables are denied by default. } satisfies PermissionsConfig; }); ``` Permission Evaluation Zero permissions are \"compiled\" into a JSON-based format at build-time. This file is stored in the {ZERO\\_APP\\_ID}.permissions table of your upstream database. Like other tables, it replicates live down to zero-cache. zero-cache then parses this file, and applies the encoded rules to every read and write operation. The end result is that you can't really use most features of JS in these rules. Specifically you cannot: Iterate over properties or array elements in the auth token Use any JS features beyond property access of AuthData Use any conditional or global state Basically only property access is allowed. This is really confusing and we're working on a better solution. Permission Deployment During development, permissions are compiled and uploaded to your database completely automatically as part of the zero-cache-dev script. For production, you need to call npx zero-deploy-permissions within your app to update the permissions in the production database whenever they change. You would typically do this as part of your normal schema migration or CI process. For example, the SST deployment script for zbugs looks like this: ```ts new command.local.Command( 'zero-deploy-permissions', { create: `npx zero-deploy-permissions -p ../../src/schema.ts`, // Run the Command on every deploy ... triggers: [Date.now()], environment: { ZERO_UPSTREAM_DB: commonEnv.ZERO_UPSTREAM_DB, // If the application has a non-default App ID ... ZERO_APP_ID: commonEnv.ZERO_APP_ID, }, }, // after the view-syncer is deployed. {dependsOn: viewSyncer}, ); ``` See the SST Deployment Guide for more details. Rules Each operation on a policy has a ruleset containing zero or more rules. A rule is just a TypeScript function that receives the logged in user's AuthData and generates a ZQL where expression. At least one rule in a ruleset must return a row for the operation to be allowed. Select Permissions You can limit the data a user can read by specifying a select ruleset. Select permissions act like filters. If a user does not have permission to read a row, it will be filtered out of the result set. It will not generate an error. For example, imagine a select permission that restricts reads to only issues created by the user: ```ts definePermissions(schema, () => { const allowIfIssueCreator = ( authData: AuthData, {cmp}: ExpressionBuilder, ) => cmp('creatorID', authData.sub); return { issue: { row: { select: [allowIfIssueCreator], }, }, } satisfies PermissionsConfig; }); ``` If the issue table has two rows, one created by the user and one by someone else, the user will only see the row they created in any queries. Column permissions Zero does not currently support column based permissions. Select permission applies to every column. The recommended approach for now is to factor out private fields into a separate table, e.g. user\\_private. Column permissions are planned but currently not a high priority. Note that although the same limitation applies to declarative insert/update permissions, custom mutators support arbitrary server-side logic and so can easily control which columns are writable. Insert Permissions You can limit what rows can be inserted and by whom by specifying an insert ruleset. Insert rules are evaluated after the entity is inserted. So if they query the database, they will see the inserted row present. If any rule in the insert ruleset returns a row, the insert is allowed. Here's an example of an insert rule that disallows inserting users that have the role 'admin'. ```ts definePermissions(schema, () => { const allowIfNonAdmin = ( authData: AuthData, {cmp}: ExpressionBuilder, ) => cmp('role', '!=', 'admin'); return { user: { row: { insert: [allowIfNonAdmin], }, }, } satisfies PermissionsConfig; }); ``` Update Permissions There are two types of update rulesets: preMutation and postMutation. Both rulesets must pass for an update to be allowed. preMutation rules see the version of a row before the mutation is applied. This is useful for things like checking whether a user owns an entity before editing it. postMutation rules see the version of a row after the mutation is applied. This is useful for things like ensuring a user can only mark themselves as the creator of an entity and not other users. Like other rulesets, preMutation and postMutation default to NOBODY\\_CAN. This means that every table must define both these rulesets in order for any updates to be allowed. For example, the following ruleset allows an issue's owner to edit, but not re-assign the issue. The postMutation rule enforces that the current user still own the issue after edit. ```ts definePermissions(schema, () => { const allowIfIssueOwner = ( authData: AuthData, {cmp}: ExpressionBuilder, ) => cmp('ownerID', authData.sub); return { issue: { row: { update: { preMutation: [allowIfIssueOwner], postMutation: [allowIfIssueOwner], }, }, }, } satisfies PermissionsConfig; }); ``` This ruleset allows an issue's owner to edit and re-assign the issue: ```ts definePermissions(schema, () => { const allowIfIssueOwner = ( authData: AuthData, {cmp}: ExpressionBuilder, ) => cmp('ownerID', authData.sub); return { issue: { row: { update: { preMutation: [allowIfIssueOwner], postMutation: ANYONE_CAN, }, }, }, } satisfies PermissionsConfig; }); ``` And this allows anyone to edit an issue, but only if they also assign it to themselves. Useful for enforcing \"patches welcome\"? π ```ts definePermissions(schema, () => { const allowIfIssueOwner = ( authData: AuthData, {cmp}: ExpressionBuilder, ) => cmp('ownerID', authData.sub); return { issue: { row: { update: { preMutation: ANYONE_CAN, postMutation: [allowIfIssueOwner], }, }, }, } satisfies PermissionsConfig; }); ``` Delete Permissions Delete permissions work in the same way as insert permissions except they run before the delete is applied. So if a delete rule queries the database, it will see that the deleted row is present. If any rule in the ruleset returns a row, the delete is allowed. Debugging See Debugging Permissions. Examples See hello-zero for a simple example of write auth and zbugs for a much more involved one.",
+ "content": "Permissions are expressed using ZQL and run automatically with every read and write. Permissions are currently row based. Zero will eventually also have column permissions. Define Permissions Permissions are defined in schema.ts using the definePermissions function. Here's an example of limiting reads to members of an organization and deletes to only the creator of an issue: // The decoded value of your JWT. type AuthData = { // The logged-in user. sub: string; }; export const permissions = definePermissions(schema, () => { // Checks if the user exists in a related organization const allowIfInOrganization = ( authData: AuthData, eb: ExpressionBuilder, ) => eb.exists('organization', q => q.whereExists('user', q => q.where('id', authData.sub)), ); // Checks if the user is the creator const allowIfIssueCreator = ( authData: AuthData, {cmp}: ExpressionBuilder, ) => cmp('creatorID', authData.sub); return { issue: { row: { select: [allowIfInOrganization], delete: [allowIfIssueCreator], }, }, } satisfies PermissionsConfig; }); definePermission returns a policy object for each table in the schema. Each policy defines a ruleset for the operations that are possible on a table: select, insert, update, and delete. Access is Denied by Default If you don't specify any rules for an operation, it is denied by default. This is an important safety feature that helps ensure data isn't accidentally exposed. To enable full access to an action (i.e., during development) use the ANYONE\\_CAN helper: import {ANYONE_CAN} from '@rocicorp/zero'; const permissions = definePermissions(schema, () => { return { issue: { row: { select: ANYONE_CAN, // Other operations are denied by default. }, }, // Other tables are denied by default. } satisfies PermissionsConfig; }); To do this for all actions, use ANYONE\\_CAN\\_DO\\_ANYTHING: import {ANYONE_CAN_DO_ANYTHING} from '@rocicorp/zero'; const permissions = definePermissions(schema, () => { return { // All operations on issue are allowed to all users. issue: ANYONE_CAN_DO_ANYTHING, // Other tables are denied by default. } satisfies PermissionsConfig; }); Permission Evaluation Zero permissions are \"compiled\" into a JSON-based format at build-time. This file is stored in the {ZERO\\_APP\\_ID}.permissions table of your upstream database. Like other tables, it replicates live down to zero-cache. zero-cache then parses this file, and applies the encoded rules to every read and write operation. The end result is that you can't really use most features of JS in these rules. Specifically you cannot: Iterate over properties or array elements in the auth token Use any JS features beyond property access of AuthData Use any conditional or global state Basically only property access is allowed. This is really confusing and we're working on a better solution. Permission Deployment During development, permissions are compiled and uploaded to your database completely automatically as part of the zero-cache-dev script. For production, you need to call npx zero-deploy-permissions within your app to update the permissions in the production database whenever they change. You would typically do this as part of your normal schema migration or CI process. For example, the SST deployment script for zbugs looks like this: new command.local.Command( 'zero-deploy-permissions', { create: `npx zero-deploy-permissions -p ../../src/schema.ts`, // Run the Command on every deploy ... triggers: [Date.now()], environment: { ZERO_UPSTREAM_DB: commonEnv.ZERO_UPSTREAM_DB, // If the application has a non-default App ID ... ZERO_APP_ID: commonEnv.ZERO_APP_ID, }, }, // after the view-syncer is deployed. {dependsOn: viewSyncer}, ); See the SST Deployment Guide for more details. Rules Each operation on a policy has a ruleset containing zero or more rules. A rule is just a TypeScript function that receives the logged in user's AuthData and generates a ZQL where expression. At least one rule in a ruleset must return a row for the operation to be allowed. Select Permissions You can limit the data a user can read by specifying a select ruleset. Select permissions act like filters. If a user does not have permission to read a row, it will be filtered out of the result set. It will not generate an error. For example, imagine a select permission that restricts reads to only issues created by the user: definePermissions(schema, () => { const allowIfIssueCreator = ( authData: AuthData, {cmp}: ExpressionBuilder, ) => cmp('creatorID', authData.sub); return { issue: { row: { select: [allowIfIssueCreator], }, }, } satisfies PermissionsConfig; }); If the issue table has two rows, one created by the user and one by someone else, the user will only see the row they created in any queries. Note that although the same limitation applies to declarative insert/update permissions, custom mutators support arbitrary server-side logic and so can easily control which columns are writable. Insert Permissions You can limit what rows can be inserted and by whom by specifying an insert ruleset. Insert rules are evaluated after the entity is inserted. So if they query the database, they will see the inserted row present. If any rule in the insert ruleset returns a row, the insert is allowed. Here's an example of an insert rule that disallows inserting users that have the role 'admin'. definePermissions(schema, () => { const allowIfNonAdmin = ( authData: AuthData, {cmp}: ExpressionBuilder, ) => cmp('role', '!=', 'admin'); return { user: { row: { insert: [allowIfNonAdmin], }, }, } satisfies PermissionsConfig; }); Update Permissions There are two types of update rulesets: preMutation and postMutation. Both rulesets must pass for an update to be allowed. preMutation rules see the version of a row before the mutation is applied. This is useful for things like checking whether a user owns an entity before editing it. postMutation rules see the version of a row after the mutation is applied. This is useful for things like ensuring a user can only mark themselves as the creator of an entity and not other users. Like other rulesets, preMutation and postMutation default to NOBODY\\_CAN. This means that every table must define both these rulesets in order for any updates to be allowed. For example, the following ruleset allows an issue's owner to edit, but not re-assign the issue. The postMutation rule enforces that the current user still own the issue after edit. definePermissions(schema, () => { const allowIfIssueOwner = ( authData: AuthData, {cmp}: ExpressionBuilder, ) => cmp('ownerID', authData.sub); return { issue: { row: { update: { preMutation: [allowIfIssueOwner], postMutation: [allowIfIssueOwner], }, }, }, } satisfies PermissionsConfig; }); This ruleset allows an issue's owner to edit and re-assign the issue: definePermissions(schema, () => { const allowIfIssueOwner = ( authData: AuthData, {cmp}: ExpressionBuilder, ) => cmp('ownerID', authData.sub); return { issue: { row: { update: { preMutation: [allowIfIssueOwner], postMutation: ANYONE_CAN, }, }, }, } satisfies PermissionsConfig; }); And this allows anyone to edit an issue, but only if they also assign it to themselves. Useful for enforcing \"patches welcome\"? π definePermissions(schema, () => { const allowIfIssueOwner = ( authData: AuthData, {cmp}: ExpressionBuilder, ) => cmp('ownerID', authData.sub); return { issue: { row: { update: { preMutation: ANYONE_CAN, postMutation: [allowIfIssueOwner], }, }, }, } satisfies PermissionsConfig; }); Delete Permissions Delete permissions work in the same way as insert permissions except they run before the delete is applied. So if a delete rule queries the database, it will see that the deleted row is present. If any rule in the ruleset returns a row, the delete is allowed. Permissions Based on Auth Data You can use the cmpLit helper to define permissions based on a field of the authData parameter: definePermissions(schema, () => { const allowIfAdmin = ( authData: AuthData, {cmpLit}: ExpressionBuilder, ) => cmpLit(authData.role, 'admin'); return { issue: { row: { select: [allowIfAdmin], }, }, } satisfies PermissionsConfig; }); Debugging See Debugging Permissions. Examples See hello-zero for a simple example of write auth and zbugs for a much more involved one.",
"headings": []
},
{
- "id": "19-postgres-support",
+ "id": "18-postgres-support",
"title": "Supported Postgres Features",
"url": "/docs/postgres-support",
- "content": "Postgres has a massive feature set, and Zero supports a growing subset of it. Object Names Table and column names must begin with a letter or underscore This can be followed by letters, numbers, underscores, and hyphens Regex: /^\\[A-Za-z\\_]+\\[A-Za-z0-9\\_-]\\*$/ The column name \\_0\\_version is reserved for internal use Object Types Tables are synced Views are not synced identity generated columns are synced All other generated columns are not synced Indexes aren't synced per-se, but we do implicitly add indexes to the replica that match the upstream indexes. In the future, this will be customizable. Column Types Zero will sync arrays to the client, but there is no support for filtering or joining on array elements yet in ZQL. Other Postgres column types arenβt supported. They will be ignored when replicating (the synced data will be missing that column) and you will get a warning when zero-cache starts up. If your schema has a pg type not listed here, you can support it in Zero by using a trigger to map it to some type that Zero can support. For example if you have a GIS polygon type in the column my\\_poly polygon, you can use a trigger to map it to a my\\_poly\\_json json column. You could either use another trigger to map in the reverse direction to support changes for writes, or you could use a custom mutator to write to the polygon type directly on the server. Let us know if the lack of a particular column type is hindering your use of Zero. It can likely be added. Column Defaults Default values are allowed in the Postgres schema, but there currently is no way to use them from a Zero app. An insert() mutation requires all columns to be specified, except when columns are nullable (in which case, they default to null). Since there is no way to leave non-nullable columns off the insert on the client, there is no way for PG to apply the default. This is a known issue and will be fixed in the future. IDs It is strongly recommended to use client-generated random strings like uuid, ulid, nanoid, etc for primary keys. This makes optimistic creation and updates much easier. You could sync the highest value seen for that table, but there are race conditions and it is possible for that ID to be taken by the time the creation makes it to the server. Your database can resolve this and assign the next ID, but now the relationships you created optimistically will be against the wrong row. Blech. GUIDs makes a lot more sense in synced applications. If your table has a natural key you can use that and it has less problems. But there is still the chance for a conflict. Imagine you are modeling orgs and you choose domainName as the natural key. It is possible for a race to happen and when the creation gets to the server, somebody has already chosen that domain name. In that case, the best thing to do is reject the write and show the user an error. If you want to have a short auto-incrementing numeric ID for UX reasons (i.e., a bug number), that is possible - see this video. Primary Keys Each table synced with Zero must have either a primary key or at least one unique index. This is needed so that Zero can identify rows during sync, to distinguish between an edit and a remove/add. Multi-column primary and foreign keys are supported. Limiting Replication You can use Permissions to limit tables and rows from replicating to Zero. In the near future, you'll also be able to use Permissions to limit individual columns. Until then, a workaround is to use the Postgres publication feature to control the tables and columns that are replicated into zero-cache. In your pg schema setup, create a Postgres publication with the tables and columns you want: ```sql CREATE PUBLICATION zero_data FOR TABLE users (col1, col2, col3, ...), issues, comments; ``` Then, specify this publication in the App Publications zero-cache option. (By default, Zero creates a publication that publishes the entire public schema.) To limit what is synced from the zero-cache replica to actual clients (e.g., web browsers) you can use read permissions. Schema changes Most Postgres schema changes are supported as is. Two cases require special handling: Adding columns Adding a column with a non-constant DEFAULT value is not supported. This includes any expression with parentheses, as well as the special functions CURRENT\\_TIME, CURRENT\\_DATE, and CURRENT\\_TIMESTAMP (due to a constraint of SQLite). However, the DEFAULT value of an existing column can be changed to any value, including non-constant expressions. To achieve the desired column default: Add the column with no DEFAULT value Backfill the column with desired values Set the column's DEFAULT value ```sql BEGIN; ALTER TABLE foo ADD bar ...; -- without a DEFAULT value UPDATE foo SET bar = ...; ALTER TABLE foo ALTER bar SET DEFAULT ...; COMMIT; ``` Changing publications Postgres allows you to change published tables/columns with an ALTER PUBLICATION statement. Zero automatically adjusts the table schemas on the replica, but it does not receive the pre-existing data. To stream the pre-existing data to Zero, make an innocuous UPDATE after adding the tables/columns to the publication: ```sql BEGIN; ALTER PUBLICATION zero_data ADD TABLE foo; ALTER TABLE foo REPLICA IDENTITY FULL; UPDATE foo SET id = id; -- For some column \"id\" in \"foo\" ALTER TABLE foo REPLICA IDENTITY DEFAULT; COMMIT; ``` Self-Referential Relationships See zero-schema",
+ "content": "Postgres has a massive feature set, and Zero supports a growing subset of it. Object Names Table and column names must begin with a letter or underscore This can be followed by letters, numbers, underscores, and hyphens Regex: /^\\[A-Za-z\\_]+\\[A-Za-z0-9\\_-]\\*$/ The column name \\_0\\_version is reserved for internal use Object Types Tables are synced Views are not synced identity generated columns are synced All other generated columns are not synced Indexes aren't synced per-se, but we do implicitly add indexes to the replica that match the upstream indexes. In the future, this will be customizable. Column Types Zero will sync arrays to the client, but there is no support for filtering or joining on array elements yet in ZQL. Other Postgres column types arenβt supported. They will be ignored when replicating (the synced data will be missing that column) and you will get a warning when zero-cache starts up. If your schema has a pg type not listed here, you can support it in Zero by using a trigger to map it to some type that Zero can support. For example if you have a GIS polygon type in the column my\\_poly polygon, you can use a trigger to map it to a my\\_poly\\_json json column. You could either use another trigger to map in the reverse direction to support changes for writes, or you could use a custom mutator to write to the polygon type directly on the server. Let us know if the lack of a particular column type is hindering your use of Zero. It can likely be added. Column Defaults Default values are allowed in the Postgres schema, but there currently is no way to use them from a Zero app. An insert() mutation requires all columns to be specified, except when columns are nullable (in which case, they default to null). Since there is no way to leave non-nullable columns off the insert on the client, there is no way for PG to apply the default. This is a known issue and will be fixed in the future. IDs It is strongly recommended to use client-generated random strings like uuid, ulid, nanoid, etc for primary keys. This makes optimistic creation and updates much easier. You could sync the highest value seen for that table, but there are race conditions and it is possible for that ID to be taken by the time the creation makes it to the server. Your database can resolve this and assign the next ID, but now the relationships you created optimistically will be against the wrong row. Blech. GUIDs makes a lot more sense in synced applications. If your table has a natural key you can use that and it has less problems. But there is still the chance for a conflict. Imagine you are modeling orgs and you choose domainName as the natural key. It is possible for a race to happen and when the creation gets to the server, somebody has already chosen that domain name. In that case, the best thing to do is reject the write and show the user an error. If you want to have a short auto-incrementing numeric ID for UX reasons (i.e., a bug number), that is possible - see this video. Primary Keys Each table synced with Zero must have either a primary key or at least one unique index. This is needed so that Zero can identify rows during sync, to distinguish between an edit and a remove/add. Multi-column primary and foreign keys are supported. Limiting Replication You can use Permissions to limit tables and rows from replicating to Zero. In the near future, you'll also be able to use Permissions to limit individual columns. Until then, a workaround is to use the Postgres publication feature to control the tables and columns that are replicated into zero-cache. In your pg schema setup, create a Postgres publication with the tables and columns you want: CREATE PUBLICATION zero_data FOR TABLE users (col1, col2, col3, ...), issues, comments; Then, specify this publication in the App Publications zero-cache option. (By default, Zero creates a publication that publishes the entire public schema.) To limit what is synced from the zero-cache replica to actual clients (e.g., web browsers) you can use read permissions. Schema changes Most Postgres schema changes are supported as is. Two cases require special handling: Adding columns Adding a column with a non-constant DEFAULT value is not supported. This includes any expression with parentheses, as well as the special functions CURRENT\\_TIME, CURRENT\\_DATE, and CURRENT\\_TIMESTAMP (due to a constraint of SQLite). However, the DEFAULT value of an existing column can be changed to any value, including non-constant expressions. To achieve the desired column default: Add the column with no DEFAULT value Backfill the column with desired values Set the column's DEFAULT value BEGIN; ALTER TABLE foo ADD bar ...; -- without a DEFAULT value UPDATE foo SET bar = ...; ALTER TABLE foo ALTER bar SET DEFAULT ...; COMMIT; Changing publications Postgres allows you to change published tables/columns with an ALTER PUBLICATION statement. Zero automatically adjusts the table schemas on the replica, but it does not receive the pre-existing data. To stream the pre-existing data to Zero, make an innocuous UPDATE after adding the tables/columns to the publication: BEGIN; ALTER PUBLICATION zero_data ADD TABLE foo; ALTER TABLE foo REPLICA IDENTITY FULL; UPDATE foo SET id = id; -- For some column \"id\" in \"foo\" ALTER TABLE foo REPLICA IDENTITY DEFAULT; COMMIT; Self-Referential Relationships See zero-schema",
"headings": []
},
{
- "id": "20-quickstart",
+ "id": "19-quickstart",
"title": "Quickstart",
"url": "/docs/quickstart",
- "content": "Prerequisites Docker Node 20+ Run In one terminal, install and start the database: ```bash git clone https://github.com/rocicorp/hello-zero.git cd hello-zero npm install npm run dev:db-up ``` In a second terminal, start zero-cache: ```bash cd hello-zero npm run dev:zero-cache ``` In a final terminal, start the UI: ```bash cd hello-zero npm run dev:ui ``` Quick Overview hello-zero is a demo app that allows querying over a small dataset of fake messages between early Zero users. Here are some things to try: Press the Add Messages button to add messages to the UI. Any logged-in or anonymous users are allowed to add messages. Press the Remove Messages button to remove messages. Only logged-in users are allowed to remove messages. You can hold shift to bypass the UI warning and see that write access control is being enforced server-side β the UI flickers as the optimistic write happens instantly and is then reverted by the server. Press login to login as a random user, then the remove button will work. Open two different browsers and see how fast sync propagates changes. Add a filter using the From and Contains controls. Notice that filters are fully dynamic and synced. Edit a message by pressing the pencil icon. You can only edit messages from the user youβre logged in as. As before you can attempt to bypass by holding shift. Check out the SQL schema for this database in seed.sql. Login to the database with psql postgresql://user:password@127.0.0.1:5430/postgres (or any other pg viewer) and delete or alter a row. Observe that it deletes from UI automatically. Detailed Walkthrough Deployment You can deploy Zero apps to most cloud providers that support Docker and Postgres. See Deployment for more information.",
+ "content": "Prerequisites Docker Node 20+ Run In one terminal, install and start the database: git clone https://github.com/rocicorp/hello-zero.git cd hello-zero npm install npm run dev:db-up In a second terminal, start zero-cache: cd hello-zero npm run dev:zero-cache In a final terminal, start the UI: cd hello-zero npm run dev:ui Quick Overview hello-zero is a demo app that allows querying over a small dataset of fake messages between early Zero users. Here are some things to try: Press the Add Messages button to add messages to the UI. Any logged-in or anonymous users are allowed to add messages. Press the Remove Messages button to remove messages. Only logged-in users are allowed to remove messages. You can hold shift to bypass the UI warning and see that write access control is being enforced server-side β the UI flickers as the optimistic write happens instantly and is then reverted by the server. Press login to login as a random user, then the remove button will work. Open two different browsers and see how fast sync propagates changes. Add a filter using the From and Contains controls. Notice that filters are fully dynamic and synced. Edit a message by pressing the pencil icon. You can only edit messages from the user youβre logged in as. As before you can attempt to bypass by holding shift. Check out the SQL schema for this database in seed.sql. Login to the database with psql postgresql://user:password@127.0.0.1:5430/postgres (or any other pg viewer) and delete or alter a row. Observe that it deletes from UI automatically. Detailed Walkthrough Deployment You can deploy Zero apps to most cloud providers that support Docker and Postgres. See Deployment for more information.",
"headings": []
},
{
- "id": "21-react",
+ "id": "20-react",
"title": "React",
"url": "/docs/react",
- "content": "Zero has built-in support for React. Hereβs what basic usage looks like: ```tsx import {useQuery, useZero} from '@rocicorp/zero/react'; import {type Schema} from './schema.ts'; import {type Mutators} from './mutators.ts'; function IssueList() { const z = useZero(); let issueQuery = z.query.issue .related('creator') .related('labels') .limit(100); const userID = selectedUserID(); if (userID) { issueQuery = issueQuery.where('creatorID', '=', userID); } const [issues, issuesDetail] = useQuery(issueQuery); return ( <>
> ); } ``` ZeroProvider The useZero hook must be used within a ZeroProvider component. The ZeroProvider component is responsible for creating and destroying Zero instances reactively. ```tsx import {SessionProvider} from 'my-auth-provider'; import {ZeroProvider} from '@rocicorp/zero/react'; import {type Schema, schema} from './schema.ts'; import {type Mutators, createMutators} from './mutators.ts'; export function Root() { const session = useSession(); const {userID, authToken: auth} = session; const server = import.meta.env.VITE_PUBLIC_SERVER; const mutators = useMemo(() => { return createMutators(auth); }, [auth]); return ( // ZeroProvider will reactively create and destroy Zero instances // as needed when props change. ); } ``` You can also pass a Zero instance to the ZeroProvider if you want to control the lifecycle of the Zero instance yourself: ```tsx // ZeroProvider just sets up the context, it doesn't manage // the lifecycle of the Zero instance. ``` Complete quickstart here: https://github.com/rocicorp/hello-zero",
+ "content": "Zero has built-in support for React. Hereβs what basic usage looks like: import {useQuery, useZero} from '@rocicorp/zero/react'; import {type Schema} from './schema.ts'; import {type Mutators} from './mutators.ts'; function IssueList() { const z = useZero(); let issueQuery = z.query.issue .related('creator') .related('labels') .limit(100); const userID = selectedUserID(); if (userID) { issueQuery = issueQuery.where('creatorID', '=', userID); } const [issues, issuesDetail] = useQuery(issueQuery); return ( <>
> ); } ZeroProvider The useZero hook must be used within a ZeroProvider component. The ZeroProvider component is responsible for creating and destroying Zero instances reactively. import {SessionProvider} from 'my-auth-provider'; import {ZeroProvider} from '@rocicorp/zero/react'; import {type Schema, schema} from './schema.ts'; import {type Mutators, createMutators} from './mutators.ts'; export function Root() { const session = useSession(); const {userID, authToken: auth} = session; const server = import.meta.env.VITE_PUBLIC_SERVER; const mutators = useMemo(() => { return createMutators(auth); }, [auth]); return ( // ZeroProvider will reactively create and destroy Zero instances // as needed when props change. ); } You can also pass a Zero instance to the ZeroProvider if you want to control the lifecycle of the Zero instance yourself: // ZeroProvider just sets up the context, it doesn't manage // the lifecycle of the Zero instance. Complete quickstart here: https://github.com/rocicorp/hello-zero",
"headings": []
},
{
- "id": "22-reading-data",
+ "id": "21-reading-data",
"title": "Reading Data with ZQL",
"url": "/docs/reading-data",
- "content": "ZQL is Zeroβs query language. Inspired by SQL, ZQL is expressed in TypeScript with heavy use of the builder pattern. If you have used Drizzle or Kysely, ZQL will feel familiar. ZQL queries are composed of one or more clauses that are chained together into a query. Unlike queries in classic databases, the result of a ZQL query is a view that updates automatically and efficiently as the underlying data changes. You can call a queryβs materialize() method to get a view, but more typically you run queries via some framework-specific bindings. For example see useQuery for React or SolidJS. ZQL caches values and returns them multiple times. If you modify a value returned from ZQL, you will modify it everywhere it is used. This can lead to subtle bugs. JavaScript and TypeScript lack true immutable types so we use readonly to help enforce it. But it's easy to cast away the readonly accidentally. In the future, we'll freeze all returned data in dev mode to help prevent this. Select ZQL queries start by selecting a table. There is no way to select a subset of columns; ZQL queries always return the entire row (modulo column permissions). ```tsx const z = new Zero(...); // Returns a query that selects all rows and columns from the issue table. z.query.issue; ``` This is a design tradeoff that allows Zero to better reuse the row locally for future queries. This also makes it easier to share types between different parts of the code. Ordering You can sort query results by adding an orderBy clause: ```tsx z.query.issue.orderBy('created', 'desc'); ``` Multiple orderBy clauses can be present, in which case the data is sorted by those clauses in order: ```tsx // Order by priority descending. For any rows with same priority, // then order by created desc. z.query.issue.orderBy('priority', 'desc').orderBy('created', 'desc'); ``` All queries in ZQL have a default final order of their primary key. Assuming the issue table has a primary key on the id column, then: ```tsx // Actually means: z.query.issue.orderBy('id', 'asc'); z.query.issue; // Actually means: z.query.issue.orderBy('priority', 'desc').orderBy('id', 'asc'); z.query.issue.orderBy('priority', 'desc'); ``` Limit You can limit the number of rows to return with limit(): ```tsx z.query.issue.orderBy('created', 'desc').limit(100); ``` Paging You can start the results at or after a particular row with start(): ```tsx let start: IssueRow | undefined; while (true) { let q = z.query.issue.orderBy('created', 'desc').limit(100); if (start) { q = q.start(start); } const batch = await q.run(); console.log('got batch', batch); if (batch.length < 100) { break; } start = batch[batch.length - 1]; } ``` By default start() is exclusive - it returns rows starting after the supplied reference row. This is what you usually want for paging. If you want inclusive results, you can do: ```tsx z.query.issue.start(row, {inclusive: true}); ``` Getting a Single Result If you want exactly zero or one results, use the one() clause. This causes ZQL to return Row|undefined rather than Row\\[]. ```tsx const result = await z.query.issue.where('id', 42).one().run(); if (!result) { console.error('not found'); } ``` one() overrides any limit() clause that is also present. Relationships You can query related rows using relationships that are defined in your Zero schema. ```tsx // Get all issues and their related comments z.query.issue.related('comments'); ``` Relationships are returned as hierarchical data. In the above example, each row will have a comments field which is itself an array of the corresponding comments row. You can fetch multiple relationships in a single query: ```tsx z.query.issue.related('comments').related('reactions').related('assignees'); ``` Refining Relationships By default all matching relationship rows are returned, but this can be refined. The related method accepts an optional second function which is itself a query. ```tsx z.query.issue.related( 'comments', // It is common to use the 'q' shorthand variable for this parameter, // but it is a _comment_ query in particular here, exactly as if you // had done z.query.comment. q => q.orderBy('modified', 'desc').limit(100).start(lastSeenComment), ); ``` This relationship query can have all the same clauses that top-level queries can have. You can sometimes work around this by making the junction relationship explicit, depending on your schema and usage. Nested Relationships You can nest relationships arbitrarily: ```tsx // Get all issues, first 100 comments for each (ordered by modified,desc), // and for each comment all of its reactions. z.query.issue.related('comments', q => q.orderBy('modified', 'desc').limit(100).related('reactions'), ); ``` Where You can filter a query with where(): ```tsx z.query.issue.where('priority', '=', 'high'); ``` The first parameter is always a column name from the table being queried. Intellisense will offer available options (sourced from your Zero Schema). Comparison Operators Where supports the following comparison operators: | Operator | Allowed Operand Types | Description | | ---------------------------------------- | ----------------------------- | ------------------------------------------------------------------------ | | = , != | boolean, number, string | JS strict equal (===) semantics | | < , <=, >, >= | number | JS number compare semantics | | LIKE, NOT LIKE, ILIKE, NOT ILIKE | string | SQL-compatible LIKE / ILIKE | | IN , NOT IN | boolean, number, string | RHS must be array. Returns true if rhs contains lhs by JS strict equals. | | IS , IS NOT | boolean, number, string, null | Same as = but also works for null | TypeScript will restrict you from using operators with types that donβt make sense β you canβt use > with boolean for example. Equals is the Default Comparison Operator Because comparing by = is so common, you can leave it out and where defaults to =. ```tsx z.query.issue.where('priority', 'high'); ``` Comparing to null As in SQL, ZQLβs null is not equal to itself (null β null). This is required to make join semantics work: if youβre joining employee.orgID on org.id you do not want an employee in no organization to match an org that hasnβt yet been assigned an ID. When you purposely want to compare to null ZQL supports IS and IS NOT operators that work just like in SQL: ```tsx // Find employees not in any org. z.query.employee.where('orgID', 'IS', null); ``` TypeScript will prevent you from comparing to null with other operators. Compound Filters The argument to where can also be a callback that returns a complex expression: ```tsx // Get all issues that have priority 'critical' or else have both // priority 'medium' and not more than 100 votes. z.query.issue.where(({cmp, and, or, not}) => or( cmp('priority', 'critical'), and(cmp('priority', 'medium'), not(cmp('numVotes', '>', 100))), ), ); ``` cmp is short for compare and works the same as where at the top-level except that it canβt be chained and it only accepts comparison operators (no relationship filters β see below). Note that chaining where() is also a one-level and: ```tsx // Find issues with priority 3 or higher, owned by aa z.query.issue.where('priority', '>=', 3).where('owner', 'aa'); ``` Relationship Filters Your filter can also test properties of relationships. Currently the only supported test is existence: ```tsx // Find all orgs that have at least one employee z.query.organization.whereExists('employees'); ``` The argument to whereExists is a relationship, so just like other relationships it can be refined with a query: ```tsx // Find all orgs that have at least one cool employee z.query.organization.whereExists('employees', q => q.where('location', 'Hawaii'), ); ``` As with querying relationships, relationship filters can be arbitrarily nested: ```tsx // Get all issues that have comments that have reactions z.query.issue.whereExists('comments', q => q.whereExists('reactions')); ); ``` The exists helper is also provided which can be used with and, or, cmp, and not to build compound filters that check relationship existence: ```tsx // Find issues that have at least one comment or are high priority z.query.issue.where({cmp, or, exists} => or( cmp('priority', 'high'), exists('comments'), ), ); ``` Data Lifetime and Reuse Zero reuses data synced from prior queries to answer new queries when possible. This is what enables instant UI transitions. But what controls the lifetime of this client-side data? How can you know whether any particular query will return instant results? How can you know whether those results will be up to date or stale? The answer is that the data on the client is simply the union of rows returned from queries which are currently syncing. Once a row is no longer returned by any syncing query, it is removed from the client. Thus, there is never any stale data in Zero. So when you are thinking about whether a query is going to return results instantly, you should think about what other queries are syncing, not about what data is local. Data exists locally if and only if there is a query syncing that returns that data. A cache has a random set of rows with a random set of versions. There is no expectation that the cache any particular rows, or that the rows' have matching versions. Rows are simply updated as they are fetched. A replica by contrast is eagerly updated, whether or not any client has requested a row. A replica is always very close to up-to-date, and always self-consistent. Zero is a partial replica because it only replicates rows that are returned by syncing queries. Query Lifecycle Queries can be either active or backgrounded. An active query is one that is currently being used by the application. Backgrounded queries are not currently in use, but continue syncing in case they are needed again soon. Active queries are created one of three ways: The app calls q.materialize() to get a View. The app uses a platform binding like React's useQuery(q). The app calls preload() to sync larger queries without a view. Active queries sync until they are deactivated. The way this happens depends on how the query was created: For materialize() queries, the UI calls destroy() on the view. For useQuery(), the UI unmounts the component (which calls destroy() under the covers). For preload(), the UI calls cleanup() on the return value of preload(). Background Queries By default a deactivated query stops syncing immediately. But it's often useful to keep queries syncing beyond deactivation in case the UI needs the same or a similar query in the near future. This is accomplished with the ttl parameter: ```ts const [user] = useQuery(z.query.user.where('id', userId), {ttl: '1d'}); ``` The ttl parameter specifies how long the app developer wishes the query to run in the background. The following formats are allowed (where %d is a positive integer): | Format | Meaning | | --------- | ------------------------------------------------------------------------------------ | | none | No backgrounding. Query will immediately stop when deactivated. This is the default. | | %ds | Number of seconds. | | %dm | Number of minutes. | | %dh | Number of hours. | | %dd | Number of days. | We realized long ttl values can lead to a lot of queries running in the background unnecessarily. If a new app release is deployed with new queries, the old queries keep running until their ttl expires, even though the app will never use them. We will be reworking this API to be less of a footgun in the next Zero release. For now we do not recommend using a ttl greater than 1d. If the UI re-requests a background query, it becomes an active query again. Since the query was syncing in the background, the very first synchronous result that the UI receives after reactivation will be up-to-date with the server (i.e., it will have resultType of complete). Just like other types of queries, the data from background queries is available for use by new queries. A common pattern in to preload a subset of most commonly needed data with {ttl: 'forever'} and then do more specific queries from the UI with, e.g., {ttl: '1d'}. Most often the preloaded data will be able to answer user queries, but if not, the new query will be answered by the server and backgrounded for a day in case the user revisits it. Client Capacity Management Zero has a default soft limit of 20,000 rows on the client-side, or about 20MB of data assuming 1KB rows. This limit can be increased with the --target-client-row-count flag, but we do not recommend setting it higher than 100,000. Initial sync will be slow, slowing down initial app load. Because storage in browser tabs is unreliable, initial sync can occur surprisingly often. We want to answer queries instantly as often as possible. This requires client-side data in memory on the main thread. If we have to page to disk, we may as well go to the network and reduce complexity. Even though Zero's queries are very efficient, they do still have some cost, especially hydration. Massive client-side storage would result in hydrating tons of queries that are unlikely to be used every time the app starts. Most importantly, no matter how much data you store on the client, there will be cases where you have to fallback to the server: Some users might have huge amounts of data. Some users might have tiny amounts of available client storage. You will likely want the app to start fast and sync in the background. Because you have to be able to fallback to server the question becomes what is the right amount of data to store on the client?, not how can I store the absolute max possible data on the client? The goal with Zero is to answer 99% of queries on the client from memory. The remaining 1% of queries can fallback gracefully to the server. 20,000 rows was chosen somewhat arbitrarily as a number of rows that was likely to be able to do this for many applications. There is no hard limit at 20,000 or 100,000. Nothing terrible happens if you go above. The thing to keep in mind is that: All those queries will revalidate every time your app boots. All data synced to the client is in memory in JS. Here is how this limit is managed: Active queries are never destroyed, even if the limit is exceeded. Developers are expected to keep active queries well under the limit. The ttl value counts from the moment a query deactivates. Backgrounded queries are destroyed immediately when the ttl is reached, even if the limit hasn't been reached. If the client exceeds its limit, Zero will destroy backgrounded queries, least-recently-used first, until the store is under the limit again. Thinking in Queries Although IVM is a very efficient way to keep queries up to date relative to re-running them, it isn't free. You still need to think about how many queries you are creating, how long they are kept alive, and how expensive they are. This is why Zero defaults to not backgrounding queries and doesn't try to aggressively fill its client datastore to capacity. You should put some thought into what queries you want to run in the background, and for how long. Zero currently provides a few basic tools to understand the cost of your queries: The client logs a warning for slow query materializations. Look for Slow query materialization in your logs. The default threshold is 5s (including network) but this is configurable with the slowMaterializeThreshold parameter. The client logs the materialization time of all queries at the debug level. Look for Materialized query in your logs. The server logs a warning for slow query materializations. Look for Slow query materialization in your logs. The default threshold is 5s but this is configurable with the log-slow-materialize-threshold configuration parameter. We will be adding more tools over time. Completeness Zero returns whatever data it has on the client immediately for a query, then falls back to the server for any missing data. Sometimes it's useful to know the difference between these two types of results. To do so, use the result from useQuery: ```tsx const [issues, issuesResult] = useQuery(z.query.issue); if (issuesResult.type === 'complete') { console.log('All data is present'); } else { console.log('Some data is missing'); } ``` The possible values of result.type are currently complete and unknown. The complete value is currently only returned when Zero has received the server result. But in the future, Zero will be able to return this result type when it knows that all possible data for this query is already available locally. Additionally, we plan to add a prefix result for when the data is known to be a prefix of the complete result. See Consistency for more information. Handling Missing Data It is inevitable that there will be cases where the requested data cannot be found. Because Zero returns local results immediately, and server results asynchronously, displaying \"not found\" / 404 UI can be slightly tricky. If you just use a simple existence check, you will often see the 404 UI flicker while the server result loads: ```tsx const [issue, issuesResult] = useQuery( z.query.issue.where('id', 'some-id').one(), ); // β This causes flickering of the UI if (!issue) { return
404 Not Found
; } else { return
{issue}
; } ``` The way to do this correctly is to only display the \"not found\" UI when the result type is complete. This way the 404 page is slow but pages with data are still just as fast. ```tsx const [issue, issuesResult] = useQuery( z.query.issue.where('id', 'some-id').one(), ); if (!issue && issueResult.type === 'complete') { return
404 Not Found
; } if (!issue) { return null; } return
{issue}
; ``` Listening to Changes Currently, the way to listen for changes in query results is not ideal. You can add a listener to a materialized view which has the new data and result as parameters: ```ts z.query.issue.materialize().addListener((issues, issuesResult) => { // do stuff... }); ``` However, using this method will maintain its own materialized view in memory which is wasteful. It also doesn't allow for granular listening to events like add and remove of rows. A better way would be to create your own view without actually storing the data which will also allow you to listen to specific events. Again, the API is not good and will be improved in the future. ```ts // Inside the View class // Instead of storing the change, we invoke some callback push(change: Change): void { switch (change.type) { case 'add': this.#onAdd?.(change) break case 'remove': this.#onRemove?.(change) break case 'edit': this.#onEdit?.(change) break case 'child': this.#onChild?.(change) break default: throw new Error(`Unknown change type: ${change['type']}`) } } ``` (see View implementations in zero-vue or zero-solid) Preloading Almost all Zero apps will want to preload some data in order to maximize the feel of instantaneous UI transitions. In Zero, preloading is done via queries β the same queries you use in the UI and for auth. However, because preload queries are usually much larger than a screenful of UI, Zero provides a special preload() helper to avoid the overhead of materializing the result into JS objects: ```tsx // Preload the first 1k issues + their creator, assignee, labels, and // the view state for the active user. // // There's no need to render this data, so we don't use `useQuery()`: // this avoids the overhead of pulling all this data into JS objects. z.query.issue .related('creator') .related('assignee') .related('labels') .related('viewState', q => q.where('userID', z.userID).one()) .orderBy('created', 'desc') .limit(1000) .preload(); ``` Running Queries Once Usually subscribing to a query is what you want in a reactive UI, but every so often you'll need to run a query just once. To do this, use the run() method: ```tsx const results = await z.query.issue.where('foo', 'bar').run(); ``` By default, run() only returns results that are currently available on the client. That is, it returns the data that would be given for result.type === 'unknown'. If you want to wait for the server to return results, pass {type: 'complete'} to run: ```tsx const results = await z.query.issue.where('foo', 'bar').run({type: 'complete'});await z.query.issue.where('foo', 'bar'); ``` This is the same as saying run() or run({type: 'unknown'}). Consistency Zero always syncs a consistent partial replica of the backend database to the client. This avoids many common consistency issues that come up in classic web applications. But there are still some consistency issues to be aware of when using Zero. For example, imagine that you have a bug database w/ 10k issues. You preload the first 1k issues sorted by created. The user then does a query of issues assigned to themselves, sorted by created. Among the 1k issues that were preloaded imagine 100 are found that match the query. Since the data we preloaded is in the same order as this query, we are guaranteed that any local results found will be a prefix of the server results. The UX that result is nice: the user will see initial results to the query instantly. If more results are found server-side, those results are guaranteed to sort below the local results. There's no shuffling of results when the server response comes in. Now imagine that the user switches the sort to βsort by modifiedβ. This new query will run locally, and will again find some local matches. But it is now unlikely that the local results found are a prefix of the server results. When the server result comes in, the user will probably see the results shuffle around. To avoid this annoying effect, what you should do in this example is also preload the first 1k issues sorted by modified desc. In general for any query shape you intend to do, you should preload the first n results for that query shape with no filters, in each sort you intend to use. In the future, we will be implementing a consistency model that fixes these issues automatically. We will prevent Zero from returning local data when that data is not known to be a prefix of the server result. Once the consistency model is implemented, preloading can be thought of as purely a performance thing, and not required to avoid unsightly flickering.",
+ "content": "ZQL is Zeroβs query language. Inspired by SQL, ZQL is expressed in TypeScript with heavy use of the builder pattern. If you have used Drizzle or Kysely, ZQL will feel familiar. ZQL queries are composed of one or more clauses that are chained together into a query. Unlike queries in classic databases, the result of a ZQL query is a view that updates automatically and efficiently as the underlying data changes. You can call a queryβs materialize() method to get a view, but more typically you run queries via some framework-specific bindings. For example see useQuery for React or SolidJS. ZQL caches values and returns them multiple times. If you modify a value returned from ZQL, you will modify it everywhere it is used. This can lead to subtle bugs. JavaScript and TypeScript lack true immutable types so we use readonly to help enforce it. But it's easy to cast away the readonly accidentally. In the future, we'll freeze all returned data in dev mode to help prevent this. Select ZQL queries start by selecting a table. There is no way to select a subset of columns; ZQL queries always return the entire row (modulo column permissions). const z = new Zero(...); // Returns a query that selects all rows and columns from the issue table. z.query.issue; This is a design tradeoff that allows Zero to better reuse the row locally for future queries. This also makes it easier to share types between different parts of the code. Ordering You can sort query results by adding an orderBy clause: z.query.issue.orderBy('created', 'desc'); Multiple orderBy clauses can be present, in which case the data is sorted by those clauses in order: // Order by priority descending. For any rows with same priority, // then order by created desc. z.query.issue.orderBy('priority', 'desc').orderBy('created', 'desc'); All queries in ZQL have a default final order of their primary key. Assuming the issue table has a primary key on the id column, then: // Actually means: z.query.issue.orderBy('id', 'asc'); z.query.issue; // Actually means: z.query.issue.orderBy('priority', 'desc').orderBy('id', 'asc'); z.query.issue.orderBy('priority', 'desc'); Limit You can limit the number of rows to return with limit(): z.query.issue.orderBy('created', 'desc').limit(100); Paging You can start the results at or after a particular row with start(): let start: IssueRow | undefined; while (true) { let q = z.query.issue.orderBy('created', 'desc').limit(100); if (start) { q = q.start(start); } const batch = await q.run(); console.log('got batch', batch); if (batch.length < 100) { break; } start = batch[batch.length - 1]; } By default start() is exclusive - it returns rows starting after the supplied reference row. This is what you usually want for paging. If you want inclusive results, you can do: z.query.issue.start(row, {inclusive: true}); Getting a Single Result If you want exactly zero or one results, use the one() clause. This causes ZQL to return Row|undefined rather than Row\\[]. const result = await z.query.issue.where('id', 42).one().run(); if (!result) { console.error('not found'); } one() overrides any limit() clause that is also present. Relationships You can query related rows using relationships that are defined in your Zero schema. // Get all issues and their related comments z.query.issue.related('comments'); Relationships are returned as hierarchical data. In the above example, each row will have a comments field which is itself an array of the corresponding comments row. You can fetch multiple relationships in a single query: z.query.issue.related('comments').related('reactions').related('assignees'); Refining Relationships By default all matching relationship rows are returned, but this can be refined. The related method accepts an optional second function which is itself a query. z.query.issue.related( 'comments', // It is common to use the 'q' shorthand variable for this parameter, // but it is a _comment_ query in particular here, exactly as if you // had done z.query.comment. q => q.orderBy('modified', 'desc').limit(100).start(lastSeenComment), ); This relationship query can have all the same clauses that top-level queries can have. You can sometimes work around this by making the junction relationship explicit, depending on your schema and usage. Nested Relationships You can nest relationships arbitrarily: // Get all issues, first 100 comments for each (ordered by modified,desc), // and for each comment all of its reactions. z.query.issue.related('comments', q => q.orderBy('modified', 'desc').limit(100).related('reactions'), ); Where You can filter a query with where(): z.query.issue.where('priority', '=', 'high'); The first parameter is always a column name from the table being queried. Intellisense will offer available options (sourced from your Zero Schema). Comparison Operators Where supports the following comparison operators: | Operator | Allowed Operand Types | Description | | ---------------------------------------- | ----------------------------- | ------------------------------------------------------------------------ | | = , != | boolean, number, string | JS strict equal (===) semantics | | < , <=, >, >= | number | JS number compare semantics | | LIKE, NOT LIKE, ILIKE, NOT ILIKE | string | SQL-compatible LIKE / ILIKE | | IN , NOT IN | boolean, number, string | RHS must be array. Returns true if rhs contains lhs by JS strict equals. | | IS , IS NOT | boolean, number, string, null | Same as = but also works for null | TypeScript will restrict you from using operators with types that donβt make sense β you canβt use > with boolean for example. Equals is the Default Comparison Operator Because comparing by = is so common, you can leave it out and where defaults to =. z.query.issue.where('priority', 'high'); Comparing to null As in SQL, ZQLβs null is not equal to itself (null β null). This is required to make join semantics work: if youβre joining employee.orgID on org.id you do not want an employee in no organization to match an org that hasnβt yet been assigned an ID. When you purposely want to compare to null ZQL supports IS and IS NOT operators that work just like in SQL: // Find employees not in any org. z.query.employee.where('orgID', 'IS', null); TypeScript will prevent you from comparing to null with other operators. Compound Filters The argument to where can also be a callback that returns a complex expression: // Get all issues that have priority 'critical' or else have both // priority 'medium' and not more than 100 votes. z.query.issue.where(({cmp, and, or, not}) => or( cmp('priority', 'critical'), and(cmp('priority', 'medium'), not(cmp('numVotes', '>', 100))), ), ); cmp is short for compare and works the same as where at the top-level except that it canβt be chained and it only accepts comparison operators (no relationship filters β see below). Note that chaining where() is also a one-level and: // Find issues with priority 3 or higher, owned by aa z.query.issue.where('priority', '>=', 3).where('owner', 'aa'); Comparing Literal Values The where clause always expects its first parameter to be a column name as a string. Same with the cmp helper: // \"foo\" is a column name, not a string: z.query.issue.where('foo', 'bar'); // \"foo\" is a column name, not a string: z.query.issue.where(({cmp}) => cmp('foo', 'bar')); To compareto a literal value, use the cmpLit helper: z.query.issue.where(cmpLit('foobar', 'foo' + 'bar')); By itself this is not very useful, but the first parameter can also be a JavaScript variable: z.query.issue.where(cmpLit(role, 'admin')); Or, within a permission rule, you can compare to a field of the authData parameter: z.query.issue.where(cmpLit(authData.role, 'admin')); Relationship Filters Your filter can also test properties of relationships. Currently the only supported test is existence: // Find all orgs that have at least one employee z.query.organization.whereExists('employees'); The argument to whereExists is a relationship, so just like other relationships it can be refined with a query: // Find all orgs that have at least one cool employee z.query.organization.whereExists('employees', q => q.where('location', 'Hawaii'), ); As with querying relationships, relationship filters can be arbitrarily nested: // Get all issues that have comments that have reactions z.query.issue.whereExists('comments', q => q.whereExists('reactions')); ); The exists helper is also provided which can be used with and, or, cmp, and not to build compound filters that check relationship existence: // Find issues that have at least one comment or are high priority z.query.issue.where({cmp, or, exists} => or( cmp('priority', 'high'), exists('comments'), ), ); Completeness Zero returns whatever data it has on the client immediately for a query, then falls back to the server for any missing data. Sometimes it's useful to know the difference between these two types of results. To do so, use the result from useQuery: const [issues, issuesResult] = useQuery(z.query.issue); if (issuesResult.type === 'complete') { console.log('All data is present'); } else { console.log('Some data is missing'); } The possible values of result.type are currently complete and unknown. The complete value is currently only returned when Zero has received the server result. But in the future, Zero will be able to return this result type when it knows that all possible data for this query is already available locally. Additionally, we plan to add a prefix result for when the data is known to be a prefix of the complete result. See Consistency for more information. Handling Missing Data It is inevitable that there will be cases where the requested data cannot be found. Because Zero returns local results immediately, and server results asynchronously, displaying \"not found\" / 404 UI can be slightly tricky. If you just use a simple existence check, you will often see the 404 UI flicker while the server result loads: const [issue, issuesResult] = useQuery( z.query.issue.where('id', 'some-id').one(), ); // β This causes flickering of the UI if (!issue) { return
404 Not Found
; } else { return
{issue}
; } The way to do this correctly is to only display the \"not found\" UI when the result type is complete. This way the 404 page is slow but pages with data are still just as fast. const [issue, issuesResult] = useQuery( z.query.issue.where('id', 'some-id').one(), ); if (!issue && issueResult.type === 'complete') { return
404 Not Found
; } if (!issue) { return null; } return
{issue}
; Listening to Changes Currently, the way to listen for changes in query results is not ideal. You can add a listener to a materialized view which has the new data and result as parameters: z.query.issue.materialize().addListener((issues, issuesResult) => { // do stuff... }); However, using this method will maintain its own materialized view in memory which is wasteful. It also doesn't allow for granular listening to events like add and remove of rows. A better way would be to create your own view without actually storing the data which will also allow you to listen to specific events. Again, the API is not good and will be improved in the future. // Inside the View class // Instead of storing the change, we invoke some callback push(change: Change): void { switch (change.type) { case 'add': this.#onAdd?.(change) break case 'remove': this.#onRemove?.(change) break case 'edit': this.#onEdit?.(change) break case 'child': this.#onChild?.(change) break default: throw new Error(`Unknown change type: ${change['type']}`) } } (see View implementations in zero-vue or zero-solid) Preloading Almost all Zero apps will want to preload some data in order to maximize the feel of instantaneous UI transitions. In Zero, preloading is done via queries β the same queries you use in the UI and for auth. However, because preload queries are usually much larger than a screenful of UI, Zero provides a special preload() helper to avoid the overhead of materializing the result into JS objects: // Preload the first 1k issues + their creator, assignee, labels, and // the view state for the active user. // // There's no need to render this data, so we don't use `useQuery()`: // this avoids the overhead of pulling all this data into JS objects. z.query.issue .related('creator') .related('assignee') .related('labels') .related('viewState', q => q.where('userID', z.userID).one()) .orderBy('created', 'desc') .limit(1000) .preload(); Data Lifetime and Reuse Zero reuses data synced from prior queries to answer new queries when possible. This is what enables instant UI transitions. But what controls the lifetime of this client-side data? How can you know whether any particular query will return instant results? How can you know whether those results will be up to date or stale? The answer is that the data on the client is simply the union of rows returned from queries which are currently syncing. Once a row is no longer returned by any syncing query, it is removed from the client. Thus, there is never any stale data in Zero. So when you are thinking about whether a query is going to return results instantly, you should think about what other queries are syncing, not about what data is local. Data exists locally if and only if there is a query syncing that returns that data. A cache has a random set of rows with a random set of versions. There is no expectation that the cache any particular rows, or that the rows' have matching versions. Rows are simply updated as they are fetched. A replica by contrast is eagerly updated, whether or not any client has requested a row. A replica is always very close to up-to-date, and always self-consistent. Zero is a partial replica because it only replicates rows that are returned by syncing queries. Query Lifecycle Queries can be either active or cached. An active query is one that is currently being used by the application. Cached queries are not currently in use, but continue syncing in case they are needed again soon. Active queries are created one of four ways: The app calls q.materialize() to get a View. The app uses a framework binding like React's useQuery(q). The app calls preload() to sync larger queries without a view. The app calls q.run() to get a single result. Active queries sync until they are deactivated. The way this happens depends on how the query was created: For materialize() queries, the UI calls destroy() on the view. For useQuery(), the UI unmounts the component (which calls destroy() under the covers). For preload(), the UI calls cleanup() on the return value of preload(). For run(), queries are automatically deactivated immediately after the result is returned. Additionally when a Zero instance closes, all active queries are automatically deactivated. This also happens when the containing page or script is unloaded. TTLs Each query has a ttl that controls how long it stays cached. You do not need to account for such time when choosing a TTL β you only need to account for time your app is running without a query. TTL Defaults In most cases, the default TTL should work well: preload() queries default to ttl:'none', meaning they are not cached at all, and will stop syncing immediately when deactivated. But because preload() queries are typically registered at app startup and never shutdown, and because the ttl clock only ticks while Zero is running, this means that preload queries never get unregistered. Other queries have a default ttl of 5m (five minutes). Setting Different TTLs You can override the default TTL with the ttl parameter: // With useQuery(): const [user] = useQuery( z.query.user.where('id', userId), {ttl: '5m'}); // With preload(): z.query.user.where('id', userId).preload( {ttl: '5m'}); // With run(): const user = await z.query.user.where('id', userId).run( {ttl: '5m'}); // With materialize(): const view = z.query.user.where('id', userId).materialize( {ttl: '5m'}); TTLs up to 10m (ten minutes) are currently supported. The following formats are allowed: | Format | Meaning | | --------- | --------------------------------------------------------- | | none | No caching. Query will immediately stop when deactivated. | | %ds | Number of seconds. | | %dm | Number of minutes. | Choosing a TTL If you choose a different TTL, you should consider how likely it is that the query will be reused, and how far into the future this reuse will occur. Here are some guidelines to help you choose a TTL for common query types: Preload Queries These queries load the most commonly needed data for your app. They are typically larger, run with the preload() method, and stay running the entire time your app is running. Because these queries run the entire time Zero runs, they do not need any TTL to keep them alive. And using a ttl for them is wasteful since when your app changes its preload query, it will end up running the old preload query and the new preload query, even though the app only cares about the new one. Recommendation: ttl: 'none' (the default for preload()). Navigational Queries These queries load data specific to a route. They are typically smaller and run with the useQuery() method. It is useful to cache them for a short time, so that they can be reactivated quickly if the user navigates back to the route. Recommendation: ttl: '5m' (the default for useQuery()). Ephemeral Queries These queries load data for a specific, short-lived user interaction and often come in large numbers (e.g., typeahead search). The chance of any specific ephemeral query being reused is low, so the benefit of caching them is also low. Recommendation: useQuery(..., {ttl: 'none'}))\\*. Why Zero TTLs are Short Zero queries are not free. Just as in any database, queries consume resources on both the client and server. Memory is used to keep metadata about the query, and disk storage is used to keep the query's current state. We do drop this state after we haven't heard from a client for awhile, but this is only a partial improvement. If the client returns, we have to re-run the query to get the latest data. This means that we do not actually want to keep queries active unless there is a good chance they will be needed again soon. The default Zero TTL values might initially seem too short, but they are designed to work well with the way Zero's TTL clock works and strike a good balance between keeping queries alive long enough to be useful, while not keeping them alive so long that they consume resources unnecessarily. If you think you need longer TTLs, please let us know. We are still iterating on these APIs and may have missed something. Alternately we may be able to help you achieve your goal a different way. Running Queries Once Usually subscribing to a query is what you want in a reactive UI, but every so often you'll need to run a query just once. To do this, use the run() method: const results = await z.query.issue.where('foo', 'bar').run(); By default, run() only returns results that are currently available on the client. That is, it returns the data that would be given for result.type === 'unknown'. If you want to wait for the server to return results, pass {type: 'complete'} to run: const results = await z.query.issue.where('foo', 'bar').run({type: 'complete'});await z.query.issue.where('foo', 'bar'); This is the same as saying run() or run({type: 'unknown'}). Consistency Zero always syncs a consistent partial replica of the backend database to the client. This avoids many common consistency issues that come up in classic web applications. But there are still some consistency issues to be aware of when using Zero. For example, imagine that you have a bug database w/ 10k issues. You preload the first 1k issues sorted by created. The user then does a query of issues assigned to themselves, sorted by created. Among the 1k issues that were preloaded imagine 100 are found that match the query. Since the data we preloaded is in the same order as this query, we are guaranteed that any local results found will be a prefix of the server results. The UX that result is nice: the user will see initial results to the query instantly. If more results are found server-side, those results are guaranteed to sort below the local results. There's no shuffling of results when the server response comes in. Now imagine that the user switches the sort to βsort by modifiedβ. This new query will run locally, and will again find some local matches. But it is now unlikely that the local results found are a prefix of the server results. When the server result comes in, the user will probably see the results shuffle around. To avoid this annoying effect, what you should do in this example is also preload the first 1k issues sorted by modified desc. In general for any query shape you intend to do, you should preload the first n results for that query shape with no filters, in each sort you intend to use. In the future, we will be implementing a consistency model that fixes these issues automatically. We will prevent Zero from returning local data when that data is not known to be a prefix of the server result. Once the consistency model is implemented, preloading can be thought of as purely a performance thing, and not required to avoid unsightly flickering.",
"headings": []
},
{
- "id": "23-release-notes/0.1",
+ "id": "22-release-notes/0.1",
"title": "Zero 0.1",
"url": "/docs/release-notes/0.1",
"content": "Breaking changes The name of some config keys in zero.config.json changed: upstreamUri β upstreamDBConnStr cvrDbUri β cvrDBConnStr changeDbUri β changeDBConnStr replicaDbFile β replicaDBFile Changed default port of zero-cache to 4848 . So your app startup should look like VITE\\_PUBLIC\\_SERVER=\"http://localhost:4848\". Features Print a warning to js console when Zero constructor server param is null or undefined zero-cache should now correctly bind to both ipv4 and ipv6 loopback addresses. This should fix the issue where using localhost to connect to zero-cache on some systems did not work. Check for presence of WebSocket early in startup of Zero. Print a clear error to catch people accidentally running Zero under SSR. Fix annoying error in js console in React strict mode from constructing and closing Replicache in quick succession. Source tree fixes These only apply if you were working in the Rocicorp monorepo. Fixed issue where zbugs didnβt rebuild when zero dependency changed - generally zbugs build normally again The zero binary has the right permissions bit so you donβt have to chmod u+x after build Remove overloaded name snapshot in use-query.tsx (thanks Scott π)",
"headings": []
},
{
- "id": "24-release-notes/0.10",
+ "id": "23-release-notes/0.10",
"title": "Zero 0.10",
"url": "/docs/release-notes/0.10",
- "content": "Install ```bash npm install @rocicorp/zero@0.10 ``` Features None. Fixes Remove top-level await from zero-client. Various logging improvements. Don't throw error when WebSocket unavailable on server. Support building on Windows (running on Windows still doesn't work) Breaking Changes None.",
+ "content": "Install npm install @rocicorp/zero@0.10 Features None. Fixes Remove top-level await from zero-client. Various logging improvements. Don't throw error when WebSocket unavailable on server. Support building on Windows (running on Windows still doesn't work) Breaking Changes None.",
"headings": []
},
{
- "id": "25-release-notes/0.11",
+ "id": "24-release-notes/0.11",
"title": "Zero 0.11",
"url": "/docs/release-notes/0.11",
- "content": "Install ```bash npm install @rocicorp/zero@0.11 ``` Features Windows should work a lot better now. Thank you very much to aexylus and Sergio Leon for the testing and contributions here. Support nested property access in JWT auth tokens (docs). Make initial sync configurable (docs). Add query result type to SolidJS (docs) Docker image now contains native amd64 and arm64 binaries. Add storageKey constructor parameter to enable multiple Zero instances for same userID. Fixes Many, many fixes, including: Fix downstream replication of primitive values Fix replication of TRUNCATE messages Fix large storage use for idle pg instances Add runtime sanity checks for when a table is referenced but not synced Fix zero-cache-dev for multitenant Breaking Changes The addition of result types to SolidJS is a breaking API change on SolidJS only. See the changes to hello-zero-solid for upgrade example.",
+ "content": "Install npm install @rocicorp/zero@0.11 Features Windows should work a lot better now. Thank you very much to aexylus and Sergio Leon for the testing and contributions here. Support nested property access in JWT auth tokens (docs). Make initial sync configurable (docs). Add query result type to SolidJS (docs) Docker image now contains native amd64 and arm64 binaries. Add storageKey constructor parameter to enable multiple Zero instances for same userID. Fixes Many, many fixes, including: Fix downstream replication of primitive values Fix replication of TRUNCATE messages Fix large storage use for idle pg instances Add runtime sanity checks for when a table is referenced but not synced Fix zero-cache-dev for multitenant Breaking Changes The addition of result types to SolidJS is a breaking API change on SolidJS only. See the changes to hello-zero-solid for upgrade example.",
"headings": []
},
{
- "id": "26-release-notes/0.12",
+ "id": "25-release-notes/0.12",
"title": "Zero 0.12",
"url": "/docs/release-notes/0.12",
- "content": "Install ```bash npm install @rocicorp/zero@0.12 ``` Features Schemas now support circular relationships (docs). Added one() and many() schema helpers to default relationship type (docs). Support for syncing tables without a primary key as long as there is a unique index. This enables Prisma's implicit many-to-many relations (docs). Zero has been confirmed to work with Aurora and Google Cloud SQL (docs) Client bundle size reduced from 55kb to 47kb (-15%). Fixes Windows: zero-cache was spawning emptying terminals and leaving listeners connected on exit. Incorrect warning in zero-cache about enums not being supported. Failure to handle the primary key of Postgres tables changing. Incorrect results when whereExists() is before where() in query (bug). Error: The inferred type of '...' cannot be named without a reference to .... Error: insufficient upstream connections. Several causes of flicker in React. Incorrect values for ResultType when unloading and loading a query quickly (bug). Error: Postgres is missing the column '...' but that column was part of a row. Pointless initial empty render in React when data is already available in memory. Error: Expected string at ... Got array during auth. where() incorrectly allows comparing to null with the = operator (bug). SolidJS: Only call setState once per transaction. Breaking Changes The schema definition syntax has changed to support circular relationships. See the changes to hello-zero and hello-zero-solid for upgrade examples.",
+ "content": "Install npm install @rocicorp/zero@0.12 Features Schemas now support circular relationships (docs). Added one() and many() schema helpers to default relationship type (docs). Support for syncing tables without a primary key as long as there is a unique index. This enables Prisma's implicit many-to-many relations (docs). Zero has been confirmed to work with Aurora and Google Cloud SQL (docs) Client bundle size reduced from 55kb to 47kb (-15%). Fixes Windows: zero-cache was spawning emptying terminals and leaving listeners connected on exit. Incorrect warning in zero-cache about enums not being supported. Failure to handle the primary key of Postgres tables changing. Incorrect results when whereExists() is before where() in query (bug). Error: The inferred type of '...' cannot be named without a reference to .... Error: insufficient upstream connections. Several causes of flicker in React. Incorrect values for ResultType when unloading and loading a query quickly (bug). Error: Postgres is missing the column '...' but that column was part of a row. Pointless initial empty render in React when data is already available in memory. Error: Expected string at ... Got array during auth. where() incorrectly allows comparing to null with the = operator (bug). SolidJS: Only call setState once per transaction. Breaking Changes The schema definition syntax has changed to support circular relationships. See the changes to hello-zero and hello-zero-solid for upgrade examples.",
"headings": []
},
{
- "id": "27-release-notes/0.13",
+ "id": "26-release-notes/0.13",
"title": "Zero 0.13",
"url": "/docs/release-notes/0.13",
- "content": "Install ```bash npm install @rocicorp/zero@0.13 ``` Features Multinode deployment for horizontal scalability and zero-downtime deploys (docs). SST Deployment Guide (docs). Plain AWS Deployment Guide (docs). Various exports for external libraries Remove build hash from docker version for consistency with npm (discussion) Fixes Move heartbeat monitoring to separate path, not port Type instantiation is excessively deep and possibly infinite (bug). 20x improvement to whereExists performance (discussion) Breaking Changes Removing the hash from the version is a breaking change if you had scripts relying on that. Moving the heartbeat monitor to a path is a breaking change for deployments that were using that.",
+ "content": "Install npm install @rocicorp/zero@0.13 Features Multinode deployment for horizontal scalability and zero-downtime deploys (docs). SST Deployment Guide (docs). Plain AWS Deployment Guide (docs). Various exports for external libraries Remove build hash from docker version for consistency with npm (discussion) Fixes Move heartbeat monitoring to separate path, not port Type instantiation is excessively deep and possibly infinite (bug). 20x improvement to whereExists performance (discussion) Breaking Changes Removing the hash from the version is a breaking change if you had scripts relying on that. Moving the heartbeat monitor to a path is a breaking change for deployments that were using that.",
"headings": []
},
{
- "id": "28-release-notes/0.14",
+ "id": "27-release-notes/0.14",
"title": "Zero 0.14",
"url": "/docs/release-notes/0.14",
- "content": "Install ```bash npm install @rocicorp/zero@0.14 ``` Features Use from() to map column or tables to a different name (docs). Sync from muliple Postgres schemas (docs) Fixes useQuery not working when server unset (bug) Error: \"single output already exists\" in hello-zero-solid (bug) Row helper doesn't work with query having one() (bug) Partitioned Postgres tables not replicating Breaking Changes None.",
+ "content": "Install npm install @rocicorp/zero@0.14 Features Use from() to map column or tables to a different name (docs). Sync from muliple Postgres schemas (docs) Fixes useQuery not working when server unset (bug) Error: \"single output already exists\" in hello-zero-solid (bug) Row helper doesn't work with query having one() (bug) Partitioned Postgres tables not replicating Breaking Changes None.",
"headings": []
},
{
- "id": "29-release-notes/0.15",
+ "id": "28-release-notes/0.15",
"title": "Zero 0.15",
"url": "/docs/release-notes/0.15",
- "content": "Install ```bash npm install @rocicorp/zero@0.15 ``` Upgrade Guide This release changes the way that permissions are sent to the server. Before, permissions were sent to the server by setting the ZERO\\_SCHEMA\\_JSON or ZERO\\_SCHEMA\\_FILE environment variables, which include the permissions. In 0.15, these variables go away and are replaced by a new command: npx zero-deploy-permissions. This command writes the permissions to a new table in the upstream database. This design allows live permission updates, without restarting the server. It also solves problems with max env var size that users were seeing. This release also flips the default permission from allow to deny for all rules. To upgrade your app: See the changes to hello-zero or hello-zero-solid for how to update your permissions. Remove the ZERO\\_SCHEMA\\_JSON and ZERO\\_SCHEMA\\_FILE environment variables from your setup. They aren't used anymore. Use npx zero-deploy-permissions to deploy permissions when necessary. You can hook this up to your CI to automate it. See the zbugs implementation as an example. Features Live-updating permissions (docs). Permissions now default to deny rather than allow (docs). Fixes Multiple whereExists in same query not working (PR) Allow overlapped mutators (bug) \"Immutable type too deep\" error (PR) Log server version at startup (PR) Eliminate quadratic CVR writes (PR) Handle numeric in the replication stream (PR) Make the auto-reset required error more prominent (PR) Add \"type\":\"module\" recommendation when schema load fails (PR) Throw error if multiple auth options set (PR) Handle NULL characters in JSON columns (PR) Breaking Changes Making permissions deny by default breaks existing apps. To fix add ANYONE\\_CAN or other appropriate permissions for your tables. See docs. The ZERO\\_SCHEMA\\_JSON and ZERO\\_SCHEMA\\_FILE environment variables are no longer used. Remove them from your setup and use npx zero-deploy-permissions instead.",
+ "content": "Install npm install @rocicorp/zero@0.15 Upgrade Guide This release changes the way that permissions are sent to the server. Before, permissions were sent to the server by setting the ZERO\\_SCHEMA\\_JSON or ZERO\\_SCHEMA\\_FILE environment variables, which include the permissions. In 0.15, these variables go away and are replaced by a new command: npx zero-deploy-permissions. This command writes the permissions to a new table in the upstream database. This design allows live permission updates, without restarting the server. It also solves problems with max env var size that users were seeing. This release also flips the default permission from allow to deny for all rules. To upgrade your app: See the changes to hello-zero or hello-zero-solid for how to update your permissions. Remove the ZERO\\_SCHEMA\\_JSON and ZERO\\_SCHEMA\\_FILE environment variables from your setup. They aren't used anymore. Use npx zero-deploy-permissions to deploy permissions when necessary. You can hook this up to your CI to automate it. See the zbugs implementation as an example. Features Live-updating permissions (docs). Permissions now default to deny rather than allow (docs). Fixes Multiple whereExists in same query not working (PR) Allow overlapped mutators (bug) \"Immutable type too deep\" error (PR) Log server version at startup (PR) Eliminate quadratic CVR writes (PR) Handle numeric in the replication stream (PR) Make the auto-reset required error more prominent (PR) Add \"type\":\"module\" recommendation when schema load fails (PR) Throw error if multiple auth options set (PR) Handle NULL characters in JSON columns (PR) Breaking Changes Making permissions deny by default breaks existing apps. To fix add ANYONE\\_CAN or other appropriate permissions for your tables. See docs. The ZERO\\_SCHEMA\\_JSON and ZERO\\_SCHEMA\\_FILE environment variables are no longer used. Remove them from your setup and use npx zero-deploy-permissions instead.",
"headings": []
},
{
- "id": "30-release-notes/0.16",
+ "id": "29-release-notes/0.16",
"title": "Zero 0.16",
"url": "/docs/release-notes/0.16",
- "content": "Install ```bash npm install @rocicorp/zero@0.16 ``` Upgrading See the upgrade from hello-zero or hello-zero-solid for an example. Features Documented how to use lambdas to deploy permissions in SST, rather than needing CI/CD to have access to Postgres. (doc β search for \"permissionsDeployer\"). Added simple debugging logs for read and write permissions (doc). Fixes Improve performance of initial sync about 2x (PR 1, PR 2). IN should allow readonly array arguments (Report, PR). Export ANYONE\\_CAN\\_DO\\_ANYTHING (Report). Fix false-positive in schema change detection (Report, PR). Fix writes of numeric types (Report, PR) Fix bug where litestream was creating way too many files in s3 (PR) Fix memory leak in change-streamer noticeable under high write load (PR) Fix query already registered error (PR) Correctly handle optional booleans (PR) Ignore indexes with unpublished columns (PR) Breaking Changes None.",
+ "content": "Install npm install @rocicorp/zero@0.16 Upgrading See the upgrade from hello-zero or hello-zero-solid for an example. Features Documented how to use lambdas to deploy permissions in SST, rather than needing CI/CD to have access to Postgres. (doc β search for \"permissionsDeployer\"). Added simple debugging logs for read and write permissions (doc). Fixes Improve performance of initial sync about 2x (PR 1, PR 2). IN should allow readonly array arguments (Report, PR). Export ANYONE\\_CAN\\_DO\\_ANYTHING (Report). Fix false-positive in schema change detection (Report, PR). Fix writes of numeric types (Report, PR) Fix bug where litestream was creating way too many files in s3 (PR) Fix memory leak in change-streamer noticeable under high write load (PR) Fix query already registered error (PR) Correctly handle optional booleans (PR) Ignore indexes with unpublished columns (PR) Breaking Changes None.",
"headings": []
},
{
- "id": "31-release-notes/0.17",
+ "id": "30-release-notes/0.17",
"title": "Zero 0.17",
"url": "/docs/release-notes/0.17",
- "content": "Install ```bash npm install @rocicorp/zero@0.17 ``` Upgrading See the upgrade from hello-zero or hello-zero-solid for an example. Features Queries now take an optional ttl argument. This argument backgrounds queries for some time after the app stops using them. Background queries continue syncing so they are instantly ready if the UI re-requests them. The data from background queries is also available to be used by new queries where possible (doc). Structural schema versioning. This is TypeScript, why are we versioning with numbers like cave-people?? We got rid of schemaVersion concept entirely and now determine schema compatibility completely automatically, TS-stylie (doc). Permissions now scoped to \"apps\". You can now have different Zero \"apps\" talking to the same upstream database. Each app gets completely separate configuration and permissions. This should also enable previewing zero-cache (each preview would be its own app). Apps replace the existing \"shard\" concept (doc). Initial replication is over 5x faster, up to about 50MB/second or 15k row/second in our tests. Added warnings for slow hydration in both client and server (doc). auto-reset is now enabled by default for databases that don't support event triggers (doc). Default cvr and change databases to upstream, so that you don't have to specify them in the common case where they are the same as upstream. This docs site now has search! Fixes Certain kinds of many:many joins were causing node already exists assertions Certain kinds of or queries were causing consistency issues Support replica identity full for PostgreSQL tables We now print a stack trace during close at debug level to enable debugging errors where Zero is accessed after close. We now print a warning when IndexedDB is missing rather than throwing. This makes it a little easier to use Zero in SSR setups. We now reset zero-cache implicitly in a few edge cases rather than halting replication. Fixed a deadlock in change-streamer. Breaking Changes query.run() now returns its result via promise. This is required for compatibility with upcoming custom mutators, but also will allow us to wait for server results in the future (though that (still π’) doesn't exist yet).",
+ "content": "Install npm install @rocicorp/zero@0.17 Upgrading See the upgrade from hello-zero or hello-zero-solid for an example. Features Queries now take an optional ttl argument. This argument backgrounds queries for some time after the app stops using them. Background queries continue syncing so they are instantly ready if the UI re-requests them. The data from background queries is also available to be used by new queries where possible (doc). Structural schema versioning. This is TypeScript, why are we versioning with numbers like cave-people?? We got rid of schemaVersion concept entirely and now determine schema compatibility completely automatically, TS-stylie (doc). Permissions now scoped to \"apps\". You can now have different Zero \"apps\" talking to the same upstream database. Each app gets completely separate configuration and permissions. This should also enable previewing zero-cache (each preview would be its own app). Apps replace the existing \"shard\" concept (doc). Initial replication is over 5x faster, up to about 50MB/second or 15k row/second in our tests. Added warnings for slow hydration in both client and server (doc). auto-reset is now enabled by default for databases that don't support event triggers (doc). Default cvr and change databases to upstream, so that you don't have to specify them in the common case where they are the same as upstream. This docs site now has search! Fixes Certain kinds of many:many joins were causing node already exists assertions Certain kinds of or queries were causing consistency issues Support replica identity full for PostgreSQL tables We now print a stack trace during close at debug level to enable debugging errors where Zero is accessed after close. We now print a warning when IndexedDB is missing rather than throwing. This makes it a little easier to use Zero in SSR setups. We now reset zero-cache implicitly in a few edge cases rather than halting replication. Fixed a deadlock in change-streamer. Breaking Changes query.run() now returns its result via promise. This is required for compatibility with upcoming custom mutators, but also will allow us to wait for server results in the future (though that (still π’) doesn't exist yet).",
"headings": []
},
{
- "id": "32-release-notes/0.18",
+ "id": "31-release-notes/0.18",
"title": "Zero 0.18",
"url": "/docs/release-notes/0.18",
- "content": "Install ```bash npm install @rocicorp/zero@0.18 ``` Upgrading To try out custom mutators, see the changes to hello-zero-solid. Features Custom Mutators! Finally! Define arbitrary write operations in code (doc). Added inspector API for debugging sync, queries, and client storage (doc). Added analyze-query tool to debug query performance (doc). Added transform-query tool to debug permissions (doc). Added ast-to-zql script to prettify Zero's internal AST format (doc). Fixes Added backpressure to replication-manager to protect against Postgres moving faster than we can push to clients (PR). @rocicorp/zero/advanced has been deprecated. AdvancedQuery got folded into Query and ZeroAdvancedOptions got folded into ZeroOptions (PR). Support ALTER SCHEMA DDL changes (PR) Allow replication-manager to continue running while a new one re-replicates. (PR). Improve replication performance for some schema changes (PR). Make the log level of zero-deploy-permissions configurable (PR) Bind exists to the expression builder (PR) Fix single output already exists error (PR) Fix getBrowserGlobal('window')?.addEventListener not a function in Expo (thanks @andrewcoelho!) (PR). Fix Vue bindings ref counting bug. Bindings no longer need to pass RefCountMap (PR). Fix CVR ownership takeover race conditions (PR). Support REPLICA IDENTITY FULL in degraded-mode pg providers (PR). Handle corrupt sqlite db by re-replicating (PR). Don't send useless pokes to clients that are unchanged (PR). Add limit(1) to queries using a relation that is marked one() (PR). Export UseQueryOptions Breaking Changes None.",
+ "content": "Install npm install @rocicorp/zero@0.18 Upgrading To try out custom mutators, see the changes to hello-zero-solid. Features Custom Mutators! Finally! Define arbitrary write operations in code (doc). Added inspector API for debugging sync, queries, and client storage (doc). Added analyze-query tool to debug query performance (doc). Added transform-query tool to debug permissions (doc). Added ast-to-zql script to prettify Zero's internal AST format (doc). Fixes Added backpressure to replication-manager to protect against Postgres moving faster than we can push to clients (PR). @rocicorp/zero/advanced has been deprecated. AdvancedQuery got folded into Query and ZeroAdvancedOptions got folded into ZeroOptions (PR). Support ALTER SCHEMA DDL changes (PR) Allow replication-manager to continue running while a new one re-replicates. (PR). Improve replication performance for some schema changes (PR). Make the log level of zero-deploy-permissions configurable (PR) Bind exists to the expression builder (PR) Fix single output already exists error (PR) Fix getBrowserGlobal('window')?.addEventListener not a function in Expo (thanks @andrewcoelho!) (PR). Fix Vue bindings ref counting bug. Bindings no longer need to pass RefCountMap (PR). Fix CVR ownership takeover race conditions (PR). Support REPLICA IDENTITY FULL in degraded-mode pg providers (PR). Handle corrupt sqlite db by re-replicating (PR). Don't send useless pokes to clients that are unchanged (PR). Add limit(1) to queries using a relation that is marked one() (PR). Export UseQueryOptions Breaking Changes None.",
"headings": []
},
{
- "id": "33-release-notes/0.19",
+ "id": "32-release-notes/0.19",
"title": "Zero 0.19",
"url": "/docs/release-notes/0.19",
- "content": "Install ```bash npm install @rocicorp/zero@0.19 ``` Upgrading If you use custom mutators, please see hello-zero-solid for how to update your push endpoint. If you use SolidJS, please switch to createQuery. If you are awaiting z.mutate.foo.bar(), you should switch to await z.mutate.foo.bar().client to be consistent with .server. If you were using a 0.19 canary, the .server property returns error by rejection again (like 0.18 did). Sorry about the thrash here. Features Add a type param to query.run() so it can wait for server results (doc, bug) await z.mutate.foo.bar() is now await z.mutate.foo.bar().client for consistency with .server, old API still works but deprecated (doc) Improve speed of litestream restore by about 7x Increase replication speed when using JSON by about 25% Add options to analyze-query to apply permissions and auth data (doc). Add option to --lazy-startup to zero-cache to delay connecting to upstram until first connection (doc) Add /statz endpoint for getting some health statistics from a running Zero instance (doc) Fixes Support passing Request to PushProccesor.process() (PR) Fix layering in PushProcessor to better support custom db implementations (thanks Erik Munson!) (PR) Fix socket disconnects in GCP (PR) Quote Postgres enum types to preserve casing (report) z2s: Return undefined for empty result set when using query.one() z2s: Allow accessing tables in non-public schemas z2s: Allow tx.foo.update({bar: undefined}) where bar is optional to match client behavior Fix broken replication when updating a key that is part of a unique (but non-PK) index solid: Rename useQuery to createQuery to fit Solid naming conventions (old name deprecated) Resync when publications are missing (PR) Fix missing NOT LIKE in query.where() (PR) Fix timezone shift when writing to timestamp/timestamptz and server is non-UTC timezone (thanks Tom Jenkinson!) (PR) Bound time spent in incremental updates to 1/2 hydration time Fix ttl being off by 1000 in some cases π¬ (PR) z2s: Relationships nested in a junction relationship were not working correctly (PR) Custom mutators: Due to multitab, client can receive multiple responses for same mutation Fix deadlock that could happen when pushing on a closed websocket (PR) Fix incorrect shutdown under heavy CPU load (thanks Erik Munson!) (PR) Fix case where deletes were getting reverted (thanks for reproduction Marc MacLeod!) (PR) z2s: Incorrect handling of self-join, and not exists not(exists()) is not supported on the client re-auth on 401s returned by push endpoint Added push.queryParams constructor parameter to allow passing query params to the push endpoint (doc) Breaking Changes The structure of setting up a PushProcesor has changed slightly. See push endpoint setup or upgrade guide. Not technically a breaking change from 0.18, but if you were using 0.19 canaries, the .server property returns error by rejection again (like 0.18 did) (doc).",
+ "content": "Install npm install @rocicorp/zero@0.19 Upgrading If you use custom mutators, please see hello-zero-solid for how to update your push endpoint. If you use SolidJS, please switch to createQuery. If you are awaiting z.mutate.foo.bar(), you should switch to await z.mutate.foo.bar().client to be consistent with .server. If you were using a 0.19 canary, the .server property returns error by rejection again (like 0.18 did). Sorry about the thrash here. Features Add a type param to query.run() so it can wait for server results (doc, bug) await z.mutate.foo.bar() is now await z.mutate.foo.bar().client for consistency with .server, old API still works but deprecated (doc) Improve speed of litestream restore by about 7x Increase replication speed when using JSON by about 25% Add options to analyze-query to apply permissions and auth data (doc). Add option to --lazy-startup to zero-cache to delay connecting to upstram until first connection (doc) Add /statz endpoint for getting some health statistics from a running Zero instance (doc) Fixes Support passing Request to PushProccesor.process() (PR) Fix layering in PushProcessor to better support custom db implementations (thanks Erik Munson!) (PR) Fix socket disconnects in GCP (PR) Quote Postgres enum types to preserve casing (report) z2s: Return undefined for empty result set when using query.one() z2s: Allow accessing tables in non-public schemas z2s: Allow tx.foo.update({bar: undefined}) where bar is optional to match client behavior Fix broken replication when updating a key that is part of a unique (but non-PK) index solid: Rename useQuery to createQuery to fit Solid naming conventions (old name deprecated) Resync when publications are missing (PR) Fix missing NOT LIKE in query.where() (PR) Fix timezone shift when writing to timestamp/timestamptz and server is non-UTC timezone (thanks Tom Jenkinson!) (PR) Bound time spent in incremental updates to 1/2 hydration time Fix ttl being off by 1000 in some cases π¬ (PR) z2s: Relationships nested in a junction relationship were not working correctly (PR) Custom mutators: Due to multitab, client can receive multiple responses for same mutation Fix deadlock that could happen when pushing on a closed websocket (PR) Fix incorrect shutdown under heavy CPU load (thanks Erik Munson!) (PR) Fix case where deletes were getting reverted (thanks for reproduction Marc MacLeod!) (PR) z2s: Incorrect handling of self-join, and not exists not(exists()) is not supported on the client re-auth on 401s returned by push endpoint Added push.queryParams constructor parameter to allow passing query params to the push endpoint (doc) Breaking Changes The structure of setting up a PushProcesor has changed slightly. See push endpoint setup or upgrade guide. Not technically a breaking change from 0.18, but if you were using 0.19 canaries, the .server property returns error by rejection again (like 0.18 did) (doc).",
"headings": []
},
{
- "id": "34-release-notes/0.2",
+ "id": "33-release-notes/0.2",
"title": "Zero 0.2",
"url": "/docs/release-notes/0.2",
"content": "Breaking changes None Features βSkip modeβ: zero-cache now skips columns with unsupported datatypes. A warning is printed out when this happens: This makes it easy to use zero-cache with existing schemas that have columns Zero canβt handle. You can pair this with Postgres triggers to easily translate unsupported types into something Zero can sync. Zero now supports compound primary keys. You no longer need to include an extraneous id column on the junction tables. Fixes Change the way Zero detects unsupported environments to work in One (and any other supported env). Before, Zero was looking for WebSocket and indexedDB early on, but indexedDB wonβt be present on RN as SQLite will be used. Instead look for indexedDB only at use. Require Node v20 explicitly in package.json to prevent accidentally compiling better-sqlite3 with different Node version than running with. Ensure error messages early in startup get printed out before shutting down in multiprocess mode. Docs Factored out the sample app from the docs into its own Github repo so you can just download it and poke around if you prefer that. Source tree fixes Run zero-cache from source. You no longer have to build zero before running zbugs, it picks up the changes automatically. zbugs Numerous polish/styling fixes Change default to βopenβ bugs Add βassigneeβ field",
"headings": []
},
{
- "id": "35-release-notes/0.20",
+ "id": "34-release-notes/0.20",
"title": "Zero 0.20",
"url": "/docs/release-notes/0.20",
- "content": "Install ```bash npm install @rocicorp/zero@0.20 ``` Upgrading There are two config changes for multinode deployments: Required: Remove view-syncer's ZERO\\_CHANGE\\_STREAMER\\_URI env var and replace it with ZERO\\_CHANGE\\_STREAMER\\_MODE: \"discover\". Optional: Change the ZERO\\_LITESTREAM\\_BACKUP\\_URL env var from being passed to both replication-manager and view-syncer nodes to being passed only to replication-manager. This config is no longer needed by view-syncer (and is ignored by it). See hello-zero for an upgrade example using SST. Additionally, the ZERO\\_TENANTS\\_JSON, feature was removed. We do not think anyone was using it, but if you were please reach out to us for options. Features Supabase is now fully supported. After upgrading, you should see that schema changes are incremental and don't reset the replica (docs). Improve performance of single-key reads on client. Scale depends on size of data but 100x improvement is common (PR). Implement short-circuiting for or queries. Because of permissions, one or more branches of or would often be empty, turning the entire or into a full-table scan. 100x improvement on chinook test dataset (PR). Remove DNF conversion. This was intended to make consistency easier in the future, but was resulting in some queries exploding in size (PR, bug). Autodiscovery for replication-manager. view-syncer nodes now find replication-manager using the Postgres changedb database, and no longer need an internal load balancer. See the new ZERO\\_CHANGE\\_STREAMER\\_MODE: \"discover\" config in the deployment docs (PR). Make ZERO\\_LITESTREAM\\_BACKUP\\_URL specific to replication-manager. view-syncer nodes now ignore this config and learn it from replication-manager instead. This makes restarting replication less error-prone (PR, discussion). OpenTelemetry support (docs). Fixes Allow dots in column names (only works with custom mutators) (PR). Fix websocket liveness check to avoid false negatives when busy (PR). Fix unhandled exception in zero-cache when processing query eviction (PR). Keep microsecond precision across timezones (PR). Fix unhandled exception in zero-cache during handleClose (PR). Fix NOT IN in z2s (PR). Mutators: assert provided columns actually exist (PR). Fix ordering of columns in replicated index (PR). Use a shorter keepalive for replication stream for compat with Neon (PR). Allow destructuring where in query.related (PR). Add flow control for large change DB transactions (PR). Fix z2s handling of pg types with params (char, varchar, numeric, etc) (PR). Support from and --schema-path in analyze-query (PR). Breaking Changes The autodiscovery feature for replication-manager is a breaking change for multinode deployments. See the upgrade instructions for details. The ZERO\\_TENANTS\\_JSON config was removed π«. The ZERO\\_INITIAL\\_SYNC\\_ROW\\_BATCH\\_SIZE config was removed. It is no longer needed because initial sync now adapts to available memory automatically.",
+ "content": "Install npm install @rocicorp/zero@0.20 Upgrading There are two config changes for multinode deployments: Required: Remove view-syncer's ZERO\\_CHANGE\\_STREAMER\\_URI env var and replace it with ZERO\\_CHANGE\\_STREAMER\\_MODE: \"discover\". Optional: Change the ZERO\\_LITESTREAM\\_BACKUP\\_URL env var from being passed to both replication-manager and view-syncer nodes to being passed only to replication-manager. This config is no longer needed by view-syncer (and is ignored by it). See hello-zero for an upgrade example using SST. Additionally, the ZERO\\_TENANTS\\_JSON, feature was removed. We do not think anyone was using it, but if you were please reach out to us for options. Features Supabase is now fully supported. After upgrading, you should see that schema changes are incremental and don't reset the replica (docs). Improve performance of single-key reads on client. Scale depends on size of data but 100x improvement is common (PR). Implement short-circuiting for or queries. Because of permissions, one or more branches of or would often be empty, turning the entire or into a full-table scan. 100x improvement on chinook test dataset (PR). Remove DNF conversion. This was intended to make consistency easier in the future, but was resulting in some queries exploding in size (PR, bug). Autodiscovery for replication-manager. view-syncer nodes now find replication-manager using the Postgres changedb database, and no longer need an internal load balancer. See the new ZERO\\_CHANGE\\_STREAMER\\_MODE: \"discover\" config in the deployment docs (PR). Make ZERO\\_LITESTREAM\\_BACKUP\\_URL specific to replication-manager. view-syncer nodes now ignore this config and learn it from replication-manager instead. This makes restarting replication less error-prone (PR, discussion). OpenTelemetry support (docs). Fixes Allow dots in column names (only works with custom mutators) (PR). Fix websocket liveness check to avoid false negatives when busy (PR). Fix unhandled exception in zero-cache when processing query eviction (PR). Keep microsecond precision across timezones (PR). Fix unhandled exception in zero-cache during handleClose (PR). Fix NOT IN in z2s (PR). Mutators: assert provided columns actually exist (PR). Fix ordering of columns in replicated index (PR). Use a shorter keepalive for replication stream for compat with Neon (PR). Allow destructuring where in query.related (PR). Add flow control for large change DB transactions (PR). Fix z2s handling of pg types with params (char, varchar, numeric, etc) (PR). Support from and --schema-path in analyze-query (PR). Breaking Changes The autodiscovery feature for replication-manager is a breaking change for multinode deployments. See the upgrade instructions for details. The ZERO\\_TENANTS\\_JSON config was removed π«. The ZERO\\_INITIAL\\_SYNC\\_ROW\\_BATCH\\_SIZE config was removed. It is no longer needed because initial sync now adapts to available memory automatically.",
"headings": []
},
{
- "id": "36-release-notes/0.21",
+ "id": "35-release-notes/0.21",
"title": "Zero 0.21",
"url": "/docs/release-notes/0.21",
- "content": "Install ```bash npm install @rocicorp/zero@0.21 ``` Upgrading There is one breaking change in this release, but we think it is unlikely to affect anyone since the results were wrong already β the change just makes the error explicit. See hello-zero for an example of using arrays and the new ZeroProvider features. Features New \"ztunes\" sample using TanStack, Drizzle, Better Auth, and Fly.io (docs). Add initial support for Postgres arrays (docs, bug). Improved React lifecycle management with ZeroProvider (docs, PR). Expose Zero instances automatically at \\_\\_zero (docs, PR). Add --output-{synced|vended}-rows to analyze-query (PR). Technically a bug fix, but this was so annoying I'm calling it a feature: zero-sqlite3 now correctly supports the up/down arrow keys (commit). Another super annoying fix: logs from zero-cache are now level-colored (PR). Fixes Lazy-load otel. This was causing problems with pnpm (PR). Initial replication is now memory-bounded (PR). Change the way otel starts up in zero-cache-dev to not rely on npx (PR). Use existing --log-slow-hydrate-threshold as the threshold for --query-hydration-stats rather than hardcoded 200ms. Fix race condition starting up in multinode deployments (PR). Avoid site-local IPv6 addresses in auto-discovery (PR). Many z2s fixes found by fuzzing (PRs: 4415, 4416, 4417, 4421, 4422, 4423). Don't load prettier in analyze-query. This was causing problems when prettier config was cjs. (PR). Don't hydrate system relationships in analyze-query. This was causing incorrect results. (PR). Fix memory leaks from not cleaning up pusher and mutagen (PR). Fix handling of invalid websocket requests that were crashing server. (PR). Remove red error text when .env missing (PR). Allow zero-cache to startup without schema file, but print a warning (PR). Log a warning when auth token exceeds max allowed header size (PR). Breaking Changes Using order by and limit in many-to-many relationships now throws an error. It didn't work before but did the wrong thing silently. Now it throws a runtime error. See docs, bug.",
+ "content": "Install npm install @rocicorp/zero@0.21 Upgrading There is one breaking change in this release, but we think it is unlikely to affect anyone since the results were wrong already β the change just makes the error explicit. See hello-zero for an example of using arrays and the new ZeroProvider features. Features New \"ztunes\" sample using TanStack, Drizzle, Better Auth, and Fly.io (docs). Add initial support for Postgres arrays (docs, bug). Improved React lifecycle management with ZeroProvider (docs, PR). Expose Zero instances automatically at \\_\\_zero (docs, PR). Add --output-{synced|vended}-rows to analyze-query (PR). Technically a bug fix, but this was so annoying I'm calling it a feature: zero-sqlite3 now correctly supports the up/down arrow keys (commit). Another super annoying fix: logs from zero-cache are now level-colored (PR). Fixes Lazy-load otel. This was causing problems with pnpm (PR). Initial replication is now memory-bounded (PR). Change the way otel starts up in zero-cache-dev to not rely on npx (PR). Use existing --log-slow-hydrate-threshold as the threshold for --query-hydration-stats rather than hardcoded 200ms. Fix race condition starting up in multinode deployments (PR). Avoid site-local IPv6 addresses in auto-discovery (PR). Many z2s fixes found by fuzzing (PRs: 4415, 4416, 4417, 4421, 4422, 4423). Don't load prettier in analyze-query. This was causing problems when prettier config was cjs. (PR). Don't hydrate system relationships in analyze-query. This was causing incorrect results. (PR). Fix memory leaks from not cleaning up pusher and mutagen (PR). Fix handling of invalid websocket requests that were crashing server. (PR). Remove red error text when .env missing (PR). Allow zero-cache to startup without schema file, but print a warning (PR). Log a warning when auth token exceeds max allowed header size (PR). Breaking Changes Using order by and limit in many-to-many relationships now throws an error. It didn't work before but did the wrong thing silently. Now it throws a runtime error. See docs, bug.",
+ "headings": []
+ },
+ {
+ "id": "36-release-notes/0.22",
+ "title": "Zero 0.22",
+ "url": "/docs/release-notes/0.22",
+ "content": "Install npm install @rocicorp/zero@0.22 Upgrading This release simplifies the concept of TTLs in Zero. See hello-zero, hello-zero-solid, or ztunes for example upgrades. This release also adds anonymous telemetry collection. You can opt-out with the DO\\_NOT\\_TRACK=1 environment variable. Though we hope you will not, as it helps us improve Zero. How TTLs Used to Work Previously, the TTL of a query simply measured normal \"wall clock time\" from when a query inactivated, including any time the app wasn't running at all. With experience, we realized this was a misfeature because it encouraged the use of very long or infinite TTLs, especially for preload queries. Developers always want preload queries registered, but since they do not know how long the app will be offline, they had no real choice but to use the TTL forever. These infinite TTLs would remain registered even after the app's code changed such that it no longer wanted them, slowing connections and incremental updates to process queries that the app was not even using. Worse, the prevalence of infinite TTLs in turns meant we needed some way to limit the size of the client cache. We introduced the \"client row limit\" for this. But developers would frequently accidentally blow through this limit, causing cache thrash. How TTLs Work Now Now, query TTLs measure \"TTL time\" which only elapses while Zero is running. This means that preload queries usually don't need a TTL at all, since they run the entire time Zero is active. This in turn means we can clamp TTLs to low values, which means queries evict naturally, which means we no longer need the client row limit either. Using New TTLs You don't need to do anything specific to upgrade. Zero will clamp your TTLs at 10m and print a warning. But for best results, please review the new TTL documentation. In particular, see how to set your TTLs (TL;DR: You can often just remove them β the defaults usually just work). Features Rework and simplify query TTLs (docs, upgrading). SolidJS bindings are now fine-grained, improving performance (PR). Restore ZERO\\_CHANGE\\_STREAMER\\_URI option (doc, PR). Add useZeroOnline to React and SolidJS bindings (doc). Add ttl to run() (PR). Allow client to specify push.url in the Zero constructor (doc). Add anonymous telemetry collection to zero-cache (doc). Fixes Handle public in aliases, like .from('public.table') (PR). Sorting by columns with null values was incorrect in some cases (PR). Fix fencepost issue editing queries with limits (PR). Fix copy runner to more reliably reuse connections (PR). Queries early in startup could not contain non-latin chars (PR). SolidJS: Export createUseZero (PR). Support parallel rollouts of replication-manager and view-syncer (PR). Fix upgrade path for already replicated array types (PR). Breaking Changes Require Node v22+ (see discussion)",
"headings": []
},
{
"id": "37-release-notes/0.3",
"title": "Zero 0.3",
"url": "/docs/release-notes/0.3",
- "content": "Install ```bash npm install @rocicorp/zero@0.3 ``` Breaking changes zero.config file is now TypeScript, not JSON. See: https://github.com/rocicorp/hello-zero/blob/07c08b1f86b526a96e281ee65af672f52a59bcee/zero.config.ts. Features Schema Migrations: Zero now has first-class support for schema migration (documentation). Write Permissions: First-class write permissions based on ZQL (documentation). Date/Time related types: Zero now natively supports the TIMESTAMP and DATE Postgres types (sample app, documentation). SolidJS: We now have first-class support for SolidJS (documentation). Intellisense for Schema Definition: Introduce createSchema and createTableSchema helper functions to enable intellisense when defining shemas. See Sample App. escapeLike() : Add helper to properly escape strings for use in LIKE filters. See Sample App. New QuickStart App: Entirely rewrote the setup/sample flow to (a) make it much faster to get started playing with Zero, and (b) demonstrate more features. Fixes The @rocicorp/zero package now downloads a prebuilt sqlite instead of compiling it locally. This significantly speeds up install. Support rds.force\\_ssl=1 RDS configuration. Fixed bug where sibling subqueries could be lost on edit changes. Fixes to error handling to ensure zero-cache prints errors when crashing in multiprocess mode. If zero-cache hears from a client with an unknown CVR/cookie, zero-cache forces that client to reset itself and reload automatically. Useful during development when server-state is frequently getting cleared. Docs Started work to make real docs. Not quite done yet. zbugs https://bugs.rocicorp.dev/ (pw: zql) Improve startup perf: ~3s β ~1.5s Hawaii β US East. More work to do here but good progress. Responsive design for mobile. βShort IDsβ: Bugs now have a short numeric ID, not a random hash. See Demo Video. First-class label picker. Unread indicators. Finish j/k support for paging through issues. Itβs now βsearch-awareβ, it pages through issues in order of search you clicked through to detail page in. Text search (slash to activate β needs better discoverability) Emojis on issues and comments Sort controls on list view remove fps meter temporarily numerous other UI polish",
+ "content": "Install npm install @rocicorp/zero@0.3 Breaking changes zero.config file is now TypeScript, not JSON. See: https://github.com/rocicorp/hello-zero/blob/07c08b1f86b526a96e281ee65af672f52a59bcee/zero.config.ts. Features Schema Migrations: Zero now has first-class support for schema migration (documentation). Write Permissions: First-class write permissions based on ZQL (documentation). Date/Time related types: Zero now natively supports the TIMESTAMP and DATE Postgres types (sample app, documentation). SolidJS: We now have first-class support for SolidJS (documentation). Intellisense for Schema Definition: Introduce createSchema and createTableSchema helper functions to enable intellisense when defining shemas. See Sample App. escapeLike() : Add helper to properly escape strings for use in LIKE filters. See Sample App. New QuickStart App: Entirely rewrote the setup/sample flow to (a) make it much faster to get started playing with Zero, and (b) demonstrate more features. Fixes The @rocicorp/zero package now downloads a prebuilt sqlite instead of compiling it locally. This significantly speeds up install. Support rds.force\\_ssl=1 RDS configuration. Fixed bug where sibling subqueries could be lost on edit changes. Fixes to error handling to ensure zero-cache prints errors when crashing in multiprocess mode. If zero-cache hears from a client with an unknown CVR/cookie, zero-cache forces that client to reset itself and reload automatically. Useful during development when server-state is frequently getting cleared. Docs Started work to make real docs. Not quite done yet. zbugs https://bugs.rocicorp.dev/ (pw: zql) Improve startup perf: ~3s β ~1.5s Hawaii β US East. More work to do here but good progress. Responsive design for mobile. βShort IDsβ: Bugs now have a short numeric ID, not a random hash. See Demo Video. First-class label picker. Unread indicators. Finish j/k support for paging through issues. Itβs now βsearch-awareβ, it pages through issues in order of search you clicked through to detail page in. Text search (slash to activate β needs better discoverability) Emojis on issues and comments Sort controls on list view remove fps meter temporarily numerous other UI polish",
"headings": []
},
{
"id": "38-release-notes/0.4",
"title": "Zero 0.4",
"url": "/docs/release-notes/0.4",
- "content": "Install ```bash npm install @rocicorp/zero@0.4 ``` Breaking changes The or changes modified the client/server protocol. Youβll need to restart zero-cache and clear browser data after updating. Added or , and , and not to ZQL (documentation). Added query.run() method (documentation). Fixes Use batch() method in zero-solid to improve performance when multiple updates happen in same frame. To take advantage of this you must use the createZero helper from @rocicorp/zero/solid, instead of instantiating Zero directly. See the solid sample app. Postgres tables that were reserved words in SQLite but not Postgres caused crash during replication. LIKE was not matching correctly in the case of multiline subjects. Upstream database and zero database can now be same Postgres db (donβt need separate ports). Docs nothing notable zbugs Use or to run text search over both titles and bodies prevent j/k in emoji preload emojis",
+ "content": "Install npm install @rocicorp/zero@0.4 Breaking changes The or changes modified the client/server protocol. Youβll need to restart zero-cache and clear browser data after updating. Added or , and , and not to ZQL (documentation). Added query.run() method (documentation). Fixes Use batch() method in zero-solid to improve performance when multiple updates happen in same frame. To take advantage of this you must use the createZero helper from @rocicorp/zero/solid, instead of instantiating Zero directly. See the solid sample app. Postgres tables that were reserved words in SQLite but not Postgres caused crash during replication. LIKE was not matching correctly in the case of multiline subjects. Upstream database and zero database can now be same Postgres db (donβt need separate ports). Docs nothing notable zbugs Use or to run text search over both titles and bodies prevent j/k in emoji preload emojis",
"headings": []
},
{
"id": "39-release-notes/0.5",
"title": "Zero 0.5",
"url": "/docs/release-notes/0.5",
- "content": "Install ```bash npm install @rocicorp/zero@0.5 ``` Breaking changes createTableSchema and createSchema moved to @rocicorp/zero/schema subpackage. This is in preparation to moving authorization into the schema file. SchemaToRow helper type was renamed TableSchemaToRow and moved into @rocicorp/zero/schema. Basically: ```diff - import { createSchema, createTableSchema, SchemaToRow } from \"@rocicorp/zero\"; + import { createSchema, createTableSchema, TableSchemaToRow } from \"@rocicorp/zero/schema\"; ``` Features Added support for JSON columns in Postgres (documentation). Zero pacakage now includes zero-sqlite3, which can be used to explore our sqlite files (documentation). Fixes We were not correctly replicating the char(n) type, despite documenting that we were. Docs nothing notable zbugs nothing notable",
+ "content": "Install npm install @rocicorp/zero@0.5 Breaking changes createTableSchema and createSchema moved to @rocicorp/zero/schema subpackage. This is in preparation to moving authorization into the schema file. SchemaToRow helper type was renamed TableSchemaToRow and moved into @rocicorp/zero/schema. Basically: - import { createSchema, createTableSchema, SchemaToRow } from \"@rocicorp/zero\"; + import { createSchema, createTableSchema, TableSchemaToRow } from \"@rocicorp/zero/schema\"; Features Added support for JSON columns in Postgres (documentation). Zero pacakage now includes zero-sqlite3, which can be used to explore our sqlite files (documentation). Fixes We were not correctly replicating the char(n) type, despite documenting that we were. Docs nothing notable zbugs nothing notable",
"headings": []
},
{
"id": "40-release-notes/0.6",
"title": "Zero 0.6",
"url": "/docs/release-notes/0.6",
- "content": "Install ```bash npm install @rocicorp/zero@0.6 ``` Upgrade Guide This release is a bit harder to upgrade to than previous alphas. For a step-by-step guide, please refer to the commits that upgrade the React and Solid quickstart apps: Upgrading hello-zero from Zero 0.5 to 0.6 Upgrading hello-zero-solid from Zero 0.5 to 0.6 Breaking Changes Totally new configuration system. zero.config.ts is no more β config is now via env vars (documentation). Permissions rules moved into schema (documentation). Renamed CRUD mutators to be consistent with SQL naming (bug, documentation). z.mutate.\\
.create -> insert z.mutate.\\
.put -> upsert Removed select from ZQL. It wasnβt doing anything (documentation) Moved batch mutation to its own mutateBatch method. Before the mutate field also doubled as a method. This made intellisense hard to understand since z.mutate had all the tables as fields but also all the fields of a function. Features Relationship filters. Queries can now include whereExists (bug, documentation). Reworked syntax for compound where filters, including ergonomically building or expressions with dynamic number of clauses (bug, documentation). Support using Postgres databases without superuser access for smaller apps (documentation). Support for running Zero client under Cloudflare Durable Objects (documentation). Reworked support for null / undefined to properly support optional fields (bug, documentation). Added IS / IS NOT to ZQL to support checking for null (bug, documentation). Improved intellisense for mutators. Added --port flag and ZERO\\_PORT environment variable (bug, documentation). Default max connections of zero-cache more conservatively so that it should fit with even common small Postgres configurations. zero-cache now accepts requests with any base path, not just /api. The server parameter to the Zero client constructor can now be a host (https://myapp-myteam.zero.ms) or a host with a single path component (https://myapp-myteam.zero.ms/zero). These two changes together allow hosting zero-cache on same domain with an app that already uses the /api prefix (bug). Allow Postgres columns with default values, but donβt sync them (documentation). The npx zero-sqlite utility now accepts all the same flags and arguments that sqlite3 does (documentation). zbugs Added tooltip describing who submitted which emoji reactions Updated implementation of label, assignee, and owner filters to use relationship filters Updated text filter implementation to use or to search description and comments too Docs Added new ZQL reference Added new mutators reference Added new config reference",
+ "content": "Install npm install @rocicorp/zero@0.6 Upgrade Guide This release is a bit harder to upgrade to than previous alphas. For a step-by-step guide, please refer to the commits that upgrade the React and Solid quickstart apps: Upgrading hello-zero from Zero 0.5 to 0.6 Upgrading hello-zero-solid from Zero 0.5 to 0.6 Breaking Changes Totally new configuration system. zero.config.ts is no more β config is now via env vars (documentation). Permissions rules moved into schema (documentation). Renamed CRUD mutators to be consistent with SQL naming (bug, documentation). z.mutate.\\
.create -> insert z.mutate.\\
.put -> upsert Removed select from ZQL. It wasnβt doing anything (documentation) Moved batch mutation to its own mutateBatch method. Before the mutate field also doubled as a method. This made intellisense hard to understand since z.mutate had all the tables as fields but also all the fields of a function. Features Relationship filters. Queries can now include whereExists (bug, documentation). Reworked syntax for compound where filters, including ergonomically building or expressions with dynamic number of clauses (bug, documentation). Support using Postgres databases without superuser access for smaller apps (documentation). Support for running Zero client under Cloudflare Durable Objects (documentation). Reworked support for null / undefined to properly support optional fields (bug, documentation). Added IS / IS NOT to ZQL to support checking for null (bug, documentation). Improved intellisense for mutators. Added --port flag and ZERO\\_PORT environment variable (bug, documentation). Default max connections of zero-cache more conservatively so that it should fit with even common small Postgres configurations. zero-cache now accepts requests with any base path, not just /api. The server parameter to the Zero client constructor can now be a host (https://myapp-myteam.zero.ms) or a host with a single path component (https://myapp-myteam.zero.ms/zero). These two changes together allow hosting zero-cache on same domain with an app that already uses the /api prefix (bug). Allow Postgres columns with default values, but donβt sync them (documentation). The npx zero-sqlite utility now accepts all the same flags and arguments that sqlite3 does (documentation). zbugs Added tooltip describing who submitted which emoji reactions Updated implementation of label, assignee, and owner filters to use relationship filters Updated text filter implementation to use or to search description and comments too Docs Added new ZQL reference Added new mutators reference Added new config reference",
"headings": []
},
{
"id": "41-release-notes/0.7",
"title": "Zero 0.7",
"url": "/docs/release-notes/0.7",
- "content": "Install ```bash npm install @rocicorp/zero@0.7 ``` Features Read permissions. You can now control read access to data using ZQL (docs). Deployment. We now have a single-node Docker container (docs). Future work will add multinode support. Compound FKs. Zero already supported compound primary keys, but now it also supports compound foreign keys (docs). Schema DX: Columns types can use bare strings now if optional is not needed (example). PK can be a single string in the common case where itβs non-compound (example). Breaking Changes Several changes to schema.ts. See update to hello-zero for overview. Details: defineAuthorization was renamed to definedPermissions to avoid confusion with authentication. The way that many:many relationships are defined has changed to be more general and easy to remember. See example. The signature of definePermissions and the related rule functions have changed: Now rules return an expression instead of full query. This was required to make read permissions work and we did it for write permissions for consitency (see example). The update policy now has two child policies: preMutation and postMutation. The rules we used to have were preMutation. They run before a change and can be used to validate a user has permission to change a row. The postMutation rules run after and can be used to limit the changes a user is allowed to make. The schema.ts file should export an object having two fields: schema and permissions. The way that schema.ts is consumed has also changed. Rather than zero-cache directly reading the typescript source, we compile it to JSON and read that. ZERO\\_SCHEMA\\_FILE should now point to a JSON file, not .ts. It defaults to ./zero-schema.json which weβve found to be pretty useful so youβll probably just remove this key from your .env entirely. Use npx zero-build-schema to generate the JSON. You must currently do this manually each time you change the schema, we will automate it soon. zbugs Comments now have permalinks. Implementing permalinks in a synced SPA is fun! Private issues. Zbugs now supports private (to team only) issues. I wonder whatβs in them β¦ π. Docs The docs have moved. Please donβt use Notion anymore, they wonβt be updated.",
+ "content": "Install npm install @rocicorp/zero@0.7 Features Read permissions. You can now control read access to data using ZQL (docs). Deployment. We now have a single-node Docker container (docs). Future work will add multinode support. Compound FKs. Zero already supported compound primary keys, but now it also supports compound foreign keys (docs). Schema DX: Columns types can use bare strings now if optional is not needed (example). PK can be a single string in the common case where itβs non-compound (example). Breaking Changes Several changes to schema.ts. See update to hello-zero for overview. Details: defineAuthorization was renamed to definedPermissions to avoid confusion with authentication. The way that many:many relationships are defined has changed to be more general and easy to remember. See example. The signature of definePermissions and the related rule functions have changed: Now rules return an expression instead of full query. This was required to make read permissions work and we did it for write permissions for consitency (see example). The update policy now has two child policies: preMutation and postMutation. The rules we used to have were preMutation. They run before a change and can be used to validate a user has permission to change a row. The postMutation rules run after and can be used to limit the changes a user is allowed to make. The schema.ts file should export an object having two fields: schema and permissions. The way that schema.ts is consumed has also changed. Rather than zero-cache directly reading the typescript source, we compile it to JSON and read that. ZERO\\_SCHEMA\\_FILE should now point to a JSON file, not .ts. It defaults to ./zero-schema.json which weβve found to be pretty useful so youβll probably just remove this key from your .env entirely. Use npx zero-build-schema to generate the JSON. You must currently do this manually each time you change the schema, we will automate it soon. zbugs Comments now have permalinks. Implementing permalinks in a synced SPA is fun! Private issues. Zbugs now supports private (to team only) issues. I wonder whatβs in them β¦ π. Docs The docs have moved. Please donβt use Notion anymore, they wonβt be updated.",
"headings": []
},
{
"id": "42-release-notes/0.8",
"title": "Zero 0.8",
"url": "/docs/release-notes/0.8",
- "content": "Install ```bash npm install @rocicorp/zero@0.8 ``` See the changes to hello-zero or hello-zero-solid for example updates. Features Schema Autobuild. There's now a zero-cache-dev script that automatically rebuilds the schema and restarts zero-cache on changes to schema.ts. (docs) Result Type. You can now tell whether a query is complete or partial. (docs) Enums. Enums are now supported in Postgres schemas and on client. (docs) Custom Types. You can define custom JSON types in your schema. (docs) OTEL Tracing. Initial tracing support. (docs) timestampz. Add support for timestampz Postgres column type. (docs) SSLMode. You can disable TLS when zero-cache connects to DB with sslmode=disable. (docs) Permission Helpers. ANYONE\\_CAN and NOBODY\\_CAN helpers were added to make these cases more readable. (docs) Multitenant Support. A single zero-cache can now front separate Postgres databases. This is useful for customers that have one \"dev\" database in production per-developer. (docs) Fixes Crash with JSON Columns. Fixed a crash when a JSON column was used in a Zero app with write permissions (bug) Better Connection Error Reporting. Some connection errors would cause zero-cache to exit silently. Now they are returned to client and logged. Breaking Changes useQuery in React now returns a 2-tuple of \\[rows, result] where result is an object with a type field. postProposedMutation in write permissions for update renamed to postMutation for consistency. TableScheamToRow renamed to Row to not be so silly long.",
+ "content": "Install npm install @rocicorp/zero@0.8 See the changes to hello-zero or hello-zero-solid for example updates. Features Schema Autobuild. There's now a zero-cache-dev script that automatically rebuilds the schema and restarts zero-cache on changes to schema.ts. (docs) Result Type. You can now tell whether a query is complete or partial. (docs) Enums. Enums are now supported in Postgres schemas and on client. (docs) Custom Types. You can define custom JSON types in your schema. (docs) OTEL Tracing. Initial tracing support. (docs) timestampz. Add support for timestampz Postgres column type. (docs) SSLMode. You can disable TLS when zero-cache connects to DB with sslmode=disable. (docs) Permission Helpers. ANYONE\\_CAN and NOBODY\\_CAN helpers were added to make these cases more readable. (docs) Multitenant Support. A single zero-cache can now front separate Postgres databases. This is useful for customers that have one \"dev\" database in production per-developer. (docs) Fixes Crash with JSON Columns. Fixed a crash when a JSON column was used in a Zero app with write permissions (bug) Better Connection Error Reporting. Some connection errors would cause zero-cache to exit silently. Now they are returned to client and logged. Breaking Changes useQuery in React now returns a 2-tuple of \\[rows, result] where result is an object with a type field. postProposedMutation in write permissions for update renamed to postMutation for consistency. TableScheamToRow renamed to Row to not be so silly long.",
"headings": []
},
{
"id": "43-release-notes/0.9",
"title": "Zero 0.9",
"url": "/docs/release-notes/0.9",
- "content": "Install ```bash npm install @rocicorp/zero@0.9 ``` See the changes to hello-zero or hello-zero-solid for example updates. Features JWK Support. For auth, you can now specify a JWK containing a public key, or a JWKS url to support autodiscovery of keys. (docs) UUID column. Zero now supports the uuid Postgres column type. (docs) Fixes Readonly Values. Type of values returned from Zero queries are marked readonly. The system always considered them readonly, but now the types reflect that. (docs) Breaking Changes The zero-cache config ZERO\\_JWT\\_SECRET has been renamed to ZERO\\_AUTH\\_SECRET for consistency with the new JWK-related keys. If you were using the old name, you'll need to update your .env file. All values returned by Zero are now readonly. You'll probably have to add this TS modifier various places. If you find yourself casting away readonly you probably should be cloing the value instead.",
+ "content": "Install npm install @rocicorp/zero@0.9 See the changes to hello-zero or hello-zero-solid for example updates. Features JWK Support. For auth, you can now specify a JWK containing a public key, or a JWKS url to support autodiscovery of keys. (docs) UUID column. Zero now supports the uuid Postgres column type. (docs) Fixes Readonly Values. Type of values returned from Zero queries are marked readonly. The system always considered them readonly, but now the types reflect that. (docs) Breaking Changes The zero-cache config ZERO\\_JWT\\_SECRET has been renamed to ZERO\\_AUTH\\_SECRET for consistency with the new JWK-related keys. If you were using the old name, you'll need to update your .env file. All values returned by Zero are now readonly. You'll probably have to add this TS modifier various places. If you find yourself casting away readonly you probably should be cloing the value instead.",
"headings": []
},
{
- "id": "44-release-notes/index",
+ "id": "44-release-notes",
"title": "Release Notes",
- "url": "/docs/release-notes/index",
- "content": "Zero 0.21: PG arrays, TanStack starter, and more Zero 0.20: Full Supabase support, performance improvements Zero 0.19: Many, many bugfixes and cleanups Zero 0.18: Custom Mutators Zero 0.17: Background Queries Zero 0.16: Lambda-Based Permission Deployment Zero 0.15: Live Permission Updates Zero 0.14: Name Mapping and Multischema Zero 0.13: Multinode and SST Zero 0.12: Circular Relationships Zero 0.11: Windows Zero 0.10: Remove Top-Level Await Zero 0.9: JWK Support Zero 0.8: Schema Autobuild, Result Types, and Enums Zero 0.7: Read Perms and Docker Zero 0.6: Relationship Filters Zero 0.5: JSON Columns Zero 0.4: Compound Filters Zero 0.3: Schema Migrations and Write Perms Zero 0.2: Skip Mode and Computed PKs Zero 0.1: First Release",
+ "url": "/docs/release-notes",
+ "content": "Zero 0.22: Simplified TTLs Zero 0.21: PG arrays, TanStack starter, and more Zero 0.20: Full Supabase support, performance improvements Zero 0.19: Many, many bugfixes and cleanups Zero 0.18: Custom Mutators Zero 0.17: Background Queries Zero 0.16: Lambda-Based Permission Deployment Zero 0.15: Live Permission Updates Zero 0.14: Name Mapping and Multischema Zero 0.13: Multinode and SST Zero 0.12: Circular Relationships Zero 0.11: Windows Zero 0.10: Remove Top-Level Await Zero 0.9: JWK Support Zero 0.8: Schema Autobuild, Result Types, and Enums Zero 0.7: Read Perms and Docker Zero 0.6: Relationship Filters Zero 0.5: JSON Columns Zero 0.4: Compound Filters Zero 0.3: Schema Migrations and Write Perms Zero 0.2: Skip Mode and Computed PKs Zero 0.1: First Release",
"headings": []
},
{
@@ -339,42 +339,56 @@
"id": "48-solidjs",
"title": "SolidJS",
"url": "/docs/solidjs",
- "content": "Zero has built-in support for Solid. Hereβs what basic usage looks like: ```tsx import {createQuery} from '@rocicorp/zero/solid'; const issues = createQuery(() => { let issueQuery = z.query.issue .related('creator') .related('labels') .limit(100); const userID = selectedUserID(); if (userID) { issueQuery = issueQuery.where('creatorID', '=', userID); } return issueQuery; }); ``` Complete quickstart here: https://github.com/rocicorp/hello-zero-solid",
+ "content": "Zero has built-in support for Solid. Hereβs what basic usage looks like: import {useQuery} from '@rocicorp/zero/solid'; const issues = useQuery(() => { let issueQuery = z.query.issue .related('creator') .related('labels') .limit(100); const userID = selectedUserID(); if (userID) { issueQuery = issueQuery.where('creatorID', '=', userID); } return issueQuery; }); Complete quickstart here: https://github.com/rocicorp/hello-zero-solid",
"headings": []
},
{
- "id": "49-sync",
+ "id": "49-status",
+ "title": "Project Status",
+ "url": "/docs/status",
+ "content": "You will encounter bugs. You may encounter pathologically slow queries. You are likely to encounter situations where ZQL is not powerful enough to express the query you want. That said, we are building Zero live. It has been running our own bug tracker for months, and is used in production by a small set of customer applications that are an extremely good fit. This page describes the current state of Zero at a high level. To understand whether Zero makes sense for you, please also see When to Use Zero. Platforms and Frameworks React and SolidJS are fully-supported Svelte and Vue have community support React Native is not supported yet, but is planned Databases Most Postgres providers are supported Drizzle and Prisma have high-quality community-supported integrations Query Language Filters, sorts, limits, relationships, and exists are supported. Queries can have ttl to keep data synced across sesssions. Zero will stay within a (configurable) client-side row limit using LRU. Aggregates (count, min, max, group-by) are not yet supported. Full-text search is not yet supported (you can sometimes simulate with ILIKE, though it scales linearly). Infinite/virtual scroll is possible, but not easy or optimal. Performance We do not have a query analyzer, and do not do any join reordering. It's sometimes, but not always possible to manually reorder. Because of this, some queries (especially exists) can be pathological. We are actively working on this. Every query is a hybrid query. We haven't yet implemented \"client-only\" queries, meaning patterns like typeahead search can easily crush the server if the query is expensive. We have basic CLI tools to understand query performance, but we lack a full-featured inspector to understand at a glance what queries are open or slow. We share queries within a \"client group\" (e.g. all tabs in a browser), but not across groups. This means that if you have many users doing the same query, they will duplicate all that work server-side. Miscellaneous We do not have a way to limit queries to only expected/allowed forms (in progress). We do not have a good way to support previews (in progress). Running Zero requires deploying it yourself to AWS or similar. Running in a multinode, zero-downtime way is possible (we do it for zbugs), but significant effort. Running single node is easier, but updating the server takes it down for a minute or so (we are working on a SaaS solution).",
+ "headings": []
+ },
+ {
+ "id": "50-sync",
"title": "What is Sync?",
"url": "/docs/sync",
- "content": "We say that Zero is a sync engine. But what even is that? And why does it matter? Problem Let's say you have some data that you want to read and write from multiple devices. The most common way to do this today is to put that data into a central database and expose access to it via APIs. This works, but has downsides: Slow access. Every read and write has to go to the server, addding hundreds of milliseconds to each interaction. Stale data. API responses are immediately stale. The client has no way to know when to refresh them. Users may make decisions based on old information, and the views on different devices diverge over time. Online-only. If the server or the user's network connection is down, the app stops working completely. Solution Sync engines can solve these problems by keeping a local copy of the data on each device. The app reads and writes only to the local copy, not to the network. The sync engine pushes changes back and forth between the local copy and the server in the background, when connectivity allows. Zero uses server reconciliation β an elegant and flexible technique pionneered by the video game industry. This architecture can enable: Instant UI. Reads and writes are to local storage, effectively instant. Realtime updates. By running the sync engine continuously, users can see updates from other devices and users in realtime. The data is always fresh. Offline support. Because data is stored locally, it is possible to support at least limited offline access. Read-only access is definitely possible, and with careful attention to conflict resolution, offline writes can also be supported in some applications. Sync engines also simplify the development of complex apps. Big parts of modern app development are just data plumbing: fetching data, updating data, caching data, invalidating caches, keeping different copies of data consistent, and so-on. A sync engine abstracts all this away and lets you focus on what your app actually does. History of Sync Sync Engines have been around a long time. The first mass-market sync engine was probably Lotus Notes, released way back in 1989! Since then, there has been a steady trickle of important software built on sync engines: Microsoft Exchange Dropbox Google Docs Linear Superhuman Figma But sync engines are very hard to build. Typically, a new custom sync engine was built for each application at great expense. Knowledge about the specific application and its data model has to be built into each sync engine to correctly handle conflicts and partial sync. There have been some attempts at general-purpose sync engines: Firebase Realtime Database (2012) - a cloud-hosted database and that syncs. PouchDB (2013) - a sync engine attachment for CouchDB. Realm (2016) - a mobile database with sync capabilities. Replicache (2020) - The predecessor to Zero, a JavaScript library for building collaborative applications with real-time sync. But all have suffered from one or more significant problems that have prevented widespread adoption: No support for fine-grained data authorization Limited support for partial sync β users have to sync all data, even if they only need a small subset Required adoption of non-standard backend databases Limited ability to put business logic on read or write paths We are building Zero to address these limitations, and bring the benefits of sync to many more applications.",
+ "content": "We say that Zero is a sync engine. But what even is that? And why does it matter? Problem Let's say you have some data that you want to read and write from multiple devices. The most common way to do this today is to put that data into a central database and expose access to it via APIs. This works, but has downsides: Slow access. Every read and write has to go to the server, adding hundreds of milliseconds to each interaction. Stale data. API responses are immediately stale. The client has no way to know when to refresh them. Users may make decisions based on old information, and the views on different devices diverge over time. Online-only. If the server or the user's network connection is down, the app stops working completely. Solution Sync engines can solve these problems by keeping a local copy of the data on each device. The app reads and writes only to the local copy, not to the network. The sync engine pushes changes back and forth between the local copy and the server in the background, when connectivity allows. Zero uses server reconciliation β an elegant and flexible technique pionneered by the video game industry. This architecture can enable: Instant UI. Reads and writes are to local storage, effectively instant. Realtime updates. By running the sync engine continuously, users can see updates from other devices and users in realtime. The data is always fresh. Offline support. Because data is stored locally, it is possible to support at least limited offline access. For example, Zero supports read-only access while offline, and other sync engines support some limited offline writes. Sync engines also simplify the development of complex apps. Big parts of modern app development are just data plumbing: fetching data, updating data, caching data, invalidating caches, keeping different copies of data consistent, and so-on. A sync engine abstracts all this away and lets you focus on what your app actually does. History of Sync Sync Engines have been around a long time. The first mass-market sync engine was probably Lotus Notes, released way back in 1989! Since then, there has been a steady trickle of important software built on sync engines: Microsoft Exchange (1996) Google Docs (2006) Dropbox (2007) Figma (2016) Superhuman (2017) Linear (2019) But sync engines are very hard to build. Typically, a new custom sync engine is built for each application at great expense. Knowledge about the specific application and its data model must be built into each sync engine to correctly handle conflicts and partial sync. There have also been some attempts at general-purpose sync engines: Firebase Realtime Database (2012) - a cloud-hosted database and that syncs. PouchDB (2013) - a sync engine attachment for CouchDB. Realm (2016) - a mobile database with sync capabilities. Replicache (2020) - The predecessor to Zero, a JavaScript library for building collaborative applications with real-time sync. But all have suffered from one or more significant problems that have prevented widespread adoption: No support for fine-grained authorization Limited support for partial sync β users have to sync all data, even if they only need a small subset Required adoption of non-standard backend databases or data models Limited ability to put custom business logic on read or write paths We are building Zero to address these limitations, and bring the benefits of sync to many more applications.",
+ "headings": []
+ },
+ {
+ "id": "51-when-to-use",
+ "title": "When To Use Zero",
+ "url": "/docs/when-to-use",
+ "content": "We are trying to make Zero a great choice for a wide variety of applications. But every tool has tradeoffs, and Zero especially so while in alpha. This page will help you understand if Zero is a good fit for you today. Zero Might be a Good Fit You want to sync only a small subset of data to client Zero's query-driven sync is a powerful solution for partial sync. You can sync any data you can express as a set of Zero queries. By using partial sync, Zero apps can commonly load in < 1s, yet still maintain the interaction perf of sync. You need fine-grained read or write permissions Zero's custom mutators allow you to run arbitrary authorization, validation, or business logic on the write path. You can enforce that a write depends on what group a user is in, what has been shared with them, their role, etc. Read permissions are very expressive, allowing similar control over what data is synced to the client. You are building a traditional client-server web app Zero was designed from the ground up to be as close to a classic web app as a sync engine can be. If you have a traditional web app, you can try Zero side-by-side with your existing REST or GraphQL API, and incrementally migrate over time. You use PostgreSQL Some tools in our space require you to use a non-standard backend database or data model. Zero works with PostgreSQL, and uses your existing schema. Your app is broadly \"like Linear\" Zero is currently best suited for productivity apps with lots of interactivity. Interaction performance is very important to you Zero was built by people obsessed with interaction performance. If you share this goal you'll be going with the grain of Zero's design choices. Zero Might Not be a Good Fit You need the privacy or data ownership benefits of local-first Zero is not local-first. It's a client-server system with an authoritative server. You need to support offline writes or long periods offline Zero doesn't support offline writes yet. You are building a native mobile app Zero is written in TypeScript and only supports TypeScript clients. The total backend dataset is > ~100GB Zero stores a replica of your database (at least the subset you want to be syncable to clients) in a SQLite database owned by zero-cache. Zero's query engine is built assuming very fast local access to this replica (i.e., attached NVMe). But other setups are technically supported and work for smaller data. The ultimate size limit on the database that Zero can work with is the size limit of this SQLite database. So up to 45TB on EC2 at time of writing. However, most of our experience with Zero so far is with much smaller workloads. We currently recommend Zero for use with datasets smaller than 100GB, but are working to improve this in the beta timeframe. Zero Might Not be a Good Fit Yet While Zero is in alpha, there are additional reasons not to choose it: You don't want to run server-side infra Zero is a Docker container that you currently have to self-host. We're working on a SaaS solution but it's not ready yet. You can't tolerate occasional downtime The easiest way to run Zero today is single-node, which requires downtime for updates. Also there are occasional regressions. You need immediate support for React Native Zero doesn't support React Native yet, but it is planned. You need support for SSR Zero doesn't support SSR yet, but it is planned. Alternatives If Zero isn't right for you, here are some good alternatives to consider: Automerge: Local-first, CRDT-based solution. Pioneering branch-based offline support. Convex: Not a sync engine (reads and writes are server-first), but a very nice reactive database that is in GA. Ditto: CRDT-based, with high quality offline support. Electric: Postgres-based sync engine with a SaaS cloud. LiveStore: Interesting event sourced design from one of the founders of Prisma. Jazz: Batteries-included local-first. PowerSync: Sync engine that works with Postgres, MySQL, and MongoDB.",
"headings": []
},
{
- "id": "50-writing-data",
+ "id": "52-writing-data",
"title": "Writing Data with Mutators",
"url": "/docs/writing-data",
- "content": "Zero generates basic CRUD mutators for every table you sync. Mutators are available at zero.mutate.\\: ```tsx const z = new Zero(...); z.mutate.user.insert({ id: nanoid(), username: 'abby', language: 'en-us', }); ``` Insert Create new records with insert: ```tsx z.mutate.user.insert({ id: nanoid(), username: 'sam', language: 'js', }); ``` Optional fields can be set to null to explicitly set the new field to null. They can also be set to undefined to take the default value (which is often null but can also be some generated value server-side). ```tsx // schema.ts import {createTableSchema} from '@rocicorp/zero'; const userSchema = createTableSchema({ tableName: 'user', columns: { id: {type: 'string'}, name: {type: 'string'}, language: {type: 'string', optional: true}, }, primaryKey: ['id'], relationships: {}, }); // app.tsx // Sets language to `null` specifically z.mutate.user.insert({ id: nanoid(), username: 'sam', language: null, }); // Sets language to the default server-side value. Could be null, or some // generated or constant default value too. z.mutate.user.insert({ id: nanoid(), username: 'sam', }); // Same as above z.mutate.user.insert({ id: nanoid(), username: 'sam', language: undefined, }); ``` Upsert Create new records or update existing ones with upsert: ```tsx z.mutate.user.upsert({ id: samID, username: 'sam', language: 'ts', }); ``` upsert supports the same null / undefined semantics for optional fields that insert does (see above). Update Update an existing record. Does nothing if the specified record (by PK) does not exist. You can pass a partial, leaving fields out that you donβt want to change. For example here we leave the username the same: ```tsx // Leaves username field to previous value. z.mutate.user.update({ id: samID, language: 'golang', }); // Same as above z.mutate.user.update({ id: samID, username: undefined, language: 'haskell', }); // Reset language field to `null` z.mutate.user.update({ id: samID, language: null, }); ``` Delete Delete an existing record. Does nothing if specified record does not exist. ```tsx z.mutate.user.delete({ id: samID, }); ``` You can read more about it in Authentication. Batch Mutate You can do multiple CRUD mutates in a single batch. If any of the mutations fails, all will. They also all appear together atomically in a single transaction to other clients. ```tsx z.mutateBatch(async tx => { const samID = nanoid(); tx.user.insert({ id: samID, username: 'sam', }); const langID = nanoid(); tx.language.insert({ id: langID, userID: samID, name: 'js', }); }); ```",
+ "content": "Zero generates basic CRUD mutators for every table you sync. Mutators are available at zero.mutate.\\: const z = new Zero(...); z.mutate.user.insert({ id: nanoid(), username: 'abby', language: 'en-us', }); Insert Create new records with insert: z.mutate.user.insert({ id: nanoid(), username: 'sam', language: 'js', }); Optional fields can be set to null to explicitly set the new field to null. They can also be set to undefined to take the default value (which is often null but can also be some generated value server-side). // schema.ts import {createTableSchema} from '@rocicorp/zero'; const userSchema = createTableSchema({ tableName: 'user', columns: { id: {type: 'string'}, name: {type: 'string'}, language: {type: 'string', optional: true}, }, primaryKey: ['id'], relationships: {}, }); // app.tsx // Sets language to `null` specifically z.mutate.user.insert({ id: nanoid(), username: 'sam', language: null, }); // Sets language to the default server-side value. Could be null, or some // generated or constant default value too. z.mutate.user.insert({ id: nanoid(), username: 'sam', }); // Same as above z.mutate.user.insert({ id: nanoid(), username: 'sam', language: undefined, }); Upsert Create new records or update existing ones with upsert: z.mutate.user.upsert({ id: samID, username: 'sam', language: 'ts', }); upsert supports the same null / undefined semantics for optional fields that insert does (see above). Update Update an existing record. Does nothing if the specified record (by PK) does not exist. You can pass a partial, leaving fields out that you donβt want to change. For example here we leave the username the same: // Leaves username field to previous value. z.mutate.user.update({ id: samID, language: 'golang', }); // Same as above z.mutate.user.update({ id: samID, username: undefined, language: 'haskell', }); // Reset language field to `null` z.mutate.user.update({ id: samID, language: null, }); Delete Delete an existing record. Does nothing if specified record does not exist. z.mutate.user.delete({ id: samID, }); You can read more about it in Authentication. Batch Mutate You can do multiple CRUD mutates in a single batch. If any of the mutations fails, all will. They also all appear together atomically in a single transaction to other clients. z.mutateBatch(async tx => { const samID = nanoid(); tx.user.insert({ id: samID, username: 'sam', }); const langID = nanoid(); tx.language.insert({ id: langID, userID: samID, name: 'js', }); });",
"headings": []
},
{
- "id": "51-zero-cache-config",
+ "id": "53-zero-cache-config",
"title": "zero-cache Config",
"url": "/docs/zero-cache-config",
- "content": "zero-cache is configured either via CLI flag or environment variable. There is no separate zero.config file. You can also see all available flags by running zero-cache --help. Required Flags Auth One of Auth JWK, Auth JWK URL, or Auth Secret must be specified. See Authentication for more details. Replica File File path to the SQLite replica that zero-cache maintains. This can be lost, but if it is, zero-cache will have to re-replicate next time it starts up. flag: --replica-file env: ZERO\\_REPLICA\\_FILE required: true Upstream DB The \"upstream\" authoritative postgres database. In the future we will support other types of upstream besides PG. flag: --upstream-db env: ZERO\\_UPSTREAM\\_DB required: true Optional Flags Admin Password A password used to administer zero-cache server, for example to access the /statz endpoint. flag: --admin-password env: ZERO\\_ADMIN\\_PASSWORD required: false App ID Unique identifier for the app. Multiple zero-cache apps can run on a single upstream database, each of which is isolated from the others, with its own permissions, sharding (future feature), and change/cvr databases. The metadata of an app is stored in an upstream schema with the same name, e.g. zero, and the metadata for each app shard, e.g. client and mutation ids, is stored in the {app-id}\\_{#} schema. (Currently there is only a single \"0\" shard, but this will change with sharding). The CVR and Change data are managed in schemas named {app-id}\\_{shard-num}/cvr and {app-id}\\_{shard-num}/cdc, respectively, allowing multiple apps and shards to share the same database instance (e.g. a Postgres \"cluster\") for CVR and Change management. Due to constraints on replication slot names, an App ID may only consist of lower-case letters, numbers, and the underscore character. Note that this option is used by both zero-cache and zero-deploy-permissions. flag: --app-id env: ZERO\\_APP\\_ID default: zero App Publications Postgres PUBLICATIONs that define the tables and columns to replicate. Publication names may not begin with an underscore, as zero reserves that prefix for internal use. If unspecified, zero-cache will create and use an internal publication that publishes all tables in the public schema, i.e.: ``` CREATE PUBLICATION _{app-id}_public_0 FOR TABLES IN SCHEMA public; ``` Note that once an app has begun syncing data, this list of publications cannot be changed, and zero-cache will refuse to start if a specified value differs from what was originally synced. To use a different set of publications, a new app should be created. flag: --app-publications env: ZERO\\_APP\\_PUBLICATIONS default: \\[] Auth JWK A public key in JWK format used to verify JWTs. Only one of jwk, jwksUrl and secret may be set. flag: --auth-jwk env: ZERO\\_AUTH\\_JWK required: false Auth JWK URL A URL that returns a JWK set used to verify JWTs. Only one of jwk, jwksUrl and secret may be set. flag: --auth-jwks-url env: ZERO\\_AUTH\\_JWKS\\_URL required: false Auto Reset Automatically wipe and resync the replica when replication is halted. This situation can occur for configurations in which the upstream database provider prohibits event trigger creation, preventing the zero-cache from being able to correctly replicate schema changes. For such configurations, an upstream schema change will instead result in halting replication with an error indicating that the replica needs to be reset. When auto-reset is enabled, zero-cache will respond to such situations by shutting down, and when restarted, resetting the replica and all synced clients. This is a heavy-weight operation and can result in user-visible slowness or downtime if compute resources are scarce. flag: --auto-reset env: ZERO\\_AUTO\\_RESET default: true Auth Secret A symmetric key used to verify JWTs. Only one of jwk, jwksUrl and secret may be set. flag: --auth-secret env: ZERO\\_AUTH\\_SECRET required: false Change DB The Postgres database used to store recent replication log entries, in order to sync multiple view-syncers without requiring multiple replication slots on the upstream database. If unspecified, the upstream-db will be used. flag: --change-db env: ZERO\\_CHANGE\\_DB required: false Change Max Connections The maximum number of connections to open to the change database. This is used by the change-streamer for catching up zero-cache replication subscriptions. flag: --change-max-conns env: ZERO\\_CHANGE\\_MAX\\_CONNS default: 5 Change Streamer Mode The mode for running or connecting to the change-streamer: dedicated: runs the change-streamer and shuts down when another change-streamer takes over the replication slot. This is appropriate in a single-node configuration, or for the replication-manager in a multi-node configuration. discover: connects to the change-streamer as internally advertised in the change-db. This is appropriate for the view-syncers in a multi-node flag: --change-streamer-mode env: ZERO\\_CHANGE\\_STREAMER\\_MODE default: dedicated Change Streamer Port The port on which the change-streamer runs. This is an internal protocol between the replication-manager and zero-cache, which runs in the same process in local development. If unspecified, defaults to --port + 1. flag: --change-streamer-port env: ZERO\\_CHANGE\\_STREAMER\\_PORT required: false CVR DB The Postgres database used to store CVRs. CVRs (client view records) keep track of the data synced to clients in order to determine the diff to send on reconnect. If unspecified, the upstream-db will be used. flag: --cvr-db env: ZERO\\_CVR\\_DB required: false CVR Max Connections The maximum number of connections to open to the CVR database. This is divided evenly amongst sync workers. Note that this number must allow for at least one connection per sync worker, or zero-cache will fail to start. See num-sync-workers. flag: --cvr-max-conns env: ZERO\\_CVR\\_MAX\\_CONNS default: 30 Initial Sync Table Copy Workers The number of parallel workers used to copy tables during initial sync. Each worker copies a single table at a time, fetching rows in batches of initial-sync-row-batch-size. flag: --initial-sync-table-copy-workers env: ZERO\\_INITIAL\\_SYNC\\_TABLE\\_COPY\\_WORKERS default: 5 Lazy Startup Delay starting the majority of zero-cache until first request. This is mainly intended to avoid connecting to Postgres replication stream until the first request is received, which can be useful i.e., for preview instances. Currently only supported in single-node mode. flag: --lazy-startup env: ZERO\\_LAZY\\_STARTUP default: false Litestream Executable Path to the litestream executable. This option has no effect if litestream-backup-url is unspecified. flag: --litestream-executable env: ZERO\\_LITESTREAM\\_EXECUTABLE required: false Litestream Config Path Path to the litestream yaml config file. zero-cache will run this with its environment variables, which can be referenced in the file via ${ENV} substitution, for example: ZERO\\_REPLICA\\_FILE for the db Path ZERO\\_LITESTREAM\\_BACKUP\\_LOCATION for the db replica url ZERO\\_LITESTREAM\\_LOG\\_LEVEL for the log Level ZERO\\_LOG\\_FORMAT for the log type flag: --litestream-config-path env: ZERO\\_LITESTREAM\\_CONFIG\\_PATH default: ./src/services/litestream/config.yml Litestream Log Level flag: --litestream-log-level env: ZERO\\_LITESTREAM\\_LOG\\_LEVEL default: warn values: debug, info, warn, error Litestream Backup URL The location of the litestream backup, usually an s3:// URL. This is only consulted by the replication-manager. view-syncers receive this information from the replication-manager. flag: --litestream-backup-url env: ZERO\\_LITESTREAM\\_BACKUP\\_URL required: false Litestream Checkpoint Threshold MB The size of the WAL file at which to perform an SQlite checkpoint to apply the writes in the WAL to the main database file. Each checkpoint creates a new WAL segment file that will be backed up by litestream. Smaller thresholds may improve read performance, at the expense of creating more files to download when restoring the replica from the backup. flag: --litestream-checkpoint-threshold-mb env: ZERO\\_LITESTREAM\\_CHECKPOINT\\_THRESHOLD\\_MB default: 40 Litestream Incremental Backup Interval Minutes The interval between incremental backups of the replica. Shorter intervals reduce the amount of change history that needs to be replayed when catching up a new view-syncer, at the expense of increasing the number of files needed to download for the initial litestream restore. flag: --litestream-incremental-backup-interval-minutes env: ZERO\\_LITESTREAM\\_INCREMENTAL\\_BACKUP\\_INTERVAL\\_MINUTES default: 15 Litestream Snapshot Backup Interval Hours The interval between snapshot backups of the replica. Snapshot backups make a full copy of the database to a new litestream generation. This improves restore time at the expense of bandwidth. Applications with a large database and low write rate can increase this interval to reduce network usage for backups (litestream defaults to 24 hours). flag: --litestream-snapshot-backup-interval-hours env: ZERO\\_LITESTREAM\\_SNAPSHOT\\_BACKUP\\_INTERVAL\\_HOURS default: 12 Litestream Restore Parallelism The number of WAL files to download in parallel when performing the initial restore of the replica from the backup. flag: --litestream-restore-parallelism env: ZERO\\_LITESTREAM\\_RESTORE\\_PARALLELISM default: 48 Log Format Use text for developer-friendly console logging and json for consumption by structured-logging services. flag: --log-format env: ZERO\\_LOG\\_FORMAT default: \"text\" values: text, json Log IVM Sampling How often to collect IVM metrics. 1 out of N requests will be sampled where N is this value. flag: --log-ivm-sampling env: ZERO\\_LOG\\_IVM\\_SAMPLING default: 5000 Log Level Sets the logging level for the application. flag: --log-level env: ZERO\\_LOG\\_LEVEL default: \"info\" values: debug, info, warn, error Log Slow Hydrate Threshold The number of milliseconds a query hydration must take to print a slow warning. flag: --log-slow-hydrate-threshold env: ZERO\\_LOG\\_SLOW\\_HYDRATE\\_THRESHOLD default: 100 Log Slow Row Threshold The number of ms a row must take to fetch from table-source before it is considered slow. flag: --log-slow-row-threshold env: ZERO\\_LOG\\_SLOW\\_ROW\\_THRESHOLD default: 2 Log Trace Collector The URL of the trace collector to which to send trace data. Traces are sent over http. Port defaults to 4318 for most collectors. flag: --log-trace-collector env: ZERO\\_LOG\\_TRACE\\_COLLECTOR required: false Number of Sync Workers The number of processes to use for view syncing. Leave this unset to use the maximum available parallelism. If set to 0, the server runs without sync workers, which is the configuration for running the replication-manager. flag: --num-sync-workers env: ZERO\\_NUM\\_SYNC\\_WORKERS required: false Per User Mutation Limit Max The maximum mutations per user within the specified windowMs. flag: --per-user-mutation-limit-max env: ZERO\\_PER\\_USER\\_MUTATION\\_LIMIT\\_MAX required: false Per User Mutation Limit Window (ms) The sliding window over which the perUserMutationLimitMax is enforced. flag: --per-user-mutation-limit-window-ms env: ZERO\\_PER\\_USER\\_MUTATION\\_LIMIT\\_WINDOW\\_MS default: 60000 Port The port for sync connections. flag: --port env: ZERO\\_PORT default: 4848 Push URL The URL of the API server to which zero-cache will push mutations. Required if you use custom mutators. flag: --push-url env: ZERO\\_PUSH\\_URL required: false Query Hydration Stats Track and log the number of rows considered by query hydrations which take longer than log-slow-hydrate-threshold milliseconds. This is useful for debugging and performance tuning. flag: --query-hydration-stats env: ZERO\\_QUERY\\_HYDRATION\\_STATS required: false Replica Vacuum Interval Hours Performs a VACUUM at server startup if the specified number of hours has elapsed since the last VACUUM (or initial-sync). The VACUUM operation is heavyweight and requires double the size of the db in disk space. If unspecified, VACUUM operations are not performed. flag: --replica-vacuum-interval-hours env: ZERO\\_REPLICA\\_VACUUM\\_INTERVAL\\_HOURS required: false Server Version The version string outputted to logs when the server starts up. flag: --server-version env: ZERO\\_SERVER\\_VERSION required: false Storage DB Temp Dir Temporary directory for IVM operator storage. Leave unset to use os.tmpdir(). flag: --storage-db-tmp-dir env: ZERO\\_STORAGE\\_DB\\_TMP\\_DIR required: false Target Client Row Count A soft limit on the number of rows Zero will keep on the client. 20k is a good default value for most applications, and we do not recommend exceeding 100k. See Client Capacity Management for more details. flag: --target-client-row-count env: ZERO\\_TARGET\\_CLIENT\\_ROW\\_COUNT default: 20000 Task ID Globally unique identifier for the zero-cache instance. Setting this to a platform specific task identifier can be useful for debugging. If unspecified, zero-cache will attempt to extract the TaskARN if run from within an AWS ECS container, and otherwise use a random string. flag: --task-id env: ZERO\\_TASK\\_ID required: false Upstream Max Connections The maximum number of connections to open to the upstream database for committing mutations. This is divided evenly amongst sync workers. In addition to this number, zero-cache uses one connection for the replication stream. Note that this number must allow for at least one connection per sync worker, or zero-cache will fail to start. See num-sync-workers. flag: --upstream-max-conns env: ZERO\\_UPSTREAM\\_MAX\\_CONNS default: 20",
+ "content": "zero-cache is configured either via CLI flag or environment variable. There is no separate zero.config file. You can also see all available flags by running zero-cache --help. Required Flags Auth One of Auth JWK, Auth JWK URL, or Auth Secret must be specified. See Authentication for more details. Replica File File path to the SQLite replica that zero-cache maintains. This can be lost, but if it is, zero-cache will have to re-replicate next time it starts up. flag: --replica-file env: ZERO\\_REPLICA\\_FILE required: true Upstream DB The \"upstream\" authoritative postgres database. In the future we will support other types of upstream besides PG. flag: --upstream-db env: ZERO\\_UPSTREAM\\_DB required: true Optional Flags Admin Password A password used to administer zero-cache server, for example to access the /statz endpoint. flag: --admin-password env: ZERO\\_ADMIN\\_PASSWORD required: false App ID Unique identifier for the app. Multiple zero-cache apps can run on a single upstream database, each of which is isolated from the others, with its own permissions, sharding (future feature), and change/cvr databases. The metadata of an app is stored in an upstream schema with the same name, e.g. zero, and the metadata for each app shard, e.g. client and mutation ids, is stored in the {app-id}\\_{#} schema. (Currently there is only a single \"0\" shard, but this will change with sharding). The CVR and Change data are managed in schemas named {app-id}\\_{shard-num}/cvr and {app-id}\\_{shard-num}/cdc, respectively, allowing multiple apps and shards to share the same database instance (e.g. a Postgres \"cluster\") for CVR and Change management. Due to constraints on replication slot names, an App ID may only consist of lower-case letters, numbers, and the underscore character. Note that this option is used by both zero-cache and zero-deploy-permissions. flag: --app-id env: ZERO\\_APP\\_ID default: zero App Publications Postgres PUBLICATIONs that define the tables and columns to replicate. Publication names may not begin with an underscore, as zero reserves that prefix for internal use. If unspecified, zero-cache will create and use an internal publication that publishes all tables in the public schema, i.e.: CREATE PUBLICATION _{app-id}_public_0 FOR TABLES IN SCHEMA public; Note that once an app has begun syncing data, this list of publications cannot be changed, and zero-cache will refuse to start if a specified value differs from what was originally synced. To use a different set of publications, a new app should be created. flag: --app-publications env: ZERO\\_APP\\_PUBLICATIONS default: \\[] Auth JWK A public key in JWK format used to verify JWTs. Only one of jwk, jwksUrl and secret may be set. flag: --auth-jwk env: ZERO\\_AUTH\\_JWK required: false Auth JWK URL A URL that returns a JWK set used to verify JWTs. Only one of jwk, jwksUrl and secret may be set. flag: --auth-jwks-url env: ZERO\\_AUTH\\_JWKS\\_URL required: false Auto Reset Automatically wipe and resync the replica when replication is halted. This situation can occur for configurations in which the upstream database provider prohibits event trigger creation, preventing the zero-cache from being able to correctly replicate schema changes. For such configurations, an upstream schema change will instead result in halting replication with an error indicating that the replica needs to be reset. When auto-reset is enabled, zero-cache will respond to such situations by shutting down, and when restarted, resetting the replica and all synced clients. This is a heavy-weight operation and can result in user-visible slowness or downtime if compute resources are scarce. flag: --auto-reset env: ZERO\\_AUTO\\_RESET default: true Auth Secret A symmetric key used to verify JWTs. Only one of jwk, jwksUrl and secret may be set. flag: --auth-secret env: ZERO\\_AUTH\\_SECRET required: false Change DB The Postgres database used to store recent replication log entries, in order to sync multiple view-syncers without requiring multiple replication slots on the upstream database. If unspecified, the upstream-db will be used. flag: --change-db env: ZERO\\_CHANGE\\_DB required: false Change Max Connections The maximum number of connections to open to the change database. This is used by the change-streamer for catching up zero-cache replication subscriptions. flag: --change-max-conns env: ZERO\\_CHANGE\\_MAX\\_CONNS default: 5 Change Streamer Mode The mode for running or connecting to the change-streamer: dedicated: runs the change-streamer and shuts down when another change-streamer takes over the replication slot. This is appropriate in a single-node configuration, or for the replication-manager in a multi-node configuration. discover: connects to the change-streamer as internally advertised in the change-db. This is appropriate for the view-syncers in a multi-node flag: --change-streamer-mode env: ZERO\\_CHANGE\\_STREAMER\\_MODE default: dedicated Change Streamer Port The port on which the change-streamer runs. This is an internal protocol between the replication-manager and zero-cache, which runs in the same process in local development. If unspecified, defaults to --port + 1. flag: --change-streamer-port env: ZERO\\_CHANGE\\_STREAMER\\_PORT required: false Change Streamer URI When unset, the zero-cache runs its own replication-manager (i.e. change-streamer). In production, this should be set to the replication-manager URI, which runs a change-streamer on port 4849. flag: --change-streamer-uri env: ZERO\\_CHANGE\\_STREAMER\\_URI required: false CVR DB The Postgres database used to store CVRs. CVRs (client view records) keep track of the data synced to clients in order to determine the diff to send on reconnect. If unspecified, the upstream-db will be used. flag: --cvr-db env: ZERO\\_CVR\\_DB required: false CVR Max Connections The maximum number of connections to open to the CVR database. This is divided evenly amongst sync workers. Note that this number must allow for at least one connection per sync worker, or zero-cache will fail to start. See num-sync-workers. flag: --cvr-max-conns env: ZERO\\_CVR\\_MAX\\_CONNS default: 30 Enable Telemetry Zero collects anonymous telemetry data to help us understand usage. We collect: Zero version Uptime General machine information, like the number of CPUs, OS, CI/CD environment, etc. Information about usage, such as number of queries or mutations processed per hour. This is completely optional and can be disabled at any time. You can also opt-out by setting DO\\_NOT\\_TRACK=1. flag: --enable-telemetry env: ZERO\\_ENABLE\\_TELEMETRY default: true Initial Sync Table Copy Workers The number of parallel workers used to copy tables during initial sync. Each worker copies a single table at a time, fetching rows in batches of initial-sync-row-batch-size. flag: --initial-sync-table-copy-workers env: ZERO\\_INITIAL\\_SYNC\\_TABLE\\_COPY\\_WORKERS default: 5 Lazy Startup Delay starting the majority of zero-cache until first request. This is mainly intended to avoid connecting to Postgres replication stream until the first request is received, which can be useful i.e., for preview instances. Currently only supported in single-node mode. flag: --lazy-startup env: ZERO\\_LAZY\\_STARTUP default: false Litestream Backup URL The location of the litestream backup, usually an s3:// URL. This is only consulted by the replication-manager. view-syncers receive this information from the replication-manager. flag: --litestream-backup-url env: ZERO\\_LITESTREAM\\_BACKUP\\_URL required: false Litestream Checkpoint Threshold MB The size of the WAL file at which to perform an SQlite checkpoint to apply the writes in the WAL to the main database file. Each checkpoint creates a new WAL segment file that will be backed up by litestream. Smaller thresholds may improve read performance, at the expense of creating more files to download when restoring the replica from the backup. flag: --litestream-checkpoint-threshold-mb env: ZERO\\_LITESTREAM\\_CHECKPOINT\\_THRESHOLD\\_MB default: 40 Litestream Config Path Path to the litestream yaml config file. zero-cache will run this with its environment variables, which can be referenced in the file via ${ENV} substitution, for example: ZERO\\_REPLICA\\_FILE for the db Path ZERO\\_LITESTREAM\\_BACKUP\\_LOCATION for the db replica url ZERO\\_LITESTREAM\\_LOG\\_LEVEL for the log Level ZERO\\_LOG\\_FORMAT for the log type flag: --litestream-config-path env: ZERO\\_LITESTREAM\\_CONFIG\\_PATH default: ./src/services/litestream/config.yml Litestream Executable Path to the litestream executable. This option has no effect if litestream-backup-url is unspecified. flag: --litestream-executable env: ZERO\\_LITESTREAM\\_EXECUTABLE required: false Litestream Incremental Backup Interval Minutes The interval between incremental backups of the replica. Shorter intervals reduce the amount of change history that needs to be replayed when catching up a new view-syncer, at the expense of increasing the number of files needed to download for the initial litestream restore. flag: --litestream-incremental-backup-interval-minutes env: ZERO\\_LITESTREAM\\_INCREMENTAL\\_BACKUP\\_INTERVAL\\_MINUTES default: 15 Litestream Multipart Concurrency The number of parts (of size --litestream-multipart-size bytes) to upload or download in parallel when backing up or restoring the snapshot. flag: --litestream-multipart-concurrency env: ZERO\\_LITESTREAM\\_MULTIPART\\_CONCURRENCY default: 48 Litestream Multipart Size The size of each part when uploading or downloading the snapshot with \\--litestream-multipart-concurrency. Note that up to concurrency \\* size bytes of memory are used when backing up or restoring the snapshot. flag: --litestream-multipart-size env: ZERO\\_LITESTREAM\\_MULTIPART\\_SIZE default: 16777216 (16 MiB) Litestream Log Level flag: --litestream-log-level env: ZERO\\_LITESTREAM\\_LOG\\_LEVEL default: warn values: debug, info, warn, error Litestream Port Port on which litestream exports metrics, used to determine the replication watermark up to which it is safe to purge change log records. flag: --litestream-port env: ZERO\\_LITESTREAM\\_PORT default: --port + 2 Litestream Restore Parallelism The number of WAL files to download in parallel when performing the initial restore of the replica from the backup. flag: --litestream-restore-parallelism env: ZERO\\_LITESTREAM\\_RESTORE\\_PARALLELISM default: 48 Litestream Snapshot Backup Interval Hours The interval between snapshot backups of the replica. Snapshot backups make a full copy of the database to a new litestream generation. This improves restore time at the expense of bandwidth. Applications with a large database and low write rate can increase this interval to reduce network usage for backups (litestream defaults to 24 hours). flag: --litestream-snapshot-backup-interval-hours env: ZERO\\_LITESTREAM\\_SNAPSHOT\\_BACKUP\\_INTERVAL\\_HOURS default: 12 Log Format Use text for developer-friendly console logging and json for consumption by structured-logging services. flag: --log-format env: ZERO\\_LOG\\_FORMAT default: \"text\" values: text, json Log IVM Sampling How often to collect IVM metrics. 1 out of N requests will be sampled where N is this value. flag: --log-ivm-sampling env: ZERO\\_LOG\\_IVM\\_SAMPLING default: 5000 Log Level Sets the logging level for the application. flag: --log-level env: ZERO\\_LOG\\_LEVEL default: \"info\" values: debug, info, warn, error Log Slow Hydrate Threshold The number of milliseconds a query hydration must take to print a slow warning. flag: --log-slow-hydrate-threshold env: ZERO\\_LOG\\_SLOW\\_HYDRATE\\_THRESHOLD default: 100 Log Slow Row Threshold The number of ms a row must take to fetch from table-source before it is considered slow. flag: --log-slow-row-threshold env: ZERO\\_LOG\\_SLOW\\_ROW\\_THRESHOLD default: 2 Number of Sync Workers The number of processes to use for view syncing. Leave this unset to use the maximum available parallelism. If set to 0, the server runs without sync workers, which is the configuration for running the replication-manager. flag: --num-sync-workers env: ZERO\\_NUM\\_SYNC\\_WORKERS required: false Per User Mutation Limit Max The maximum mutations per user within the specified windowMs. flag: --per-user-mutation-limit-max env: ZERO\\_PER\\_USER\\_MUTATION\\_LIMIT\\_MAX required: false Per User Mutation Limit Window (ms) The sliding window over which the perUserMutationLimitMax is enforced. flag: --per-user-mutation-limit-window-ms env: ZERO\\_PER\\_USER\\_MUTATION\\_LIMIT\\_WINDOW\\_MS default: 60000 Port The port for sync connections. flag: --port env: ZERO\\_PORT default: 4848 Push API Key An optional secret used to authorize zero-cache to call the API server handling writes. flag: --push-api-key env: ZERO\\_PUSH\\_API\\_KEY required: false Push Forward Cookies If true, zero-cache will forward cookies from the request. This is useful for passing authentication cookies to the API server. If false, cookies are not forwarded. flag: --push-forward-cookies env: ZERO\\_PUSH\\_FORWARD\\_COOKIES default: false Push URL The URL of the API server to which zero-cache will push custom mutations. Can also be a pattern, or set of patterns, which is used in conjunction with the push.url paramter of the Zero constructor. In this case, the pattern specifies the URLs which Zero will allow the constructor to specify. Examples: https://\\*.example.com matches https://api.example.com and https://www.example.com https://\\*.example.com does not match https://example.com (no subdomain) https://\\*.example.com does not match https://api.example.com/path (no trailing path) https://\\*.\\*.example.com matches https://api.v1.example.com and https://www.v2.example.com https://\\*.\\*.example.com does not match https://api.example.com (only one subdomain) Currently, wildcards are only allowed for subdomains. flag: --push-url env: ZERO\\_PUSH\\_URL required: false Query Hydration Stats Track and log the number of rows considered by query hydrations which take longer than log-slow-hydrate-threshold milliseconds. This is useful for debugging and performance tuning. flag: --query-hydration-stats env: ZERO\\_QUERY\\_HYDRATION\\_STATS required: false Replica Vacuum Interval Hours Performs a VACUUM at server startup if the specified number of hours has elapsed since the last VACUUM (or initial-sync). The VACUUM operation is heavyweight and requires double the size of the db in disk space. If unspecified, VACUUM operations are not performed. flag: --replica-vacuum-interval-hours env: ZERO\\_REPLICA\\_VACUUM\\_INTERVAL\\_HOURS required: false Server Version The version string outputted to logs when the server starts up. flag: --server-version env: ZERO\\_SERVER\\_VERSION required: false Storage DB Temp Dir Temporary directory for IVM operator storage. Leave unset to use os.tmpdir(). flag: --storage-db-tmp-dir env: ZERO\\_STORAGE\\_DB\\_TMP\\_DIR required: false Task ID Globally unique identifier for the zero-cache instance. Setting this to a platform specific task identifier can be useful for debugging. If unspecified, zero-cache will attempt to extract the TaskARN if run from within an AWS ECS container, and otherwise use a random string. flag: --task-id env: ZERO\\_TASK\\_ID required: false Upstream Max Connections The maximum number of connections to open to the upstream database for committing mutations. This is divided evenly amongst sync workers. In addition to this number, zero-cache uses one connection for the replication stream. Note that this number must allow for at least one connection per sync worker, or zero-cache will fail to start. See num-sync-workers. flag: --upstream-max-conns env: ZERO\\_UPSTREAM\\_MAX\\_CONNS default: 20",
"headings": []
},
{
- "id": "52-zero-schema",
+ "id": "54-zero-schema",
"title": "Zero Schema",
"url": "/docs/zero-schema",
- "content": "Zero applications have both a database schema (the normal backend database schema that all web apps have) and a Zero schema. The purpose of the Zero schema is to: Provide typesafety for ZQL queries Define first-class relationships between tables Define permissions for access control \\(), }) .primaryKey('id'); ``` Custom JSON Types Use the json helper to define a column that stores a JSON-compatible value: ```tsx import {table, string, json} from '@rocicorp/zero'; const user = table('user') .columns({ id: string(), name: string(), settings: json<{theme: 'light' | 'dark'}>(), }) .primaryKey('id'); ``` Compound Primary Keys Pass multiple columns to primaryKey to define a compound primary key: ```ts const user = table('user') .columns({ orgID: string(), userID: string(), name: string(), }) .primaryKey('orgID', 'userID'); ``` Relationships Use the relationships function to define relationships between tables. Use the one and many helpers to define singular and plural relationships, respectively: ```ts const messageRelationships = relationships(message, ({one, many}) => ({ sender: one({ sourceField: ['senderID'], destField: ['id'], destSchema: user, }), replies: many({ sourceField: ['id'], destSchema: message, destField: ['parentMessageID'], }), })); ``` This creates \"sender\" and \"replies\" relationships that can later be queried with the related ZQL clause: ```ts const messagesWithSenderAndReplies = z.query.messages .related('sender') .related('replies'); ``` This will return an object for each message row. Each message will have a sender field that is a single User object or null, and a replies field that is an array of Message objects. Many-to-Many Relationships You can create many-to-many relationships by chaining the relationship definitions. Assuming issue and label tables, along with an issueLabel junction table, you can define a labels relationship like this: ```ts const issueRelationships = relationships(issue, ({many}) => ({ labels: many( { sourceField: ['id'], destSchema: issueLabel, destField: ['issueID'], }, { sourceField: ['labelID'], destSchema: label, destField: ['id'], }, ), })); ``` Compound Keys Relationships Relationships can traverse compound keys. Imagine a user table with a compound primary key of orgID and userID, and a message table with a related senderOrgID and senderUserID. This can be represented in your schema with: ```ts const messageRelationships = relationships(message, ({one}) => ({ sender: one({ sourceField: ['senderOrgID', 'senderUserID'], destSchema: user, destField: ['orgID', 'userID'], }), })); ``` Circular Relationships Circular relationships are fully supported: ```tsx const commentRelationships = relationships(comment, ({one}) => ({ parent: one({ sourceField: ['parentID'], destSchema: comment, destField: ['id'], }), })); ``` Database Schemas Use createSchema to define the entire Zero schema: ```tsx import {createSchema} from '@rocicorp/zero'; export const schema = createSchema({ tables: [user, medium, message], relationships: [userRelationships, mediumRelationships, messageRelationships], }); ``` Migrations Zero uses TypeScript-style structural typing to detect schema changes and implement smooth migrations. How it Works When the Zero client connects to zero-cache it sends a copy of the schema it was constructed with. zero-cache compares this schema to the one it has, and rejects the connection with a special error code if the schema is incompatible. By default, The Zero client handles this error code by calling location.reload(). The intent is to to get a newer version of the app that has been updated to handle the new server schema. If a reload loop does occur, Zero uses exponential backoff to avoid overloading the server. If you want to delay this reload, you can do so by providing the onUpdateNeeded constructor parameter: ```ts const z = new Zero({ onUpdateNeeded: updateReason => { if (reason.type === 'SchemaVersionNotSupported') { // Do something custom here, like show a banner. // When you're ready, call `location.reload()`. } }, }); ``` If the schema changes while a client is running in a compatible way, zero-cache syncs the schema change to the client so that it's ready when the app reloads and gets new code that needs it. If the schema changes while a client is running in an incompatible way, zero-cache will close the client connection with the same error code as above. Schema Change Process Like other database-backed applications, Zero schema migration generally follow an βexpand/migrate/contractβ pattern: Implement and run an βexpandβ migration on the backend that is backwards compatible with existing schemas. Add new rows, tables, as well as any defaults and triggers needed for backwards compatibility. Add any new permissions required for the new tables/columns by running zero-deploy-permissions. Update and deploy the client app to use the new schema. Optionally, after some grace period, implement and run a βcontractβ migration on the backend, deleting any obsolete rows/tables. Steps 1-3 can generally be done as part of one deploy by your CI pipeline, but step 4 would be weeks later when most open clients have refreshed and gotten new code.",
+ "content": "Zero applications have both a database schema (the normal backend database schema that all web apps have) and a Zero schema. The purpose of the Zero schema is to: Provide typesafety for ZQL queries Define first-class relationships between tables Define permissions for access control \\(), }) .primaryKey('id'); Custom JSON Types Use the json helper to define a column that stores a JSON-compatible value: import {table, string, json} from '@rocicorp/zero'; const user = table('user') .columns({ id: string(), name: string(), settings: json<{theme: 'light' | 'dark'}>(), }) .primaryKey('id'); Compound Primary Keys Pass multiple columns to primaryKey to define a compound primary key: const user = table('user') .columns({ orgID: string(), userID: string(), name: string(), }) .primaryKey('orgID', 'userID'); Relationships Use the relationships function to define relationships between tables. Use the one and many helpers to define singular and plural relationships, respectively: const messageRelationships = relationships(message, ({one, many}) => ({ sender: one({ sourceField: ['senderID'], destField: ['id'], destSchema: user, }), replies: many({ sourceField: ['id'], destSchema: message, destField: ['parentMessageID'], }), })); This creates \"sender\" and \"replies\" relationships that can later be queried with the related ZQL clause: const messagesWithSenderAndReplies = z.query.messages .related('sender') .related('replies'); This will return an object for each message row. Each message will have a sender field that is a single User object or null, and a replies field that is an array of Message objects. Many-to-Many Relationships You can create many-to-many relationships by chaining the relationship definitions. Assuming issue and label tables, along with an issueLabel junction table, you can define a labels relationship like this: const issueRelationships = relationships(issue, ({many}) => ({ labels: many( { sourceField: ['id'], destSchema: issueLabel, destField: ['issueID'], }, { sourceField: ['labelID'], destSchema: label, destField: ['id'], }, ), })); Compound Keys Relationships Relationships can traverse compound keys. Imagine a user table with a compound primary key of orgID and userID, and a message table with a related senderOrgID and senderUserID. This can be represented in your schema with: const messageRelationships = relationships(message, ({one}) => ({ sender: one({ sourceField: ['senderOrgID', 'senderUserID'], destSchema: user, destField: ['orgID', 'userID'], }), })); Circular Relationships Circular relationships are fully supported: const commentRelationships = relationships(comment, ({one}) => ({ parent: one({ sourceField: ['parentID'], destSchema: comment, destField: ['id'], }), })); Database Schemas Use createSchema to define the entire Zero schema: import {createSchema} from '@rocicorp/zero'; export const schema = createSchema({ tables: [user, medium, message], relationships: [userRelationships, mediumRelationships, messageRelationships], }); Migrations Zero uses TypeScript-style structural typing to detect schema changes and implement smooth migrations. How it Works When the Zero client connects to zero-cache it sends a copy of the schema it was constructed with. zero-cache compares this schema to the one it has, and rejects the connection with a special error code if the schema is incompatible. By default, The Zero client handles this error code by calling location.reload(). The intent is to to get a newer version of the app that has been updated to handle the new server schema. If a reload loop does occur, Zero uses exponential backoff to avoid overloading the server. If you want to delay this reload, you can do so by providing the onUpdateNeeded constructor parameter: const z = new Zero({ onUpdateNeeded: updateReason => { if (reason.type === 'SchemaVersionNotSupported') { // Do something custom here, like show a banner. // When you're ready, call `location.reload()`. } }, }); If the schema changes while a client is running in a compatible way, zero-cache syncs the schema change to the client so that it's ready when the app reloads and gets new code that needs it. If the schema changes while a client is running in an incompatible way, zero-cache will close the client connection with the same error code as above. Schema Change Process Like other database-backed applications, Zero schema migration generally follow an βexpand/migrate/contractβ pattern: Implement and run an βexpandβ migration on the backend that is backwards compatible with existing schemas. Add new rows, tables, as well as any defaults and triggers needed for backwards compatibility. Add any new permissions required for the new tables/columns by running zero-deploy-permissions. Update and deploy the client app to use the new schema. Optionally, after some grace period, implement and run a βcontractβ migration on the backend, deleting any obsolete rows/tables. Steps 1-3 can generally be done as part of one deploy by your CI pipeline, but step 4 would be weeks later when most open clients have refreshed and gotten new code.",
"headings": []
},
{
- "id": "53-zql-on-the-server",
+ "id": "55-zql-on-the-server",
"title": "ZQL on the Server",
"url": "/docs/zql-on-the-server",
- "content": "Custom Mutators use ZQL on the server as an implementation detail, but you can also use ZQL on the server directly, outside of Custom Mutators. This is useful for a variety of reasons: You can use ZQL to implement standard REST endpoints, allowing you to share code with custom mutators. You can use ZQL as part of schema migrations. In the future (but not yet implemented), this can support server-side rendering Here's a basic example: ```ts import { PushProcessor, ZQLDatabase, PostgresJSConnection, TransactionProviderInput, } from '@rocicorp/zero/pg'; const db = new ZQLDatabase( new PostgresJSConnection( postgres( must( process.env.ZERO_UPSTREAM_DB as string, 'required env var ZERO_UPSTREAM_DB', ), ), ), schema, ); // This is needed temporarily and will be cleaned up in the future. const dummyTransactionInput: TransactionProviderInput = { clientGroupID: 'unused', clientID: 'unused', mutationID: 42, upstreamSchema: 'unused', }; db.transaction(async tx => { // await tx.mutate... // await tx.query... // await myMutator(tx, ...args); }, dummyTransactionInput); ``` If ZQL does not have the featuers you need, you can use tx.dbTransaction to drop down to raw SQL. Custom Database Connection Zero only provides an adapter for postgres.js. It is possible to write your own adatapter by implementing DBTransaction and DBConnection. Node Postgres Here is an example for node-postgres by JΓΆkull SΓ³lberg (full example) ```ts import {Client, type ClientBase} from 'pg'; class PgConnection implements DBConnection { readonly #client: ClientBase; constructor(client: ClientBase) { this.#client = client; } async query(sql: string, params: unknown[]): Promise { const result = await this.#client.query(sql, params as JSONValue[]); return result.rows; } async transaction( fn: (tx: DBTransaction) => Promise, ): Promise { if (!(this.#client instanceof Client)) { throw new Error('Transactions require a non-pooled Client instance'); } const tx = new PgTransaction(this.#client); try { await this.#client.query('BEGIN'); const result = await fn(tx); await this.#client.query('COMMIT'); return result; } catch (error) { await this.#client.query('ROLLBACK'); throw error; } } } class PgTransaction implements DBTransaction { readonly wrappedTransaction: ClientBase; constructor(client: ClientBase) { this.wrappedTransaction = client; } async query(sql: string, params: unknown[]): Promise { const result = await this.wrappedTransaction.query( sql, params as JSONValue[], ); return result.rows; } } // Then you can use it just like postgres.js const client = new Client({ connectionString: process.env.ZERO_UPSTREAM_DB, }); await client.connect(); const db = new ZQLDatabase(new PgConnection(client), schema); ``` Drizzle ORM It is also possible to use ORMs like Drizzle. Wrap the drizzle transaction and now you can access drizzle's transaction within custom mutators. Blog post and full example by JΓΆkull SΓ³lberg (again π) ```ts // Assuming $client is the raw pg.PoolClient, this type matches how // `drizzle()` inits when using `node-postgres` type Drizzle = NodePgDatabase & {$client: PoolClient}; // Extract the Drizzle-specific transaction type type DrizzleTransaction = Parameters[0]>[0]; class DrizzleConnection implements DBConnection { drizzle: Drizzle; constructor(drizzle: Drizzle) { this.drizzle = drizzle; } // `query` is used by Zero's ZQLDatabase for ZQL reads on the server query(sql: string, params: unknown[]): Promise { return this.drizzle.$client .query(sql, params) .then(({rows}) => rows); } // `transaction` wraps Drizzle's transaction transaction( fn: (tx: DBTransaction) => Promise, ): Promise { return this.drizzle.transaction(drizzleTx => // Pass a new Zero DBTransaction wrapper around Drizzle's one fn(new ZeroDrizzleTransaction(drizzleTx)), ); } } class ZeroDrizzleTransaction implements DBTransaction { readonly wrappedTransaction: DrizzleTransaction; constructor(drizzleTx: DrizzleTransaction) { this.wrappedTransaction = drizzleTx; } // This `query` method would be used if ZQL reads happen *within* // a custom mutator that is itself running inside this wrapped transaction. query(sql: string, params: unknown[]): Promise { // Drizzle's transaction object might hide the raw client, // this is one way to get at it for `pg` driver. Adjust if needed. const session = this.wrappedTransaction._.session as unknown as { client: Drizzle['$client']; }; return session.client .query(sql, params) .then(({rows}) => rows); } } ``` SSR Although you can run ZQL on the server, Zero does not yet have the wiring setup in its bindings layers to support server-side rendering (patches welcome though!). For now, you should use your framework's recommended pattern to prevent SSR execution. Next.js Add the use client directive. SolidStart Wrap components that use Zero with the clientOnly higher-order component. The standard clientOnly pattern uses dynamic imports, but note that this approach (similar to React's lazy) works with any function returning a Promise<{default: () => JSX.Element}>. If code splitting is unnecessary, you can skip the dynamic import. TanStack Start Use React's lazy for dynamic imports.",
+ "content": "Custom Mutators use ZQL on the server as an implementation detail, but you can also use ZQL on the server directly, outside of Custom Mutators. This is useful for a variety of reasons: You can use ZQL to implement standard REST endpoints, allowing you to share code with custom mutators. You can use ZQL as part of schema migrations. In the future (but not yet implemented), this can support server-side rendering Here's a basic example: import { PushProcessor, ZQLDatabase, PostgresJSConnection, TransactionProviderInput, } from '@rocicorp/zero/pg'; const db = new ZQLDatabase( new PostgresJSConnection( postgres( must( process.env.ZERO_UPSTREAM_DB as string, 'required env var ZERO_UPSTREAM_DB', ), ), ), schema, ); // This is needed temporarily and will be cleaned up in the future. const dummyTransactionInput: TransactionProviderInput = { clientGroupID: 'unused', clientID: 'unused', mutationID: 42, upstreamSchema: 'unused', }; db.transaction(async tx => { // await tx.mutate... // await tx.query... // await myMutator(tx, ...args); }, dummyTransactionInput); If ZQL does not have the featuers you need, you can use tx.dbTransaction to drop down to raw SQL. Custom Database Connection Zero only provides an adapter for postgres.js. It is possible to write your own adatapter by implementing DBTransaction and DBConnection. Node Postgres Here is an example for node-postgres by JΓΆkull SΓ³lberg (full example) import {Client, type ClientBase} from 'pg'; class PgConnection implements DBConnection { readonly #client: ClientBase; constructor(client: ClientBase) { this.#client = client; } async query(sql: string, params: unknown[]): Promise { const result = await this.#client.query(sql, params as JSONValue[]); return result.rows; } async transaction( fn: (tx: DBTransaction) => Promise, ): Promise { if (!(this.#client instanceof Client)) { throw new Error('Transactions require a non-pooled Client instance'); } const tx = new PgTransaction(this.#client); try { await this.#client.query('BEGIN'); const result = await fn(tx); await this.#client.query('COMMIT'); return result; } catch (error) { await this.#client.query('ROLLBACK'); throw error; } } } class PgTransaction implements DBTransaction { readonly wrappedTransaction: ClientBase; constructor(client: ClientBase) { this.wrappedTransaction = client; } async query(sql: string, params: unknown[]): Promise { const result = await this.wrappedTransaction.query( sql, params as JSONValue[], ); return result.rows; } } // Then you can use it just like postgres.js const client = new Client({ connectionString: process.env.ZERO_UPSTREAM_DB, }); await client.connect(); const db = new ZQLDatabase(new PgConnection(client), schema); Drizzle ORM It is also possible to use ORMs like Drizzle. Wrap the drizzle transaction and now you can access drizzle's transaction within custom mutators. Blog post and full example by JΓΆkull SΓ³lberg (again π) // Assuming $client is the raw pg.PoolClient, this type matches how // `drizzle()` inits when using `node-postgres` type Drizzle = NodePgDatabase & {$client: PoolClient}; // Extract the Drizzle-specific transaction type type DrizzleTransaction = Parameters[0]>[0]; class DrizzleConnection implements DBConnection { drizzle: Drizzle; constructor(drizzle: Drizzle) { this.drizzle = drizzle; } // `query` is used by Zero's ZQLDatabase for ZQL reads on the server query(sql: string, params: unknown[]): Promise { return this.drizzle.$client .query(sql, params) .then(({rows}) => rows); } // `transaction` wraps Drizzle's transaction transaction( fn: (tx: DBTransaction) => Promise, ): Promise { return this.drizzle.transaction(drizzleTx => // Pass a new Zero DBTransaction wrapper around Drizzle's one fn(new ZeroDrizzleTransaction(drizzleTx)), ); } } class ZeroDrizzleTransaction implements DBTransaction { readonly wrappedTransaction: DrizzleTransaction; constructor(drizzleTx: DrizzleTransaction) { this.wrappedTransaction = drizzleTx; } // This `query` method would be used if ZQL reads happen *within* // a custom mutator that is itself running inside this wrapped transaction. query(sql: string, params: unknown[]): Promise { // Drizzle's transaction object might hide the raw client, // this is one way to get at it for `pg` driver. Adjust if needed. const session = this.wrappedTransaction._.session as unknown as { client: Drizzle['$client']; }; return session.client .query(sql, params) .then(({rows}) => rows); } } SSR Although you can run ZQL on the server, Zero does not yet have the wiring setup in its bindings layers to support server-side rendering (patches welcome though!). For now, you should use your framework's recommended pattern to prevent SSR execution. Next.js Add the use client directive. SolidStart Wrap components that use Zero with the clientOnly higher-order component. The standard clientOnly pattern uses dynamic imports, but note that this approach (similar to React's lazy) works with any function returning a Promise<{default: () => JSX.Element}>. If code splitting is unnecessary, you can skip the dynamic import. TanStack Start Use React's lazy for dynamic imports.",
"headings": []
}
]
\ No newline at end of file
diff --git a/components/CodeBlock.tsx b/components/CodeBlock.tsx
index 1dea76c7..35324a30 100644
--- a/components/CodeBlock.tsx
+++ b/components/CodeBlock.tsx
@@ -1,6 +1,6 @@
'use client';
-import React, {useEffect} from 'react';
+import React from 'react';
import hljs from 'highlight.js';
type CodeBlockProps = {
diff --git a/components/search.tsx b/components/search.tsx
index edc7807d..82a01695 100644
--- a/components/search.tsx
+++ b/components/search.tsx
@@ -143,7 +143,7 @@ export default function Search() {
const doc = searchDocs.find(d => d.id === ref);
if (!doc) return null;
- let snippet = extractSnippet(doc.content, sanitizedInput);
+ const snippet = extractSnippet(doc.content, sanitizedInput);
const snippetIndex = doc.content
.toLowerCase()
@@ -224,7 +224,7 @@ export default function Search() {
}, 20);
return () => clearTimeout(delayDebounce);
- }, [searchedInput]);
+ }, [searchedInput, lunrIndex]);
// Toggle the menu when βK is pressed
useHotkeys(
@@ -333,13 +333,13 @@ const PreloadCurrentItem = () => {
const activeItem = useMemo(() => {
return searchDocs.find(item => item.id === value);
- }, [value, searchDocs]);
+ }, [value]);
useEffect(() => {
if (activeItem) {
router.prefetch(activeItem.url);
}
- }, [activeItem]);
+ }, [activeItem, router]);
return <>>;
};
diff --git a/components/sublink.tsx b/components/sublink.tsx
index fc93f9d8..4dc64fdb 100644
--- a/components/sublink.tsx
+++ b/components/sublink.tsx
@@ -6,7 +6,6 @@ import {
CollapsibleTrigger,
} from '@/components/ui/collapsible';
import {SheetClose} from '@/components/ui/sheet';
-import {icons} from '@/lib/icons';
import {EachRoute} from '@/lib/routes-config';
import {cn} from '@/lib/utils';
import {ChevronRight} from 'lucide-react';
diff --git a/components/theme-provider.tsx b/components/theme-provider.tsx
index efcca84e..e0f112d6 100644
--- a/components/theme-provider.tsx
+++ b/components/theme-provider.tsx
@@ -2,7 +2,7 @@
import * as React from 'react';
import {ThemeProvider as NextThemesProvider} from 'next-themes';
-import {type ThemeProviderProps} from 'next-themes/dist/types';
+import type {ThemeProviderProps} from 'next-themes';
export function ThemeProvider({children, ...props}: ThemeProviderProps) {
return (
diff --git a/components/ui/ActiveHashLink.tsx b/components/ui/ActiveHashLink.tsx
index e9e6b06d..35369e1a 100644
--- a/components/ui/ActiveHashLink.tsx
+++ b/components/ui/ActiveHashLink.tsx
@@ -1,6 +1,5 @@
'use client';
-import clsx from 'clsx';
import Link from 'next/link';
import {useEffect, useRef} from 'react';
import useHash from '../hooks/useHash';
diff --git a/contents/docs/auth.mdx b/contents/docs/auth.mdx
index 2ce8593d..716d820b 100644
--- a/contents/docs/auth.mdx
+++ b/contents/docs/auth.mdx
@@ -139,8 +139,8 @@ Any data placed into your JWT (claims) can be used by permission rules on the ba
const isAdminRule = (decodedJWT, {cmp}) => cmp(decodedJWT.role, '=', 'admin');
```
-See the [permissions](permissions) section for more details.
+See the [permissions](/docs/permissions) section for more details.
## Examples
-See [zbugs](samples#zbugs) or [hello-zero](samples#hello-zero).
+See [zbugs](/docs/samples#zbugs) or [hello-zero](/docs/samples#hello-zero).
diff --git a/contents/docs/custom-mutators.mdx b/contents/docs/custom-mutators.mdx
index ff6f8855..899a025b 100644
--- a/contents/docs/custom-mutators.mdx
+++ b/contents/docs/custom-mutators.mdx
@@ -295,7 +295,7 @@ You can use the `.client` promise in this case to wait for a write to complete o
```ts
try {
- const write = zero.mutate.issue.update({
+ const write = zero.mutate.issue.insert({
id: 'issue-123',
title: 'New title',
});
@@ -318,12 +318,25 @@ You can also wait for the server write to succeed:
```ts
try {
- await zero.mutate.issue.update({
+ const write = zero.mutate.issue.insert({
id: 'issue-123',
title: 'New title',
- }).server;
+ });
+
+ await write.client;
- // issue-123 is written to server
+ // optimistic write guaranteed to be present here, but not
+ // server write.
+ const read1 = await zero.query.issue.where('id', 'issue-123').one();
+
+ // Await server write β this involves a round-trip.
+ await write.server;
+
+ // issue-123 is written to server and any results are
+ // syned to this client.
+ // read2 could potentially be undefined here, for example if the
+ // server mutator rejected the write.
+ const read2 = await zero.query.issue.where('id', 'issue-123').one();
} catch (e) {
console.error('Mutator failed on client or server', e);
}
@@ -339,20 +352,24 @@ If the client-side mutator fails, the `.server` promise is also rejected with th
You will need a server somewhere you can run an endpoint on. This is typically a serverless function on a platform like Vercel or AWS but can really be anything.
-Set the push URL with the [`ZERO_PUSH_URL` env var or `--push-url`](./zero-cache-config#push-url).
-
-If there is per-client configuration you need to send to the push endpoint, you can do that with `push.queryParams`:
+Configure the push endpoint with the `push.url` parameter in your `Zero` constructor:
```ts
-const z = new Zero({
+const zero = new Zero({
push: {
- queryParams: {
- workspaceID: '42',
- },
+ url: 'https://zero.my-server.com/push',
},
});
```
+You will also need to enable the server to be used as a push endpoint with the [`ZERO_PUSH_URL` environment variable or `--push-url` flag](./zero-cache-config#push-url):
+
+```bash
+ZERO_PUSH_URL=https://*.my-server.com/push
+```
+
+The `ZERO_PUSH_URL` parameter accepts wildcards, enabling the client to pass runtime configuration to the push endpoint or to use a different push endpoint, e.g., for previews. See the [config docs](./zero-cache-config#push-url) for the full syntax.
+
The push endpoint receives a `PushRequest` as input describing one or more mutations to apply to the backend, and must return a `PushResponse` describing the results of those mutations.
If you are implementing your server in TypeScript, you can use the `PushProcessor` class to trivially implement this endpoint. Hereβs an example in a [Hono](https://hono.dev/) app:
@@ -672,4 +689,4 @@ This will be documented in the future, but you can refer to the [PushProcessor](
## Examples
- Zbugs uses [custom mutators](https://github.com/rocicorp/mono/blob/a76c9a61670cc09e1a9fe7ab795749f3eef25577/apps/zbugs/shared/mutators.ts) for all mutations, [write permissions](https://github.com/rocicorp/mono/blob/a76c9a61670cc09e1a9fe7ab795749f3eef25577/apps/zbugs/shared/mutators.ts#L61), and [notifications](https://github.com/rocicorp/mono/blob/a76c9a61670cc09e1a9fe7ab795749f3eef25577/apps/zbugs/server/server-mutators.ts#L35).
-- `hello-zero-solid` uses custom mutators for all [mutations](TODO), and for [permissions](TODO).
+- [`hello-zero-solid`](./samples#hello-zero-solid) uses custom mutators for all mutations and for permissions.
diff --git a/contents/docs/debug/slow-queries.mdx b/contents/docs/debug/slow-queries.mdx
index 2100a5a4..ac0fdeab 100644
--- a/contents/docs/debug/slow-queries.mdx
+++ b/contents/docs/debug/slow-queries.mdx
@@ -31,7 +31,7 @@ If you are seeing unexpected UI flicker when moving between views, it is likely
You may alternately want to [preload some data](https://zero.rocicorp.dev/docs/reading-data#preloading) at app startup.
-Conversely, if you are setting `ttl` to long values, then it can happen that you have many backgrounded queries still running that the app is not using. You can see which queries are running using the [inspector](/docs/inspector). Ensure that only expected queries are running. See [long TTLs](/docs/reading-data#long-ttl-warning) for more information.
+Conversely, if you are setting `ttl` to long values, then it can happen that you have many backgrounded queries still running that the app is not using. You can see which queries are running using the [inspector](./inspector). Ensure that only expected queries are running. See [long TTLs](/docs/reading-data#long-ttl-warning) for more information.
## Check Storage
diff --git a/contents/docs/deployment.mdx b/contents/docs/deployment.mdx
index f9a23d0a..85777cf8 100644
--- a/contents/docs/deployment.mdx
+++ b/contents/docs/deployment.mdx
@@ -4,7 +4,7 @@ title: Deploying Zero
To deploy a Zero app, you need to:
-1. Deploy your backend database. Most standard Postgres hosts [work with Zero](connecting-to-postgres).
+1. Deploy your backend database. Most standard Postgres hosts [work with Zero](/docs/connecting-to-postgres).
1. Deploy `zero-cache`. We provide a [Docker image](https://hub.docker.com/r/rocicorp/zero) that can work with most Docker hosts.
1. Deploy your frontend. You can use any hosting service like Vercel or Netlify.
@@ -65,7 +65,7 @@ To upgrade Zero to a new major version, first deploy the new zero-cache, then th
## Configuration
-The `zero-cache` image is configured via environment variables. See [zero-cache Config](./zero-cache-config) for available options.
+The `zero-cache` image is configured via environment variables. See [zero-cache Config](/docs/zero-cache-config) for available options.
When using custom mutators, don't forget to set the push api url with
@@ -80,7 +80,7 @@ The setup below costs about $35/month. You can scale it up or down as needed by
### Setup Upstream
-Create an upstream Postgres database server somewhere. See [Connecting to Postgres](connecting-to-postgres) for details. Populate the schema and any initial data for your application.
+Create an upstream Postgres database server somewhere. See [Connecting to Postgres](/docs/connecting-to-postgres) for details. Populate the schema and any initial data for your application.
### Setup AWS
@@ -166,7 +166,20 @@ export default $config({
ZERO_LITESTREAM_BACKUP_URL: $interpolate`s3://${replicationBucket.name}/backup`,
ZERO_NUM_SYNC_WORKERS: '0',
},
+ loadBalancer: {
+ public: false,
+ ports: [
+ {
+ listen: '80/http',
+ forward: '4849/http',
+ },
+ ],
+ },
transform: {
+ service: {
+ // e.g. extend the grace period for initial sync of large databases
+ healthCheckGracePeriodSeconds: 600,
+ }
target: {
healthCheck: {
enabled: true,
@@ -197,12 +210,24 @@ export default $config({
},
environment: {
...commonEnv,
- ZERO_CHANGE_STREAMER_MODE: 'discover',
+ ZERO_CHANGE_STREAMER_URI: replicationManager.url,
+ },
+ loadBalancer: {
+ ports: [
+ {
+ listen: '80/http',
+ forward: '4848/http',
+ },
+ ],
},
logging: {
retention: '1 month',
},
transform: {
+ service: {
+ // e.g. extend the grace period for initial sync of large databases
+ healthCheckGracePeriodSeconds: 600,
+ }
target: {
healthCheck: {
enabled: true,
@@ -220,11 +245,6 @@ export default $config({
},
},
},
- {
- // Wait for replication-manager to come up first, for breaking changes
- // to replication-manager interface.
- dependsOn: [replicationManager],
- },
);
// Permissions deployment
@@ -276,11 +296,11 @@ If unsuccessful, you can get detailed logs with `npx sst deploy --verbose`. [Com
## Guide: Single-Node on Fly.io
-Let's deploy the [Quickstart](quickstart) app to [Fly.io](https://fly.io). We'll use Fly.io for both the database and `zero-cache`.
+Let's deploy the [Quickstart](/docs/quickstart) app to [Fly.io](https://fly.io). We'll use Fly.io for both the database and `zero-cache`.
### Setup Quickstart
-Go through the [Quickstart](quickstart) guide to get the app running locally.
+Go through the [Quickstart](/docs/quickstart) guide to get the app running locally.
### Setup Fly.io
@@ -418,6 +438,92 @@ Explaining the arguments above --
- `ZERO_AUTH_SECRET` - The secret to create and verify JWTs. This is the same secret that was used when deploying zero-cache to fly.
- `VITE_PUBLIC_SERVER` - The URL the frontend will call to talk to the zero-cache server. This is the URL of the fly app.
+## Guide: Single-Node on Sevalla
+
+[Sevalla.com](https://sevalla.com) is a modern Platform as a Service (PaaS) that can be used to deploy `zero-cache` in a single-node configuration, similar to Fly.io.
+
+This guide will walk you through deploying `zero-cache` to Sevalla using its web dashboard.
+
+### Setup Sevalla
+
+First, create an account on [Sevalla.com](https://sevalla.com). You will also need an upstream Postgres database. You can use any hosted Postgres provider like Supabase or Neon. Ensure you have the connection string handy.
+
+### Create a `zero-cache` Sevalla app
+
+1. From the Sevalla dashboard, create a new Application.
+2. Choose **Deploy from a public Docker image**.
+3. For the **Image URL**, enter `rocicorp/zero`. You can append a specific version tag like `rocicorp/zero:0.22.2025080201`, or use `latest` to get the newest version.
+4. Click **Continue**.
+
+On the configuration screen, you will set up the necessary resources, networking, and environment variables.
+
+#### Resources
+
+Under the **Resources** section, it is critical to allocate enough memory. `zero-cache` can be memory-intensive during startup.
+
+- **RAM**: Set to at least **2 GB**.
+- **vCPU**: Set to at least **0.5 vCPU**.
+
+
+ **Note:** Running with less than 2GB of RAM may cause the deployment to fail with an Out-Of-Memory (OOM) error (exit code 137). The process may fail silently and enter a restart loop, making it difficult to debug.
+
+
+#### Storage
+
+`zero-cache` requires a persistent disk to store the SQLite replica.
+
+1. Under the **Storage** section, click **Add disk**.
+2. **Name** your disk (e.g., `sqlite-db`).
+3. Set the **Mount path** to `/opt/app`. This is the working directory inside the `zero-cache` Docker container.
+4. Choose a sufficient size (e.g., 5 GB).
+
+#### Networking
+
+Expose `zero-cache` to the internet so your frontend client can connect to it.
+
+1. Under the **Networking** section, ensure the **Web (HTTP)** service is enabled.
+2. Set the **Port** to `4848`. This is the default port `zero-cache` listens on in single-node mode.
+3. You can leave the other settings at their defaults. Sevalla automatically handles HTTPS termination and WebSocket proxying.
+
+#### Environment Variables
+
+This is where you'll configure `zero-cache` to connect to your database.
+
+1. Under the **Environment variables** section, add the following variables, replacing them with their corresponding values.
+```
+ZERO_UPSTREAM_DB="..."
+ZERO_REPLICA_FILE="./sync-replica.db"
+ZERO_PUSH_URL="..."
+ZERO_AUTH_JWKS_URL="..." # or `ZERO_AUTH_SECRET` alternatively
+ZERO_LOG_FORMAT="text" # required by Sevalla.com to properly display logs
+```
+
+#### Deploy
+
+Click **Deploy** to deploy your `zero-cache` app.
+
+### Deploy Permissions
+
+Now `zero-cache` is running on Sevalla, but there are no permissions. If you run the app against this `zero-cache`, you'll see that no data is returned from any query. To fix this, deploy your permissions:
+
+```bash
+npx zero-deploy-permissions --schema-path='./src/schema.ts' --output-file='/tmp/permissions.sql'
+(cat /tmp/permissions.sql; echo "\q") | fly pg connect -a $PG_APP_NAME -d zstart
+```
+
+You will need to redo this step every time you change your app's permissions, likely as part of your
+CI/CD pipeline.
+
+### Use Remote `zero-cache`
+
+```bash
+VITE_PUBLIC_SERVER="https://${CACHE_APP_NAME}.fly.dev/" npm run dev:ui
+```
+
+Now restart the frontend to pick up the env change, and refresh the app. You can stop your local database and `zero-cache` as we're not using them anymore. Open the web inspector to verify the app is talking to the remote `zero-cache`!
+
+You can deploy the frontend to any standard hosting service like Vercel or Netlify, or even to Sevalla.com!
+
## Guide: Multi-Node on Raw AWS
### S3 Bucket
@@ -430,7 +536,7 @@ Run `zero-cache` as two Fargate services (using the same [rocicorp/zero](https:/
#### replication-manager
-- `zero-cache` [config](https://zero.rocicorp.dev/docs/zero-cache-config):
+- `zero-cache` config:
- `ZERO_LITESTREAM_BACKUP_URL=s3://{bucketName}/{generation}`
- `ZERO_NUM_SYNC_WORKERS=0`
- Task count: **1**
@@ -438,7 +544,7 @@ Run `zero-cache` as two Fargate services (using the same [rocicorp/zero](https:/
#### view-syncer
- `zero-cache` config:
- - `ZERO_CHANGE_STREAMER_MODE=discover`
+ - `ZERO_CHANGE_STREAMER_URI=http://{replication-manager}`
- Task count: **N**
- You can also use dynamic scaling
@@ -448,7 +554,10 @@ Run `zero-cache` as two Fargate services (using the same [rocicorp/zero](https:/
- Set `ZERO_CVR_MAX_CONNS` and `ZERO_UPSTREAM_MAX_CONNS` appropriately so that the total connections from both running and updating `view-syncers` (e.g. DesiredCount \* MaximumPercent) do not exceed your databaseβs `max_connections`.
- The `{generation}` component of the `s3://{bucketName}/{generation}` URL is an arbitrary path component that can be modified to reset the replica (e.g. a date, a number, etc.). Setting this to a new path is the multi-node equivalent of deleting the replica file to resync.
- Note: `zero-cache` does not manage cleanup of old generations.
-- The `replication-manager` serves requests on port **4849**. Routing from the `view-syncer` to the `http://{replication-manager}` is handled internally by storing data in the `changedb`.
+- The `replication-manager` serves requests on port **4849**. Routing from the `view-syncer` to the `http://{replication-manager}` can be achieved using the following mechanisms (in order of preference):
+ - An internal load balancer
+ - [Service Connect](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/service-connect.html)
+ - [Service Discovery](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/service-discovery.html)
- Fargate ephemeral storage is used for the replica.
- The default size is 20GB. This can be increased up to 200GB
- Allocate at least twice the size of the database to support the internal VACUUM operation.
diff --git a/contents/docs/introduction.mdx b/contents/docs/introduction.mdx
index 52e3c9f7..7ffac49d 100644
--- a/contents/docs/introduction.mdx
+++ b/contents/docs/introduction.mdx
@@ -2,7 +2,7 @@
title: Welcome to Zero Alpha
---
-Zero is a new kind of [sync engine](./sync) powered by queries.
+Zero is a new kind of [sync engine](/docs/sync) powered by queries.
Rather than syncing entire tables to the client, or using static rules to carefully specify what to sync, you just write queries directly in your client code. Queries can access the entire backend database.
@@ -10,4 +10,4 @@ Zero caches the data for queries locally on the device, and reuses that data aut
For typical applications, the result is that almost all queries are answered locally, instantly. It feels like you have access to the entire backend database directly from the client in memory. Occasionally, when you do a more specific query, Zero falls back to the server. But this happens automatically without any extra work required.
-Zero is made possible by a custom streaming query engine we built called [ZQL](reading-data), which uses [Incremental View Maintenance](https://www.vldb.org/pvldb/vol16/p1601-budiu.pdf) on both client and server to efficiently keep large, complex queries up to date.
+Zero is made possible by a custom streaming query engine we built called [ZQL](/docs/reading-data), which uses [Incremental View Maintenance](https://www.vldb.org/pvldb/vol16/p1601-budiu.pdf) on both client and server to efficiently keep large, complex queries up to date.
diff --git a/contents/docs/offline.mdx b/contents/docs/offline.mdx
index 98ca0f4d..a60be666 100644
--- a/contents/docs/offline.mdx
+++ b/contents/docs/offline.mdx
@@ -61,7 +61,23 @@ We would like to revisit this in the future and really think through how to desi
## Dealing with Offline Today
-Until Zero disables offline writes automatically, we recomment using the `onOnlineChange` parameter to the `Zero` constructor to detect connection loss and disable editing manually in your UI.
+Until Zero disables offline writes automatically, use `useZeroOnline` to detect connection loss and manually disable writes in your UI:
+
+```tsx
+const {online} = useZeroOnline();
+
+return ;
+```
+
+... or use the underlying `zero.onOnline` event:
+
+```tsx
+const unsubscribe = zero.onOnline(online => {
+ console.log('Online:', online);
+});
+```
## Even More Information
diff --git a/contents/docs/permissions.mdx b/contents/docs/permissions.mdx
index bc25d740..8d54ced9 100644
--- a/contents/docs/permissions.mdx
+++ b/contents/docs/permissions.mdx
@@ -161,11 +161,11 @@ definePermissions(schema, () => {
If the issue table has two rows, one created by the user and one by someone else, the user will only see the row they created in any queries.
-### Column permissions
-
-Zero does not currently support column based permissions. Select permission applies to every column. The recommended approach for now is to factor out private fields into a separate table, e.g. `user_private`. Column permissions are planned but currently not a high priority.
+
+Select permission applies to every column. The recommended approach for now is to factor out private fields into a separate table, e.g. `user_private`. Column permissions are planned but currently not a high priority.
Note that although the same limitation applies to declarative insert/update permissions, [custom mutators](/docs/custom-mutators) support arbitrary server-side logic and so can easily control which columns are writable.
+
## Insert Permissions
@@ -272,6 +272,27 @@ definePermissions(schema, () => {
Delete permissions work in the same way as `insert` permissions except they run _before_ the delete is applied. So if a delete rule queries the database, it will see that the deleted row is present. If any rule in the ruleset returns a row, the delete is allowed.
+## Permissions Based on Auth Data
+
+You can use the [`cmpLit` helper](reading-data#comparing-literal-values) to define permissions based on a field of the `authData` parameter:
+
+```ts
+definePermissions(schema, () => {
+ const allowIfAdmin = (
+ authData: AuthData,
+ {cmpLit}: ExpressionBuilder,
+ ) => cmpLit(authData.role, 'admin');
+
+ return {
+ issue: {
+ row: {
+ select: [allowIfAdmin],
+ },
+ },
+ } satisfies PermissionsConfig;
+});
+```
+
## Debugging
See [Debugging Permissions](./debug/permissions).
diff --git a/contents/docs/reading-data.mdx b/contents/docs/reading-data.mdx
index 7f0d24f5..9a982ac5 100644
--- a/contents/docs/reading-data.mdx
+++ b/contents/docs/reading-data.mdx
@@ -8,7 +8,7 @@ Inspired by SQL, ZQL is expressed in TypeScript with heavy use of the builder pa
ZQL queries are composed of one or more _clauses_ that are chained together into a _query_.
-Unlike queries in classic databases, the result of a ZQL query is a _view_ that updates automatically and efficiently as the underlying data changes. You can call a queryβs `materialize()` method to get a view, but more typically you run queries via some framework-specific bindings. For example see `useQuery` for [React](react) or [SolidJS](solidjs).
+Unlike queries in classic databases, the result of a ZQL query is a _view_ that updates automatically and efficiently as the underlying data changes. You can call a queryβs `materialize()` method to get a view, but more typically you run queries via some framework-specific bindings. For example see `useQuery` for [React](/docs/react) or [SolidJS](/docs/solidjs).
This means you should not modify the data directly. Instead, clone the data and modify the clone.
@@ -236,6 +236,36 @@ Note that chaining `where()` is also a one-level `and`:
z.query.issue.where('priority', '>=', 3).where('owner', 'aa');
```
+### Comparing Literal Values
+
+The `where` clause always expects its first parameter to be a column name as a string. Same with the `cmp` helper:
+
+```ts
+// "foo" is a column name, not a string:
+z.query.issue.where('foo', 'bar');
+
+// "foo" is a column name, not a string:
+z.query.issue.where(({cmp}) => cmp('foo', 'bar'));
+```
+
+To compareto a literal value, use the `cmpLit` helper:
+
+```ts
+z.query.issue.where(cmpLit('foobar', 'foo' + 'bar'));
+```
+
+By itself this is not very useful, but the first parameter can also be a JavaScript variable:
+
+```ts
+z.query.issue.where(cmpLit(role, 'admin'));
+```
+
+Or, within a [permission rule](/docs/permissions#permissions-based-on-auth-data), you can compare to a field of the `authData` parameter:
+
+```ts
+z.query.issue.where(cmpLit(authData.role, 'admin'));
+```
+
### Relationship Filters
Your filter can also test properties of relationships. Currently the only supported test is existence:
@@ -275,131 +305,6 @@ z.query.issue.where({cmp, or, exists} =>
);
```
-## Data Lifetime and Reuse
-
-Zero reuses data synced from prior queries to answer new queries when possible. This is what enables instant UI transitions.
-
-But what controls the lifetime of this client-side data? How can you know whether any particular query will return instant results? How can you know whether those results will be up to date or stale?
-
-The answer is that the data on the client is simply the union of rows returned from queries which are currently syncing. Once a row is no longer returned by any syncing query, it is removed from the client. Thus, there is never any stale data in Zero.
-
-So when you are thinking about whether a query is going to return results instantly, you should think about _what other queries are syncing_, not about what data is local. Data exists locally if and only if there is a query syncing that returns that data.
-
-
- This is why we often say that despite the name `zero-cache`, Zero is not technically a cache. It's a *replica*.
-
-A cache has a random set of rows with a random set of versions. There is no expectation that the cache any particular rows, or that the rows' have matching versions. Rows are simply updated as they are fetched.
-
-A replica by contrast is eagerly updated, whether or not any client has requested a row. A replica is always very close to up-to-date, and always self-consistent.
-
-Zero is a _partial_ replica because it only replicates rows that are returned by syncing queries.
-
-
-
-## Query Lifecycle
-
-
-
-Queries can be either _active_ or _backgrounded_. An active query is one that is currently being used by the application. Backgrounded queries are not currently in use, but continue syncing in case they are needed again soon.
-
-Active queries are created one of three ways:
-
-1. The app calls `q.materialize()` to get a `View`.
-2. The app uses a platform binding like React's `useQuery(q)`.
-3. The app calls [`preload()`](#preloading) to sync larger queries without a view.
-
-Active queries sync until they are _deactivated_. The way this happens depends on how the query was created:
-
-1. For `materialize()` queries, the UI calls `destroy()` on the view.
-2. For `useQuery()`, the UI unmounts the component (which calls `destroy()` under the covers).
-3. For `preload()`, the UI calls `cleanup()` on the return value of `preload()`.
-
-### Background Queries
-
-By default a deactivated query stops syncing immediately.
-
-But it's often useful to keep queries syncing beyond deactivation in case the UI needs the same or a similar query in the near future. This is accomplished with the `ttl` parameter:
-
-```ts
-const [user] = useQuery(z.query.user.where('id', userId), {ttl: '1d'});
-```
-
-The `ttl` parameter specifies how long the app developer wishes the query to run in the background. The following formats are allowed (where `%d` is a positive integer):
-
-| Format | Meaning |
-| --------- | ------------------------------------------------------------------------------------ |
-| `none` | No backgrounding. Query will immediately stop when deactivated. This is the default. |
-| `%ds` | Number of seconds. |
-| `%dm` | Number of minutes. |
-| `%dh` | Number of hours. |
-| `%dd` | Number of days. |
-
-
-Zero currently also accepts `ttl` values of `forever` and `%dy` (number of years). These are not recommended and will be removed in the next release. They were a misfeature.
-
-We realized long `ttl` values can lead to a lot of queries running in the background unnecessarily. If a new app release is deployed with new queries, the old queries keep running until their `ttl` expires, even though the app will never use them.
-
-We will be reworking this API to be less of a footgun in the next Zero release. For now we do not recommend using a `ttl` greater than `1d`.
-
-
-If the UI re-requests a background query, it becomes an active query again. Since the query was syncing in the background, the very first synchronous result that the UI receives after reactivation will be up-to-date with the server (i.e., it will have `resultType` of `complete`).
-
-Just like other types of queries, the data from background queries is available for use by new queries. A common pattern in to [preload](#preloading) a subset of most commonly needed data with `{ttl: 'forever'}` and then do more specific queries from the UI with, e.g., `{ttl: '1d'}`. Most often the preloaded data will be able to answer user queries, but if not, the new query will be answered by the server and backgrounded for a day in case the user revisits it.
-
-### Client Capacity Management
-
-Zero has a default soft limit of 20,000 rows on the client-side, or about 20MB of data assuming 1KB rows.
-
-This limit can be increased with the [`--target-client-row-count`](./zero-cache-config#target-client-row-count) flag, but we do not recommend setting it higher than 100,000.
-
-
-Contrary to the design of other sync engines, we believe that storing tons of data client-side doesn't make sense. Here are some reasons why:
-
-- Initial sync will be slow, slowing down initial app load.
-- Because storage in browser tabs is unreliable, initial sync can occur surprisingly often.
-- We want to answer queries _instantly_ as often as possible. This requires client-side data in memory on the main thread. If we have to page to disk, we may as well go to the network and reduce complexity.
-- Even though Zero's queries are very efficient, they do still have some cost, especially hydration. Massive client-side storage would result in hydrating tons of queries that are unlikely to be used every time the app starts.
-
-Most importantly, no matter how much data you store on the client, there will be cases where you have to fallback to the server:
-
-- Some users might have huge amounts of data.
-- Some users might have tiny amounts of available client storage.
-- You will likely want the app to start fast and sync in the background.
-
-Because you have to be able to fallback to server the question becomes _what is the **right** amount of data to store on the client?_, not _how can I store the absolute max possible data on the client?_
-
-The goal with Zero is to answer 99% of queries on the client from memory. The remaining 1% of queries can fallback gracefully to the server. 20,000 rows was chosen somewhat arbitrarily as a number of rows that was likely to be able to do this for many applications.
-
-There is no hard limit at 20,000 or 100,000. Nothing terrible happens if you go above. The thing to keep in mind is that:
-
-1. All those queries will revalidate every time your app boots.
-2. All data synced to the client is in memory in JS.
-
-
-
-Here is how this limit is managed:
-
-1. Active queries are never destroyed, even if the limit is exceeded. Developers are expected to keep active queries well under the limit.
-2. The `ttl` value counts from the moment a query deactivates. Backgrounded queries are destroyed immediately when the `ttl` is reached, even if the limit hasn't been reached.
-3. If the client exceeds its limit, Zero will destroy backgrounded queries, least-recently-used first, until the store is under the limit again.
-
-### Thinking in Queries
-
-Although IVM is a very efficient way to keep queries up to date relative to re-running them, it isn't free. You still need to think about how many queries you are creating, how long they are kept alive, and how expensive they are.
-
-This is why Zero defaults to _not_ backgrounding queries and doesn't try to aggressively fill its client datastore to capacity. You should put some thought into what queries you want to run in the background, and for how long.
-
-Zero currently provides a few basic tools to understand the cost of your queries:
-
-- The client logs a warning for slow query materializations. Look for `Slow query materialization` in your logs. The default threshold is `5s` (including network) but this is configurable with the `slowMaterializeThreshold` parameter.
-- The client logs the materialization time of all queries at the `debug` level. Look for `Materialized query` in your logs.
-- The server logs a warning for slow query materializations. Look for `Slow query materialization` in your logs. The default threshold is `5s` but this is configurable with the `log-slow-materialize-threshold` configuration parameter.
-
-We will be adding more tools over time.
-
## Completeness
Zero returns whatever data it has on the client immediately for a query, then falls back to the server for any missing data. Sometimes it's useful to know the difference between these two types of results. To do so, use the `result` from `useQuery`:
@@ -515,6 +420,145 @@ z.query.issue
.preload();
```
+## Data Lifetime and Reuse
+
+Zero reuses data synced from prior queries to answer new queries when possible. This is what enables instant UI transitions.
+
+But what controls the lifetime of this client-side data? How can you know whether any particular query will return instant results? How can you know whether those results will be up to date or stale?
+
+The answer is that the data on the client is simply the union of rows returned from queries which are currently syncing. Once a row is no longer returned by any syncing query, it is removed from the client. Thus, there is never any stale data in Zero.
+
+So when you are thinking about whether a query is going to return results instantly, you should think about _what other queries are syncing_, not about what data is local. Data exists locally if and only if there is a query syncing that returns that data.
+
+
+ This is why we often say that despite the name `zero-cache`, Zero is not technically a cache. It's a *replica*.
+
+A cache has a random set of rows with a random set of versions. There is no expectation that the cache any particular rows, or that the rows' have matching versions. Rows are simply updated as they are fetched.
+
+A replica by contrast is eagerly updated, whether or not any client has requested a row. A replica is always very close to up-to-date, and always self-consistent.
+
+Zero is a _partial_ replica because it only replicates rows that are returned by syncing queries.
+
+
+
+## Query Lifecycle
+
+
+
+Queries can be either _active_ or _cached_. An active query is one that is currently being used by the application. Cached queries are not currently in use, but continue syncing in case they are needed again soon.
+
+Active queries are created one of four ways:
+
+1. The app calls `q.materialize()` to get a `View`.
+2. The app uses a framework binding like React's `useQuery(q)`.
+3. The app calls [`preload()`](#preloading) to sync larger queries without a view.
+4. The app calls `q.run()` to get a single result.
+
+Active queries sync until they are _deactivated_. The way this happens depends on how the query was created:
+
+1. For `materialize()` queries, the UI calls `destroy()` on the view.
+2. For `useQuery()`, the UI unmounts the component (which calls `destroy()` under the covers).
+3. For `preload()`, the UI calls `cleanup()` on the return value of `preload()`.
+4. For `run()`, queries are automatically deactivated immediately after the result is returned.
+
+Additionally when a Zero instance closes, all active queries are automatically deactivated. This also happens when the containing page or script is unloaded.
+
+## TTLs
+
+Each query has a `ttl` that controls how long it stays cached.
+
+
+If the user closes all tabs for your app, Zero stops running and the time that elapses doesn't count toward any TTLs.
+
+You do not need to account for such time when choosing a TTL β you only need to account for time your app is running *without* a query.
+
+
+## TTL Defaults
+
+In most cases, the default TTL should work well:
+
+* `preload()` queries default to `ttl:'none'`, meaning they are not cached at all, and will stop syncing immediately when deactivated. But because `preload()` queries are typically registered at app startup and never shutdown, and [because the ttl clock only ticks while Zero is running](#the-ttl-clock-only-ticks-while-zero-is-running), this means that preload queries never get unregistered.
+* Other queries have a default `ttl` of `5m` (five minutes).
+
+## Setting Different TTLs
+
+You can override the default TTL with the `ttl` parameter:
+
+```ts
+// With useQuery():
+const [user] = useQuery(
+ z.query.user.where('id', userId),
+ {ttl: '5m'});
+
+// With preload():
+z.query.user.where('id', userId).preload(
+ {ttl: '5m'});
+
+// With run():
+const user = await z.query.user.where('id', userId).run(
+ {ttl: '5m'});
+
+// With materialize():
+const view = z.query.user.where('id', userId).materialize(
+ {ttl: '5m'});
+```
+
+TTLs up to `10m` (ten minutes) are currently supported. The following formats are allowed:
+
+| Format | Meaning |
+| --------- | --------------------------------------------------------- |
+| `none` | No caching. Query will immediately stop when deactivated. |
+| `%ds` | Number of seconds. |
+| `%dm` | Number of minutes. |
+
+## Choosing a TTL
+
+If you choose a different TTL, you should consider how likely it is that the query will be reused, and how far into the future this reuse will occur. Here are some guidelines to help you choose a TTL for common query types:
+
+### Preload Queries
+
+These queries load the most commonly needed data for your app. They are typically larger, run with the `preload()` method, and stay running the entire time your app is running.
+
+Because these queries run the entire time Zero runs, they do not need any TTL to keep them alive. And using a `ttl` for them is wasteful since when your app changes its preload query, it will end up running the old preload query *and* the new preload query, even though the app only cares about the new one.
+
+**Recommendation:** `ttl: 'none'` *(the default for `preload()`)*.
+
+### Navigational Queries
+
+These queries load data specific to a route. They are typically smaller and run with the `useQuery()` method. It is useful to cache them for a short time, so that they can be reactivated quickly if the user navigates back to the route.
+
+**Recommendation:** `ttl: '5m'` *(the default for `useQuery()`)*.
+
+### Ephemeral Queries
+
+These queries load data for a specific, short-lived user interaction and often come in large numbers (e.g., typeahead search).
+
+The chance of any specific ephemeral query being reused is low, so the benefit of caching them is also low.
+
+**Recommendation:** `useQuery(..., {ttl: 'none'})`)*.
+
+### Why Zero TTLs are Short
+
+Zero queries are not free.
+
+Just as in any database, queries consume resources on both the client and server. Memory is used to keep metadata about the query, and disk storage is used to keep the query's current state.
+
+We do drop this state after we haven't heard from a client for awhile, but this is only a partial improvement. If the client returns, we have to re-run the query to get the latest data.
+
+This means that we do not actually *want* to keep queries active unless there is a good chance they will be needed again soon.
+
+The default Zero TTL values might initially seem too short, but they are designed to work well with the way Zero's TTL clock works and strike a good balance between keeping queries alive long enough to be useful, while not keeping them alive so long that they consume resources unnecessarily.
+
+
+Previous versions of Zero allowed longer TTLs. The API still supports these, but they are clamped to `10m` and Zero prints a warning.
+
+If you think you need longer TTLs, please [let us know](https://discord.rocicorp.dev). We are still iterating on these APIs and may have missed something. Alternately we may be able to help you achieve your goal a different way.
+
+
## Running Queries Once
Usually subscribing to a query is what you want in a reactive UI, but every so often you'll need to run a query just once. To do this, use the `run()` method:
diff --git a/contents/docs/release-notes/0.21.mdx b/contents/docs/release-notes/0.21.mdx
index 3da33cd3..68bb372f 100644
--- a/contents/docs/release-notes/0.21.mdx
+++ b/contents/docs/release-notes/0.21.mdx
@@ -17,7 +17,7 @@ See [hello-zero](https://github.com/rocicorp/hello-zero/pull/44) for an example
## Features
-- New _"ztunes"_ sample using TanStack, Drizzle, Better Auth, and Fly.io ([docs](/samples#ztunes)).
+- New _"ztunes"_ sample using TanStack, Drizzle, Better Auth, and Fly.io ([docs](/docs/samples#ztunes)).
- Add initial support for Postgres arrays ([docs](/docs/postgres-support#column-types), [bug](https://bugs.rocicorp.dev/issue/3617)).
- Improved React lifecycle management with `ZeroProvider` ([docs](/docs/react#zero-provider), [PR](https://github.com/rocicorp/mono/pull/4527)).
- Expose `Zero` instances automatically at `__zero` ([docs](/docs/debug/inspector#creating-an-inspector), [PR](https://github.com/rocicorp/mono/pull/4526)).
diff --git a/contents/docs/release-notes/0.22.mdx b/contents/docs/release-notes/0.22.mdx
new file mode 100644
index 00000000..9466319e
--- /dev/null
+++ b/contents/docs/release-notes/0.22.mdx
@@ -0,0 +1,63 @@
+---
+title: Zero 0.22
+description: Simplified TTLs, fine-grained SolidJS, and more
+---
+
+## Install
+
+```bash
+npm install @rocicorp/zero@0.22
+```
+
+## Upgrading
+
+This release simplifies the concept of TTLs in Zero.
+
+See [hello-zero](https://github.com/rocicorp/hello-zero/pull/48), [hello-zero-solid](https://github.com/rocicorp/hello-zero-solid/pull/23), or [ztunes](https://github.com/rocicorp/ztunes/pull/17) for example upgrades.
+
+This release also adds anonymous telemetry collection. You can opt-out with the [DO_NOT_TRACK=1](../zero-cache-config#enable-telemetry) environment variable. Though we hope you will not, as it helps us improve Zero.
+
+### How TTLs Used to Work
+
+Previously, the TTL of a query simply measured normal "wall clock time" from when a query inactivated, including any time the app wasn't running at all.
+
+With experience, we realized this was a misfeature because it encouraged the use of very long or infinite TTLs, especially for preload queries. Developers always want preload queries registered, but since they do not know how long the app will be offline, they had no real choice but to use the TTL `forever`.
+
+These infinite TTLs would remain registered even after the app's code changed such that it no longer wanted them, slowing connections and incremental updates to process queries that the app was not even using.
+
+Worse, the prevalence of infinite TTLs in turns meant we needed some way to limit the size of the client cache. We introduced the "client row limit" for this. But developers would frequently accidentally blow through this limit, causing cache thrash.
+
+### How TTLs Work Now
+
+Now, query TTLs measure *"TTL time"* which ***only elapses while Zero is running***. This means that preload queries usually don't need a TTL at all, since they run the entire time Zero is active. This in turn means we can clamp TTLs to low values, which means queries evict naturally, which means we no longer need the client row limit either.
+
+### Using New TTLs
+
+You don't need to do anything specific to upgrade. Zero [will clamp your TTLs at `10m`](../reading-data#longer-ttls-are-disallowed) and print a warning.
+
+But for best results, please review the [new TTL documentation](../reading-data#query-lifecycle). In particular, see [how to set your TTLs](../reading-data#choosing-a-ttl) (TL;DR: You can often just remove them β [the defaults usually just work](../reading-data#ttl-defaults)).
+
+## Features
+
+- Rework and simplify query TTLs ([docs](/docs/reading-data#query-lifecycle), [upgrading](#upgrading)).
+- SolidJS bindings are now fine-grained, improving performance ([PR](https://github.com/rocicorp/mono/pull/4575)).
+- Restore `ZERO_CHANGE_STREAMER_URI` option ([doc](../zero-cache-config#change-streamer-uri), [PR](https://github.com/rocicorp/mono/pull/4584)).
+- Add `useZeroOnline` to React and SolidJS bindings ([doc](/docs/offline#dealing-with-offline-today)).
+- Add `ttl` to `run()` ([PR](https://github.com/rocicorp/mono/pull/4603)).
+- Allow client to specify `push.url` in the `Zero` constructor ([doc](../custom-mutators#setting-up-the-server)).
+- Add anonymous telemetry collection to `zero-cache` ([doc](../zero-cache-config#enable-telemetry)).
+
+## Fixes
+
+- Handle `public` in aliases, like `.from('public.table')` ([PR](https://github.com/rocicorp/mono/pull/4548)).
+- Sorting by columns with `null` values was incorrect in some cases ([PR](https://github.com/rocicorp/mono/pull/4562)).
+- Fix fencepost issue editing queries with limits ([PR](https://github.com/rocicorp/mono/pull/4563)).
+- Fix copy runner to more reliably reuse connections ([PR](https://github.com/rocicorp/mono/pull/4573)).
+- Queries early in startup could not contain non-latin chars ([PR](https://github.com/rocicorp/mono/pull/4607)).
+- SolidJS: Export `createUseZero` ([PR](https://github.com/rocicorp/mono/pull/4610)).
+- Support parallel rollouts of replication-manager and view-syncer ([PR](https://github.com/rocicorp/mono/pull/4658)).
+- Fix upgrade path for already replicated array types ([PR](https://github.com/rocicorp/mono/pull/4676)).
+
+## Breaking Changes
+
+- Require Node v22+ (see [discussion](https://discord.com/channels/830183651022471199/1367274189178015955/1391931944089948361))
diff --git a/contents/docs/release-notes/0.5.mdx b/contents/docs/release-notes/0.5.mdx
index 4ab763d4..11b88330 100644
--- a/contents/docs/release-notes/0.5.mdx
+++ b/contents/docs/release-notes/0.5.mdx
@@ -24,7 +24,7 @@ Basically:
## Features
- Added support for JSON columns in Postgres ([documentation](/docs/postgres-support)).
-- Zero pacakage now includes `zero-sqlite3`, which can be used to explore our sqlite files ([documentation](/docs/recipes)).
+- Zero pacakage now includes `zero-sqlite3`, which can be used to explore our sqlite files ([documentation](/docs/debug/replication#inspecting)).
## Fixes
diff --git a/contents/docs/release-notes/0.6.mdx b/contents/docs/release-notes/0.6.mdx
index 4995b8cf..9cb7e5e0 100644
--- a/contents/docs/release-notes/0.6.mdx
+++ b/contents/docs/release-notes/0.6.mdx
@@ -40,7 +40,7 @@ This release is a bit harder to upgrade to than previous alphas. For a step-by-s
- Default max connections of zero-cache more conservatively so that it should fit with even common small Postgres configurations.
- `zero-cache` now accepts requests with any base path, not just `/api`. The `server` parameter to the `Zero` client constructor can now be a host (`https://myapp-myteam.zero.ms`) or a host with a single path component (`https://myapp-myteam.zero.ms/zero`). These two changes together allow hosting `zero-cache` on same domain with an app that already uses the `/api` prefix ([bug](https://bugs.rocicorp.dev/issue/3115)).
- Allow Postgres columns with default values, but donβt sync them ([documentation](/docs/postgres-support#column-defaults)).
-- The `npx zero-sqlite` utility now accepts all the same flags and arguments that `sqlite3` does ([documentation](/docs/debugging/replication)).
+- The `npx zero-sqlite` utility now accepts all the same flags and arguments that `sqlite3` does ([documentation](/docs/debug/replication#inspecting)).
## zbugs
diff --git a/contents/docs/release-notes/index.mdx b/contents/docs/release-notes/index.mdx
index 974579bd..7ad73e28 100644
--- a/contents/docs/release-notes/index.mdx
+++ b/contents/docs/release-notes/index.mdx
@@ -2,6 +2,7 @@
title: Release Notes
---
+- [Zero 0.22: Simplified TTLs](/docs/release-notes/0.22)
- [Zero 0.21: PG arrays, TanStack starter, and more](/docs/release-notes/0.21)
- [Zero 0.20: Full Supabase support, performance improvements](/docs/release-notes/0.20)
- [Zero 0.19: Many, many bugfixes and cleanups](/docs/release-notes/0.19)
diff --git a/contents/docs/solidjs.mdx b/contents/docs/solidjs.mdx
index eb0551d1..78dcc5dd 100644
--- a/contents/docs/solidjs.mdx
+++ b/contents/docs/solidjs.mdx
@@ -5,9 +5,9 @@ title: SolidJS
Zero has built-in support for Solid. Hereβs what basic usage looks like:
```tsx
-import {createQuery} from '@rocicorp/zero/solid';
+import {useQuery} from '@rocicorp/zero/solid';
-const issues = createQuery(() => {
+const issues = useQuery(() => {
let issueQuery = z.query.issue
.related('creator')
.related('labels')
diff --git a/contents/docs/status.mdx b/contents/docs/status.mdx
index aa3346eb..a7b6a058 100644
--- a/contents/docs/status.mdx
+++ b/contents/docs/status.mdx
@@ -1,3 +1,6 @@
+---
+title: Project Status
+---
Zero is a new sync engine based on a novel streaming query engine. This is an ambitious project at an early stage.
diff --git a/contents/docs/sync.mdx b/contents/docs/sync.mdx
index 05f09a71..48dc7466 100644
--- a/contents/docs/sync.mdx
+++ b/contents/docs/sync.mdx
@@ -1,5 +1,6 @@
---
title: What is Sync?
+description: A Slightly Opinionated Tour of the Space
---
We say that Zero is a *sync engine*. But what even is that? And why does it matter?
@@ -20,7 +21,7 @@ Let's say you have some data that you want to read and write from multiple devic
This works, but has downsides:
-* **Slow access.** Every read and write has to go to the server, addding hundreds of milliseconds to each interaction.
+* **Slow access.** Every read and write has to go to the server, adding hundreds of milliseconds to each interaction.
* **Stale data.** API responses are immediately stale. The client has no way to know when to refresh them. Users may make decisions based on old information, and the views on different devices diverge over time.
* **Online-only.** If the server or the user's network connection is down, the app stops working completely.
@@ -59,8 +60,8 @@ The first mass-market sync engine was probably [Lotus Notes](https://en.wikipedi
* Microsoft Exchange (1996)
* Google Docs (2006)
* Dropbox (2007)
-* Superhuman (2017)
* Figma (2016)
+* Superhuman (2017)
* Linear (2019)
But sync engines are very hard to build. Typically, a new custom sync engine is built for each application at great expense. Knowledge about the specific application and its data model must be built into each sync engine to correctly handle conflicts and partial sync.
@@ -69,7 +70,7 @@ There have also been some attempts at general-purpose sync engines:
* [Firebase Realtime Database](https://firebase.google.com/products/realtime-database) (2012) - a cloud-hosted database and that syncs.
* [PouchDB](https://pouchdb.com/) (2013) - a sync engine attachment for CouchDB.
-* [Realm](https://realm.io/) (2016) - a mobile database with sync capabilities.
+* [Realm](https://github.com/realm) (2016) - a mobile database with sync capabilities.
* [Replicache](https://replicache.dev/) (2020) - The predecessor to Zero, a JavaScript library for building collaborative applications with real-time sync.
But all have suffered from one or more significant problems that have prevented widespread adoption:
diff --git a/contents/docs/when-to-use.mdx b/contents/docs/when-to-use.mdx
index bfbcaeab..f0238bb4 100644
--- a/contents/docs/when-to-use.mdx
+++ b/contents/docs/when-to-use.mdx
@@ -1,10 +1,11 @@
---
-title: When To Use Zero (and When Not To)
+title: When To Use Zero
+description: And When Not To β A Quick Guide
---
We are trying to make Zero a great choice for a wide variety of applications. But every tool has tradeoffs, and Zero especially so [while in alpha](./status).
-This page will help you understance if Zero is a good fit for you today.
+This page will help you understand if Zero is a good fit for you today.
## Zero Might be a Good Fit
@@ -46,9 +47,15 @@ Zero doesn't support [offline writes](./offline) yet.
Zero is written in TypeScript and only supports TypeScript clients.
-### The total backend dataset is > ~1TB
+### The total backend dataset is > ~100GB
-Zero stores a replica of your database (at least the parts that can sync to client) in a SQLite database stored on attached SSD within the Zero server. The ultimate limit of this database size is the size of attached SSD. But 1TB is a reasonable practical limit today.
+Zero stores a replica of your database (at least the subset you want to be syncable to clients) in a SQLite database owned by zero-cache.
+
+Zero's query engine is built assuming very fast local access to this replica (i.e., attached NVMe). But other setups are technically supported and work for smaller data.
+
+The ultimate size limit on the database that Zero can work with is the size limit of this SQLite database. So [up to 45TB on EC2](https://aws.amazon.com/ec2/instance-types/) at time of writing.
+
+However, most of our experience with Zero so far is with much smaller workloads. We currently recommend Zero for use with datasets smaller than 100GB, but are working to improve this in the beta timeframe.
## Zero Might Not be a Good Fit **Yet**
diff --git a/contents/docs/zero-cache-config.mdx b/contents/docs/zero-cache-config.mdx
index 53061de3..211c3db4 100644
--- a/contents/docs/zero-cache-config.mdx
+++ b/contents/docs/zero-cache-config.mdx
@@ -143,6 +143,15 @@ flag: `--change-streamer-port`
env: `ZERO_CHANGE_STREAMER_PORT`
required: `false`
+### Change Streamer URI
+
+When unset, the zero-cache runs its own replication-manager (i.e. change-streamer). In production, this should be set to the replication-manager URI, which runs a change-streamer on port 4849.
+
+flag: `--change-streamer-uri`
+env: `ZERO_CHANGE_STREAMER_URI`
+required: `false`
+
+
### CVR DB
The Postgres database used to store CVRs. CVRs (client view records) keep track of the data synced to clients in order to determine the diff to send on reconnect. If unspecified, the upstream-db will be used.
@@ -161,6 +170,21 @@ flag: `--cvr-max-conns`
env: `ZERO_CVR_MAX_CONNS`
default: `30`
+### Enable Telemetry
+
+Zero collects anonymous telemetry data to help us understand usage. We collect:
+
+- Zero version
+- Uptime
+- General machine information, like the number of CPUs, OS, CI/CD environment, etc.
+- Information about usage, such as number of queries or mutations processed per hour.
+
+This is completely optional and can be disabled at any time. You can also opt-out by setting [`DO_NOT_TRACK=1`](https://consoledonottrack.com/).
+
+flag: `--enable-telemetry`
+env: `ZERO_ENABLE_TELEMETRY`
+default: `true`
+
### Initial Sync Table Copy Workers
The number of parallel workers used to copy tables during initial sync. Each worker copies a single table at a time, fetching rows in batches of `initial-sync-row-batch-size`.
@@ -181,14 +205,22 @@ flag: `--lazy-startup`
env: `ZERO_LAZY_STARTUP`
default: `false`
-### Litestream Executable
+### Litestream Backup URL
-Path to the litestream executable. This option has no effect if litestream-backup-url is unspecified.
+The location of the litestream backup, usually an s3:// URL. This is only consulted by the replication-manager. view-syncers receive this information from the replication-manager.
-flag: `--litestream-executable`
-env: `ZERO_LITESTREAM_EXECUTABLE`
+flag: `--litestream-backup-url`
+env: `ZERO_LITESTREAM_BACKUP_URL`
required: `false`
+### Litestream Checkpoint Threshold MB
+
+The size of the WAL file at which to perform an SQlite checkpoint to apply the writes in the WAL to the main database file. Each checkpoint creates a new WAL segment file that will be backed up by litestream. Smaller thresholds may improve read performance, at the expense of creating more files to download when restoring the replica from the backup.
+
+flag: `--litestream-checkpoint-threshold-mb`
+env: `ZERO_LITESTREAM_CHECKPOINT_THRESHOLD_MB`
+default: `40`
+
### Litestream Config Path
Path to the litestream yaml config file. zero-cache will run this with its environment variables, which can be referenced in the file via `${ENV}` substitution, for example:
@@ -202,29 +234,14 @@ flag: `--litestream-config-path`
env: `ZERO_LITESTREAM_CONFIG_PATH`
default: `./src/services/litestream/config.yml`
-### Litestream Log Level
-
-flag: `--litestream-log-level`
-env: `ZERO_LITESTREAM_LOG_LEVEL`
-default: `warn`
-values: `debug`, `info`, `warn`, `error`
-
-### Litestream Backup URL
+### Litestream Executable
-The location of the litestream backup, usually an s3:// URL. This is only consulted by the replication-manager. view-syncers receive this information from the replication-manager.
+Path to the litestream executable. This option has no effect if litestream-backup-url is unspecified.
-flag: `--litestream-backup-url`
-env: `ZERO_LITESTREAM_BACKUP_URL`
+flag: `--litestream-executable`
+env: `ZERO_LITESTREAM_EXECUTABLE`
required: `false`
-### Litestream Checkpoint Threshold MB
-
-The size of the WAL file at which to perform an SQlite checkpoint to apply the writes in the WAL to the main database file. Each checkpoint creates a new WAL segment file that will be backed up by litestream. Smaller thresholds may improve read performance, at the expense of creating more files to download when restoring the replica from the backup.
-
-flag: `--litestream-checkpoint-threshold-mb`
-env: `ZERO_LITESTREAM_CHECKPOINT_THRESHOLD_MB`
-default: `40`
-
### Litestream Incremental Backup Interval Minutes
The interval between incremental backups of the replica. Shorter intervals reduce the amount of change history that needs to be replayed when catching up a new view-syncer, at the expense of increasing the number of files needed to download for the initial litestream restore.
@@ -233,13 +250,40 @@ flag: `--litestream-incremental-backup-interval-minutes`
env: `ZERO_LITESTREAM_INCREMENTAL_BACKUP_INTERVAL_MINUTES`
default: `15`
-### Litestream Snapshot Backup Interval Hours
-The interval between snapshot backups of the replica. Snapshot backups make a full copy of the database to a new litestream generation. This improves restore time at the expense of bandwidth. Applications with a large database and low write rate can increase this interval to reduce network usage for backups (litestream defaults to 24 hours).
+### Litestream Multipart Concurrency
-flag: `--litestream-snapshot-backup-interval-hours`
-env: `ZERO_LITESTREAM_SNAPSHOT_BACKUP_INTERVAL_HOURS`
-default: `12`
+The number of parts (of size --litestream-multipart-size bytes) to upload or download in parallel when backing up or restoring the snapshot.
+
+flag: `--litestream-multipart-concurrency`
+env: `ZERO_LITESTREAM_MULTIPART_CONCURRENCY`
+default: `48`
+
+### Litestream Multipart Size
+
+The size of each part when uploading or downloading the snapshot with
+`--litestream-multipart-concurrency`. Note that up to concurrency * size
+bytes of memory are used when backing up or restoring the snapshot.
+
+flag: `--litestream-multipart-size`
+env: `ZERO_LITESTREAM_MULTIPART_SIZE`
+default: `16777216` (16 MiB)
+
+### Litestream Log Level
+
+flag: `--litestream-log-level`
+env: `ZERO_LITESTREAM_LOG_LEVEL`
+default: `warn`
+values: `debug`, `info`, `warn`, `error`
+
+### Litestream Port
+
+Port on which litestream exports metrics, used to determine the replication
+watermark up to which it is safe to purge change log records.
+
+flag: `--litestream-port`
+env: `ZERO_LITESTREAM_PORT`
+default: `--port + 2`
### Litestream Restore Parallelism
@@ -249,6 +293,14 @@ flag: `--litestream-restore-parallelism`
env: `ZERO_LITESTREAM_RESTORE_PARALLELISM`
default: `48`
+### Litestream Snapshot Backup Interval Hours
+
+The interval between snapshot backups of the replica. Snapshot backups make a full copy of the database to a new litestream generation. This improves restore time at the expense of bandwidth. Applications with a large database and low write rate can increase this interval to reduce network usage for backups (litestream defaults to 24 hours).
+
+flag: `--litestream-snapshot-backup-interval-hours`
+env: `ZERO_LITESTREAM_SNAPSHOT_BACKUP_INTERVAL_HOURS`
+default: `12`
+
### Log Format
Use text for developer-friendly console logging and json for consumption by structured-logging services.
@@ -291,14 +343,6 @@ flag: `--log-slow-row-threshold`
env: `ZERO_LOG_SLOW_ROW_THRESHOLD`
default: `2`
-### Log Trace Collector
-
-The URL of the trace collector to which to send trace data. Traces are sent over http. Port defaults to 4318 for most collectors.
-
-flag: `--log-trace-collector`
-env: `ZERO_LOG_TRACE_COLLECTOR`
-required: `false`
-
### Number of Sync Workers
The number of processes to use for view syncing. Leave this unset to use the maximum available parallelism. If set to 0, the server runs without sync workers, which is the configuration for running the replication-manager.
@@ -331,9 +375,37 @@ flag: `--port`
env: `ZERO_PORT`
default: `4848`
+### Push API Key
+
+An optional secret used to authorize zero-cache to call the API server handling writes.
+
+flag: `--push-api-key`
+env: `ZERO_PUSH_API_KEY`
+required: `false`
+
+### Push Forward Cookies
+
+If true, zero-cache will forward cookies from the request. This is useful for passing authentication cookies to the API server. If false, cookies are not forwarded.
+
+flag: `--push-forward-cookies`
+env: `ZERO_PUSH_FORWARD_COOKIES`
+default: `false`
+
### Push URL
-The URL of the API server to which zero-cache will push mutations. Required if you use [custom mutators](/docs/custom-mutators).
+The URL of the API server to which zero-cache will push custom mutations.
+
+Can also be a pattern, or set of patterns, which is used in conjunction with the `push.url` paramter of the `Zero` constructor. In this case, the pattern specifies the URLs which Zero will allow the constructor to specify.
+
+Examples:
+
+* `https://*.example.com` matches `https://api.example.com` and `https://www.example.com`
+* `https://*.example.com` does not match `https://example.com` (no subdomain)
+* `https://*.example.com` does not match `https://api.example.com/path` (no trailing path)
+* `https://*.*.example.com` matches `https://api.v1.example.com` and `https://www.v2.example.com`
+* `https://*.*.example.com` does not match `https://api.example.com` (only one subdomain)
+
+Currently, wildcards are only allowed for subdomains.
flag: `--push-url`
env: `ZERO_PUSH_URL`
@@ -373,14 +445,6 @@ flag: `--storage-db-tmp-dir`
env: `ZERO_STORAGE_DB_TMP_DIR`
required: `false`
-### Target Client Row Count
-
-A soft limit on the number of rows Zero will keep on the client. 20k is a good default value for most applications, and we do not recommend exceeding 100k. See [Client Capacity Management](/docs/reading-data#client-capacity-management) for more details.
-
-flag: `--target-client-row-count`
-env: `ZERO_TARGET_CLIENT_ROW_COUNT`
-default: `20000`
-
### Task ID
Globally unique identifier for the zero-cache instance. Setting this to a platform specific task identifier can be useful for debugging. If unspecified, zero-cache will attempt to extract the TaskARN if run from within an AWS ECS container, and otherwise use a random string.
diff --git a/contents/docs/zero-schema.mdx b/contents/docs/zero-schema.mdx
index 2f2ef13d..e0670156 100644
--- a/contents/docs/zero-schema.mdx
+++ b/contents/docs/zero-schema.mdx
@@ -13,7 +13,7 @@ Zero applications have both a _database schema_ (the normal backend database sch
slug="generating"
heading="You do not need to define the Zero schema by hand"
>
- [Community-contributed converters](./community#database-tools) exist for
+ [Community-contributed converters](/docs/community#database-tools) exist for
Prisma and Drizzle that generate the tables and relationships. It is good to
know how the underlying Zero schemas work, however, for debugging and
conceptual understanding.
@@ -101,7 +101,7 @@ An optional column can store a value of the specified type or `null` to mean _no
### Enumerations
-Use the `enumeration` helper to define a column that can only take on a specific set of values. This is most often used alongside an [`enum` Postgres column type](postgres-support#column-types).
+Use the `enumeration` helper to define a column that can only take on a specific set of values. This is most often used alongside an [`enum` Postgres column type](/docs/postgres-support#column-types).
```tsx
import {table, string, enumeration} from '@rocicorp/zero';
@@ -164,7 +164,7 @@ const messageRelationships = relationships(message, ({one, many}) => ({
}));
```
-This creates "sender" and "replies" relationships that can later be queried with the [`related` ZQL clause](./reading-data#relationships):
+This creates "sender" and "replies" relationships that can later be queried with the [`related` ZQL clause](/docs/reading-data#relationships):
```ts
const messagesWithSenderAndReplies = z.query.messages
diff --git a/lib/generateSearchIndex.ts b/lib/generateSearchIndex.ts
index 6e0b13fb..c1fa3931 100644
--- a/lib/generateSearchIndex.ts
+++ b/lib/generateSearchIndex.ts
@@ -5,10 +5,9 @@ import remarkParse from 'remark-parse';
import remarkStringify from 'remark-stringify';
import {unified} from 'unified';
import {visit} from 'unist-util-visit';
-import {page_routes} from './routes-config';
-import {toString} from 'mdast-util-to-string';
-import {Root} from 'mdast';
+import {Nodes, Root} from 'mdast';
import strip from 'strip-markdown';
+import {getAllMDXFiles} from './get-slugs';
// Define the root directory where docs are stored
const DOCS_ROOT = path.join(process.cwd(), 'contents/docs');
@@ -23,37 +22,20 @@ interface SearchDocument {
headings: {text: string; id: string}[];
}
-/**
- * Recursively find all `index.mdx` files in subdirectories
- */
-function getAllMDXFiles(dir: string): string[] {
- let files: string[] = [];
-
- fs.readdirSync(dir, {withFileTypes: true}).forEach(entry => {
- const fullPath = path.join(dir, entry.name);
-
- if (entry.isDirectory()) {
- // If it's a directory, recurse into it
- files = files.concat(getAllMDXFiles(fullPath));
- } else if (entry.isFile() && entry.name.endsWith('.mdx')) {
- files.push(fullPath);
- }
- });
-
- return files;
-}
-
/**
* Extract headings with IDs from MDX content
*/
function extractHeadings(tree: Root): {text: string; id: string}[] {
const headings: {text: string; id: string}[] = [];
- visit(tree, 'heading', (node: any) => {
- const text = node.children
- .filter((child: any) => child.type === 'text')
- .map((child: any) => child.value)
- .join('');
+ visit(tree, 'heading', (node: Nodes) => {
+ const text =
+ 'children' in node
+ ? node.children
+ .filter((child: Nodes) => child.type === 'text')
+ .map((child: Nodes) => ('value' in child ? child.value : ''))
+ .join('')
+ : '';
// Extract the slug ID from the heading node
const id = text
@@ -97,13 +79,10 @@ async function extractTextFromMDX(filePath: string): Promise {
// Derive a URL from the file name
const pathWithoutExtension = path
.relative(DOCS_ROOT, filePath)
+ .replace(/\/index\.mdx$/, '')
.replace(/\.mdx$/, '');
const url = `/docs/${pathWithoutExtension}`;
- const route = page_routes.find(
- route => route.href && url.endsWith(route.href),
- );
-
const cleanedContent = plainText
.replace(/```.*$/gm, '')
.replace(/\n+/g, ' ')
@@ -114,7 +93,7 @@ async function extractTextFromMDX(filePath: string): Promise {
id: `${index++}-${pathWithoutExtension}`, // Use file name as ID
title: data.title || pathWithoutExtension, // Use frontmatter title or fallback to path
url,
- content: plainText.replace(/\n+/g, ' ').replace(/\s+/g, ' ').trim(),
+ content: cleanedContent,
headings, // Include extracted headings with IDs
};
}
@@ -132,5 +111,4 @@ async function generateSearchIndex() {
console.log(`β Search index generated: ${OUTPUT_FILE}`);
}
-// Run the script
generateSearchIndex().catch(console.error);
diff --git a/lib/get-slugs.ts b/lib/get-slugs.ts
new file mode 100644
index 00000000..510e4965
--- /dev/null
+++ b/lib/get-slugs.ts
@@ -0,0 +1,53 @@
+import path from 'path';
+import fs from 'fs';
+
+export type StaticParam = {slug: string[]};
+
+/**
+ * Returns all static params (slug arrays) for docs pages all files under `contents/docs/*.mdx`
+ */
+export const getAllPageSlugs = (): StaticParam[] => {
+ const DOCS_ROOT = path.join(process.cwd(), 'contents/docs');
+ const files = getAllMDXFiles(DOCS_ROOT);
+
+ const params: StaticParam[] = files
+ .map(fullPath => path.relative(DOCS_ROOT, fullPath))
+ .map(relPath => {
+ if (relPath.toLowerCase().endsWith('/index.mdx')) {
+ const withoutIndex = relPath.replace(/\/index\.mdx$/i, '');
+ const segments = withoutIndex === '' ? [] : withoutIndex.split('/');
+ return {slug: segments};
+ }
+ const withoutExt = relPath.replace(/\.mdx$/i, '');
+ return {slug: withoutExt.split('/')};
+ })
+ .filter(p => p.slug.length > 0);
+
+ const seen = new Set();
+ return params.filter(p => {
+ const key = p.slug.join('/');
+ if (seen.has(key)) return false;
+ seen.add(key);
+ return true;
+ });
+};
+
+/**
+ * Recursively find all `*.mdx` files in subdirectories
+ */
+export function getAllMDXFiles(dir: string): string[] {
+ let files: string[] = [];
+
+ fs.readdirSync(dir, {withFileTypes: true}).forEach(entry => {
+ const fullPath = path.join(dir, entry.name);
+
+ if (entry.isDirectory()) {
+ // If it's a directory, recurse into it
+ files = files.concat(getAllMDXFiles(fullPath));
+ } else if (entry.isFile() && entry.name.endsWith('.mdx')) {
+ files.push(fullPath);
+ }
+ });
+
+ return files;
+}
\ No newline at end of file
diff --git a/lib/icons.tsx b/lib/icons.tsx
index 525470fa..ffc298bf 100644
--- a/lib/icons.tsx
+++ b/lib/icons.tsx
@@ -17,7 +17,6 @@ import {
CopyIcon,
Database,
Eclipse,
- File,
FileCode,
KeyRound,
Link2,
diff --git a/lib/markdown.ts b/lib/markdown.ts
index 02ae5714..3dcc7e85 100644
--- a/lib/markdown.ts
+++ b/lib/markdown.ts
@@ -58,28 +58,35 @@ export async function getDocsForSlug(slug: string) {
return await parseMdx(rawMdx);
} catch (err) {
console.error(`Error fetching docs for slug "${slug}":`, err);
- throw err;
+ return null;
}
}
// Generate a Table of Contents (TOC) from markdown headings
export async function getDocsTocs(slug: string) {
- const contentPath = await getDocsContentPath(slug);
- const rawMdx = await fs.readFile(contentPath, 'utf-8');
- const headingsRegex = /^(#{2,4})\s(.+)$/gm; // Matches headings ## to ####
- let match;
- const extractedHeadings = [];
- while ((match = headingsRegex.exec(rawMdx)) !== null) {
- const headingLevel = match[1].length;
- const headingText = match[2].trim();
- const slug = sluggify(headingText);
- extractedHeadings.push({
- level: headingLevel,
- text: headingText,
- href: `#${slug}`, // Create anchor links
- });
+ let rawMdx: string;
+ try {
+ const contentPath = await getDocsContentPath(slug);
+ rawMdx = await fs.readFile(contentPath, 'utf-8');
+
+ const headingsRegex = /^(#{2,4})\s(.+)$/gm; // Matches headings ## to ####
+ let match;
+ const extractedHeadings = [];
+ while ((match = headingsRegex.exec(rawMdx)) !== null) {
+ const headingLevel = match[1].length;
+ const headingText = match[2].trim();
+ const slug = sluggify(headingText);
+ extractedHeadings.push({
+ level: headingLevel,
+ text: headingText,
+ href: `#${slug}`, // Create anchor links
+ });
+ }
+ return extractedHeadings;
+ } catch (err) {
+ console.error(`Error fetching docs for slug "${slug}":`, err);
+ return [];
}
- return extractedHeadings;
}
export function getPreviousNext(path: string): {
diff --git a/lib/routes-config.ts b/lib/routes-config.ts
index cb7b2d01..1e7980e6 100644
--- a/lib/routes-config.ts
+++ b/lib/routes-config.ts
@@ -1,7 +1,5 @@
// for page navigation & to sort on leftbar
-import {IconKey} from './icons';
-
export type EachRoute = {
title: string;
href: string | null;
diff --git a/package-lock.json b/package-lock.json
index 4414222d..7e074295 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8,57 +8,58 @@
"name": "aria-docs",
"version": "1.0.0",
"dependencies": {
- "@radix-ui/react-collapsible": "^1.1.0",
- "@radix-ui/react-dialog": "^1.1.1",
- "@radix-ui/react-dropdown-menu": "^2.1.1",
- "@radix-ui/react-scroll-area": "^1.1.0",
- "@radix-ui/react-slot": "^1.1.0",
+ "@radix-ui/react-collapsible": "^1.1.11",
+ "@radix-ui/react-dialog": "^1.1.14",
+ "@radix-ui/react-dropdown-menu": "^2.1.15",
+ "@radix-ui/react-scroll-area": "^1.2.9",
+ "@radix-ui/react-slot": "^1.2.3",
"@radix-ui/react-tooltip": "^1.2.7",
+ "@vercel/og": "^0.8.5",
"broken-link-checker": "^0.7.8",
- "class-variance-authority": "^0.7.0",
+ "class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cmdk": "^1.1.1",
"gray-matter": "^4.0.3",
- "lucide-react": "^0.435.0",
+ "lucide-react": "^0.537.0",
"lunr": "^2.3.9",
"mdast-util-to-string": "^4.0.0",
- "next": "^14.2.6",
+ "next": "^15.4.6",
"next-mdx-remote": "^5.0.0",
- "next-themes": "^0.3.0",
- "react": "^18.3.1",
- "react-dom": "^18.3.1",
+ "next-themes": "^0.4.6",
+ "react": "^19.1.1",
+ "react-dom": "^19.1.1",
"react-hotkeys-hook": "^5.1.0",
"rehype-autolink-headings": "^7.1.0",
"rehype-code-titles": "^1.2.0",
- "rehype-prism-plus": "^2.0.0",
+ "rehype-prism-plus": "^2.0.1",
"rehype-slug": "^6.0.0",
"remark": "^15.0.1",
- "remark-gfm": "^4.0.0",
+ "remark-gfm": "^4.0.1",
"remark-parse": "^11.0.0",
"remark-stringify": "^11.0.0",
"strip-markdown": "^6.0.0",
- "tailwind-merge": "^2.5.2",
+ "tailwind-merge": "^3.3.1",
"tailwindcss-animate": "^1.0.7",
"unist-util-visit": "^5.0.0"
},
"devDependencies": {
"@rocicorp/prettier-config": "^0.3.0",
- "@tailwindcss/typography": "^0.5.14",
+ "@tailwindcss/typography": "^0.5.16",
"@types/hast": "^3.0.4",
"@types/lunr": "^2.3.7",
- "@types/node": "^20.17.19",
- "@types/react": "^18",
- "@types/react-dom": "^18",
+ "@types/node": "^24.2.0",
+ "@types/react": "^19",
+ "@types/react-dom": "^19",
"@types/unist": "^3.0.3",
- "autoprefixer": "^10.4.20",
- "eslint": "^8",
- "eslint-config-next": "^14.2.6",
- "highlight.js": "^11.10.0",
+ "autoprefixer": "^10.4.21",
+ "eslint": "^9",
+ "eslint-config-next": "^15.4.6",
+ "highlight.js": "^11.11.1",
"postcss": "^8",
"react-highlight": "^0.15.0",
"tailwindcss": "^3.4.10",
"ts-node": "^10.9.2",
- "tsx": "^4.19.3",
+ "tsx": "^4.20.3",
"typescript": "^5"
}
},
@@ -75,6 +76,7 @@
"version": "5.2.0",
"resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz",
"integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==",
+ "license": "MIT",
"engines": {
"node": ">=10"
},
@@ -180,19 +182,6 @@
"node": ">=4"
}
},
- "node_modules/@babel/runtime": {
- "version": "7.27.0",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz",
- "integrity": "sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "regenerator-runtime": "^0.14.0"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
"node_modules/@cspotcode/source-map-support": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
@@ -217,6 +206,39 @@
"@jridgewell/sourcemap-codec": "^1.4.10"
}
},
+ "node_modules/@emnapi/core": {
+ "version": "1.4.5",
+ "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.4.5.tgz",
+ "integrity": "sha512-XsLw1dEOpkSX/WucdqUhPWP7hDxSvZiY+fsUC14h+FtQ2Ifni4znbBt8punRX+Uj2JG/uDb8nEHVKvrVlvdZ5Q==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "@emnapi/wasi-threads": "1.0.4",
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@emnapi/runtime": {
+ "version": "1.4.5",
+ "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.5.tgz",
+ "integrity": "sha512-++LApOtY0pEEz1zrd9vy1/zXVaVJJ/EbAF3u0fXIzPJEDtnITsBGbbK0EkM72amhl/R5b+5xx0Y/QhcVOpuulg==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@emnapi/wasi-threads": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.0.4.tgz",
+ "integrity": "sha512-PJR+bOmMOPH8AtcTGAyYNiuJ3/Fcoj2XN/gBEWzDIKh254XO+mM9XoXHk5GNEhodxeMznbg7BlRojVbKN+gC6g==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
"node_modules/@esbuild/aix-ppc64": {
"version": "0.25.0",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz",
@@ -643,39 +665,83 @@
}
},
"node_modules/@eslint-community/eslint-utils": {
- "version": "4.4.0",
- "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
- "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==",
+ "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.3.0"
+ "eslint-visitor-keys": "^3.4.3"
},
"engines": {
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
},
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ },
"peerDependencies": {
"eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
}
},
"node_modules/@eslint-community/regexpp": {
- "version": "4.10.0",
- "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz",
- "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==",
+ "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.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.6",
+ "debug": "^4.3.1",
+ "minimatch": "^3.1.2"
+ },
+ "engines": {
+ "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.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": "2.1.4",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz",
- "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==",
+ "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",
- "espree": "^9.6.0",
- "globals": "^13.19.0",
+ "espree": "^10.0.1",
+ "globals": "^14.0.0",
"ignore": "^5.2.0",
"import-fresh": "^3.2.1",
"js-yaml": "^4.1.0",
@@ -683,44 +749,75 @@
"strip-json-comments": "^3.1.1"
},
"engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/@eslint/js": {
- "version": "8.57.0",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz",
- "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==",
+ "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": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://eslint.org/donate"
+ }
+ },
+ "node_modules/@eslint/object-schema": {
+ "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.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": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
"node_modules/@floating-ui/core": {
- "version": "1.6.7",
- "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.7.tgz",
- "integrity": "sha512-yDzVT/Lm101nQ5TCVeK65LtdN7Tj4Qpr9RTXJ2vPFLqtLxwOrpoxAHAJI8J3yYWUc40J0BDBheaitK5SJmno2g==",
+ "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.7"
+ "@floating-ui/utils": "^0.2.10"
}
},
"node_modules/@floating-ui/dom": {
- "version": "1.6.10",
- "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.10.tgz",
- "integrity": "sha512-fskgCFv8J8OamCmyun8MfjB1Olfn+uZKjOKZ0vhYF3gRmEUXcGOjxWL8bBr7i4kIuPZ2KD2S3EUIOxnjC8kl2A==",
+ "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.6.0",
- "@floating-ui/utils": "^0.2.7"
+ "@floating-ui/core": "^1.7.3",
+ "@floating-ui/utils": "^0.2.10"
}
},
"node_modules/@floating-ui/react-dom": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.1.tgz",
- "integrity": "sha512-4h84MJt3CHrtG18mGsXuLCHMrug49d7DFkU0RMIyshRveBeyV2hmV/pDaF2Uxtu8kgq5r46llp5E5FQiR0K2Yg==",
+ "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.0.0"
+ "@floating-ui/dom": "^1.7.3"
},
"peerDependencies": {
"react": ">=16.8.0",
@@ -728,22 +825,47 @@
}
},
"node_modules/@floating-ui/utils": {
- "version": "0.2.7",
- "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.7.tgz",
- "integrity": "sha512-X8R8Oj771YRl/w+c1HqAC1szL8zWQRwFvgDwT129k9ACdBoud/+/rX9V0qiMl6LWUdP9voC2nDVZYPMQQsb6eA=="
+ "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",
+ "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">=18.18.0"
+ }
},
- "node_modules/@humanwhocodes/config-array": {
- "version": "0.11.14",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
- "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==",
+ "node_modules/@humanfs/node": {
+ "version": "0.16.6",
+ "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz",
+ "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==",
"dev": true,
+ "license": "Apache-2.0",
"dependencies": {
- "@humanwhocodes/object-schema": "^2.0.2",
- "debug": "^4.3.1",
- "minimatch": "^3.0.5"
+ "@humanfs/core": "^0.19.1",
+ "@humanwhocodes/retry": "^0.3.0"
},
"engines": {
- "node": ">=10.10.0"
+ "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": {
@@ -759,1021 +881,770 @@
"url": "https://github.com/sponsors/nzakas"
}
},
- "node_modules/@humanwhocodes/object-schema": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
- "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
- "dev": true
- },
- "node_modules/@isaacs/cliui": {
- "version": "8.0.2",
- "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
- "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
- "dependencies": {
- "string-width": "^5.1.2",
- "string-width-cjs": "npm:string-width@^4.2.0",
- "strip-ansi": "^7.0.1",
- "strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
- "wrap-ansi": "^8.1.0",
- "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
- },
- "engines": {
- "node": ">=12"
- }
- },
- "node_modules/@isaacs/cliui/node_modules/ansi-regex": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
- "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
+ "node_modules/@humanwhocodes/retry": {
+ "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": ">=12"
+ "node": ">=18.18"
},
"funding": {
- "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+ "type": "github",
+ "url": "https://github.com/sponsors/nzakas"
}
},
- "node_modules/@isaacs/cliui/node_modules/strip-ansi": {
- "version": "7.1.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
- "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
- "dependencies": {
- "ansi-regex": "^6.0.1"
- },
+ "node_modules/@img/sharp-darwin-arm64": {
+ "version": "0.34.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.3.tgz",
+ "integrity": "sha512-ryFMfvxxpQRsgZJqBd4wsttYQbCxsJksrv9Lw/v798JcQ8+w84mBWuXwl+TT0WJ/WrYOLaYpwQXi3sA9nTIaIg==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
"engines": {
- "node": ">=12"
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
- "url": "https://github.com/chalk/strip-ansi?sponsor=1"
- }
- },
- "node_modules/@jridgewell/gen-mapping": {
- "version": "0.3.5",
- "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
- "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
- "dependencies": {
- "@jridgewell/set-array": "^1.2.1",
- "@jridgewell/sourcemap-codec": "^1.4.10",
- "@jridgewell/trace-mapping": "^0.3.24"
+ "url": "https://opencollective.com/libvips"
},
- "engines": {
- "node": ">=6.0.0"
- }
- },
- "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==",
- "engines": {
- "node": ">=6.0.0"
+ "optionalDependencies": {
+ "@img/sharp-libvips-darwin-arm64": "1.2.0"
}
},
- "node_modules/@jridgewell/set-array": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
- "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
+ "node_modules/@img/sharp-darwin-x64": {
+ "version": "0.34.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.3.tgz",
+ "integrity": "sha512-yHpJYynROAj12TA6qil58hmPmAwxKKC7reUqtGLzsOHfP7/rniNGTL8tjWX6L3CTV4+5P4ypcS7Pp+7OB+8ihA==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
"engines": {
- "node": ">=6.0.0"
- }
- },
- "node_modules/@jridgewell/sourcemap-codec": {
- "version": "1.4.15",
- "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
- "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
- },
- "node_modules/@jridgewell/trace-mapping": {
- "version": "0.3.25",
- "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
- "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
- "dependencies": {
- "@jridgewell/resolve-uri": "^3.1.0",
- "@jridgewell/sourcemap-codec": "^1.4.14"
- }
- },
- "node_modules/@mdx-js/mdx": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-3.0.1.tgz",
- "integrity": "sha512-eIQ4QTrOWyL3LWEe/bu6Taqzq2HQvHcyTMaOrI95P2/LmJE7AsfPfgJGuFLPVqBUE1BC1rik3VIhU+s9u72arA==",
- "dependencies": {
- "@types/estree": "^1.0.0",
- "@types/estree-jsx": "^1.0.0",
- "@types/hast": "^3.0.0",
- "@types/mdx": "^2.0.0",
- "collapse-white-space": "^2.0.0",
- "devlop": "^1.0.0",
- "estree-util-build-jsx": "^3.0.0",
- "estree-util-is-identifier-name": "^3.0.0",
- "estree-util-to-js": "^2.0.0",
- "estree-walker": "^3.0.0",
- "hast-util-to-estree": "^3.0.0",
- "hast-util-to-jsx-runtime": "^2.0.0",
- "markdown-extensions": "^2.0.0",
- "periscopic": "^3.0.0",
- "remark-mdx": "^3.0.0",
- "remark-parse": "^11.0.0",
- "remark-rehype": "^11.0.0",
- "source-map": "^0.7.0",
- "unified": "^11.0.0",
- "unist-util-position-from-estree": "^2.0.0",
- "unist-util-stringify-position": "^4.0.0",
- "unist-util-visit": "^5.0.0",
- "vfile": "^6.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
- "node_modules/@mdx-js/react": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.0.1.tgz",
- "integrity": "sha512-9ZrPIU4MGf6et1m1ov3zKf+q9+deetI51zprKB1D/z3NOb+rUxxtEl3mCjW5wTGh6VhRdwPueh1oRzi6ezkA8A==",
- "dependencies": {
- "@types/mdx": "^2.0.0"
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
+ "url": "https://opencollective.com/libvips"
},
- "peerDependencies": {
- "@types/react": ">=16",
- "react": ">=16"
- }
- },
- "node_modules/@next/env": {
- "version": "14.2.26",
- "resolved": "https://registry.npmjs.org/@next/env/-/env-14.2.26.tgz",
- "integrity": "sha512-vO//GJ/YBco+H7xdQhzJxF7ub3SUwft76jwaeOyVVQFHCi5DCnkP16WHB+JBylo4vOKPoZBlR94Z8xBxNBdNJA==",
- "license": "MIT"
- },
- "node_modules/@next/eslint-plugin-next": {
- "version": "14.2.6",
- "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-14.2.6.tgz",
- "integrity": "sha512-d3+p4AjIYmhqzYHhhmkRYYN6ZU35TwZAKX08xKRfnHkz72KhWL2kxMFsDptpZs5e8bBGdepn7vn1+9DaF8iX+A==",
- "dev": true,
- "dependencies": {
- "glob": "10.3.10"
+ "optionalDependencies": {
+ "@img/sharp-libvips-darwin-x64": "1.2.0"
}
},
- "node_modules/@next/swc-darwin-arm64": {
- "version": "14.2.26",
- "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-14.2.26.tgz",
- "integrity": "sha512-zDJY8gsKEseGAxG+C2hTMT0w9Nk9N1Sk1qV7vXYz9MEiyRoF5ogQX2+vplyUMIfygnjn9/A04I6yrUTRTuRiyQ==",
+ "node_modules/@img/sharp-libvips-darwin-arm64": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.2.0.tgz",
+ "integrity": "sha512-sBZmpwmxqwlqG9ueWFXtockhsxefaV6O84BMOrhtg/YqbTaRdqDE7hxraVE3y6gVM4eExmfzW4a8el9ArLeEiQ==",
"cpu": [
"arm64"
],
- "license": "MIT",
+ "license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"darwin"
],
- "engines": {
- "node": ">= 10"
+ "funding": {
+ "url": "https://opencollective.com/libvips"
}
},
- "node_modules/@next/swc-darwin-x64": {
- "version": "14.2.26",
- "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-14.2.26.tgz",
- "integrity": "sha512-U0adH5ryLfmTDkahLwG9sUQG2L0a9rYux8crQeC92rPhi3jGQEY47nByQHrVrt3prZigadwj/2HZ1LUUimuSbg==",
+ "node_modules/@img/sharp-libvips-darwin-x64": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.2.0.tgz",
+ "integrity": "sha512-M64XVuL94OgiNHa5/m2YvEQI5q2cl9d/wk0qFTDVXcYzi43lxuiFTftMR1tOnFQovVXNZJ5TURSDK2pNe9Yzqg==",
"cpu": [
"x64"
],
- "license": "MIT",
+ "license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"darwin"
],
- "engines": {
- "node": ">= 10"
+ "funding": {
+ "url": "https://opencollective.com/libvips"
}
},
- "node_modules/@next/swc-linux-arm64-gnu": {
- "version": "14.2.26",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-14.2.26.tgz",
- "integrity": "sha512-SINMl1I7UhfHGM7SoRiw0AbwnLEMUnJ/3XXVmhyptzriHbWvPPbbm0OEVG24uUKhuS1t0nvN/DBvm5kz6ZIqpg==",
+ "node_modules/@img/sharp-libvips-linux-arm": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.2.0.tgz",
+ "integrity": "sha512-mWd2uWvDtL/nvIzThLq3fr2nnGfyr/XMXlq8ZJ9WMR6PXijHlC3ksp0IpuhK6bougvQrchUAfzRLnbsen0Cqvw==",
"cpu": [
- "arm64"
+ "arm"
],
- "license": "MIT",
+ "license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"linux"
],
- "engines": {
- "node": ">= 10"
+ "funding": {
+ "url": "https://opencollective.com/libvips"
}
},
- "node_modules/@next/swc-linux-arm64-musl": {
- "version": "14.2.26",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-14.2.26.tgz",
- "integrity": "sha512-s6JaezoyJK2DxrwHWxLWtJKlqKqTdi/zaYigDXUJ/gmx/72CrzdVZfMvUc6VqnZ7YEvRijvYo+0o4Z9DencduA==",
+ "node_modules/@img/sharp-libvips-linux-arm64": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.2.0.tgz",
+ "integrity": "sha512-RXwd0CgG+uPRX5YYrkzKyalt2OJYRiJQ8ED/fi1tq9WQW2jsQIn0tqrlR5l5dr/rjqq6AHAxURhj2DVjyQWSOA==",
"cpu": [
"arm64"
],
- "license": "MIT",
+ "license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"linux"
],
- "engines": {
- "node": ">= 10"
+ "funding": {
+ "url": "https://opencollective.com/libvips"
}
},
- "node_modules/@next/swc-linux-x64-gnu": {
- "version": "14.2.26",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-14.2.26.tgz",
- "integrity": "sha512-FEXeUQi8/pLr/XI0hKbe0tgbLmHFRhgXOUiPScz2hk0hSmbGiU8aUqVslj/6C6KA38RzXnWoJXo4FMo6aBxjzg==",
+ "node_modules/@img/sharp-libvips-linux-ppc64": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.2.0.tgz",
+ "integrity": "sha512-Xod/7KaDDHkYu2phxxfeEPXfVXFKx70EAFZ0qyUdOjCcxbjqyJOEUpDe6RIyaunGxT34Anf9ue/wuWOqBW2WcQ==",
"cpu": [
- "x64"
+ "ppc64"
],
- "license": "MIT",
+ "license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"linux"
],
- "engines": {
- "node": ">= 10"
+ "funding": {
+ "url": "https://opencollective.com/libvips"
}
},
- "node_modules/@next/swc-linux-x64-musl": {
- "version": "14.2.26",
- "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-14.2.26.tgz",
- "integrity": "sha512-BUsomaO4d2DuXhXhgQCVt2jjX4B4/Thts8nDoIruEJkhE5ifeQFtvW5c9JkdOtYvE5p2G0hcwQ0UbRaQmQwaVg==",
+ "node_modules/@img/sharp-libvips-linux-s390x": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.2.0.tgz",
+ "integrity": "sha512-eMKfzDxLGT8mnmPJTNMcjfO33fLiTDsrMlUVcp6b96ETbnJmd4uvZxVJSKPQfS+odwfVaGifhsB07J1LynFehw==",
+ "cpu": [
+ "s390x"
+ ],
+ "license": "LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ }
+ },
+ "node_modules/@img/sharp-libvips-linux-x64": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.2.0.tgz",
+ "integrity": "sha512-ZW3FPWIc7K1sH9E3nxIGB3y3dZkpJlMnkk7z5tu1nSkBoCgw2nSRTFHI5pB/3CQaJM0pdzMF3paf9ckKMSE9Tg==",
"cpu": [
"x64"
],
- "license": "MIT",
+ "license": "LGPL-3.0-or-later",
"optional": true,
"os": [
"linux"
],
- "engines": {
- "node": ">= 10"
+ "funding": {
+ "url": "https://opencollective.com/libvips"
}
},
- "node_modules/@next/swc-win32-arm64-msvc": {
- "version": "14.2.26",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-14.2.26.tgz",
- "integrity": "sha512-5auwsMVzT7wbB2CZXQxDctpWbdEnEW/e66DyXO1DcgHxIyhP06awu+rHKshZE+lPLIGiwtjo7bsyeuubewwxMw==",
+ "node_modules/@img/sharp-libvips-linuxmusl-arm64": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.2.0.tgz",
+ "integrity": "sha512-UG+LqQJbf5VJ8NWJ5Z3tdIe/HXjuIdo4JeVNADXBFuG7z9zjoegpzzGIyV5zQKi4zaJjnAd2+g2nna8TZvuW9Q==",
"cpu": [
"arm64"
],
- "license": "MIT",
+ "license": "LGPL-3.0-or-later",
"optional": true,
"os": [
- "win32"
+ "linux"
],
- "engines": {
- "node": ">= 10"
+ "funding": {
+ "url": "https://opencollective.com/libvips"
}
},
- "node_modules/@next/swc-win32-ia32-msvc": {
- "version": "14.2.26",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-14.2.26.tgz",
- "integrity": "sha512-GQWg/Vbz9zUGi9X80lOeGsz1rMH/MtFO/XqigDznhhhTfDlDoynCM6982mPCbSlxJ/aveZcKtTlwfAjwhyxDpg==",
+ "node_modules/@img/sharp-libvips-linuxmusl-x64": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.2.0.tgz",
+ "integrity": "sha512-SRYOLR7CXPgNze8akZwjoGBoN1ThNZoqpOgfnOxmWsklTGVfJiGJoC/Lod7aNMGA1jSsKWM1+HRX43OP6p9+6Q==",
"cpu": [
- "ia32"
+ "x64"
],
- "license": "MIT",
+ "license": "LGPL-3.0-or-later",
"optional": true,
"os": [
- "win32"
+ "linux"
],
- "engines": {
- "node": ">= 10"
+ "funding": {
+ "url": "https://opencollective.com/libvips"
}
},
- "node_modules/@next/swc-win32-x64-msvc": {
- "version": "14.2.26",
- "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-14.2.26.tgz",
- "integrity": "sha512-2rdB3T1/Gp7bv1eQTTm9d1Y1sv9UuJ2LAwOE0Pe2prHKe32UNscj7YS13fRB37d0GAiGNR+Y7ZcW8YjDI8Ns0w==",
+ "node_modules/@img/sharp-linux-arm": {
+ "version": "0.34.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.3.tgz",
+ "integrity": "sha512-oBK9l+h6KBN0i3dC8rYntLiVfW8D8wH+NPNT3O/WBHeW0OQWCjfWksLUaPidsrDKpJgXp3G3/hkmhptAW0I3+A==",
"cpu": [
- "x64"
+ "arm"
],
- "license": "MIT",
+ "license": "Apache-2.0",
"optional": true,
"os": [
- "win32"
+ "linux"
],
"engines": {
- "node": ">= 10"
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-arm": "1.2.0"
}
},
- "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==",
- "dependencies": {
- "@nodelib/fs.stat": "2.0.5",
- "run-parallel": "^1.1.9"
- },
+ "node_modules/@img/sharp-linux-arm64": {
+ "version": "0.34.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.3.tgz",
+ "integrity": "sha512-QdrKe3EvQrqwkDrtuTIjI0bu6YEJHTgEeqdzI3uWJOH6G1O8Nl1iEeVYRGdj1h5I21CqxSvQp1Yv7xeU3ZewbA==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
"engines": {
- "node": ">= 8"
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-arm64": "1.2.0"
}
},
- "node_modules/@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==",
+ "node_modules/@img/sharp-linux-ppc64": {
+ "version": "0.34.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.34.3.tgz",
+ "integrity": "sha512-GLtbLQMCNC5nxuImPR2+RgrviwKwVql28FWZIW1zWruy6zLgA5/x2ZXk3mxj58X/tszVF69KK0Is83V8YgWhLA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
"engines": {
- "node": ">= 8"
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-ppc64": "1.2.0"
}
},
- "node_modules/@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==",
- "dependencies": {
- "@nodelib/fs.scandir": "2.1.5",
- "fastq": "^1.6.0"
- },
+ "node_modules/@img/sharp-linux-s390x": {
+ "version": "0.34.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.3.tgz",
+ "integrity": "sha512-3gahT+A6c4cdc2edhsLHmIOXMb17ltffJlxR0aC2VPZfwKoTGZec6u5GrFgdR7ciJSsHT27BD3TIuGcuRT0KmQ==",
+ "cpu": [
+ "s390x"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
"engines": {
- "node": ">= 8"
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-s390x": "1.2.0"
}
},
- "node_modules/@pkgjs/parseargs": {
- "version": "0.11.0",
- "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
- "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
+ "node_modules/@img/sharp-linux-x64": {
+ "version": "0.34.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.3.tgz",
+ "integrity": "sha512-8kYso8d806ypnSq3/Ly0QEw90V5ZoHh10yH0HnrzOCr6DKAPI6QVHvwleqMkVQ0m+fc7EH8ah0BB0QPuWY6zJQ==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "Apache-2.0",
"optional": true,
+ "os": [
+ "linux"
+ ],
"engines": {
- "node": ">=14"
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-libvips-linux-x64": "1.2.0"
}
},
- "node_modules/@radix-ui/number": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.0.tgz",
- "integrity": "sha512-V3gRzhVNU1ldS5XhAPTom1fOIo4ccrjjJgmE+LI2h/WaFpHmx0MQApT+KZHnx8abG6Avtfcz4WoEciMnpFT3HQ=="
- },
- "node_modules/@radix-ui/primitive": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.0.tgz",
- "integrity": "sha512-4Z8dn6Upk0qk4P74xBhZ6Hd/w0mPEzOOLxy4xiPXOXqjF7jZS0VAKk7/x/H6FyY2zCkYJqePf1G5KmkmNJ4RBA=="
- },
- "node_modules/@radix-ui/react-arrow": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.0.tgz",
- "integrity": "sha512-FmlW1rCg7hBpEBwFbjHwCW6AmWLQM6g/v0Sn8XbP9NvmSZ2San1FpQeyPtufzOMSIx7Y4dzjlHoifhp+7NkZhw==",
- "dependencies": {
- "@radix-ui/react-primitive": "2.0.0"
+ "node_modules/@img/sharp-linuxmusl-arm64": {
+ "version": "0.34.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.3.tgz",
+ "integrity": "sha512-vAjbHDlr4izEiXM1OTggpCcPg9tn4YriK5vAjowJsHwdBIdx0fYRsURkxLG2RLm9gyBq66gwtWI8Gx0/ov+JKQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
- "peerDependencies": {
- "@types/react": "*",
- "@types/react-dom": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
- "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ "funding": {
+ "url": "https://opencollective.com/libvips"
},
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- },
- "@types/react-dom": {
- "optional": true
- }
+ "optionalDependencies": {
+ "@img/sharp-libvips-linuxmusl-arm64": "1.2.0"
}
},
- "node_modules/@radix-ui/react-collapsible": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.0.tgz",
- "integrity": "sha512-zQY7Epa8sTL0mq4ajSJpjgn2YmCgyrG7RsQgLp3C0LQVkG7+Tf6Pv1CeNWZLyqMjhdPkBa5Lx7wYBeSu7uCSTA==",
- "dependencies": {
- "@radix-ui/primitive": "1.1.0",
- "@radix-ui/react-compose-refs": "1.1.0",
- "@radix-ui/react-context": "1.1.0",
- "@radix-ui/react-id": "1.1.0",
- "@radix-ui/react-presence": "1.1.0",
- "@radix-ui/react-primitive": "2.0.0",
- "@radix-ui/react-use-controllable-state": "1.1.0",
- "@radix-ui/react-use-layout-effect": "1.1.0"
+ "node_modules/@img/sharp-linuxmusl-x64": {
+ "version": "0.34.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.3.tgz",
+ "integrity": "sha512-gCWUn9547K5bwvOn9l5XGAEjVTTRji4aPTqLzGXHvIr6bIDZKNTA34seMPgM0WmSf+RYBH411VavCejp3PkOeQ==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
- "peerDependencies": {
- "@types/react": "*",
- "@types/react-dom": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
- "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ "funding": {
+ "url": "https://opencollective.com/libvips"
},
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- },
- "@types/react-dom": {
- "optional": true
- }
+ "optionalDependencies": {
+ "@img/sharp-libvips-linuxmusl-x64": "1.2.0"
}
},
- "node_modules/@radix-ui/react-collection": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.0.tgz",
- "integrity": "sha512-GZsZslMJEyo1VKm5L1ZJY8tGDxZNPAoUeQUIbKeJfoi7Q4kmig5AsgLMYYuyYbfjd8fBmFORAIwYAkXMnXZgZw==",
+ "node_modules/@img/sharp-wasm32": {
+ "version": "0.34.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.3.tgz",
+ "integrity": "sha512-+CyRcpagHMGteySaWos8IbnXcHgfDn7pO2fiC2slJxvNq9gDipYBN42/RagzctVRKgxATmfqOSulgZv5e1RdMg==",
+ "cpu": [
+ "wasm32"
+ ],
+ "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT",
+ "optional": true,
"dependencies": {
- "@radix-ui/react-compose-refs": "1.1.0",
- "@radix-ui/react-context": "1.1.0",
- "@radix-ui/react-primitive": "2.0.0",
- "@radix-ui/react-slot": "1.1.0"
+ "@emnapi/runtime": "^1.4.4"
},
- "peerDependencies": {
- "@types/react": "*",
- "@types/react-dom": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
- "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- },
- "@types/react-dom": {
- "optional": true
- }
+ "funding": {
+ "url": "https://opencollective.com/libvips"
}
},
- "node_modules/@radix-ui/react-compose-refs": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.0.tgz",
- "integrity": "sha512-b4inOtiaOnYf9KWyO3jAeeCG6FeyfY6ldiEPanbUjWd+xIk5wZeHa8yVwmrJ2vderhu/BQvzCrJI0lHd+wIiqw==",
- "peerDependencies": {
- "@types/react": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ "node_modules/@img/sharp-win32-arm64": {
+ "version": "0.34.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.34.3.tgz",
+ "integrity": "sha512-MjnHPnbqMXNC2UgeLJtX4XqoVHHlZNd+nPt1kRPmj63wURegwBhZlApELdtxM2OIZDRv/DFtLcNhVbd1z8GYXQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "Apache-2.0 AND LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- }
+ "funding": {
+ "url": "https://opencollective.com/libvips"
}
},
- "node_modules/@radix-ui/react-context": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.0.tgz",
- "integrity": "sha512-OKrckBy+sMEgYM/sMmqmErVn0kZqrHPJze+Ql3DzYsDDp0hl0L62nx/2122/Bvps1qz645jlcu2tD9lrRSdf8A==",
- "peerDependencies": {
- "@types/react": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ "node_modules/@img/sharp-win32-ia32": {
+ "version": "0.34.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.3.tgz",
+ "integrity": "sha512-xuCdhH44WxuXgOM714hn4amodJMZl3OEvf0GVTm0BEyMeA2to+8HEdRPShH0SLYptJY1uBw+SCFP9WVQi1Q/cw==",
+ "cpu": [
+ "ia32"
+ ],
+ "license": "Apache-2.0 AND LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- }
+ "funding": {
+ "url": "https://opencollective.com/libvips"
}
},
- "node_modules/@radix-ui/react-dialog": {
- "version": "1.1.14",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.14.tgz",
- "integrity": "sha512-+CpweKjqpzTmwRwcYECQcNYbI8V9VSQt0SNFKeEBLgfucbsLssU6Ppq7wUdNXEGb573bMjFhVjKVll8rmV6zMw==",
- "license": "MIT",
- "dependencies": {
- "@radix-ui/primitive": "1.1.2",
- "@radix-ui/react-compose-refs": "1.1.2",
- "@radix-ui/react-context": "1.1.2",
- "@radix-ui/react-dismissable-layer": "1.1.10",
- "@radix-ui/react-focus-guards": "1.1.2",
- "@radix-ui/react-focus-scope": "1.1.7",
- "@radix-ui/react-id": "1.1.1",
- "@radix-ui/react-portal": "1.1.9",
- "@radix-ui/react-presence": "1.1.4",
- "@radix-ui/react-primitive": "2.1.3",
- "@radix-ui/react-slot": "1.2.3",
- "@radix-ui/react-use-controllable-state": "1.2.2",
- "aria-hidden": "^1.2.4",
- "react-remove-scroll": "^2.6.3"
+ "node_modules/@img/sharp-win32-x64": {
+ "version": "0.34.3",
+ "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.3.tgz",
+ "integrity": "sha512-OWwz05d++TxzLEv4VnsTz5CmZ6mI6S05sfQGEMrNrQcOEERbX46332IvE7pO/EUiw7jUrrS40z/M7kPyjfl04g==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "Apache-2.0 AND LGPL-3.0-or-later",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
- "peerDependencies": {
- "@types/react": "*",
- "@types/react-dom": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
- "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- },
- "@types/react-dom": {
- "optional": true
- }
- }
- },
- "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/primitive": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.2.tgz",
- "integrity": "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA==",
- "license": "MIT"
- },
- "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-compose-refs": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
- "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==",
- "license": "MIT",
- "peerDependencies": {
- "@types/react": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- }
+ "funding": {
+ "url": "https://opencollective.com/libvips"
}
},
- "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-context": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz",
- "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==",
- "license": "MIT",
- "peerDependencies": {
- "@types/react": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ "node_modules/@isaacs/cliui": {
+ "version": "8.0.2",
+ "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
+ "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==",
+ "license": "ISC",
+ "dependencies": {
+ "string-width": "^5.1.2",
+ "string-width-cjs": "npm:string-width@^4.2.0",
+ "strip-ansi": "^7.0.1",
+ "strip-ansi-cjs": "npm:strip-ansi@^6.0.1",
+ "wrap-ansi": "^8.1.0",
+ "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0"
},
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- }
+ "engines": {
+ "node": ">=12"
}
},
- "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-dismissable-layer": {
- "version": "1.1.10",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.10.tgz",
- "integrity": "sha512-IM1zzRV4W3HtVgftdQiiOmA0AdJlCtMLe00FXaHwgt3rAnNsIyDqshvkIW3hj/iu5hu8ERP7KIYki6NkqDxAwQ==",
+ "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==",
"license": "MIT",
"dependencies": {
- "@radix-ui/primitive": "1.1.2",
- "@radix-ui/react-compose-refs": "1.1.2",
- "@radix-ui/react-primitive": "2.1.3",
- "@radix-ui/react-use-callback-ref": "1.1.1",
- "@radix-ui/react-use-escape-keydown": "1.1.1"
- },
- "peerDependencies": {
- "@types/react": "*",
- "@types/react-dom": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
- "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- },
- "@types/react-dom": {
- "optional": true
- }
+ "@jridgewell/sourcemap-codec": "^1.5.0",
+ "@jridgewell/trace-mapping": "^0.3.24"
}
},
- "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-focus-guards": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.2.tgz",
- "integrity": "sha512-fyjAACV62oPV925xFCrH8DR5xWhg9KYtJT4s3u54jxp+L/hbpTY2kIeEFFbFe+a/HCE94zGQMZLIpVTPVZDhaA==",
- "license": "MIT",
- "peerDependencies": {
- "@types/react": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- }
+ "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==",
+ "engines": {
+ "node": ">=6.0.0"
}
},
- "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-focus-scope": {
- "version": "1.1.7",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz",
- "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==",
- "license": "MIT",
- "dependencies": {
- "@radix-ui/react-compose-refs": "1.1.2",
- "@radix-ui/react-primitive": "2.1.3",
- "@radix-ui/react-use-callback-ref": "1.1.1"
- },
- "peerDependencies": {
- "@types/react": "*",
- "@types/react-dom": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
- "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- },
- "@types/react-dom": {
- "optional": true
- }
- }
+ "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==",
+ "license": "MIT"
},
- "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-id": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz",
- "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==",
+ "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==",
"license": "MIT",
"dependencies": {
- "@radix-ui/react-use-layout-effect": "1.1.1"
- },
- "peerDependencies": {
- "@types/react": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- }
+ "@jridgewell/resolve-uri": "^3.1.0",
+ "@jridgewell/sourcemap-codec": "^1.4.14"
}
},
- "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-portal": {
- "version": "1.1.9",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz",
- "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==",
- "license": "MIT",
+ "node_modules/@mdx-js/mdx": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-3.0.1.tgz",
+ "integrity": "sha512-eIQ4QTrOWyL3LWEe/bu6Taqzq2HQvHcyTMaOrI95P2/LmJE7AsfPfgJGuFLPVqBUE1BC1rik3VIhU+s9u72arA==",
"dependencies": {
- "@radix-ui/react-primitive": "2.1.3",
- "@radix-ui/react-use-layout-effect": "1.1.1"
- },
- "peerDependencies": {
- "@types/react": "*",
- "@types/react-dom": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
- "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ "@types/estree": "^1.0.0",
+ "@types/estree-jsx": "^1.0.0",
+ "@types/hast": "^3.0.0",
+ "@types/mdx": "^2.0.0",
+ "collapse-white-space": "^2.0.0",
+ "devlop": "^1.0.0",
+ "estree-util-build-jsx": "^3.0.0",
+ "estree-util-is-identifier-name": "^3.0.0",
+ "estree-util-to-js": "^2.0.0",
+ "estree-walker": "^3.0.0",
+ "hast-util-to-estree": "^3.0.0",
+ "hast-util-to-jsx-runtime": "^2.0.0",
+ "markdown-extensions": "^2.0.0",
+ "periscopic": "^3.0.0",
+ "remark-mdx": "^3.0.0",
+ "remark-parse": "^11.0.0",
+ "remark-rehype": "^11.0.0",
+ "source-map": "^0.7.0",
+ "unified": "^11.0.0",
+ "unist-util-position-from-estree": "^2.0.0",
+ "unist-util-stringify-position": "^4.0.0",
+ "unist-util-visit": "^5.0.0",
+ "vfile": "^6.0.0"
},
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- },
- "@types/react-dom": {
- "optional": true
- }
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
}
},
- "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-presence": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.4.tgz",
- "integrity": "sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA==",
- "license": "MIT",
+ "node_modules/@mdx-js/react": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/@mdx-js/react/-/react-3.0.1.tgz",
+ "integrity": "sha512-9ZrPIU4MGf6et1m1ov3zKf+q9+deetI51zprKB1D/z3NOb+rUxxtEl3mCjW5wTGh6VhRdwPueh1oRzi6ezkA8A==",
"dependencies": {
- "@radix-ui/react-compose-refs": "1.1.2",
- "@radix-ui/react-use-layout-effect": "1.1.1"
- },
- "peerDependencies": {
- "@types/react": "*",
- "@types/react-dom": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
- "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ "@types/mdx": "^2.0.0"
},
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- },
- "@types/react-dom": {
- "optional": true
- }
- }
- },
- "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-primitive": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz",
- "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==",
- "license": "MIT",
- "dependencies": {
- "@radix-ui/react-slot": "1.2.3"
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/unified"
},
"peerDependencies": {
- "@types/react": "*",
- "@types/react-dom": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
- "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- },
- "@types/react-dom": {
- "optional": true
- }
+ "@types/react": ">=16",
+ "react": ">=16"
}
},
- "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-slot": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz",
- "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==",
+ "node_modules/@napi-rs/wasm-runtime": {
+ "version": "0.2.12",
+ "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-0.2.12.tgz",
+ "integrity": "sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==",
+ "dev": true,
"license": "MIT",
+ "optional": true,
"dependencies": {
- "@radix-ui/react-compose-refs": "1.1.2"
- },
- "peerDependencies": {
- "@types/react": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- }
+ "@emnapi/core": "^1.4.3",
+ "@emnapi/runtime": "^1.4.3",
+ "@tybys/wasm-util": "^0.10.0"
}
},
- "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-use-callback-ref": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz",
- "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==",
- "license": "MIT",
- "peerDependencies": {
- "@types/react": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- }
- }
+ "node_modules/@next/env": {
+ "version": "15.4.6",
+ "resolved": "https://registry.npmjs.org/@next/env/-/env-15.4.6.tgz",
+ "integrity": "sha512-yHDKVTcHrZy/8TWhj0B23ylKv5ypocuCwey9ZqPyv4rPdUdRzpGCkSi03t04KBPyU96kxVtUqx6O3nE1kpxASQ==",
+ "license": "MIT"
},
- "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-use-controllable-state": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz",
- "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==",
+ "node_modules/@next/eslint-plugin-next": {
+ "version": "15.4.6",
+ "resolved": "https://registry.npmjs.org/@next/eslint-plugin-next/-/eslint-plugin-next-15.4.6.tgz",
+ "integrity": "sha512-2NOu3ln+BTcpnbIDuxx6MNq+pRrCyey4WSXGaJIyt0D2TYicHeO9QrUENNjcf673n3B1s7hsiV5xBYRCK1Q8kA==",
+ "dev": true,
"license": "MIT",
"dependencies": {
- "@radix-ui/react-use-effect-event": "0.0.2",
- "@radix-ui/react-use-layout-effect": "1.1.1"
- },
- "peerDependencies": {
- "@types/react": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- }
+ "fast-glob": "3.3.1"
}
},
- "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-use-escape-keydown": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz",
- "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==",
+ "node_modules/@next/swc-darwin-arm64": {
+ "version": "15.4.6",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.4.6.tgz",
+ "integrity": "sha512-667R0RTP4DwxzmrqTs4Lr5dcEda9OxuZsVFsjVtxVMVhzSpo6nLclXejJVfQo2/g7/Z9qF3ETDmN3h65mTjpTQ==",
+ "cpu": [
+ "arm64"
+ ],
"license": "MIT",
- "dependencies": {
- "@radix-ui/react-use-callback-ref": "1.1.1"
- },
- "peerDependencies": {
- "@types/react": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- }
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10"
}
},
- "node_modules/@radix-ui/react-dialog/node_modules/@radix-ui/react-use-layout-effect": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz",
- "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==",
+ "node_modules/@next/swc-darwin-x64": {
+ "version": "15.4.6",
+ "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.4.6.tgz",
+ "integrity": "sha512-KMSFoistFkaiQYVQQnaU9MPWtp/3m0kn2Xed1Ces5ll+ag1+rlac20sxG+MqhH2qYWX1O2GFOATQXEyxKiIscg==",
+ "cpu": [
+ "x64"
+ ],
"license": "MIT",
- "peerDependencies": {
- "@types/react": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- }
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">= 10"
}
},
- "node_modules/@radix-ui/react-dialog/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==",
+ "node_modules/@next/swc-linux-arm64-gnu": {
+ "version": "15.4.6",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.4.6.tgz",
+ "integrity": "sha512-PnOx1YdO0W7m/HWFeYd2A6JtBO8O8Eb9h6nfJia2Dw1sRHoHpNf6lN1U4GKFRzRDBi9Nq2GrHk9PF3Vmwf7XVw==",
+ "cpu": [
+ "arm64"
+ ],
"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"
- },
+ "optional": true,
+ "os": [
+ "linux"
+ ],
"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": ">= 10"
}
},
- "node_modules/@radix-ui/react-direction": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.0.tgz",
- "integrity": "sha512-BUuBvgThEiAXh2DWu93XsT+a3aWrGqolGlqqw5VU1kG7p/ZH2cuDlM1sRLNnY3QcBS69UIz2mcKhMxDsdewhjg==",
- "peerDependencies": {
- "@types/react": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- }
+ "node_modules/@next/swc-linux-arm64-musl": {
+ "version": "15.4.6",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.4.6.tgz",
+ "integrity": "sha512-XBbuQddtY1p5FGPc2naMO0kqs4YYtLYK/8aPausI5lyOjr4J77KTG9mtlU4P3NwkLI1+OjsPzKVvSJdMs3cFaw==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
}
},
- "node_modules/@radix-ui/react-dismissable-layer": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.0.tgz",
- "integrity": "sha512-/UovfmmXGptwGcBQawLzvn2jOfM0t4z3/uKffoBlj724+n3FvBbZ7M0aaBOmkp6pqFYpO4yx8tSVJjx3Fl2jig==",
- "dependencies": {
- "@radix-ui/primitive": "1.1.0",
- "@radix-ui/react-compose-refs": "1.1.0",
- "@radix-ui/react-primitive": "2.0.0",
- "@radix-ui/react-use-callback-ref": "1.1.0",
- "@radix-ui/react-use-escape-keydown": "1.1.0"
- },
- "peerDependencies": {
- "@types/react": "*",
- "@types/react-dom": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
- "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- },
- "@types/react-dom": {
- "optional": true
- }
+ "node_modules/@next/swc-linux-x64-gnu": {
+ "version": "15.4.6",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.4.6.tgz",
+ "integrity": "sha512-+WTeK7Qdw82ez3U9JgD+igBAP75gqZ1vbK6R8PlEEuY0OIe5FuYXA4aTjL811kWPf7hNeslD4hHK2WoM9W0IgA==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
}
},
- "node_modules/@radix-ui/react-dropdown-menu": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.1.tgz",
- "integrity": "sha512-y8E+x9fBq9qvteD2Zwa4397pUVhYsh9iq44b5RD5qu1GMJWBCBuVg1hMyItbc6+zH00TxGRqd9Iot4wzf3OoBQ==",
- "dependencies": {
- "@radix-ui/primitive": "1.1.0",
- "@radix-ui/react-compose-refs": "1.1.0",
- "@radix-ui/react-context": "1.1.0",
- "@radix-ui/react-id": "1.1.0",
- "@radix-ui/react-menu": "2.1.1",
- "@radix-ui/react-primitive": "2.0.0",
- "@radix-ui/react-use-controllable-state": "1.1.0"
- },
- "peerDependencies": {
- "@types/react": "*",
- "@types/react-dom": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
- "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- },
- "@types/react-dom": {
- "optional": true
- }
+ "node_modules/@next/swc-linux-x64-musl": {
+ "version": "15.4.6",
+ "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.4.6.tgz",
+ "integrity": "sha512-XP824mCbgQsK20jlXKrUpZoh/iO3vUWhMpxCz8oYeagoiZ4V0TQiKy0ASji1KK6IAe3DYGfj5RfKP6+L2020OQ==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">= 10"
}
},
- "node_modules/@radix-ui/react-focus-guards": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.0.tgz",
- "integrity": "sha512-w6XZNUPVv6xCpZUqb/yN9DL6auvpGX3C/ee6Hdi16v2UUy25HV2Q5bcflsiDyT/g5RwbPQ/GIT1vLkeRb+ITBw==",
- "peerDependencies": {
- "@types/react": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- }
+ "node_modules/@next/swc-win32-arm64-msvc": {
+ "version": "15.4.6",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.4.6.tgz",
+ "integrity": "sha512-FxrsenhUz0LbgRkNWx6FRRJIPe/MI1JRA4W4EPd5leXO00AZ6YU8v5vfx4MDXTvN77lM/EqsE3+6d2CIeF5NYg==",
+ "cpu": [
+ "arm64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10"
}
},
- "node_modules/@radix-ui/react-focus-scope": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.0.tgz",
- "integrity": "sha512-200UD8zylvEyL8Bx+z76RJnASR2gRMuxlgFCPAe/Q/679a/r0eK3MBVYMb7vZODZcffZBdob1EGnky78xmVvcA==",
- "dependencies": {
- "@radix-ui/react-compose-refs": "1.1.0",
- "@radix-ui/react-primitive": "2.0.0",
- "@radix-ui/react-use-callback-ref": "1.1.0"
- },
- "peerDependencies": {
- "@types/react": "*",
- "@types/react-dom": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
- "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- },
- "@types/react-dom": {
- "optional": true
- }
+ "node_modules/@next/swc-win32-x64-msvc": {
+ "version": "15.4.6",
+ "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.4.6.tgz",
+ "integrity": "sha512-T4ufqnZ4u88ZheczkBTtOF+eKaM14V8kbjud/XrAakoM5DKQWjW09vD6B9fsdsWS2T7D5EY31hRHdta7QKWOng==",
+ "cpu": [
+ "x64"
+ ],
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">= 10"
}
},
- "node_modules/@radix-ui/react-id": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.0.tgz",
- "integrity": "sha512-EJUrI8yYh7WOjNOqpoJaf1jlFIH2LvtgAl+YcFqNCa+4hj64ZXmPkAKOFs/ukjz3byN6bdb/AVUqHkI8/uWWMA==",
+ "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==",
+ "license": "MIT",
"dependencies": {
- "@radix-ui/react-use-layout-effect": "1.1.0"
- },
- "peerDependencies": {
- "@types/react": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ "@nodelib/fs.stat": "2.0.5",
+ "run-parallel": "^1.1.9"
},
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- }
+ "engines": {
+ "node": ">= 8"
}
},
- "node_modules/@radix-ui/react-menu": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.1.tgz",
- "integrity": "sha512-oa3mXRRVjHi6DZu/ghuzdylyjaMXLymx83irM7hTxutQbD+7IhPKdMdRHD26Rm+kHRrWcrUkkRPv5pd47a2xFQ==",
- "dependencies": {
- "@radix-ui/primitive": "1.1.0",
- "@radix-ui/react-collection": "1.1.0",
- "@radix-ui/react-compose-refs": "1.1.0",
- "@radix-ui/react-context": "1.1.0",
- "@radix-ui/react-direction": "1.1.0",
- "@radix-ui/react-dismissable-layer": "1.1.0",
- "@radix-ui/react-focus-guards": "1.1.0",
- "@radix-ui/react-focus-scope": "1.1.0",
- "@radix-ui/react-id": "1.1.0",
- "@radix-ui/react-popper": "1.2.0",
- "@radix-ui/react-portal": "1.1.1",
- "@radix-ui/react-presence": "1.1.0",
- "@radix-ui/react-primitive": "2.0.0",
- "@radix-ui/react-roving-focus": "1.1.0",
- "@radix-ui/react-slot": "1.1.0",
- "@radix-ui/react-use-callback-ref": "1.1.0",
- "aria-hidden": "^1.1.1",
- "react-remove-scroll": "2.5.7"
- },
- "peerDependencies": {
- "@types/react": "*",
- "@types/react-dom": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
- "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- },
- "@types/react-dom": {
- "optional": true
- }
+ "node_modules/@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==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 8"
}
},
- "node_modules/@radix-ui/react-popper": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.0.tgz",
- "integrity": "sha512-ZnRMshKF43aBxVWPWvbj21+7TQCvhuULWJ4gNIKYpRlQt5xGRhLx66tMp8pya2UkGHTSlhpXwmjqltDYHhw7Vg==",
+ "node_modules/@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==",
+ "license": "MIT",
"dependencies": {
- "@floating-ui/react-dom": "^2.0.0",
- "@radix-ui/react-arrow": "1.1.0",
- "@radix-ui/react-compose-refs": "1.1.0",
- "@radix-ui/react-context": "1.1.0",
- "@radix-ui/react-primitive": "2.0.0",
- "@radix-ui/react-use-callback-ref": "1.1.0",
- "@radix-ui/react-use-layout-effect": "1.1.0",
- "@radix-ui/react-use-rect": "1.1.0",
- "@radix-ui/react-use-size": "1.1.0",
- "@radix-ui/rect": "1.1.0"
- },
- "peerDependencies": {
- "@types/react": "*",
- "@types/react-dom": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
- "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ "@nodelib/fs.scandir": "2.1.5",
+ "fastq": "^1.6.0"
},
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- },
- "@types/react-dom": {
- "optional": true
- }
+ "engines": {
+ "node": ">= 8"
}
},
- "node_modules/@radix-ui/react-portal": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.1.tgz",
- "integrity": "sha512-A3UtLk85UtqhzFqtoC8Q0KvR2GbXF3mtPgACSazajqq6A41mEQgo53iPzY4i6BwDxlIFqWIhiQ2G729n+2aw/g==",
- "dependencies": {
- "@radix-ui/react-primitive": "2.0.0",
- "@radix-ui/react-use-layout-effect": "1.1.0"
- },
- "peerDependencies": {
- "@types/react": "*",
- "@types/react-dom": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
- "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- },
- "@types/react-dom": {
- "optional": true
- }
+ "node_modules/@nolyfill/is-core-module": {
+ "version": "1.0.39",
+ "resolved": "https://registry.npmjs.org/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz",
+ "integrity": "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12.4.0"
}
},
- "node_modules/@radix-ui/react-presence": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.0.tgz",
- "integrity": "sha512-Gq6wuRN/asf9H/E/VzdKoUtT8GC9PQc9z40/vEr0VCJ4u5XvvhWIrSsCB6vD2/cH7ugTdSfYq9fLJCcM00acrQ==",
+ "node_modules/@pkgjs/parseargs": {
+ "version": "0.11.0",
+ "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz",
+ "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==",
+ "license": "MIT",
+ "optional": true,
+ "engines": {
+ "node": ">=14"
+ }
+ },
+ "node_modules/@radix-ui/number": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz",
+ "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==",
+ "license": "MIT"
+ },
+ "node_modules/@radix-ui/primitive": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.2.tgz",
+ "integrity": "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA==",
+ "license": "MIT"
+ },
+ "node_modules/@radix-ui/react-arrow": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz",
+ "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==",
+ "license": "MIT",
"dependencies": {
- "@radix-ui/react-compose-refs": "1.1.0",
- "@radix-ui/react-use-layout-effect": "1.1.0"
+ "@radix-ui/react-primitive": "2.1.3"
},
"peerDependencies": {
"@types/react": "*",
@@ -1790,12 +1661,20 @@
}
}
},
- "node_modules/@radix-ui/react-primitive": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.0.0.tgz",
- "integrity": "sha512-ZSpFm0/uHa8zTvKBDjLFWLo8dkr4MBsiDLz0g3gMUwqgLHz9rTaRRGYDgvZPtBJgYCBKXkS9fzmoySgr8CO6Cw==",
+ "node_modules/@radix-ui/react-collapsible": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.11.tgz",
+ "integrity": "sha512-2qrRsVGSCYasSz1RFOorXwl0H7g7J1frQtgpQgYrt+MOidtPAINHn9CPovQXb83r8ahapdx3Tu0fa/pdFFSdPg==",
+ "license": "MIT",
"dependencies": {
- "@radix-ui/react-slot": "1.1.0"
+ "@radix-ui/primitive": "1.1.2",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-id": "1.1.1",
+ "@radix-ui/react-presence": "1.1.4",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-use-controllable-state": "1.2.2",
+ "@radix-ui/react-use-layout-effect": "1.1.1"
},
"peerDependencies": {
"@types/react": "*",
@@ -1812,20 +1691,16 @@
}
}
},
- "node_modules/@radix-ui/react-roving-focus": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.0.tgz",
- "integrity": "sha512-EA6AMGeq9AEeQDeSH0aZgG198qkfHSbvWTf1HvoDmOB5bBG/qTxjYMWUKMnYiV6J/iP/J8MEFSuB2zRU2n7ODA==",
- "dependencies": {
- "@radix-ui/primitive": "1.1.0",
- "@radix-ui/react-collection": "1.1.0",
- "@radix-ui/react-compose-refs": "1.1.0",
- "@radix-ui/react-context": "1.1.0",
- "@radix-ui/react-direction": "1.1.0",
- "@radix-ui/react-id": "1.1.0",
- "@radix-ui/react-primitive": "2.0.0",
- "@radix-ui/react-use-callback-ref": "1.1.0",
- "@radix-ui/react-use-controllable-state": "1.1.0"
+ "node_modules/@radix-ui/react-collection": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz",
+ "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-slot": "1.2.3"
},
"peerDependencies": {
"@types/react": "*",
@@ -1842,43 +1717,26 @@
}
}
},
- "node_modules/@radix-ui/react-scroll-area": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.1.0.tgz",
- "integrity": "sha512-9ArIZ9HWhsrfqS765h+GZuLoxaRHD/j0ZWOWilsCvYTpYJp8XwCqNG7Dt9Nu/TItKOdgLGkOPCodQvDc+UMwYg==",
- "dependencies": {
- "@radix-ui/number": "1.1.0",
- "@radix-ui/primitive": "1.1.0",
- "@radix-ui/react-compose-refs": "1.1.0",
- "@radix-ui/react-context": "1.1.0",
- "@radix-ui/react-direction": "1.1.0",
- "@radix-ui/react-presence": "1.1.0",
- "@radix-ui/react-primitive": "2.0.0",
- "@radix-ui/react-use-callback-ref": "1.1.0",
- "@radix-ui/react-use-layout-effect": "1.1.0"
- },
+ "node_modules/@radix-ui/react-compose-refs": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
+ "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==",
+ "license": "MIT",
"peerDependencies": {
"@types/react": "*",
- "@types/react-dom": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
- "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
- },
- "@types/react-dom": {
- "optional": true
}
}
},
- "node_modules/@radix-ui/react-slot": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.1.0.tgz",
- "integrity": "sha512-FUCf5XMfmW4dtYl69pdS4DbxKy8nj4M7SafBgPllysxmdachynNflAdp/gCsnYWNDnge6tI9onzMp5ARYc1KNw==",
- "dependencies": {
- "@radix-ui/react-compose-refs": "1.1.0"
- },
+ "node_modules/@radix-ui/react-context": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz",
+ "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==",
+ "license": "MIT",
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
@@ -1889,24 +1747,26 @@
}
}
},
- "node_modules/@radix-ui/react-tooltip": {
- "version": "1.2.7",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.7.tgz",
- "integrity": "sha512-Ap+fNYwKTYJ9pzqW+Xe2HtMRbQ/EeWkj2qykZ6SuEV4iS/o1bZI5ssJbk4D2r8XuDuOBVz/tIx2JObtuqU+5Zw==",
+ "node_modules/@radix-ui/react-dialog": {
+ "version": "1.1.14",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.14.tgz",
+ "integrity": "sha512-+CpweKjqpzTmwRwcYECQcNYbI8V9VSQt0SNFKeEBLgfucbsLssU6Ppq7wUdNXEGb573bMjFhVjKVll8rmV6zMw==",
"license": "MIT",
"dependencies": {
"@radix-ui/primitive": "1.1.2",
"@radix-ui/react-compose-refs": "1.1.2",
"@radix-ui/react-context": "1.1.2",
"@radix-ui/react-dismissable-layer": "1.1.10",
+ "@radix-ui/react-focus-guards": "1.1.2",
+ "@radix-ui/react-focus-scope": "1.1.7",
"@radix-ui/react-id": "1.1.1",
- "@radix-ui/react-popper": "1.2.7",
"@radix-ui/react-portal": "1.1.9",
"@radix-ui/react-presence": "1.1.4",
"@radix-ui/react-primitive": "2.1.3",
"@radix-ui/react-slot": "1.2.3",
"@radix-ui/react-use-controllable-state": "1.2.2",
- "@radix-ui/react-visually-hidden": "1.2.3"
+ "aria-hidden": "^1.2.4",
+ "react-remove-scroll": "^2.6.3"
},
"peerDependencies": {
"@types/react": "*",
@@ -1923,19 +1783,32 @@
}
}
},
- "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/primitive": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.2.tgz",
- "integrity": "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA==",
- "license": "MIT"
+ "node_modules/@radix-ui/react-direction": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz",
+ "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ }
+ }
},
- "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-arrow": {
- "version": "1.1.7",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz",
- "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==",
+ "node_modules/@radix-ui/react-dismissable-layer": {
+ "version": "1.1.10",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.10.tgz",
+ "integrity": "sha512-IM1zzRV4W3HtVgftdQiiOmA0AdJlCtMLe00FXaHwgt3rAnNsIyDqshvkIW3hj/iu5hu8ERP7KIYki6NkqDxAwQ==",
"license": "MIT",
"dependencies": {
- "@radix-ui/react-primitive": "2.1.3"
+ "@radix-ui/primitive": "1.1.2",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-use-callback-ref": "1.1.1",
+ "@radix-ui/react-use-escape-keydown": "1.1.1"
},
"peerDependencies": {
"@types/react": "*",
@@ -1952,25 +1825,39 @@
}
}
},
- "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-compose-refs": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
- "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==",
+ "node_modules/@radix-ui/react-dropdown-menu": {
+ "version": "2.1.15",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.15.tgz",
+ "integrity": "sha512-mIBnOjgwo9AH3FyKaSWoSu/dYj6VdhJ7frEPiGTeXCdUFHjl9h3mFh2wwhEtINOmYXWhdpf1rY2minFsmaNgVQ==",
"license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.2",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-id": "1.1.1",
+ "@radix-ui/react-menu": "2.1.15",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-use-controllable-state": "1.2.2"
+ },
"peerDependencies": {
"@types/react": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
}
}
},
- "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-context": {
+ "node_modules/@radix-ui/react-focus-guards": {
"version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz",
- "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.2.tgz",
+ "integrity": "sha512-fyjAACV62oPV925xFCrH8DR5xWhg9KYtJT4s3u54jxp+L/hbpTY2kIeEFFbFe+a/HCE94zGQMZLIpVTPVZDhaA==",
"license": "MIT",
"peerDependencies": {
"@types/react": "*",
@@ -1982,17 +1869,15 @@
}
}
},
- "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-dismissable-layer": {
- "version": "1.1.10",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.10.tgz",
- "integrity": "sha512-IM1zzRV4W3HtVgftdQiiOmA0AdJlCtMLe00FXaHwgt3rAnNsIyDqshvkIW3hj/iu5hu8ERP7KIYki6NkqDxAwQ==",
+ "node_modules/@radix-ui/react-focus-scope": {
+ "version": "1.1.7",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz",
+ "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==",
"license": "MIT",
"dependencies": {
- "@radix-ui/primitive": "1.1.2",
"@radix-ui/react-compose-refs": "1.1.2",
"@radix-ui/react-primitive": "2.1.3",
- "@radix-ui/react-use-callback-ref": "1.1.1",
- "@radix-ui/react-use-escape-keydown": "1.1.1"
+ "@radix-ui/react-use-callback-ref": "1.1.1"
},
"peerDependencies": {
"@types/react": "*",
@@ -2009,7 +1894,7 @@
}
}
},
- "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-id": {
+ "node_modules/@radix-ui/react-id": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz",
"integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==",
@@ -2027,7 +1912,47 @@
}
}
},
- "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-popper": {
+ "node_modules/@radix-ui/react-menu": {
+ "version": "2.1.15",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.15.tgz",
+ "integrity": "sha512-tVlmA3Vb9n8SZSd+YSbuFR66l87Wiy4du+YE+0hzKQEANA+7cWKH1WgqcEX4pXqxUFQKrWQGHdvEfw00TjFiew==",
+ "license": "MIT",
+ "dependencies": {
+ "@radix-ui/primitive": "1.1.2",
+ "@radix-ui/react-collection": "1.1.7",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-direction": "1.1.1",
+ "@radix-ui/react-dismissable-layer": "1.1.10",
+ "@radix-ui/react-focus-guards": "1.1.2",
+ "@radix-ui/react-focus-scope": "1.1.7",
+ "@radix-ui/react-id": "1.1.1",
+ "@radix-ui/react-popper": "1.2.7",
+ "@radix-ui/react-portal": "1.1.9",
+ "@radix-ui/react-presence": "1.1.4",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-roving-focus": "1.1.10",
+ "@radix-ui/react-slot": "1.2.3",
+ "@radix-ui/react-use-callback-ref": "1.1.1",
+ "aria-hidden": "^1.2.4",
+ "react-remove-scroll": "^2.6.3"
+ },
+ "peerDependencies": {
+ "@types/react": "*",
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ },
+ "peerDependenciesMeta": {
+ "@types/react": {
+ "optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@radix-ui/react-popper": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.7.tgz",
"integrity": "sha512-IUFAccz1JyKcf/RjB552PlWwxjeCJB8/4KxT7EhBHOJM+mN7LdW+B3kacJXILm32xawcMMjb2i0cIZpo+f9kiQ==",
@@ -2059,7 +1984,7 @@
}
}
},
- "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-portal": {
+ "node_modules/@radix-ui/react-portal": {
"version": "1.1.9",
"resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz",
"integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==",
@@ -2083,7 +2008,7 @@
}
}
},
- "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-presence": {
+ "node_modules/@radix-ui/react-presence": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.4.tgz",
"integrity": "sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA==",
@@ -2107,7 +2032,7 @@
}
}
},
- "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-primitive": {
+ "node_modules/@radix-ui/react-primitive": {
"version": "2.1.3",
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz",
"integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==",
@@ -2130,98 +2055,75 @@
}
}
},
- "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-slot": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz",
- "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==",
+ "node_modules/@radix-ui/react-roving-focus": {
+ "version": "1.1.10",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.10.tgz",
+ "integrity": "sha512-dT9aOXUen9JSsxnMPv/0VqySQf5eDQ6LCk5Sw28kamz8wSOW2bJdlX2Bg5VUIIcV+6XlHpWTIuTPCf/UNIyq8Q==",
"license": "MIT",
"dependencies": {
- "@radix-ui/react-compose-refs": "1.1.2"
+ "@radix-ui/primitive": "1.1.2",
+ "@radix-ui/react-collection": "1.1.7",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-direction": "1.1.1",
+ "@radix-ui/react-id": "1.1.1",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-use-callback-ref": "1.1.1",
+ "@radix-ui/react-use-controllable-state": "1.2.2"
},
"peerDependencies": {
"@types/react": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
- }
- }
- },
- "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-use-callback-ref": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz",
- "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==",
- "license": "MIT",
- "peerDependencies": {
- "@types/react": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
+ },
+ "@types/react-dom": {
"optional": true
}
}
},
- "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-use-controllable-state": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz",
- "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==",
+ "node_modules/@radix-ui/react-scroll-area": {
+ "version": "1.2.9",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.9.tgz",
+ "integrity": "sha512-YSjEfBXnhUELsO2VzjdtYYD4CfQjvao+lhhrX5XsHD7/cyUNzljF1FHEbgTPN7LH2MClfwRMIsYlqTYpKTTe2A==",
"license": "MIT",
"dependencies": {
- "@radix-ui/react-use-effect-event": "0.0.2",
+ "@radix-ui/number": "1.1.1",
+ "@radix-ui/primitive": "1.1.2",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-direction": "1.1.1",
+ "@radix-ui/react-presence": "1.1.4",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-use-callback-ref": "1.1.1",
"@radix-ui/react-use-layout-effect": "1.1.1"
},
"peerDependencies": {
"@types/react": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- }
- }
- },
- "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-use-escape-keydown": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz",
- "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==",
- "license": "MIT",
- "dependencies": {
- "@radix-ui/react-use-callback-ref": "1.1.1"
- },
- "peerDependencies": {
- "@types/react": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
- }
- }
- },
- "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-use-layout-effect": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz",
- "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==",
- "license": "MIT",
- "peerDependencies": {
- "@types/react": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
+ },
+ "@types/react-dom": {
"optional": true
}
}
},
- "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-use-rect": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz",
- "integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==",
+ "node_modules/@radix-ui/react-slot": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz",
+ "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==",
"license": "MIT",
"dependencies": {
- "@radix-ui/rect": "1.1.1"
+ "@radix-ui/react-compose-refs": "1.1.2"
},
"peerDependencies": {
"@types/react": "*",
@@ -2233,34 +2135,45 @@
}
}
},
- "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/react-use-size": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz",
- "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==",
+ "node_modules/@radix-ui/react-tooltip": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.7.tgz",
+ "integrity": "sha512-Ap+fNYwKTYJ9pzqW+Xe2HtMRbQ/EeWkj2qykZ6SuEV4iS/o1bZI5ssJbk4D2r8XuDuOBVz/tIx2JObtuqU+5Zw==",
"license": "MIT",
"dependencies": {
- "@radix-ui/react-use-layout-effect": "1.1.1"
+ "@radix-ui/primitive": "1.1.2",
+ "@radix-ui/react-compose-refs": "1.1.2",
+ "@radix-ui/react-context": "1.1.2",
+ "@radix-ui/react-dismissable-layer": "1.1.10",
+ "@radix-ui/react-id": "1.1.1",
+ "@radix-ui/react-popper": "1.2.7",
+ "@radix-ui/react-portal": "1.1.9",
+ "@radix-ui/react-presence": "1.1.4",
+ "@radix-ui/react-primitive": "2.1.3",
+ "@radix-ui/react-slot": "1.2.3",
+ "@radix-ui/react-use-controllable-state": "1.2.2",
+ "@radix-ui/react-visually-hidden": "1.2.3"
},
"peerDependencies": {
"@types/react": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ "@types/react-dom": "*",
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
+ },
+ "@types/react-dom": {
+ "optional": true
}
}
},
- "node_modules/@radix-ui/react-tooltip/node_modules/@radix-ui/rect": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz",
- "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==",
- "license": "MIT"
- },
"node_modules/@radix-ui/react-use-callback-ref": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.0.tgz",
- "integrity": "sha512-CasTfvsy+frcFkbXtSJ2Zu9JHpN8TYKxkgJGWbjiZhFivxaeW7rMeZt7QELGVLaYVfFMsKHjb7Ak0nMEe+2Vfw==",
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz",
+ "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==",
+ "license": "MIT",
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
@@ -2272,11 +2185,13 @@
}
},
"node_modules/@radix-ui/react-use-controllable-state": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.1.0.tgz",
- "integrity": "sha512-MtfMVJiSr2NjzS0Aa90NPTnvTSg6C/JLCV7ma0W6+OMV78vd8OyRpID+Ng9LxzsPbLeuBnWBA1Nq30AtBIDChw==",
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz",
+ "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==",
+ "license": "MIT",
"dependencies": {
- "@radix-ui/react-use-callback-ref": "1.1.0"
+ "@radix-ui/react-use-effect-event": "0.0.2",
+ "@radix-ui/react-use-layout-effect": "1.1.1"
},
"peerDependencies": {
"@types/react": "*",
@@ -2306,27 +2221,13 @@
}
}
},
- "node_modules/@radix-ui/react-use-effect-event/node_modules/@radix-ui/react-use-layout-effect": {
+ "node_modules/@radix-ui/react-use-escape-keydown": {
"version": "1.1.1",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz",
- "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz",
+ "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==",
"license": "MIT",
- "peerDependencies": {
- "@types/react": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- }
- }
- },
- "node_modules/@radix-ui/react-use-escape-keydown": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.0.tgz",
- "integrity": "sha512-L7vwWlR1kTTQ3oh7g1O0CBF3YCyyTj8NmhLR+phShpyA50HCfBFKVJTpshm9PzLiKmehsrQzTYTpX9HvmC9rhw==",
"dependencies": {
- "@radix-ui/react-use-callback-ref": "1.1.0"
+ "@radix-ui/react-use-callback-ref": "1.1.1"
},
"peerDependencies": {
"@types/react": "*",
@@ -2339,43 +2240,10 @@
}
},
"node_modules/@radix-ui/react-use-layout-effect": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.0.tgz",
- "integrity": "sha512-+FPE0rOdziWSrH9athwI1R0HDVbWlEhd+FR+aSDk4uWGmSJ9Z54sdZVDQPZAinJhJXwfT+qnj969mCsT2gfm5w==",
- "peerDependencies": {
- "@types/react": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- }
- }
- },
- "node_modules/@radix-ui/react-use-rect": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.0.tgz",
- "integrity": "sha512-0Fmkebhr6PiseyZlYAOtLS+nb7jLmpqTrJyv61Pe68MKYW6OWdRE2kI70TaYY27u7H0lajqM3hSMMLFq18Z7nQ==",
- "dependencies": {
- "@radix-ui/rect": "1.1.0"
- },
- "peerDependencies": {
- "@types/react": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- }
- }
- },
- "node_modules/@radix-ui/react-use-size": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.0.tgz",
- "integrity": "sha512-XW3/vWuIXHa+2Uwcc2ABSfcCledmXhhQPlGbfcRXbiUQI5Icjcg19BGCZVKKInYbvUCut/ufbbLLPFC5cbb1hw==",
- "dependencies": {
- "@radix-ui/react-use-layout-effect": "1.1.0"
- },
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz",
+ "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==",
+ "license": "MIT",
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
@@ -2386,34 +2254,32 @@
}
}
},
- "node_modules/@radix-ui/react-visually-hidden": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz",
- "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==",
+ "node_modules/@radix-ui/react-use-rect": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz",
+ "integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==",
"license": "MIT",
"dependencies": {
- "@radix-ui/react-primitive": "2.1.3"
+ "@radix-ui/rect": "1.1.1"
},
"peerDependencies": {
"@types/react": "*",
- "@types/react-dom": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
- "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+ "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
"optional": true
- },
- "@types/react-dom": {
- "optional": true
}
}
},
- "node_modules/@radix-ui/react-visually-hidden/node_modules/@radix-ui/react-compose-refs": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
- "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==",
+ "node_modules/@radix-ui/react-use-size": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz",
+ "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==",
"license": "MIT",
+ "dependencies": {
+ "@radix-ui/react-use-layout-effect": "1.1.1"
+ },
"peerDependencies": {
"@types/react": "*",
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
@@ -2424,13 +2290,13 @@
}
}
},
- "node_modules/@radix-ui/react-visually-hidden/node_modules/@radix-ui/react-primitive": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz",
- "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==",
+ "node_modules/@radix-ui/react-visually-hidden": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz",
+ "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==",
"license": "MIT",
"dependencies": {
- "@radix-ui/react-slot": "1.2.3"
+ "@radix-ui/react-primitive": "2.1.3"
},
"peerDependencies": {
"@types/react": "*",
@@ -2447,28 +2313,20 @@
}
}
},
- "node_modules/@radix-ui/react-visually-hidden/node_modules/@radix-ui/react-slot": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz",
- "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==",
- "license": "MIT",
- "dependencies": {
- "@radix-ui/react-compose-refs": "1.1.2"
- },
- "peerDependencies": {
- "@types/react": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- }
- }
- },
"node_modules/@radix-ui/rect": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.0.tgz",
- "integrity": "sha512-A9+lCBZoaMJlVKcRBz2YByCG+Cp2t6nAnMnNba+XiWxnj6r4JUFqfsgwocMBZU9LPtdxC6wB56ySYpc7LQIoJg=="
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz",
+ "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==",
+ "license": "MIT"
+ },
+ "node_modules/@resvg/resvg-wasm": {
+ "version": "2.4.0",
+ "resolved": "https://registry.npmjs.org/@resvg/resvg-wasm/-/resvg-wasm-2.4.0.tgz",
+ "integrity": "sha512-C7c51Nn4yTxXFKvgh2txJFNweaVcfUPQxwEUFw4aWsCmfiBDJsTSwviIF8EcwjQ6k8bPyMWCl1vw4BdxE569Cg==",
+ "license": "MPL-2.0",
+ "engines": {
+ "node": ">= 10"
+ }
},
"node_modules/@rocicorp/prettier-config": {
"version": "0.3.0",
@@ -2479,31 +2337,51 @@
"prettier": "^3.5.3"
}
},
+ "node_modules/@rtsao/scc": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz",
+ "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/@rushstack/eslint-patch": {
- "version": "1.10.2",
- "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.10.2.tgz",
- "integrity": "sha512-hw437iINopmQuxWPSUEvqE56NCPsiU8N4AYtfHmJFckclktzK9YQJieD3XkDCDH4OjL+C7zgPUh73R/nrcHrqw==",
- "dev": true
+ "version": "1.12.0",
+ "resolved": "https://registry.npmjs.org/@rushstack/eslint-patch/-/eslint-patch-1.12.0.tgz",
+ "integrity": "sha512-5EwMtOqvJMMa3HbmxLlF74e+3/HhwBTMcvt3nqVJgGCozO6hzIPOBlwm8mGVNR9SN2IJpxSnlxczyDjcn7qIyw==",
+ "dev": true,
+ "license": "MIT"
},
- "node_modules/@swc/counter": {
- "version": "0.1.3",
- "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz",
- "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ=="
+ "node_modules/@shuding/opentype.js": {
+ "version": "1.4.0-beta.0",
+ "resolved": "https://registry.npmjs.org/@shuding/opentype.js/-/opentype.js-1.4.0-beta.0.tgz",
+ "integrity": "sha512-3NgmNyH3l/Hv6EvsWJbsvpcpUba6R8IREQ83nH83cyakCw7uM1arZKNfHwv1Wz6jgqrF/j4x5ELvR6PnK9nTcA==",
+ "license": "MIT",
+ "dependencies": {
+ "fflate": "^0.7.3",
+ "string.prototype.codepointat": "^0.2.1"
+ },
+ "bin": {
+ "ot": "bin/ot"
+ },
+ "engines": {
+ "node": ">= 8.0.0"
+ }
},
"node_modules/@swc/helpers": {
- "version": "0.5.5",
- "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.5.tgz",
- "integrity": "sha512-KGYxvIOXcceOAbEk4bi/dVLEK9z8sZ0uBB3Il5b1rhfClSpcX0yfRO0KmTkqR2cnQDymwLB+25ZyMzICg/cm/A==",
+ "version": "0.5.15",
+ "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz",
+ "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==",
+ "license": "Apache-2.0",
"dependencies": {
- "@swc/counter": "^0.1.3",
- "tslib": "^2.4.0"
+ "tslib": "^2.8.0"
}
},
"node_modules/@tailwindcss/typography": {
- "version": "0.5.14",
- "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.14.tgz",
- "integrity": "sha512-ZvOCjUbsJBjL9CxQBn+VEnFpouzuKhxh2dH8xMIWHILL+HfOYtlAkWcyoon8LlzE53d2Yo6YO6pahKKNW3q1YQ==",
+ "version": "0.5.16",
+ "resolved": "https://registry.npmjs.org/@tailwindcss/typography/-/typography-0.5.16.tgz",
+ "integrity": "sha512-0wDLwCVF5V3x3b1SGXPCDcdsbDHMBe+lkFzBRaHeLvNi+nrrnZ1lA18u+OTWO8iSWU2GxUOCvlXtDuqftc1oiA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"lodash.castarray": "^4.4.0",
"lodash.isplainobject": "^4.0.6",
@@ -2511,7 +2389,7 @@
"postcss-selector-parser": "6.0.10"
},
"peerDependencies": {
- "tailwindcss": ">=3.0.0 || insiders"
+ "tailwindcss": ">=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1"
}
},
"node_modules/@tailwindcss/typography/node_modules/postcss-selector-parser": {
@@ -2555,6 +2433,17 @@
"devOptional": true,
"license": "MIT"
},
+ "node_modules/@tybys/wasm-util": {
+ "version": "0.10.0",
+ "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.0.tgz",
+ "integrity": "sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ==",
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
"node_modules/@types/acorn": {
"version": "4.0.6",
"resolved": "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.6.tgz",
@@ -2572,9 +2461,10 @@
}
},
"node_modules/@types/estree": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
- "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw=="
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
+ "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
+ "license": "MIT"
},
"node_modules/@types/estree-jsx": {
"version": "1.0.5",
@@ -2593,11 +2483,19 @@
"@types/unist": "*"
}
},
+ "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/json5": {
"version": "0.0.29",
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
"integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/@types/lunr": {
"version": "2.3.7",
@@ -2625,12 +2523,12 @@
"integrity": "sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g=="
},
"node_modules/@types/node": {
- "version": "20.17.19",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.19.tgz",
- "integrity": "sha512-LEwC7o1ifqg/6r2gn9Dns0f1rhK+fPFDoMiceTJ6kWmVk6bgXBI/9IOWfVan4WiAavK9pIVWdX0/e3J+eEUh5A==",
+ "version": "24.2.0",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-24.2.0.tgz",
+ "integrity": "sha512-3xyG3pMCq3oYCNg7/ZP+E1ooTaGB4cG8JWRsqqOYQdbWNY4zbaV0Ennrd7stjiJEFZCaybcIgpTjJWHRfBSIDw==",
"license": "MIT",
"dependencies": {
- "undici-types": "~6.19.2"
+ "undici-types": "~7.10.0"
}
},
"node_modules/@types/prismjs": {
@@ -2638,27 +2536,23 @@
"resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.3.tgz",
"integrity": "sha512-A0D0aTXvjlqJ5ZILMz3rNfDBOx9hHxLZYv2by47Sm/pqW35zzjusrZTryatjN/Rf8Us2gZrJD+KeHbUSTux1Cw=="
},
- "node_modules/@types/prop-types": {
- "version": "15.7.12",
- "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz",
- "integrity": "sha512-5zvhXYtRNRluoE/jAp4GVsSduVUzNWKkOZrCDBWYtE7biZywwdC2AcEzg+cSMLFRfVgeAFqpfNabiPjxFddV1Q=="
- },
"node_modules/@types/react": {
- "version": "18.2.77",
- "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.77.tgz",
- "integrity": "sha512-CUT9KUUF+HytDM7WiXKLF9qUSg4tGImwy4FXTlfEDPEkkNUzJ7rVFolYweJ9fS1ljoIaP7M7Rdjc5eUm/Yu5AA==",
+ "version": "19.1.9",
+ "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.9.tgz",
+ "integrity": "sha512-WmdoynAX8Stew/36uTSVMcLJJ1KRh6L3IZRx1PZ7qJtBqT3dYTgyDTx8H1qoRghErydW7xw9mSJ3wS//tCRpFA==",
+ "license": "MIT",
"dependencies": {
- "@types/prop-types": "*",
"csstype": "^3.0.2"
}
},
"node_modules/@types/react-dom": {
- "version": "18.2.25",
- "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.25.tgz",
- "integrity": "sha512-o/V48vf4MQh7juIKZU2QGDfli6p1+OOi5oXx36Hffpc9adsHeXjVp8rHuPkjd8VT8sOJ2Zp05HR7CdpGTIUFUA==",
+ "version": "19.1.7",
+ "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.7.tgz",
+ "integrity": "sha512-i5ZzwYpqjmrKenzkoLM2Ibzt6mAsM7pxB6BCIouEVVmgiqaMj1TjaK7hnA36hbW5aZv20kx7Lw6hWzPWg0Rurw==",
"devOptional": true,
- "dependencies": {
- "@types/react": "*"
+ "license": "MIT",
+ "peerDependencies": {
+ "@types/react": "^19.0.0"
}
},
"node_modules/@types/unist": {
@@ -2667,147 +2561,604 @@
"integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==",
"license": "MIT"
},
+ "node_modules/@typescript-eslint/eslint-plugin": {
+ "version": "8.39.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.39.0.tgz",
+ "integrity": "sha512-bhEz6OZeUR+O/6yx9Jk6ohX6H9JSFTaiY0v9/PuKT3oGK0rn0jNplLmyFUGV+a9gfYnVNwGDwS/UkLIuXNb2Rw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@eslint-community/regexpp": "^4.10.0",
+ "@typescript-eslint/scope-manager": "8.39.0",
+ "@typescript-eslint/type-utils": "8.39.0",
+ "@typescript-eslint/utils": "8.39.0",
+ "@typescript-eslint/visitor-keys": "8.39.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.39.0",
+ "eslint": "^8.57.0 || ^9.0.0",
+ "typescript": ">=4.8.4 <6.0.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": "6.21.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz",
- "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==",
+ "version": "8.39.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.39.0.tgz",
+ "integrity": "sha512-g3WpVQHngx0aLXn6kfIYCZxM6rRJlWzEkVpqEFLT3SgEDsp9cpCbxxgwnE504q4H+ruSDh/VGS6nqZIDynP+vg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/scope-manager": "8.39.0",
+ "@typescript-eslint/types": "8.39.0",
+ "@typescript-eslint/typescript-estree": "8.39.0",
+ "@typescript-eslint/visitor-keys": "8.39.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 <6.0.0"
+ }
+ },
+ "node_modules/@typescript-eslint/project-service": {
+ "version": "8.39.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.39.0.tgz",
+ "integrity": "sha512-CTzJqaSq30V/Z2Og9jogzZt8lJRR5TKlAdXmWgdu4hgcC9Kww5flQ+xFvMxIBWVNdxJO7OifgdOK4PokMIWPew==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/tsconfig-utils": "^8.39.0",
+ "@typescript-eslint/types": "^8.39.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": {
+ "typescript": ">=4.8.4 <6.0.0"
+ }
+ },
+ "node_modules/@typescript-eslint/scope-manager": {
+ "version": "8.39.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.39.0.tgz",
+ "integrity": "sha512-8QOzff9UKxOh6npZQ/4FQu4mjdOCGSdO3p44ww0hk8Vu+IGbg0tB/H1LcTARRDzGCC8pDGbh2rissBuuoPgH8A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "8.39.0",
+ "@typescript-eslint/visitor-keys": "8.39.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.39.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.39.0.tgz",
+ "integrity": "sha512-Fd3/QjmFV2sKmvv3Mrj8r6N8CryYiCS8Wdb/6/rgOXAWGcFuc+VkQuG28uk/4kVNVZBQuuDHEDUpo/pQ32zsIQ==",
+ "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 <6.0.0"
+ }
+ },
+ "node_modules/@typescript-eslint/type-utils": {
+ "version": "8.39.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.39.0.tgz",
+ "integrity": "sha512-6B3z0c1DXVT2vYA9+z9axjtc09rqKUPRmijD5m9iv8iQpHBRYRMBcgxSiKTZKm6FwWw1/cI4v6em35OsKCiN5Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/types": "8.39.0",
+ "@typescript-eslint/typescript-estree": "8.39.0",
+ "@typescript-eslint/utils": "8.39.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 <6.0.0"
+ }
+ },
+ "node_modules/@typescript-eslint/types": {
+ "version": "8.39.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.39.0.tgz",
+ "integrity": "sha512-ArDdaOllnCj3yn/lzKn9s0pBQYmmyme/v1HbGIGB0GB/knFI3fWMHloC+oYTJW46tVbYnGKTMDK4ah1sC2v0Kg==",
+ "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.39.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.39.0.tgz",
+ "integrity": "sha512-ndWdiflRMvfIgQRpckQQLiB5qAKQ7w++V4LlCHwp62eym1HLB/kw7D9f2e8ytONls/jt89TEasgvb+VwnRprsw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@typescript-eslint/project-service": "8.39.0",
+ "@typescript-eslint/tsconfig-utils": "8.39.0",
+ "@typescript-eslint/types": "8.39.0",
+ "@typescript-eslint/visitor-keys": "8.39.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 <6.0.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/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/@typescript-eslint/typescript-estree/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/@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/utils": {
+ "version": "8.39.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.39.0.tgz",
+ "integrity": "sha512-4GVSvNA0Vx1Ktwvf4sFE+exxJ3QGUorQG1/A5mRfRNZtkBT2xrA/BCO2H0eALx/PnvCS6/vmYwRdDA41EoffkQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@typescript-eslint/scope-manager": "6.21.0",
- "@typescript-eslint/types": "6.21.0",
- "@typescript-eslint/typescript-estree": "6.21.0",
- "@typescript-eslint/visitor-keys": "6.21.0",
- "debug": "^4.3.4"
+ "@eslint-community/eslint-utils": "^4.7.0",
+ "@typescript-eslint/scope-manager": "8.39.0",
+ "@typescript-eslint/types": "8.39.0",
+ "@typescript-eslint/typescript-estree": "8.39.0"
},
"engines": {
- "node": "^16.0.0 || >=18.0.0"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
- "eslint": "^7.0.0 || ^8.0.0"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
+ "eslint": "^8.57.0 || ^9.0.0",
+ "typescript": ">=4.8.4 <6.0.0"
}
},
- "node_modules/@typescript-eslint/scope-manager": {
- "version": "6.21.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz",
- "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==",
+ "node_modules/@typescript-eslint/visitor-keys": {
+ "version": "8.39.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.39.0.tgz",
+ "integrity": "sha512-ldgiJ+VAhQCfIjeOgu8Kj5nSxds0ktPOSO9p4+0VDH2R2pLvQraaM5Oen2d7NxzMCm+Sn/vJT+mv2H5u6b/3fA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@typescript-eslint/types": "6.21.0",
- "@typescript-eslint/visitor-keys": "6.21.0"
+ "@typescript-eslint/types": "8.39.0",
+ "eslint-visitor-keys": "^4.2.1"
},
"engines": {
- "node": "^16.0.0 || >=18.0.0"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
- "node_modules/@typescript-eslint/types": {
- "version": "6.21.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz",
- "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==",
+ "node_modules/@typescript-eslint/visitor-keys/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": "^16.0.0 || >=18.0.0"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
+ "url": "https://opencollective.com/eslint"
}
},
- "node_modules/@typescript-eslint/typescript-estree": {
- "version": "6.21.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz",
- "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==",
+ "node_modules/@ungap/structured-clone": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
+ "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ=="
+ },
+ "node_modules/@unrs/resolver-binding-android-arm-eabi": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.11.1.tgz",
+ "integrity": "sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==",
+ "cpu": [
+ "arm"
+ ],
"dev": true,
- "dependencies": {
- "@typescript-eslint/types": "6.21.0",
- "@typescript-eslint/visitor-keys": "6.21.0",
- "debug": "^4.3.4",
- "globby": "^11.1.0",
- "is-glob": "^4.0.3",
- "minimatch": "9.0.3",
- "semver": "^7.5.4",
- "ts-api-utils": "^1.0.1"
- },
- "engines": {
- "node": "^16.0.0 || >=18.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
- },
- "peerDependenciesMeta": {
- "typescript": {
- "optional": true
- }
- }
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
},
- "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/@unrs/resolver-binding-android-arm64": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.11.1.tgz",
+ "integrity": "sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==",
+ "cpu": [
+ "arm64"
+ ],
"dev": true,
- "dependencies": {
- "balanced-match": "^1.0.0"
- }
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "android"
+ ]
},
- "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
- "version": "9.0.3",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz",
- "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==",
+ "node_modules/@unrs/resolver-binding-darwin-arm64": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.11.1.tgz",
+ "integrity": "sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-darwin-x64": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.11.1.tgz",
+ "integrity": "sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "darwin"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-freebsd-x64": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.11.1.tgz",
+ "integrity": "sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "freebsd"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.11.1.tgz",
+ "integrity": "sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.11.1.tgz",
+ "integrity": "sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-linux-arm64-gnu": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.11.1.tgz",
+ "integrity": "sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-linux-arm64-musl": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.11.1.tgz",
+ "integrity": "sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.11.1.tgz",
+ "integrity": "sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.11.1.tgz",
+ "integrity": "sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-linux-riscv64-musl": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.11.1.tgz",
+ "integrity": "sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==",
+ "cpu": [
+ "riscv64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-linux-s390x-gnu": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.11.1.tgz",
+ "integrity": "sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-linux-x64-gnu": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.11.1.tgz",
+ "integrity": "sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-linux-x64-musl": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.11.1.tgz",
+ "integrity": "sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-wasm32-wasi": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.11.1.tgz",
+ "integrity": "sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==",
+ "cpu": [
+ "wasm32"
+ ],
"dev": true,
+ "license": "MIT",
+ "optional": true,
"dependencies": {
- "brace-expansion": "^2.0.1"
+ "@napi-rs/wasm-runtime": "^0.2.11"
},
"engines": {
- "node": ">=16 || 14 >=14.17"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
+ "node": ">=14.0.0"
}
},
- "node_modules/@typescript-eslint/visitor-keys": {
- "version": "6.21.0",
- "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz",
- "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==",
+ "node_modules/@unrs/resolver-binding-win32-arm64-msvc": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.11.1.tgz",
+ "integrity": "sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-win32-ia32-msvc": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.11.1.tgz",
+ "integrity": "sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==",
+ "cpu": [
+ "ia32"
+ ],
+ "dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@unrs/resolver-binding-win32-x64-msvc": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.11.1.tgz",
+ "integrity": "sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==",
+ "cpu": [
+ "x64"
+ ],
"dev": true,
+ "license": "MIT",
+ "optional": true,
+ "os": [
+ "win32"
+ ]
+ },
+ "node_modules/@vercel/og": {
+ "version": "0.8.5",
+ "resolved": "https://registry.npmjs.org/@vercel/og/-/og-0.8.5.tgz",
+ "integrity": "sha512-fHqnxfBYcwkamlEgcIzaZqL8IHT09hR7FZL7UdMTdGJyoaBzM/dY6ulO5Swi4ig30FrBJI9I2C+GLV9sb9vexA==",
+ "license": "MPL-2.0",
"dependencies": {
- "@typescript-eslint/types": "6.21.0",
- "eslint-visitor-keys": "^3.4.1"
+ "@resvg/resvg-wasm": "2.4.0",
+ "satori": "0.16.0"
},
"engines": {
- "node": "^16.0.0 || >=18.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/typescript-eslint"
+ "node": ">=16"
}
},
- "node_modules/@ungap/structured-clone": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
- "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ=="
- },
"node_modules/abbrev": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
},
"node_modules/acorn": {
- "version": "8.11.3",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz",
- "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==",
+ "version": "8.15.0",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
+ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
+ "license": "MIT",
"bin": {
"acorn": "bin/acorn"
},
@@ -2841,6 +3192,7 @@
"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",
@@ -2853,11 +3205,15 @@
}
},
"node_modules/ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz",
+ "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==",
+ "license": "MIT",
"engines": {
- "node": ">=8"
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-regex?sponsor=1"
}
},
"node_modules/ansi-styles": {
@@ -2877,12 +3233,14 @@
"node_modules/any-promise": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
- "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A=="
+ "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==",
+ "license": "MIT"
},
"node_modules/anymatch": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "license": "ISC",
"dependencies": {
"normalize-path": "^3.0.0",
"picomatch": "^2.0.4"
@@ -2894,18 +3252,21 @@
"node_modules/arg": {
"version": "5.0.2",
"resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
- "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg=="
+ "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==",
+ "license": "MIT"
},
"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
+ "dev": true,
+ "license": "Python-2.0"
},
"node_modules/aria-hidden": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.4.tgz",
- "integrity": "sha512-y+CcFFwelSXpLZk/7fMB2mUbGtX9lKycf1MWJ7CaTIERyitVlyQx6C+sxcROU2BAJ24OiZyK+8wj2i8AlBoS3A==",
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz",
+ "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==",
+ "license": "MIT",
"dependencies": {
"tslib": "^2.0.0"
},
@@ -2914,22 +3275,24 @@
}
},
"node_modules/aria-query": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
- "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
+ "version": "5.3.2",
+ "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz",
+ "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==",
"dev": true,
- "dependencies": {
- "dequal": "^2.0.3"
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">= 0.4"
}
},
"node_modules/array-buffer-byte-length": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz",
- "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==",
+ "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-bind": "^1.0.5",
- "is-array-buffer": "^3.0.4"
+ "call-bound": "^1.0.3",
+ "is-array-buffer": "^3.0.5"
},
"engines": {
"node": ">= 0.4"
@@ -2939,17 +3302,20 @@
}
},
"node_modules/array-includes": {
- "version": "3.1.8",
- "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz",
- "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==",
+ "version": "3.1.9",
+ "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.9.tgz",
+ "integrity": "sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "call-bind": "^1.0.7",
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.4",
"define-properties": "^1.2.1",
- "es-abstract": "^1.23.2",
- "es-object-atoms": "^1.0.0",
- "get-intrinsic": "^1.2.4",
- "is-string": "^1.0.7"
+ "es-abstract": "^1.24.0",
+ "es-object-atoms": "^1.1.1",
+ "get-intrinsic": "^1.3.0",
+ "is-string": "^1.1.1",
+ "math-intrinsics": "^1.1.0"
},
"engines": {
"node": ">= 0.4"
@@ -2958,20 +3324,12 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/array-union": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
- "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/array.prototype.findlast": {
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz",
"integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bind": "^1.0.7",
"define-properties": "^1.2.1",
@@ -2988,17 +3346,19 @@
}
},
"node_modules/array.prototype.findlastindex": {
- "version": "1.2.5",
- "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz",
- "integrity": "sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ==",
+ "version": "1.2.6",
+ "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.6.tgz",
+ "integrity": "sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "call-bind": "^1.0.7",
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.4",
"define-properties": "^1.2.1",
- "es-abstract": "^1.23.2",
+ "es-abstract": "^1.23.9",
"es-errors": "^1.3.0",
- "es-object-atoms": "^1.0.0",
- "es-shim-unscopables": "^1.0.2"
+ "es-object-atoms": "^1.1.1",
+ "es-shim-unscopables": "^1.1.0"
},
"engines": {
"node": ">= 0.4"
@@ -3008,15 +3368,16 @@
}
},
"node_modules/array.prototype.flat": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz",
- "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==",
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz",
+ "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.2.0",
- "es-abstract": "^1.22.1",
- "es-shim-unscopables": "^1.0.0"
+ "call-bind": "^1.0.8",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.5",
+ "es-shim-unscopables": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
@@ -3026,15 +3387,16 @@
}
},
"node_modules/array.prototype.flatmap": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz",
- "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==",
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz",
+ "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.2.0",
- "es-abstract": "^1.22.1",
- "es-shim-unscopables": "^1.0.0"
+ "call-bind": "^1.0.8",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.5",
+ "es-shim-unscopables": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
@@ -3043,45 +3405,37 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/array.prototype.toreversed": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/array.prototype.toreversed/-/array.prototype.toreversed-1.1.2.tgz",
- "integrity": "sha512-wwDCoT4Ck4Cz7sLtgUmzR5UV3YF5mFHUlbChCzZBQZ+0m2cl/DH3tKgvphv1nKgFsJ48oCSg6p91q2Vm0I/ZMA==",
- "dev": true,
- "dependencies": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.2.0",
- "es-abstract": "^1.22.1",
- "es-shim-unscopables": "^1.0.0"
- }
- },
"node_modules/array.prototype.tosorted": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.3.tgz",
- "integrity": "sha512-/DdH4TiTmOKzyQbp/eadcCVexiCb36xJg7HshYOYJnNZFDj33GEv0P7GxsynpShhq4OLYJzbGcBDkLsDt7MnNg==",
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz",
+ "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "call-bind": "^1.0.5",
+ "call-bind": "^1.0.7",
"define-properties": "^1.2.1",
- "es-abstract": "^1.22.3",
- "es-errors": "^1.1.0",
+ "es-abstract": "^1.23.3",
+ "es-errors": "^1.3.0",
"es-shim-unscopables": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
}
},
"node_modules/arraybuffer.prototype.slice": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz",
- "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==",
+ "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.5",
+ "call-bind": "^1.0.8",
"define-properties": "^1.2.1",
- "es-abstract": "^1.22.3",
- "es-errors": "^1.2.1",
- "get-intrinsic": "^1.2.3",
- "is-array-buffer": "^3.0.4",
- "is-shared-array-buffer": "^1.0.2"
+ "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"
@@ -3094,7 +3448,8 @@
"version": "0.0.8",
"resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz",
"integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/astring": {
"version": "1.8.6",
@@ -3104,10 +3459,20 @@
"astring": "bin/astring"
}
},
+ "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/autoprefixer": {
- "version": "10.4.20",
- "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.20.tgz",
- "integrity": "sha512-XY25y5xSv/wEoqzDyXXME4AFfkZI0P23z6Fs3YgymDnKJkCGOnkL0iTxCa85UTqaSgfcqyf3UA6+c7wUvx/16g==",
+ "version": "10.4.21",
+ "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz",
+ "integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==",
"dev": true,
"funding": [
{
@@ -3123,12 +3488,13 @@
"url": "https://github.com/sponsors/ai"
}
],
+ "license": "MIT",
"dependencies": {
- "browserslist": "^4.23.3",
- "caniuse-lite": "^1.0.30001646",
+ "browserslist": "^4.24.4",
+ "caniuse-lite": "^1.0.30001702",
"fraction.js": "^4.3.7",
"normalize-range": "^0.1.2",
- "picocolors": "^1.0.1",
+ "picocolors": "^1.1.1",
"postcss-value-parser": "^4.2.0"
},
"bin": {
@@ -3157,21 +3523,23 @@
}
},
"node_modules/axe-core": {
- "version": "4.7.0",
- "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.7.0.tgz",
- "integrity": "sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==",
+ "version": "4.10.3",
+ "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.10.3.tgz",
+ "integrity": "sha512-Xm7bpRXnDSX2YE2YFfBk2FnF0ep6tmG7xPh8iHee8MIcrgq762Nkce856dYtJYLkuIoYZvGfTs/PbZhideTcEg==",
"dev": true,
+ "license": "MPL-2.0",
"engines": {
"node": ">=4"
}
},
"node_modules/axobject-query": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz",
- "integrity": "sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==",
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz",
+ "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==",
"dev": true,
- "dependencies": {
- "dequal": "^2.0.3"
+ "license": "Apache-2.0",
+ "engines": {
+ "node": ">= 0.4"
}
},
"node_modules/bail": {
@@ -3188,6 +3556,15 @@
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
},
+ "node_modules/base64-js": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz",
+ "integrity": "sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
"node_modules/bhttp": {
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/bhttp/-/bhttp-1.2.8.tgz",
@@ -3231,6 +3608,7 @@
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
"integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
+ "license": "MIT",
"engines": {
"node": ">=8"
},
@@ -3368,9 +3746,9 @@
}
},
"node_modules/browserslist": {
- "version": "4.23.3",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.3.tgz",
- "integrity": "sha512-btwCFJVjI4YWDNfau8RhZ+B1Q/VLoUITrm3RlP6y1tYGWIOa+InuYiRGXUBXo8nA1qKmHMyLB/iVQg5TT4eFoA==",
+ "version": "4.25.1",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.1.tgz",
+ "integrity": "sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==",
"dev": true,
"funding": [
{
@@ -3386,11 +3764,12 @@
"url": "https://github.com/sponsors/ai"
}
],
+ "license": "MIT",
"dependencies": {
- "caniuse-lite": "^1.0.30001646",
- "electron-to-chromium": "^1.5.4",
- "node-releases": "^2.0.18",
- "update-browserslist-db": "^1.1.0"
+ "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"
@@ -3404,28 +3783,46 @@
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
},
- "node_modules/busboy": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz",
- "integrity": "sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==",
+ "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": {
- "streamsearch": "^1.1.0"
+ "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": ">=10.16.0"
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/call-bind": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
- "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
- "dev": true,
+ "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==",
+ "license": "MIT",
"dependencies": {
- "es-define-property": "^1.0.0",
"es-errors": "^1.3.0",
- "function-bind": "^1.1.2",
- "get-intrinsic": "^1.2.4",
- "set-function-length": "^1.2.1"
+ "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==",
+ "license": "MIT",
+ "dependencies": {
+ "call-bind-apply-helpers": "^1.0.2",
+ "get-intrinsic": "^1.3.0"
},
"engines": {
"node": ">= 0.4"
@@ -3458,6 +3855,7 @@
"resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz",
"integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=6"
}
@@ -3480,14 +3878,24 @@
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
"integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
+ "license": "MIT",
"engines": {
"node": ">= 6"
}
},
+ "node_modules/camelize": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz",
+ "integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/caniuse-lite": {
- "version": "1.0.30001710",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001710.tgz",
- "integrity": "sha512-B5C0I0UmaGqHgo5FuqJ7hBd4L57A4dDD+Xi+XX1nXOoxGeDdY4Ko38qJYOyqznBVJEqON5p8P1x5zRR3+rsnxA==",
+ "version": "1.0.30001731",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001731.tgz",
+ "integrity": "sha512-lDdp2/wrOmTRWuoB5DpfNkC0rJDU8DqRa6nYL6HK6sytw70QMopt/NIc/9SM7ylItlBWfACXk0tEn37UWM/+mg==",
"funding": [
{
"type": "opencollective",
@@ -3574,6 +3982,7 @@
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
+ "license": "MIT",
"dependencies": {
"anymatch": "~3.1.2",
"braces": "~3.0.2",
@@ -3597,6 +4006,7 @@
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "license": "ISC",
"dependencies": {
"is-glob": "^4.0.1"
},
@@ -3605,22 +4015,15 @@
}
},
"node_modules/class-variance-authority": {
- "version": "0.7.0",
- "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.0.tgz",
- "integrity": "sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A==",
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz",
+ "integrity": "sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==",
+ "license": "Apache-2.0",
"dependencies": {
- "clsx": "2.0.0"
+ "clsx": "^2.1.1"
},
"funding": {
- "url": "https://joebell.co.uk"
- }
- },
- "node_modules/class-variance-authority/node_modules/clsx": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.0.0.tgz",
- "integrity": "sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==",
- "engines": {
- "node": ">=6"
+ "url": "https://polar.sh/cva"
}
},
"node_modules/cli-table": {
@@ -3637,7 +4040,8 @@
"node_modules/client-only": {
"version": "0.0.1",
"resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz",
- "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA=="
+ "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==",
+ "license": "MIT"
},
"node_modules/clsx": {
"version": "2.1.1",
@@ -3663,62 +4067,6 @@
"react-dom": "^18 || ^19 || ^19.0.0-rc"
}
},
- "node_modules/cmdk/node_modules/@radix-ui/react-compose-refs": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
- "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==",
- "license": "MIT",
- "peerDependencies": {
- "@types/react": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- }
- }
- },
- "node_modules/cmdk/node_modules/@radix-ui/react-primitive": {
- "version": "2.1.3",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz",
- "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==",
- "license": "MIT",
- "dependencies": {
- "@radix-ui/react-slot": "1.2.3"
- },
- "peerDependencies": {
- "@types/react": "*",
- "@types/react-dom": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
- "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- },
- "@types/react-dom": {
- "optional": true
- }
- }
- },
- "node_modules/cmdk/node_modules/@radix-ui/react-slot": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz",
- "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==",
- "license": "MIT",
- "dependencies": {
- "@radix-ui/react-compose-refs": "1.1.2"
- },
- "peerDependencies": {
- "@types/react": "*",
- "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
- },
- "peerDependenciesMeta": {
- "@types/react": {
- "optional": true
- }
- }
- },
"node_modules/collapse-white-space": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-2.1.0.tgz",
@@ -3728,6 +4076,20 @@
"url": "https://github.com/sponsors/wooorm"
}
},
+ "node_modules/color": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
+ "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "color-convert": "^2.0.1",
+ "color-string": "^1.9.0"
+ },
+ "engines": {
+ "node": ">=12.5.0"
+ }
+ },
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
@@ -3744,6 +4106,17 @@
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
},
+ "node_modules/color-string": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/color-string/-/color-string-1.9.1.tgz",
+ "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "color-name": "^1.0.0",
+ "simple-swizzle": "^0.2.2"
+ }
+ },
"node_modules/colors": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz",
@@ -3788,6 +4161,7 @@
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz",
"integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==",
+ "license": "MIT",
"engines": {
"node": ">= 6"
}
@@ -3846,6 +4220,47 @@
"node": ">= 8"
}
},
+ "node_modules/css-background-parser": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/css-background-parser/-/css-background-parser-0.1.0.tgz",
+ "integrity": "sha512-2EZLisiZQ+7m4wwur/qiYJRniHX4K5Tc9w93MT3AS0WS1u5kaZ4FKXlOTBhOjc+CgEgPiGY+fX1yWD8UwpEqUA==",
+ "license": "MIT"
+ },
+ "node_modules/css-box-shadow": {
+ "version": "1.0.0-3",
+ "resolved": "https://registry.npmjs.org/css-box-shadow/-/css-box-shadow-1.0.0-3.tgz",
+ "integrity": "sha512-9jaqR6e7Ohds+aWwmhe6wILJ99xYQbfmK9QQB9CcMjDbTxPZjwEmUQpU91OG05Xgm8BahT5fW+svbsQGjS/zPg==",
+ "license": "MIT"
+ },
+ "node_modules/css-color-keywords": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz",
+ "integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==",
+ "license": "ISC",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/css-gradient-parser": {
+ "version": "0.0.16",
+ "resolved": "https://registry.npmjs.org/css-gradient-parser/-/css-gradient-parser-0.0.16.tgz",
+ "integrity": "sha512-3O5QdqgFRUbXvK1x5INf1YkBz1UKSWqrd63vWsum8MNHDBYD5urm3QtxZbKU259OrEXNM26lP/MPY3d1IGkBgA==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=16"
+ }
+ },
+ "node_modules/css-to-react-native": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz",
+ "integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==",
+ "license": "MIT",
+ "dependencies": {
+ "camelize": "^1.0.0",
+ "css-color-keywords": "^1.0.0",
+ "postcss-value-parser": "^4.0.2"
+ }
+ },
"node_modules/cssesc": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
@@ -3866,17 +4281,19 @@
"version": "1.0.8",
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz",
"integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==",
- "dev": true
+ "dev": true,
+ "license": "BSD-2-Clause"
},
"node_modules/data-view-buffer": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz",
- "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==",
+ "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-bind": "^1.0.6",
+ "call-bound": "^1.0.3",
"es-errors": "^1.3.0",
- "is-data-view": "^1.0.1"
+ "is-data-view": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
@@ -3886,29 +4303,31 @@
}
},
"node_modules/data-view-byte-length": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz",
- "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==",
+ "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-bind": "^1.0.7",
+ "call-bound": "^1.0.3",
"es-errors": "^1.3.0",
- "is-data-view": "^1.0.1"
+ "is-data-view": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
- "url": "https://github.com/sponsors/ljharb"
+ "url": "https://github.com/sponsors/inspect-js"
}
},
"node_modules/data-view-byte-offset": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz",
- "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==",
+ "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-bind": "^1.0.6",
+ "call-bound": "^1.0.2",
"es-errors": "^1.3.0",
"is-data-view": "^1.0.1"
},
@@ -4006,10 +4425,21 @@
"node": ">=6"
}
},
+ "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==",
+ "license": "Apache-2.0",
+ "optional": 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=="
+ "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==",
+ "license": "MIT"
},
"node_modules/dev-null": {
"version": "0.1.1",
@@ -4031,7 +4461,8 @@
"node_modules/didyoumean": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
- "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw=="
+ "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==",
+ "license": "Apache-2.0"
},
"node_modules/diff": {
"version": "4.0.2",
@@ -4043,33 +4474,37 @@
"node": ">=0.3.1"
}
},
- "node_modules/dir-glob": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
- "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==",
- "dev": true,
- "dependencies": {
- "path-type": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/dlv": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
- "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="
+ "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
+ "license": "MIT"
},
"node_modules/doctrine": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
- "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==",
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
+ "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
"dev": true,
+ "license": "Apache-2.0",
"dependencies": {
"esutils": "^2.0.2"
},
"engines": {
- "node": ">=6.0.0"
+ "node": ">=0.10.0"
+ }
+ },
+ "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==",
+ "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/duplexer": {
@@ -4080,30 +4515,29 @@
"node_modules/eastasianwidth": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
- "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="
+ "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==",
+ "license": "MIT"
},
"node_modules/electron-to-chromium": {
- "version": "1.5.13",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.13.tgz",
- "integrity": "sha512-lbBcvtIJ4J6sS4tb5TLp1b4LyfCdMkwStzXPyAgVgTRAsep4bvrAGaBOP7ZJtQMNJpSQ9SqG4brWOroNaQtm7Q==",
- "dev": true
+ "version": "1.5.199",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.199.tgz",
+ "integrity": "sha512-3gl0S7zQd88kCAZRO/DnxtBKuhMO4h0EaQIN3YgZfV6+pW+5+bf2AdQeHNESCoaQqo/gjGVYEf2YM4O5HJQqpQ==",
+ "dev": true,
+ "license": "ISC"
},
"node_modules/emoji-regex": {
"version": "9.2.2",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz",
- "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg=="
+ "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==",
+ "license": "MIT"
},
- "node_modules/enhanced-resolve": {
- "version": "5.16.0",
- "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz",
- "integrity": "sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA==",
- "dev": true,
- "dependencies": {
- "graceful-fs": "^4.2.4",
- "tapable": "^2.2.0"
- },
+ "node_modules/emoji-regex-xs": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/emoji-regex-xs/-/emoji-regex-xs-2.0.1.tgz",
+ "integrity": "sha512-1QFuh8l7LqUcKe24LsPUNzjrzJQ7pgRwp1QMcZ5MX6mFplk2zQ08NVCM84++1cveaUUYtcCYHmeFEuNg16sU4g==",
+ "license": "MIT",
"engines": {
- "node": ">=10.13.0"
+ "node": ">=10.0.0"
}
},
"node_modules/entities": {
@@ -4142,57 +4576,66 @@
}
},
"node_modules/es-abstract": {
- "version": "1.23.3",
- "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz",
- "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==",
+ "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.1",
- "arraybuffer.prototype.slice": "^1.0.3",
+ "array-buffer-byte-length": "^1.0.2",
+ "arraybuffer.prototype.slice": "^1.0.4",
"available-typed-arrays": "^1.0.7",
- "call-bind": "^1.0.7",
- "data-view-buffer": "^1.0.1",
- "data-view-byte-length": "^1.0.1",
- "data-view-byte-offset": "^1.0.0",
- "es-define-property": "^1.0.0",
+ "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.0.0",
- "es-set-tostringtag": "^2.0.3",
- "es-to-primitive": "^1.2.1",
- "function.prototype.name": "^1.1.6",
- "get-intrinsic": "^1.2.4",
- "get-symbol-description": "^1.0.2",
- "globalthis": "^1.0.3",
- "gopd": "^1.0.1",
+ "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.0.3",
- "has-symbols": "^1.0.3",
+ "has-proto": "^1.2.0",
+ "has-symbols": "^1.1.0",
"hasown": "^2.0.2",
- "internal-slot": "^1.0.7",
- "is-array-buffer": "^3.0.4",
+ "internal-slot": "^1.1.0",
+ "is-array-buffer": "^3.0.5",
"is-callable": "^1.2.7",
- "is-data-view": "^1.0.1",
+ "is-data-view": "^1.0.2",
"is-negative-zero": "^2.0.3",
- "is-regex": "^1.1.4",
- "is-shared-array-buffer": "^1.0.3",
- "is-string": "^1.0.7",
- "is-typed-array": "^1.1.13",
- "is-weakref": "^1.0.2",
- "object-inspect": "^1.13.1",
+ "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.5",
- "regexp.prototype.flags": "^1.5.2",
- "safe-array-concat": "^1.1.2",
- "safe-regex-test": "^1.0.3",
- "string.prototype.trim": "^1.2.9",
- "string.prototype.trimend": "^1.0.8",
+ "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.2",
- "typed-array-byte-length": "^1.0.1",
- "typed-array-byte-offset": "^1.0.2",
- "typed-array-length": "^1.0.6",
- "unbox-primitive": "^1.0.2",
- "which-typed-array": "^1.1.15"
+ "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"
@@ -4202,13 +4645,10 @@
}
},
"node_modules/es-define-property": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
- "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
- "dev": true,
- "dependencies": {
- "get-intrinsic": "^1.2.4"
- },
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz",
+ "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==",
+ "license": "MIT",
"engines": {
"node": ">= 0.4"
}
@@ -4217,41 +4657,43 @@
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
"integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
- "dev": true,
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-iterator-helpers": {
- "version": "1.0.18",
- "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.18.tgz",
- "integrity": "sha512-scxAJaewsahbqTYrGKJihhViaM6DDZDDoucfvzNbK0pOren1g/daDQ3IAhzn+1G14rBG7w+i5N+qul60++zlKA==",
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.2.1.tgz",
+ "integrity": "sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "call-bind": "^1.0.7",
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.3",
"define-properties": "^1.2.1",
- "es-abstract": "^1.23.0",
+ "es-abstract": "^1.23.6",
"es-errors": "^1.3.0",
"es-set-tostringtag": "^2.0.3",
"function-bind": "^1.1.2",
- "get-intrinsic": "^1.2.4",
- "globalthis": "^1.0.3",
+ "get-intrinsic": "^1.2.6",
+ "globalthis": "^1.0.4",
+ "gopd": "^1.2.0",
"has-property-descriptors": "^1.0.2",
- "has-proto": "^1.0.3",
- "has-symbols": "^1.0.3",
- "internal-slot": "^1.0.7",
- "iterator.prototype": "^1.1.2",
- "safe-array-concat": "^1.1.2"
+ "has-proto": "^1.2.0",
+ "has-symbols": "^1.1.0",
+ "internal-slot": "^1.1.0",
+ "iterator.prototype": "^1.1.4",
+ "safe-array-concat": "^1.1.3"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-object-atoms": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz",
- "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==",
- "dev": true,
+ "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==",
+ "license": "MIT",
"dependencies": {
"es-errors": "^1.3.0"
},
@@ -4260,37 +4702,44 @@
}
},
"node_modules/es-set-tostringtag": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz",
- "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==",
+ "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": {
- "get-intrinsic": "^1.2.4",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.6",
"has-tostringtag": "^1.0.2",
- "hasown": "^2.0.1"
+ "hasown": "^2.0.2"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/es-shim-unscopables": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz",
- "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==",
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz",
+ "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "hasown": "^2.0.0"
+ "hasown": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
}
},
"node_modules/es-to-primitive": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
- "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
+ "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.1.4",
- "is-date-object": "^1.0.1",
- "is-symbol": "^1.0.2"
+ "is-callable": "^1.2.7",
+ "is-date-object": "^1.0.5",
+ "is-symbol": "^1.0.4"
},
"engines": {
"node": ">= 0.4"
@@ -4341,14 +4790,21 @@
}
},
"node_modules/escalade": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz",
- "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==",
+ "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-html": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+ "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
+ "license": "MIT"
+ },
"node_modules/escape-string-regexp": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
@@ -4362,78 +4818,86 @@
}
},
"node_modules/eslint": {
- "version": "8.57.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz",
- "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==",
+ "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.6.1",
- "@eslint/eslintrc": "^2.1.4",
- "@eslint/js": "8.57.0",
- "@humanwhocodes/config-array": "^0.11.14",
+ "@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",
- "@nodelib/fs.walk": "^1.2.8",
- "@ungap/structured-clone": "^1.2.0",
+ "@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.2",
+ "cross-spawn": "^7.0.6",
"debug": "^4.3.2",
- "doctrine": "^3.0.0",
"escape-string-regexp": "^4.0.0",
- "eslint-scope": "^7.2.2",
- "eslint-visitor-keys": "^3.4.3",
- "espree": "^9.6.1",
- "esquery": "^1.4.2",
+ "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": "^6.0.1",
+ "file-entry-cache": "^8.0.0",
"find-up": "^5.0.0",
"glob-parent": "^6.0.2",
- "globals": "^13.19.0",
- "graphemer": "^1.4.0",
"ignore": "^5.2.0",
"imurmurhash": "^0.1.4",
"is-glob": "^4.0.0",
- "is-path-inside": "^3.0.3",
- "js-yaml": "^4.1.0",
"json-stable-stringify-without-jsonify": "^1.0.1",
- "levn": "^0.4.1",
"lodash.merge": "^4.6.2",
"minimatch": "^3.1.2",
"natural-compare": "^1.4.0",
- "optionator": "^0.9.3",
- "strip-ansi": "^6.0.1",
- "text-table": "^0.2.0"
+ "optionator": "^0.9.3"
},
"bin": {
"eslint": "bin/eslint.js"
},
"engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
- "url": "https://opencollective.com/eslint"
+ "url": "https://eslint.org/donate"
+ },
+ "peerDependencies": {
+ "jiti": "*"
+ },
+ "peerDependenciesMeta": {
+ "jiti": {
+ "optional": true
+ }
}
},
"node_modules/eslint-config-next": {
- "version": "14.2.6",
- "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-14.2.6.tgz",
- "integrity": "sha512-z0URA5LO6y8lS/YLN0EDW/C4LEkDODjJzA37dvLVdzCPzuewjzTe1os5g3XclZAZrQ8X8hPaSMQ2JuVWwMmrTA==",
+ "version": "15.4.6",
+ "resolved": "https://registry.npmjs.org/eslint-config-next/-/eslint-config-next-15.4.6.tgz",
+ "integrity": "sha512-4uznvw5DlTTjrZgYZjMciSdDDMO2SWIuQgUNaFyC2O3Zw3Z91XeIejeVa439yRq2CnJb/KEvE4U2AeN/66FpUA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@next/eslint-plugin-next": "14.2.6",
- "@rushstack/eslint-patch": "^1.3.3",
- "@typescript-eslint/parser": "^5.4.2 || ^6.0.0 || 7.0.0 - 7.2.0",
+ "@next/eslint-plugin-next": "15.4.6",
+ "@rushstack/eslint-patch": "^1.10.3",
+ "@typescript-eslint/eslint-plugin": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0",
+ "@typescript-eslint/parser": "^5.4.2 || ^6.0.0 || ^7.0.0 || ^8.0.0",
"eslint-import-resolver-node": "^0.3.6",
"eslint-import-resolver-typescript": "^3.5.2",
- "eslint-plugin-import": "^2.28.1",
- "eslint-plugin-jsx-a11y": "^6.7.1",
- "eslint-plugin-react": "^7.33.2",
- "eslint-plugin-react-hooks": "^4.5.0 || 5.0.0-canary-7118f5dd7-20230705"
+ "eslint-plugin-import": "^2.31.0",
+ "eslint-plugin-jsx-a11y": "^6.10.0",
+ "eslint-plugin-react": "^7.37.0",
+ "eslint-plugin-react-hooks": "^5.0.0"
},
"peerDependencies": {
- "eslint": "^7.23.0 || ^8.0.0",
+ "eslint": "^7.23.0 || ^8.0.0 || ^9.0.0",
"typescript": ">=3.3.1"
},
"peerDependenciesMeta": {
@@ -4463,35 +4927,71 @@
}
},
"node_modules/eslint-import-resolver-typescript": {
- "version": "3.6.1",
- "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.6.1.tgz",
- "integrity": "sha512-xgdptdoi5W3niYeuQxKmzVDTATvLYqhpwmykwsh7f6HIOStGWEIL9iqZgQDF9u9OEzrRwR8no5q2VT+bjAujTg==",
+ "version": "3.10.1",
+ "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.1.tgz",
+ "integrity": "sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==",
"dev": true,
+ "license": "ISC",
"dependencies": {
- "debug": "^4.3.4",
- "enhanced-resolve": "^5.12.0",
- "eslint-module-utils": "^2.7.4",
- "fast-glob": "^3.3.1",
- "get-tsconfig": "^4.5.0",
- "is-core-module": "^2.11.0",
- "is-glob": "^4.0.3"
+ "@nolyfill/is-core-module": "1.0.39",
+ "debug": "^4.4.0",
+ "get-tsconfig": "^4.10.0",
+ "is-bun-module": "^2.0.0",
+ "stable-hash": "^0.0.5",
+ "tinyglobby": "^0.2.13",
+ "unrs-resolver": "^1.6.2"
},
"engines": {
"node": "^14.18.0 || >=16.0.0"
},
"funding": {
- "url": "https://opencollective.com/unts/projects/eslint-import-resolver-ts"
+ "url": "https://opencollective.com/eslint-import-resolver-typescript"
},
"peerDependencies": {
"eslint": "*",
- "eslint-plugin-import": "*"
+ "eslint-plugin-import": "*",
+ "eslint-plugin-import-x": "*"
+ },
+ "peerDependenciesMeta": {
+ "eslint-plugin-import": {
+ "optional": true
+ },
+ "eslint-plugin-import-x": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/eslint-import-resolver-typescript/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/eslint-import-resolver-typescript/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/eslint-module-utils": {
- "version": "2.8.1",
- "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz",
- "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==",
+ "version": "2.12.1",
+ "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.12.1.tgz",
+ "integrity": "sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"debug": "^3.2.7"
},
@@ -4514,34 +5014,37 @@
}
},
"node_modules/eslint-plugin-import": {
- "version": "2.29.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz",
- "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==",
+ "version": "2.32.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.32.0.tgz",
+ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "array-includes": "^3.1.7",
- "array.prototype.findlastindex": "^1.2.3",
- "array.prototype.flat": "^1.3.2",
- "array.prototype.flatmap": "^1.3.2",
+ "@rtsao/scc": "^1.1.0",
+ "array-includes": "^3.1.9",
+ "array.prototype.findlastindex": "^1.2.6",
+ "array.prototype.flat": "^1.3.3",
+ "array.prototype.flatmap": "^1.3.3",
"debug": "^3.2.7",
"doctrine": "^2.1.0",
"eslint-import-resolver-node": "^0.3.9",
- "eslint-module-utils": "^2.8.0",
- "hasown": "^2.0.0",
- "is-core-module": "^2.13.1",
+ "eslint-module-utils": "^2.12.1",
+ "hasown": "^2.0.2",
+ "is-core-module": "^2.16.1",
"is-glob": "^4.0.3",
"minimatch": "^3.1.2",
- "object.fromentries": "^2.0.7",
- "object.groupby": "^1.0.1",
- "object.values": "^1.1.7",
+ "object.fromentries": "^2.0.8",
+ "object.groupby": "^1.0.3",
+ "object.values": "^1.2.1",
"semver": "^6.3.1",
+ "string.prototype.trimend": "^1.0.9",
"tsconfig-paths": "^3.15.0"
},
"engines": {
"node": ">=4"
},
"peerDependencies": {
- "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8"
+ "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9"
}
},
"node_modules/eslint-plugin-import/node_modules/debug": {
@@ -4549,115 +5052,95 @@
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz",
"integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"ms": "^2.1.1"
}
},
- "node_modules/eslint-plugin-import/node_modules/doctrine": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
- "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
- "dev": true,
- "dependencies": {
- "esutils": "^2.0.2"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/eslint-plugin-import/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,
+ "license": "ISC",
"bin": {
"semver": "bin/semver.js"
}
},
"node_modules/eslint-plugin-jsx-a11y": {
- "version": "6.8.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.8.0.tgz",
- "integrity": "sha512-Hdh937BS3KdwwbBaKd5+PLCOmYY6U4f2h9Z2ktwtNKvIdIEu137rjYbcb9ApSbVJfWxANNuiKTD/9tOKjK9qOA==",
+ "version": "6.10.2",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz",
+ "integrity": "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@babel/runtime": "^7.23.2",
- "aria-query": "^5.3.0",
- "array-includes": "^3.1.7",
+ "aria-query": "^5.3.2",
+ "array-includes": "^3.1.8",
"array.prototype.flatmap": "^1.3.2",
"ast-types-flow": "^0.0.8",
- "axe-core": "=4.7.0",
- "axobject-query": "^3.2.1",
+ "axe-core": "^4.10.0",
+ "axobject-query": "^4.1.0",
"damerau-levenshtein": "^1.0.8",
"emoji-regex": "^9.2.2",
- "es-iterator-helpers": "^1.0.15",
- "hasown": "^2.0.0",
+ "hasown": "^2.0.2",
"jsx-ast-utils": "^3.3.5",
"language-tags": "^1.0.9",
"minimatch": "^3.1.2",
- "object.entries": "^1.1.7",
- "object.fromentries": "^2.0.7"
+ "object.fromentries": "^2.0.8",
+ "safe-regex-test": "^1.0.3",
+ "string.prototype.includes": "^2.0.1"
},
"engines": {
"node": ">=4.0"
},
"peerDependencies": {
- "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8"
+ "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9"
}
},
"node_modules/eslint-plugin-react": {
- "version": "7.34.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.1.tgz",
- "integrity": "sha512-N97CxlouPT1AHt8Jn0mhhN2RrADlUAsk1/atcT2KyA/l9Q/E6ll7OIGwNumFmWfZ9skV3XXccYS19h80rHtgkw==",
+ "version": "7.37.5",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz",
+ "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "array-includes": "^3.1.7",
- "array.prototype.findlast": "^1.2.4",
- "array.prototype.flatmap": "^1.3.2",
- "array.prototype.toreversed": "^1.1.2",
- "array.prototype.tosorted": "^1.1.3",
+ "array-includes": "^3.1.8",
+ "array.prototype.findlast": "^1.2.5",
+ "array.prototype.flatmap": "^1.3.3",
+ "array.prototype.tosorted": "^1.1.4",
"doctrine": "^2.1.0",
- "es-iterator-helpers": "^1.0.17",
+ "es-iterator-helpers": "^1.2.1",
"estraverse": "^5.3.0",
+ "hasown": "^2.0.2",
"jsx-ast-utils": "^2.4.1 || ^3.0.0",
"minimatch": "^3.1.2",
- "object.entries": "^1.1.7",
- "object.fromentries": "^2.0.7",
- "object.hasown": "^1.1.3",
- "object.values": "^1.1.7",
+ "object.entries": "^1.1.9",
+ "object.fromentries": "^2.0.8",
+ "object.values": "^1.2.1",
"prop-types": "^15.8.1",
"resolve": "^2.0.0-next.5",
"semver": "^6.3.1",
- "string.prototype.matchall": "^4.0.10"
+ "string.prototype.matchall": "^4.0.12",
+ "string.prototype.repeat": "^1.0.0"
},
"engines": {
"node": ">=4"
},
"peerDependencies": {
- "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8"
+ "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7"
}
},
"node_modules/eslint-plugin-react-hooks": {
- "version": "4.6.0",
- "resolved": "https://registry.npmjs.org/eslint-plugin-react-hooks/-/eslint-plugin-react-hooks-4.6.0.tgz",
- "integrity": "sha512-oFc7Itz9Qxh2x4gNHStv3BqJq54ExXmfC+a1NjAta66IAN87Wu0R/QArgIS9qKzX3dXKPI9H5crl9QchNMY9+g==",
+ "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"
- }
- },
- "node_modules/eslint-plugin-react/node_modules/doctrine": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
- "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
- "dev": true,
- "dependencies": {
- "esutils": "^2.0.2"
- },
- "engines": {
- "node": ">=0.10.0"
+ "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/node_modules/resolve": {
@@ -4665,6 +5148,7 @@
"resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.5.tgz",
"integrity": "sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"is-core-module": "^2.13.0",
"path-parse": "^1.0.7",
@@ -4682,21 +5166,23 @@
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
"integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
"dev": true,
+ "license": "ISC",
"bin": {
"semver": "bin/semver.js"
}
},
"node_modules/eslint-scope": {
- "version": "7.2.2",
- "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
- "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
+ "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": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
@@ -4714,18 +5200,45 @@
"url": "https://opencollective.com/eslint"
}
},
+ "node_modules/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": "9.6.1",
- "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
- "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
+ "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.9.0",
+ "acorn": "^8.15.0",
"acorn-jsx": "^5.3.2",
- "eslint-visitor-keys": "^3.4.1"
+ "eslint-visitor-keys": "^4.2.1"
},
"engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/espree/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"
@@ -4761,6 +5274,7 @@
"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"
},
@@ -4878,12 +5392,15 @@
"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
+ "dev": true,
+ "license": "MIT"
},
"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==",
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz",
+ "integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==",
+ "dev": true,
+ "license": "MIT",
"dependencies": {
"@nodelib/fs.stat": "^2.0.2",
"@nodelib/fs.walk": "^1.2.3",
@@ -4899,6 +5416,8 @@
"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"
},
@@ -4910,7 +5429,8 @@
"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
+ "dev": true,
+ "license": "MIT"
},
"node_modules/fast-levenshtein": {
"version": "2.0.6",
@@ -4919,23 +5439,31 @@
"dev": true
},
"node_modules/fastq": {
- "version": "1.17.1",
- "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
- "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
+ "version": "1.19.1",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz",
+ "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==",
+ "license": "ISC",
"dependencies": {
"reusify": "^1.0.4"
}
},
+ "node_modules/fflate": {
+ "version": "0.7.4",
+ "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.7.4.tgz",
+ "integrity": "sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==",
+ "license": "MIT"
+ },
"node_modules/file-entry-cache": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
- "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
+ "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": "^3.0.4"
+ "flat-cache": "^4.0.0"
},
"engines": {
- "node": "^10.12.0 || >=12.0.0"
+ "node": ">=16.0.0"
}
},
"node_modules/fill-range": {
@@ -4967,40 +5495,49 @@
}
},
"node_modules/flat-cache": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz",
- "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==",
+ "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": {
"flatted": "^3.2.9",
- "keyv": "^4.5.3",
- "rimraf": "^3.0.2"
+ "keyv": "^4.5.4"
},
"engines": {
- "node": "^10.12.0 || >=12.0.0"
+ "node": ">=16"
}
},
"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
+ "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.3",
- "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
- "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
+ "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": {
- "is-callable": "^1.1.3"
+ "is-callable": "^1.2.7"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/foreground-child": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz",
- "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==",
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz",
+ "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==",
+ "license": "ISC",
"dependencies": {
- "cross-spawn": "^7.0.0",
+ "cross-spawn": "^7.0.6",
"signal-exit": "^4.0.1"
},
"engines": {
@@ -5053,12 +5590,6 @@
"url": "https://github.com/sponsors/rawify"
}
},
- "node_modules/fs.realpath": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
- "dev": true
- },
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
@@ -5082,15 +5613,18 @@
}
},
"node_modules/function.prototype.name": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz",
- "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==",
+ "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": {
- "call-bind": "^1.0.2",
- "define-properties": "^1.2.0",
- "es-abstract": "^1.22.1",
- "functions-have-names": "^1.2.3"
+ "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": ">= 0.4"
@@ -5109,16 +5643,21 @@
}
},
"node_modules/get-intrinsic": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
- "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
- "dev": true,
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz",
+ "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==",
+ "license": "MIT",
"dependencies": {
+ "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",
- "has-proto": "^1.0.1",
- "has-symbols": "^1.0.3",
- "hasown": "^2.0.0"
+ "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": ">= 0.4"
@@ -5131,19 +5670,34 @@
"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",
+ "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==",
+ "license": "MIT",
+ "dependencies": {
+ "dunder-proto": "^1.0.1",
+ "es-object-atoms": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
"node_modules/get-symbol-description": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz",
- "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==",
+ "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": {
- "call-bind": "^1.0.5",
+ "call-bound": "^1.0.3",
"es-errors": "^1.3.0",
- "get-intrinsic": "^1.2.4"
+ "get-intrinsic": "^1.2.6"
},
"engines": {
"node": ">= 0.4"
@@ -5171,22 +5725,21 @@
"integrity": "sha512-IaOQ9puYtjrkq7Y0Ygl9KDZnrf/aiUJYUpVf89y8kyaxbRG7Y1SrX/jaumrv81vc61+kiMempujsM3Yw7w5qcw=="
},
"node_modules/glob": {
- "version": "10.3.10",
- "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz",
- "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==",
+ "version": "10.4.5",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz",
+ "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==",
+ "license": "ISC",
"dependencies": {
"foreground-child": "^3.1.0",
- "jackspeak": "^2.3.5",
- "minimatch": "^9.0.1",
- "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0",
- "path-scurry": "^1.10.1"
+ "jackspeak": "^3.1.2",
+ "minimatch": "^9.0.4",
+ "minipass": "^7.1.2",
+ "package-json-from-dist": "^1.0.0",
+ "path-scurry": "^1.11.1"
},
"bin": {
"glob": "dist/esm/bin.mjs"
},
- "engines": {
- "node": ">=16 || 14 >=14.17"
- },
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
@@ -5203,17 +5756,19 @@
}
},
"node_modules/glob/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==",
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
+ "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
+ "license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0"
}
},
"node_modules/glob/node_modules/minimatch": {
- "version": "9.0.4",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz",
- "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==",
+ "version": "9.0.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
+ "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
+ "license": "ISC",
"dependencies": {
"brace-expansion": "^2.0.1"
},
@@ -5225,27 +5780,27 @@
}
},
"node_modules/globals": {
- "version": "13.24.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
- "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
+ "version": "14.0.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
+ "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
"dev": true,
- "dependencies": {
- "type-fest": "^0.20.2"
- },
+ "license": "MIT",
"engines": {
- "node": ">=8"
+ "node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/globalthis": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz",
- "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==",
+ "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": {
- "define-properties": "^1.1.3"
+ "define-properties": "^1.2.1",
+ "gopd": "^1.0.1"
},
"engines": {
"node": ">= 0.4"
@@ -5254,48 +5809,24 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/globby": {
- "version": "11.1.0",
- "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz",
- "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==",
- "dev": true,
- "dependencies": {
- "array-union": "^2.1.0",
- "dir-glob": "^3.0.1",
- "fast-glob": "^3.2.9",
- "ignore": "^5.2.0",
- "merge2": "^1.4.1",
- "slash": "^3.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/gopd": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
- "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
- "dev": true,
- "dependencies": {
- "get-intrinsic": "^1.1.3"
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz",
+ "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/graceful-fs": {
- "version": "4.2.11",
- "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
- "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ=="
- },
"node_modules/graphemer": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz",
"integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/gray-matter": {
"version": "4.0.3",
@@ -5384,10 +5915,14 @@
}
},
"node_modules/has-proto": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",
- "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
+ "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": {
+ "dunder-proto": "^1.0.0"
+ },
"engines": {
"node": ">= 0.4"
},
@@ -5396,9 +5931,10 @@
}
},
"node_modules/has-symbols": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
- "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz",
+ "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==",
+ "license": "MIT",
"engines": {
"node": ">= 0.4"
},
@@ -5673,10 +6209,22 @@
"integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==",
"license": "MIT"
},
+ "node_modules/hex-rgb": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/hex-rgb/-/hex-rgb-4.3.0.tgz",
+ "integrity": "sha512-Ox1pJVrDCyGHMG9CFg1tmrRUMRPRsAWYc/PinY0XzJU4K7y7vjNoLKIQ7BR5UJMCxNN8EM1MNDmHWA/B3aZUuw==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/highlight.js": {
- "version": "11.10.0",
- "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.10.0.tgz",
- "integrity": "sha512-SYVnVFswQER+zu1laSya563s+F8VDGt7o35d4utbamowvUNLLMovFqwCLSocpZTz3MgaSRA1IbqRWZv97dtErQ==",
+ "version": "11.11.1",
+ "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-11.11.1.tgz",
+ "integrity": "sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==",
"dev": true,
"license": "BSD-3-Clause",
"engines": {
@@ -5706,10 +6254,11 @@
}
},
"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==",
+ "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"
@@ -5730,16 +6279,6 @@
"node": ">=0.8.19"
}
},
- "node_modules/inflight": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
- "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
- "dev": true,
- "dependencies": {
- "once": "^1.3.0",
- "wrappy": "1"
- }
- },
"node_modules/inherits": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
@@ -5751,14 +6290,15 @@
"integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q=="
},
"node_modules/internal-slot": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz",
- "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==",
+ "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": {
"es-errors": "^1.3.0",
- "hasown": "^2.0.0",
- "side-channel": "^1.0.4"
+ "hasown": "^2.0.2",
+ "side-channel": "^1.1.0"
},
"engines": {
"node": ">= 0.4"
@@ -5787,13 +6327,15 @@
}
},
"node_modules/is-array-buffer": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz",
- "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==",
+ "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": {
- "call-bind": "^1.0.2",
- "get-intrinsic": "^1.2.1"
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.3",
+ "get-intrinsic": "^1.2.6"
},
"engines": {
"node": ">= 0.4"
@@ -5802,13 +6344,25 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/is-arrayish": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
+ "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==",
+ "license": "MIT",
+ "optional": true
+ },
"node_modules/is-async-function": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.0.0.tgz",
- "integrity": "sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA==",
+ "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": {
- "has-tostringtag": "^1.0.0"
+ "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": ">= 0.4"
@@ -5818,12 +6372,16 @@
}
},
"node_modules/is-bigint": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz",
- "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==",
+ "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.1"
+ "has-bigints": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
@@ -5833,6 +6391,7 @@
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "license": "MIT",
"dependencies": {
"binary-extensions": "^2.0.0"
},
@@ -5841,13 +6400,14 @@
}
},
"node_modules/is-boolean-object": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz",
- "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==",
+ "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": {
- "call-bind": "^1.0.2",
- "has-tostringtag": "^1.0.0"
+ "call-bound": "^1.0.3",
+ "has-tostringtag": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
@@ -5861,6 +6421,16 @@
"resolved": "https://registry.npmjs.org/is-browser/-/is-browser-2.1.0.tgz",
"integrity": "sha512-F5rTJxDQ2sW81fcfOR1GnCXT6sVJC104fCyfj+mjpwNEwaPYSn5fte5jiHmBg3DHsIoL/l8Kvw5VN5SsTRcRFQ=="
},
+ "node_modules/is-bun-module": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-2.0.0.tgz",
+ "integrity": "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "semver": "^7.7.1"
+ }
+ },
"node_modules/is-callable": {
"version": "1.2.7",
"resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
@@ -5874,22 +6444,29 @@
}
},
"node_modules/is-core-module": {
- "version": "2.13.1",
- "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz",
- "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==",
+ "version": "2.16.1",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
+ "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
+ "license": "MIT",
"dependencies": {
- "hasown": "^2.0.0"
+ "hasown": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-data-view": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz",
- "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==",
+ "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": {
+ "call-bound": "^1.0.2",
+ "get-intrinsic": "^1.2.6",
"is-typed-array": "^1.1.13"
},
"engines": {
@@ -5900,12 +6477,14 @@
}
},
"node_modules/is-date-object": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
- "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
+ "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": {
- "has-tostringtag": "^1.0.0"
+ "call-bound": "^1.0.2",
+ "has-tostringtag": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
@@ -5941,12 +6520,16 @@
}
},
"node_modules/is-finalizationregistry": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.0.2.tgz",
- "integrity": "sha512-0by5vtUJs8iFQb5TYUHHPudOR+qXYIMKtiUzvLIZITZUjknFmziyBJuLhVRc+Ds0dREFlskDNJKYIdIzu/9pfw==",
+ "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": {
- "call-bind": "^1.0.2"
+ "call-bound": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
@@ -5956,17 +6539,22 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/is-generator-function": {
- "version": "1.0.10",
- "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.10.tgz",
- "integrity": "sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A==",
+ "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": {
- "has-tostringtag": "^1.0.0"
+ "call-bound": "^1.0.3",
+ "get-proto": "^1.0.0",
+ "has-tostringtag": "^1.0.2",
+ "safe-regex-test": "^1.1.0"
},
"engines": {
"node": ">= 0.4"
@@ -6000,6 +6588,7 @@
"resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz",
"integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">= 0.4"
},
@@ -6029,12 +6618,14 @@
}
},
"node_modules/is-number-object": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz",
- "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==",
+ "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": {
- "has-tostringtag": "^1.0.0"
+ "call-bound": "^1.0.3",
+ "has-tostringtag": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
@@ -6051,15 +6642,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/is-path-inside": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz",
- "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/is-plain-obj": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz",
@@ -6080,13 +6662,16 @@
}
},
"node_modules/is-regex": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
- "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
+ "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": {
- "call-bind": "^1.0.2",
- "has-tostringtag": "^1.0.0"
+ "call-bound": "^1.0.2",
+ "gopd": "^1.2.0",
+ "has-tostringtag": "^1.0.2",
+ "hasown": "^2.0.2"
},
"engines": {
"node": ">= 0.4"
@@ -6108,12 +6693,13 @@
}
},
"node_modules/is-shared-array-buffer": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz",
- "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==",
+ "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-bind": "^1.0.7"
+ "call-bound": "^1.0.3"
},
"engines": {
"node": ">= 0.4"
@@ -6131,11 +6717,13 @@
}
},
"node_modules/is-string": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
- "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==",
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz",
+ "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==",
+ "license": "MIT",
"dependencies": {
- "has-tostringtag": "^1.0.0"
+ "call-bound": "^1.0.3",
+ "has-tostringtag": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
@@ -6145,12 +6733,15 @@
}
},
"node_modules/is-symbol": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz",
- "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==",
+ "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": {
- "has-symbols": "^1.0.2"
+ "call-bound": "^1.0.2",
+ "has-symbols": "^1.1.0",
+ "safe-regex-test": "^1.1.0"
},
"engines": {
"node": ">= 0.4"
@@ -6160,12 +6751,13 @@
}
},
"node_modules/is-typed-array": {
- "version": "1.1.13",
- "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz",
- "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==",
+ "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": {
- "which-typed-array": "^1.1.14"
+ "which-typed-array": "^1.1.16"
},
"engines": {
"node": ">= 0.4"
@@ -6179,6 +6771,7 @@
"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.4"
},
@@ -6187,25 +6780,30 @@
}
},
"node_modules/is-weakref": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz",
- "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==",
+ "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-bind": "^1.0.2"
+ "call-bound": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-weakset": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz",
- "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==",
+ "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": {
- "call-bind": "^1.0.7",
- "get-intrinsic": "^1.2.4"
+ "call-bound": "^1.0.3",
+ "get-intrinsic": "^1.2.6"
},
"engines": {
"node": ">= 0.4"
@@ -6234,28 +6832,31 @@
"integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="
},
"node_modules/iterator.prototype": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.2.tgz",
- "integrity": "sha512-DR33HMMr8EzwuRL8Y9D3u2BMj8+RqSE850jfGu59kS7tbmPLzGkZmVSfyCFSDxuZiEY6Rzt3T2NA/qU+NwVj1w==",
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz",
+ "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "define-properties": "^1.2.1",
- "get-intrinsic": "^1.2.1",
- "has-symbols": "^1.0.3",
- "reflect.getprototypeof": "^1.0.4",
- "set-function-name": "^2.0.1"
+ "define-data-property": "^1.1.4",
+ "es-object-atoms": "^1.0.0",
+ "get-intrinsic": "^1.2.6",
+ "get-proto": "^1.0.0",
+ "has-symbols": "^1.1.0",
+ "set-function-name": "^2.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
}
},
"node_modules/jackspeak": {
- "version": "2.3.6",
- "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz",
- "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==",
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz",
+ "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==",
+ "license": "BlueOak-1.0.0",
"dependencies": {
"@isaacs/cliui": "^8.0.2"
},
- "engines": {
- "node": ">=14"
- },
"funding": {
"url": "https://github.com/sponsors/isaacs"
},
@@ -6264,9 +6865,10 @@
}
},
"node_modules/jiti": {
- "version": "1.21.0",
- "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz",
- "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==",
+ "version": "1.21.7",
+ "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz",
+ "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==",
+ "license": "MIT",
"bin": {
"jiti": "bin/jiti.js"
}
@@ -6281,6 +6883,7 @@
"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"
},
@@ -6292,13 +6895,15 @@
"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-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",
@@ -6311,6 +6916,7 @@
"resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz",
"integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"minimist": "^1.2.0"
},
@@ -6338,6 +6944,7 @@
"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"
}
@@ -6352,16 +6959,18 @@
}
},
"node_modules/language-subtag-registry": {
- "version": "0.3.22",
- "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.22.tgz",
- "integrity": "sha512-tN0MCzyWnoz/4nHS6uxdlFWoUZT7ABptwKPQ52Ea7URk6vll88bWBVhodtnlfEuCcKWNGoc+uGbw1cwa9IKh/w==",
- "dev": true
+ "version": "0.3.23",
+ "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz",
+ "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==",
+ "dev": true,
+ "license": "CC0-1.0"
},
"node_modules/language-tags": {
"version": "1.0.9",
"resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz",
"integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"language-subtag-registry": "^0.3.20"
},
@@ -6383,11 +6992,15 @@
}
},
"node_modules/lilconfig": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz",
- "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==",
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",
+ "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==",
+ "license": "MIT",
"engines": {
- "node": ">=10"
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antonk52"
}
},
"node_modules/limited-request-queue": {
@@ -6402,10 +7015,21 @@
"node": ">= 0.10"
}
},
+ "node_modules/linebreak": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/linebreak/-/linebreak-1.1.0.tgz",
+ "integrity": "sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==",
+ "license": "MIT",
+ "dependencies": {
+ "base64-js": "0.0.8",
+ "unicode-trie": "^2.0.0"
+ }
+ },
"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=="
+ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==",
+ "license": "MIT"
},
"node_modules/link-types": {
"version": "1.1.0",
@@ -6465,6 +7089,8 @@
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
+ "dev": true,
+ "license": "MIT",
"dependencies": {
"js-tokens": "^3.0.0 || ^4.0.0"
},
@@ -6473,19 +7099,18 @@
}
},
"node_modules/lru-cache": {
- "version": "10.2.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz",
- "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==",
- "engines": {
- "node": "14 || >=16.14"
- }
+ "version": "10.4.3",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz",
+ "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==",
+ "license": "ISC"
},
"node_modules/lucide-react": {
- "version": "0.435.0",
- "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.435.0.tgz",
- "integrity": "sha512-we5GKfzjMDw9m9SsyZJvWim9qaT+Ya5kaRS+OGFqgLqXUrPM1h+7CiMw5pKdEIoaBqfXz2pyv9TASAdpIAJs0Q==",
+ "version": "0.537.0",
+ "resolved": "https://registry.npmjs.org/lucide-react/-/lucide-react-0.537.0.tgz",
+ "integrity": "sha512-VxWsdxBGeFnlC+HwMg/l08HptN4YRU9o/lRog156jOmRxI1ERKqN+rJiNY/mPcKAdWdM0UbyO8ft1o0jq69SSQ==",
+ "license": "ISC",
"peerDependencies": {
- "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0-rc"
+ "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0"
}
},
"node_modules/lunr": {
@@ -6521,6 +7146,15 @@
"url": "https://github.com/sponsors/wooorm"
}
},
+ "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==",
+ "license": "MIT",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
"node_modules/maybe-callback": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/maybe-callback/-/maybe-callback-2.1.0.tgz",
@@ -6850,6 +7484,7 @@
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
"integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==",
+ "license": "MIT",
"engines": {
"node": ">= 8"
}
@@ -7581,9 +8216,10 @@
}
},
"node_modules/minipass": {
- "version": "7.0.4",
- "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz",
- "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==",
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz",
+ "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==",
+ "license": "ISC",
"engines": {
"node": ">=16 || 14 >=14.17"
}
@@ -7597,6 +8233,7 @@
"version": "2.7.0",
"resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
"integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==",
+ "license": "MIT",
"dependencies": {
"any-promise": "^1.0.0",
"object-assign": "^4.0.1",
@@ -7621,6 +8258,22 @@
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
}
},
+ "node_modules/napi-postinstall": {
+ "version": "0.3.2",
+ "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.2.tgz",
+ "integrity": "sha512-tWVJxJHmBWLy69PvO96TZMZDrzmw5KeiZBz3RHmiM2XZ9grBJ2WgMAFVVg25nqp3ZjTFUs2Ftw1JhscL3Teliw==",
+ "dev": true,
+ "license": "MIT",
+ "bin": {
+ "napi-postinstall": "lib/cli.js"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.18.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/napi-postinstall"
+ }
+ },
"node_modules/natural-compare": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
@@ -7628,41 +8281,40 @@
"dev": true
},
"node_modules/next": {
- "version": "14.2.26",
- "resolved": "https://registry.npmjs.org/next/-/next-14.2.26.tgz",
- "integrity": "sha512-b81XSLihMwCfwiUVRRja3LphLo4uBBMZEzBBWMaISbKTwOmq3wPknIETy/8000tr7Gq4WmbuFYPS7jOYIf+ZJw==",
+ "version": "15.4.6",
+ "resolved": "https://registry.npmjs.org/next/-/next-15.4.6.tgz",
+ "integrity": "sha512-us++E/Q80/8+UekzB3SAGs71AlLDsadpFMXVNM/uQ0BMwsh9m3mr0UNQIfjKed8vpWXsASe+Qifrnu1oLIcKEQ==",
"license": "MIT",
"dependencies": {
- "@next/env": "14.2.26",
- "@swc/helpers": "0.5.5",
- "busboy": "1.6.0",
+ "@next/env": "15.4.6",
+ "@swc/helpers": "0.5.15",
"caniuse-lite": "^1.0.30001579",
- "graceful-fs": "^4.2.11",
"postcss": "8.4.31",
- "styled-jsx": "5.1.1"
+ "styled-jsx": "5.1.6"
},
"bin": {
"next": "dist/bin/next"
},
"engines": {
- "node": ">=18.17.0"
+ "node": "^18.18.0 || ^19.8.0 || >= 20.0.0"
},
"optionalDependencies": {
- "@next/swc-darwin-arm64": "14.2.26",
- "@next/swc-darwin-x64": "14.2.26",
- "@next/swc-linux-arm64-gnu": "14.2.26",
- "@next/swc-linux-arm64-musl": "14.2.26",
- "@next/swc-linux-x64-gnu": "14.2.26",
- "@next/swc-linux-x64-musl": "14.2.26",
- "@next/swc-win32-arm64-msvc": "14.2.26",
- "@next/swc-win32-ia32-msvc": "14.2.26",
- "@next/swc-win32-x64-msvc": "14.2.26"
+ "@next/swc-darwin-arm64": "15.4.6",
+ "@next/swc-darwin-x64": "15.4.6",
+ "@next/swc-linux-arm64-gnu": "15.4.6",
+ "@next/swc-linux-arm64-musl": "15.4.6",
+ "@next/swc-linux-x64-gnu": "15.4.6",
+ "@next/swc-linux-x64-musl": "15.4.6",
+ "@next/swc-win32-arm64-msvc": "15.4.6",
+ "@next/swc-win32-x64-msvc": "15.4.6",
+ "sharp": "^0.34.3"
},
"peerDependencies": {
"@opentelemetry/api": "^1.1.0",
- "@playwright/test": "^1.41.2",
- "react": "^18.2.0",
- "react-dom": "^18.2.0",
+ "@playwright/test": "^1.51.1",
+ "babel-plugin-react-compiler": "*",
+ "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0",
+ "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0",
"sass": "^1.3.0"
},
"peerDependenciesMeta": {
@@ -7672,6 +8324,9 @@
"@playwright/test": {
"optional": true
},
+ "babel-plugin-react-compiler": {
+ "optional": true
+ },
"sass": {
"optional": true
}
@@ -7698,12 +8353,13 @@
}
},
"node_modules/next-themes": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.3.0.tgz",
- "integrity": "sha512-/QHIrsYpd6Kfk7xakK4svpDI5mmXP0gfvCoJdGpZQ2TOrQZmsW0QxjaiLn8wbIKjtm4BTSqLoix4lxYYOnLJ/w==",
+ "version": "0.4.6",
+ "resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.4.6.tgz",
+ "integrity": "sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==",
+ "license": "MIT",
"peerDependencies": {
- "react": "^16.8 || ^17 || ^18",
- "react-dom": "^16.8 || ^17 || ^18"
+ "react": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc",
+ "react-dom": "^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc"
}
},
"node_modules/next/node_modules/postcss": {
@@ -7734,10 +8390,11 @@
}
},
"node_modules/node-releases": {
- "version": "2.0.18",
- "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz",
- "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==",
- "dev": true
+ "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/nopt": {
"version": "3.0.6",
@@ -7859,6 +8516,7 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "license": "MIT",
"engines": {
"node": ">=0.10.0"
}
@@ -7884,15 +8542,20 @@
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
"integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==",
+ "license": "MIT",
"engines": {
"node": ">= 6"
}
},
"node_modules/object-inspect": {
- "version": "1.13.1",
- "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz",
- "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==",
+ "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": {
+ "node": ">= 0.4"
+ },
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
@@ -7907,14 +8570,17 @@
}
},
"node_modules/object.assign": {
- "version": "4.1.5",
- "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz",
- "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==",
+ "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,
+ "license": "MIT",
"dependencies": {
- "call-bind": "^1.0.5",
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.3",
"define-properties": "^1.2.1",
- "has-symbols": "^1.0.3",
+ "es-object-atoms": "^1.0.0",
+ "has-symbols": "^1.1.0",
"object-keys": "^1.1.1"
},
"engines": {
@@ -7925,14 +8591,16 @@
}
},
"node_modules/object.entries": {
- "version": "1.1.8",
- "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.8.tgz",
- "integrity": "sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==",
+ "version": "1.1.9",
+ "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz",
+ "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "call-bind": "^1.0.7",
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.4",
"define-properties": "^1.2.1",
- "es-object-atoms": "^1.0.0"
+ "es-object-atoms": "^1.1.1"
},
"engines": {
"node": ">= 0.4"
@@ -7961,6 +8629,7 @@
"resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.3.tgz",
"integrity": "sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"call-bind": "^1.0.7",
"define-properties": "^1.2.1",
@@ -7970,30 +8639,15 @@
"node": ">= 0.4"
}
},
- "node_modules/object.hasown": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.4.tgz",
- "integrity": "sha512-FZ9LZt9/RHzGySlBARE3VF+gE26TxR38SdmqOqliuTnl9wrKulaQs+4dee1V+Io8VfxqzAfHu6YuRgUy8OHoTg==",
- "dev": true,
- "dependencies": {
- "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"
- }
- },
"node_modules/object.values": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz",
- "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==",
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz",
+ "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "call-bind": "^1.0.7",
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.3",
"define-properties": "^1.2.1",
"es-object-atoms": "^1.0.0"
},
@@ -8004,15 +8658,6 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/once": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
- "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
- "dev": true,
- "dependencies": {
- "wrappy": "1"
- }
- },
"node_modules/optionator": {
"version": "0.9.3",
"resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
@@ -8067,6 +8712,24 @@
"node": ">=0.10.0"
}
},
+ "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": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/p-limit": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz",
@@ -8097,11 +8760,24 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/package-json-from-dist": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
+ "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
+ "license": "BlueOak-1.0.0"
+ },
+ "node_modules/pako": {
+ "version": "0.2.9",
+ "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz",
+ "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==",
+ "license": "MIT"
+ },
"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": {
"callsites": "^3.0.0"
},
@@ -8109,6 +8785,16 @@
"node": ">=6"
}
},
+ "node_modules/parse-css-color": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/parse-css-color/-/parse-css-color-0.2.1.tgz",
+ "integrity": "sha512-bwS/GGIFV3b6KS4uwpzCFj4w297Yl3uqnSgIPsoQkx7GMLROXfMnWvxfNkL0oh8HVhZA4hvJoEoEIqonfJ3BWg==",
+ "license": "MIT",
+ "dependencies": {
+ "color-name": "^1.1.4",
+ "hex-rgb": "^4.1.0"
+ }
+ },
"node_modules/parse-domain": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/parse-domain/-/parse-domain-0.2.2.tgz",
@@ -8164,15 +8850,6 @@
"node": ">=8"
}
},
- "node_modules/path-is-absolute": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
- "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
"node_modules/path-key": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
@@ -8187,29 +8864,21 @@
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
},
"node_modules/path-scurry": {
- "version": "1.10.2",
- "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz",
- "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==",
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
+ "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
+ "license": "BlueOak-1.0.0",
"dependencies": {
"lru-cache": "^10.2.0",
"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
},
"engines": {
- "node": ">=16 || 14 >=14.17"
+ "node": ">=16 || 14 >=14.18"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
- "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==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/periscopic": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz",
@@ -8221,14 +8890,16 @@
}
},
"node_modules/picocolors": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz",
- "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew=="
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
+ "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+ "license": "ISC"
},
"node_modules/picomatch": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "license": "MIT",
"engines": {
"node": ">=8.6"
},
@@ -8240,14 +8911,16 @@
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
"integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==",
+ "license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/pirates": {
- "version": "4.0.6",
- "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.6.tgz",
- "integrity": "sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==",
+ "version": "4.0.7",
+ "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz",
+ "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==",
+ "license": "MIT",
"engines": {
"node": ">= 6"
}
@@ -8262,9 +8935,9 @@
}
},
"node_modules/postcss": {
- "version": "8.4.38",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.38.tgz",
- "integrity": "sha512-Wglpdk03BSfXkHoQa3b/oulrotAkwrlLDRSOb9D0bN86FdRyE9lppSp33aHNPgBa0JKCoB+drFLZkQoRRYae5A==",
+ "version": "8.5.6",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
+ "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
"funding": [
{
"type": "opencollective",
@@ -8279,10 +8952,11 @@
"url": "https://github.com/sponsors/ai"
}
],
+ "license": "MIT",
"dependencies": {
- "nanoid": "^3.3.7",
- "picocolors": "^1.0.0",
- "source-map-js": "^1.2.0"
+ "nanoid": "^3.3.11",
+ "picocolors": "^1.1.1",
+ "source-map-js": "^1.2.1"
},
"engines": {
"node": "^10 || ^12 || >=14"
@@ -8292,6 +8966,7 @@
"version": "15.1.0",
"resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz",
"integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==",
+ "license": "MIT",
"dependencies": {
"postcss-value-parser": "^4.0.0",
"read-cache": "^1.0.0",
@@ -8308,6 +8983,7 @@
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz",
"integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==",
+ "license": "MIT",
"dependencies": {
"camelcase-css": "^2.0.1"
},
@@ -8336,6 +9012,7 @@
"url": "https://github.com/sponsors/ai"
}
],
+ "license": "MIT",
"dependencies": {
"lilconfig": "^3.0.0",
"yaml": "^2.3.4"
@@ -8356,39 +9033,36 @@
}
}
},
- "node_modules/postcss-load-config/node_modules/lilconfig": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.1.tgz",
- "integrity": "sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==",
- "engines": {
- "node": ">=14"
- },
- "funding": {
- "url": "https://github.com/sponsors/antonk52"
- }
- },
"node_modules/postcss-nested": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.0.1.tgz",
- "integrity": "sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==",
+ "version": "6.2.0",
+ "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz",
+ "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==",
+ "funding": [
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/postcss/"
+ },
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/ai"
+ }
+ ],
+ "license": "MIT",
"dependencies": {
- "postcss-selector-parser": "^6.0.11"
+ "postcss-selector-parser": "^6.1.1"
},
"engines": {
"node": ">=12.0"
},
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/postcss/"
- },
"peerDependencies": {
"postcss": "^8.2.14"
}
},
"node_modules/postcss-selector-parser": {
- "version": "6.0.16",
- "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz",
- "integrity": "sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==",
+ "version": "6.1.2",
+ "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz",
+ "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==",
+ "license": "MIT",
"dependencies": {
"cssesc": "^3.0.0",
"util-deprecate": "^1.0.2"
@@ -8437,6 +9111,7 @@
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
@@ -8498,29 +9173,28 @@
"type": "consulting",
"url": "https://feross.org/support"
}
- ]
+ ],
+ "license": "MIT"
},
"node_modules/react": {
- "version": "18.3.1",
- "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
- "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
- "dependencies": {
- "loose-envify": "^1.1.0"
- },
+ "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"
}
},
"node_modules/react-dom": {
- "version": "18.3.1",
- "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
- "integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
+ "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": {
- "loose-envify": "^1.1.0",
- "scheduler": "^0.23.2"
+ "scheduler": "^0.26.0"
},
"peerDependencies": {
- "react": "^18.3.1"
+ "react": "^19.1.1"
}
},
"node_modules/react-highlight": {
@@ -8560,25 +9234,27 @@
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/react-remove-scroll": {
- "version": "2.5.7",
- "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.5.7.tgz",
- "integrity": "sha512-FnrTWO4L7/Bhhf3CYBNArEG/yROV0tKmTv7/3h9QCFvH6sndeFf1wPqOcbFVu5VAulS5dV1wGT3GZZ/1GawqiA==",
+ "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.4",
- "react-style-singleton": "^2.2.1",
+ "react-remove-scroll-bar": "^2.3.7",
+ "react-style-singleton": "^2.2.3",
"tslib": "^2.1.0",
- "use-callback-ref": "^1.3.0",
- "use-sidecar": "^1.1.2"
+ "use-callback-ref": "^1.3.3",
+ "use-sidecar": "^1.1.3"
},
"engines": {
"node": ">=10"
},
"peerDependencies": {
- "@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
- "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
+ "@types/react": "*",
+ "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc"
},
"peerDependenciesMeta": {
"@types/react": {
@@ -8634,6 +9310,7 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
"integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==",
+ "license": "MIT",
"dependencies": {
"pify": "^2.3.0"
}
@@ -8661,6 +9338,7 @@
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "license": "MIT",
"dependencies": {
"picomatch": "^2.2.1"
},
@@ -8669,18 +9347,20 @@
}
},
"node_modules/reflect.getprototypeof": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.6.tgz",
- "integrity": "sha512-fmfw4XgoDke3kdI6h4xcUz1dG8uaiv5q9gcEwLS4Pnth2kxT+GZ7YehS1JTMGBQmtV7Y4GFGbs2re2NqhdozUg==",
+ "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,
+ "license": "MIT",
"dependencies": {
- "call-bind": "^1.0.7",
+ "call-bind": "^1.0.8",
"define-properties": "^1.2.1",
- "es-abstract": "^1.23.1",
+ "es-abstract": "^1.23.9",
"es-errors": "^1.3.0",
- "get-intrinsic": "^1.2.4",
- "globalthis": "^1.0.3",
- "which-builtin-type": "^1.1.3"
+ "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"
@@ -8719,22 +9399,19 @@
"integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==",
"license": "MIT"
},
- "node_modules/regenerator-runtime": {
- "version": "0.14.1",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
- "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==",
- "dev": true
- },
"node_modules/regexp.prototype.flags": {
- "version": "1.5.2",
- "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz",
- "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==",
+ "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,
+ "license": "MIT",
"dependencies": {
- "call-bind": "^1.0.6",
+ "call-bind": "^1.0.8",
"define-properties": "^1.2.1",
"es-errors": "^1.3.0",
- "set-function-name": "^2.0.1"
+ "get-proto": "^1.0.1",
+ "gopd": "^1.2.0",
+ "set-function-name": "^2.0.2"
},
"engines": {
"node": ">= 0.4"
@@ -8808,9 +9485,10 @@
}
},
"node_modules/rehype-prism-plus": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/rehype-prism-plus/-/rehype-prism-plus-2.0.0.tgz",
- "integrity": "sha512-FeM/9V2N7EvDZVdR2dqhAzlw5YI49m9Tgn7ZrYJeYHIahM6gcXpH0K1y2gNnKanZCydOMluJvX2cB9z3lhY8XQ==",
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/rehype-prism-plus/-/rehype-prism-plus-2.0.1.tgz",
+ "integrity": "sha512-Wglct0OW12tksTUseAPyWPo3srjBOY7xKlql/DPKi7HbsdZTyaLCAoO58QBKSczFQxElTsQlOY3JDOFzB/K++Q==",
+ "license": "MIT",
"dependencies": {
"hast-util-to-string": "^3.0.0",
"parse-numeric-range": "^1.3.0",
@@ -8854,9 +9532,10 @@
}
},
"node_modules/remark-gfm": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.0.tgz",
- "integrity": "sha512-U92vJgBPkbw4Zfu/IiW2oTZLSL3Zpv+uI7My2eq8JxKgqraFdU8YUGicEJCEgSbeaG+QDFqIcwwfMTOEelPxuA==",
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/remark-gfm/-/remark-gfm-4.0.1.tgz",
+ "integrity": "sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==",
+ "license": "MIT",
"dependencies": {
"@types/mdast": "^4.0.0",
"mdast-util-gfm": "^3.0.0",
@@ -8951,6 +9630,7 @@
"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"
}
@@ -8965,49 +9645,15 @@
}
},
"node_modules/reusify": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
- "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz",
+ "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==",
+ "license": "MIT",
"engines": {
"iojs": ">=1.0.0",
"node": ">=0.10.0"
}
},
- "node_modules/rimraf": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
- "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
- "dev": true,
- "dependencies": {
- "glob": "^7.1.3"
- },
- "bin": {
- "rimraf": "bin.js"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/rimraf/node_modules/glob": {
- "version": "7.2.3",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
- "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
- "dev": true,
- "dependencies": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.1.1",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- },
- "engines": {
- "node": "*"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
"node_modules/robot-directives": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/robot-directives/-/robot-directives-0.3.0.tgz",
@@ -9054,19 +9700,22 @@
"url": "https://feross.org/support"
}
],
+ "license": "MIT",
"dependencies": {
"queue-microtask": "^1.2.2"
}
},
"node_modules/safe-array-concat": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz",
- "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==",
+ "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,
+ "license": "MIT",
"dependencies": {
- "call-bind": "^1.0.7",
- "get-intrinsic": "^1.2.4",
- "has-symbols": "^1.0.3",
+ "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": {
@@ -9081,15 +9730,33 @@
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
+ "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,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "isarray": "^2.0.5"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
"node_modules/safe-regex-test": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz",
- "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==",
+ "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,
+ "license": "MIT",
"dependencies": {
- "call-bind": "^1.0.6",
+ "call-bound": "^1.0.2",
"es-errors": "^1.3.0",
- "is-regex": "^1.1.4"
+ "is-regex": "^1.2.1"
},
"engines": {
"node": ">= 0.4"
@@ -9098,14 +9765,34 @@
"url": "https://github.com/sponsors/ljharb"
}
},
- "node_modules/scheduler": {
- "version": "0.23.2",
- "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
- "integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
+ "node_modules/satori": {
+ "version": "0.16.0",
+ "resolved": "https://registry.npmjs.org/satori/-/satori-0.16.0.tgz",
+ "integrity": "sha512-ZvHN3ygzZ8FuxjSNB+mKBiF/NIoqHzlBGbD0MJiT+MvSsFOvotnWOhdTjxKzhHRT2wPC1QbhLzx2q/Y83VhfYQ==",
+ "license": "MPL-2.0",
"dependencies": {
- "loose-envify": "^1.1.0"
+ "@shuding/opentype.js": "1.4.0-beta.0",
+ "css-background-parser": "^0.1.0",
+ "css-box-shadow": "1.0.0-3",
+ "css-gradient-parser": "^0.0.16",
+ "css-to-react-native": "^3.0.0",
+ "emoji-regex-xs": "^2.0.1",
+ "escape-html": "^1.0.3",
+ "linebreak": "^1.1.0",
+ "parse-css-color": "^0.2.1",
+ "postcss-value-parser": "^4.2.0",
+ "yoga-layout": "^3.2.1"
+ },
+ "engines": {
+ "node": ">=16"
}
},
+ "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"
+ },
"node_modules/section-matter": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz",
@@ -9120,13 +9807,11 @@
}
},
"node_modules/semver": {
- "version": "7.6.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
- "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
- "dev": true,
- "dependencies": {
- "lru-cache": "^6.0.0"
- },
+ "version": "7.7.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.2.tgz",
+ "integrity": "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==",
+ "devOptional": true,
+ "license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
@@ -9134,18 +9819,6 @@
"node": ">=10"
}
},
- "node_modules/semver/node_modules/lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "dev": true,
- "dependencies": {
- "yallist": "^4.0.0"
- },
- "engines": {
- "node": ">=10"
- }
- },
"node_modules/set-function-length": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
@@ -9178,6 +9851,64 @@
"node": ">= 0.4"
}
},
+ "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"
+ }
+ },
+ "node_modules/sharp": {
+ "version": "0.34.3",
+ "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.3.tgz",
+ "integrity": "sha512-eX2IQ6nFohW4DbvHIOLRB3MHFpYqaqvXd3Tp5e/T/dSH83fxaNJQRvDMhASmkNTsNTVF2/OOopzRCt7xokgPfg==",
+ "hasInstallScript": true,
+ "license": "Apache-2.0",
+ "optional": true,
+ "dependencies": {
+ "color": "^4.2.3",
+ "detect-libc": "^2.0.4",
+ "semver": "^7.7.2"
+ },
+ "engines": {
+ "node": "^18.17.0 || ^20.3.0 || >=21.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/libvips"
+ },
+ "optionalDependencies": {
+ "@img/sharp-darwin-arm64": "0.34.3",
+ "@img/sharp-darwin-x64": "0.34.3",
+ "@img/sharp-libvips-darwin-arm64": "1.2.0",
+ "@img/sharp-libvips-darwin-x64": "1.2.0",
+ "@img/sharp-libvips-linux-arm": "1.2.0",
+ "@img/sharp-libvips-linux-arm64": "1.2.0",
+ "@img/sharp-libvips-linux-ppc64": "1.2.0",
+ "@img/sharp-libvips-linux-s390x": "1.2.0",
+ "@img/sharp-libvips-linux-x64": "1.2.0",
+ "@img/sharp-libvips-linuxmusl-arm64": "1.2.0",
+ "@img/sharp-libvips-linuxmusl-x64": "1.2.0",
+ "@img/sharp-linux-arm": "0.34.3",
+ "@img/sharp-linux-arm64": "0.34.3",
+ "@img/sharp-linux-ppc64": "0.34.3",
+ "@img/sharp-linux-s390x": "0.34.3",
+ "@img/sharp-linux-x64": "0.34.3",
+ "@img/sharp-linuxmusl-arm64": "0.34.3",
+ "@img/sharp-linuxmusl-x64": "0.34.3",
+ "@img/sharp-wasm32": "0.34.3",
+ "@img/sharp-win32-arm64": "0.34.3",
+ "@img/sharp-win32-ia32": "0.34.3",
+ "@img/sharp-win32-x64": "0.34.3"
+ }
+ },
"node_modules/shebang-command": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
@@ -9198,15 +9929,73 @@
}
},
"node_modules/side-channel": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
- "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
+ "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": {
- "call-bind": "^1.0.7",
"es-errors": "^1.3.0",
- "get-intrinsic": "^1.2.4",
- "object-inspect": "^1.13.1"
+ "object-inspect": "^1.13.3",
+ "side-channel-list": "^1.0.0",
+ "side-channel-map": "^1.0.1",
+ "side-channel-weakmap": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-list": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
+ "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
+ "dev": true,
+ "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": {
+ "call-bound": "^1.0.2",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.5",
+ "object-inspect": "^1.13.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/side-channel-weakmap": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
+ "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
+ "dev": true,
+ "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"
@@ -9219,6 +10008,7 @@
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
"integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+ "license": "ISC",
"engines": {
"node": ">=14"
},
@@ -9226,13 +10016,14 @@
"url": "https://github.com/sponsors/isaacs"
}
},
- "node_modules/slash": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz",
- "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==",
- "dev": true,
- "engines": {
- "node": ">=8"
+ "node_modules/simple-swizzle": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
+ "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==",
+ "license": "MIT",
+ "optional": true,
+ "dependencies": {
+ "is-arrayish": "^0.3.1"
}
},
"node_modules/source-map": {
@@ -9244,9 +10035,10 @@
}
},
"node_modules/source-map-js": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.0.tgz",
- "integrity": "sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==",
+ "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==",
+ "license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
}
@@ -9282,6 +10074,27 @@
"integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==",
"license": "BSD-3-Clause"
},
+ "node_modules/stable-hash": {
+ "version": "0.0.5",
+ "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz",
+ "integrity": "sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "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,
+ "license": "MIT",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "internal-slot": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
"node_modules/stream-combiner": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz",
@@ -9299,14 +10112,6 @@
"bluebird": "^2.6.2"
}
},
- "node_modules/streamsearch": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-1.1.0.tgz",
- "integrity": "sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg==",
- "engines": {
- "node": ">=10.0.0"
- }
- },
"node_modules/string_decoder": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
@@ -9319,6 +10124,7 @@
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz",
"integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==",
+ "license": "MIT",
"dependencies": {
"eastasianwidth": "^0.2.0",
"emoji-regex": "^9.2.2",
@@ -9336,6 +10142,7 @@
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "license": "MIT",
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
@@ -9345,54 +10152,74 @@
"node": ">=8"
}
},
+ "node_modules/string-width-cjs/node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/string-width-cjs/node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "license": "MIT"
},
- "node_modules/string-width/node_modules/ansi-regex": {
+ "node_modules/string-width-cjs/node_modules/strip-ansi": {
"version": "6.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
- "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
}
},
- "node_modules/string-width/node_modules/strip-ansi": {
- "version": "7.1.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
- "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
+ "node_modules/string.prototype.codepointat": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/string.prototype.codepointat/-/string.prototype.codepointat-0.2.1.tgz",
+ "integrity": "sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg==",
+ "license": "MIT"
+ },
+ "node_modules/string.prototype.includes": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.1.tgz",
+ "integrity": "sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==",
+ "dev": true,
+ "license": "MIT",
"dependencies": {
- "ansi-regex": "^6.0.1"
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1",
+ "es-abstract": "^1.23.3"
},
"engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+ "node": ">= 0.4"
}
},
"node_modules/string.prototype.matchall": {
- "version": "4.0.11",
- "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz",
- "integrity": "sha512-NUdh0aDavY2og7IbBPenWqR9exH+E26Sv8e0/eTe1tltDGZL+GtBkDAnnyBtmekfK6/Dq3MkcGtzXFEd1LQrtg==",
+ "version": "4.0.12",
+ "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.12.tgz",
+ "integrity": "sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "call-bind": "^1.0.7",
+ "call-bind": "^1.0.8",
+ "call-bound": "^1.0.3",
"define-properties": "^1.2.1",
- "es-abstract": "^1.23.2",
+ "es-abstract": "^1.23.6",
"es-errors": "^1.3.0",
"es-object-atoms": "^1.0.0",
- "get-intrinsic": "^1.2.4",
- "gopd": "^1.0.1",
- "has-symbols": "^1.0.3",
- "internal-slot": "^1.0.7",
- "regexp.prototype.flags": "^1.5.2",
+ "get-intrinsic": "^1.2.6",
+ "gopd": "^1.2.0",
+ "has-symbols": "^1.1.0",
+ "internal-slot": "^1.1.0",
+ "regexp.prototype.flags": "^1.5.3",
"set-function-name": "^2.0.2",
- "side-channel": "^1.0.6"
+ "side-channel": "^1.1.0"
},
"engines": {
"node": ">= 0.4"
@@ -9401,16 +10228,31 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/string.prototype.repeat": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz",
+ "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "define-properties": "^1.1.3",
+ "es-abstract": "^1.17.5"
+ }
+ },
"node_modules/string.prototype.trim": {
- "version": "1.2.9",
- "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz",
- "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==",
+ "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,
+ "license": "MIT",
"dependencies": {
- "call-bind": "^1.0.7",
+ "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.0",
- "es-object-atoms": "^1.0.0"
+ "es-abstract": "^1.23.5",
+ "es-object-atoms": "^1.0.0",
+ "has-property-descriptors": "^1.0.2"
},
"engines": {
"node": ">= 0.4"
@@ -9420,15 +10262,20 @@
}
},
"node_modules/string.prototype.trimend": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz",
- "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==",
+ "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,
+ "license": "MIT",
"dependencies": {
- "call-bind": "^1.0.7",
+ "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"
}
@@ -9464,14 +10311,18 @@
}
},
"node_modules/strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "version": "7.1.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
+ "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
+ "license": "MIT",
"dependencies": {
- "ansi-regex": "^5.0.1"
+ "ansi-regex": "^6.0.1"
},
"engines": {
- "node": ">=8"
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/strip-ansi?sponsor=1"
}
},
"node_modules/strip-ansi-cjs": {
@@ -9479,6 +10330,7 @@
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "license": "MIT",
"dependencies": {
"ansi-regex": "^5.0.1"
},
@@ -9486,11 +10338,21 @@
"node": ">=8"
}
},
+ "node_modules/strip-ansi-cjs/node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
"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,
+ "license": "MIT",
"engines": {
"node": ">=4"
}
@@ -9509,6 +10371,7 @@
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
"integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=8"
},
@@ -9538,9 +10401,10 @@
}
},
"node_modules/styled-jsx": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.1.tgz",
- "integrity": "sha512-pW7uC1l4mBZ8ugbiZrcIsiIvVx1UmTfw7UkC3Um2tmfUq9Bhk8IiyEIPl6F8agHgjzku6j0xQEZbfA5uSgSaCw==",
+ "version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz",
+ "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==",
+ "license": "MIT",
"dependencies": {
"client-only": "0.0.1"
},
@@ -9548,7 +10412,7 @@
"node": ">= 12.0.0"
},
"peerDependencies": {
- "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0"
+ "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0"
},
"peerDependenciesMeta": {
"@babel/core": {
@@ -9563,6 +10427,7 @@
"version": "3.35.0",
"resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz",
"integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==",
+ "license": "MIT",
"dependencies": {
"@jridgewell/gen-mapping": "^0.3.2",
"commander": "^4.0.0",
@@ -9604,41 +10469,43 @@
}
},
"node_modules/tailwind-merge": {
- "version": "2.5.2",
- "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.5.2.tgz",
- "integrity": "sha512-kjEBm+pvD+6eAwzJL2Bi+02/9LFLal1Gs61+QB7HvTfQQ0aXwC5LGT8PEt1gS0CWKktKe6ysPTAy3cBC5MeiIg==",
+ "version": "3.3.1",
+ "resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-3.3.1.tgz",
+ "integrity": "sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g==",
+ "license": "MIT",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/dcastil"
}
},
"node_modules/tailwindcss": {
- "version": "3.4.10",
- "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.10.tgz",
- "integrity": "sha512-KWZkVPm7yJRhdu4SRSl9d4AK2wM3a50UsvgHZO7xY77NQr2V+fIrEuoDGQcbvswWvFGbS2f6e+jC/6WJm1Dl0w==",
+ "version": "3.4.17",
+ "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz",
+ "integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==",
+ "license": "MIT",
"dependencies": {
"@alloc/quick-lru": "^5.2.0",
"arg": "^5.0.2",
- "chokidar": "^3.5.3",
+ "chokidar": "^3.6.0",
"didyoumean": "^1.2.2",
"dlv": "^1.1.3",
- "fast-glob": "^3.3.0",
+ "fast-glob": "^3.3.2",
"glob-parent": "^6.0.2",
"is-glob": "^4.0.3",
- "jiti": "^1.21.0",
- "lilconfig": "^2.1.0",
- "micromatch": "^4.0.5",
+ "jiti": "^1.21.6",
+ "lilconfig": "^3.1.3",
+ "micromatch": "^4.0.8",
"normalize-path": "^3.0.0",
"object-hash": "^3.0.0",
- "picocolors": "^1.0.0",
- "postcss": "^8.4.23",
+ "picocolors": "^1.1.1",
+ "postcss": "^8.4.47",
"postcss-import": "^15.1.0",
"postcss-js": "^4.0.1",
- "postcss-load-config": "^4.0.1",
- "postcss-nested": "^6.0.1",
- "postcss-selector-parser": "^6.0.11",
- "resolve": "^1.22.2",
- "sucrase": "^3.32.0"
+ "postcss-load-config": "^4.0.2",
+ "postcss-nested": "^6.2.0",
+ "postcss-selector-parser": "^6.1.2",
+ "resolve": "^1.22.8",
+ "sucrase": "^3.35.0"
},
"bin": {
"tailwind": "lib/cli.js",
@@ -9656,25 +10523,39 @@
"tailwindcss": ">=3.0.0 || insiders"
}
},
- "node_modules/tapable": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
- "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
- "dev": true,
+ "node_modules/tailwindcss/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==",
+ "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": ">=6"
+ "node": ">=8.6.0"
}
},
- "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/tailwindcss/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==",
+ "license": "ISC",
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
},
"node_modules/thenify": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz",
"integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==",
+ "license": "MIT",
"dependencies": {
"any-promise": "^1.0.0"
}
@@ -9683,6 +10564,7 @@
"version": "1.6.0",
"resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz",
"integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==",
+ "license": "MIT",
"dependencies": {
"thenify": ">= 3.1.0 < 4"
},
@@ -9743,6 +10625,57 @@
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
"integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ=="
},
+ "node_modules/tiny-inflate": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz",
+ "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==",
+ "license": "MIT"
+ },
+ "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,
+ "license": "MIT",
+ "dependencies": {
+ "fdir": "^6.4.4",
+ "picomatch": "^4.0.2"
+ },
+ "engines": {
+ "node": ">=12.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/SuperchupuDev"
+ }
+ },
+ "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,
+ "license": "MIT",
+ "peerDependencies": {
+ "picomatch": "^3 || ^4"
+ },
+ "peerDependenciesMeta": {
+ "picomatch": {
+ "optional": true
+ }
+ }
+ },
+ "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,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
"node_modules/tmp": {
"version": "0.0.33",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
@@ -9797,21 +10730,23 @@
}
},
"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==",
+ "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,
+ "license": "MIT",
"engines": {
- "node": ">=16"
+ "node": ">=18.12"
},
"peerDependencies": {
- "typescript": ">=4.2.0"
+ "typescript": ">=4.8.4"
}
},
"node_modules/ts-interface-checker": {
"version": "0.1.13",
"resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
- "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA=="
+ "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==",
+ "license": "Apache-2.0"
},
"node_modules/ts-node": {
"version": "10.9.2",
@@ -9869,6 +10804,7 @@
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz",
"integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"@types/json5": "^0.0.29",
"json5": "^1.0.2",
@@ -9877,14 +10813,15 @@
}
},
"node_modules/tslib": {
- "version": "2.6.2",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
- "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
+ "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/tsx": {
- "version": "4.19.3",
- "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.3.tgz",
- "integrity": "sha512-4H8vUNGNjQ4V2EOoGw005+c+dGuPSnhpPBPHBtsZdGZBk/iJb4kguGlPWaZTZ3q5nMtFOEsY0nRDlh9PJyd6SQ==",
+ "version": "4.20.3",
+ "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.20.3.tgz",
+ "integrity": "sha512-qjbnuR9Tr+FJOMBqJCW5ehvIo/buZq7vH7qD7JziU98h6l3qGy0a/yPFjwO+y0/T7GFpNgNAvEcPPVfyT8rrPQ==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -9913,43 +10850,33 @@
"node": ">= 0.8.0"
}
},
- "node_modules/type-fest": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
- "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
- "dev": true,
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
"node_modules/typed-array-buffer": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz",
- "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==",
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz",
+ "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "call-bind": "^1.0.7",
+ "call-bound": "^1.0.3",
"es-errors": "^1.3.0",
- "is-typed-array": "^1.1.13"
+ "is-typed-array": "^1.1.14"
},
"engines": {
"node": ">= 0.4"
}
},
"node_modules/typed-array-byte-length": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz",
- "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==",
+ "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,
+ "license": "MIT",
"dependencies": {
- "call-bind": "^1.0.7",
+ "call-bind": "^1.0.8",
"for-each": "^0.3.3",
- "gopd": "^1.0.1",
- "has-proto": "^1.0.3",
- "is-typed-array": "^1.1.13"
+ "gopd": "^1.2.0",
+ "has-proto": "^1.2.0",
+ "is-typed-array": "^1.1.14"
},
"engines": {
"node": ">= 0.4"
@@ -9959,17 +10886,19 @@
}
},
"node_modules/typed-array-byte-offset": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz",
- "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==",
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz",
+ "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"available-typed-arrays": "^1.0.7",
- "call-bind": "^1.0.7",
+ "call-bind": "^1.0.8",
"for-each": "^0.3.3",
- "gopd": "^1.0.1",
- "has-proto": "^1.0.3",
- "is-typed-array": "^1.1.13"
+ "gopd": "^1.2.0",
+ "has-proto": "^1.2.0",
+ "is-typed-array": "^1.1.15",
+ "reflect.getprototypeof": "^1.0.9"
},
"engines": {
"node": ">= 0.4"
@@ -9979,17 +10908,18 @@
}
},
"node_modules/typed-array-length": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.6.tgz",
- "integrity": "sha512-/OxDN6OtAk5KBpGb28T+HZc2M+ADtvRxXrKKbUwtsLgdoxgX13hyy7ek6bFRl5+aBs2yZzB0c4CnQfAtVypW/g==",
+ "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,
+ "license": "MIT",
"dependencies": {
"call-bind": "^1.0.7",
"for-each": "^0.3.3",
"gopd": "^1.0.1",
- "has-proto": "^1.0.3",
"is-typed-array": "^1.1.13",
- "possible-typed-array-names": "^1.0.0"
+ "possible-typed-array-names": "^1.0.0",
+ "reflect.getprototypeof": "^1.0.6"
},
"engines": {
"node": ">= 0.4"
@@ -10017,26 +10947,40 @@
}
},
"node_modules/unbox-primitive": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz",
- "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==",
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz",
+ "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "call-bind": "^1.0.2",
+ "call-bound": "^1.0.3",
"has-bigints": "^1.0.2",
- "has-symbols": "^1.0.3",
- "which-boxed-primitive": "^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"
}
},
"node_modules/undici-types": {
- "version": "6.19.8",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
- "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==",
+ "version": "7.10.0",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz",
+ "integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==",
"license": "MIT"
},
+ "node_modules/unicode-trie": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz",
+ "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==",
+ "license": "MIT",
+ "dependencies": {
+ "pako": "^0.2.5",
+ "tiny-inflate": "^1.0.0"
+ }
+ },
"node_modules/unified": {
"version": "11.0.4",
"resolved": "https://registry.npmjs.org/unified/-/unified-11.0.4.tgz",
@@ -10236,10 +11180,45 @@
"url": "https://opencollective.com/unified"
}
},
+ "node_modules/unrs-resolver": {
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.11.1.tgz",
+ "integrity": "sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "MIT",
+ "dependencies": {
+ "napi-postinstall": "^0.3.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/unrs-resolver"
+ },
+ "optionalDependencies": {
+ "@unrs/resolver-binding-android-arm-eabi": "1.11.1",
+ "@unrs/resolver-binding-android-arm64": "1.11.1",
+ "@unrs/resolver-binding-darwin-arm64": "1.11.1",
+ "@unrs/resolver-binding-darwin-x64": "1.11.1",
+ "@unrs/resolver-binding-freebsd-x64": "1.11.1",
+ "@unrs/resolver-binding-linux-arm-gnueabihf": "1.11.1",
+ "@unrs/resolver-binding-linux-arm-musleabihf": "1.11.1",
+ "@unrs/resolver-binding-linux-arm64-gnu": "1.11.1",
+ "@unrs/resolver-binding-linux-arm64-musl": "1.11.1",
+ "@unrs/resolver-binding-linux-ppc64-gnu": "1.11.1",
+ "@unrs/resolver-binding-linux-riscv64-gnu": "1.11.1",
+ "@unrs/resolver-binding-linux-riscv64-musl": "1.11.1",
+ "@unrs/resolver-binding-linux-s390x-gnu": "1.11.1",
+ "@unrs/resolver-binding-linux-x64-gnu": "1.11.1",
+ "@unrs/resolver-binding-linux-x64-musl": "1.11.1",
+ "@unrs/resolver-binding-wasm32-wasi": "1.11.1",
+ "@unrs/resolver-binding-win32-arm64-msvc": "1.11.1",
+ "@unrs/resolver-binding-win32-ia32-msvc": "1.11.1",
+ "@unrs/resolver-binding-win32-x64-msvc": "1.11.1"
+ }
+ },
"node_modules/update-browserslist-db": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz",
- "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==",
+ "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,
"funding": [
{
@@ -10255,9 +11234,10 @@
"url": "https://github.com/sponsors/ai"
}
],
+ "license": "MIT",
"dependencies": {
- "escalade": "^3.1.2",
- "picocolors": "^1.0.1"
+ "escalade": "^3.2.0",
+ "picocolors": "^1.1.1"
},
"bin": {
"update-browserslist-db": "cli.js"
@@ -10271,6 +11251,7 @@
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
"dev": true,
+ "license": "BSD-2-Clause",
"dependencies": {
"punycode": "^2.1.0"
}
@@ -10461,39 +11442,45 @@
}
},
"node_modules/which-boxed-primitive": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz",
- "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==",
+ "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.0.1",
- "is-boolean-object": "^1.1.0",
- "is-number-object": "^1.0.4",
- "is-string": "^1.0.5",
- "is-symbol": "^1.0.3"
+ "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.1.3",
- "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.1.3.tgz",
- "integrity": "sha512-YmjsSMDBYsM1CaFiayOVT06+KJeXf0o5M/CAd4o1lTadFAtacTUM49zoYxr/oroopFDfhvN6iEcBxUyc3gvKmw==",
+ "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": {
- "function.prototype.name": "^1.1.5",
- "has-tostringtag": "^1.0.0",
+ "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.0.5",
- "is-finalizationregistry": "^1.0.2",
+ "is-date-object": "^1.1.0",
+ "is-finalizationregistry": "^1.1.0",
"is-generator-function": "^1.0.10",
- "is-regex": "^1.1.4",
+ "is-regex": "^1.2.1",
"is-weakref": "^1.0.2",
"isarray": "^2.0.5",
- "which-boxed-primitive": "^1.0.2",
- "which-collection": "^1.0.1",
- "which-typed-array": "^1.1.9"
+ "which-boxed-primitive": "^1.1.0",
+ "which-collection": "^1.0.2",
+ "which-typed-array": "^1.1.16"
},
"engines": {
"node": ">= 0.4"
@@ -10507,6 +11494,7 @@
"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",
@@ -10521,15 +11509,18 @@
}
},
"node_modules/which-typed-array": {
- "version": "1.1.15",
- "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz",
- "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==",
+ "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.7",
- "for-each": "^0.3.3",
- "gopd": "^1.0.1",
+ "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": {
@@ -10562,6 +11553,7 @@
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz",
"integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==",
+ "license": "MIT",
"dependencies": {
"ansi-styles": "^6.1.0",
"string-width": "^5.0.1",
@@ -10579,6 +11571,7 @@
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "license": "MIT",
"dependencies": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
@@ -10591,15 +11584,26 @@
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
+ "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "license": "MIT",
+ "engines": {
+ "node": ">=8"
+ }
+ },
"node_modules/wrap-ansi-cjs/node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "license": "MIT"
},
"node_modules/wrap-ansi-cjs/node_modules/string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "license": "MIT",
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
@@ -10609,21 +11613,23 @@
"node": ">=8"
}
},
- "node_modules/wrap-ansi/node_modules/ansi-regex": {
+ "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": {
"version": "6.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz",
- "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==",
- "engines": {
- "node": ">=12"
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
},
- "funding": {
- "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+ "engines": {
+ "node": ">=8"
}
},
"node_modules/wrap-ansi/node_modules/ansi-styles": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz",
"integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==",
+ "license": "MIT",
"engines": {
"node": ">=12"
},
@@ -10631,26 +11637,6 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
- "node_modules/wrap-ansi/node_modules/strip-ansi": {
- "version": "7.1.0",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz",
- "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==",
- "dependencies": {
- "ansi-regex": "^6.0.1"
- },
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/chalk/strip-ansi?sponsor=1"
- }
- },
- "node_modules/wrappy": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
- "dev": true
- },
"node_modules/xtend": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-3.0.0.tgz",
@@ -10659,12 +11645,6 @@
"node": ">=0.4"
}
},
- "node_modules/yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
- "dev": true
- },
"node_modules/yaml": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.1.tgz",
@@ -10698,6 +11678,12 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/yoga-layout": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/yoga-layout/-/yoga-layout-3.2.1.tgz",
+ "integrity": "sha512-0LPOt3AxKqMdFBZA3HBAt/t/8vIKq7VaQYbuA8WxCgung+p9TVyKRYdpvCb80HcdTN2NkbIKbhNwKUfm3tQywQ==",
+ "license": "MIT"
+ },
"node_modules/zwitch": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz",
diff --git a/package.json b/package.json
index c40dc1d4..16f317ea 100644
--- a/package.json
+++ b/package.json
@@ -1,5 +1,5 @@
{
- "name": "aria-docs",
+ "name": "@rocicorp/zero-docs",
"version": "1.0.0",
"private": true,
"scripts": {
@@ -10,60 +10,61 @@
"start": "npm run build:search && next start",
"lint": "next lint",
"format": "prettier --write **/*.{ts,tsx,js,json,md,mdx}",
- "links": "blc http://localhost:3000/ -ro --exclude 'https://discord.rocicorp.dev/' --exclude 'https://bsky.app/profile/zero.rocicorp.dev' --exclude 'https://x.com/rocicorp_zero'"
+ "links": "blc http://localhost:3000/ -ro --exclude 'https://discord.rocicorp.dev/' --exclude 'https://bsky.app/profile/zero.rocicorp.dev' --exclude 'https://x.com/rocicorp_zero' --exclude 'https://x.com/zero__ms'"
},
"dependencies": {
- "@radix-ui/react-collapsible": "^1.1.0",
- "@radix-ui/react-dialog": "^1.1.1",
- "@radix-ui/react-dropdown-menu": "^2.1.1",
- "@radix-ui/react-scroll-area": "^1.1.0",
- "@radix-ui/react-slot": "^1.1.0",
+ "@radix-ui/react-collapsible": "^1.1.11",
+ "@radix-ui/react-dialog": "^1.1.14",
+ "@radix-ui/react-dropdown-menu": "^2.1.15",
+ "@radix-ui/react-scroll-area": "^1.2.9",
+ "@radix-ui/react-slot": "^1.2.3",
"@radix-ui/react-tooltip": "^1.2.7",
+ "@vercel/og": "^0.8.5",
"broken-link-checker": "^0.7.8",
- "class-variance-authority": "^0.7.0",
+ "class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cmdk": "^1.1.1",
"gray-matter": "^4.0.3",
- "lucide-react": "^0.435.0",
+ "lucide-react": "^0.537.0",
"lunr": "^2.3.9",
"mdast-util-to-string": "^4.0.0",
- "next": "^14.2.6",
+ "next": "^15.4.6",
"next-mdx-remote": "^5.0.0",
- "next-themes": "^0.3.0",
- "react": "^18.3.1",
- "react-dom": "^18.3.1",
+ "next-themes": "^0.4.6",
+ "react": "^19.1.1",
+ "react-dom": "^19.1.1",
"react-hotkeys-hook": "^5.1.0",
"rehype-autolink-headings": "^7.1.0",
"rehype-code-titles": "^1.2.0",
- "rehype-prism-plus": "^2.0.0",
+ "rehype-prism-plus": "^2.0.1",
"rehype-slug": "^6.0.0",
"remark": "^15.0.1",
- "remark-gfm": "^4.0.0",
+ "remark-gfm": "^4.0.1",
"remark-parse": "^11.0.0",
"remark-stringify": "^11.0.0",
"strip-markdown": "^6.0.0",
- "tailwind-merge": "^2.5.2",
+ "tailwind-merge": "^3.3.1",
"tailwindcss-animate": "^1.0.7",
"unist-util-visit": "^5.0.0"
},
"devDependencies": {
"@rocicorp/prettier-config": "^0.3.0",
- "@tailwindcss/typography": "^0.5.14",
+ "@tailwindcss/typography": "^0.5.16",
"@types/hast": "^3.0.4",
"@types/lunr": "^2.3.7",
- "@types/node": "^20.17.19",
- "@types/react": "^18",
- "@types/react-dom": "^18",
+ "@types/node": "^24.2.0",
+ "@types/react": "^19",
+ "@types/react-dom": "^19",
"@types/unist": "^3.0.3",
- "autoprefixer": "^10.4.20",
- "eslint": "^8",
- "eslint-config-next": "^14.2.6",
- "highlight.js": "^11.10.0",
+ "autoprefixer": "^10.4.21",
+ "eslint": "^9",
+ "eslint-config-next": "^15.4.6",
+ "highlight.js": "^11.11.1",
"postcss": "^8",
"react-highlight": "^0.15.0",
"tailwindcss": "^3.4.10",
"ts-node": "^10.9.2",
- "tsx": "^4.19.3",
+ "tsx": "^4.20.3",
"typescript": "^5"
},
"prettier": "@rocicorp/prettier-config"
diff --git a/public/images/reading-data/query-lifecycle.png b/public/images/reading-data/query-lifecycle.png
deleted file mode 100644
index 868ec239..00000000
Binary files a/public/images/reading-data/query-lifecycle.png and /dev/null differ
diff --git a/public/images/reading-data/query-lifecycle.svg b/public/images/reading-data/query-lifecycle.svg
new file mode 100644
index 00000000..8949e31c
--- /dev/null
+++ b/public/images/reading-data/query-lifecycle.svg
@@ -0,0 +1,14 @@
+
diff --git a/public/images/zero-docs-logo.svg b/public/images/zero-docs-logo.svg
new file mode 100644
index 00000000..31e191f6
--- /dev/null
+++ b/public/images/zero-docs-logo.svg
@@ -0,0 +1,12 @@
+
diff --git a/tsconfig.json b/tsconfig.json
index e7ff90fd..64c21044 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -19,7 +19,8 @@
],
"paths": {
"@/*": ["./*"]
- }
+ },
+ "target": "ES2017"
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
"exclude": ["node_modules"]