diff --git a/CHANGELOG_PUBLIC.md b/CHANGELOG_PUBLIC.md index 128db7b97fe..cb80938fa8a 100644 --- a/CHANGELOG_PUBLIC.md +++ b/CHANGELOG_PUBLIC.md @@ -18,6 +18,52 @@ list and feel free to give them credit at the end of a line, e.g.: --> +# Week 25 (2026-06-19) + +## v3.20.0 + +### All packages + +- Add support for new resource-specific permissions. You can now start from a + `*:read` or `*:write` base, then grant or deny access per resource (storage, + comments, feeds) using new permission strings like `storage:none` or + `comments:read`. + +### `@liveblocks/node` + +- Deprecate `session.FULL_ACCESS` and `session.READ_ACCESS` in favor of + `["*:write"]` and `["*:read"]` respectively. + +### `@liveblocks/client` + +- Deprecate `room.getStorageSnapshot()` in favor of `room.getStorageOrNull()`. + +## Examples + +- New example: [AI Spreadsheet](https://liveblocks.io/examples/ai-spreadsheet/nextjs-ai-spreadsheet). +- New example: [Realtime AI Elements Chats](https://liveblocks.io/examples/ai-elements-realtime/nextjs-ai-elements-realtime). +- Added “?” button to various examples, featuring a pop-up that explains how to use them. + +## Contributors + +ofoucherot, nvie, marcbouchenoire, ctnicholas + +# Week 24 (2026-06-12) + +## v3.19.5 + +### `@liveblocks/client` + +- Fix a `LiveList` divergence after reconnects: a pending `push` could under specific timing conditions during a reconnect still cause a divergence between clients, despite the fix from 3.19.4. + +## Liveblocks dev server (v1.6.1) + +- Fix a `LiveList` divergence after reconnects: when a client re-sends a pending `push` op whose node the server had already stored (the original ack got lost in the disconnect) + +## Contributors + +nvie + # Week 23 (2026-06-05) ## v3.19.4 @@ -49,9 +95,7 @@ list and feel free to give them credit at the end of a line, e.g.: ## Liveblocks dev server (v1.6.0) -- Update internal storage format of dev server. Note that your local dev rooms - are not automatically migrated and will appear as empty rooms after the - upgrade. +- Update internal storage format of dev server. Note that your local dev rooms are not automatically migrated and will appear as empty rooms after the upgrade. ## Contributors diff --git a/docs/pages/platform/limits.mdx b/docs/pages/platform/limits.mdx index df4861ae401..6bff7f4d67a 100644 --- a/docs/pages/platform/limits.mdx +++ b/docs/pages/platform/limits.mdx @@ -1,49 +1,51 @@ --- meta: title: "Limits" - parentTitle: "Platform" + parentTitle: "Pricing" description: "A list of all the limits and limitations that apply on Liveblocks." --- ## General limits -There are three plans: Free, Pro, Team, and Enterprise. Each plan has its own -set of limits. - -| | Free | Pro | Team | Enterprise | -| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | -| Monthly active rooms | | included
| included
| Up to | -| Monthly active users | | | | | -| Projects | | | | Up to | -| Team members | | included
| included
| Up to | -| Simultaneous connections per room | | | | | -| Simultaneous connections per project | | | | | -| Monthly anonymous connections Public key only recommended for prototyping. Set up authentication. | | | | | -| Realtime data storage This is a cumulative calculation that represents all data that is currently stored. It does not reset monthly, and the total usage will continue to accrue over time as you add more content and data. | | included
| included
| Up to | -| Realtime data stored per room | | | | | -| File storage This is a cumulative calculation that represents all files that are stored with Liveblocks. It does not reset monthly, and the total usage will continue to accrue over time as you add more files. Files can be uploaded as comment attachments for instance. | | included
| included
| | -| Max file upload size | | | | Up to | -| Comments stored | | | | | -| Monthly collaboration notifications Notifications automatically triggered from collaborative features like comment thread updates and @ mentions. | | | | | -| Monthly custom notifications Non-collaborative notifications that can be triggered from your own code. | | included
| included
| Up to | -| Webhook event frequency The frequency at which `yDocUpdated` (Yjs) and `storageUpdated` (Liveblocks Storage) events are sent to your webhook endpoint. Learn more | | | | Down to | -| Version history APIs, hooks, and pre-built components to access the previous versions of the realtime data stored in rooms. | | Unlimited with Version History Plus add‑on | Unlimited with Version History Plus add‑on | | -| Event log retention | | | | Up to | +There are four plans: Free, Pro, Team, and Enterprise. Each plan has its own set +of limits. + +| Limit | Free | Pro | Team | Enterprise | +| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------- | ------------------------------------------------- | -------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Monthly active rooms | | | | | +| Monthly active users | | | | | +| Projects | included | included | included | Up to }> included | +| Team members | included | included | included | Up to }> included | +| Simultaneous connections per room | | | | | +| Simultaneous connections per project | | | | | +| Monthly anonymous connections | | | | | +| Realtime data stored per room | | | | | +| Comments stored | | | | | +| Monthly collaboration notifications | | | | | +| Webhook event frequency | | | | Down to }> | +| Version history | | | | | +| Event log retention | | | | Up to }> | +| Max file upload size | | | | Up to }> | + +Metered usage like realtime collaboration minutes, comments, storage updates, +data stored, custom notifications, and file storage is billed through monthly +credits. See each [plan page](/docs/pricing/plans) for rates and included +credits. ## Other limits -| Item | Limit | -| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `roomId` The unique identifier for a room. What's a room? | 128 characters | -| `userId` The unique identifier for a user. Each `userId` must be used to represent a single user. | 128 characters | -| `userInfo` User information sent from the authentication endpoint. | 1024 characters once serialized to JSON | -| Broadcast event message Messages sent via the broadcast API for real-time communication between clients. | 32 MB Limited to 1 MB for client versions below 3.14. Make sure to upgrade to get higher limits. | -| Thread metadata Custom metadata attached to a thread. | 50 properties, key length 40 characters, value length 4000 characters | -| Comment metadata Custom metadata attached to a comment. | 50 properties, key length 40 characters, value length 4000 characters | -| `LiveObject` A realtime data structure that stores key-value pairs. Learn more | 2 MB when totalling the size of the keys and values For rooms powered by the v2 Storage engine. Rooms powered by the classic v1 engine are limited to 128 kB. | -| `LiveMap` A realtime data structure that stores key-value pairs in a map. Learn more | Unlimited, so long as each individual value does not exceed 2 MB For rooms powered by the v2 Storage engine. Rooms powered by the classic v1 engine are limited to 128 kB. | -| `LiveList` A realtime data structure that stores an ordered list of items. Learn more | Unlimited, so long as each individual value does not exceed 2 MB For rooms powered by the v2 Storage engine. Rooms powered by the classic v1 engine are limited to 128 kB. | +| Item | Limit | +| ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | +| roomId | 128 characters | +| userId | 128 characters | +| userInfo | 1024 characters once serialized to JSON | +| Broadcast event message | 32 MB | +| Thread metadata | 50 properties, key length 40 characters, value length 4000 characters | +| Comment metadata | 50 properties, key length 40 characters, value length 4000 characters | +| LiveObject | 2 MB when totalling the size of the keys and values | +| LiveMap | Unlimited, so long as each individual value does not exceed 2 MB | +| LiveList | Unlimited, so long as each individual value does not exceed 2 MB | Note that when one realtime data structure is nested inside another, it does not count towards the limit. Only the JSON leaves of your data structure count @@ -84,29 +86,29 @@ counted as 1 MAU, and a user that connects 8 hours a day for a month is also counted as 1 MAU. This applies so long as usage falls under our [Fair Use Policy](/docs/platform/limits/fair-use-policy). -### What’s a connection? +### What's a connection? A connection occurs when a user opens a web page containing a Liveblocks room. Each tab counts as one connection, which means that a user with two open tabs -has two connections. A room is joined when using{" "} +has two connections. A room is joined when using [`RoomProvider`](/docs/api-reference/liveblocks-react#RoomProvider) in React or [`enterRoom`](/docs/api-reference/liveblocks-client#Client.enterRoom) in JavaScript. Liveblocks connections are analogous to WebSocket connections, representing a realtime link to our server. -### What’s a room? +### What's a room? A room is the virtual space where people collaborate. For most products, a room corresponds to a document. -### What’s a simultaneous connection per room? +### What's a simultaneous connection per room? A simultaneous connection per room is when a user or multiple users are connected to the same Liveblocks room at the same time. Learn more about handling simultaneous room connection limits in our guide about [joining rooms at maximum capacity](/docs/guides/what-happens-when-a-user-joins-a-room-at-maximum-capacity). -### What’s a simultaneous connection per project? +### What's a simultaneous connection per project? A simultaneous connection per project is when a user or multiple users are connected to the same project at the same time. @@ -126,5 +128,5 @@ That way, you can decide how to best handle those cases in your product. ### Do you count monthly active rooms during testing? Yes, if test users connect to a room during automated testing, the room will be -counted as a monthly active room. To prevet hitting limits during testing, you +counted as a monthly active room. To prevent hitting limits during testing, you may want to provide a set of reusable `roomId`s. diff --git a/docs/pages/platform/limits/fair-use-guidelines.mdx b/docs/pages/platform/limits/fair-use-guidelines.mdx index bd4e03b4239..87f066dc33f 100644 --- a/docs/pages/platform/limits/fair-use-guidelines.mdx +++ b/docs/pages/platform/limits/fair-use-guidelines.mdx @@ -73,13 +73,13 @@ additional usage, giving you greater flexibility and control over your usage. The typical monthly usage guidelines above are still applicable, while extra usage will be automatically charged at the following rates: -| Item | Included | Pay-as-you-go | -| -------------------------------------------------------------------------------- | ---------------------------------------- | ------------------------------------------ | -| Monthly active rooms | | | -| Team members | | | -| Realtime data storage | | | -| File storage | | | -| Monthly custom notifications | | | +| Item | Included | Pay-as-you-go | +| ----------------------------------------------------------------------------------- | ---------------------------------------- | ---------------------------------------- | +| Monthly active rooms | | | +| Dashboard seats | | | +| Realtime data storage | | | +| File storage | | | +| Monthly custom notifications | | | Usage beyond included amounts will continue to be billed at pay-as-you-go rates unless another arrangement is put in place. diff --git a/docs/pages/pricing/billing.mdx b/docs/pages/pricing/billing.mdx new file mode 100644 index 00000000000..6c17fd98159 --- /dev/null +++ b/docs/pages/pricing/billing.mdx @@ -0,0 +1,46 @@ +--- +meta: + title: "Billing" + parentTitle: "Pricing" + description: "How billing works on Liveblocks, from credits to your invoice." +--- + +This page explains how credits, billing cycles, overage, and invoices work. For +plan prices and metered rates, see [Pricing overview](/docs/pricing/overview). + +## Credits + +Every paid plan includes a monthly credit allowance. Credits are applied +automatically to your metered usage, like realtime collaboration minutes, +comments, custom notifications, and storage. You only pay once you have used up +your credits. Your plan base is what buys those credits, and on higher Team +tiers the included credits are worth more than the base price, so you get more +usage for the same spend. + +## Billing cycle + +Billing runs monthly, from the 1st to the last day of the month. Credits reset +at the start of each cycle and do not roll over. + +## Overage + +Usage above your monthly credits is overage. It is charged at the per-unit rates +in each plan's [Metered usage](/docs/pricing/plans/pro#Metered-usage) table and +added to your invoice. Your total is always your plan base plus any overage. + +## Annual billing + +Pay annually to get two months free compared with monthly billing. Credits still +reset each month. + +## Invoices and payment + +Paid plans are billed by card. Invoicing is available on Enterprise. +[Contact sales](/contact/sales) to set this up. You can view and download past +invoices from your [dashboard billing settings](/dashboard). + +## Tracking your spend + +See your usage and remaining credits at any time on your +[dashboard usage page](/dashboard/usage), so there are no surprises on your +invoice. diff --git a/docs/pages/pricing/faqs.mdx b/docs/pages/pricing/faqs.mdx new file mode 100644 index 00000000000..50ac7303fb2 --- /dev/null +++ b/docs/pages/pricing/faqs.mdx @@ -0,0 +1,102 @@ +--- +meta: + title: "Pricing FAQs" + parentTitle: "Pricing" + description: "Frequently asked questions about Liveblocks pricing." +--- + +## How does pricing work in Liveblocks? + +Each plan includes a monthly credit allowance you spend across all features. +Credits reset at the start of each billing cycle and don't roll over. Pro is +$30/month with $30 of credits, and Team plans range from $600 to $3,750/month +with up to $5,000 of credits. Once you've used your credits, additional usage on +Pro and Team is billed at metered rates. Free hits hard limits per feature +instead. + +For full per-metric rates and worked examples, see our +[pricing overview](/docs/pricing/overview). + +## What counts as a realtime collaboration minute? + +One realtime collaboration minute is one connected user, in one room, for one +minute. Two users in a room for 5 minutes is 10 collaboration minutes, billed at +$0.002 each. You can see exactly what's being counted on your +[dashboard usage page](/dashboard/usage). + +## Which Liveblocks plan should I choose? + +Liveblocks offers four plans to support developers and teams of all sizes: + +- **Free:** Personal projects and prototyping +- **Pro:** Indie devs and small teams shipping commercial apps +- **Team:** Teams that need SSO, SOC 2, and more than 3 seats +- **Enterprise:** Larger orgs needing volume discounts, multi-region hosting, + and custom terms + +Compare features in detail: [Free](/docs/pricing/plans/free), +[Pro](/docs/pricing/plans/pro), [Team](/docs/pricing/plans/team), +[Enterprise](/docs/pricing/plans/enterprise). + +## What comes with my Liveblocks subscription? + +Every plan includes the full platform: +[Presence](/docs/ready-made-features/presence), +[Storage](/docs/collaboration-features/multiplayer/sync-engine/liveblocks-storage), +[Comments](/docs/ready-made-features/comments), +[Custom Notifications](/docs/ready-made-features/notifications/concepts#Custom-notifications), +[Feeds](/docs/collaboration-features/ai-collaboration), +[AI Copilots](/docs/ready-made-features/ai-copilots), the +[dashboard](/dashboard), SDKs, and APIs. What changes between plans is your +monthly credit allowance, seat count, and the security and support features you +get. After you've used your credits, you keep using Liveblocks. Pro and Team are +charged for overage at the same metered rates. Free plans hit hard limits per +feature. + +For a full plan-by-plan breakdown, see the [plans docs](/docs/pricing/plans). + +## Can I try Liveblocks before paying for it? + +Yes. The Free plan is permanently free, no credit card required. You can build, +test, and even ship commercial apps on Free as long as the Liveblocks watermark +stays visible. To remove the watermark and unlock overage, upgrade to Pro at +$30/month. [Get started for free](/auth/signup). + +## Are there discounts for startups, nonprofits, or students? + +We offer a discount for early-stage startups. [Learn more and apply](/startups). + +## What happens when I run out of Liveblocks credits? + +On Free, you'll hit hard limits per metric and the affected feature pauses until +your credits reset. On Pro and Team, additional usage is billed at metered rates +with no markup. We send automated email alerts as you approach your limits. + +See [usage limits](/docs/platform/limits) for full details. + +## How do I track and control my Liveblocks spending? + +The [usage page](/dashboard/usage) in your dashboard shows real-time usage +broken down by metric, current credit consumption, and projected month-end +spend. We also send automated email alerts as you approach your limits. For +predictable spend, your monthly credits give you a fixed ceiling unless you +allow overage, and annual Team plans lock in a fixed monthly cost while saving +up to 38% versus monthly billing. + +## Can I pay by invoice instead of credit card? + +Yes, on Enterprise plans. [Contact sales](/contact/sales) to set this up. + +## Does Liveblocks support multi-region hosting? + +Yes, on Enterprise. We currently support EU and US, with more coming. +[Reach out to sales](/contact) to discuss upgrading to an Enterprise plan. + +## How secure and reliable is Liveblocks? + +We run on edge infrastructure with 99.99% uptime, monitored on our +[status page](https://liveblocks.statuspage.io). We're SOC 2 and HIPAA +compliant, and GDPR-compliant with a Data Processing Agreement (DPA) available +on request. Enterprise plans support data residency in specific regions. For +more, see our [security page](/security) and +[data storage docs](/docs/platform/data-storage). diff --git a/docs/pages/pricing/overview.mdx b/docs/pages/pricing/overview.mdx new file mode 100644 index 00000000000..07c39706d02 --- /dev/null +++ b/docs/pages/pricing/overview.mdx @@ -0,0 +1,72 @@ +--- +meta: + title: "Pricing overview" + parentTitle: "Pricing" + description: + "How Liveblocks pricing works: plans, credits, metered usage, and billing." +--- + +Liveblocks is usage-based. You choose a plan, each plan includes a monthly +credit allowance, and your credits are applied to what your app actually uses. +You only pay more if your usage goes above your credits. For full plan details, +see the [pricing page](/pricing/). + +## Plans + +There are four plans, so you can pick the one that fits where you are: + +- **Free:** for personal development, prototyping, and testing. No credit card + required. +- **Pro:** for developers shipping collaborative features in production. +- **Team:** for teams shipping collaborative features at scale, with added + security and support. +- **Enterprise:** a custom plan for premium security and partnership needs. + +| Plan | Monthly base | Included credits | +| ---------- | -------------------------------- | -------------------- | +| Free | $0 | Free monthly credits | +| Pro | $30 ($25 billed annually) | $30 | +| Team | from $600 ($500 billed annually) | from $600 | +| Enterprise | Custom | Custom | + +See [Plans](/docs/pricing/plans) for full details on each plan. + +## How usage is metered + +Liveblocks charges for what your app uses, applied against your monthly credits +first. The main metered units: + +| Unit | Description | Rate | +| ----------------------------------------------------------------------- | ----------------------------------------------------- | ----------------- | +| [Realtime collaboration minutes](/docs/pricing/plans/pro#Metered-usage) | Active time people and agents spend together in rooms | $0.002 per minute | +| [Comments created](/docs/pricing/plans/pro#Metered-usage) | Each comment posted in your app | $0.01 per comment | +| [Realtime data storage updates](/docs/pricing/plans/pro#Metered-usage) | Each change written to stored data | $1 per 1M updates | +| [Realtime data stored](/docs/pricing/plans/pro#Metered-usage) | Total data kept in storage | $0.15 per GB | +| [Monthly custom notifications](/docs/pricing/plans/pro#Metered-usage) | Notifications you trigger from your own code | $0.01 per event | +| [File storage](/docs/pricing/plans/pro#Metered-usage) | Total files stored | $0.15 per GB | + +Rates shown here are indicative. See +[Pro](/docs/pricing/plans/pro#Metered-usage) and +[Team](/docs/pricing/plans/team#Metered-usage) for current per-unit prices. + +[Collaboration notifications](/docs/ready-made-features/notifications/concepts#Collaboration-notifications), +like mentions and thread replies, are included free. + +## Credits + +Every plan includes a monthly credit allowance that covers your metered usage +first. Credits reset at the start of each billing cycle and do not roll over. +Higher Team tiers include more credit value than they cost, so you get more +usage for the same base. Usage above your credits is overage, billed at the +per-unit rates above. + +## Limits + +Each plan has limits that protect your account and your costs. See +[Limits](/docs/platform/limits) for the full list. + +## Billing + +You're billed monthly: your plan base plus any overage from the previous cycle. +Pay annually to get two months free. See [Billing](/docs/pricing/billing) for +details. diff --git a/docs/pages/pricing/plans.mdx b/docs/pages/pricing/plans.mdx index 42a10788dcc..816ad9904a0 100644 --- a/docs/pages/pricing/plans.mdx +++ b/docs/pages/pricing/plans.mdx @@ -32,19 +32,19 @@ monthly credits. The Team plan is designed for teams shipping collaborative experiences in production with the ability to scale. It includes everything in Pro, plus SAML -Single Sign-on (SSO), SOC 2, and a private Slack channel. Team starts at +Single Sign-on (SSO), SOC 2, and a private Slack channel. - monthly credits, and volume discounts can be -applied by purchasing more credits. You can also request a HIPAA Business -Associate Agreement (BAA) as a paid add-on. +Team comes with monthly credits, and volume +discounts can be applied by purchasing more credits. You can also request a +HIPAA Business Associate Agreement (BAA) as a paid add-on. [Learn more about the Team plan](/docs/pricing/plans/team) ### Add-ons -| Add-on | Price | -| --------- | --------------------------------------------------------- | -| HIPAA BAA | $350 per month Billed annually | +| Add-on | Price | +| ------------------------------------------------------------- | -------------- | +| HIPAA BAA | $350 per month | ## Enterprise diff --git a/docs/pages/pricing/plans/enterprise.mdx b/docs/pages/pricing/plans/enterprise.mdx index d126d8620fb..8ab056d0612 100644 --- a/docs/pages/pricing/plans/enterprise.mdx +++ b/docs/pages/pricing/plans/enterprise.mdx @@ -5,11 +5,44 @@ meta: description: "Learn about the Liveblocks Enterprise plan." --- -The Enterprise plan is tailored for organizations with advanced security, -compliance, and scalability requirements. It includes everything in Team, plus -multi-region hosting, a management API, SCIM/directory sync, advanced -permissions, custom usage allocations, and higher-touch support options with -SLAs and solution engineering. +The Enterprise plan is for organizations with advanced security, compliance, and +scalability requirements. It includes everything in Team, plus multi-region +hosting, a management API, SCIM/directory sync, advanced permissions, custom +usage allocations, and higher-touch support with SLAs. + +[Contact sales](/contact/sales) for pricing, custom credit allocations, and +invoice billing. + +## Metered usage + +Metered usage is billed per unit, only for what you actually use. Enterprise +plans include a custom monthly credit allowance negotiated for your workload. +Usage above your credits is overage, billed at agreed per-unit rates. + +See [Team metered usage](/docs/pricing/plans/team#Metered-usage) for reference +rates. Your contract may include volume discounts or custom allocations. + +## Other limits + +Enterprise limits are customized for your organization. See +[Limits](/docs/platform/limits) for reference values and +[contact sales](/contact/sales) to discuss your requirements. + +| Item | Enterprise limit | +| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Monthly active users | | +| Monthly active rooms | | +| Projects | Up to }> included | +| Dashboard seats | Up to }> included | +| Simultaneous connections per room | | +| Simultaneous connections per project | | +| Monthly anonymous connections | | +| Realtime data stored per room | | +| Max file upload size | Up to }> | +| Webhook event frequency | Down to }> | +| Version history | | +| Event log retention | Up to }> | +| Environments | | ## Security and compliance @@ -25,16 +58,18 @@ Built-in support for global security and data protection standards, including: ## Observability and reporting -Gain actionable insights with enhanced observability & logging: - - Extended event log retention - External observability integrations (soon) ## Administration and support -The Enterprise plan allows for streamlined team collaboration and offers robust -support with: - - Role-Based Access Control (RBAC) - A dedicated solution engineer - SLAs, including response time + +## Billing cycle + +The Enterprise plan follows a monthly billing cycle that starts on the 1st of +each month and ends on the last day of the month. Monthly credits renew at the +beginning of each billing cycle and are applied to metered usage. Any usage not +covered by credits appears on your invoice. diff --git a/docs/pages/pricing/plans/free.mdx b/docs/pages/pricing/plans/free.mdx index cc62d1d6155..e1be0b64392 100644 --- a/docs/pages/pricing/plans/free.mdx +++ b/docs/pages/pricing/plans/free.mdx @@ -11,38 +11,47 @@ month basis. ## Included usage -| Item | Free included usage | -| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------ | -| Realtime collaboration minutes The total active time people and agents spent together inside rooms. | included | -| Comments created The number of comments created in rooms. | included | -| Realtime data storage updates Number of Liveblocks Storage row updates in the selected period, aggregated across the projects you include in the filter. | included | -| Realtime data stored This is a cumulative calculation that represents all data that is currently stored. It does not reset monthly, and the total usage will continue to accrue over time as you add more content and data. | included | -| Monthly collaboration notifications Notifications automatically triggered from collaborative features like comment thread updates and @ mentions. | | -| Monthly custom notifications Non-collaborative notifications that can be triggered from your own code. | included | -| File storage This is a cumulative calculation that represents all files that are stored with Liveblocks. It does not reset monthly, and the total usage will continue to accrue over time as you add more files. Files can be uploaded as comment attachments for instance. | included | +The Free plan includes monthly usage allowances for each metered unit. When you +reach a limit, the affected feature pauses until the next billing cycle. Upgrade +to [Pro](/docs/pricing/plans/pro) or [Team](/docs/pricing/plans/team) for +monthly credits and overage billing. + +| Item | Free included usage | +| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------ | +| Realtime collaboration minutes | included | +| Comments created | included | +| Realtime data storage updates | included | +| Realtime data stored | included | +| Monthly collaboration notifications | | +| Monthly custom notifications | included | +| File storage | included | ## Other limits -| Item | Free limit | -| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------- | -| Monthly active users | | -| Monthly active rooms | included | -| Projects | included | -| Dashboard seats Team members with Owner or Member role. They can configure projects, roll keys, and more. | included | -| Simultaneous connections per room | | -| Simultaneous connections per project | | -| Monthly anonymous connections Public key only recommended for prototyping. Set up authentication. | | -| Max file upload size | | -| Webhook event frequency The frequency at which `yDocUpdated` (Yjs) and `storageUpdated` (Liveblocks Storage) events are sent to your webhook endpoint. Learn more | | -| Version history APIs, hooks, and pre-built components to access the previous versions of the realtime data stored in rooms. | | -| Event log retention | | -| Environments | | +These are the allowances included with the plan. They are not metered. They +define what's included before you need to upgrade. + +| Item | Free limit | +| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------- | +| Monthly active users | | +| Monthly active rooms | included | +| Projects | included | +| Dashboard seats | included | +| Simultaneous connections per room | | +| Simultaneous connections per project | | +| Monthly anonymous connections | | +| Realtime data stored per room | | +| Max file upload size | | +| Webhook event frequency | | +| Version history | | +| Event log retention | | +| Environments | | ## Billing cycle Even though the Free plan has no cost, usage limits follow a monthly billing cycle that starts on the 1st of each month and ends on the last day of the -month. If you exceed your usage limits, you’ll need to wait until the next +month. If you exceed your usage limits, you'll need to wait until the next calendar month for limits to reset. Alternatively, you can upgrade to [Pro](/dashboard/billing?plan=pro) or [Team](/dashboard/billing?plan=team) to access monthly credits and ongoing metered usage. diff --git a/docs/pages/pricing/plans/pro.mdx b/docs/pages/pricing/plans/pro.mdx index 282fb0f8061..b21a83bd4d8 100644 --- a/docs/pages/pricing/plans/pro.mdx +++ b/docs/pages/pricing/plans/pro.mdx @@ -19,34 +19,42 @@ Annual Pro billing gives you 2 months free. ## Metered usage -| Item | Pro pricing | -| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------- | -| Realtime collaboration minutes The total active time people and agents spent together inside rooms. | | -| Comments created The number of comments created in rooms. | | -| Realtime data storage updates Number of Liveblocks Storage row updates in the selected period, aggregated across the projects you include in the filter. | | -| Realtime data stored This is a cumulative calculation that represents all data that is currently stored. It does not reset monthly, and the total usage will continue to accrue over time as you add more content and data. | | -| Monthly collaboration notifications Notifications automatically triggered from collaborative features like comment thread updates and @ mentions. | | -| Monthly custom notifications Non-collaborative notifications that can be triggered from your own code. | | -| File storage This is a cumulative calculation that represents all files that are stored with Liveblocks. It does not reset monthly, and the total usage will continue to accrue over time as you add more files. Files can be uploaded as comment attachments for instance. | | +Metered usage is billed per unit, only for what you actually use. Each plan +includes monthly credits that cover this usage first, so you only pay for +anything above them. + +| Item | Pro pricing | +| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------- | +| Realtime collaboration minutes | | +| Comments created | | +| Realtime data storage updates | | +| Realtime data stored | | +| Monthly collaboration notifications | | +| Monthly custom notifications | | +| File storage | | ## Other limits -| Item | Pro limit | -| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------- | -| Monthly active users | | -| Monthly active rooms | | -| Projects | included | -| Dashboard seats Team members with Owner or Member role. They can configure projects, roll keys, and more. | included | -| Simultaneous connections per room | | -| Simultaneous connections per project | | -| Monthly anonymous connections Public key only recommended for prototyping. Set up authentication. | | -| Average connections per user | | -| Active room hours per month | | -| Max file upload size | | -| Webhook event frequency The frequency at which `yDocUpdated` (Yjs) and `storageUpdated` (Liveblocks Storage) events are sent to your webhook endpoint. Learn more | | -| Version history APIs, hooks, and pre-built components to access the previous versions of the realtime data stored in rooms. | Unlimited with Version History add-on | -| Event log retention | | -| Environments | | +These are the allowances included with the plan. They are not metered. They +define what's included before you need to upgrade. + +| Item | Pro limit | +| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------- | +| Monthly active users | | +| Monthly active rooms | | +| Projects | included | +| Dashboard seats | included | +| Simultaneous connections per room | | +| Simultaneous connections per project | | +| Monthly anonymous connections | | +| Average connections per user | | +| Active room hours per month | | +| Realtime data stored per room | | +| Max file upload size | | +| Webhook event frequency | | +| Version history | | +| Event log retention | | +| Environments | | ## Billing cycle diff --git a/docs/pages/pricing/plans/team.mdx b/docs/pages/pricing/plans/team.mdx index 7462f00039b..ad9e8a201db 100644 --- a/docs/pages/pricing/plans/team.mdx +++ b/docs/pages/pricing/plans/team.mdx @@ -24,38 +24,46 @@ Annual Team billing gives you 2 months free. ## Metered usage -| Item | Team pricing | -| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------- | -| Realtime collaboration minutes The total active time people and agents spent together inside rooms. | | -| Comments created The number of comments created in rooms. | | -| Realtime data storage updates Number of Liveblocks Storage row updates in the selected period, aggregated across the projects you include in the filter. | | -| Realtime data stored This is a cumulative calculation that represents all data that is currently stored. It does not reset monthly, and the total usage will continue to accrue over time as you add more content and data. | | -| Monthly collaboration notifications Notifications automatically triggered from collaborative features like comment thread updates and @ mentions. | | -| Monthly custom notifications Non-collaborative notifications that can be triggered from your own code. | | -| File storage This is a cumulative calculation that represents all files that are stored with Liveblocks. It does not reset monthly, and the total usage will continue to accrue over time as you add more files. Files can be uploaded as comment attachments for instance. | | +Metered usage is billed per unit, only for what you actually use. Each plan +includes monthly credits that cover this usage first, so you only pay for +anything above them. + +| Item | Team pricing | +| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------- | +| Realtime collaboration minutes | | +| Comments created | | +| Realtime data storage updates | | +| Realtime data stored | | +| Monthly collaboration notifications | | +| Monthly custom notifications | | +| File storage | | ## Other limits -| Item | Team limit | -| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------- | -| Monthly active users | | -| Monthly active rooms | | -| Projects | included | -| Dashboard seats Team members with Owner or Member role. They can configure projects, roll keys, and more. | included, | -| Simultaneous connections per room | | -| Simultaneous connections per project | | -| Monthly anonymous connections Public key only recommended for prototyping. Set up authentication. | | -| Average connections per user | | -| Active room hours per month | | -| Max file upload size | | -| Webhook event frequency The frequency at which `yDocUpdated` (Yjs) and `storageUpdated` (Liveblocks Storage) events are sent to your webhook endpoint. Learn more | | -| Version history APIs, hooks, and pre-built components to access the previous versions of the realtime data stored in rooms. | Unlimited with Version History add-on | -| Event log retention | | -| SAML SSO | Included | -| SOC 2 report | Included | -| Private Slack channel | Included | -| HIPAA BAA | per month Billed annually | -| Environments | | +These are the allowances included with the plan. They are not metered. They +define what's included before you need to upgrade. + +| Item | Team limit | +| -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | +| Monthly active users | | +| Monthly active rooms | | +| Projects | included | +| Dashboard seats | included, | +| Simultaneous connections per room | | +| Simultaneous connections per project | | +| Monthly anonymous connections | | +| Average connections per user | | +| Active room hours per month | | +| Realtime data stored per room | | +| Max file upload size | | +| Webhook event frequency | | +| Version history | | +| Event log retention | | +| SAML SSO | Included | +| SOC 2 report | Included | +| Private Slack channel | Included | +| HIPAA BAA | per month | +| Environments | | ## Billing cycle @@ -66,6 +74,6 @@ covered by credits appears on your invoice. ## Add-ons -| Add-on | Price | -| --------- | ------------------------------------------------------------------------------------- | -| HIPAA BAA | per month Billed annually | +| Add-on | Price | +| --------- | ----------------------------------------------------------- | +| HIPAA BAA | per month, billed annually | diff --git a/docs/routes.json b/docs/routes.json index 384dcd312b0..e9cd035c0df 100644 --- a/docs/routes.json +++ b/docs/routes.json @@ -822,16 +822,6 @@ "path": "/platform/account-management/delete-an-account" } ] - }, - { - "title": "Limits", - "path": "/platform/limits", - "routes": [ - { - "title": "Fair use guidelines", - "path": "/platform/limits/fair-use-guidelines" - } - ] } ] }, @@ -839,6 +829,10 @@ "title": "Pricing", "defaultCollapsed": true, "routes": [ + { + "title": "Overview", + "path": "/pricing/overview" + }, { "title": "Plans", "path": "/pricing/plans", @@ -860,6 +854,24 @@ "path": "/pricing/plans/enterprise" } ] + }, + { + "title": "Billing", + "path": "/pricing/billing" + }, + { + "title": "Limits", + "path": "/platform/limits", + "routes": [ + { + "title": "Fair use guidelines", + "path": "/platform/limits/fair-use-guidelines" + } + ] + }, + { + "title": "Pricing FAQs", + "path": "/pricing/faqs" } ] }, diff --git a/examples/nextjs-ai-elements-realtime/components/ai-elements/artifact.tsx b/examples/nextjs-ai-elements-realtime/components/ai-elements/artifact.tsx deleted file mode 100644 index c90cb5fe3dd..00000000000 --- a/examples/nextjs-ai-elements-realtime/components/ai-elements/artifact.tsx +++ /dev/null @@ -1,147 +0,0 @@ -"use client"; - -import { Button } from "@/components/ui/button"; -import { - Tooltip, - TooltipContent, - TooltipProvider, - TooltipTrigger, -} from "@/components/ui/tooltip"; -import { cn } from "@/lib/utils"; -import { type LucideIcon, XIcon } from "lucide-react"; -import type { ComponentProps, HTMLAttributes } from "react"; - -export type ArtifactProps = HTMLAttributes; - -export const Artifact = ({ className, ...props }: ArtifactProps) => ( -
-); - -export type ArtifactHeaderProps = HTMLAttributes; - -export const ArtifactHeader = ({ - className, - ...props -}: ArtifactHeaderProps) => ( -
-); - -export type ArtifactCloseProps = ComponentProps; - -export const ArtifactClose = ({ - className, - children, - size = "sm", - variant = "ghost", - ...props -}: ArtifactCloseProps) => ( - -); - -export type ArtifactTitleProps = HTMLAttributes; - -export const ArtifactTitle = ({ className, ...props }: ArtifactTitleProps) => ( -

-); - -export type ArtifactDescriptionProps = HTMLAttributes; - -export const ArtifactDescription = ({ - className, - ...props -}: ArtifactDescriptionProps) => ( -

-); - -export type ArtifactActionsProps = HTMLAttributes; - -export const ArtifactActions = ({ - className, - ...props -}: ArtifactActionsProps) => ( -

-); - -export type ArtifactActionProps = ComponentProps & { - tooltip?: string; - label?: string; - icon?: LucideIcon; -}; - -export const ArtifactAction = ({ - tooltip, - label, - icon: Icon, - children, - className, - size = "sm", - variant = "ghost", - ...props -}: ArtifactActionProps) => { - const button = ( - - ); - - if (tooltip) { - return ( - - - {button} - -

{tooltip}

-
-
-
- ); - } - - return button; -}; - -export type ArtifactContentProps = HTMLAttributes; - -export const ArtifactContent = ({ - className, - ...props -}: ArtifactContentProps) => ( -
-); diff --git a/examples/nextjs-ai-elements-realtime/components/ai-elements/canvas.tsx b/examples/nextjs-ai-elements-realtime/components/ai-elements/canvas.tsx deleted file mode 100644 index 5aa83cb5e73..00000000000 --- a/examples/nextjs-ai-elements-realtime/components/ai-elements/canvas.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import { Background, ReactFlow, type ReactFlowProps } from "@xyflow/react"; -import type { ReactNode } from "react"; -import "@xyflow/react/dist/style.css"; - -type CanvasProps = ReactFlowProps & { - children?: ReactNode; -}; - -export const Canvas = ({ children, ...props }: CanvasProps) => ( - - - {children} - -); diff --git a/examples/nextjs-ai-elements-realtime/components/ai-elements/checkpoint.tsx b/examples/nextjs-ai-elements-realtime/components/ai-elements/checkpoint.tsx deleted file mode 100644 index d9a5d326c88..00000000000 --- a/examples/nextjs-ai-elements-realtime/components/ai-elements/checkpoint.tsx +++ /dev/null @@ -1,68 +0,0 @@ -"use client"; - -import { Button } from "@/components/ui/button"; -import { Separator } from "@/components/ui/separator"; -import { - Tooltip, - TooltipContent, - TooltipTrigger, -} from "@/components/ui/tooltip"; -import { cn } from "@/lib/utils"; -import { BookmarkIcon, type LucideProps } from "lucide-react"; -import type { ComponentProps, HTMLAttributes } from "react"; - -export type CheckpointProps = HTMLAttributes; - -export const Checkpoint = ({ - className, - children, - ...props -}: CheckpointProps) => ( -
- {children} - -
-); - -export type CheckpointIconProps = LucideProps; - -export const CheckpointIcon = ({ - className, - children, - ...props -}: CheckpointIconProps) => - children ?? ( - - ); - -export type CheckpointTriggerProps = ComponentProps & { - tooltip?: string; -}; - -export const CheckpointTrigger = ({ - children, - className, - variant = "ghost", - size = "sm", - tooltip, - ...props -}: CheckpointTriggerProps) => - tooltip ? ( - - - - - - {tooltip} - - - ) : ( - - ); diff --git a/examples/nextjs-ai-elements-realtime/components/ai-elements/confirmation.tsx b/examples/nextjs-ai-elements-realtime/components/ai-elements/confirmation.tsx deleted file mode 100644 index 2ec0aab5785..00000000000 --- a/examples/nextjs-ai-elements-realtime/components/ai-elements/confirmation.tsx +++ /dev/null @@ -1,176 +0,0 @@ -"use client"; - -import { Alert, AlertDescription } from "@/components/ui/alert"; -import { Button } from "@/components/ui/button"; -import { cn } from "@/lib/utils"; -import type { ToolUIPart } from "ai"; -import { - type ComponentProps, - createContext, - type ReactNode, - useContext, -} from "react"; - -type ToolUIPartApproval = - | { - id: string; - approved?: never; - reason?: never; - } - | { - id: string; - approved: boolean; - reason?: string; - } - | { - id: string; - approved: true; - reason?: string; - } - | { - id: string; - approved: true; - reason?: string; - } - | { - id: string; - approved: false; - reason?: string; - } - | undefined; - -type ConfirmationContextValue = { - approval: ToolUIPartApproval; - state: ToolUIPart["state"]; -}; - -const ConfirmationContext = createContext( - null -); - -const useConfirmation = () => { - const context = useContext(ConfirmationContext); - - if (!context) { - throw new Error("Confirmation components must be used within Confirmation"); - } - - return context; -}; - -export type ConfirmationProps = ComponentProps & { - approval?: ToolUIPartApproval; - state: ToolUIPart["state"]; -}; - -export const Confirmation = ({ - className, - approval, - state, - ...props -}: ConfirmationProps) => { - if (!approval || state === "input-streaming" || state === "input-available") { - return null; - } - - return ( - - - - ); -}; - -export type ConfirmationTitleProps = ComponentProps; - -export const ConfirmationTitle = ({ - className, - ...props -}: ConfirmationTitleProps) => ( - -); - -export type ConfirmationRequestProps = { - children?: ReactNode; -}; - -export const ConfirmationRequest = ({ children }: ConfirmationRequestProps) => { - const { state } = useConfirmation(); - - // Only show when approval is requested - if (state !== "approval-requested") { - return null; - } - - return children; -}; - -export type ConfirmationAcceptedProps = { - children?: ReactNode; -}; - -export const ConfirmationAccepted = ({ - children, -}: ConfirmationAcceptedProps) => { - const { approval, state } = useConfirmation(); - - // Only show when approved and in response states - if ( - !approval?.approved || - (state !== "approval-responded" && - state !== "output-denied" && - state !== "output-available") - ) { - return null; - } - - return children; -}; - -export type ConfirmationRejectedProps = { - children?: ReactNode; -}; - -export const ConfirmationRejected = ({ - children, -}: ConfirmationRejectedProps) => { - const { approval, state } = useConfirmation(); - - // Only show when rejected and in response states - if ( - approval?.approved !== false || - (state !== "approval-responded" && - state !== "output-denied" && - state !== "output-available") - ) { - return null; - } - - return children; -}; - -export type ConfirmationActionsProps = ComponentProps<"div">; - -export const ConfirmationActions = ({ - className, - ...props -}: ConfirmationActionsProps) => { - const { state } = useConfirmation(); - - // Only show when approval is requested - if (state !== "approval-requested") { - return null; - } - - return ( -
- ); -}; - -export type ConfirmationActionProps = ComponentProps; - -export const ConfirmationAction = (props: ConfirmationActionProps) => ( - - ); -}; - -export type InlineCitationCarouselNextProps = ComponentProps<"button">; - -export const InlineCitationCarouselNext = ({ - className, - ...props -}: InlineCitationCarouselNextProps) => { - const api = useCarouselApi(); - - const handleClick = useCallback(() => { - if (api) { - api.scrollNext(); - } - }, [api]); - - return ( - - ); -}; - -export type InlineCitationSourceProps = ComponentProps<"div"> & { - title?: string; - url?: string; - description?: string; -}; - -export const InlineCitationSource = ({ - title, - url, - description, - className, - children, - ...props -}: InlineCitationSourceProps) => ( -
- {title && ( -

{title}

- )} - {url && ( -

{url}

- )} - {description && ( -

- {description} -

- )} - {children} -
-); - -export type InlineCitationQuoteProps = ComponentProps<"blockquote">; - -export const InlineCitationQuote = ({ - children, - className, - ...props -}: InlineCitationQuoteProps) => ( -
- {children} -
-); diff --git a/examples/nextjs-ai-elements-realtime/components/ai-elements/model-selector.tsx b/examples/nextjs-ai-elements-realtime/components/ai-elements/model-selector.tsx deleted file mode 100644 index ef6ebd7e8b8..00000000000 --- a/examples/nextjs-ai-elements-realtime/components/ai-elements/model-selector.tsx +++ /dev/null @@ -1,205 +0,0 @@ -import { - Command, - CommandDialog, - CommandEmpty, - CommandGroup, - CommandInput, - CommandItem, - CommandList, - CommandSeparator, - CommandShortcut, -} from "@/components/ui/command"; -import { - Dialog, - DialogContent, - DialogTitle, - DialogTrigger, -} from "@/components/ui/dialog"; -import { cn } from "@/lib/utils"; -import type { ComponentProps, ReactNode } from "react"; - -export type ModelSelectorProps = ComponentProps; - -export const ModelSelector = (props: ModelSelectorProps) => ( - -); - -export type ModelSelectorTriggerProps = ComponentProps; - -export const ModelSelectorTrigger = (props: ModelSelectorTriggerProps) => ( - -); - -export type ModelSelectorContentProps = ComponentProps & { - title?: ReactNode; -}; - -export const ModelSelectorContent = ({ - className, - children, - title = "Model Selector", - ...props -}: ModelSelectorContentProps) => ( - - {title} - - {children} - - -); - -export type ModelSelectorDialogProps = ComponentProps; - -export const ModelSelectorDialog = (props: ModelSelectorDialogProps) => ( - -); - -export type ModelSelectorInputProps = ComponentProps; - -export const ModelSelectorInput = ({ - className, - ...props -}: ModelSelectorInputProps) => ( - -); - -export type ModelSelectorListProps = ComponentProps; - -export const ModelSelectorList = (props: ModelSelectorListProps) => ( - -); - -export type ModelSelectorEmptyProps = ComponentProps; - -export const ModelSelectorEmpty = (props: ModelSelectorEmptyProps) => ( - -); - -export type ModelSelectorGroupProps = ComponentProps; - -export const ModelSelectorGroup = (props: ModelSelectorGroupProps) => ( - -); - -export type ModelSelectorItemProps = ComponentProps; - -export const ModelSelectorItem = (props: ModelSelectorItemProps) => ( - -); - -export type ModelSelectorShortcutProps = ComponentProps; - -export const ModelSelectorShortcut = (props: ModelSelectorShortcutProps) => ( - -); - -export type ModelSelectorSeparatorProps = ComponentProps< - typeof CommandSeparator ->; - -export const ModelSelectorSeparator = (props: ModelSelectorSeparatorProps) => ( - -); - -export type ModelSelectorLogoProps = Omit< - ComponentProps<"img">, - "src" | "alt" -> & { - provider: - | "moonshotai-cn" - | "lucidquery" - | "moonshotai" - | "zai-coding-plan" - | "alibaba" - | "xai" - | "vultr" - | "nvidia" - | "upstage" - | "groq" - | "github-copilot" - | "mistral" - | "vercel" - | "nebius" - | "deepseek" - | "alibaba-cn" - | "google-vertex-anthropic" - | "venice" - | "chutes" - | "cortecs" - | "github-models" - | "togetherai" - | "azure" - | "baseten" - | "huggingface" - | "opencode" - | "fastrouter" - | "google" - | "google-vertex" - | "cloudflare-workers-ai" - | "inception" - | "wandb" - | "openai" - | "zhipuai-coding-plan" - | "perplexity" - | "openrouter" - | "zenmux" - | "v0" - | "iflowcn" - | "synthetic" - | "deepinfra" - | "zhipuai" - | "submodel" - | "zai" - | "inference" - | "requesty" - | "morph" - | "lmstudio" - | "anthropic" - | "aihubmix" - | "fireworks-ai" - | "modelscope" - | "llama" - | "scaleway" - | "amazon-bedrock" - | "cerebras" - | (string & {}); -}; - -export const ModelSelectorLogo = ({ - provider, - className, - ...props -}: ModelSelectorLogoProps) => ( - {`${provider} -); - -export type ModelSelectorLogoGroupProps = ComponentProps<"div">; - -export const ModelSelectorLogoGroup = ({ - className, - ...props -}: ModelSelectorLogoGroupProps) => ( -
img]:rounded-full [&>img]:bg-background [&>img]:p-px [&>img]:ring-1 dark:[&>img]:bg-foreground", - className - )} - {...props} - /> -); - -export type ModelSelectorNameProps = ComponentProps<"span">; - -export const ModelSelectorName = ({ - className, - ...props -}: ModelSelectorNameProps) => ( - -); diff --git a/examples/nextjs-ai-elements-realtime/components/ai-elements/node.tsx b/examples/nextjs-ai-elements-realtime/components/ai-elements/node.tsx deleted file mode 100644 index 75ac59a153f..00000000000 --- a/examples/nextjs-ai-elements-realtime/components/ai-elements/node.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import { - Card, - CardAction, - CardContent, - CardDescription, - CardFooter, - CardHeader, - CardTitle, -} from "@/components/ui/card"; -import { cn } from "@/lib/utils"; -import { Handle, Position } from "@xyflow/react"; -import type { ComponentProps } from "react"; - -export type NodeProps = ComponentProps & { - handles: { - target: boolean; - source: boolean; - }; -}; - -export const Node = ({ handles, className, ...props }: NodeProps) => ( - - {handles.target && } - {handles.source && } - {props.children} - -); - -export type NodeHeaderProps = ComponentProps; - -export const NodeHeader = ({ className, ...props }: NodeHeaderProps) => ( - -); - -export type NodeTitleProps = ComponentProps; - -export const NodeTitle = (props: NodeTitleProps) => ; - -export type NodeDescriptionProps = ComponentProps; - -export const NodeDescription = (props: NodeDescriptionProps) => ( - -); - -export type NodeActionProps = ComponentProps; - -export const NodeAction = (props: NodeActionProps) => ; - -export type NodeContentProps = ComponentProps; - -export const NodeContent = ({ className, ...props }: NodeContentProps) => ( - -); - -export type NodeFooterProps = ComponentProps; - -export const NodeFooter = ({ className, ...props }: NodeFooterProps) => ( - -); diff --git a/examples/nextjs-ai-elements-realtime/components/ai-elements/open-in-chat.tsx b/examples/nextjs-ai-elements-realtime/components/ai-elements/open-in-chat.tsx deleted file mode 100644 index 0c62a6ac4ac..00000000000 --- a/examples/nextjs-ai-elements-realtime/components/ai-elements/open-in-chat.tsx +++ /dev/null @@ -1,365 +0,0 @@ -"use client"; - -import { Button } from "@/components/ui/button"; -import { - DropdownMenu, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuLabel, - DropdownMenuSeparator, - DropdownMenuTrigger, -} from "@/components/ui/dropdown-menu"; -import { cn } from "@/lib/utils"; -import { - ChevronDownIcon, - ExternalLinkIcon, - MessageCircleIcon, -} from "lucide-react"; -import { type ComponentProps, createContext, useContext } from "react"; - -const providers = { - github: { - title: "Open in GitHub", - createUrl: (url: string) => url, - icon: ( - - GitHub - - - ), - }, - scira: { - title: "Open in Scira", - createUrl: (q: string) => - `https://scira.ai/?${new URLSearchParams({ - q, - })}`, - icon: ( - - Scira AI - - - - - - - - - ), - }, - chatgpt: { - title: "Open in ChatGPT", - createUrl: (prompt: string) => - `https://chatgpt.com/?${new URLSearchParams({ - hints: "search", - prompt, - })}`, - icon: ( - - OpenAI - - - ), - }, - claude: { - title: "Open in Claude", - createUrl: (q: string) => - `https://claude.ai/new?${new URLSearchParams({ - q, - })}`, - icon: ( - - Claude - - - ), - }, - t3: { - title: "Open in T3 Chat", - createUrl: (q: string) => - `https://t3.chat/new?${new URLSearchParams({ - q, - })}`, - icon: , - }, - v0: { - title: "Open in v0", - createUrl: (q: string) => - `https://v0.app?${new URLSearchParams({ - q, - })}`, - icon: ( - - v0 - - - - ), - }, - cursor: { - title: "Open in Cursor", - createUrl: (text: string) => { - const url = new URL("https://cursor.com/link/prompt"); - url.searchParams.set("text", text); - return url.toString(); - }, - icon: ( - - Cursor - - - ), - }, -}; - -const OpenInContext = createContext<{ query: string } | undefined>(undefined); - -const useOpenInContext = () => { - const context = useContext(OpenInContext); - if (!context) { - throw new Error("OpenIn components must be used within an OpenIn provider"); - } - return context; -}; - -export type OpenInProps = ComponentProps & { - query: string; -}; - -export const OpenIn = ({ query, ...props }: OpenInProps) => ( - - - -); - -export type OpenInContentProps = ComponentProps; - -export const OpenInContent = ({ className, ...props }: OpenInContentProps) => ( - -); - -export type OpenInItemProps = ComponentProps; - -export const OpenInItem = (props: OpenInItemProps) => ( - -); - -export type OpenInLabelProps = ComponentProps; - -export const OpenInLabel = (props: OpenInLabelProps) => ( - -); - -export type OpenInSeparatorProps = ComponentProps; - -export const OpenInSeparator = (props: OpenInSeparatorProps) => ( - -); - -export type OpenInTriggerProps = ComponentProps; - -export const OpenInTrigger = ({ children, ...props }: OpenInTriggerProps) => ( - - {children ?? ( - - )} - -); - -export type OpenInChatGPTProps = ComponentProps; - -export const OpenInChatGPT = (props: OpenInChatGPTProps) => { - const { query } = useOpenInContext(); - return ( - - - {providers.chatgpt.icon} - {providers.chatgpt.title} - - - - ); -}; - -export type OpenInClaudeProps = ComponentProps; - -export const OpenInClaude = (props: OpenInClaudeProps) => { - const { query } = useOpenInContext(); - return ( - - - {providers.claude.icon} - {providers.claude.title} - - - - ); -}; - -export type OpenInT3Props = ComponentProps; - -export const OpenInT3 = (props: OpenInT3Props) => { - const { query } = useOpenInContext(); - return ( - - - {providers.t3.icon} - {providers.t3.title} - - - - ); -}; - -export type OpenInSciraProps = ComponentProps; - -export const OpenInScira = (props: OpenInSciraProps) => { - const { query } = useOpenInContext(); - return ( - - - {providers.scira.icon} - {providers.scira.title} - - - - ); -}; - -export type OpenInv0Props = ComponentProps; - -export const OpenInv0 = (props: OpenInv0Props) => { - const { query } = useOpenInContext(); - return ( - - - {providers.v0.icon} - {providers.v0.title} - - - - ); -}; - -export type OpenInCursorProps = ComponentProps; - -export const OpenInCursor = (props: OpenInCursorProps) => { - const { query } = useOpenInContext(); - return ( - - - {providers.cursor.icon} - {providers.cursor.title} - - - - ); -}; diff --git a/examples/nextjs-ai-elements-realtime/components/ai-elements/panel.tsx b/examples/nextjs-ai-elements-realtime/components/ai-elements/panel.tsx deleted file mode 100644 index 059cb7ac213..00000000000 --- a/examples/nextjs-ai-elements-realtime/components/ai-elements/panel.tsx +++ /dev/null @@ -1,15 +0,0 @@ -import { cn } from "@/lib/utils"; -import { Panel as PanelPrimitive } from "@xyflow/react"; -import type { ComponentProps } from "react"; - -type PanelProps = ComponentProps; - -export const Panel = ({ className, ...props }: PanelProps) => ( - -); diff --git a/examples/nextjs-ai-elements-realtime/components/ai-elements/plan.tsx b/examples/nextjs-ai-elements-realtime/components/ai-elements/plan.tsx deleted file mode 100644 index be04d883bed..00000000000 --- a/examples/nextjs-ai-elements-realtime/components/ai-elements/plan.tsx +++ /dev/null @@ -1,142 +0,0 @@ -"use client"; - -import { Button } from "@/components/ui/button"; -import { - Card, - CardAction, - CardContent, - CardDescription, - CardFooter, - CardHeader, - CardTitle, -} from "@/components/ui/card"; -import { - Collapsible, - CollapsibleContent, - CollapsibleTrigger, -} from "@/components/ui/collapsible"; -import { cn } from "@/lib/utils"; -import { ChevronsUpDownIcon } from "lucide-react"; -import type { ComponentProps } from "react"; -import { createContext, useContext } from "react"; -import { Shimmer } from "./shimmer"; - -type PlanContextValue = { - isStreaming: boolean; -}; - -const PlanContext = createContext(null); - -const usePlan = () => { - const context = useContext(PlanContext); - if (!context) { - throw new Error("Plan components must be used within Plan"); - } - return context; -}; - -export type PlanProps = ComponentProps & { - isStreaming?: boolean; -}; - -export const Plan = ({ - className, - isStreaming = false, - children, - ...props -}: PlanProps) => ( - - - {children} - - -); - -export type PlanHeaderProps = ComponentProps; - -export const PlanHeader = ({ className, ...props }: PlanHeaderProps) => ( - -); - -export type PlanTitleProps = Omit< - ComponentProps, - "children" -> & { - children: string; -}; - -export const PlanTitle = ({ children, ...props }: PlanTitleProps) => { - const { isStreaming } = usePlan(); - - return ( - - {isStreaming ? {children} : children} - - ); -}; - -export type PlanDescriptionProps = Omit< - ComponentProps, - "children" -> & { - children: string; -}; - -export const PlanDescription = ({ - className, - children, - ...props -}: PlanDescriptionProps) => { - const { isStreaming } = usePlan(); - - return ( - - {isStreaming ? {children} : children} - - ); -}; - -export type PlanActionProps = ComponentProps; - -export const PlanAction = (props: PlanActionProps) => ( - -); - -export type PlanContentProps = ComponentProps; - -export const PlanContent = (props: PlanContentProps) => ( - - - -); - -export type PlanFooterProps = ComponentProps<"div">; - -export const PlanFooter = (props: PlanFooterProps) => ( - -); - -export type PlanTriggerProps = ComponentProps; - -export const PlanTrigger = ({ className, ...props }: PlanTriggerProps) => ( - - - -); diff --git a/examples/nextjs-ai-elements-realtime/components/ai-elements/queue.tsx b/examples/nextjs-ai-elements-realtime/components/ai-elements/queue.tsx deleted file mode 100644 index 0c91d1300b5..00000000000 --- a/examples/nextjs-ai-elements-realtime/components/ai-elements/queue.tsx +++ /dev/null @@ -1,274 +0,0 @@ -"use client"; - -import { Button } from "@/components/ui/button"; -import { - Collapsible, - CollapsibleContent, - CollapsibleTrigger, -} from "@/components/ui/collapsible"; -import { ScrollArea } from "@/components/ui/scroll-area"; -import { cn } from "@/lib/utils"; -import { ChevronDownIcon, PaperclipIcon } from "lucide-react"; -import type { ComponentProps } from "react"; - -export type QueueMessagePart = { - type: string; - text?: string; - url?: string; - filename?: string; - mediaType?: string; -}; - -export type QueueMessage = { - id: string; - parts: QueueMessagePart[]; -}; - -export type QueueTodo = { - id: string; - title: string; - description?: string; - status?: "pending" | "completed"; -}; - -export type QueueItemProps = ComponentProps<"li">; - -export const QueueItem = ({ className, ...props }: QueueItemProps) => ( -
  • -); - -export type QueueItemIndicatorProps = ComponentProps<"span"> & { - completed?: boolean; -}; - -export const QueueItemIndicator = ({ - completed = false, - className, - ...props -}: QueueItemIndicatorProps) => ( - -); - -export type QueueItemContentProps = ComponentProps<"span"> & { - completed?: boolean; -}; - -export const QueueItemContent = ({ - completed = false, - className, - ...props -}: QueueItemContentProps) => ( - -); - -export type QueueItemDescriptionProps = ComponentProps<"div"> & { - completed?: boolean; -}; - -export const QueueItemDescription = ({ - completed = false, - className, - ...props -}: QueueItemDescriptionProps) => ( -
    -); - -export type QueueItemActionsProps = ComponentProps<"div">; - -export const QueueItemActions = ({ - className, - ...props -}: QueueItemActionsProps) => ( -
    -); - -export type QueueItemActionProps = Omit< - ComponentProps, - "variant" | "size" ->; - -export const QueueItemAction = ({ - className, - ...props -}: QueueItemActionProps) => ( - - -); - -// QueueSectionLabel - label content with icon and count -export type QueueSectionLabelProps = ComponentProps<"span"> & { - count?: number; - label: string; - icon?: React.ReactNode; -}; - -export const QueueSectionLabel = ({ - count, - label, - icon, - className, - ...props -}: QueueSectionLabelProps) => ( - - - {icon} - - {count} {label} - - -); - -// QueueSectionContent - collapsible content area -export type QueueSectionContentProps = ComponentProps< - typeof CollapsibleContent ->; - -export const QueueSectionContent = ({ - className, - ...props -}: QueueSectionContentProps) => ( - -); - -export type QueueProps = ComponentProps<"div">; - -export const Queue = ({ className, ...props }: QueueProps) => ( -
    -); diff --git a/examples/nextjs-ai-elements-realtime/components/ai-elements/task.tsx b/examples/nextjs-ai-elements-realtime/components/ai-elements/task.tsx deleted file mode 100644 index eeb802c61d0..00000000000 --- a/examples/nextjs-ai-elements-realtime/components/ai-elements/task.tsx +++ /dev/null @@ -1,87 +0,0 @@ -"use client"; - -import { - Collapsible, - CollapsibleContent, - CollapsibleTrigger, -} from "@/components/ui/collapsible"; -import { cn } from "@/lib/utils"; -import { ChevronDownIcon, SearchIcon } from "lucide-react"; -import type { ComponentProps } from "react"; - -export type TaskItemFileProps = ComponentProps<"div">; - -export const TaskItemFile = ({ - children, - className, - ...props -}: TaskItemFileProps) => ( -
    - {children} -
    -); - -export type TaskItemProps = ComponentProps<"div">; - -export const TaskItem = ({ children, className, ...props }: TaskItemProps) => ( -
    - {children} -
    -); - -export type TaskProps = ComponentProps; - -export const Task = ({ - defaultOpen = true, - className, - ...props -}: TaskProps) => ( - -); - -export type TaskTriggerProps = ComponentProps & { - title: string; -}; - -export const TaskTrigger = ({ - children, - className, - title, - ...props -}: TaskTriggerProps) => ( - - {children ?? ( -
    - -

    {title}

    - -
    - )} -
    -); - -export type TaskContentProps = ComponentProps; - -export const TaskContent = ({ - children, - className, - ...props -}: TaskContentProps) => ( - -
    - {children} -
    -
    -); diff --git a/examples/nextjs-ai-elements-realtime/components/ai-elements/toolbar.tsx b/examples/nextjs-ai-elements-realtime/components/ai-elements/toolbar.tsx deleted file mode 100644 index b55aa8895d0..00000000000 --- a/examples/nextjs-ai-elements-realtime/components/ai-elements/toolbar.tsx +++ /dev/null @@ -1,16 +0,0 @@ -import { cn } from "@/lib/utils"; -import { NodeToolbar, Position } from "@xyflow/react"; -import type { ComponentProps } from "react"; - -type ToolbarProps = ComponentProps; - -export const Toolbar = ({ className, ...props }: ToolbarProps) => ( - -); diff --git a/examples/nextjs-ai-elements-realtime/components/ai-elements/web-preview.tsx b/examples/nextjs-ai-elements-realtime/components/ai-elements/web-preview.tsx deleted file mode 100644 index 8f0ab5a530e..00000000000 --- a/examples/nextjs-ai-elements-realtime/components/ai-elements/web-preview.tsx +++ /dev/null @@ -1,263 +0,0 @@ -"use client"; - -import { Button } from "@/components/ui/button"; -import { - Collapsible, - CollapsibleContent, - CollapsibleTrigger, -} from "@/components/ui/collapsible"; -import { Input } from "@/components/ui/input"; -import { - Tooltip, - TooltipContent, - TooltipProvider, - TooltipTrigger, -} from "@/components/ui/tooltip"; -import { cn } from "@/lib/utils"; -import { ChevronDownIcon } from "lucide-react"; -import type { ComponentProps, ReactNode } from "react"; -import { createContext, useContext, useEffect, useState } from "react"; - -export type WebPreviewContextValue = { - url: string; - setUrl: (url: string) => void; - consoleOpen: boolean; - setConsoleOpen: (open: boolean) => void; -}; - -const WebPreviewContext = createContext(null); - -const useWebPreview = () => { - const context = useContext(WebPreviewContext); - if (!context) { - throw new Error("WebPreview components must be used within a WebPreview"); - } - return context; -}; - -export type WebPreviewProps = ComponentProps<"div"> & { - defaultUrl?: string; - onUrlChange?: (url: string) => void; -}; - -export const WebPreview = ({ - className, - children, - defaultUrl = "", - onUrlChange, - ...props -}: WebPreviewProps) => { - const [url, setUrl] = useState(defaultUrl); - const [consoleOpen, setConsoleOpen] = useState(false); - - const handleUrlChange = (newUrl: string) => { - setUrl(newUrl); - onUrlChange?.(newUrl); - }; - - const contextValue: WebPreviewContextValue = { - url, - setUrl: handleUrlChange, - consoleOpen, - setConsoleOpen, - }; - - return ( - -
    - {children} -
    -
    - ); -}; - -export type WebPreviewNavigationProps = ComponentProps<"div">; - -export const WebPreviewNavigation = ({ - className, - children, - ...props -}: WebPreviewNavigationProps) => ( -
    - {children} -
    -); - -export type WebPreviewNavigationButtonProps = ComponentProps & { - tooltip?: string; -}; - -export const WebPreviewNavigationButton = ({ - onClick, - disabled, - tooltip, - children, - ...props -}: WebPreviewNavigationButtonProps) => ( - - - - - - -

    {tooltip}

    -
    -
    -
    -); - -export type WebPreviewUrlProps = ComponentProps; - -export const WebPreviewUrl = ({ - value, - onChange, - onKeyDown, - ...props -}: WebPreviewUrlProps) => { - const { url, setUrl } = useWebPreview(); - const [inputValue, setInputValue] = useState(url); - - // Sync input value with context URL when it changes externally - useEffect(() => { - setInputValue(url); - }, [url]); - - const handleChange = (event: React.ChangeEvent) => { - setInputValue(event.target.value); - onChange?.(event); - }; - - const handleKeyDown = (event: React.KeyboardEvent) => { - if (event.key === "Enter") { - const target = event.target as HTMLInputElement; - setUrl(target.value); - } - onKeyDown?.(event); - }; - - return ( - - ); -}; - -export type WebPreviewBodyProps = ComponentProps<"iframe"> & { - loading?: ReactNode; -}; - -export const WebPreviewBody = ({ - className, - loading, - src, - ...props -}: WebPreviewBodyProps) => { - const { url } = useWebPreview(); - - return ( -
    -