From 4db78dfe5fa81a89ff0b1b4769092616c956ff6b Mon Sep 17 00:00:00 2001 From: "claude[bot]" <209825114+claude[bot]@users.noreply.github.com> Date: Thu, 30 Jul 2026 12:49:19 +0200 Subject: [PATCH 01/12] chore(www): update DPA effective date to August 1, 2026 (#48481) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _Requested by **Nicole Kramer** · [Slack thread](https://supabase.slack.com/archives/C0161K73J1J/p1785399057853249?thread_ts=1785399057.853249&cid=C0161K73J1J)_ ## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES ## What kind of change does this PR introduce? Content update — moves the Data Processing Addendum's effective date out by two months. ## What is the current behavior? The DPA page at `/legal/customer-resources/data-processing-addendum` shows "Version 1 — June 1, 2026" in the version selector, and the document body opens with "Last Modified: 1 June 2026". ## What is the new behavior? Both now read August 1, 2026: the version selector shows "Version 1 — August 1, 2026" and the document opens with "Last Modified: 1 August 2026". ## Additional context The page renders a hardcoded `versions` array through the shared `LegalDocVersions` component, so the effective date lives in the TSX file; the "Last Modified" line is simply the first line of the MDX content file. Both were updated, each keeping its file's existing date format (`M D, YYYY` in the TSX, `D Month YYYY` in the MDX). No other content changed. ### Not changed — flagging for confirmation The same June 1, 2026 date appears on a few other surfaces. I left them alone because they are either different documents or point at a dated PDF asset that would need to be re-generated and re-uploaded. Let me know if any of these should move too: - `apps/www/pages/legal/dpa.tsx` — the legacy `/legal/dpa` page, which links `Supabase+DPA+260601.pdf` - `apps/studio/components/interfaces/Organization/Documents/DPA.tsx` — Studio links that same PDF - `apps/www/pages/legal/customer-resources/subprocessor-list.tsx` — the subprocessor list (`June-1-2026.pdf` and a "June 1, 2026" label); a separate document - `apps/www/pages/aup.mdx` — the Acceptable Use Policy, "Last Modified: 1 June 2026"; a separate document Co-authored-by: Claude --- .../legal/customer-resources/data-processing-addendum/v1.mdx | 2 +- .../pages/legal/customer-resources/data-processing-addendum.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/www/data/legal/customer-resources/data-processing-addendum/v1.mdx b/apps/www/data/legal/customer-resources/data-processing-addendum/v1.mdx index 42c17b579df38..a62a4bbb4dda4 100644 --- a/apps/www/data/legal/customer-resources/data-processing-addendum/v1.mdx +++ b/apps/www/data/legal/customer-resources/data-processing-addendum/v1.mdx @@ -1,4 +1,4 @@ -_Last Modified: 1 June 2026_ +_Last Modified: 1 August 2026_ This Data Processing Addendum (the “**DPA**”) supplements and forms part of the Supabase Terms of Service available at [https://supabase.com/terms](https://supabase.com/terms), or such other agreement entered into between the Customer and Supabase Pte. Ltd (“**Supabase**”) relevant to Customer’s use of the Services (the “**Agreement**”), and in case of any conflict, supersedes the Agreement in relation to the transfer and processing of Covered Data in connection with the performance of the Services. This DPA is effective as of the Effective Date of the Agreement. diff --git a/apps/www/pages/legal/customer-resources/data-processing-addendum.tsx b/apps/www/pages/legal/customer-resources/data-processing-addendum.tsx index 8898d3603e2b8..0e4610d4b0dbd 100644 --- a/apps/www/pages/legal/customer-resources/data-processing-addendum.tsx +++ b/apps/www/pages/legal/customer-resources/data-processing-addendum.tsx @@ -14,7 +14,7 @@ const meta = { } const versions: LegalDocVersion[] = [ - { id: 'v1', label: 'Version 1', effectiveDate: 'June 1, 2026', Component: V1 }, + { id: 'v1', label: 'Version 1', effectiveDate: 'August 1, 2026', Component: V1 }, ] export default function DataProcessingAddendumPage() { From 44bc7b5a57cffa6f0041159063a173802a6735bf Mon Sep 17 00:00:00 2001 From: "claude[bot]" <209825114+claude[bot]@users.noreply.github.com> Date: Thu, 30 Jul 2026 12:49:30 +0200 Subject: [PATCH 02/12] feat(www): add Terms of Service v3 (effective August 1, 2026) (#48482) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _Requested by **Nicole Kramer** · [Slack thread](https://supabase.slack.com/archives/C0161K73J1J/p1785399344523739)_ ## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES ## What kind of change does this PR introduce? Content update — adds a new version of the Terms of Service to the marketing site (`apps/www`). ## What is the current behavior? `/terms` offers two versions in the version dropdown: **Version 2 (May 6, 2026)**, shown by default, and **Version 1 (July 11, 2025)**. ## What is the new behavior? `/terms` shows **Version 3 (August 1, 2026)** by default. Version 2 and Version 1 are still selectable from the version dropdown (`/terms?version=v2`, `/terms?version=v1`) and are completely unchanged. Two files: - **New:** `apps/www/data/legal/terms/v3.mdx` — the full v3 Terms of Service. - **Changed:** `apps/www/pages/terms.tsx` — imports `V3` and prepends it to the `versions` array. Newest-first ordering is required, because `LegalDocVersions` treats `versions[0]` as the latest. ## Additional context ### The legal text is a verbatim transcription — please review it as such It comes from a Word document supplied by Legal, converted with pandoc and then verified character-exact against the source: **8055 words, 136 blocks, 0 word-level diffs**. Prettier was run over the file and changed nothing. **Known typos in the source document were deliberately preserved. Please do not correct them in review:** - §1 Definitions contains a **duplicate `d.`** — one `d.` introduces the Data Processing Addendum definition and the very next item is also lettered `d.` for the Documentation definition. The list therefore runs a, b, c, d, d, e … Re-lettering would shift internal cross-references, so it is left exactly as drafted. - §12(d) Survival contains a **doubled “and”** — *and Sections 1, 5, 6, 8, 9, 10, 11, and 13, and 14 survive*. Also preserved verbatim from the source: curly quotes on the Data Processing Addendum definition only (every other defined term uses straight quotes), and non-breaking spaces around the hyperlinks. ### Date The source document carries **no date line of its own**, even though its §14(d) states that the last-modified date *will be updated at the top of this Agreement*. August 1, 2026 was specified by the requester, and is placed in the `_Last Modified: 1 August 2026_` line at the top of the MDX, following the v1/v2 convention. As with v1 and v2, the `.mdx` uses `D Month YYYY` while `effectiveDate` in `terms.tsx` uses US long form (`August 1, 2026`). That split is pre-existing and intentional. ### New DPA link §1 of v3 links the Data Processing Addendum page at `/legal/customer-resources/data-processing-addendum`. This link is new relative to v2, and the DPA is also incorporated by reference in §7(b). ### No overlap with the concurrent DPA branch This PR touches only `apps/www/data/legal/terms/v3.mdx` and `apps/www/pages/terms.tsx` — **zero file overlap** with the branch updating the DPA page dates. ### Reviewer checklist - 14 numbered sections (1 Definitions → 14 Miscellaneous), 44 lettered subsections, 6 roman sub-subsections. - ALL-CAPS acceptance block at the top; ALL-CAPS AI disclaimer at the end of §9(b); ALL-CAPS §11 Limitations of Liability. - Three link targets intact: the DPA page, `https://supabase.com/privacy`, and `mailto:legal@supabase.io` (×3). Co-authored-by: Claude --- apps/www/data/legal/terms/v3.mdx | 273 +++++++++++++++++++++++++++++++ apps/www/pages/terms.tsx | 2 + 2 files changed, 275 insertions(+) create mode 100644 apps/www/data/legal/terms/v3.mdx diff --git a/apps/www/data/legal/terms/v3.mdx b/apps/www/data/legal/terms/v3.mdx new file mode 100644 index 0000000000000..6ac34f24b226e --- /dev/null +++ b/apps/www/data/legal/terms/v3.mdx @@ -0,0 +1,273 @@ +_Last Modified: 1 August 2026_ + +These Terms of Service (this "Agreement") are a binding contract between you ("Customer," "you," or "your") and SUPABASE PTE. LTD., a Singapore entity with a registered address of 65 Chulia Street #38-02/03, OCBC Centre, Singapore 049513 ("Supabase," "we," or "us"). This Agreement governs your access to and use of the Cloud Services, except to the extent that Customer has entered into an Order or separate agreement with Supabase that expressly incorporates different terms, in which case those other terms will govern. Supabase and Customer may be referred to herein collectively as the "Parties" or individually as a "Party." + +THIS AGREEMENT TAKES EFFECT WHEN YOU CLICK THE "I ACCEPT" BUTTON BELOW OR BY ACCESSING OR USING THE SERVICES (the "Effective Date"). BY CLICKING ON THE "I ACCEPT" BUTTON BELOW OR BY ACCESSING OR USING THE SERVICES YOU (A) ACKNOWLEDGE THAT YOU HAVE READ AND UNDERSTAND THIS AGREEMENT; (B) REPRESENT AND WARRANT THAT YOU HAVE THE RIGHT, POWER, AND AUTHORITY TO ENTER INTO THIS AGREEMENT AND, IF ENTERING INTO THIS AGREEMENT FOR AN ORGANIZATION, THAT YOU HAVE THE LEGAL AUTHORITY TO BIND THAT ORGANIZATION; AND (C) ACCEPT THIS AGREEMENT AND AGREE THAT YOU ARE LEGALLY BOUND BY ITS TERMS. + +PLEASE READ THESE TERMS CAREFULLY TO ENSURE THAT YOU UNDERSTAND EACH PROVISION. THIS AGREEMENT CONTAINS A MANDATORY INDIVIDUAL ARBITRATION PROVISION IN SECTION 13(b) (THE "ARBITRATION AGREEMENT") AND A CLASS ACTION/JURY TRIAL WAIVER PROVISION IN SECTION 13(c) (THE "CLASS ACTION/JURY TRIAL WAIVER") THAT REQUIRE, UNLESS CUSTOMER OPTS OUT PURSUANT TO THE INSTRUCTIONS IN THE ARBITRATION AGREEMENT, THE EXCLUSIVE USE OF FINAL AND BINDING ARBITRATION ON AN INDIVIDUAL BASIS TO RESOLVE DISPUTES BETWEEN YOU AND US, INCLUDING ANY CLAIMS THAT AROSE OR WERE ASSERTED BEFORE YOU AGREED TO THIS AGREEMENT. TO THE FULLEST EXTENT PERMITTED BY APPLICABLE LAW (AS DEFINED BELOW), YOU EXPRESSLY WAIVE YOUR RIGHT TO SEEK RELIEF IN A COURT OF LAW AND TO HAVE A JURY TRIAL ON YOUR CLAIMS, AS WELL AS YOUR RIGHT TO PARTICIPATE AS A PLAINTIFF OR CLASS MEMBER IN ANY CLASS, COLLECTIVE, PRIVATE ATTORNEY GENERAL, OR REPRESENTATIVE ACTION OR PROCEEDING. + +IF YOU DO NOT ACCEPT THESE TERMS, YOU MAY NOT ACCESS OR USE THE SERVICES. + +## 1. Definitions. + +a. "Aggregated Data" means data and information related to or derived from Customer Data or Customer's use of the Services that is used by Supabase in an aggregate and anonymized manner, including to compile statistical and performance information related to the Services. + +b. "Authorized User" means Customer's employees, consultants, contractors, and agents (i) who are authorized by Customer to access and use the Services under the rights granted to Customer pursuant to this Agreement; and (ii) for whom access to the Services has been purchased hereunder. + +c. "Customer Data" means information, data, and other content, in any form or medium, that is submitted, posted, or otherwise transmitted by or on behalf of Customer or an Authorized User through the Services; provided that, for purposes of clarity, Customer Data does not include Aggregated Data. + +d. “Data Processing Addendum” means the Data Processing Addendum available at [https://supabase.com/legal/customer-resources/data-processing-addendum](https://supabase.com/legal/customer-resources/data-processing-addendum), or, if the Parties have a separately executed agreement in effect that covers the same subject matter, the separately executed agreement. + +d. "Documentation" means Supabase's end user documentation relating to the Services available at supabase.io. + +e. "Harmful Code" means any software, hardware, or other technology, device, or means, including any virus, worm, malware, or other malicious computer code, the purpose or effect of which is to permit unauthorized access to, or to destroy, disrupt, disable, distort, or otherwise harm or impede in any manner any (i) computer, software, firmware, hardware, system, or network; or (ii) any application or function of any of the foregoing or the security, integrity, confidentiality, or use of any data processed thereby. + +f. "Order" means: (i) the purchase order, order form, or other ordering document entered into by the Parties that incorporates this Agreement by reference; or (ii) if Customer registered for the Services through Supabase's online ordering process, the results of such online ordering process. + +g. "Personal Information" means any information that, individually or in combination, does or can identify a specific individual or by or from which a specific individual may be identified, contacted, or located, including without limitation all data considered "personal data", "personally identifiable information", or something similar under applicable laws, rules, or regulations relating to data privacy. + +h. "Services" means Supabase's proprietary hosted software platform, as made available by Supabase to Authorized Users from time to time. + +i. "Supabase IP" means the Services, the Documentation, and any and all intellectual property provided to Customer or any Authorized User in connection with the foregoing. For the avoidance of doubt, Supabase IP includes Aggregated Data and any information, data, or other content derived from Supabase's provision of the Services but does not include Customer Data. + +j. "Third-Party Products" means any third-party products provided with, integrated with, or incorporated into the Services. + +k. "Usage Limitations" means the usage limitations set forth in this Agreement and the Order, including without limitation any limitations on the number of Authorized Users (if any), and the applicable product, pricing, and support tiers agreed-upon by the Parties. + +## 2. Access and Use. + +### a. Provision of Access + +Subject to and conditioned on Customer's compliance with the terms and conditions of this Agreement, including without limitation the Usage Limitations, Supabase will make available to Customer during the Subscription Period, on a non-exclusive, non-transferable (except in compliance with Section 14(g)), and non-sublicensable basis, access to and use of the Services, solely for use by Authorized Users. Such use is limited to Customer's internal business purposes and the features and functionalities specified in the Order. Supabase shall provide to Customer the necessary access credentials to allow Customer to access the Services. + +### b. Documentation License + +Subject to and conditioned on Customer's compliance with the terms and conditions of this Agreement, Supabase hereby grants to Customer a non-exclusive, non-transferable (except in compliance with Section 14(g)), and non-sublicensable license to use the Documentation during the Subscription Period solely for Customer's internal business purposes in connection with its use of the Services. + +### c. Use Restrictions + +Customer shall not use the Services for any purposes beyond the scope of the access granted in this Agreement. Customer shall not at any time, directly or indirectly, and shall not permit any Authorized Users to: (i) copy, modify, or create derivative works of any Supabase IP, whether in whole or in part; (ii) rent, lease, lend, sell, license, sublicense, assign, distribute, publish, transfer, or otherwise make available the Services or Documentation to any third party; (iii) reverse engineer, disassemble, decompile, decode, adapt, or otherwise attempt to derive or gain access to any software component of the Services, in whole or in part; (iv) remove any proprietary notices from any Supabase IP; (v) use any Supabase IP in any manner or for any purpose that infringes, misappropriates, or otherwise violates any intellectual property right or other right of any person, or that violates any applicable law; (vi) access or use any Supabase IP for purposes of competitive analysis of Supabase or the Services, the development, provision, or use of a competing software service or product, or any other purpose that is to Supabase's detriment or commercial disadvantage; (vii) bypass or breach any security device or protection used by the Services or access or use the Services other than by an Authorized User through the use of valid access credentials; or (viii) input, upload, transmit, or otherwise provide to or through the Services any information or materials that are unlawful or injurious, or that contain, transmit, or activate any Harmful Code. + +### d. Reservation of Rights + +Supabase reserves all rights not expressly granted to Customer in this Agreement. Except for the limited rights and licenses expressly granted under this Agreement, nothing in this Agreement grants, by implication, waiver, estoppel, or otherwise, to Customer or any third party, any intellectual property rights or other right, title, or interest in or to the Supabase IP. + +### e. Suspension + +Notwithstanding anything to the contrary in this Agreement, Supabase may temporarily suspend Customer's and any Authorized User's access to any portion or all of the Services if: (i) Supabase reasonably determines that (A) there is a threat or attack on any of the Supabase IP; (B) Customer's or any Authorized User's use of the Supabase IP disrupts or poses a security risk to the Supabase IP or to any other customer or vendor of Supabase; (C) Customer, or any Authorized User, is using the Supabase IP for fraudulent or illegal activities; (D) subject to applicable law, Customer has ceased to continue its business in the ordinary course, made an assignment for the benefit of creditors or similar disposition of its assets, or become the subject of any bankruptcy, reorganization, liquidation, dissolution, or similar proceeding; or (E) Supabase's provision of the Services to Customer or any Authorized User is prohibited by applicable law; (ii) any vendor of Supabase has suspended or terminated Supabase's access to or use of any Third-Party Products required to enable Customer to access the Services; or (iii) in accordance with Section 5(a) (any such suspension described in subclause (i), (ii), or (iii), a "Service Suspension"). Supabase shall use commercially reasonable efforts to provide written notice of any Service Suspension to Customer and to provide updates regarding resumption of access to the Services following any Service Suspension. Supabase shall use commercially reasonable efforts to resume providing access to the Services as soon as reasonably possible after the event giving rise to the Service Suspension is cured. Supabase will have no liability for any damage, liabilities, losses (including any loss of data or profits), or any other consequences that Customer or any Authorized User may incur as a result of a Service Suspension. + +### f. Aggregated Statistics + +Notwithstanding anything to the contrary in this Agreement, Supabase may monitor Customer's use of the Services and collect and compile Aggregated Data. As between Supabase and Customer, all right, title, and interest in Aggregated Data, and all intellectual property rights therein, belong to and are retained solely by Supabase. Customer acknowledges that Supabase may compile Aggregated Data based on Customer Data input into the Services. Customer agrees that Supabase may (i) make Aggregated Data available to third parties including its other customers in compliance with applicable law, and (ii) use Aggregated Data to the extent and in the manner permitted under applicable law. + +## 3. Customer Responsibilities. + +### a. General + +Customer is responsible and liable for all uses of the Services and Documentation resulting from access provided by Customer, directly or indirectly, whether such access or use is permitted by or in violation of this Agreement. Without limiting the generality of the foregoing, Customer is responsible for all acts and omissions of Authorized Users, and any act or omission by an Authorized User that would constitute a breach of this Agreement if taken by Customer will be deemed a breach of this Agreement by Customer. Customer shall use reasonable efforts to make all Authorized Users aware of this Agreement's provisions as applicable to such Authorized User's use of the Services and shall cause Authorized Users to comply with such provisions. + +### b. Third-Party Products + +Supabase may from time to time make Third-Party Products available to Customer or Supabase may allow for certain Third-Party Products to be integrated with the Services to allow for the transmission of Customer Data from such Third-Party Products into the Services. For purposes of this Agreement, such Third-Party Products are subject to their own terms and conditions. If Customer does not agree to abide by the applicable terms for any such Third-Party Products, then Customer should not install or use such Third-Party Products. By authorizing Supabase to transmit Customer Data from Third-Party Products into the Services, Customer represents and warrants to Supabase that it has all right, power, and authority to provide such authorization. + +### c. Customer Control and Responsibility + +Customer has and will retain sole responsibility for: (i) all Customer Data, including its content and use; (ii) all information, instructions, and materials provided by or on behalf of Customer or any Authorized User in connection with the Services; (iii) Customer's information technology infrastructure, including computers, software, databases, electronic systems (including database management systems), and networks, whether operated directly by Customer or through the use of third-party services ("Customer Systems"); (iv) the security and use of Customer's and its Authorized Users' access credentials; and (v) all access to and use of the Services directly or indirectly by or through the Customer Systems or its or its Authorized Users' access credentials, with or without Customer's knowledge or consent, including all results obtained from, and all conclusions, decisions, and actions based on, such access or use. + +### d. Responsible Use of AI-Powered Tools + +From time to time, Supabase may make available chatbots or other artificial intelligence-enabled tools to assist with customer support inquiries or other interactions (each, an "AI Tool"). Customer is responsible for the responsible and informed use of any AI Tool, including by: (a) ensuring that any data, content, prompts, or other materials Customer or its Authorized Users submit to an AI Tool (collectively, "AI Input") (i) are submitted with all necessary rights, consents, and authorizations, including with respect to any third-party or personal information contained therein, and (ii) do not violate applicable law, infringe or misappropriate any third-party right, or breach any obligation of confidentiality owed to a third party; (b) applying human judgment to review, evaluate, and verify any output generated by an AI Tool ("AI Output") before relying on it, using it or otherwise acting on it; (c) not treating any AI Output as legal, financial, security, or other professional advice; and (d) escalating to a human Supabase representative through Supabase's standard support channels whenever Customer requires authoritative confirmation, has a time-sensitive issue, or is otherwise not satisfied with the AI Output. + +## 4. Support. + +During the Subscription Period, Supabase will use commercially reasonable efforts to provide Customer with basic customer support via Supabase's standard support channels during Supabase's normal business hours. + +## 5. Fees and Payment. + +### a. Fees + +Where paid for services are agreed between Supabase and Customer per the Order, Customer shall pay Supabase the fees ("Fees") identified in the Order without offset or deduction at the cadence identified in the Order (e.g., monthly or annually). Fees paid by Customer are non-refundable. If Customer fails to make any payment when due, and Customer has not notified Supabase in writing within ten (10) days of the payment becoming due and payable that the payment is subject to a good faith dispute, without limiting Supabase's other rights and remedies: (i) Supabase may charge interest on the undisputed past due amount at the rate of 1.5% per month, calculated daily and compounded monthly or, if lower, the highest rate permitted under applicable law; (ii) Customer shall reimburse Supabase for all reasonable costs incurred by Supabase in collecting any late payments or interest, including attorneys' fees, court costs, and collection agency fees; and (iii) if such failure continues for ten (10) days or more, Supabase may suspend Customer's and its Authorized Users' access to any portion or all of the Services until such amounts are paid in full. + +#### i. Waiver of Withdrawal Right for EU and UK Consumers + +If you are a resident of the European Union or the United Kingdom and subject to applicable consumer protection laws, you acknowledge that by creating a project or initiating use of the Supabase services during the 14-day statutory withdrawal period, the services will begin immediately at your request. Accordingly, you expressly consent to the immediate provision of the services and acknowledge that you waive your right to cancel the service and receive a refund under applicable consumer protection laws. + +### b. Taxes + +All Fees and other amounts payable by Customer under this Agreement are exclusive of taxes and similar assessments. Customer is responsible for all sales, use, and excise taxes, and any other similar taxes, duties, and charges of any kind imposed by any federal, state, or local governmental or regulatory authority on any amounts payable by Customer hereunder, other than any taxes imposed on Supabase's income. To the extent that Supabase is required by law to pay any such taxes, duties, or other charges to any governmental or regulatory authority, Supabase may invoice Customer for such taxes, duties, or other charges and Customer will pay such invoiced amounts in accordance with this Agreement. + +### c. Credit Authorization and Fraud Prevention. + +To mitigate billing fraud and unauthorized usage, Supabase reserves the right to implement reasonable credit authorization, payment validation, and usage control measures, including but not limited to: (i) preauthorization or validation of Customer's payment method upon account creation or prior to provisioning Services; (ii) applying initial or ongoing spend limits, usage caps, or throttling mechanisms to accounts with insufficient billing history or elevated risk profiles; (iii) suspending or restricting access to Services where Supabase reasonably suspects fraudulent activity, failed payment authorization, or violation of usage terms; (iv) delaying the provisioning of high-cost Services or infrastructure pending verification or authorization; and (v) employing fraud-detection tools and analytics, including third-party services, to assess and manage risk. Supabase will make commercially reasonable efforts to notify Customer prior to suspending or restricting Service access under this Section, except in cases of suspected fraud, payment failure, or material risk to Supabase's infrastructure or systems. Customer agrees to cooperate with any reasonable verification or remediation steps required by Supabase to restore access. + +## 6. Confidential Information. + +### a. Definition + +From time to time during the Subscription Period, either Party may disclose or make available to the other Party information about its business affairs, products, confidential intellectual property, trade secrets, third-party confidential information, and other sensitive or proprietary information, whether orally or in written, electronic, or other form or media that: (i) is marked, designated or otherwise identified as "confidential" or something similar at the time of disclosure or within a reasonable period of time thereafter; or (ii) would be considered confidential by a reasonable person given the nature of the information or the circumstances of its disclosure (collectively, "Confidential Information"). Except for Personal Information, Confidential Information does not include information that, at the time of disclosure is: (a) in the public domain; (b) known to the receiving Party at the time of disclosure; (c) rightfully obtained by the receiving Party on a non-confidential basis from a third party; or (d) independently developed by the receiving Party without use of, reference to, or reliance upon the disclosing Party's Confidential Information. + +### b. Duty + +The receiving Party shall not disclose the disclosing Party's Confidential Information to any person or entity, except to the receiving Party's employees, contractors, and agents who have a need to know the Confidential Information for the receiving Party to exercise its rights or perform its obligations hereunder ("Representatives"). The receiving Party will be responsible for all the acts and omissions of its Representatives as they relate to Confidential Information hereunder. Notwithstanding the foregoing, each Party may disclose Confidential Information to the limited extent required (i) in order to comply with the order of a court or other governmental body, or as otherwise necessary to comply with applicable law, provided that the Party making the disclosure pursuant to the order shall first have given written notice to the other Party and made a reasonable effort to obtain a protective order; or (ii) to establish a Party's rights under this Agreement, including to make required court filings. Further, notwithstanding the foregoing, each Party may disclose the terms and existence of this Agreement to its actual or potential investors, debtholders, acquirers, or merger partners under customary confidentiality terms. + +### c. Return of Materials; Effect of Termination/Expiration + +On the expiration or termination of the Agreement, the receiving Party shall promptly return to the disclosing Party all copies, whether in written, electronic, or other form or media, of the disclosing Party's Confidential Information, or destroy all such copies and certify in writing to the disclosing Party that such Confidential Information has been destroyed. Each Party's obligations of non-use and non-disclosure with regard to Confidential Information are effective as of the Effective Date and will expire three (3) years from the date of termination or expiration of this Agreement; provided, however, with respect to any Confidential Information that constitutes a trade secret (as determined under applicable law), such obligations of non-disclosure will survive the termination or expiration of this Agreement for as long as such Confidential Information remains subject to trade secret protection under applicable laws and regulations. + +## 7. Personal Information. + +### a. Account Information. + +Supabase's privacy policy, available at [https://supabase.com/privacy](https://supabase.com/privacy) ("Privacy Policy") is subject to change as described therein. By accessing, using, and providing information to or through the Services, Customer acknowledges that it has reviewed the Privacy Policy, and consents to all actions taken by Supabase with respect to Customer's information in compliance with the then-current version of the Privacy Policy. + +### b. Customer Data. + +Customer will ensure that its Customer Data, and its use of such Customer Data, complies with this Agreement and any applicable law. Customer is responsible for properly configuring and using the Services and taking its own steps to maintain appropriate security, protection, and backup of Customer Data. Customer may not store or process protected health information (as defined in HIPAA) using the Services unless Customer signs a Business Associate Agreement with Supabase. Customer may not store any payment cardholder information using the Services without Supabase's prior written approval. The Parties agree to comply with the Data Processing Addendum, which is incorporated into this Agreement. + +## 8. Intellectual Property Ownership; Feedback. + +### a. Supabase IP + +Customer acknowledges that, as between Customer and Supabase, Supabase owns all right, title, and interest, including all intellectual property rights, in and to the Supabase IP and, with respect to Third-Party Products, the applicable third-party providers own all right, title, and interest, including all intellectual property rights, in and to the Third-Party Products. + +### b. Customer Data + +Supabase acknowledges that, as between Supabase and Customer, Customer owns all right, title, and interest, including all intellectual property rights, in and to the Customer Data. Customer hereby grants to Supabase a non-exclusive, royalty-free, worldwide license to reproduce, distribute, and otherwise use and display the Customer Data and perform all acts with respect to the Customer Data as may be necessary for Supabase to provide the Services to Customer, and a non-exclusive, perpetual, irrevocable, royalty-free, worldwide license to reproduce, distribute, modify, and otherwise use and display Customer Data incorporated within the Aggregated Data. Customer may export the Customer Data at any time through the features and functionalities made available via the Services. To the extent Supabase utilizes artificial intelligence to provide features to Customer via the Services, and in Supabase's provision of the AI Tools, Supabase will not use, nor allow any third-party to use, Customer Data, Customer's AI Input, or any AI Output to train, fine-tune, or otherwise improve any artificial intelligence or machine learning model, without Customer's prior written consent. For the avoidance of doubt, Customer retains all right, title and interest in Customer Data contained in AI Inputs and AI Outputs. + +### c. Feedback + +If Customer or any of its employees or contractors sends or transmits any communications or materials to Supabase by mail, email, telephone, or otherwise, suggesting or recommending changes to the Supabase IP, including without limitation, new features or functionality relating thereto, or any comments, questions, suggestions, or the like ("Feedback"), Supabase is free to use such Feedback irrespective of any other obligation or limitation between the Parties governing such Feedback so long as Supabase does not identify Customer as the source of the Feedback without Customer's prior approval. + +## 9. Warranties; Disclaimer + +### a. Customer + +Customer represents, warrants, and covenants to Supabase that Customer owns or otherwise has and will have the necessary rights and consents in and relating to the Customer Data so that, as received by Supabase and processed in accordance with this Agreement, they do not and will not infringe, misappropriate, or otherwise violate any intellectual property, privacy or other rights of any third party or violate any applicable laws or regulations. + +### b. Disclaimer + +Notwithstanding anything to the contrary, the Supabase IP is provided "as is" and Supabase hereby disclaims all warranties, whether express, implied, statutory, or otherwise. Supabase specifically disclaims all implied warranties of merchantability, fitness for a particular purpose, title, and non-infringement, and all warranties arising from course of dealing, usage, or trade practice. Supabase makes no warranty of any kind that the Supabase IP, or any products or results of the use thereof, will meet Customer's or any other person's requirements, operate without interruption, achieve any intended result, be compatible or work with any software, system or other services, or be secure, accurate, complete, free of harmful code, or error free. In addition, Customer acknowledges that AI Tools are powered by one or more third-party large language models that Supabase does not own or control, and that AI Outputs may be inaccurate, incomplete, or unsuitable for Customer's particular use case. Customer acknowledges that other customers providing similar AI Input may receive similar or the same AI Output. AI TOOLS AND THEIR OUTPUTS ARE PROVIDED ON AN "AS IS" AND "AS AVAILABLE" BASIS, AND SUPABASE MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, AS TO THE ACCURACY, RELIABILITY, COMPLETENESS, ERROR-FREE NATURE, NON-INFRINGEMENT, OR FITNESS FOR A PARTICULAR PURPOSE OF ANY OUTPUT GENERATED FROM THE AI TOOLS. + +## 10. Indemnification + +### a. Supabase Indemnification + +Supabase shall indemnify, defend, and hold harmless Customer from and against any and all losses, damages, liabilities, costs (including reasonable attorneys' fees) ("Losses") incurred by Customer resulting from any third-party claim, suit, action, or proceeding ("Third-Party Claim") that the Services, or any use of the Services in accordance with this Agreement, infringes or misappropriates such third party's US copyrights or trade secrets; provided that Customer promptly notifies Supabase in writing of the claim, cooperates with Supabase, and allows Supabase sole authority to control the defense and settlement of such claim. + +If such a claim is made or appears possible, Customer agrees to permit Supabase, at Supabase's sole discretion: to (i) modify or replace the Services, or component or part thereof, to make it non-infringing; or (ii) obtain the right for Customer to continue use. If Supabase determines that neither alternative is reasonably commercially available, Supabase may terminate this Agreement, in its entirety or with respect to the affected component or part, effective immediately on written notice to Customer. + +This Section 10(a) will not apply to the extent that the alleged infringement arises from: (i) use of the Services in combination with data, software, hardware, equipment, or technology not provided by Supabase or authorized by Supabase in writing; (ii) modifications to the Services not made by Supabase; (iii) Customer Data; (iv) Third-Party Products; (v) AI Output; or (vi) AI Input. + +### b. Customer Indemnification + +Customer shall indemnify, hold harmless, and, at Supabase's option, defend Supabase from and against any Losses resulting from any Third-Party Claim that the Customer Data, AI Input or any use of the Customer Data in accordance with this Agreement, infringes or misappropriates such third party's US intellectual property or other rights and any Third-Party Claims based on Customer's or any Authorized User's (i) negligence or willful misconduct; (ii) use of the Services in a manner not authorized by this Agreement; or (iii) use of the Services in combination with data, software, hardware, equipment or technology not provided by Supabase or authorized by Supabase in writing; in each case provided that Customer may not settle any Third-Party Claim against Supabase unless Supabase consents to such settlement, and further provided that Supabase will have the right, at its option, to defend itself against any such Third-Party Claim or to participate in the defense thereof by counsel of its own choice. + +### c. Sole Remedy + +This Section 10 sets forth Customer's sole remedies and Supabase's sole liability and obligation for any actual, threatened, or alleged claims that the services infringe, misappropriate, or otherwise violate any intellectual property rights of any third party. + +## 11. Limitations of Liability. + +EXCEPT FOR: (I) A PARTY'S BREACH OF ITS CONFIDENTIALITY OBLIGATIONS; (II) A PARTY'S INDEMNITY OBLIGATIONS; OR (III) A PARTY'S GROSS NEGLIGENCE, FRAUD, OR WILLFUL MISCONDUCT ("EXCLUDED LIABILITIES"), (A) IN NO EVENT WILL EITHER PARTY BE LIABLE UNDER OR IN CONNECTION WITH THIS AGREEMENT UNDER ANY LEGAL OR EQUITABLE THEORY, INCLUDING BREACH OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY, AND OTHERWISE, FOR ANY: (1) CONSEQUENTIAL, INCIDENTAL, INDIRECT, EXEMPLARY, SPECIAL, ENHANCED, OR PUNITIVE DAMAGES; (2) INCREASED COSTS, DIMINUTION IN VALUE OR LOST BUSINESS, PRODUCTION, REVENUES, OR PROFITS; (3) LOSS OF GOODWILL OR REPUTATION; (4) USE, INABILITY TO USE, LOSS, INTERRUPTION, DELAY OR RECOVERY OF ANY DATA, OR BREACH OF DATA OR SYSTEM SECURITY; OR (5) COST OF REPLACEMENT GOODS OR SERVICES, IN EACH CASE REGARDLESS OF WHETHER SUCH PARTY WAS ADVISED OF THE POSSIBILITY OF SUCH LOSSES OR DAMAGES OR SUCH LOSSES OR DAMAGES WERE OTHERWISE FORESEEABLE; AND (B) IN NO EVENT WILL EITHER PARTY'S AGGREGATE LIABILITY ARISING OUT OF OR RELATED TO THIS AGREEMENT UNDER ANY LEGAL OR EQUITABLE THEORY, INCLUDING BREACH OF CONTRACT, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY, AND OTHERWISE EXCEED THE TOTAL AMOUNTS PAID AND/OR PAYABLE TO SUPABASE UNDER THIS AGREEMENT IN THE TWELVE (12) MONTHS IMMEDIATELY PRECEDING THE CLAIM; PROVIDED THAT, NOTWITHSTANDING THE FOREGOING, SUPABASE'S AGGREGATE LIABILITY ARISING OUT OF OR RELATING TO ANY EXCLUDED LIABILITIES WILL NOT EXCEED THREE TIMES (3X) THE TOTAL AMOUNTS PAID AND/OR PAYABLE TO SUPABASE BY CUSTOMER UNDER THIS AGREEMENT IN THE TWELVE (12) MONTHS IMMEDIATELY PRECEDING THE CLAIM. + +## 12. Subscription Period and Termination. + +### a. Subscription Period + +The initial term of this Agreement begins on the Effective Date and, unless terminated earlier pursuant to Section 12(b), will continue in effect for the period identified in the Order (the "Initial Subscription Period"). This Agreement will automatically renew for additional successive terms equal to the length of the Initial Subscription Period unless earlier terminated pursuant to this Agreement's express provisions or either Party gives the other Party written notice of non-renewal at least thirty (30) days prior to the expiration of the then-current term (each a "Renewal Subscription Period" and together with the Initial Subscription Period, the "Subscription Period"). + +### b. Termination + +In addition to any other express termination right set forth in this Agreement: + +Supabase may terminate this Agreement, effective on written notice to Customer, if Customer: (i) fails to pay any amount when due hereunder, and such failure continues more than ten (10) calendar days after Supabase's delivery of written notice thereof; or (ii) breaches any of its obligations under Section 2(c) or Section 6. + +Either Party may terminate this Agreement, effective on written notice to the other Party, if the other Party materially breaches this Agreement, and such breach: (i) is incapable of cure; or (ii) being capable of cure, remains uncured thirty (30) calendar days after the non-breaching Party provides the breaching Party with written notice of such breach. + +Either Party may terminate this Agreement, effective immediately upon written notice to the other Party, if the other Party: (i) becomes insolvent or is generally unable to pay, or fails to pay, its debts as they become due; (ii) files or has filed against it, a petition for voluntary or involuntary bankruptcy or otherwise becomes subject, voluntarily or involuntarily, to any proceeding under any domestic or foreign bankruptcy or insolvency law; (iii) makes or seeks to make a general assignment for the benefit of its creditors; or (iv) applies for or has appointed a receiver, trustee, custodian, or similar agent appointed by order of any court of competent jurisdiction to take charge of or sell any material portion of its property or business. + +### c. Effect of Expiration or Termination + +Upon expiration or earlier termination of this Agreement, Customer shall immediately discontinue use of the Supabase IP and, without limiting Customer's obligations under Section 6, Customer shall delete, destroy, or return all copies of the Supabase IP and certify in writing to the Supabase that the Supabase IP has been deleted or destroyed. No expiration or termination will affect Customer's obligation to pay all Fees that may have become due before such expiration or termination or entitle Customer to any refund. + +### d. Survival + +This Section 12(d), and Sections 1, 5, 6, 8, 9, 10, 11, and 13, and 14 survive any termination or expiration of this Agreement. No other provisions of this Agreement survive the expiration or earlier termination of this Agreement. + +## 13. Governing Law, Arbitration and Class Action/Jury Waiver + +### a. Governing Law + +Customer agrees that: (a) the Services will be deemed solely based in the State of California; and (b) the Service will be deemed a passive one that does not give rise to personal jurisdiction over us, either specific or general, in jurisdictions other than California. This Agreement will be governed by the internal substantive laws of the State of California, without respect to its conflict of laws principles. The parties acknowledge that this Agreement evidences a transaction involving interstate commerce. Notwithstanding the preceding sentences with respect to the substantive law governing this Agreement, the Federal Arbitration Act (9 U.S.C. §§ 1-16) (as it may be amended, "FAA") governs the interpretation and enforcement of the Arbitration Agreement below and preempts all state laws (and laws of other jurisdictions) to the fullest extent permitted by applicable laws and regulations. If the FAA is found to not apply to any issue that arises from or relates to the Arbitration Agreement, then that issue will be resolved under and governed by the law of the U.S. state where Customer resides (if applicable) or the jurisdiction mutually agreed upon in writing by the Parties. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Customer agrees to submit to the exclusive personal jurisdiction of the federal and state courts located in California for any actions for which Supabase retains the right to seek injunctive or other equitable relief in a court of competent jurisdiction to prevent the actual or threatened infringement, misappropriation, or violation of data security, Confidential Information, or intellectual property rights, as set forth in the Arbitration Agreement below, including any provisional relief required to prevent irreparable harm. Customer agrees that California is the proper and exclusive forum for any appeals of an arbitration award, or for trial court proceedings in the event that the Arbitration Agreement below is found to be unenforceable. This Agreement was drafted in the English language and this English language version of the Agreement is the original, governing instrument of the understanding between the Parties. In the event of any conflict between the English version of this Agreement and any translation, the English version will prevail. + +### b. Arbitration Agreement + +#### i. General + +READ THIS SECTION CAREFULLY BECAUSE IT REQUIRES THE PARTIES TO ARBITRATE THEIR DISPUTES AND LIMITS THE MANNER IN WHICH CUSTOMER CAN SEEK RELIEF FROM SUPABASE. This Arbitration Agreement applies to and governs any dispute, controversy, or claim between the Parties that arises out of or relates to, directly or indirectly: (i) this Agreement, including the formation, existence, breach, termination, enforcement, interpretation, validity, and enforceability thereof; (ii) access to or use of the Services, including receipt of any advertising or marketing communications; (iii) any transactions through, by, or using the Services; or (iv) any other aspect of Customer's relationship or transactions with Supabase, directly or indirectly, as a user or consumer (each, a "Claim," and, collectively, "Claims"). This Arbitration Agreement will apply, without limitation, to all Claims that arose or were asserted before or after Customer's consent to this Agreement. + +#### ii. Opting Out of Arbitration Agreement + +If you are a new customer, you can reject and opt out of this Arbitration Agreement within thirty (30) days of accepting this Agreement by emailing Supabase at [legal@supabase.io](mailto:legal@supabase.io) with your full, legal name (or the name of the organization that you had the legal authority to bind to this Agreement if you entered this Agreement for an organization) and stating your intent to opt out of this Arbitration Agreement. Opting out of this Arbitration Agreement does not affect the binding nature of any other part of this Agreement, including the provisions regarding controlling law or the courts in which any disputes must be brought. + +#### iii. Dispute-Resolution Process + +For any Claim, Customer will first contact Supabase at [legal@supabase.io](mailto:legal@supabase.io) and attempt to resolve the Claim with Supabase informally. In the unlikely event that the Parties have not been able to resolve a Claim after sixty (60) days, the Claim shall be finally settled under the Rules of Arbitration ("Rules") of the International Chamber of Commerce ("ICC") by one or more arbitrators (each, an "Arbitrator") appointed in accordance with such Rules. The place of arbitration shall be: (a) Singapore to the extent that Customer is located in Asia; (b) London, United Kingdom to the extent that Customer is located in Europe; or (c) San Francisco County, California to the extent that Customer is located in the United States or any other jurisdiction, in each case unless the Parties agree otherwise. If Customer is using the Service for commercial purposes, each party will be responsible for paying any ICC filing and administrative fees and Arbitrator fees in accordance with the Rules, and the award rendered by the Arbitrator will include costs of arbitration, reasonable attorneys' fees, and reasonable costs for expert and other witnesses. If Customer is an individual using the Services for non-commercial purposes: (i) ICC may require Customer to pay a fee for the initiation of a case; (ii) the award rendered by the Arbitrators may include Customer's costs of arbitration, reasonable attorneys' fees, and reasonable costs for expert and other witnesses; and (iii) Customer may sue in a small claims court of competent jurisdiction without first engaging in arbitration, but this would not absolve Customer of any commitment to engage in the informal dispute resolution process. Any judgment on the award rendered by the Arbitrators may be entered in any court of competent jurisdiction. The Parties agree that the Arbitrators, and not any federal, state, or local court or agency, will have exclusive authority to resolve any disputes relating to the scope, interpretation, applicability, enforceability, or formation of this Arbitration Agreement, including any claim that all or any part of this Arbitration Agreement is void or voidable. The Arbitrator will also be responsible for determining all threshold arbitrability issues, including issues relating to whether this Agreement is, or whether any provision hereof, unconscionable or illusory, and any defense to arbitration, including waiver, delay, laches, unconscionability, and/or estoppel. + +#### iv. Equitable Relief + +Nothing in this Arbitration Agreement will be deemed as: preventing Supabase from seeking injunctive or other equitable relief from the courts as necessary to prevent the actual or threatened infringement, misappropriation, or violation of Supabase's data security, confidential information, or intellectual property rights; or preventing Customer from asserting claims in a small claims court, provided that Customer's claims qualify and so long as the matter remains in such court and advances on only an individual (non-class, non-collective, and non-representative) basis. + +#### v. Severability + +If this Arbitration Agreement is found to be void, unenforceable, or unlawful, in whole or in part, the void, unenforceable, or unlawful provision, in whole or in part, will be severed. Severance of the void, unenforceable, or unlawful provision, in whole or in part, will have no impact on the remaining provisions of this Arbitration Agreement, which will remain in force, or on the Parties' ability to compel arbitration of any remaining Claims on an individual basis pursuant to this Arbitration Agreement. Notwithstanding the foregoing, if the Class Action/Jury Trial Waiver below is found to be void, unenforceable, or unlawful, in whole or in part, because it would prevent Customer from seeking public injunctive relief, then any dispute regarding the entitlement to such relief (and only that relief) must be severed from arbitration and may be litigated in a civil court of competent jurisdiction. All other claims for relief subject to arbitration under this Arbitration Agreement will be arbitrated under its terms, and the Parties agree that litigation of any dispute regarding the entitlement to public injunctive relief will be stayed pending the outcome of any individual claims in arbitration. + +### c. Class Action/Jury Trial Waiver + +By entering into this Agreement, each Party is waiving the right to a trial by jury or to bring, join, or participate in any purported class action, collective action, private attorney general action, or other representative proceeding of any kind as a plaintiff or class member. The foregoing applies to all users (both natural persons and entities), regardless of whether Customer has obtained or used the service for personal, commercial, or other purposes. This class action/jury trial waiver applies to class arbitration, and, unless the Parties agree otherwise, the Arbitrators may not consolidate more than one person's or entity's claims. The Parties agree that the Arbitrators may award relief only to an individual claimant and only to the extent necessary to provide relief on Customer's individual claim(s). Any relief awarded may not affect other users. + +## 14. Miscellaneous. + +### a. Entire Agreement + +This Agreement, together with any other documents incorporated herein by reference, constitutes the sole and entire agreement of the Parties with respect to the subject matter of this Agreement and supersedes all prior and contemporaneous understandings, agreements, and representations and warranties, both written and oral, with respect to such subject matter. In the event of any inconsistency between the statements made in the body of this Agreement, the related Exhibits, and any other documents incorporated herein by reference, the following order of precedence governs: (i) first, this Agreement; and (ii) second, any other documents incorporated herein by reference. + +### b. Notices + +All notices, requests, consents, claims, demands, waivers, and other communications hereunder (each, a "Notice") must be in writing and addressed to the Parties at the addresses set forth on the first page of this Agreement or as identified on the Order Form (or to such other address that may be designated by the Party giving Notice from time to time in accordance with this Section). All Notices must be delivered by personal delivery, nationally recognized signed for on delivery courier (with all fees pre-paid), or email (with confirmation of transmission). All email Notices to Supabase must be sent to [legal@supabase.io](mailto:legal@supabase.io). Except as otherwise provided in this Agreement, a Notice is effective only: (i) upon receipt by the receiving Party; and (ii) if the Party giving the Notice has complied with the requirements of this Section 14(b). Notwithstanding the foregoing, Customer hereby consents to receiving electronic communications from Supabase, which may include notices about applicable fees and charges, transactional information, and other information concerning or related to the Services. Customer agrees that any notices, agreements, disclosures, or other communications that Supabase sends to Customer electronically will satisfy any legal communication requirements, including that such communications be in writing. + +### c. Force Majeure + +In no event shall either Party be liable to the other Party, or be deemed to have breached this Agreement, for any failure or delay in performing its obligations under this Agreement (except for any obligations to make payments), if and to the extent such failure or delay is caused by any circumstances beyond such Party's reasonable control, including but not limited to acts of God, flood, fire, earthquake, explosion, war, terrorism, invasion, riot or other civil unrest, strikes, labor stoppages or slowdowns or other industrial disturbances, or passage of law or any action taken by a governmental or public authority, including imposing an embargo. + +### d. Amendment and Modification + +Supabase may change this Agreement (except for any Orders) from time to time at its discretion. The date on which the Agreement was last modified will be updated at the top of this Agreement. Supabase will provide Customer with reasonable notice prior to any amendments or modifications taking effect, either by emailing the email address associated with Customer's account on the Services or by another method reasonably designed to provide notice to Customer. If Customer accesses or uses the Services after the effective date of the revised Agreement, such access and use will constitute Customer's acceptance of the revised Agreement beginning at the next Renewal Subscription Period or, if Customer enters into a new Order with Supabase, as of the date of execution of such Order. + +### e. Waiver + +No failure or delay by either Party in exercising any right or remedy available to it in connection with this Agreement will constitute a waiver of such right or remedy. No waiver under this Agreement will be effective unless made in writing and signed by an authorized representative of the Party granting the waiver. + +### f. Severability + +If any provision of this Agreement is invalid, illegal, or unenforceable in any jurisdiction, such invalidity, illegality, or unenforceability will not affect any other term or provision of this Agreement or invalidate or render unenforceable such term or provision in any other jurisdiction. Upon such determination that any term or other provision is invalid, illegal, or unenforceable, the Parties shall negotiate in good faith to modify this Agreement so as to effect their original intent as closely as possible in a mutually acceptable manner in order that the transactions contemplated hereby be consummated as originally contemplated to the greatest extent possible. + +### g. Assignment + +Customer may not assign any of its rights or delegate any of its obligations hereunder, in each case whether voluntarily, involuntarily, by operation of law or otherwise, without the prior written consent of Supabase. Any purported assignment or delegation in violation of this Section will be null and void. No assignment or delegation will relieve the assigning or delegating Party of any of its obligations hereunder. This Agreement is binding upon and inures to the benefit of the Parties and their respective permitted successors and assigns. + +### h. Export Regulation + +The Services utilize software and technology that may be subject to US export control laws, including the US Export Administration Act and its associated regulations. Customer shall not, directly or indirectly, export, re-export, or release the Services or the underlying software or technology to, or make the Services or the underlying software or technology accessible from, any jurisdiction or country to which export, re-export, or release is prohibited by law, rule, or regulation. Customer shall comply with all applicable federal laws, regulations, and rules, and complete all required undertakings (including obtaining any necessary export license or other governmental approval), prior to exporting, re-exporting, releasing, or otherwise making the Services or the underlying software or technology available outside the US. + +### i. US Government Rights + +Each of the Documentation and the software components that constitute the Services is a "commercial item" as that term is defined at 48 C.F.R. § 2.101, consisting of "commercial computer software" and "commercial computer software documentation" as such terms are used in 48 C.F.R. § 12.212. Accordingly, if Customer is an agency of the US Government or any contractor therefor, Customer only receives those rights with respect to the Services and Documentation as are granted to all other end users, in accordance with (a) 48 C.F.R. § 227.7201 through 48 C.F.R. § 227.7204, with respect to the Department of Defense and their contractors, or (b) 48 C.F.R. § 12.212, with respect to all other US Government users and their contractors. + +### j. Equitable Relief + +Each Party acknowledges and agrees that a breach or threatened breach by such Party of any of its obligations under Section 6 or, in the case of Customer, Section 2(c), would cause the other Party irreparable harm for which monetary damages would not be an adequate remedy and agrees that, in the event of such breach or threatened breach, the other Party will be entitled to equitable relief, including a restraining order, an injunction, specific performance and any other relief that may be available from any court, without any requirement to post a bond or other security, or to prove actual damages or that monetary damages are not an adequate remedy. Such remedies are not exclusive and are in addition to all other remedies that may be available at law, in equity or otherwise. + +### k. Publicity + +Supabase may identify Customer as a user of the Services and may use Customer's name, logo, and other trademarks in Supabase's customer list, press releases, blog posts, advertisements, and website (and all use thereof and goodwill arising therefrom shall inure to the sole and exclusive benefit of Customer). Otherwise, neither Party may use the name, logo, or other trademarks of the other Party for any purpose without the other Party's prior written approval. diff --git a/apps/www/pages/terms.tsx b/apps/www/pages/terms.tsx index 87e4f171f87bd..a1f603dd6bc63 100644 --- a/apps/www/pages/terms.tsx +++ b/apps/www/pages/terms.tsx @@ -4,6 +4,7 @@ import SectionContainer from '~/components/Layouts/SectionContainer' import LegalDocVersions, { type LegalDocVersion } from '~/components/Legal/LegalDocVersions' import V1 from '~/data/legal/terms/v1.mdx' import V2 from '~/data/legal/terms/v2.mdx' +import V3 from '~/data/legal/terms/v3.mdx' import mdxComponents from '~/lib/mdx/mdxComponents' import { NextSeo } from 'next-seo' @@ -13,6 +14,7 @@ const meta = { } const versions: LegalDocVersion[] = [ + { id: 'v3', label: 'Version 3', effectiveDate: 'August 1, 2026', Component: V3 }, { id: 'v2', label: 'Version 2', effectiveDate: 'May 6, 2026', Component: V2 }, { id: 'v1', label: 'Version 1', effectiveDate: 'July 11, 2025', Component: V1 }, ] From 8a607a6108a110e2653b1b38853c09eb178d7437 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <209825114+claude[bot]@users.noreply.github.com> Date: Thu, 30 Jul 2026 12:49:40 +0200 Subject: [PATCH 03/12] feat(www): add Enterprise SaaS Subscription Agreement v3 (#48484) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _Requested by **Nicole Kramer** · [Slack thread](https://supabase.slack.com/archives/C0161K73J1J/p1785399555203219)_ ## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES ## What kind of change does this PR introduce? Content update — a new version of a published legal agreement. ## What is the current behavior? The version selector on `/enterprise-terms` offers two versions of the Enterprise SaaS Subscription Agreement: Version 2 (May 6, 2026) and Version 1 (April 17, 2026). Version 2 is what the page shows by default. ## What is the new behavior? **Before:** opening `/enterprise-terms` showed Version 2 — May 6, 2026. **After:** it shows **Version 3 — August 1, 2026**. Versions 2 and 1 are unchanged and still reachable from the dropdown (`?version=v2`, `?version=v1`). Two files change: - **New** `apps/www/data/legal/enterprise-terms/v3.mdx` — the Version 3 text, transcribed from the source Word document supplied in the Slack thread (`2026.07.29 - Supabase - Enterprise Terms.docx`). - `apps/www/pages/enterprise-terms.tsx` — imports the new MDX and prepends `{ id: 'v3', label: 'Version 3', effectiveDate: 'August 1, 2026', Component: V3 }` to the `versions` array. Since the array is newest-first, v3 becomes the default. ## Additional context ### Transcription fidelity The legal text was not edited, reworded, reordered, or corrected — only re-rendered in the MDX conventions already used by `v1.mdx` and `v2.mdx`. This was verified mechanically rather than by eye: markdown markup was stripped from `v3.mdx` and the result diffed paragraph-by-paragraph against text extracted directly from the source document's OOXML. - **137 paragraphs in the source, 137 in `v3.mdx`, 0 differing.** - 14 top-level sections and 48 subsections, matching the source's heading counts exactly. - All 3 distinct URLs preserved, written as bare URLs per the existing convention in this file family (remark-gfm autolinks them). - Pure ASCII apart from 5 `§` characters in the 48 C.F.R. citations, matching `v1.mdx`/`v2.mdx`. - Prettier clean; no British spellings that would trip the US-locale misspell check. Formatting decisions worth knowing: the source document contains no bold or italic runs at all, but `v1.mdx` and `v2.mdx` both bold defined terms and section numbers, so v3 follows that house style for consistent rendering across the three versions. The source also carries no date or version line of its own; the `_Last Modified: 1 August 2026_` first line is repo convention, matching how every other legal MDX in `apps/www/data/legal/` is written. ### What changed from v2, in the legal text Structure is identical — same 14 sections, same 48 subsection titles. Five substantive prose changes: 1. **Preamble** — the effective date is now "the date of last signature of an Order referencing these terms", replacing v2's unfilled `[Deal.CloseDate]` merge-field placeholder. "Signature block below" becomes "signature block in an Order". 2. **New § 1.4 "Data Processing Addendum"** — defined by reference to `https://supabase.com/legal/customer-resources/data-processing-addendum`, with a carve-out for a separately executed agreement covering the same subject matter. Former § 1.4–1.12 shift to § 1.5–1.13; nothing was removed or reordered. 3. **§ 7.2 Data Processing** replaced — v2's GDPR / UK GDPR / Swiss clause is gone, replaced by a general compliance paragraph that incorporates the Data Processing Addendum into the Agreement. 4. **§ 13.3** cross-reference corrected from Section 10.1 (Mutual) to Section 10.3 (Limited Warranty), which is the clause the refund remedy actually depends on. 5. **§ 14.4 Amendment and Modification** rewritten — v2 required a writing executed by both Parties; v3 gives Supabase a unilateral right to modify by posting a revised version at `https://supabase.com/enterprise-terms`, effective the first day of the following calendar month, or at the start of the next Renewal Subscription Period for Orders with a fixed Subscription Period of 12 months or longer, with non-renewal under § 13.1 as Customer's sole and exclusive remedy. Two things carried over verbatim from the source rather than fixed, since the text must not be edited: § 7.2 is now near-duplicative of § 7.1 (three of its four sentences repeat § 7.1 almost word for word), and "HIPAA" is used in both § 7.1 and § 7.2 without being defined. One pre-existing inconsistency, unrelated to this change: `v2.mdx`'s own first line reads `_Last Modified: 1 May 2026_` while the page lists Version 2's effective date as `May 6, 2026`. Left alone here. ### Overlap with concurrent work Two sibling changes are in flight for the same requester today — one adjusting the new Data Processing Addendum page's dates, one publishing Terms of Service v3. Neither touches these two files, but all three touch the `apps/www/data/legal/` tree, and note that § 1.4 above now links to the DPA page. [#48483](https://github.com/supabase/supabase/pull/48483) removes the `_Last Modified:` first line from every versioned legal MDX, on the principle that the version selector should be the only place a date appears. It is sequenced to land after this PR, and its file list predates `v3.mdx`. A three-way merge of the two branches is clean, but whoever rebases #48483 should add `apps/www/data/legal/enterprise-terms/v3.mdx` to that removal — otherwise v3 keeps a body date after v1 and v2 lose theirs. The `_Last Modified: 1 May 2026` / `May 6, 2026` mismatch on v2 is also handled in #48483 and is deliberately left alone here, so the same line isn't touched by two PRs. Co-authored-by: Claude --- apps/www/data/legal/enterprise-terms/v3.mdx | 275 ++++++++++++++++++++ apps/www/pages/enterprise-terms.tsx | 2 + 2 files changed, 277 insertions(+) create mode 100644 apps/www/data/legal/enterprise-terms/v3.mdx diff --git a/apps/www/data/legal/enterprise-terms/v3.mdx b/apps/www/data/legal/enterprise-terms/v3.mdx new file mode 100644 index 0000000000000..c156a7e28cb13 --- /dev/null +++ b/apps/www/data/legal/enterprise-terms/v3.mdx @@ -0,0 +1,275 @@ +_Last Modified: 1 August 2026_ + +This Enterprise SaaS Subscription Agreement (this "**Agreement**") is entered into by and between the customer identified in the signature block in an Order ("**Customer**") and Supabase, Pte. Ltd., as subsidiary of Supabase, Inc., a Delaware corporation ("**Supabase**") (Customer and Supabase each, a "**Party**" and collectively, the "**Parties**"), effective as of the date of last signature of an Order referencing these terms ("**Effective Date**"), and sets forth the terms and conditions under which Customer may subscribe to certain products and services of Supabase as set forth in one or more Orders (defined below). + +**Accepted and agreed to as of the Effective Date by the authorized representative of each Party by Customer's entering into an Order referencing this Agreement.** + +## 1. Definitions. + +**1.1** "**Aggregated Data**" means data and information related to or derived from Customer Data or Customer's use of the Services that is used by Supabase in an aggregate and anonymized manner, including to compile statistical and performance information related to the Services. + +**1.2** "**Authorized User**" means Customer's employees, consultants, contractors, and agents (a) who are authorized by Customer to access and use the Services under the rights granted to Customer pursuant to this Agreement; and (b) for whom access to the Services has been purchased by Customer hereunder. + +**1.3** "**Customer Data**" means information, data, and other content, in any form or medium, that is submitted, posted, or otherwise transmitted by or on behalf of Customer or an Authorized User through the Services; provided that, for purposes of clarity, Customer Data does not include Aggregated Data. + +**1.4** "**Data Processing Addendum**" means the Data Processing Addendum available at https://supabase.com/legal/customer-resources/data-processing-addendum, or, if the Parties have a separately executed agreement in effect that covers the same subject matter, the separately executed agreement. + +**1.5** "**Documentation**" means Supabase's end user documentation relating to the Services available at supabase.io. + +**1.6** "**Harmful Code**" means any software, hardware, or other technology, device, or means, including any virus, worm, malware, or other malicious computer code, the purpose or effect of which is to permit unauthorized access to, or to destroy, disrupt, disable, distort, or otherwise harm or impede in any manner any (a) computer, software, firmware, hardware, system, or network or (b) any application or function of any of the foregoing or the security, integrity, confidentiality, or use of any data processed thereby. + +**1.7** "**Order**" means: (a) the purchase order, order form, or other ordering document entered into by the Parties that incorporates this Agreement by reference; or (b) if Customer registered for the Services through Supabase's online ordering process, the results of such online ordering process. + +**1.8** "**Personal Information**" means any information that, individually or in combination, does or can identify a specific individual or by or from which a specific individual may be identified, contacted, or located, including without limitation all data considered "personal data", "personally identifiable information", or something similar under applicable laws, rules, or regulations relating to data privacy. + +**1.9** "**Supabase IP**" means the Services, the Documentation, all related and underlying technology, documentation and other information, and any and all intellectual property provided to Customer or any Authorized User in connection with the foregoing, and any derivatives thereof. For the avoidance of doubt, Supabase IP includes Aggregated Data and any information, data, intellectual property or other content derived from Supabase's provision of the Services but does not include Customer Data. + +**1.10** "**Services**" means Supabase's proprietary hosted software platform, as made available by Supabase to Authorized Users from time to time. + +**1.11** "**Subscription Period**" means the period set forth in Section 13.1, below. + +**1.12** "**Third-Party Products**" means any third-party products, software components, or services provided with, integrated with, or incorporated into the Services. + +**1.13** "**Usage Limitations**" means the usage limitations set forth in this Agreement and the Order, including without limitation any limitations on the number of Authorized Users (if any), and the applicable product, pricing, and support tiers agreed-upon by the Parties. + +## 2. Access and Use. + +### 2.1 Provision of Access. + +Subject to and conditioned on Customer's compliance with the terms and conditions of this Agreement, including without limitation the Usage Limitations, Supabase will make available to Customer during the Subscription Period, on a non-exclusive, non-transferable (except in compliance with Section 14.8), and non-sublicensable basis, access to and use of the Services, solely for use by Authorized Users. Such use is limited to Customer's internal business purposes and the features and functionalities specified in the Order. Supabase shall provide to Customer the necessary access credentials to allow Customer to access the Services. Each Order will be incorporated into, and is fully governed by, this Agreement upon execution of the Order by both Parties. + +### 2.2 Documentation License. + +Subject to and conditioned on Customer's compliance with the terms and conditions of this Agreement, Supabase hereby grants to Customer a non-exclusive, non-transferable (except in compliance with Section 14.8), and non-sublicensable license to use the Documentation during the Subscription Period solely for Customer's internal business purposes in connection with its use of the Services. + +### 2.3 Use Restrictions. + +Customer shall not use the Services for any purposes beyond the scope of the access granted in this Agreement. Customer shall not at any time, directly or indirectly, and shall not permit any Authorized Users to: (a) copy, modify, or create derivative works of any Supabase IP, whether in whole or in part; (b) rent, lease, lend, sell, license, sublicense, assign, distribute, publish, transfer, or otherwise make available the Services or Documentation to any third party; (c) reverse engineer, disassemble, decompile, decode, adapt, or otherwise attempt to derive or gain access to any software component of the Services, in whole or in part; (d) remove any proprietary notices from any Supabase IP; (e) use any Supabase IP in any manner or for any purpose that infringes, misappropriates, or otherwise violates any intellectual property right or other right of any person, or that violates any applicable law; (f) access or use any Supabase IP for purposes of competitive analysis of Supabase or the Services, the development, provision, or use of a competing software service or product, or any other purpose that is to Supabase's detriment or commercial disadvantage; (g) bypass or breach any security device or protection used by the Services or access or use the Services other than by an Authorized User through the use of valid access credentials; or (h) input, upload, transmit, or otherwise provide to or through the Services any information or materials that are unlawful or injurious, or that contain, transmit, or activate any Harmful Code. + +### 2.4 Use by Affiliates. + +Each of Customer's Affiliates (defined below) identified on an Order will be entitled to access and use the applicable Supabase IP in accordance with this Agreement and the applicable Order; provided that Customer shall remain responsible to Supabase for the actions and omissions of each such Affiliate (and each of such Affiliate's Authorized Users). The terms of this Agreement will govern, and will be incorporated by reference in, each such Order as if this Agreement were separately executed by the applicable Customer Affiliate, and the term "Customer" as used in this Agreement will be deemed as applying to such Affiliate of Customer for the purposes of such Order. "**Affiliate**" means an entity that, directly or indirectly, controls, is controlled by, or is under common control with a Party. As used herein, "**control**" means the power to direct the management or affairs of an entity or the beneficial ownership of fifty percent (50%) or more of the voting equity securities or other equivalent voting interests of an entity. + +### 2.5 Reservation of Rights. + +Supabase reserves all rights not expressly granted to Customer in this Agreement. Except for the limited rights and licenses expressly granted under this Agreement, nothing in this Agreement grants, by implication, waiver, estoppel, or otherwise, to Customer or any third party any intellectual property rights or any other right, title, or interest in or to the Supabase IP. + +### 2.6 Suspension. + +Notwithstanding anything to the contrary in this Agreement, Supabase may temporarily suspend Customer's and any Authorized User's access to any portion or all of the Services if: (a) Supabase reasonably determines that (i) there is a threat or attack on any of the Supabase IP, (ii) Customer's or any Authorized User's use of the Supabase IP disrupts or poses a security risk to the Supabase IP or to any other customer or vendor of Supabase, (iii) Customer, or any Authorized User, is using the Supabase IP for fraudulent or illegal activities, (iv) subject to applicable law, Customer has ceased to continue its business in the ordinary course, made an assignment for the benefit of creditors or similar disposition of its assets, or become the subject of any bankruptcy, reorganization, liquidation, dissolution, or similar proceeding, or (v) Supabase's provision of the Services to Customer or any Authorized User is prohibited by applicable law; (b) any vendor of Supabase has suspended or terminated Supabase's access to or use of any Third-Party Products required to enable Customer to access the Services; or (c) in accordance with Section 5.1 (any such suspension described in subclause (a), (b), or (c), a "**Service Suspension**"). Supabase shall use commercially reasonable efforts to provide prior written notice of any Service Suspension to Customer and to provide updates regarding resumption of access to the Services following any Service Suspension. Supabase shall use commercially reasonable efforts to resume providing access to the Services as soon as reasonably possible after the event giving rise to the Service Suspension is cured. Supabase will have no liability for any damage, liabilities, losses (including any loss of data or profits), or any other consequences that Customer or any Authorized User may incur as a result of a Service Suspension. + +### 2.7 Aggregated Data. + +Notwithstanding anything to the contrary in this Agreement, Supabase may monitor Customer's use of the Services and collect and compile Aggregated Data. As between Supabase and Customer, all right, title, and interest in Aggregated Data, and all intellectual property rights therein, belong to and are retained solely by Supabase. Customer acknowledges that Supabase may compile Aggregated Data based on Customer Data input into the Services. Customer agrees that Supabase may (a) make Aggregated Data available to third parties including its other customers in compliance with applicable law, and (b) use Aggregated Data to the extent and in the manner permitted under applicable law. + +### 2.8 Service Level Agreement. + +Supabase will make commercially reasonable efforts to provide the Services in accordance with the uptime commitment, service credit, and other terms available at: https://supabase.com/docs/company/sla ("**Service Level Agreement**"). + +## 3. Customer Responsibilities. + +### 3.1 General. + +Customer is responsible and liable for all uses of the Services and Documentation resulting from access provided by Customer, directly or indirectly, whether such access or use is permitted by or in violation of this Agreement. Without limiting the generality of the foregoing, Customer is responsible for all acts and omissions of Authorized Users, and any act or omission by an Authorized User that would constitute a breach of this Agreement if taken by Customer will be deemed a breach of this Agreement by Customer. Customer shall use reasonable efforts to make all Authorized Users aware of this Agreement's provisions as applicable to such Authorized User's use of the Services and shall cause Authorized Users to comply with such provisions. + +### 3.2 Third-Party Terms. + +Supabase may from time to time make Third-Party Products available to Customer or Supabase may allow for certain Third-Party Products to be integrated with the Services to allow for the transmission of Customer Data from such Third-Party Products into the Services. For purposes of this Agreement, such Third-Party Products are subject to their own terms and conditions. To the extent there is a conflict between the terms and conditions applicable to any such Third-Party Product and this Agreement, the Third-Party Product terms and conditions shall control. If Customer does not agree to abide by the applicable terms for any such Third-Party Products, then Customer should not install or use such Third-Party Products. By authorizing Supabase to transmit Customer Data from Third-Party Products into the Services, Customer represents and warrants to Supabase that it has all right, power, and authority to provide such authorization. ALL THIRD-PARTY PRODUCTS ARE MADE AVAILABLE ON AN "AS IS" BASIS WITHOUT WARRANTY OF ANY KIND. IF CUSTOMER USES ANY THIRD-PARTY PRODUCTS, SUPABASE WILL NOT BE RESPONSIBLE FOR ANY ACT OR OMISSION OF ANY PROVIDER OF SUCH THIRD-PARTY PRODUCTS. CUSTOMER ACKNOWLEDGES AND AGREES THAT SUPABASE WILL HAVE NO RESPONSIBILITY OR LIABILITY FOR THE ACTS OR OMISSIONS OF ANY AUTHORIZED USERS IN CONNECTION WITH ANY THIRD-PARTY PRODUCTS. + +### 3.3 Customer Control and Responsibility. + +Customer has and will retain sole responsibility for: (a) all Customer Data, including its content, accuracy, legality and use; (b) all information, instructions, and materials provided by or on behalf of Customer or any Authorized User in connection with the Services; (c) Customer's information technology infrastructure, including computers, software, databases, electronic systems (including database management systems), and networks, whether operated directly by Customer or through the use of third-party services ("**Customer Systems**"); (d) the security and use of Customer's and its Authorized Users' access credentials; and (e) all access to and use of the Services directly or indirectly by or through the Customer Systems or its or its Authorized Users' access credentials, with or without Customer's knowledge or consent, including all results obtained from, and all conclusions, decisions, and actions based on, such access or use. + +### 3.4 Responsible Use of AI-Powered Tools. + +From time to time, Supabase may make available chatbots or other artificial intelligence-enabled tools to assist with customer support inquiries or other interactions (each, an "**AI Tool**"). Customer is responsible for the responsible and informed use of any AI Tool, including by: (a) ensuring that any data, content, prompts, or other materials Customer or its Authorized Users submit to an AI Tool (collectively, "**AI Input**") (i) are submitted with all necessary rights, consents, and authorizations, including with respect to any third-party or personal information contained therein, and (ii) do not violate applicable law, infringe or misappropriate any third-party right, or breach any obligation of confidentiality owed to a third party; (b) applying human judgment to review, evaluate, and verify any output generated by an AI Tool ("**AI Output**") before relying on it, using it or otherwise acting on it; (c) not treating any AI Output as legal, financial, security, or other professional advice; and (d) escalating to a human Supabase representative through Supabase's standard support channels whenever Customer requires authoritative confirmation, has a time-sensitive issue, or is otherwise not satisfied with the AI Output. + +## 4. Support. + +During the Subscription Period, Supabase will use commercially reasonable efforts to provide Customer with basic customer support via Supabase's standard support channels during Supabase's normal business hours. + +## 5. Fees and Taxes. + +### 5.1 Fees and Payment. + +Where paid-for services are agreed between Supabase and Customer per the applicable Order, Customer shall pay Supabase the fees ("**Fees**") identified in the Order without offset or deduction at the cadence identified in the Order (e.g., monthly or annually). Customer will pay the Fees within thirty (30) days of the issuance of an invoice. Except as otherwise set forth in the applicable Order, Fees are payable by credit card or other payment method permitted by Supabase from time to time, payment will be in USD, and Customer authorizes Supabase to charge its credit card or bank account for all Fees. Customer further authorizes Supabase to use a third party to process payments, and consents to the disclosure of Customer's payment information to such third party. Fees paid by Customer are non-refundable (except as set forth in Sections 10.3 or 11.1(b)). If Customer fails to make any payment when due, and Customer has not notified Supabase in writing within ten (10) days of the payment becoming due and payable that the payment is subject to a good faith dispute, without limiting Supabase's other rights and remedies: (a) Supabase may charge interest on the undisputed past due amount at the rate of 1.5% per month, calculated daily and compounded monthly or, if lower, the highest rate permitted under applicable law; (b) Customer shall reimburse Supabase for all reasonable costs incurred by Supabase in collecting any late payments or interest, including attorneys' fees, court costs, and collection agency fees; and (c) if such failure continues for ten (10) days or more, Supabase may suspend Customer's and its Authorized Users' access to any portion or all of the Services until such amounts are paid in full. + +### 5.2 Taxes. + +All Fees and other amounts payable by Customer under this Agreement are exclusive of taxes and similar assessments. Customer is responsible for all sales, use, and excise taxes, and any other similar taxes, duties, and charges of any kind imposed by any federal, state, or local governmental or regulatory authority on any amounts payable by Customer hereunder, other than any taxes imposed on Supabase's income. To the extent that Supabase is required by law to pay any such taxes, duties, or other charges to any governmental or regulatory authority, Supabase may invoice Customer for such taxes, duties, or other charges and Customer will pay such invoiced amounts in accordance with this Agreement. + +## 6. Confidential Information. + +### 6.1 Definition. + +From time to time during the Subscription Period, either Party may disclose or make available to the other Party information about its business affairs, products, confidential intellectual property, trade secrets, third-party confidential information, and other sensitive or proprietary information, whether orally or in written, electronic, or other form or media that: (a) is marked, designated or otherwise identified as "confidential" or something similar at the time of disclosure or within a reasonable period of time thereafter; or (b) would be considered confidential by a reasonable person given the nature of the information or the circumstances of its disclosure (collectively, "**Confidential Information**"). Except for Personal Information, Confidential Information does not include information that, at the time of disclosure is: (i) in the public domain; (ii) known to the receiving Party at the time of disclosure; (iii) rightfully obtained by the receiving Party on a non-confidential basis from a third party; or (iv) independently developed by the receiving Party without use of, reference to, or reliance upon the disclosing Party's Confidential Information, as proven by the receiving Party's then-contemporaneous written records. + +### 6.2 Duty. + +The receiving Party shall not disclose the disclosing Party's Confidential Information to any person or entity, except to the receiving Party's employees, contractors, and agents who have a need to know the Confidential Information for the receiving Party to exercise its rights or perform its obligations hereunder ("**Representatives**"). The receiving Party will be responsible for all the acts and omissions of its Representatives as they relate to Confidential Information hereunder. Notwithstanding the foregoing, each Party may disclose Confidential Information to the limited extent required (a) in order to comply with the order of a court or other governmental body, or as otherwise necessary to comply with applicable law, provided that the Party making the disclosure pursuant to the order shall first have given written notice to the other Party and made a reasonable effort to obtain a protective order, or (b) to establish a Party's rights under this Agreement, including to make required court filings. Further, notwithstanding the foregoing, each Party may disclose the terms and existence of this Agreement to its actual or potential investors, debtholders, acquirers, or merger partners under customary confidentiality terms. + +### 6.3 Return of Materials; Effects of Termination / Expiration. + +On the expiration or termination of this Agreement, the receiving Party shall promptly return to the disclosing Party all copies, whether in written, electronic, or other form or media, of the disclosing Party's Confidential Information, or destroy all such copies and certify in writing to the disclosing Party that such Confidential Information has been destroyed. Each Party's obligations of non-use and non-disclosure with regard to Confidential Information are effective as of the Effective Date and will expire three (3) years from the date of termination or expiration of this Agreement; provided, however, with respect to any Confidential Information that constitutes a trade secret (as determined under applicable law), such obligations of non-disclosure will survive the termination or expiration of this Agreement for as long as such Confidential Information remains subject to trade secret protection under applicable law. + +## 7. Personal Information. + +### 7.1 General. + +Customer will ensure that its Customer Data, and its use of such Customer Data, complies with this Agreement and any applicable local, state, federal and international laws, regulations and conventions, including, without limitation, those related to data privacy, international communications, and the exportation of technical or personal data (including Personal Information). Customer is responsible for properly configuring and using the Services and taking its own steps to maintain appropriate security, protection, and backup of Customer Data. Customer may not store or process protected health information (as defined in HIPAA) using the Services unless Customer signs a Business Associate Agreement with Supabase. Customer may not store any payment cardholder information using the Services without Supabase's prior written approval. + +### 7.2 Data Processing. + +Customer will ensure that its Customer Data, and its use of such Customer Data, complies with this Agreement and any applicable law. Customer is responsible for properly configuring and using the Services and taking its own steps to maintain appropriate security, protection, and backup of Customer Data. Customer may not store or process protected health information (as defined in HIPAA) using the Services unless Customer signs a Business Associate Agreement with Supabase. Customer may not store any payment cardholder information using the Services without Supabase's prior written approval. The Parties agree to comply with the Data Processing Addendum, which is incorporated into this Agreement. + +## 8. Security. + +Supabase shall use reasonable physical, technical, and administrative procedures designed to protect, safeguard and help prevent loss, misuse, and unauthorized access, disclosure, alteration or destruction of Customer Data, and Supabase will choose these safeguards based on the sensitivity of the information that is collected, processed, and stored and the current state of applicable technology. + +## 9. Intellectual Property Ownership; Feedback. + +### 9.1 Supabase IP. + +Customer acknowledges that, as between Customer and Supabase, Supabase owns all right, title, and interest, including all intellectual property rights, in and to the Supabase IP and, with respect to Third-Party Products, the applicable third-party providers own all right, title, and interest, including all intellectual property rights, in and to the Third-Party Products. + +### 9.2 Customer Data. + +Supabase acknowledges that, as between Supabase and Customer, Customer owns all right, title, and interest, including all intellectual property rights, in and to the Customer Data. Customer hereby grants to Supabase a non-exclusive, royalty-free, worldwide license to reproduce, distribute, and otherwise use and display the Customer Data and perform all acts with respect to the Customer Data as may be necessary for Supabase to provide the Services to Customer. Customer may export the Customer Data at any time through the features and functionalities made available via the Services. To the extent Supabase utilizes artificial intelligence to provide features to Customer via the Services, and in Supabase's provision of the AI Tools, Supabase will not use, nor allow any third-party to use, Customer Data, Customer's AI Input, or any AI Output to train, fine-tune, or otherwise improve any artificial intelligence or machine learning model, without Customer's prior written consent. For the avoidance of doubt, Customer retains all right, title and interest in Customer Data contained in AI Inputs and AI Outputs. + +### 9.3 Feedback. + +If Customer or any of its employees or contractors sends or transmits any communications or materials to Supabase by mail, email, telephone, or otherwise, suggesting or recommending changes to the Supabase IP, including without limitation, new features or functionality relating thereto, or any comments, questions, suggestions, or the like ("**Feedback**"), Customer hereby assigns to Supabase all right, title and interest in and to the Feedback, including all intellectual property rights therein, and acknowledges that Supabase shall own such Feedback. + +## 10. Warranties. + +### 10.1 Mutual. + +Each Party represents and warrants to the other Party that: + +(a) it is duly organized, validly existing, and in good standing as a corporation or other entity under the Laws of the jurisdiction of its incorporation or other organization; + +(b) it has the full right, power, and authority to enter into and perform its obligations and grant the rights, licenses, consents, and authorizations it grants or is required to grant under this Agreement; + +(c) the execution of this Agreement by its representative whose signature is set forth at the end of this Agreement has been duly authorized by all necessary corporate or organizational action of such party; and + +(d) when executed and delivered by both parties, this Agreement will constitute the legal, valid, and binding obligation of such party, enforceable against such party in accordance with its terms. + +### 10.2 Customer. + +Customer represents, warrants, and covenants to Supabase that Customer owns or otherwise has and will have the necessary rights and consents in and relating to the Customer Data so that, as received by Supabase and processed in accordance with this Agreement, they do not and will not infringe, misappropriate, or otherwise violate any intellectual property, privacy or other rights of any third party or violate any applicable Law. + +### 10.3 Limited Warranty. + +Supabase warrants that it will provide the Services in substantial conformity with the applicable Documentation and the descriptions in the Order. Supabase's sole liability (and Customer's sole and exclusive remedy) for any breach of this warranty shall be, in Supabase's sole discretion and at no charge to Customer, to use commercially reasonable efforts to provide Customer with an error correction or work-around that corrects the reported non-conformity, or if Supabase determines such remedies to be impracticable, to allow Customer to terminate the Subscription Period and receive as its sole remedy and Supabase's entire liability, a refund of any Fees Customer has pre-paid for use of the Services or related services it has not received as of the date of the warranty claim. The limited warranty set forth in this Section 10.3 shall not apply: (a) unless Customer makes a claim within thirty (30) days of the date on which the condition giving rise to the claim first appeared, (b) if the error was caused by misuse, unauthorized modifications or third-party hardware, software or services, or (c) to Services provided on a no-charge or evaluation basis. + +### 10.4 Warranty Disclaimer. + +EXCEPT FOR THE LIMITED WARRANTY SET FORTH IN SECTION 10.3, THE SUPABASE IP IS PROVIDED "AS IS" AND ON AN "AS AVAILABLE" BASIS. SUPABASE HEREBY DISCLAIMS ALL WARRANTIES, WHETHER EXPRESS, IMPLIED, STATUTORY, OR OTHERWISE. SUPABASE SPECIFICALLY DISCLAIMS ALL IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND NON-INFRINGEMENT, AND ALL WARRANTIES ARISING FROM COURSE OF DEALING, USAGE, OR TRADE PRACTICE. SUPABASE MAKES NO WARRANTY OF ANY KIND THAT THE SUPABASE IP, OR ANY PRODUCTS OR RESULTS OF THE USE THEREOF, WILL MEET CUSTOMER'S OR ANY OTHER PERSON'S REQUIREMENTS, OPERATE WITHOUT INTERRUPTION, ACHIEVE ANY INTENDED RESULT, BE COMPATIBLE OR WORK WITH ANY SOFTWARE, SYSTEM OR OTHER SERVICES, OR BE SECURE, ACCURATE, COMPLETE, FREE OF HARMFUL CODE, OR ERROR FREE. In addition, Customer acknowledges that AI Tools are powered by one or more third-party large language models that Supabase does not own or control, and that AI Outputs may be inaccurate, incomplete, or unsuitable for Customer's particular use case. Customer acknowledges that other customers providing similar AI Input may receive similar or the same AI Output. AI TOOLS AND THEIR OUTPUTS ARE PROVIDED ON AN "AS IS" AND "AS AVAILABLE" BASIS, AND SUPABASE MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, AS TO THE ACCURACY, RELIABILITY, COMPLETENESS, ERROR-FREE NATURE, NON-INFRINGEMENT, OR FITNESS FOR A PARTICULAR PURPOSE OF ANY OUTPUT GENERATED FROM THE AI TOOLS. + +## 11. Indemnification. + +### 11.1 Supabase Indemnification. + +(a) Supabase shall indemnify, defend, and hold harmless Customer from and against any and all losses, damages, liabilities, costs (including reasonable attorneys' fees) ("**Losses**") incurred by Customer resulting from any claim, suit, action, or proceeding asserted by a third-party ("**Third-Party Claim**") against Customer that the Services, or any use of the Services in accordance with this Agreement, infringes or misappropriates such third party's US copyrights or trade secrets; provided that Customer promptly notifies Supabase in writing of the claim (but in any event notice in sufficient time for Supabase to respond without prejudice), cooperates with Supabase, and allows Supabase sole authority to control the defense and settlement of such claim. + +(b) If such a claim is made or appears possible, Customer agrees to permit Supabase, at Supabase's sole discretion: to (i) modify or replace the Services, or component or part thereof, to make it non-infringing; or (ii) obtain the right for Customer to continue use. If Supabase determines that neither alternative is reasonably commercially available, Supabase may terminate this Agreement, in its entirety or with respect to the affected component or part, effective immediately on written notice to Customer. + +(c) This Section 11.1 will not apply to the extent that the alleged infringement arises from: (i) use of the Services in combination with data, software, hardware, equipment, or technology not provided by Supabase or authorized by Supabase in writing; (ii) modifications to the Services not made by Supabase; (iii) Customer Data; (iv) Third-Party Products; (v) use of the Services in breach of this Agreement; (vi) AI Output; or (vii) AI Input. + +### 11.2 Customer Indemnification. + +Customer shall indemnify, hold harmless, and, at Supabase's option, defend Supabase from and against any Losses resulting from (a) any Third-Party Claim that the Customer Data, AI Input or any use of the Customer Data in accordance with this Agreement, infringes or misappropriates such third party's US intellectual property or other rights, and (b) arising out of or in connection with any claim arising from or relating to Customer's or any Authorized User's: (i) negligence or willful misconduct; (ii) use of the Services in a manner not authorized by this Agreement; (iii) Customer's violation of any laws, regulations, or rights relating to Customer Data or AI Input (including, without limitation, privacy laws, regulations, or rights), or (iv) use of the Services in combination with data, software, hardware, equipment or technology not provided by Supabase or authorized by Supabase in writing; in each case provided that Customer may not settle any Third-Party Claim against Supabase unless Supabase consents to such settlement, and further provided that Supabase will have the right, at its option, to defend itself against any such Third-Party Claim or to participate in the defense thereof by counsel of its own choice. This indemnification obligation is subject to Customer receiving prompt written notice of such claim (but in any event notice in sufficient time for Customer to respond without prejudice). + +### 11.3 Sole Remedy. + +Section 11.1 sets forth Customer's sole remedies and Supabase's sole liability and obligation for any actual, threatened, or alleged claims that the Services infringe, misappropriate, or otherwise violate any intellectual property rights of any third party. + +## 12. Limitations of Liability. + +Except for (a) a Party's breach of its confidentiality obligations, (b) a Party's indemnity obligations, or (c) a Party's gross negligence, fraud, or willful misconduct ("**Excluded Liabilities**"): (i) in no event will either Party be liable under or in connection with this Agreement under any legal or equitable theory, including breach of contract, tort (including negligence), strict liability, and otherwise, for any: (1) consequential, incidental, indirect, exemplary, special, enhanced, or punitive damages; (2) increased costs, diminution in value or lost business, production, contracts, anticipated savings, revenues, or profits; (3) loss of goodwill or reputation; (4) use, inability to use, loss, interruption, delay or recovery of any data, or breach of data or system security; or (5) cost of replacement goods or services, in each case regardless of whether such Party was advised of the possibility of such losses or damages or such losses or damages were otherwise foreseeable; and (ii) in no event will either Party's aggregate liability arising out of or related to this Agreement under any legal or equitable theory, including breach of contract, tort (including negligence), strict liability, and otherwise exceed the total amounts paid and/or payable to Supabase under this Agreement in the twelve (12) months immediately preceding the events giving rise to the applicable claim; provided that, notwithstanding the foregoing, Supabase's aggregate, cumulative liability arising out of or relating to any Excluded Liabilities will not exceed three times (3x) the total amounts paid and/or payable to Supabase by Customer under this Agreement in the twelve (12) months immediately preceding the events giving rise to the applicable claim. + +## 13. Subscription Period and Termination. + +### 13.1 Subscription Period. + +The initial term of this Agreement begins on the Effective Date and, unless terminated earlier pursuant to Section 13.2, will continue in effect for the period identified in the Order (the "**Initial Subscription Period**"). This Agreement will automatically renew for additional successive terms equal to the length of the Initial Subscription Period unless earlier terminated pursuant to this Agreement's express provisions or either Party gives the other Party written notice of non-renewal at least thirty (30) days prior to the expiration of the then-current term (each a "**Renewal Subscription Period**" and together with the Initial Subscription Period, the "**Subscription Period**"). + +### 13.2 Termination. + +In addition to any other express termination right set forth in this Agreement: + +(a) Supabase may terminate this Agreement, effective on written notice to Customer, if Customer: (i) fails to pay any amount when due hereunder, and such failure continues more than ten (10) calendar days after Supabase's delivery of written notice thereof; or (ii) breaches any of its obligations under Section 2.3 or Section 6; + +(b) either Party may terminate this Agreement, effective on written notice to the other Party, if the other Party materially breaches this Agreement, and such breach: (i) is incapable of cure; or (ii) being capable of cure, remains uncured thirty (30) calendar days after the non-breaching Party provides the breaching Party with written notice of such breach; or + +(c) either Party may terminate this Agreement, effective immediately upon written notice to the other Party, if the other Party: (i) becomes insolvent or is generally unable to pay, or fails to pay, its debts as they become due; (ii) files or has filed against it, a petition for voluntary or involuntary bankruptcy or otherwise becomes subject, voluntarily or involuntarily, to any proceeding under any domestic or foreign bankruptcy or insolvency law; (iii) makes or seeks to make a general assignment for the benefit of its creditors; or (iv) applies for or has appointed a receiver, trustee, custodian, or similar agent appointed by order of any court of competent jurisdiction to take charge of or sell any material portion of its property or business. + +### 13.3 Effect of Expiration or Termination. + +Upon expiration or earlier termination of this Agreement, Customer shall immediately discontinue use of the Supabase IP and, without limiting Customer's obligations under Section 6, Customer shall delete, destroy, or return all copies of the Supabase IP and certify in writing to the Supabase that the Supabase IP has been deleted or destroyed. No expiration or termination will affect Customer's obligation to pay all Fees that may have become due before such expiration or termination or entitle Customer to any refund (except as provided under Section 10.3). + +### 13.4 Survival. + +This Section 13.4 and Sections 1, 5, 6, 9, 10, 11.2, 12, and 14 survive any termination or expiration of this Agreement. No other provisions of this Agreement survive the expiration or earlier termination of this Agreement. + +## 14. Miscellaneous. + +### 14.1 Entire Agreement. + +This Agreement, together with any other documents incorporated herein by reference, constitutes the sole and entire agreement of the Parties with respect to the subject matter of this Agreement and supersedes all prior and contemporaneous understandings, agreements, and representations and warranties, both written and oral, with respect to such subject matter. In the event of any inconsistency between the statements made in the body of this Agreement, the related Exhibits, and any other documents incorporated herein by reference, the following order of precedence governs: (a) first, this Agreement; (b) second, any Order; and (c) any other documents incorporated herein by reference. This Agreement may be executed electronically and in counterparts (such as via DocuSign), which counterparts taken together shall form one legal instrument. Any pre-printed terms in a Customer purchase order or similar document are null and void. + +### 14.2 Notices. + +All notices, requests, consents, claims, demands, waivers, and other communications hereunder (each, a "**Notice**") must be in writing and addressed to the Parties at the addresses set forth on the first page of this Agreement or as identified on the Order (or to such other address that may be designated by the Party giving Notice from time to time in accordance with this Section 14.2). All Notices must be delivered by personal delivery, nationally recognized signed for on delivery courier (with all fees pre-paid), or email (with confirmation of transmission). All email Notices to Supabase must be sent to legal@supabase.io. Except as otherwise provided in this Agreement, a Notice is effective only: (a) upon receipt by the receiving Party; and (b) if the Party giving the Notice has complied with the requirements of this Section 14.2. + +### 14.3 Force Majeure. + +In no event shall either Party be liable to the other Party, or be deemed to have breached this Agreement, for any failure or delay in performing its obligations under this Agreement (except for any obligations to make payments), if and to the extent such failure or delay is caused by any circumstances beyond such Party's reasonable control, including but not limited to acts of God, flood, fire, earthquake, explosion, war, terrorism, invasion, riot or other civil unrest, strikes, labor stoppages or slowdowns or other industrial disturbances, or passage of law or any action taken by a governmental or public authority, including imposing an embargo. + +### 14.4 Amendment and Modification. + +Supabase may modify this Agreement at any time by posting a revised version at https://supabase.com/enterprise-terms, which modification will become effective as of the first day of the calendar month following the month in which it was first posted; provided, however, that if an Order specifies a fixed Subscription Period of twelve (12) months or longer, the modification will instead be effective immediately upon the start of the next Renewal Subscription Period. In either case, if Customer objects to the updated Agreement, as its sole and exclusive remedy, Customer may elect not to renew in accordance with Section 13.1. For the avoidance of doubt, any Order is subject to the version of this Agreement in effect at the time of the Order. Purchase orders (and similar documents) issued by Customer are for administrative purposes only (e.g. setting forth products and services ordered and associated fees) and any additional or different terms or conditions contained in any such order shall not apply (even if the order is accepted or performed on by Supabase). + +### 14.5 Waiver. + +No failure or delay by either Party in exercising any right or remedy available to it in connection with this Agreement will constitute a waiver of such right or remedy. No waiver under this Agreement will be effective unless made in writing and signed by an authorized representative of the Party granting the waiver. + +### 14.6 Severability. + +If any provision of this Agreement is adjudged by any court of competent jurisdiction to be invalid, illegal, or unenforceable in any jurisdiction, such invalidity, illegality, or unenforceability will not affect any other term or provision of this Agreement or invalidate or render unenforceable such term or provision in any other jurisdiction. Upon such determination that any term or other provision is invalid, illegal, or unenforceable, the Parties shall negotiate in good faith to modify this Agreement so as to effect their original intent as closely as possible in a mutually acceptable manner in order that the transactions contemplated hereby be consummated as originally contemplated to the greatest extent possible. + +### 14.7 Governing Law; Submission to Jurisdiction; Dispute Resolution. + +This Agreement is governed by and construed in accordance with the internal laws of the State of California without giving effect to any choice or conflict of law provision or rule that would require or permit the application of the laws of any jurisdiction other than those of the State of California. All disputes arising out of or in connection with this Agreement between the Parties shall be finally settled under the Rules of Arbitration of the International Chamber of Commerce by one or more arbitrators appointed in accordance with such Rules of Arbitration, subject to the terms of this Section 14.7. The place of arbitration shall be: (a) Singapore to the extent that Customer is located in Asia; (b) London, United Kingdom to the extent that Customer is located in Europe; or (c) San Francisco County, California to the extent that Customer is located in the United States or any other jurisdiction. The language of the arbitration shall be English. Nothing in this Section 14.7 will be deemed as preventing Supabase from seeking injunctive or other equitable relief from the courts as necessary to prevent the actual or threatened infringement, misappropriation, or violation of Supabase's data security, confidential information, or intellectual property rights. Customer agrees to submit to the exclusive personal jurisdiction of the federal and state courts located in California for any actions for which Supabase retains the right to seek injunctive or other equitable relief in a court of competent jurisdiction to prevent the actual or threatened infringement, misappropriation, or violation of data security, Confidential Information, or intellectual property rights, including any provisional relief required to prevent irreparable harm. + +### 14.8 Assignment. + +Customer may not assign any of its rights or delegate any of its obligations hereunder, in each case whether voluntarily, involuntarily, by operation of law or otherwise, without the prior written consent of Supabase. Any purported assignment or delegation in violation of this Section 14.8 will be null and void. No assignment or delegation will relieve the assigning or delegating Party of any of its obligations hereunder. This Agreement is binding upon and inures to the benefit of the Parties and their respective permitted successors and assigns. + +### 14.9 Export Regulation. + +The Services utilize software and technology that may be subject to US export control laws, including the US Export Administration Act and its associated regulations. Each Party shall comply with all applicable export and re-export control and trade and economic sanctions laws. Customer shall not, directly or indirectly, export, re-export, or release the Services or the underlying software or technology to, or make the Services or the underlying software or technology accessible from, any jurisdiction or country to which export, re-export, or release is prohibited by law, rule, or regulation. Customer shall comply with all applicable federal laws, regulations, and rules, and complete all required undertakings (including obtaining any necessary export license or other governmental approval), prior to exporting, re-exporting, releasing, or otherwise making the Services or the underlying software or technology available outside the US. Neither Party, nor any of its subsidiaries or any person acting on its behalf or owning 50% or more of its equity securities or other equivalent voting interests, is (a) a person on the List of Specially Designated Nationals and Blocked Persons or any other list of sanctioned persons administered by OFAC or any other governmental entity, or (b) a national or resident of, or a segment of the government of, any country or territory for which the United States has embargoed goods or imposed trade sanctions. + +### 14.10 US Government Rights. + +Each of the Documentation and the software components that constitute the Services is a "commercial item" as that term is defined at 48 C.F.R. § 2.101, consisting of "commercial computer software" and "commercial computer software documentation" as such terms are used in 48 C.F.R. § 12.212. Accordingly, if Customer is an agency of the US Government or any contractor therefor, Customer only receives those rights with respect to the Services and Documentation as are granted to all other end users, in accordance with (a) 48 C.F.R. § 227.7201 through 48 C.F.R. § 227.7204, with respect to the Department of Defense and their contractors, or (b) 48 C.F.R. § 12.212, with respect to all other US Government users and their contractors. + +### 14.11 Equitable Relief. + +Each Party acknowledges and agrees that a breach or threatened breach by such Party of any of its obligations under Section 6 or, in the case of Customer, Section 2.3, would cause the other Party irreparable harm for which monetary damages would not be an adequate remedy and agrees that, in the event of such breach or threatened breach, the other Party will be entitled to equitable relief, including a restraining order, an injunction, specific performance and any other relief that may be available from any court, without any requirement to post a bond or other security, or to prove actual damages or that monetary damages are not an adequate remedy. Such remedies are not exclusive and are in addition to all other remedies that may be available at law, in equity or otherwise. + +### 14.12 Publicity. + +Supabase may identify Customer as a user of the Services and may use Customer's name, logo, and other trademarks in Supabase's customer list, press releases, blog posts, advertisements, and website (and all use thereof and goodwill arising therefrom shall inure to the sole and exclusive benefit of Customer). Otherwise, neither Party may use the name, logo, or other trademarks of the other Party for any purpose without the other Party's prior written approval. Customer may opt out of the foregoing publicity rights at any time by providing written notice to Supabase at legal@supabase.io, and Supabase will cease any such use within a commercially reasonable period. + +### 14.13 Subcontractors. + +Supabase may use the services of subcontractors for performance of services under this Agreement, provided that Supabase remains responsible for such subcontractors' compliance with the terms of this Agreement. + +### 14.14 Independent Contractors. + +The Parties to this Agreement are independent contractors. There is no relationship of partnership, joint venture, employment, franchise or agency created hereby between the Parties. Neither Party will have the power to bind the other or incur obligations on the other Party's behalf without the other Party's prior written consent. + +### 14.15 No Third Party Rights. + +There are no third-party beneficiaries to this Agreement. diff --git a/apps/www/pages/enterprise-terms.tsx b/apps/www/pages/enterprise-terms.tsx index fdbfe1e513798..be4507aeef083 100644 --- a/apps/www/pages/enterprise-terms.tsx +++ b/apps/www/pages/enterprise-terms.tsx @@ -4,6 +4,7 @@ import SectionContainer from '~/components/Layouts/SectionContainer' import LegalDocVersions, { type LegalDocVersion } from '~/components/Legal/LegalDocVersions' import V1 from '~/data/legal/enterprise-terms/v1.mdx' import V2 from '~/data/legal/enterprise-terms/v2.mdx' +import V3 from '~/data/legal/enterprise-terms/v3.mdx' import mdxComponents from '~/lib/mdx/mdxComponents' import { NextSeo } from 'next-seo' @@ -15,6 +16,7 @@ const meta = { } const versions: LegalDocVersion[] = [ + { id: 'v3', label: 'Version 3', effectiveDate: 'August 1, 2026', Component: V3 }, { id: 'v2', label: 'Version 2', effectiveDate: 'May 6, 2026', Component: V2 }, { id: 'v1', label: 'Version 1', effectiveDate: 'April 17, 2026', Component: V1 }, ] From 76a9ba968c9145d85d6c1b4f643df61719a01847 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <209825114+claude[bot]@users.noreply.github.com> Date: Thu, 30 Jul 2026 14:05:46 +0200 Subject: [PATCH 04/12] refactor(www): unify legal page shells and versioning (#48483) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit _Requested by **Francesco Sansalvadore, Nicole Kramer** · [Slack thread](https://supabase.slack.com/archives/C0161K73J1J/p1785399057853249?thread_ts=1785399057.853249&cid=C0161K73J1J)_ ## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES ## What kind of change does this PR introduce? Refactor of the marketing site's legal pages, plus two small content fixes (removal of duplicated dates, two heading corrections) and two permanent redirects. ## What is the current behavior? The documents linked from the Legal Hub are built three different ways: - `/terms` and `/enterprise-terms` render a plain inline heading with no breadcrumbs. - `/sla`, `/support-policy`, `/aup` and `/privacy` are standalone MDX pages carrying their own layout. - `/legal/dpa` has a one-off centered heading and grid of its own. On top of that, the documents that already have a version selector *also* print a "Last Modified" line inside the document body, so the same fact is stated twice on the page. On `/terms` and `/enterprise-terms` the two statements disagree: the selector says "Version 2 — May 6, 2026" while the body says "Last Modified: 1 May 2026". `/privacy` handles its history differently again — earlier versions live at their own archived URLs (`/privacy-260316` and `/privacy-250528`), strung together by "Previous Version" links at the bottom of each page. ## What is the new behavior? Every legal page now renders through one shell: `PageHeader` with a `PageBreadcrumb`, so the Legal Hub is one click away from any document. - The duplicate "Last Modified" rows are removed from the five versioned documents. The version selector is now the single place a date appears. - `/aup` and `/privacy` gain the version selector. - `/privacy`'s three historical versions are now selectable from the one page, and the two old archived URLs permanently redirect to it. - `/sla` and `/support-policy` pick up the shell and breadcrumbs but intentionally show neither a date nor a selector — neither document has ever carried one, and Legal asked that the SLA stay that way for now. Implementation-wise the canonical pattern is the one the Data Processing Addendum page was already using: `DefaultLayout` > `NextSeo` > `PageHeader` (with a `breadcrumb` slot) > `MDXProvider` > `SectionContainer className="prose"` > `LegalDocVersions`. The standalone MDX pages were moved to `apps/www/data/legal//vN.mdx` as bare content partials, with a new TSX shell taking over the original route. No route changed except the two archived privacy pages, which redirect. Dates were carried across from the "Last Modified" lines being deleted rather than invented: `/aup` becomes Version 1 — June 1, 2026, and privacy v1/v2/v3 become May 28 2025, March 16 2026 and May 13 2026. ## Additional context **This is a stacked PR.** It is sequenced behind three PRs that touch the same files and should land first: the Terms of Service v3 bump, the Enterprise SaaS Subscription Agreement v3 bump, and #48481 (DPA effective date → August 1, 2026). #48481 edits the very "Last Modified" line this PR removes from the DPA content file, so a trivial conflict there is expected. This branch will be rebased onto master before it leaves draft. **Two contracts now contain a clause that no longer describes the page.** `apps/www/data/legal/terms/v1.mdx` and `v2.mdx` — and the same sentence in the MPPA and both integration-partner addenda — still read "The date on which the Agreement was last modified will be updated at the top of this Agreement". There is no longer a date in the document body; it sits in the version selector above it. Left untouched here because it is contract text, but Legal should re-word it. **The date mismatch is resolved in favour of the selector.** On `/terms` and `/enterprise-terms`, deleting the body line leaves May 6, 2026 as the only date on the page. Nicole Kramer confirmed in Slack that May 6 is the correct date. **Two headings change visibly**, to line up with the labels used on the Legal Hub: "Terms of service" → "Terms of Service", and "Service Level Agreements" → "Service Level Agreement". **`/legal/dpa` now looks almost identical to `/legal/customer-resources/data-processing-addendum`** — same heading, same breadcrumb, different content. The legacy page is a PDF download plus a signing flow and was deliberately left live, but the overlap is more obvious than it was. Redirecting it to the versioned page is the natural follow-up; it is not done here. **Build verification was incomplete in this environment.** `pnpm install` could not finish because `npm.jsr.io` is blocked by network policy (403), so `next build` never gave a real signal. What did run and pass: - `tsc --noEmit` on `apps/www`, with output byte-identical to clean master - ESLint on every changed file — 0 errors - Prettier using the repo's actual config - a direct MDX compile of all 14 `data/legal/**/*.mdx` files using the app's own MDX options The one thing left unverified is webpack resolving `ui-patterns/PrivacySettings` from the privacy content's new directory. CI will confirm that. Co-authored-by: Claude --- .../{pages/aup.mdx => data/legal/aup/v1.mdx} | 18 --- .../data-processing-addendum/v1.mdx | 2 - apps/www/data/legal/enterprise-terms/v1.mdx | 2 - apps/www/data/legal/enterprise-terms/v2.mdx | 2 - apps/www/data/legal/enterprise-terms/v3.mdx | 2 - .../legal/privacy/v1.mdx} | 19 ---- .../legal/privacy/v2.mdx} | 19 ---- .../privacy.mdx => data/legal/privacy/v3.mdx} | 20 ---- .../{pages/sla.mdx => data/legal/sla/v1.mdx} | 16 --- .../legal/support-policy/v1.mdx} | 16 --- apps/www/data/legal/terms/v1.mdx | 2 - apps/www/data/legal/terms/v2.mdx | 2 - apps/www/data/legal/terms/v3.mdx | 2 - apps/www/lib/redirects.js | 10 ++ apps/www/pages/aup.tsx | 35 ++++++ apps/www/pages/enterprise-terms.tsx | 15 ++- apps/www/pages/legal/dpa.tsx | 107 ++++++++++-------- apps/www/pages/privacy.tsx | 39 +++++++ apps/www/pages/sla.tsx | 37 ++++++ apps/www/pages/support-policy.tsx | 37 ++++++ apps/www/pages/terms.tsx | 22 +++- 21 files changed, 242 insertions(+), 182 deletions(-) rename apps/www/{pages/aup.mdx => data/legal/aup/v1.mdx} (93%) rename apps/www/{pages/privacy-250528.mdx => data/legal/privacy/v1.mdx} (99%) rename apps/www/{pages/privacy-260316.mdx => data/legal/privacy/v2.mdx} (99%) rename apps/www/{pages/privacy.mdx => data/legal/privacy/v3.mdx} (99%) rename apps/www/{pages/sla.mdx => data/legal/sla/v1.mdx} (97%) rename apps/www/{pages/support-policy.mdx => data/legal/support-policy/v1.mdx} (92%) create mode 100644 apps/www/pages/aup.tsx create mode 100644 apps/www/pages/privacy.tsx create mode 100644 apps/www/pages/sla.tsx create mode 100644 apps/www/pages/support-policy.tsx diff --git a/apps/www/pages/aup.mdx b/apps/www/data/legal/aup/v1.mdx similarity index 93% rename from apps/www/pages/aup.mdx rename to apps/www/data/legal/aup/v1.mdx index 22a8f22d7f26e..3413a578dfe7a 100644 --- a/apps/www/pages/aup.mdx +++ b/apps/www/data/legal/aup/v1.mdx @@ -1,17 +1,3 @@ -import Layout from '../layouts/Layout' -import SectionContainer from '../components/Layouts/SectionContainer' - -export const meta = { - title: 'Acceptable Use Policy | Supabase', - description: 'Supabase Acceptable Use Policy', -} - - - -# Acceptable Use Policy - -_Last Modified: 1 June 2026_ - This Acceptable Use Policy (this "Policy") describes prohibited uses of the web services offered by Supabase, Inc. and its affiliates (the "Services") and the website located at https://supabase.com (the "Supabase Site"). By using the Services or accessing the Supabase Site, you agree to the latest version of this Policy. Violation of this Policy may result in the immediate suspension or termination of your Accounts and / or Services. @@ -61,7 +47,3 @@ By using the Services or accessing the Supabase Site, you agree to the latest ve ## 7. Reporting Violations Report violations to legal@supabase.io or abuse@supabase.io - - - -export default (context) => diff --git a/apps/www/data/legal/customer-resources/data-processing-addendum/v1.mdx b/apps/www/data/legal/customer-resources/data-processing-addendum/v1.mdx index a62a4bbb4dda4..70d330bc66abe 100644 --- a/apps/www/data/legal/customer-resources/data-processing-addendum/v1.mdx +++ b/apps/www/data/legal/customer-resources/data-processing-addendum/v1.mdx @@ -1,5 +1,3 @@ -_Last Modified: 1 August 2026_ - This Data Processing Addendum (the “**DPA**”) supplements and forms part of the Supabase Terms of Service available at [https://supabase.com/terms](https://supabase.com/terms), or such other agreement entered into between the Customer and Supabase Pte. Ltd (“**Supabase**”) relevant to Customer’s use of the Services (the “**Agreement**”), and in case of any conflict, supersedes the Agreement in relation to the transfer and processing of Covered Data in connection with the performance of the Services. This DPA is effective as of the Effective Date of the Agreement. ## 1. Definitions. diff --git a/apps/www/data/legal/enterprise-terms/v1.mdx b/apps/www/data/legal/enterprise-terms/v1.mdx index fdc28888efcf4..96a74df65844a 100644 --- a/apps/www/data/legal/enterprise-terms/v1.mdx +++ b/apps/www/data/legal/enterprise-terms/v1.mdx @@ -1,5 +1,3 @@ -_Last Modified: 17 April 2026_ - This Enterprise SaaS Subscription Agreement (this "**Agreement**") is entered into by and between the customer identified in the signature to the Order which references these terms ("**Customer**") and the Supabase Affiliate entity identified in such Order ("**Supabase**") (Customer and Supabase each, a "**Party**" and collectively, the "**Parties**"), and is effective as of the Services Start Date identified in such Order ("**Effective Date**"), and sets forth the terms and conditions under which Customer may subscribe to certain products and services of Supabase as set forth in one or more Orders (defined below). ## 1. Definitions. diff --git a/apps/www/data/legal/enterprise-terms/v2.mdx b/apps/www/data/legal/enterprise-terms/v2.mdx index b4824d2ae4498..b12c8af21048d 100644 --- a/apps/www/data/legal/enterprise-terms/v2.mdx +++ b/apps/www/data/legal/enterprise-terms/v2.mdx @@ -1,5 +1,3 @@ -_Last Modified: 1 May 2026_ - This Enterprise SaaS Subscription Agreement (this "**Agreement**") is entered into by and between the customer identified in the signature block below ("**Customer**") and Supabase, Pte. Ltd., as subsidiary of Supabase, Inc., a Delaware corporation ("**Supabase**") (Customer and Supabase each, a "**Party**" and collectively, the "**Parties**"), effective as of [Deal.CloseDate] ("**Effective Date**"), and sets forth the terms and conditions under which Customer may subscribe to certain products and services of Supabase as set forth in one or more Orders (defined below). **Accepted and agreed to as of the Effective Date by the authorized representative of each Party by Customer's entering into an Order referencing this Agreement.** diff --git a/apps/www/data/legal/enterprise-terms/v3.mdx b/apps/www/data/legal/enterprise-terms/v3.mdx index c156a7e28cb13..538c559648cb6 100644 --- a/apps/www/data/legal/enterprise-terms/v3.mdx +++ b/apps/www/data/legal/enterprise-terms/v3.mdx @@ -1,5 +1,3 @@ -_Last Modified: 1 August 2026_ - This Enterprise SaaS Subscription Agreement (this "**Agreement**") is entered into by and between the customer identified in the signature block in an Order ("**Customer**") and Supabase, Pte. Ltd., as subsidiary of Supabase, Inc., a Delaware corporation ("**Supabase**") (Customer and Supabase each, a "**Party**" and collectively, the "**Parties**"), effective as of the date of last signature of an Order referencing these terms ("**Effective Date**"), and sets forth the terms and conditions under which Customer may subscribe to certain products and services of Supabase as set forth in one or more Orders (defined below). **Accepted and agreed to as of the Effective Date by the authorized representative of each Party by Customer's entering into an Order referencing this Agreement.** diff --git a/apps/www/pages/privacy-250528.mdx b/apps/www/data/legal/privacy/v1.mdx similarity index 99% rename from apps/www/pages/privacy-250528.mdx rename to apps/www/data/legal/privacy/v1.mdx index fca8be6f97c4a..62f973893f771 100644 --- a/apps/www/pages/privacy-250528.mdx +++ b/apps/www/data/legal/privacy/v1.mdx @@ -1,20 +1,5 @@ -import Layout from '../layouts/Layout' -import SectionContainer from '../components/Layouts/SectionContainer' import { PrivacySettings } from 'ui-patterns/PrivacySettings' -export const meta = { - title: 'Privacy Policy | Supabase', - description: 'Supabase Privacy Policy', -} - - - -# Privacy Policy - -_Last Modified: 28 May 2025_ - -Previous Version: [14 March 2025](/privacy-250314) - Thank you for your interest in Supabase, Inc., ("**_Supabase_**," "**_we_**", "**_our_**" or "**_us_**"). Supabase provides a suite of open source tools, stitched together to build a seamless developer experience. This Privacy Notice explains how information about you, that directly identifies you, or that makes you identifiable ("**_personal information_**") is collected, used and disclosed by Supabase in connection with our website at [supabase.com](https://supabase.com) (the "**_Site_**") and our services offered in connection with the Site (collectively with the Site, the "**_Service_**"). ## What Does This Privacy Notice Apply To? @@ -343,7 +328,3 @@ Most browsers also allow you to change your cookie settings to block certain coo If you would like to find out more about cookies and other similar technologies, please visit [allaboutcookies.org](http://www.allaboutcookies.org). Please note that deleting or blocking cookies may not be effective for all types of tracking technologies, such as Local Storage Objects (LSOs) like HTML5. - - - -export default (context) => diff --git a/apps/www/pages/privacy-260316.mdx b/apps/www/data/legal/privacy/v2.mdx similarity index 99% rename from apps/www/pages/privacy-260316.mdx rename to apps/www/data/legal/privacy/v2.mdx index e74d25cde711f..a4f433b0293a0 100644 --- a/apps/www/pages/privacy-260316.mdx +++ b/apps/www/data/legal/privacy/v2.mdx @@ -1,20 +1,5 @@ -import Layout from '../layouts/Layout' -import SectionContainer from '../components/Layouts/SectionContainer' import { PrivacySettings } from 'ui-patterns/PrivacySettings' -export const meta = { - title: 'Privacy Policy | Supabase', - description: 'Supabase Privacy Policy', -} - - - -# Privacy Policy - -_Last Modified: 16 March 2026_ - -Previous Version: [28 May 2025](/privacy-250528) - Thank you for your interest in Supabase, Inc., ("**_Supabase_**," "**_we_**", "**_our_**" or "**_us_**"). Supabase provides a suite of open source tools, stitched together to build a seamless developer experience. This Privacy Notice explains how information about you, that directly identifies you, or that makes you identifiable ("**_personal information_**") is collected, used and disclosed by Supabase in connection with our website at [supabase.com](https://supabase.com) (the "**_Site_**") and our services offered in connection with the Site (collectively with the Site, the "**_Service_**"). ## What Does This Privacy Notice Apply To? @@ -346,7 +331,3 @@ Most browsers also allow you to change your cookie settings to block certain coo If you would like to find out more about cookies and other similar technologies, please visit [allaboutcookies.org](http://www.allaboutcookies.org). Please note that deleting or blocking cookies may not be effective for all types of tracking technologies, such as Local Storage Objects (LSOs) like HTML5. - - - -export default (context) => diff --git a/apps/www/pages/privacy.mdx b/apps/www/data/legal/privacy/v3.mdx similarity index 99% rename from apps/www/pages/privacy.mdx rename to apps/www/data/legal/privacy/v3.mdx index a462e70b58c5e..6e4fcc79f8d9d 100644 --- a/apps/www/pages/privacy.mdx +++ b/apps/www/data/legal/privacy/v3.mdx @@ -1,21 +1,5 @@ import { PrivacySettings } from 'ui-patterns/PrivacySettings' -import SectionContainer from '../components/Layouts/SectionContainer' -import Layout from '../layouts/Layout' - -export const meta = { - title: 'Privacy Policy | Supabase', - description: 'Supabase Privacy Policy', -} - - - -# Privacy Policy - -_Last Modified: 13 May 2026_ - -Previous Version: [16 March 2026](/privacy-260316) - Thank you for your interest in Supabase, Inc., ("**_Supabase_**," "**_we_**", "**_our_**" or "**_us_**"). Supabase provides a suite of open source tools, stitched together to build a seamless developer experience. This Privacy Notice explains how information about you, that directly identifies you, or that makes you identifiable ("**_personal information_**") is collected, used and disclosed by Supabase in connection with our website at [supabase.com](https://supabase.com) (the "**_Site_**") and our services offered in connection with the Site (collectively with the Site, the "**_Service_**"). ## What Does This Privacy Notice Apply To? @@ -349,7 +333,3 @@ Most browsers also allow you to change your cookie settings to block certain coo If you would like to find out more about cookies and other similar technologies, please visit [allaboutcookies.org](http://www.allaboutcookies.org). Please note that deleting or blocking cookies may not be effective for all types of tracking technologies, such as Local Storage Objects (LSOs) like HTML5. - - - -export default (context) => diff --git a/apps/www/pages/sla.mdx b/apps/www/data/legal/sla/v1.mdx similarity index 97% rename from apps/www/pages/sla.mdx rename to apps/www/data/legal/sla/v1.mdx index e69876d16ce0b..7a1cbb0105851 100644 --- a/apps/www/pages/sla.mdx +++ b/apps/www/data/legal/sla/v1.mdx @@ -1,15 +1,3 @@ -import Layout from '../layouts/Layout' -import SectionContainer from '../components/Layouts/SectionContainer' - -export const meta = { - title: 'Service Level Agreement | Supabase', - description: 'Supabase Service Level Agreement', -} - - - -# Service Level Agreements - ## Enterprise Platform Uptime SLA The following Service Level Agreement, which is incorporated into and forms part of the Subscription Agreement between Supabase, Inc. ("Supabase") and Customer (the "Agreement"), will apply to the Services for Enterprise Customers specified in an Order Form during the applicable Subscription Term. @@ -370,7 +358,3 @@ An Information request about Supabase or feature request. | 4. Low | 2 business days
Monday - Friday | 2 business days
Monday - Friday | 24 hours
24/7 x 365 | Business hours are 6am to 6pm local time unless stated otherwise. - -
- -export default (context) => diff --git a/apps/www/pages/support-policy.mdx b/apps/www/data/legal/support-policy/v1.mdx similarity index 92% rename from apps/www/pages/support-policy.mdx rename to apps/www/data/legal/support-policy/v1.mdx index 9decc3cba6a9d..95a71a9cdfe76 100644 --- a/apps/www/pages/support-policy.mdx +++ b/apps/www/data/legal/support-policy/v1.mdx @@ -1,15 +1,3 @@ -import SectionContainer from '../components/Layouts/SectionContainer' -import Layout from '../layouts/Layout' - -export const meta = { - title: 'Support Policy', - description: 'Supabase Support Policy', -} - - - -# Support Policy - Supabase is dedicated to providing an exceptional customer experience. As a crucial aspect of this commitment, we offer limited technical support for all paid projects running on our hosted Supabase platform. Technical support is confined to the scope, hours, contacts, and channels below. @@ -77,7 +65,3 @@ In the event of a platform issue, a notice will be posted on our platform status Please contact us to find out about our Premium Support options available for Team Plan and Enterprise customers using the form below: [https://forms.supabase.com/enterprise](https://forms.supabase.com/enterprise) - - - -export default (context) => diff --git a/apps/www/data/legal/terms/v1.mdx b/apps/www/data/legal/terms/v1.mdx index 328f7cbdd4987..8205b0cd15f41 100644 --- a/apps/www/data/legal/terms/v1.mdx +++ b/apps/www/data/legal/terms/v1.mdx @@ -1,5 +1,3 @@ -_Last Modified: 11 July 2025_ - These Terms of Service (this "**Agreement**") are a binding contract between you ("**Customer**," "**you**," or "**your**") and Supabase, Inc., a Delaware corporation with offices located at 65 Chulia Street #38-02/03, OCBC Centre, Singapore 049513 ("**Supabase**," "**we**," or "**us**"). This Agreement governs your access to and use of the Cloud Services. Supabase and Customer may be referred to herein collectively as the "**Parties**" or individually as a "**Party**." ## Agreement Acceptance diff --git a/apps/www/data/legal/terms/v2.mdx b/apps/www/data/legal/terms/v2.mdx index a790bafb29d5f..954a97df5ed9b 100644 --- a/apps/www/data/legal/terms/v2.mdx +++ b/apps/www/data/legal/terms/v2.mdx @@ -1,5 +1,3 @@ -_Last Modified: 1 May 2026_ - These Terms of Service (this "**Agreement**") are a binding contract between you ("**Customer**," "**you**," or "**your**") and SUPABASE PTE. LTD., a Singapore entity with a registered address of 65 Chulia Street #38-02/03, OCBC Centre, Singapore 049513 ("**Supabase**," "**we**," or "**us**"). This Agreement governs your access to and use of the Cloud Services. Supabase and Customer may be referred to herein collectively as the "**Parties**" or individually as a "**Party**." THIS AGREEMENT TAKES EFFECT WHEN YOU CLICK THE "I ACCEPT" BUTTON BELOW OR BY ACCESSING OR USING THE SERVICES (the "**Effective Date**"). BY CLICKING ON THE "I ACCEPT" BUTTON BELOW OR BY ACCESSING OR USING THE SERVICES YOU (A) ACKNOWLEDGE THAT YOU HAVE READ AND UNDERSTAND THIS AGREEMENT; (B) REPRESENT AND WARRANT THAT YOU HAVE THE RIGHT, POWER, AND AUTHORITY TO ENTER INTO THIS AGREEMENT AND, IF ENTERING INTO THIS AGREEMENT FOR AN ORGANIZATION, THAT YOU HAVE THE LEGAL AUTHORITY TO BIND THAT ORGANIZATION; AND (C) ACCEPT THIS AGREEMENT AND AGREE THAT YOU ARE LEGALLY BOUND BY ITS TERMS. diff --git a/apps/www/data/legal/terms/v3.mdx b/apps/www/data/legal/terms/v3.mdx index 6ac34f24b226e..a5faf26fa3952 100644 --- a/apps/www/data/legal/terms/v3.mdx +++ b/apps/www/data/legal/terms/v3.mdx @@ -1,5 +1,3 @@ -_Last Modified: 1 August 2026_ - These Terms of Service (this "Agreement") are a binding contract between you ("Customer," "you," or "your") and SUPABASE PTE. LTD., a Singapore entity with a registered address of 65 Chulia Street #38-02/03, OCBC Centre, Singapore 049513 ("Supabase," "we," or "us"). This Agreement governs your access to and use of the Cloud Services, except to the extent that Customer has entered into an Order or separate agreement with Supabase that expressly incorporates different terms, in which case those other terms will govern. Supabase and Customer may be referred to herein collectively as the "Parties" or individually as a "Party." THIS AGREEMENT TAKES EFFECT WHEN YOU CLICK THE "I ACCEPT" BUTTON BELOW OR BY ACCESSING OR USING THE SERVICES (the "Effective Date"). BY CLICKING ON THE "I ACCEPT" BUTTON BELOW OR BY ACCESSING OR USING THE SERVICES YOU (A) ACKNOWLEDGE THAT YOU HAVE READ AND UNDERSTAND THIS AGREEMENT; (B) REPRESENT AND WARRANT THAT YOU HAVE THE RIGHT, POWER, AND AUTHORITY TO ENTER INTO THIS AGREEMENT AND, IF ENTERING INTO THIS AGREEMENT FOR AN ORGANIZATION, THAT YOU HAVE THE LEGAL AUTHORITY TO BIND THAT ORGANIZATION; AND (C) ACCEPT THIS AGREEMENT AND AGREE THAT YOU ARE LEGALLY BOUND BY ITS TERMS. diff --git a/apps/www/lib/redirects.js b/apps/www/lib/redirects.js index b4e6ba6618a54..ccff21267ae50 100644 --- a/apps/www/lib/redirects.js +++ b/apps/www/lib/redirects.js @@ -1732,6 +1732,16 @@ module.exports = [ source: '/docs/company/privacy', destination: '/privacy', }, + { + permanent: true, + source: '/privacy-260316', + destination: '/privacy?version=v2', + }, + { + permanent: true, + source: '/privacy-250528', + destination: '/privacy?version=v1', + }, { permanent: true, source: '/docs/company/sla', diff --git a/apps/www/pages/aup.tsx b/apps/www/pages/aup.tsx new file mode 100644 index 0000000000000..2c779f304376f --- /dev/null +++ b/apps/www/pages/aup.tsx @@ -0,0 +1,35 @@ +import { MDXProvider } from '@mdx-js/react' +import DefaultLayout from '~/components/Layouts/Default' +import SectionContainer from '~/components/Layouts/SectionContainer' +import LegalDocVersions, { type LegalDocVersion } from '~/components/Legal/LegalDocVersions' +import PageBreadcrumb from '~/components/Sections/PageBreadcrumb' +import PageHeader from '~/components/Sections/PageHeader' +import V1 from '~/data/legal/aup/v1.mdx' +import mdxComponents from '~/lib/mdx/mdxComponents' +import { NextSeo } from 'next-seo' + +const meta = { + title: 'Acceptable Use Policy | Supabase', + description: 'Supabase Acceptable Use Policy', +} + +const versions: LegalDocVersion[] = [ + { id: 'v1', label: 'Version 1', effectiveDate: 'June 1, 2026', Component: V1 }, +] + +export default function AcceptableUsePolicyPage() { + return ( + + + } + h1="Acceptable Use Policy" + /> + + + + + + + ) +} diff --git a/apps/www/pages/enterprise-terms.tsx b/apps/www/pages/enterprise-terms.tsx index be4507aeef083..9dff0a4d440d5 100644 --- a/apps/www/pages/enterprise-terms.tsx +++ b/apps/www/pages/enterprise-terms.tsx @@ -2,6 +2,8 @@ import { MDXProvider } from '@mdx-js/react' import DefaultLayout from '~/components/Layouts/Default' import SectionContainer from '~/components/Layouts/SectionContainer' import LegalDocVersions, { type LegalDocVersion } from '~/components/Legal/LegalDocVersions' +import PageBreadcrumb from '~/components/Sections/PageBreadcrumb' +import PageHeader from '~/components/Sections/PageHeader' import V1 from '~/data/legal/enterprise-terms/v1.mdx' import V2 from '~/data/legal/enterprise-terms/v2.mdx' import V3 from '~/data/legal/enterprise-terms/v3.mdx' @@ -25,13 +27,14 @@ export default function EnterpriseTermsPage() { return ( + } + h1="Enterprise SaaS Subscription Agreement" + /> -
- -

Enterprise SaaS Subscription Agreement

- -
-
+ + +
) diff --git a/apps/www/pages/legal/dpa.tsx b/apps/www/pages/legal/dpa.tsx index 1d2506851e020..51458b76b4cc3 100644 --- a/apps/www/pages/legal/dpa.tsx +++ b/apps/www/pages/legal/dpa.tsx @@ -1,60 +1,71 @@ -import Layout from '~/components/Layouts/Default' +import DefaultLayout from '~/components/Layouts/Default' import SectionContainer from '~/components/Layouts/SectionContainer' +import PageBreadcrumb from '~/components/Sections/PageBreadcrumb' +import PageHeader from '~/components/Sections/PageHeader' import { useSendTelemetryEvent } from '~/lib/telemetry' import CTABanner from 'components/CTABanner/index' +import { NextSeo } from 'next-seo' + +const meta = { + title: 'Data Processing Addendum', + description: 'Supabase Data Processing Addendum', +} const DPA = () => { const sendTelemetryEvent = useSendTelemetryEvent() return ( - <> - - -
-
-
-

DPA

-

- We have a long-standing commitment to customer privacy and data protection. As - part of this commitment, we have prepared a Data Processing Addendum ("DPA"). You - can review a static PDF version of our latest DPA document{' '} - - sendTelemetryEvent({ - action: 'dpa_pdf_opened', - properties: { source: 'www' }, - }) - } - > - here - - . -

+ + + + } + h1="Data Processing Addendum" + /> + +

+ We have a long-standing commitment to customer privacy and data protection. As part of + this commitment, we have prepared a Data Processing Addendum ("DPA"). You can review a + static PDF version of our latest DPA document{' '} + + sendTelemetryEvent({ + action: 'dpa_pdf_opened', + properties: { source: 'www' }, + }) + } + > + here + + . +

-

- To make the DPA legally binding, you need to sign and complete the details through - a PandaDoc document that we prepare. To get this version of the DPA,{' '} - - request it from the legal documents page - {' '} - of your Supabase dashboard. -

-
-
-
-
- -
- +

+ To make the DPA legally binding, you need to sign and complete the details through a + PandaDoc document that we prepare. To get this version of the DPA,{' '} + + request it from the legal documents page + {' '} + of your Supabase dashboard. +

+ + + ) } export default DPA diff --git a/apps/www/pages/privacy.tsx b/apps/www/pages/privacy.tsx new file mode 100644 index 0000000000000..11940a8c612c2 --- /dev/null +++ b/apps/www/pages/privacy.tsx @@ -0,0 +1,39 @@ +import { MDXProvider } from '@mdx-js/react' +import DefaultLayout from '~/components/Layouts/Default' +import SectionContainer from '~/components/Layouts/SectionContainer' +import LegalDocVersions, { type LegalDocVersion } from '~/components/Legal/LegalDocVersions' +import PageBreadcrumb from '~/components/Sections/PageBreadcrumb' +import PageHeader from '~/components/Sections/PageHeader' +import V1 from '~/data/legal/privacy/v1.mdx' +import V2 from '~/data/legal/privacy/v2.mdx' +import V3 from '~/data/legal/privacy/v3.mdx' +import mdxComponents from '~/lib/mdx/mdxComponents' +import { NextSeo } from 'next-seo' + +const meta = { + title: 'Privacy Policy | Supabase', + description: 'Supabase Privacy Policy', +} + +const versions: LegalDocVersion[] = [ + { id: 'v3', label: 'Version 3', effectiveDate: 'May 13, 2026', Component: V3 }, + { id: 'v2', label: 'Version 2', effectiveDate: 'March 16, 2026', Component: V2 }, + { id: 'v1', label: 'Version 1', effectiveDate: 'May 28, 2025', Component: V1 }, +] + +export default function PrivacyPolicyPage() { + return ( + + + } + h1="Privacy Policy" + /> + + + + + + + ) +} diff --git a/apps/www/pages/sla.tsx b/apps/www/pages/sla.tsx new file mode 100644 index 0000000000000..c1fe411c717f4 --- /dev/null +++ b/apps/www/pages/sla.tsx @@ -0,0 +1,37 @@ +import { MDXProvider } from '@mdx-js/react' +import DefaultLayout from '~/components/Layouts/Default' +import SectionContainer from '~/components/Layouts/SectionContainer' +import PageBreadcrumb from '~/components/Sections/PageBreadcrumb' +import PageHeader from '~/components/Sections/PageHeader' +import Content from '~/data/legal/sla/v1.mdx' +import mdxComponents from '~/lib/mdx/mdxComponents' +import { NextSeo } from 'next-seo' + +const meta = { + title: 'Service Level Agreement | Supabase', + description: 'Supabase Service Level Agreement', +} + +export default function SLAPage() { + return ( + + + + } + h1="Service Level Agreement" + /> + + + + + + + ) +} diff --git a/apps/www/pages/support-policy.tsx b/apps/www/pages/support-policy.tsx new file mode 100644 index 0000000000000..7528e1f5b6f6b --- /dev/null +++ b/apps/www/pages/support-policy.tsx @@ -0,0 +1,37 @@ +import { MDXProvider } from '@mdx-js/react' +import DefaultLayout from '~/components/Layouts/Default' +import SectionContainer from '~/components/Layouts/SectionContainer' +import PageBreadcrumb from '~/components/Sections/PageBreadcrumb' +import PageHeader from '~/components/Sections/PageHeader' +import Content from '~/data/legal/support-policy/v1.mdx' +import mdxComponents from '~/lib/mdx/mdxComponents' +import { NextSeo } from 'next-seo' + +const meta = { + title: 'Support Policy', + description: 'Supabase Support Policy', +} + +export default function SupportPolicyPage() { + return ( + + + + } + h1="Support Policy" + /> + + + + + + + ) +} diff --git a/apps/www/pages/terms.tsx b/apps/www/pages/terms.tsx index a1f603dd6bc63..36f4c77338e62 100644 --- a/apps/www/pages/terms.tsx +++ b/apps/www/pages/terms.tsx @@ -2,6 +2,8 @@ import { MDXProvider } from '@mdx-js/react' import DefaultLayout from '~/components/Layouts/Default' import SectionContainer from '~/components/Layouts/SectionContainer' import LegalDocVersions, { type LegalDocVersion } from '~/components/Legal/LegalDocVersions' +import PageBreadcrumb from '~/components/Sections/PageBreadcrumb' +import PageHeader from '~/components/Sections/PageHeader' import V1 from '~/data/legal/terms/v1.mdx' import V2 from '~/data/legal/terms/v2.mdx' import V3 from '~/data/legal/terms/v3.mdx' @@ -23,13 +25,21 @@ export default function TermsPage() { return ( + + } + h1="Terms of Service" + /> -
- -

Terms of service

- -
-
+ + +
) From 91b40f15abc715db5825ba788b8497749497439f Mon Sep 17 00:00:00 2001 From: Pedro Rodrigues <44656907+Rodriguespn@users.noreply.github.com> Date: Thu, 30 Jul 2026 13:22:10 +0100 Subject: [PATCH 05/12] docs: how to fully remove account access when deleting a user (#48487) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The [User Management → Deleting users](https://supabase.com/docs/guides/auth/managing-user-data) section warned that deleting a user does not sign them out, but did not say what to do about it. Adds a **Removing account access** subsection: revoke sessions before deleting, why a soft-delete flag or [ban](https://supabase.com/docs/reference/javascript/auth-admin-updateuserbyid) is not a substitute, and the residual [access-token window](https://supabase.com/docs/guides/auth/sessions) after revocation. Fills a docs gap surfaced by [supabase/agent-skills#194](https://github.com/supabase/agent-skills/pull/194) while investigating the [`investigate-auth-001-deleted-user-access`](https://github.com/supabase/evals/blob/main/evals/investigate-auth-001-deleted-user-access/PROMPT.md) eval scenario. ## Summary by CodeRabbit * **Documentation** * Updated the “Deleting users” guidance to specify deleting via `auth.admin.deleteUser()` (with `shouldSoftDelete: false`) and clarify that this cascades to sessions, invalidates refresh tokens, and blocks new access-token minting. * Rewrote the explanation to emphasize that it does not substitute for temporary bans or application-level “deleted” states. * Clarified the access-token window: already-issued stateless JWTs remain valid until `exp`, and recommended mitigations include short JWT expiry and enforcing session validation (via `session_id`) for sensitive actions. --------- Co-authored-by: Claude Opus 4.8 (1M context) --- .../content/guides/auth/managing-user-data.mdx | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/apps/docs/content/guides/auth/managing-user-data.mdx b/apps/docs/content/guides/auth/managing-user-data.mdx index 8e1dffb4ca5eb..d703563143c83 100644 --- a/apps/docs/content/guides/auth/managing-user-data.mdx +++ b/apps/docs/content/guides/auth/managing-user-data.mdx @@ -210,6 +210,22 @@ You will encounter an error when you try to delete an Auth user that owns any St +### Removing account access + +When the goal is to remove an account so it can no longer access your app, delete the auth user with [`auth.admin.deleteUser()`](/docs/reference/javascript/auth-admin-deleteuser). With the default `shouldSoftDelete: false`, this removes the row from `auth.users`, which cascades to `auth.sessions` and invalidates the user's refresh tokens — so the account can no longer mint new access tokens. + +A few things are _not_ a substitute for deleting the user: + +- A temporary [ban](/docs/reference/javascript/auth-admin-updateuserbyid) only blocks sign-in for its duration and does not revoke existing sessions. +- Marking the account as deleted only in your own application tables leaves the `auth.users` row intact, so it can still authenticate and refresh. + +Deleting the user still cannot retroactively invalidate an access token that was already issued. Supabase access tokens are stateless JWTs, so a token already in the user's hands stays valid until its `exp` claim passes, and during that window the account can still call the API. You have two ways to handle this window: + +- **Bound it:** keep the [access token (JWT) expiry](/docs/guides/auth/sessions) short, so any outstanding token expires soon after you delete the user. +- **Close it for sensitive operations:** validate the `session_id` claim against the `auth.sessions` table on those operations. Because deleting the user removes the session row, an outstanding token fails this check — but only on the requests where you perform it; other API calls still accept the token until `exp`. + +See [User sessions](/docs/guides/auth/sessions) for details. + ## Exporting users As Supabase is built on top of Postgres, you can query the `auth.users` and `auth.identities` table via the `SQL Editor` tab to extract all users: From 6b14df77246004089823ec9b375cfe5387be4ea7 Mon Sep 17 00:00:00 2001 From: Ivan Vasilov Date: Thu, 30 Jul 2026 14:23:43 +0200 Subject: [PATCH 06/12] chore: Bump vulnerable deps (#48387) ## Summary by CodeRabbit * **Chores** * Updated Next.js, PostCSS, and tar package versions. * Added the required TypeScript native tooling where needed. * Refined package configuration and dependency ordering across the project. * Removed an unused empty dependency configuration. --- apps/design-system/package.json | 4 +- apps/docs/package.json | 6 +- apps/studio/package.json | 6 +- apps/ui-library/package.json | 2 +- apps/www/package.json | 4 +- blocks/vue/package.json | 2 +- packages/common/package.json | 4 +- packages/generator/package.json | 1 - packages/ui-patterns/package.json | 2 +- packages/ui/package.json | 2 +- pnpm-lock.yaml | 712 +++++++++++++++--------------- pnpm-workspace.yaml | 12 +- 12 files changed, 382 insertions(+), 375 deletions(-) diff --git a/apps/design-system/package.json b/apps/design-system/package.json index d1ffddf65031c..8b8da975e3653 100644 --- a/apps/design-system/package.json +++ b/apps/design-system/package.json @@ -19,8 +19,8 @@ "dependencies": { "@hookform/resolvers": "^3.1.1", "@tanstack/react-table": "catalog:", - "contentlayer2": "0.4.6", "common": "workspace:*", + "contentlayer2": "0.4.6", "date-fns": "^2.30.0", "dayjs": "1.11.13", "eslint-config-supabase": "workspace:*", @@ -57,6 +57,7 @@ "@types/lodash.template": "4.5.0", "@types/react": "catalog:", "@types/react-dom": "catalog:", + "@typescript/native": "catalog:", "config": "workspace:*", "mdast-util-toc": "^6.1.1", "npm-run-all": "^4.1.5", @@ -66,7 +67,6 @@ "tailwindcss": "catalog:", "tsconfig": "workspace:*", "tsx": "catalog:", - "@typescript/native": "catalog:", "typescript": "catalog:", "unist-builder": "3.0.0" } diff --git a/apps/docs/package.json b/apps/docs/package.json index e343ae6e65c51..a016e79a1b0ff 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -102,7 +102,7 @@ "mdast-util-to-string": "^3.1.1", "micromark-extension-gfm": "^2.0.3", "micromark-extension-mdxjs": "^1.0.0", - "next": "^15.5.18", + "next": "^15.5.21", "next-mdx-remote-client": "^1.1.7", "next-plugin-yaml": "^1.0.1", "next-themes": "catalog:", @@ -157,6 +157,7 @@ "@types/react-copy-to-clipboard": "^5.0.4", "@types/react-dom": "catalog:", "@types/unist": "^2.0.6", + "@typescript/native": "catalog:", "amaro": "^1.1.5", "api-types": "workspace:*", "cheerio": "^1.0.0-rc.12", @@ -175,11 +176,10 @@ "slugify": "^1.6.6", "smol-toml": "^1.3.1", "tailwindcss": "catalog:", - "tar": "^7.5.19", + "tar": "^7.5.21", "tsconfig": "workspace:*", "tsx": "catalog:", "twoslash": "^0.3.1", - "@typescript/native": "catalog:", "typescript": "catalog:", "unist-util-visit-parents": "5.1.3", "vite": "catalog:", diff --git a/apps/studio/package.json b/apps/studio/package.json index 8bc2705636573..2f3d947c9ed2c 100644 --- a/apps/studio/package.json +++ b/apps/studio/package.json @@ -69,6 +69,7 @@ "@std/path": "npm:@jsr/std__path@^1.0.8", "@stripe/react-stripe-js": "6.1.0", "@stripe/stripe-js": "9.1.0", + "@stripe/sync-engine": "1.0.32", "@supabase/auth-js": "catalog:", "@supabase/mcp-server-supabase": "^0.7.0", "@supabase/pg-meta": "workspace:*", @@ -150,7 +151,6 @@ "sonner": "^1.5.0", "sql-formatter": "^15.0.0", "streamdown": "^1.3.0", - "@stripe/sync-engine": "1.0.32", "swiper": "^12.1.2", "tus-js-client": "^4.1.0", "ui": "workspace:*", @@ -168,6 +168,7 @@ "@faker-js/faker": "^9.9.0", "@graphql-codegen/cli": "5.0.5", "@graphql-typed-document-node/core": "^3.2.0", + "@jridgewell/remapping": "^2.3.5", "@tailwindcss/vite": "4.2.4", "@tanstack/devtools-vite": "^0.6.0", "@testing-library/dom": "^10.0.0", @@ -188,7 +189,7 @@ "@types/react-grid-layout": "^1.3.0", "@types/react-simple-maps": "^3.0.1", "@types/zxcvbn": "^4.4.1", - "@jridgewell/remapping": "^2.3.5", + "@typescript/native": "catalog:", "@vercel/config": "^0.2.1", "@vitejs/plugin-react": "catalog:", "@vitest/coverage-v8": "catalog:", @@ -215,7 +216,6 @@ "require-in-the-middle": "^8.0.0", "tsconfig": "workspace:*", "tsx": "catalog:", - "@typescript/native": "catalog:", "typescript": "catalog:", "vite": "catalog:", "vite-tsconfig-paths": "catalog:", diff --git a/apps/ui-library/package.json b/apps/ui-library/package.json index dfbcb6c3de802..62abc5c3b9e50 100644 --- a/apps/ui-library/package.json +++ b/apps/ui-library/package.json @@ -80,6 +80,7 @@ "@types/lodash": "^4.17.16", "@types/react": "catalog:", "@types/react-dom": "catalog:", + "@typescript/native": "catalog:", "config": "workspace:^", "lodash": "catalog:", "mdast-util-toc": "^6.1.1", @@ -92,7 +93,6 @@ "tailwindcss": "catalog:", "tsconfig": "workspace:*", "tsx": "catalog:", - "@typescript/native": "catalog:", "typescript": "catalog:", "vite": "catalog:" } diff --git a/apps/www/package.json b/apps/www/package.json index 901f465841e72..c67c4195a47e7 100644 --- a/apps/www/package.json +++ b/apps/www/package.json @@ -38,6 +38,7 @@ "@sentry/nextjs": "catalog:", "@supabase/ssr": "catalog:", "@supabase/supabase-js": "catalog:", + "@typescript/native": "catalog:", "@vercel/og": "^0.6.2", "ai-commands": "workspace:*", "animejs": "^4.0.2", @@ -66,7 +67,7 @@ "mdast-util-to-markdown": "^1.5.0", "micromark-extension-gfm": "^2.0.3", "micromark-extension-mdxjs": "^1.0.1", - "next": "^15.5.18", + "next": "^15.5.21", "next-mdx-remote-client": "^1.1.7", "next-seo": "^6.5.0", "next-themes": "catalog:", @@ -91,7 +92,6 @@ "shiki": "^4.2.0", "swiper": "^12.1.2", "typed.js": "^2.0.16", - "@typescript/native": "catalog:", "typescript": "catalog:", "ui": "workspace:*", "ui-patterns": "workspace:*", diff --git a/blocks/vue/package.json b/blocks/vue/package.json index 39fd1c19c31d5..4ca3008fd4c23 100644 --- a/blocks/vue/package.json +++ b/blocks/vue/package.json @@ -24,9 +24,9 @@ "vue-router": "^4.5.1" }, "devDependencies": { + "@typescript/native": "catalog:", "shadcn": "^3.3.1", "tsconfig": "workspace:*", - "@typescript/native": "catalog:", "typescript": "catalog:", "vite": "^7.3.2" } diff --git a/packages/common/package.json b/packages/common/package.json index bc9c7ebd64db5..b874061734ef1 100644 --- a/packages/common/package.json +++ b/packages/common/package.json @@ -26,16 +26,16 @@ "valtio": "catalog:" }, "devDependencies": { - "lucide-react": "*", "@types/lodash": "4.17.5", "@types/node": "catalog:", "@types/react": "catalog:", "@types/react-dom": "catalog:", + "@typescript/native": "catalog:", "@vitest/coverage-v8": "catalog:", "@vitest/ui": "catalog:", + "lucide-react": "*", "tsconfig": "workspace:*", "type-fest": "5.6.0", - "@typescript/native": "catalog:", "typescript": "catalog:", "vitest": "catalog:" }, diff --git a/packages/generator/package.json b/packages/generator/package.json index cb3e56a7e713f..0d81708b40e59 100644 --- a/packages/generator/package.json +++ b/packages/generator/package.json @@ -20,7 +20,6 @@ "tsdoc:dereference:storage:v2": "tsx ./tsdoc.ts --input ../../apps/docs/spec/enrichments/tsdoc_v2/storage.json --output ../../apps/docs/spec/enrichments/tsdoc_v2/storage_dereferenced.json", "tsdoc:dereference:supabase:v2": "tsx ./tsdoc.ts --input ../../apps/docs/spec/enrichments/tsdoc_v2/supabase.json --output ../../apps/docs/spec/enrichments/tsdoc_v2/supabase_dereferenced.json" }, - "dependencies": {}, "devDependencies": { "@types/json-stringify-safe": "^5.0.0", "@types/lodash": "^4.14.202", diff --git a/packages/ui-patterns/package.json b/packages/ui-patterns/package.json index 749f48a721cc8..1955a7f3195c3 100644 --- a/packages/ui-patterns/package.json +++ b/packages/ui-patterns/package.json @@ -815,13 +815,13 @@ "@types/react": "catalog:", "@types/react-dom": "catalog:", "@types/react-syntax-highlighter": "^15.5.13", + "@typescript/native": "catalog:", "@vitest/coverage-v8": "catalog:", "api-types": "workspace:*", "config": "workspace:*", "next-router-mock": "^0.9.13", "tailwindcss": "^4.2.4", "tsx": "catalog:", - "@typescript/native": "catalog:", "typescript": "catalog:", "unified": "^11.0.5", "vfile": "^6.0.3", diff --git a/packages/ui/package.json b/packages/ui/package.json index b9fb78d53c2ca..f87bfb5a4a595 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -52,11 +52,11 @@ "@types/react": "catalog:", "@types/react-copy-to-clipboard": "^5.0.4", "@types/react-dom": "catalog:", + "@typescript/native": "catalog:", "@vitest/coverage-v8": "catalog:", "config": "workspace:*", "tsconfig": "workspace:*", "tsx": "catalog:", - "@typescript/native": "catalog:", "typescript": "catalog:", "vite": "catalog:", "vitest": "catalog:" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b64b52b7c226d..12e2b783928f5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -61,8 +61,8 @@ catalogs: specifier: ^4.1.4 version: 4.1.4 next: - specifier: 16.2.6 - version: 16.2.6 + specifier: ^16.2.11 + version: 16.2.11 next-themes: specifier: ^0.4.6 version: 0.4.6 @@ -106,24 +106,24 @@ catalogs: overrides: '@ardatan/relay-compiler>immutable': ^3.8.3 monaco-editor: 0.52.2 - '@mapbox/node-pre-gyp>tar': ^7.5.19 + '@mapbox/node-pre-gyp>tar': ^7.5.21 '@sentry/webpack-plugin>uuid': ^11.1.1 '@usercentrics/cmp-browser-sdk>uuid': ^11.1.1 braintrust>esbuild: ^0.28.1 braintrust>uuid: ^11.1.1 - cacache>tar: ^7.5.19 + cacache>tar: ^7.5.21 dompurify: ^3.3.2 express-rate-limit>ip-address: ^10.1.1 h3@1: 1.15.11 lodash: ^4.18.1 lodash-es: ^4.18.1 mdx-bundler>uuid: ^11.1.1 - node-gyp>tar: ^7.5.19 + node-gyp>tar: ^7.5.21 nodemailer: ^7.0.11 - postcss: ^8.5.10 + postcss: ^8.5.18 qs: ^6.15.2 refractor>prismjs: ^1.30.0 - supabase>tar: ^7.5.19 + supabase>tar: ^7.5.21 tmp: ^0.2.7 vite>esbuild: ^0.28.1 webpack: ^5.104.1 @@ -223,10 +223,10 @@ importers: version: 1.2.0 next: specifier: 'catalog:' - version: 16.2.6(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4) + version: 16.2.11(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4) next-contentlayer2: specifier: 0.4.6 - version: 0.4.6(contentlayer2@0.4.6(esbuild@0.28.1)(markdown-wasm@1.2.0)(supports-color@8.1.1))(esbuild@0.28.1)(markdown-wasm@1.2.0)(next@16.2.6(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(supports-color@8.1.1) + version: 0.4.6(contentlayer2@0.4.6(esbuild@0.28.1)(markdown-wasm@1.2.0)(supports-color@8.1.1))(esbuild@0.28.1)(markdown-wasm@1.2.0)(next@16.2.11(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(supports-color@8.1.1) next-themes: specifier: 'catalog:' version: 0.4.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6) @@ -316,8 +316,8 @@ importers: specifier: ^4.1.5 version: 4.1.5 postcss: - specifier: ^8.5.10 - version: 8.5.10 + specifier: ^8.5.18 + version: 8.5.22 rimraf: specifier: ^4.1.3 version: 4.4.1 @@ -377,7 +377,7 @@ importers: version: 8.1.0(@octokit/core@7.0.6) '@sentry/nextjs': specifier: 'catalog:' - version: 10.59.0(@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.8.0(@opentelemetry/api@1.9.1))(encoding@0.1.13)(next@15.5.18(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react@19.2.6)(supports-color@8.1.1)(vite@8.0.16(@types/node@22.13.14)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0))(webpack@5.105.4(esbuild@0.28.1)) + version: 10.59.0(@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.8.0(@opentelemetry/api@1.9.1))(encoding@0.1.13)(next@15.5.21(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react@19.2.6)(supports-color@8.1.1)(vite@8.0.16(@types/node@22.13.14)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0))(webpack@5.105.4(esbuild@0.28.1)) '@supabase/supabase-js': specifier: 'catalog:' version: 2.110.9 @@ -490,8 +490,8 @@ importers: specifier: ^1.0.0 version: 1.0.1 next: - specifier: ^15.5.18 - version: 15.5.18(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4) + specifier: ^15.5.21 + version: 15.5.21(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4) next-mdx-remote-client: specifier: ^1.1.7 version: 1.1.7(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(supports-color@8.1.1)(unified@11.0.5) @@ -503,7 +503,7 @@ importers: version: 0.4.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6) nuqs: specifier: ^1.19.1 - version: 1.19.1(next@15.5.18(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4)) + version: 1.19.1(next@15.5.21(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4)) openai: specifier: ^4.75.1 version: 4.104.0(encoding@0.1.13)(ws@8.21.0)(zod@3.25.76) @@ -683,8 +683,8 @@ importers: specifier: ^12.1.3 version: 12.1.3 postcss: - specifier: ^8.5.10 - version: 8.5.10 + specifier: ^8.5.18 + version: 8.5.22 shiki: specifier: ^3.2.1 version: 3.13.0 @@ -704,8 +704,8 @@ importers: specifier: 'catalog:' version: 4.2.4 tar: - specifier: ^7.5.19 - version: 7.5.20 + specifier: ^7.5.21 + version: 7.5.21 tsconfig: specifier: workspace:* version: link:../../packages/tsconfig @@ -750,10 +750,10 @@ importers: version: 0.511.0(react@19.2.6) next: specifier: 'catalog:' - version: 16.2.6(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4) + version: 16.2.11(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4) next-contentlayer2: specifier: 0.4.6 - version: 0.4.6(contentlayer2@0.4.6(esbuild@0.28.1)(markdown-wasm@1.2.0)(supports-color@8.1.1))(esbuild@0.28.1)(markdown-wasm@1.2.0)(next@16.2.6(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(supports-color@8.1.1) + version: 0.4.6(contentlayer2@0.4.6(esbuild@0.28.1)(markdown-wasm@1.2.0)(supports-color@8.1.1))(esbuild@0.28.1)(markdown-wasm@1.2.0)(next@16.2.11(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(supports-color@8.1.1) next-themes: specifier: 'catalog:' version: 0.4.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6) @@ -826,13 +826,13 @@ importers: dependencies: '@react-router/fs-routes': specifier: ^7.17.0 - version: 7.17.0(@react-router/dev@7.17.0(@react-router/serve@7.17.0(react-router@7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(supports-color@8.1.1)(typescript@6.0.2))(@types/node@22.13.14)(babel-plugin-macros@3.1.0)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(sass@1.77.4)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.22.4)(typescript@6.0.2)(vite@7.3.5(@types/node@22.13.14)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0))(yaml@2.9.0))(typescript@6.0.2) + version: 7.17.0(@react-router/dev@7.17.0(@react-router/serve@7.17.0(react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(supports-color@8.1.1)(typescript@6.0.2))(@types/node@22.13.14)(babel-plugin-macros@3.1.0)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(sass@1.77.4)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.22.4)(typescript@6.0.2)(vite@7.3.5(@types/node@22.13.14)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0))(yaml@2.9.0))(typescript@6.0.2) '@react-router/node': specifier: ^7.17.0 - version: 7.17.0(react-router@7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@6.0.2) + version: 7.17.0(react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@6.0.2) '@react-router/serve': specifier: ^7.17.0 - version: 7.17.0(react-router@7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(supports-color@8.1.1)(typescript@6.0.2) + version: 7.17.0(react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(supports-color@8.1.1)(typescript@6.0.2) isbot: specifier: ^5.1.36 version: 5.1.36 @@ -844,7 +844,7 @@ importers: version: 19.2.6(react@19.2.6) react-router: specifier: ^7.17.0 - version: 7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + version: 7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6) ui: specifier: workspace:* version: link:../../packages/ui @@ -854,7 +854,7 @@ importers: devDependencies: '@react-router/dev': specifier: ^7.17.0 - version: 7.17.0(@react-router/serve@7.17.0(react-router@7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(supports-color@8.1.1)(typescript@6.0.2))(@types/node@22.13.14)(babel-plugin-macros@3.1.0)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(sass@1.77.4)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.22.4)(typescript@6.0.2)(vite@7.3.5(@types/node@22.13.14)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0))(yaml@2.9.0) + version: 7.17.0(@react-router/serve@7.17.0(react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(supports-color@8.1.1)(typescript@6.0.2))(@types/node@22.13.14)(babel-plugin-macros@3.1.0)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(sass@1.77.4)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.22.4)(typescript@6.0.2)(vite@7.3.5(@types/node@22.13.14)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0))(yaml@2.9.0) '@tailwindcss/vite': specifier: 4.2.4 version: 4.2.4(vite@7.3.5(@types/node@22.13.14)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0)) @@ -956,7 +956,7 @@ importers: version: 1.1.1(@types/react@19.2.14)(react@19.2.6) '@sentry/nextjs': specifier: 'catalog:' - version: 10.59.0(@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.8.0(@opentelemetry/api@1.9.1))(encoding@0.1.13)(next@16.2.6(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react@19.2.6)(supports-color@8.1.1)(vite@8.0.16(@types/node@22.13.14)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0))(webpack@5.105.4(esbuild@0.28.1)) + version: 10.59.0(@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.8.0(@opentelemetry/api@1.9.1))(encoding@0.1.13)(next@16.2.11(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react@19.2.6)(supports-color@8.1.1)(vite@8.0.16(@types/node@22.13.14)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0))(webpack@5.105.4(esbuild@0.28.1)) '@sentry/react': specifier: ^10.27.0 version: 10.59.0(react@19.2.6) @@ -1139,13 +1139,13 @@ importers: version: 0.52.2 next: specifier: 'catalog:' - version: 16.2.6(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4) + version: 16.2.11(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4) next-themes: specifier: 'catalog:' version: 0.4.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6) nuqs: specifier: 2.7.1 - version: 2.7.1(@tanstack/react-router@1.170.10(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(next@16.2.6(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react-router@7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react@19.2.6) + version: 2.7.1(@tanstack/react-router@1.170.10(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(next@16.2.11(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react@19.2.6) openai: specifier: ^4.104.0 version: 4.104.0(encoding@0.1.13)(ws@8.21.0)(zod@3.25.76) @@ -1386,13 +1386,13 @@ importers: version: 2.11.3(@types/node@22.13.14)(typescript@6.0.2) next-router-mock: specifier: ^0.9.13 - version: 0.9.13(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react@19.2.6) + version: 0.9.13(next@16.2.11(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react@19.2.6) node-mocks-http: specifier: ^1.17.2 version: 1.17.2(@types/node@22.13.14) postcss: - specifier: ^8.5.10 - version: 8.5.10 + specifier: ^8.5.18 + version: 8.5.22 raw-loader: specifier: ^4.0.2 version: 4.0.2(webpack@5.105.4(esbuild@0.28.1)) @@ -1428,7 +1428,7 @@ importers: version: 4.7.0(monaco-editor@0.52.2)(react-dom@19.2.6(react@19.2.6))(react@19.2.6) '@react-router/fs-routes': specifier: ^7.4.0 - version: 7.4.0(@react-router/dev@7.13.2(@react-router/serve@7.17.0(react-router@7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(supports-color@8.1.1)(typescript@6.0.2))(@types/node@22.13.14)(babel-plugin-macros@3.1.0)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(sass@1.77.4)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.22.4)(typescript@6.0.2)(vite@8.0.16(@types/node@22.13.14)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0))(yaml@2.9.0))(typescript@6.0.2) + version: 7.4.0(@react-router/dev@7.13.2(@react-router/serve@7.17.0(react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(supports-color@8.1.1)(typescript@6.0.2))(@types/node@22.13.14)(babel-plugin-macros@3.1.0)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(sass@1.77.4)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.22.4)(typescript@6.0.2)(vite@8.0.16(@types/node@22.13.14)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0))(yaml@2.9.0))(typescript@6.0.2) '@supabase-labs/y-supabase': specifier: 0.1.0 version: 0.1.0 @@ -1488,10 +1488,10 @@ importers: version: 0.52.2 next: specifier: 'catalog:' - version: 16.2.6(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4) + version: 16.2.11(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4) next-contentlayer2: specifier: 0.4.6 - version: 0.4.6(contentlayer2@0.4.6(esbuild@0.28.1)(markdown-wasm@1.2.0)(supports-color@8.1.1))(esbuild@0.28.1)(markdown-wasm@1.2.0)(next@16.2.6(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(supports-color@8.1.1) + version: 0.4.6(contentlayer2@0.4.6(esbuild@0.28.1)(markdown-wasm@1.2.0)(supports-color@8.1.1))(esbuild@0.28.1)(markdown-wasm@1.2.0)(next@16.2.11(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(supports-color@8.1.1) next-themes: specifier: 'catalog:' version: 0.4.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6) @@ -1573,7 +1573,7 @@ importers: version: 7.29.7(supports-color@8.1.1) '@react-router/dev': specifier: ^7.9.0 - version: 7.13.2(@react-router/serve@7.17.0(react-router@7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(supports-color@8.1.1)(typescript@6.0.2))(@types/node@22.13.14)(babel-plugin-macros@3.1.0)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(sass@1.77.4)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.22.4)(typescript@6.0.2)(vite@8.0.16(@types/node@22.13.14)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0))(yaml@2.9.0) + version: 7.13.2(@react-router/serve@7.17.0(react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(supports-color@8.1.1)(typescript@6.0.2))(@types/node@22.13.14)(babel-plugin-macros@3.1.0)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(sass@1.77.4)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.22.4)(typescript@6.0.2)(vite@8.0.16(@types/node@22.13.14)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0))(yaml@2.9.0) '@shikijs/compat': specifier: ^1.1.7 version: 1.6.0 @@ -1614,14 +1614,14 @@ importers: specifier: ^6.1.1 version: 6.1.1 postcss: - specifier: ^8.5.10 - version: 8.5.10 + specifier: ^8.5.18 + version: 8.5.22 react-dropzone: specifier: ^14.3.8 version: 14.3.8(react@19.2.6) react-router: specifier: ^7.13.2 - version: 7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + version: 7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6) rimraf: specifier: ^4.1.3 version: 4.4.1 @@ -1693,7 +1693,7 @@ importers: version: 21.1.1 '@sentry/nextjs': specifier: 'catalog:' - version: 10.59.0(@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.8.0(@opentelemetry/api@1.9.1))(encoding@0.1.13)(next@15.5.18(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react@19.2.6)(supports-color@8.1.1)(vite@8.0.16(@types/node@22.13.14)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0))(webpack@5.105.4(esbuild@0.28.1)) + version: 10.59.0(@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.8.0(@opentelemetry/api@1.9.1))(encoding@0.1.13)(next@15.5.21(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react@19.2.6)(supports-color@8.1.1)(vite@8.0.16(@types/node@22.13.14)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0))(webpack@5.105.4(esbuild@0.28.1)) '@supabase/ssr': specifier: 'catalog:' version: 0.10.2(@supabase/supabase-js@2.110.9) @@ -1788,20 +1788,20 @@ importers: specifier: ^1.0.1 version: 1.0.1 next: - specifier: ^15.5.18 - version: 15.5.18(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4) + specifier: ^15.5.21 + version: 15.5.21(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4) next-mdx-remote-client: specifier: ^1.1.7 version: 1.1.7(@types/react@19.2.14)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(supports-color@8.1.1)(unified@11.0.5) next-seo: specifier: ^6.5.0 - version: 6.5.0(next@15.5.18(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + version: 6.5.0(next@15.5.21(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react-dom@19.2.6(react@19.2.6))(react@19.2.6) next-themes: specifier: 'catalog:' version: 0.4.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6) nuqs: specifier: ^2.8.1 - version: 2.8.1(@tanstack/react-router@1.170.10(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(next@15.5.18(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react-router@7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react@19.2.6) + version: 2.8.1(@tanstack/react-router@1.170.10(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(next@15.5.21(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react@19.2.6) ogl: specifier: ^1.0.11 version: 1.0.11 @@ -1873,7 +1873,7 @@ importers: version: link:../../packages/ui-patterns unicornstudio-react: specifier: 2.0.1-1 - version: 2.0.1-1(next@15.5.18(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + version: 2.0.1-1(next@15.5.21(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react-dom@19.2.6(react@19.2.6))(react@19.2.6) use-debounce: specifier: ^7.0.1 version: 7.0.1(react@19.2.6) @@ -1924,8 +1924,8 @@ importers: specifier: workspace:* version: link:../../packages/api-types postcss: - specifier: ^8.5.10 - version: 8.5.10 + specifier: ^8.5.18 + version: 8.5.22 react-hook-form: specifier: ^7.71.2 version: 7.72.1(react@19.2.6) @@ -2181,13 +2181,13 @@ importers: version: 0.7.9 flags: specifier: ^4.0.0 - version: 4.0.1(@opentelemetry/api@1.9.1)(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + version: 4.0.1(@opentelemetry/api@1.9.1)(next@16.2.11(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react-dom@19.2.6(react@19.2.6))(react@19.2.6) lodash: specifier: ^4.18.1 version: 4.18.1 next: specifier: 'catalog:' - version: 16.2.6(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4) + version: 16.2.11(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4) next-themes: specifier: 'catalog:' version: 0.4.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6) @@ -2304,10 +2304,10 @@ importers: version: link:../config next: specifier: 'catalog:' - version: 16.2.6(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4) + version: 16.2.11(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4) next-router-mock: specifier: ^0.9.13 - version: 0.9.13(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react@19.2.6) + version: 0.9.13(next@16.2.11(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react@19.2.6) react: specifier: 'catalog:' version: 19.2.6 @@ -2689,7 +2689,7 @@ importers: version: 0.52.2 next: specifier: 'catalog:' - version: 16.2.6(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4) + version: 16.2.11(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4) next-themes: specifier: 'catalog:' version: 0.4.6(react-dom@19.2.6(react@19.2.6))(react@19.2.6) @@ -2822,7 +2822,7 @@ importers: version: link:../config next-router-mock: specifier: ^0.9.13 - version: 0.9.13(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react@19.2.6) + version: 0.9.13(next@16.2.11(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react@19.2.6) tailwindcss: specifier: ^4.2.4 version: 4.2.4 @@ -4747,11 +4747,11 @@ packages: '@next/env@14.2.35': resolution: {integrity: sha512-DuhvCtj4t9Gwrx80dmz2F4t/zKQ4ktN8WrMwOuVzkJfBilwAwGr6v16M5eI8yCuZ63H9TTuEU09Iu2HqkzFPVQ==} - '@next/env@15.5.18': - resolution: {integrity: sha512-hAV85Ckd9QR6RvH04MEKwsfLTksvFpO47j9xwtoIuvuPnlwecpSi+uZTtm8HirVbtlI2Fnz//xpcSTjFdyJk+g==} + '@next/env@15.5.21': + resolution: {integrity: sha512-hjJI/GfrjWHgNguRIBzItjRRu0m3Nrz17GhxsjuHfjIvg9hyg3239REd2dpI+bpMTFuVrVprHzEQ19m++cDtbw==} - '@next/env@16.2.6': - resolution: {integrity: sha512-gd8HoHN4ufj73WmR3JmVolrpJR47ILK6LouP5xElPglaVxir6e1a7VzvTvDWkOoPXT9rkkTzyCxBu4yeZfZwcw==} + '@next/env@16.2.11': + resolution: {integrity: sha512-0do5A3BJ2gxWr0ZCMcD6BhW+e595jyxdTl3rXTS6lOtD8ektMiW6CO+EPwt1Eca1DBnm90r/7GdiKWBKxH++DA==} '@next/eslint-plugin-next@15.5.4': resolution: {integrity: sha512-SR1vhXNNg16T4zffhJ4TS7Xn7eq4NfKfcOsRwea7RIAHrjRpI9ALYbamqIJqkAhowLlERffiwk0FMvTLNdnVtw==} @@ -4767,106 +4767,106 @@ packages: '@mdx-js/react': optional: true - '@next/swc-darwin-arm64@15.5.18': - resolution: {integrity: sha512-w0WvQf1n+txiwns/9pwIQteCJpZTbxzO2SE0FLcwuD4v0WEh1JPOjdyxWL21XwJsdpx8cFRjyzxzCS/siP7HcQ==} + '@next/swc-darwin-arm64@15.5.21': + resolution: {integrity: sha512-ZfjqPEdi6TRC/fWx7UDbwb1fbVgyh2uD5tVTRKIDZDlYM+UNuE/LafDG2fwuAoZilADpABh46OY/F5qf9JjqLQ==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@next/swc-darwin-arm64@16.2.6': - resolution: {integrity: sha512-ZJGkkcNfYgrrMkqOdZ7zoLa1TOy0qpcMfk/z4Mh/FKUz40gVO+HNQWqmLxf67Z5WB64DRp0dhEbyHfel+6sJUg==} + '@next/swc-darwin-arm64@16.2.11': + resolution: {integrity: sha512-wryL4pjKmDwGv2ox6+GZDFxvmtSRLqApBR8kL1j4+vhB7Z5vJC/zAnXpiR9Xkfzl0AS8WLMnsuGV/UKI67/rrw==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - '@next/swc-darwin-x64@15.5.18': - resolution: {integrity: sha512-znn71QmDuxm+BOaglihMZfvyySMnNljkVIY5Z2TCssBmm+WqL6c19VhtH5ktFkHa8EZ2bnTUpcNcmNSQsg67og==} + '@next/swc-darwin-x64@15.5.21': + resolution: {integrity: sha512-TlCf1NpxgQLzTrexuev75xwmNCJMd1/qkJpTVP1GRRcih93hlIBn1P72hkh8T0gnRFr6BmWksQtbyG3jT6jnww==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@next/swc-darwin-x64@16.2.6': - resolution: {integrity: sha512-v/YLBHIY132Ced3puBJ7YJKw1lqsCrgcNo2aRJlCEyQrrCeRJlvGlnmxhPxNQI3KE3N1DN5r9TPNPvka3nq5RQ==} + '@next/swc-darwin-x64@16.2.11': + resolution: {integrity: sha512-aZl2j4f/fLyjQvOhv0Oe9UaMAQHolYpKhctsoYzplSumKJKPUmgjcf6545aBtysLTcu994TREd0+pSgNE4ohmg==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - '@next/swc-linux-arm64-gnu@15.5.18': - resolution: {integrity: sha512-yPPe5MNL+igZUa+OsqQJisqSfh6oarIuA1Q0BDxljGJhRQyZeP+WRHh7rs/jZUGMh5aY0YdIjXZG0VohkKkUdw==} + '@next/swc-linux-arm64-gnu@15.5.21': + resolution: {integrity: sha512-LXRsq1p+HvHSi7ygwNcSEEcK0zuo5jS75ZlqFHtOH+LF7qntXAJVJxah+1Pi/GyBm7EpkwU7m4EgbvIKrMqm9A==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] libc: [glibc] - '@next/swc-linux-arm64-gnu@16.2.6': - resolution: {integrity: sha512-RPOvqlYBbcQjkz9VQQDZ2T2bARIjXZV1KFlt+V2Mr6SW/e4I9fcKsaA0hdyf2FHoTlsV2xnBd5Y912rP/1Ce6w==} + '@next/swc-linux-arm64-gnu@16.2.11': + resolution: {integrity: sha512-5jEriyEnH/LWFy27L2ZG0XaLlyEJIjhsImEsiS9P563PKEVp2BVups/xfOucIrsvVntp11oNcZwjHvaDPYVB5g==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] libc: [glibc] - '@next/swc-linux-arm64-musl@15.5.18': - resolution: {integrity: sha512-glaCczEWIrHsokFZ3pP08U4BpKxwIdnT+txdOM32OBgpL9Yw4aqx8NejmgtZQZOdstQ5f0L3CasIZudzCuD+nw==} + '@next/swc-linux-arm64-musl@15.5.21': + resolution: {integrity: sha512-hyGixhFxpDKjqoev6l4KlcRBlt9AXWrGhDZwmwg49sMJM5tnKQPSi+SEj9+e5n+l/bthRGZUdh59GKIs6lQPRw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] libc: [musl] - '@next/swc-linux-arm64-musl@16.2.6': - resolution: {integrity: sha512-URUTu1+dMkxJsPFgm+OeEvq9wf5sujw0EvgYy80TDGHTSLTnIHeqb0Eu8A3sC95IRgjejQL+kC4mw+4yPxiAXA==} + '@next/swc-linux-arm64-musl@16.2.11': + resolution: {integrity: sha512-eIjcpx2fnnFSSkZDbTxy74KnokUXDjfoLClpWelfgHLf621aTqswhwXQ7GkD5K5rplrS6LZ/Bj+mVuvzluBOEg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] libc: [musl] - '@next/swc-linux-x64-gnu@15.5.18': - resolution: {integrity: sha512-oUfg2EgJmU3R0OCOWiokGFUTvZiPfXtriXiuF3YNxRoROCdgvTedHIzYoeKH34gsZxS/V7mHbfq2hpAHwhH1/A==} + '@next/swc-linux-x64-gnu@15.5.21': + resolution: {integrity: sha512-qfE+YfOba6S2+13e8qn1/UozDVNZ2clBlrs8UtDoax4s8ediu6sq93z66OEHUYlb69Tffh5JTNkgtsAKiSuugg==} engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [glibc] - '@next/swc-linux-x64-gnu@16.2.6': - resolution: {integrity: sha512-DOj182mPV8G3UkrayLoREM5YEYI+Dk5wv7Ox9xl1fFibAELEsFD0lDPfHIeILlutMMfdyhlzYPELG3peuKaurw==} + '@next/swc-linux-x64-gnu@16.2.11': + resolution: {integrity: sha512-8WgzpaWMs46qJT9kiV47cje86L0x/Mu9t8/Gwj+pnbgW3rETVfCnaScPjlYUwNScpOozdcIMHWmAvuZJUonR2w==} engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [glibc] - '@next/swc-linux-x64-musl@15.5.18': - resolution: {integrity: sha512-JLxSP3KTd9iu/bvUMQxH7RJo9xKSHf55/6RPE4a6FTSZygGn7uvZbCej0AHXydwkggQGSD9UddSjwv6Xz5ESfA==} + '@next/swc-linux-x64-musl@15.5.21': + resolution: {integrity: sha512-BXLGG+EvIwp/Rrgl6HY8sqvD6BOUOIRz8/naDbeLNX7mlA5H2XRcL6MW/0IGnJISfj5BA9gNhFyJj5yOoiIDJQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [musl] - '@next/swc-linux-x64-musl@16.2.6': - resolution: {integrity: sha512-HKQ5SP/V/ub73UvF7n/zeJlxk2kLmtL7Wzrg4WfmkjmNos5onJ2tKu7yZOPdL18A6Svfn3max29ym+ry7NkK4g==} + '@next/swc-linux-x64-musl@16.2.11': + resolution: {integrity: sha512-I3UgPds7G4ZYnTb/H+5GBGuUT2DhAk6j0mL6A4s63RjFs74wB2hOWP0vaxsK+3NJraExt3eYEPQ/UtT0x/64Nw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] libc: [musl] - '@next/swc-win32-arm64-msvc@15.5.18': - resolution: {integrity: sha512-ir1v7enP52K2HNz3tQQvwF+x7VNxBk1ciiZ18WBPvxf4C59IqdfmHPJYK3vH7rSxpuCVw/8C712wTXNAtEp+NA==} + '@next/swc-win32-arm64-msvc@15.5.21': + resolution: {integrity: sha512-tNGNOlT0Wn7E4IMsSnufjXN/l2L2/AGdLLpa2vzS89SYCBuihgLn3ngLsIrvndAnWo9nAkus+4gZHTI/Ijx9HA==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@next/swc-win32-arm64-msvc@16.2.6': - resolution: {integrity: sha512-LZXpTlPyS5v7HhSmnvsLGP3iIYgYOBnc8r8ArlT55sGHV89bR2HlDdBjWQ+PY6SJMmk8TuVGFuxalnP3k/0Dwg==} + '@next/swc-win32-arm64-msvc@16.2.11': + resolution: {integrity: sha512-n89CjtcThnjrwgJMAiI5xbqwLY51zvwC9tSlArmVndAJLYVl9T9UAdlkXTmZvE++idoXe8KdglQlhNRdUp1c6g==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - '@next/swc-win32-x64-msvc@15.5.18': - resolution: {integrity: sha512-LIu5me6QTANCd25E7I5uIEfvgQ06RK7tvHAbYo3zCb3VpxQEPvMcSpd87NwUABDT6MbGPdEGR5VRiK4PPTJhQg==} + '@next/swc-win32-x64-msvc@15.5.21': + resolution: {integrity: sha512-DmIdWmC9p4rdNIiQqo8ap0+Cnj6kKtTZnuSCxoYydSc8sgpDgAg9wFhxplunak9imLV0pTvc5WVCOHwm5eHLtQ==} engines: {node: '>= 10'} cpu: [x64] os: [win32] - '@next/swc-win32-x64-msvc@16.2.6': - resolution: {integrity: sha512-F0+4i0h9J6C4eE3EAPWsoCk7UW/dbzOjyzxY0qnDUOYFu6FFmdZ6l97/XdV3/Nz3VYyO7UWjyEJUXkGqcoXfMA==} + '@next/swc-win32-x64-msvc@16.2.11': + resolution: {integrity: sha512-md8CLNggS1Dx9pUgApzps5uAf+N8GN9xywzmNx9vHAWo94HtBwCCqkSnhIrdfQe83Dhz8Lfo/20Nb1Zxal092w==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -9474,7 +9474,7 @@ packages: engines: {node: ^10 || ^12 || >=14} hasBin: true peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.18 available-typed-arrays@1.0.7: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} @@ -9617,6 +9617,10 @@ packages: resolution: {integrity: sha512-7oFy703dxfY3/NLxC1fh2SUCQ0H9rmAY+5EpDVfXjUTTs+HEwR2nYaqLv+GWcTsumwxPfiz6CzCNkwXwBUwqCA==} engines: {node: 18 || 20 || >=22} + brace-expansion@5.0.8: + resolution: {integrity: sha512-JZyDyq3D4AUifKTPOB7DELf6XsB3WdPuNxCtob1vFXPsSXhdAiHBWJ/tJ8HAc9aH84BK+5JFZLNkJKx3G9kzQg==} + engines: {node: 20 || >=22} + braces@3.0.3: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} @@ -10267,19 +10271,19 @@ packages: resolution: {integrity: sha512-OTdKeYMlvQ8KBgyej5ysktnWJoeyo7rGrVnm+bdpIHGvxhbTGPsOkB+7T1EdTuX00dGlQQb2UEbSPB1OpMXULw==} engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.18 cssnano-utils@6.0.0: resolution: {integrity: sha512-ztS9W/+uaDn+bkYmDhs+GdMveHJ3CL8IPNHpRqDUQXv5GJOTQAJjV1XUOInr9esLXSabQV1pLRZlJpyUwEqDyQ==} engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.18 cssnano@8.0.1: resolution: {integrity: sha512-oSiOnPQNNYjusTUlYJiE6xvFQG4don3N0QavaoV1BxIsC1zjvxOwikXlR7lG1EVmZNDDaJkHbQx1VRB8kaoMHA==} engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.18 csso@5.0.5: resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} @@ -11361,8 +11365,8 @@ packages: fast-string-width@3.0.2: resolution: {integrity: sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==} - fast-uri@3.1.2: - resolution: {integrity: sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==} + fast-uri@3.1.4: + resolution: {integrity: sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw==} fast-wrap-ansi@0.2.2: resolution: {integrity: sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==} @@ -12201,8 +12205,8 @@ packages: resolution: {integrity: sha512-AUY/VyX0E5XlibOmWt10uabJzam1zlYjwiEgQSDc5+UIkFNaF9WM0JxXKaNMGf+F/ffUF+7kRKXM9A7C0xXqMg==} engines: {node: '>=0.10.0'} - immutable@4.3.8: - resolution: {integrity: sha512-d/Ld9aLbKpNwyl0KiM2CT1WYvkitQ1TSvmRtkcV8FKStiDoA7Slzgjmb/1G2yhKM1p0XeNOieaTbFZmU1d3Xuw==} + immutable@4.3.9: + resolution: {integrity: sha512-ObHy4YN7ycwZOUCLI1/6svfyAFu7vL8RhAvVu/bh/RZW9EPlOyDaQ9jDQWCtdqzaXUjgXZCW1migtHE7YI7UGQ==} import-fresh@3.3.0: resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} @@ -13880,8 +13884,8 @@ packages: react: '*' react-dom: '*' - nanoid@3.3.11: - resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + nanoid@3.3.16: + resolution: {integrity: sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true @@ -13950,8 +13954,8 @@ packages: next-tick@1.1.0: resolution: {integrity: sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==} - next@15.5.18: - resolution: {integrity: sha512-eKL8zUJkX9Y5lE+RX/2YJoItVdGlIscyVyboeD9wSpp0PaGqjoA4tTpT2qPqz9ax+5IzGESyLSeZ/RCwbSZ2uQ==} + next@15.5.21: + resolution: {integrity: sha512-/TsdBtkWLhkl+NVL3Uqws2UphNd6IPzOtzSk1fHaf+0P7GQKLZDUytyhns/Ykbzdy9+YRjwG7ONvrHaaTDdFqQ==} engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} hasBin: true peerDependencies: @@ -13971,8 +13975,8 @@ packages: sass: optional: true - next@16.2.6: - resolution: {integrity: sha512-qOVgKJg1+At15NpeUP+eJgCHvTCgXsogweq87Ri/Ix7PkqQHg4sdaXmSFqKlgaIXE4kW0g25LE68W87UANlHtw==} + next@16.2.11: + resolution: {integrity: sha512-B339zaqbyK8cmxhoAvLrcwoabwCP1wz21zSzfqxqXAemTu2BXnH7tQnfcglKv1vnMUIDBc+Hth7XODQriTZiRQ==} engines: {node: '>=20.9.0'} hasBin: true peerDependencies: @@ -14714,151 +14718,151 @@ packages: resolution: {integrity: sha512-NYEsLHh8DgG/PRH2+G9BTuUdtf9ViS+vdoQ0YA5OQdGsfN4ztiwtDWNtBl9EKeqNMFnIu8IKZ0cLxEQ5r5KVMw==} engines: {node: ^18.12 || ^20.9 || >=22.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.18 postcss-colormin@8.0.0: resolution: {integrity: sha512-KKwMmsSgsmdYXqrjQeqL3tnuIFtctiR1GEMHdjNpDpz/TCRkkkok2mMcreK2zVV3l7POWOmAkR2xYHUpRUK1DA==} engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.18 postcss-convert-values@8.0.0: resolution: {integrity: sha512-Ohtj3rNZWawTRePv5NCHTy8VJSdJ/G/uKuxcxJreOMichuqcT6uEl2TAnopVeJCJ/c13jaSqg7m63yFLM5zBsA==} engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.18 postcss-discard-comments@8.0.0: resolution: {integrity: sha512-zGpvVLj2sbagEp+BTVETvAfkZdGVA6rALNujDK/WTIjdf1/rQOxOG8BBzkI8UQgnw8SkL6xffAfbtGMHFypadw==} engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.18 postcss-discard-duplicates@8.0.0: resolution: {integrity: sha512-zjRyYmNGI3PTipKBBtCgExlmZXQn49KvKoaiNnR2g+iXxeNk7GY5Js2ULtZXPrCYeqjPagrzKIBNcBocvXCR7g==} engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.18 postcss-discard-empty@8.0.0: resolution: {integrity: sha512-kxPJg6EqahbBvm+l7hpYYCtpsv8dlz7Tv6wJXUXZaeuY0WGS61DxfGdZR4uVB/Cx+yi3iOHQVSqpSHKMFaBg6Q==} engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.18 postcss-discard-overridden@8.0.0: resolution: {integrity: sha512-sW2OWH3l9p0FmBSVr228uztFseqroZxwgD7SGF0Ks0dRPDttSo3P8FK5ZBLtWBH2A5+chpB0J2fB/T8heKHLBw==} engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.18 postcss-merge-longhand@8.0.0: resolution: {integrity: sha512-YDmAmQ8H+ljfomVpSXvr9NA0GP01fraQJqjWBYoMVGg6rOT+PJLwPyeVo2ekn4WB4ZVSH5ddtK3DTRxbz6CFzg==} engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.18 postcss-merge-rules@8.0.0: resolution: {integrity: sha512-bgstL5mpi41dDpnYGDUcI3M814NWkCMcIWpwDqEHXkHg3BT7b4XRAfNEuwJncZOVn/67kVKvWzhfv/7xyrp2uQ==} engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.18 postcss-minify-font-values@8.0.0: resolution: {integrity: sha512-EnOHQEnSt6oH5NrL1DMFAQuwB2IOimFXTCzc9bKfUeH1jREbqIF5MAK4gQJQOC4mPUwJt4sWifAmNZ1qLu6j3Q==} engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.18 postcss-minify-gradients@8.0.0: resolution: {integrity: sha512-43iAnYIGk0ZjNx5X/rkIcHi6dhmu/vEjY0kqfUfxPuJRO+V7jx8uKIdcnL0dpfNoC5J9TSh3EtzLWbq0gpqnWA==} engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.18 postcss-minify-params@8.0.0: resolution: {integrity: sha512-z7w4QO7G55l4vMUK1Lmx03GW7iyRLgf2V5Dz/7ioSPLnXRjeD+b7m0XfAXUGrbBYYrJ6bXPk+3LoX5u4JfAcSg==} engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.18 postcss-minify-selectors@8.0.1: resolution: {integrity: sha512-c31D46811kTkQDxV1KTTow79axX6gj/01AY5G7cGZg3s31KvAwP13jEFXGAzQbJ7NvOFV1pRqEia6nrAdHU7qg==} engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.18 postcss-normalize-charset@8.0.0: resolution: {integrity: sha512-s88FUNDSUD8m0wBYvTQQcubVts6zhXwBU8zCD4vkRKiecd0v8cOjHVIF9r/i+5xzS/WG3f98qq4XsOM0JqvfLA==} engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.18 postcss-normalize-display-values@8.0.0: resolution: {integrity: sha512-gG2nBxD27fiw6Luinb1QYKdM/Co5GornRJgSD+JTwNH4PGKxImP0qyruDDav49aHUPLY3qrL3qN3LvybO7IzxQ==} engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.18 postcss-normalize-positions@8.0.0: resolution: {integrity: sha512-t/wGqpehS20Ke7kc4QAsWpH+AJjUdMK/V5qV2RhrXkj8hO/fT1t1MJ8NL7sedWYk7ZqC7eISEJQonW5j0tU1MQ==} engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.18 postcss-normalize-repeat-style@8.0.0: resolution: {integrity: sha512-3ebOmGdCYKrBYyGKc1xhj0unEnW7beZpVU7JohVeGl7mTxR+7T6egpaawTWAVsB0pEIhcsbJVOjPKCJSoRO6Zg==} engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.18 postcss-normalize-string@8.0.0: resolution: {integrity: sha512-TvWCGZ/e04Tv31uJvOUtbexkfgUnqmQ3M2P5DkAaVzvOj+BvTkG2QjpA5Y71SL1SPxJcj4M23fNh+RDVCmG8kA==} engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.18 postcss-normalize-timing-functions@8.0.0: resolution: {integrity: sha512-uEfaXst5Xgqxv7geYUuz6vs9mn88K2NPY2RoIzM3BMmSjsdTSeppV9x2qIgrxsisdbSqF6IVhzI2occcte3hTA==} engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.18 postcss-normalize-unicode@8.0.0: resolution: {integrity: sha512-+WYngZaChEeTHZmWhmKtnJ4gTzWdINEaFcgWBnu6WdVu8Ftim8OBTcw768DuCC/3Aax9bZ9WkwrLGHym2Lzf+A==} engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.18 postcss-normalize-url@8.0.0: resolution: {integrity: sha512-4Mz9hZHn/QIB+YtFqTXrDmE2193GYxGb3F8uMfLvMicaEXCCUlDIJ658gFFJbqEGl9FYzwPtRiuNgbwlO9kkBg==} engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.18 postcss-normalize-whitespace@8.0.0: resolution: {integrity: sha512-V1f8tYnwIP5tscOXQFTKK8Y5EJ+R2GMpFJ6FjzwoKoQnhbqQy3IeSrDjJJb8JjVos8ut6Osi80Zybpayv/XjIQ==} engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.18 postcss-ordered-values@8.0.0: resolution: {integrity: sha512-Dg9+itb6lmD0bxqhQyHCtXAwYRh0wUrx6Mp4/BNXgkLoJmdYMmWi+V+Pypw79Q6iQhxA8KFMHqLBITQJV2gKMA==} engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.18 postcss-reduce-initial@8.0.0: resolution: {integrity: sha512-DChcE9d528AKrlpCTHjhsAiOsWCk4H9ApHPS1QqRT3praObWTiWyn6W1UddGpc46K9LQnHwUu4YwaPUukGtXVA==} engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.18 postcss-reduce-transforms@8.0.0: resolution: {integrity: sha512-cLZT0som7vvumQT9XQCnSKOSnRinNQZd1Hm+J723Ney13E8CIydDhw6JwzsjPtgnYThTqn9Q45906gz6wxaAsw==} engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.18 postcss-selector-parser@6.0.10: resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==} @@ -14872,19 +14876,19 @@ packages: resolution: {integrity: sha512-Q2fMSYEiNE1ioDc/3sxvI24NdgA/MJno2XLNpOxgv8aCcJbym8mZY10/lDY5+AWCIc3Aiqzy2Wcp9/zaIXBZgQ==} engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.18 postcss-unique-selectors@8.0.0: resolution: {integrity: sha512-iObuolUX+ITJfMU2QQFQdh31JgSjNLPNjVs6YGAqBHvOvAWXMMNget6donQl83aQaeS32i5XeKZURUW/WBxIUw==} engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.18 postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} - postcss@8.5.10: - resolution: {integrity: sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==} + postcss@8.5.22: + resolution: {integrity: sha512-KBDEIpLrvpv16pp3K0Fw+UCoZfopFjjgeB+0tA/aaThfEE74kKDLrgg603YvOWJyg3+WYtyq3xYsQWsIyZlPqQ==} engines: {node: ^10 || ^12 || >=14} postgres-array@2.0.0: @@ -15266,8 +15270,8 @@ packages: peerDependencies: react: '>= 16.3' - react-router@7.17.0: - resolution: {integrity: sha512-FDELK7rTMlCHO5+reyXsPlmfr7N1F91lPHsWYfMEGQm/KQ+F4JFM8jGoeQDmDvdTs93Fw9aSilH+uKRb4/jXvQ==} + react-router@7.18.1: + resolution: {integrity: sha512-GDLgg3i3uM0aeJO3Fm+TCS+sDQ7gu12T6x0qdTEzcwqEfleci7JwugVNIF3U//0FWKnJT7ptG+20B2jfDqnZAg==} engines: {node: '>=20.0.0'} peerDependencies: react: '>=18' @@ -16310,7 +16314,7 @@ packages: resolution: {integrity: sha512-sWyjaJvBqHoVKYPbQ8JRvrGSPaYWtWrJsU+fGVtwKB1GE1rRPu3rC7T6UCuXLoL00Dwb+tsHe2T904r8Vnsx8w==} engines: {node: ^22.11.0 || ^24.11.0 || >=26.0} peerDependencies: - postcss: ^8.5.10 + postcss: ^8.5.18 stylis@4.3.6: resolution: {integrity: sha512-yQ3rwFWRfwNUY7H5vpU0wfdkNSnvnJinhF9830Swlaxl03zsOjCfmX0ugac+3LtK0lYSgwL/KXc8oYL3mG4YFQ==} @@ -16395,8 +16399,8 @@ packages: tar-stream@3.1.7: resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==} - tar@7.5.20: - resolution: {integrity: sha512-9FcyK4PA6+WbzlTM9WhQm6vB5W7cP7dUiPsv1g7YDwEQnQ1CGpK3MGlKk/ITVWMk05kHZuBhmVhiv8LZoy/PFQ==} + tar@7.5.21: + resolution: {integrity: sha512-XdhtCvlMywwxpCW8YEq3lOXBJpUPTR2OHHcwLPO3HwsJqOHa2Ok/oJ7ruGzp+JrKoRPVCzJwAdEjqLW/vNRPHA==} engines: {node: '>=18'} termi-link@1.1.0: @@ -17071,8 +17075,8 @@ packages: engines: {node: '>=8'} hasBin: true - valibot@1.2.0: - resolution: {integrity: sha512-mm1rxUsmOxzrwnX5arGS+U4T25RdvpPjPN4yR0u9pUBov9+zGVtO84tif1eY4r6zWxVxu3KzIyknJy3rxfRZZg==} + valibot@1.4.2: + resolution: {integrity: sha512-gjdCvJ6d3RyHAneqxMYMW9QMCwYMb3jpOO0IyHZV1bnRHFBHrX3VkIILt5XYR0WhwHiH7Mty8ovuPZ/O3gamrg==} peerDependencies: typescript: '>=5' peerDependenciesMeta: @@ -20318,7 +20322,7 @@ snapshots: npmlog: 5.0.1 rimraf: 3.0.2 semver: 7.8.1 - tar: 7.5.20 + tar: 7.5.21 transitivePeerDependencies: - encoding - supports-color @@ -20331,7 +20335,7 @@ snapshots: node-fetch: 2.7.0(encoding@0.1.13) nopt: 8.1.0 semver: 7.8.1 - tar: 7.5.20 + tar: 7.5.21 transitivePeerDependencies: - encoding - supports-color @@ -20472,9 +20476,9 @@ snapshots: '@next/env@14.2.35': {} - '@next/env@15.5.18': {} + '@next/env@15.5.21': {} - '@next/env@16.2.6': {} + '@next/env@16.2.11': {} '@next/eslint-plugin-next@15.5.4': dependencies: @@ -20487,52 +20491,52 @@ snapshots: '@mdx-js/loader': 3.1.1(supports-color@8.1.1)(webpack@5.105.4(esbuild@0.28.1)) '@mdx-js/react': 3.1.1(@types/react@19.2.14)(react@19.2.6) - '@next/swc-darwin-arm64@15.5.18': + '@next/swc-darwin-arm64@15.5.21': optional: true - '@next/swc-darwin-arm64@16.2.6': + '@next/swc-darwin-arm64@16.2.11': optional: true - '@next/swc-darwin-x64@15.5.18': + '@next/swc-darwin-x64@15.5.21': optional: true - '@next/swc-darwin-x64@16.2.6': + '@next/swc-darwin-x64@16.2.11': optional: true - '@next/swc-linux-arm64-gnu@15.5.18': + '@next/swc-linux-arm64-gnu@15.5.21': optional: true - '@next/swc-linux-arm64-gnu@16.2.6': + '@next/swc-linux-arm64-gnu@16.2.11': optional: true - '@next/swc-linux-arm64-musl@15.5.18': + '@next/swc-linux-arm64-musl@15.5.21': optional: true - '@next/swc-linux-arm64-musl@16.2.6': + '@next/swc-linux-arm64-musl@16.2.11': optional: true - '@next/swc-linux-x64-gnu@15.5.18': + '@next/swc-linux-x64-gnu@15.5.21': optional: true - '@next/swc-linux-x64-gnu@16.2.6': + '@next/swc-linux-x64-gnu@16.2.11': optional: true - '@next/swc-linux-x64-musl@15.5.18': + '@next/swc-linux-x64-musl@15.5.21': optional: true - '@next/swc-linux-x64-musl@16.2.6': + '@next/swc-linux-x64-musl@16.2.11': optional: true - '@next/swc-win32-arm64-msvc@15.5.18': + '@next/swc-win32-arm64-msvc@15.5.21': optional: true - '@next/swc-win32-arm64-msvc@16.2.6': + '@next/swc-win32-arm64-msvc@16.2.11': optional: true - '@next/swc-win32-x64-msvc@15.5.18': + '@next/swc-win32-x64-msvc@15.5.21': optional: true - '@next/swc-win32-x64-msvc@16.2.6': + '@next/swc-win32-x64-msvc@16.2.11': optional: true '@ngrok/ngrok-android-arm64@1.6.0': @@ -20846,9 +20850,9 @@ snapshots: '@rollup/plugin-replace': 6.0.3(rollup@4.60.3) '@vitejs/plugin-vue': 6.0.7(vite@7.3.5(@types/node@22.13.14)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0))(vue@3.5.35(typescript@6.0.2)) '@vitejs/plugin-vue-jsx': 5.1.5(supports-color@8.1.1)(vite@7.3.5(@types/node@22.13.14)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0))(vue@3.5.35(typescript@6.0.2)) - autoprefixer: 10.5.0(postcss@8.5.10) + autoprefixer: 10.5.0(postcss@8.5.22) consola: 3.4.2 - cssnano: 8.0.1(postcss@8.5.10) + cssnano: 8.0.1(postcss@8.5.22) defu: 6.1.7 escape-string-regexp: 5.0.0 exsolve: 1.0.8 @@ -20862,7 +20866,7 @@ snapshots: nypm: 0.6.6 pathe: 2.0.3 pkg-types: 2.3.1 - postcss: 8.5.10 + postcss: 8.5.22 seroval: 1.5.4 std-env: 4.1.0 ufo: 1.6.4 @@ -22361,7 +22365,7 @@ snapshots: dependencies: react: 19.2.6 - '@react-router/dev@7.13.2(@react-router/serve@7.17.0(react-router@7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(supports-color@8.1.1)(typescript@6.0.2))(@types/node@22.13.14)(babel-plugin-macros@3.1.0)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(sass@1.77.4)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.22.4)(typescript@6.0.2)(vite@8.0.16(@types/node@22.13.14)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0))(yaml@2.9.0)': + '@react-router/dev@7.13.2(@react-router/serve@7.17.0(react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(supports-color@8.1.1)(typescript@6.0.2))(@types/node@22.13.14)(babel-plugin-macros@3.1.0)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(sass@1.77.4)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.22.4)(typescript@6.0.2)(vite@8.0.16(@types/node@22.13.14)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0))(yaml@2.9.0)': dependencies: '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/generator': 7.29.0 @@ -22370,7 +22374,7 @@ snapshots: '@babel/preset-typescript': 7.27.1(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) '@babel/traverse': 7.29.0(supports-color@8.1.1) '@babel/types': 7.29.0 - '@react-router/node': 7.13.2(react-router@7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@6.0.2) + '@react-router/node': 7.13.2(react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@6.0.2) '@remix-run/node-fetch-server': 0.13.0 arg: 5.0.2 babel-dead-code-elimination: 1.0.12(supports-color@8.1.1) @@ -22387,14 +22391,14 @@ snapshots: pkg-types: 2.3.0 prettier: 3.8.1 react-refresh: 0.14.2 - react-router: 7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react-router: 7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6) semver: 7.7.4 tinyglobby: 0.2.15 - valibot: 1.2.0(typescript@6.0.2) + valibot: 1.4.2(typescript@6.0.2) vite: 8.0.16(@types/node@22.13.14)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0) vite-node: 3.2.4(@types/node@22.13.14)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.77.4)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0) optionalDependencies: - '@react-router/serve': 7.17.0(react-router@7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(supports-color@8.1.1)(typescript@6.0.2) + '@react-router/serve': 7.17.0(react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(supports-color@8.1.1)(typescript@6.0.2) typescript: 6.0.2 transitivePeerDependencies: - '@types/node' @@ -22411,7 +22415,7 @@ snapshots: - tsx - yaml - '@react-router/dev@7.17.0(@react-router/serve@7.17.0(react-router@7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(supports-color@8.1.1)(typescript@6.0.2))(@types/node@22.13.14)(babel-plugin-macros@3.1.0)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(sass@1.77.4)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.22.4)(typescript@6.0.2)(vite@7.3.5(@types/node@22.13.14)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0))(yaml@2.9.0)': + '@react-router/dev@7.17.0(@react-router/serve@7.17.0(react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(supports-color@8.1.1)(typescript@6.0.2))(@types/node@22.13.14)(babel-plugin-macros@3.1.0)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(sass@1.77.4)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.22.4)(typescript@6.0.2)(vite@7.3.5(@types/node@22.13.14)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0))(yaml@2.9.0)': dependencies: '@babel/core': 7.29.7(supports-color@8.1.1) '@babel/generator': 7.29.0 @@ -22420,7 +22424,7 @@ snapshots: '@babel/preset-typescript': 7.27.1(@babel/core@7.29.7(supports-color@8.1.1))(supports-color@8.1.1) '@babel/traverse': 7.29.0(supports-color@8.1.1) '@babel/types': 7.29.7 - '@react-router/node': 7.17.0(react-router@7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@6.0.2) + '@react-router/node': 7.17.0(react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@6.0.2) '@remix-run/node-fetch-server': 0.13.0 arg: 5.0.2 babel-dead-code-elimination: 1.0.12(supports-color@8.1.1) @@ -22437,14 +22441,14 @@ snapshots: pkg-types: 2.3.1 prettier: 3.8.1 react-refresh: 0.14.2 - react-router: 7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react-router: 7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6) semver: 7.8.1 tinyglobby: 0.2.16 - valibot: 1.2.0(typescript@6.0.2) + valibot: 1.4.2(typescript@6.0.2) vite: 7.3.5(@types/node@22.13.14)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0) vite-node: 3.2.4(@types/node@22.13.14)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.77.4)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0) optionalDependencies: - '@react-router/serve': 7.17.0(react-router@7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(supports-color@8.1.1)(typescript@6.0.2) + '@react-router/serve': 7.17.0(react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(supports-color@8.1.1)(typescript@6.0.2) typescript: 6.0.2 transitivePeerDependencies: - '@types/node' @@ -22461,52 +22465,52 @@ snapshots: - tsx - yaml - '@react-router/express@7.17.0(express@4.22.1(supports-color@8.1.1))(react-router@7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@6.0.2)': + '@react-router/express@7.17.0(express@4.22.1(supports-color@8.1.1))(react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@6.0.2)': dependencies: - '@react-router/node': 7.17.0(react-router@7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@6.0.2) + '@react-router/node': 7.17.0(react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@6.0.2) express: 4.22.1(supports-color@8.1.1) - react-router: 7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react-router: 7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6) optionalDependencies: typescript: 6.0.2 - '@react-router/fs-routes@7.17.0(@react-router/dev@7.17.0(@react-router/serve@7.17.0(react-router@7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(supports-color@8.1.1)(typescript@6.0.2))(@types/node@22.13.14)(babel-plugin-macros@3.1.0)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(sass@1.77.4)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.22.4)(typescript@6.0.2)(vite@7.3.5(@types/node@22.13.14)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0))(yaml@2.9.0))(typescript@6.0.2)': + '@react-router/fs-routes@7.17.0(@react-router/dev@7.17.0(@react-router/serve@7.17.0(react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(supports-color@8.1.1)(typescript@6.0.2))(@types/node@22.13.14)(babel-plugin-macros@3.1.0)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(sass@1.77.4)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.22.4)(typescript@6.0.2)(vite@7.3.5(@types/node@22.13.14)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0))(yaml@2.9.0))(typescript@6.0.2)': dependencies: - '@react-router/dev': 7.17.0(@react-router/serve@7.17.0(react-router@7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(supports-color@8.1.1)(typescript@6.0.2))(@types/node@22.13.14)(babel-plugin-macros@3.1.0)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(sass@1.77.4)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.22.4)(typescript@6.0.2)(vite@7.3.5(@types/node@22.13.14)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0))(yaml@2.9.0) + '@react-router/dev': 7.17.0(@react-router/serve@7.17.0(react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(supports-color@8.1.1)(typescript@6.0.2))(@types/node@22.13.14)(babel-plugin-macros@3.1.0)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(sass@1.77.4)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.22.4)(typescript@6.0.2)(vite@7.3.5(@types/node@22.13.14)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0))(yaml@2.9.0) minimatch: 9.0.7 optionalDependencies: typescript: 6.0.2 - '@react-router/fs-routes@7.4.0(@react-router/dev@7.13.2(@react-router/serve@7.17.0(react-router@7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(supports-color@8.1.1)(typescript@6.0.2))(@types/node@22.13.14)(babel-plugin-macros@3.1.0)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(sass@1.77.4)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.22.4)(typescript@6.0.2)(vite@8.0.16(@types/node@22.13.14)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0))(yaml@2.9.0))(typescript@6.0.2)': + '@react-router/fs-routes@7.4.0(@react-router/dev@7.13.2(@react-router/serve@7.17.0(react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(supports-color@8.1.1)(typescript@6.0.2))(@types/node@22.13.14)(babel-plugin-macros@3.1.0)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(sass@1.77.4)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.22.4)(typescript@6.0.2)(vite@8.0.16(@types/node@22.13.14)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0))(yaml@2.9.0))(typescript@6.0.2)': dependencies: - '@react-router/dev': 7.13.2(@react-router/serve@7.17.0(react-router@7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(supports-color@8.1.1)(typescript@6.0.2))(@types/node@22.13.14)(babel-plugin-macros@3.1.0)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(sass@1.77.4)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.22.4)(typescript@6.0.2)(vite@8.0.16(@types/node@22.13.14)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0))(yaml@2.9.0) + '@react-router/dev': 7.13.2(@react-router/serve@7.17.0(react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(supports-color@8.1.1)(typescript@6.0.2))(@types/node@22.13.14)(babel-plugin-macros@3.1.0)(jiti@2.7.0)(lightningcss@1.32.0)(react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(sass@1.77.4)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.22.4)(typescript@6.0.2)(vite@8.0.16(@types/node@22.13.14)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0))(yaml@2.9.0) minimatch: 9.0.7 optionalDependencies: typescript: 6.0.2 - '@react-router/node@7.13.2(react-router@7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@6.0.2)': + '@react-router/node@7.13.2(react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@6.0.2)': dependencies: '@mjackson/node-fetch-server': 0.2.0 - react-router: 7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react-router: 7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6) optionalDependencies: typescript: 6.0.2 - '@react-router/node@7.17.0(react-router@7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@6.0.2)': + '@react-router/node@7.17.0(react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@6.0.2)': dependencies: '@mjackson/node-fetch-server': 0.2.0 - react-router: 7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react-router: 7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6) optionalDependencies: typescript: 6.0.2 - '@react-router/serve@7.17.0(react-router@7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(supports-color@8.1.1)(typescript@6.0.2)': + '@react-router/serve@7.17.0(react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(supports-color@8.1.1)(typescript@6.0.2)': dependencies: '@mjackson/node-fetch-server': 0.2.0 - '@react-router/express': 7.17.0(express@4.22.1(supports-color@8.1.1))(react-router@7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@6.0.2) - '@react-router/node': 7.17.0(react-router@7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@6.0.2) + '@react-router/express': 7.17.0(express@4.22.1(supports-color@8.1.1))(react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@6.0.2) + '@react-router/node': 7.17.0(react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(typescript@6.0.2) compression: 1.8.1(supports-color@8.1.1) express: 4.22.1(supports-color@8.1.1) get-port: 5.1.1 morgan: 1.11.0(supports-color@8.1.1) - react-router: 7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + react-router: 7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6) source-map-support: 0.5.21 transitivePeerDependencies: - supports-color @@ -22846,7 +22850,7 @@ snapshots: dependencies: '@sentry/core': 10.59.0 - '@sentry/nextjs@10.59.0(@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.8.0(@opentelemetry/api@1.9.1))(encoding@0.1.13)(next@15.5.18(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react@19.2.6)(supports-color@8.1.1)(vite@8.0.16(@types/node@22.13.14)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0))(webpack@5.105.4(esbuild@0.28.1))': + '@sentry/nextjs@10.59.0(@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.8.0(@opentelemetry/api@1.9.1))(encoding@0.1.13)(next@15.5.21(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react@19.2.6)(supports-color@8.1.1)(vite@8.0.16(@types/node@22.13.14)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0))(webpack@5.105.4(esbuild@0.28.1))': dependencies: '@opentelemetry/api': 1.9.1 '@rollup/plugin-commonjs': 28.0.1(rollup@4.60.3) @@ -22859,7 +22863,7 @@ snapshots: '@sentry/react': 10.59.0(react@19.2.6) '@sentry/vercel-edge': 10.59.0 '@sentry/webpack-plugin': 5.3.0(encoding@0.1.13)(supports-color@8.1.1)(webpack@5.105.4(esbuild@0.28.1)) - next: 15.5.18(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4) + next: 15.5.21(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4) rollup: 4.60.3 stacktrace-parser: 0.1.11 transitivePeerDependencies: @@ -22872,7 +22876,7 @@ snapshots: - vite - webpack - '@sentry/nextjs@10.59.0(@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.8.0(@opentelemetry/api@1.9.1))(encoding@0.1.13)(next@16.2.6(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react@19.2.6)(supports-color@8.1.1)(vite@8.0.16(@types/node@22.13.14)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0))(webpack@5.105.4(esbuild@0.28.1))': + '@sentry/nextjs@10.59.0(@opentelemetry/core@2.8.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.8.0(@opentelemetry/api@1.9.1))(encoding@0.1.13)(next@16.2.11(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react@19.2.6)(supports-color@8.1.1)(vite@8.0.16(@types/node@22.13.14)(esbuild@0.28.1)(jiti@2.7.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0))(webpack@5.105.4(esbuild@0.28.1))': dependencies: '@opentelemetry/api': 1.9.1 '@rollup/plugin-commonjs': 28.0.1(rollup@4.60.3) @@ -22885,7 +22889,7 @@ snapshots: '@sentry/react': 10.59.0(react@19.2.6) '@sentry/vercel-edge': 10.59.0 '@sentry/webpack-plugin': 5.3.0(encoding@0.1.13)(supports-color@8.1.1)(webpack@5.105.4(esbuild@0.28.1)) - next: 16.2.6(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4) + next: 16.2.11(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4) rollup: 4.60.3 stacktrace-parser: 0.1.11 transitivePeerDependencies: @@ -23766,7 +23770,7 @@ snapshots: '@alloc/quick-lru': 5.2.0 '@tailwindcss/node': 4.2.4 '@tailwindcss/oxide': 4.2.4 - postcss: 8.5.10 + postcss: 8.5.22 tailwindcss: 4.2.4 '@tailwindcss/typography@0.5.19(tailwindcss@4.2.4)': @@ -24997,7 +25001,7 @@ snapshots: '@vue/shared': 3.5.35 estree-walker: 2.0.2 magic-string: 0.30.21 - postcss: 8.5.10 + postcss: 8.5.22 source-map-js: 1.2.1 '@vue/compiler-ssr@3.5.35': @@ -25317,7 +25321,7 @@ snapshots: ajv@8.18.0: dependencies: fast-deep-equal: 3.1.3 - fast-uri: 3.1.2 + fast-uri: 3.1.4 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 @@ -25540,13 +25544,13 @@ snapshots: dependencies: gulp-header: 1.8.12 - autoprefixer@10.5.0(postcss@8.5.10): + autoprefixer@10.5.0(postcss@8.5.22): dependencies: browserslist: 4.28.2 caniuse-lite: 1.0.30001792 fraction.js: 5.3.4 picocolors: 1.1.1 - postcss: 8.5.10 + postcss: 8.5.22 postcss-value-parser: 4.2.0 available-typed-arrays@1.0.7: @@ -25723,6 +25727,10 @@ snapshots: dependencies: balanced-match: 4.0.4 + brace-expansion@5.0.8: + dependencies: + balanced-match: 4.0.4 + braces@3.0.3: dependencies: fill-range: 7.1.1 @@ -25825,7 +25833,7 @@ snapshots: minipass-pipeline: 1.2.4 p-map: 4.0.0 ssri: 10.0.6 - tar: 7.5.20 + tar: 7.5.21 unique-filename: 3.0.0 call-bind-apply-helpers@1.0.2: @@ -26449,48 +26457,48 @@ snapshots: cssesc@3.0.0: {} - cssnano-preset-default@8.0.1(postcss@8.5.10): + cssnano-preset-default@8.0.1(postcss@8.5.22): dependencies: browserslist: 4.28.2 - cssnano-utils: 6.0.0(postcss@8.5.10) - postcss: 8.5.10 - postcss-calc: 10.1.1(postcss@8.5.10) - postcss-colormin: 8.0.0(postcss@8.5.10) - postcss-convert-values: 8.0.0(postcss@8.5.10) - postcss-discard-comments: 8.0.0(postcss@8.5.10) - postcss-discard-duplicates: 8.0.0(postcss@8.5.10) - postcss-discard-empty: 8.0.0(postcss@8.5.10) - postcss-discard-overridden: 8.0.0(postcss@8.5.10) - postcss-merge-longhand: 8.0.0(postcss@8.5.10) - postcss-merge-rules: 8.0.0(postcss@8.5.10) - postcss-minify-font-values: 8.0.0(postcss@8.5.10) - postcss-minify-gradients: 8.0.0(postcss@8.5.10) - postcss-minify-params: 8.0.0(postcss@8.5.10) - postcss-minify-selectors: 8.0.1(postcss@8.5.10) - postcss-normalize-charset: 8.0.0(postcss@8.5.10) - postcss-normalize-display-values: 8.0.0(postcss@8.5.10) - postcss-normalize-positions: 8.0.0(postcss@8.5.10) - postcss-normalize-repeat-style: 8.0.0(postcss@8.5.10) - postcss-normalize-string: 8.0.0(postcss@8.5.10) - postcss-normalize-timing-functions: 8.0.0(postcss@8.5.10) - postcss-normalize-unicode: 8.0.0(postcss@8.5.10) - postcss-normalize-url: 8.0.0(postcss@8.5.10) - postcss-normalize-whitespace: 8.0.0(postcss@8.5.10) - postcss-ordered-values: 8.0.0(postcss@8.5.10) - postcss-reduce-initial: 8.0.0(postcss@8.5.10) - postcss-reduce-transforms: 8.0.0(postcss@8.5.10) - postcss-svgo: 8.0.0(postcss@8.5.10) - postcss-unique-selectors: 8.0.0(postcss@8.5.10) - - cssnano-utils@6.0.0(postcss@8.5.10): - dependencies: - postcss: 8.5.10 - - cssnano@8.0.1(postcss@8.5.10): - dependencies: - cssnano-preset-default: 8.0.1(postcss@8.5.10) + cssnano-utils: 6.0.0(postcss@8.5.22) + postcss: 8.5.22 + postcss-calc: 10.1.1(postcss@8.5.22) + postcss-colormin: 8.0.0(postcss@8.5.22) + postcss-convert-values: 8.0.0(postcss@8.5.22) + postcss-discard-comments: 8.0.0(postcss@8.5.22) + postcss-discard-duplicates: 8.0.0(postcss@8.5.22) + postcss-discard-empty: 8.0.0(postcss@8.5.22) + postcss-discard-overridden: 8.0.0(postcss@8.5.22) + postcss-merge-longhand: 8.0.0(postcss@8.5.22) + postcss-merge-rules: 8.0.0(postcss@8.5.22) + postcss-minify-font-values: 8.0.0(postcss@8.5.22) + postcss-minify-gradients: 8.0.0(postcss@8.5.22) + postcss-minify-params: 8.0.0(postcss@8.5.22) + postcss-minify-selectors: 8.0.1(postcss@8.5.22) + postcss-normalize-charset: 8.0.0(postcss@8.5.22) + postcss-normalize-display-values: 8.0.0(postcss@8.5.22) + postcss-normalize-positions: 8.0.0(postcss@8.5.22) + postcss-normalize-repeat-style: 8.0.0(postcss@8.5.22) + postcss-normalize-string: 8.0.0(postcss@8.5.22) + postcss-normalize-timing-functions: 8.0.0(postcss@8.5.22) + postcss-normalize-unicode: 8.0.0(postcss@8.5.22) + postcss-normalize-url: 8.0.0(postcss@8.5.22) + postcss-normalize-whitespace: 8.0.0(postcss@8.5.22) + postcss-ordered-values: 8.0.0(postcss@8.5.22) + postcss-reduce-initial: 8.0.0(postcss@8.5.22) + postcss-reduce-transforms: 8.0.0(postcss@8.5.22) + postcss-svgo: 8.0.0(postcss@8.5.22) + postcss-unique-selectors: 8.0.0(postcss@8.5.22) + + cssnano-utils@6.0.0(postcss@8.5.22): + dependencies: + postcss: 8.5.22 + + cssnano@8.0.1(postcss@8.5.22): + dependencies: + cssnano-preset-default: 8.0.1(postcss@8.5.22) lilconfig: 3.1.3 - postcss: 8.5.10 + postcss: 8.5.22 csso@5.0.5: dependencies: @@ -27764,7 +27772,7 @@ snapshots: dependencies: fast-string-truncated-width: 3.0.3 - fast-uri@3.1.2: {} + fast-uri@3.1.4: {} fast-wrap-ansi@0.2.2: dependencies: @@ -27897,13 +27905,13 @@ snapshots: locate-path: 6.0.0 path-exists: 4.0.0 - flags@4.0.1(@opentelemetry/api@1.9.1)(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react-dom@19.2.6(react@19.2.6))(react@19.2.6): + flags@4.0.1(@opentelemetry/api@1.9.1)(next@16.2.11(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: '@edge-runtime/cookies': 5.0.2 jose: 5.9.6 optionalDependencies: '@opentelemetry/api': 1.9.1 - next: 16.2.6(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4) + next: 16.2.11(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) @@ -28730,7 +28738,7 @@ snapshots: immutable@3.8.3: {} - immutable@4.3.8: + immutable@4.3.9: optional: true import-fresh@3.3.0: @@ -30749,7 +30757,7 @@ snapshots: minimatch@10.2.3: dependencies: - brace-expansion: 5.0.7 + brace-expansion: 5.0.8 minimatch@3.1.4: dependencies: @@ -30958,7 +30966,7 @@ snapshots: stacktrace-js: 2.0.2 stylis: 4.3.6 - nanoid@3.3.11: {} + nanoid@3.3.16: {} nanotar@0.3.0: {} @@ -30979,12 +30987,12 @@ snapshots: neo-async@2.6.2: {} - next-contentlayer2@0.4.6(contentlayer2@0.4.6(esbuild@0.28.1)(markdown-wasm@1.2.0)(supports-color@8.1.1))(esbuild@0.28.1)(markdown-wasm@1.2.0)(next@16.2.6(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(supports-color@8.1.1): + next-contentlayer2@0.4.6(contentlayer2@0.4.6(esbuild@0.28.1)(markdown-wasm@1.2.0)(supports-color@8.1.1))(esbuild@0.28.1)(markdown-wasm@1.2.0)(next@16.2.11(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(supports-color@8.1.1): dependencies: '@contentlayer2/core': 0.4.3(esbuild@0.28.1)(markdown-wasm@1.2.0)(supports-color@8.1.1) '@contentlayer2/utils': 0.4.3 contentlayer2: 0.4.6(esbuild@0.28.1)(markdown-wasm@1.2.0)(supports-color@8.1.1) - next: 16.2.6(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4) + next: 16.2.11(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) transitivePeerDependencies: @@ -31013,14 +31021,14 @@ snapshots: dependencies: js-yaml-loader: 1.2.2 - next-router-mock@0.9.13(next@16.2.6(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react@19.2.6): + next-router-mock@0.9.13(next@16.2.11(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react@19.2.6): dependencies: - next: 16.2.6(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4) + next: 16.2.11(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4) react: 19.2.6 - next-seo@6.5.0(next@15.5.18(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react-dom@19.2.6(react@19.2.6))(react@19.2.6): + next-seo@6.5.0(next@15.5.21(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: - next: 15.5.18(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4) + next: 15.5.21(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4) react: 19.2.6 react-dom: 19.2.6(react@19.2.6) @@ -31031,24 +31039,24 @@ snapshots: next-tick@1.1.0: {} - next@15.5.18(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4): + next@15.5.21(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4): dependencies: - '@next/env': 15.5.18 + '@next/env': 15.5.21 '@swc/helpers': 0.5.15 caniuse-lite: 1.0.30001792 - postcss: 8.5.10 + postcss: 8.5.22 react: 19.2.6 react-dom: 19.2.6(react@19.2.6) styled-jsx: 5.1.6(@babel/core@7.29.7(supports-color@8.1.1))(babel-plugin-macros@3.1.0)(react@19.2.6) optionalDependencies: - '@next/swc-darwin-arm64': 15.5.18 - '@next/swc-darwin-x64': 15.5.18 - '@next/swc-linux-arm64-gnu': 15.5.18 - '@next/swc-linux-arm64-musl': 15.5.18 - '@next/swc-linux-x64-gnu': 15.5.18 - '@next/swc-linux-x64-musl': 15.5.18 - '@next/swc-win32-arm64-msvc': 15.5.18 - '@next/swc-win32-x64-msvc': 15.5.18 + '@next/swc-darwin-arm64': 15.5.21 + '@next/swc-darwin-x64': 15.5.21 + '@next/swc-linux-arm64-gnu': 15.5.21 + '@next/swc-linux-arm64-musl': 15.5.21 + '@next/swc-linux-x64-gnu': 15.5.21 + '@next/swc-linux-x64-musl': 15.5.21 + '@next/swc-win32-arm64-msvc': 15.5.21 + '@next/swc-win32-x64-msvc': 15.5.21 '@opentelemetry/api': 1.9.1 '@playwright/test': 1.59.1 sass: 1.77.4 @@ -31057,25 +31065,25 @@ snapshots: - '@babel/core' - babel-plugin-macros - next@16.2.6(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4): + next@16.2.11(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4): dependencies: - '@next/env': 16.2.6 + '@next/env': 16.2.11 '@swc/helpers': 0.5.15 baseline-browser-mapping: 2.10.29 caniuse-lite: 1.0.30001792 - postcss: 8.5.10 + postcss: 8.5.22 react: 19.2.6 react-dom: 19.2.6(react@19.2.6) styled-jsx: 5.1.6(@babel/core@7.29.7(supports-color@8.1.1))(babel-plugin-macros@3.1.0)(react@19.2.6) optionalDependencies: - '@next/swc-darwin-arm64': 16.2.6 - '@next/swc-darwin-x64': 16.2.6 - '@next/swc-linux-arm64-gnu': 16.2.6 - '@next/swc-linux-arm64-musl': 16.2.6 - '@next/swc-linux-x64-gnu': 16.2.6 - '@next/swc-linux-x64-musl': 16.2.6 - '@next/swc-win32-arm64-msvc': 16.2.6 - '@next/swc-win32-x64-msvc': 16.2.6 + '@next/swc-darwin-arm64': 16.2.11 + '@next/swc-darwin-x64': 16.2.11 + '@next/swc-linux-arm64-gnu': 16.2.11 + '@next/swc-linux-arm64-musl': 16.2.11 + '@next/swc-linux-x64-gnu': 16.2.11 + '@next/swc-linux-x64-musl': 16.2.11 + '@next/swc-win32-arm64-msvc': 16.2.11 + '@next/swc-win32-x64-msvc': 16.2.11 '@opentelemetry/api': 1.9.1 '@playwright/test': 1.59.1 sass: 1.77.4 @@ -31228,7 +31236,7 @@ snapshots: nopt: 7.2.1 proc-log: 3.0.0 semver: 7.8.1 - tar: 7.5.20 + tar: 7.5.21 which: 4.0.0 transitivePeerDependencies: - supports-color @@ -31332,28 +31340,28 @@ snapshots: number-flow@0.3.7: {} - nuqs@1.19.1(next@15.5.18(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4)): + nuqs@1.19.1(next@15.5.21(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4)): dependencies: mitt: 3.0.1 - next: 15.5.18(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4) + next: 15.5.21(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4) - nuqs@2.7.1(@tanstack/react-router@1.170.10(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(next@16.2.6(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react-router@7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react@19.2.6): + nuqs@2.7.1(@tanstack/react-router@1.170.10(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(next@16.2.11(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react@19.2.6): dependencies: '@standard-schema/spec': 1.0.0 react: 19.2.6 optionalDependencies: '@tanstack/react-router': 1.170.10(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - next: 16.2.6(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4) - react-router: 7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + next: 16.2.11(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(babel-plugin-macros@3.1.0)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4) + react-router: 7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - nuqs@2.8.1(@tanstack/react-router@1.170.10(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(next@15.5.18(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react-router@7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react@19.2.6): + nuqs@2.8.1(@tanstack/react-router@1.170.10(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(next@15.5.21(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6))(react@19.2.6): dependencies: '@standard-schema/spec': 1.0.0 react: 19.2.6 optionalDependencies: '@tanstack/react-router': 1.170.10(react-dom@19.2.6(react@19.2.6))(react@19.2.6) - next: 15.5.18(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4) - react-router: 7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6) + next: 15.5.21(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4) + react-router: 7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6) nuxt@4.4.8(@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.29.7(supports-color@8.1.1)))(@babel/plugin-syntax-typescript@7.28.6(@babel/core@7.29.7(supports-color@8.1.1)))(@electric-sql/pglite@0.4.5)(@parcel/watcher@2.5.6)(@types/node@22.13.14)(@vue/compiler-sfc@3.5.35)(aws4fetch@1.0.20)(cac@6.7.14)(db0@0.3.4(@electric-sql/pglite@0.4.5))(encoding@0.1.13)(eslint@9.37.0(jiti@2.7.0)(supports-color@8.1.1))(ioredis@5.10.1(supports-color@8.1.1))(lightningcss@1.32.0)(magicast@0.5.2)(rolldown@1.0.3)(rollup-plugin-visualizer@7.0.1(rolldown@1.0.3)(rollup@4.60.3))(rollup@4.60.3)(sass@1.77.4)(supports-color@8.1.1)(terser@5.39.0)(tsx@4.22.4)(typescript@6.0.2)(vite@7.3.5(@types/node@22.13.14)(jiti@2.7.0)(lightningcss@1.32.0)(sass@1.77.4)(terser@5.39.0)(tsx@4.22.4)(yaml@2.9.0))(yaml@2.9.0): dependencies: @@ -32065,144 +32073,144 @@ snapshots: possible-typed-array-names@1.0.0: {} - postcss-calc@10.1.1(postcss@8.5.10): + postcss-calc@10.1.1(postcss@8.5.22): dependencies: - postcss: 8.5.10 + postcss: 8.5.22 postcss-selector-parser: 7.1.1 postcss-value-parser: 4.2.0 - postcss-colormin@8.0.0(postcss@8.5.10): + postcss-colormin@8.0.0(postcss@8.5.22): dependencies: '@colordx/core': 5.4.3 browserslist: 4.28.2 caniuse-api: 3.0.0 - postcss: 8.5.10 + postcss: 8.5.22 postcss-value-parser: 4.2.0 - postcss-convert-values@8.0.0(postcss@8.5.10): + postcss-convert-values@8.0.0(postcss@8.5.22): dependencies: browserslist: 4.28.2 - postcss: 8.5.10 + postcss: 8.5.22 postcss-value-parser: 4.2.0 - postcss-discard-comments@8.0.0(postcss@8.5.10): + postcss-discard-comments@8.0.0(postcss@8.5.22): dependencies: - postcss: 8.5.10 + postcss: 8.5.22 postcss-selector-parser: 7.1.1 - postcss-discard-duplicates@8.0.0(postcss@8.5.10): + postcss-discard-duplicates@8.0.0(postcss@8.5.22): dependencies: - postcss: 8.5.10 + postcss: 8.5.22 - postcss-discard-empty@8.0.0(postcss@8.5.10): + postcss-discard-empty@8.0.0(postcss@8.5.22): dependencies: - postcss: 8.5.10 + postcss: 8.5.22 - postcss-discard-overridden@8.0.0(postcss@8.5.10): + postcss-discard-overridden@8.0.0(postcss@8.5.22): dependencies: - postcss: 8.5.10 + postcss: 8.5.22 - postcss-merge-longhand@8.0.0(postcss@8.5.10): + postcss-merge-longhand@8.0.0(postcss@8.5.22): dependencies: - postcss: 8.5.10 + postcss: 8.5.22 postcss-value-parser: 4.2.0 - stylehacks: 8.0.0(postcss@8.5.10) + stylehacks: 8.0.0(postcss@8.5.22) - postcss-merge-rules@8.0.0(postcss@8.5.10): + postcss-merge-rules@8.0.0(postcss@8.5.22): dependencies: browserslist: 4.28.2 caniuse-api: 3.0.0 - cssnano-utils: 6.0.0(postcss@8.5.10) - postcss: 8.5.10 + cssnano-utils: 6.0.0(postcss@8.5.22) + postcss: 8.5.22 postcss-selector-parser: 7.1.1 - postcss-minify-font-values@8.0.0(postcss@8.5.10): + postcss-minify-font-values@8.0.0(postcss@8.5.22): dependencies: - postcss: 8.5.10 + postcss: 8.5.22 postcss-value-parser: 4.2.0 - postcss-minify-gradients@8.0.0(postcss@8.5.10): + postcss-minify-gradients@8.0.0(postcss@8.5.22): dependencies: '@colordx/core': 5.4.3 - cssnano-utils: 6.0.0(postcss@8.5.10) - postcss: 8.5.10 + cssnano-utils: 6.0.0(postcss@8.5.22) + postcss: 8.5.22 postcss-value-parser: 4.2.0 - postcss-minify-params@8.0.0(postcss@8.5.10): + postcss-minify-params@8.0.0(postcss@8.5.22): dependencies: browserslist: 4.28.2 - cssnano-utils: 6.0.0(postcss@8.5.10) - postcss: 8.5.10 + cssnano-utils: 6.0.0(postcss@8.5.22) + postcss: 8.5.22 postcss-value-parser: 4.2.0 - postcss-minify-selectors@8.0.1(postcss@8.5.10): + postcss-minify-selectors@8.0.1(postcss@8.5.22): dependencies: browserslist: 4.28.2 caniuse-api: 3.0.0 cssesc: 3.0.0 - postcss: 8.5.10 + postcss: 8.5.22 postcss-selector-parser: 7.1.1 - postcss-normalize-charset@8.0.0(postcss@8.5.10): + postcss-normalize-charset@8.0.0(postcss@8.5.22): dependencies: - postcss: 8.5.10 + postcss: 8.5.22 - postcss-normalize-display-values@8.0.0(postcss@8.5.10): + postcss-normalize-display-values@8.0.0(postcss@8.5.22): dependencies: - postcss: 8.5.10 + postcss: 8.5.22 postcss-value-parser: 4.2.0 - postcss-normalize-positions@8.0.0(postcss@8.5.10): + postcss-normalize-positions@8.0.0(postcss@8.5.22): dependencies: - postcss: 8.5.10 + postcss: 8.5.22 postcss-value-parser: 4.2.0 - postcss-normalize-repeat-style@8.0.0(postcss@8.5.10): + postcss-normalize-repeat-style@8.0.0(postcss@8.5.22): dependencies: - postcss: 8.5.10 + postcss: 8.5.22 postcss-value-parser: 4.2.0 - postcss-normalize-string@8.0.0(postcss@8.5.10): + postcss-normalize-string@8.0.0(postcss@8.5.22): dependencies: - postcss: 8.5.10 + postcss: 8.5.22 postcss-value-parser: 4.2.0 - postcss-normalize-timing-functions@8.0.0(postcss@8.5.10): + postcss-normalize-timing-functions@8.0.0(postcss@8.5.22): dependencies: - postcss: 8.5.10 + postcss: 8.5.22 postcss-value-parser: 4.2.0 - postcss-normalize-unicode@8.0.0(postcss@8.5.10): + postcss-normalize-unicode@8.0.0(postcss@8.5.22): dependencies: browserslist: 4.28.2 - postcss: 8.5.10 + postcss: 8.5.22 postcss-value-parser: 4.2.0 - postcss-normalize-url@8.0.0(postcss@8.5.10): + postcss-normalize-url@8.0.0(postcss@8.5.22): dependencies: - postcss: 8.5.10 + postcss: 8.5.22 postcss-value-parser: 4.2.0 - postcss-normalize-whitespace@8.0.0(postcss@8.5.10): + postcss-normalize-whitespace@8.0.0(postcss@8.5.22): dependencies: - postcss: 8.5.10 + postcss: 8.5.22 postcss-value-parser: 4.2.0 - postcss-ordered-values@8.0.0(postcss@8.5.10): + postcss-ordered-values@8.0.0(postcss@8.5.22): dependencies: - cssnano-utils: 6.0.0(postcss@8.5.10) - postcss: 8.5.10 + cssnano-utils: 6.0.0(postcss@8.5.22) + postcss: 8.5.22 postcss-value-parser: 4.2.0 - postcss-reduce-initial@8.0.0(postcss@8.5.10): + postcss-reduce-initial@8.0.0(postcss@8.5.22): dependencies: browserslist: 4.28.2 caniuse-api: 3.0.0 - postcss: 8.5.10 + postcss: 8.5.22 - postcss-reduce-transforms@8.0.0(postcss@8.5.10): + postcss-reduce-transforms@8.0.0(postcss@8.5.22): dependencies: - postcss: 8.5.10 + postcss: 8.5.22 postcss-value-parser: 4.2.0 postcss-selector-parser@6.0.10: @@ -32215,22 +32223,22 @@ snapshots: cssesc: 3.0.0 util-deprecate: 1.0.2 - postcss-svgo@8.0.0(postcss@8.5.10): + postcss-svgo@8.0.0(postcss@8.5.22): dependencies: - postcss: 8.5.10 + postcss: 8.5.22 postcss-value-parser: 4.2.0 svgo: 4.0.2 - postcss-unique-selectors@8.0.0(postcss@8.5.10): + postcss-unique-selectors@8.0.0(postcss@8.5.22): dependencies: - postcss: 8.5.10 + postcss: 8.5.22 postcss-selector-parser: 7.1.1 postcss-value-parser@4.2.0: {} - postcss@8.5.10: + postcss@8.5.22: dependencies: - nanoid: 3.3.11 + nanoid: 3.3.16 picocolors: 1.1.1 source-map-js: 1.2.1 @@ -32667,7 +32675,7 @@ snapshots: transitivePeerDependencies: - react-dom - react-router@7.17.0(react-dom@19.2.6(react@19.2.6))(react@19.2.6): + react-router@7.18.1(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: cookie: 1.0.2 react: 19.2.6 @@ -33330,7 +33338,7 @@ snapshots: sass@1.77.4: dependencies: chokidar: 3.6.0 - immutable: 4.3.8 + immutable: 4.3.9 source-map-js: 1.2.1 optional: true @@ -33537,7 +33545,7 @@ snapshots: msw: 2.11.3(@types/node@22.13.14)(typescript@6.0.2) node-fetch: 3.3.2 ora: 8.2.0 - postcss: 8.5.10 + postcss: 8.5.22 prompts: 2.4.2 recast: 0.23.11 stringify-object: 5.0.0 @@ -34065,10 +34073,10 @@ snapshots: '@babel/core': 7.29.7(supports-color@8.1.1) babel-plugin-macros: 3.1.0 - stylehacks@8.0.0(postcss@8.5.10): + stylehacks@8.0.0(postcss@8.5.22): dependencies: browserslist: 4.28.2 - postcss: 8.5.10 + postcss: 8.5.22 postcss-selector-parser: 7.1.1 stylis@4.3.6: {} @@ -34086,7 +34094,7 @@ snapshots: bin-links: 6.0.0 https-proxy-agent: 7.0.6(supports-color@8.1.1) node-fetch: 3.3.2 - tar: 7.5.20 + tar: 7.5.21 transitivePeerDependencies: - supports-color @@ -34159,7 +34167,7 @@ snapshots: fast-fifo: 1.3.2 streamx: 2.22.0 - tar@7.5.20: + tar@7.5.21: dependencies: '@isaacs/fs-minipass': 4.0.1 chownr: 3.0.0 @@ -34531,12 +34539,12 @@ snapshots: unicorn-magic@0.4.0: {} - unicornstudio-react@2.0.1-1(next@15.5.18(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react-dom@19.2.6(react@19.2.6))(react@19.2.6): + unicornstudio-react@2.0.1-1(next@15.5.21(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4))(react-dom@19.2.6(react@19.2.6))(react@19.2.6): dependencies: react: 19.2.6 react-dom: 19.2.6(react@19.2.6) optionalDependencies: - next: 15.5.18(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4) + next: 15.5.21(@babel/core@7.29.7(supports-color@8.1.1))(@opentelemetry/api@1.9.1)(@playwright/test@1.59.1)(react-dom@19.2.6(react@19.2.6))(react@19.2.6)(sass@1.77.4) unified@10.1.2: dependencies: @@ -34837,7 +34845,7 @@ snapshots: kleur: 4.1.5 sade: 1.8.1 - valibot@1.2.0(typescript@6.0.2): + valibot@1.4.2(typescript@6.0.2): optionalDependencies: typescript: 6.0.2 @@ -35054,7 +35062,7 @@ snapshots: esbuild: 0.28.1 fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 - postcss: 8.5.10 + postcss: 8.5.22 rollup: 4.60.3 tinyglobby: 0.2.17 optionalDependencies: @@ -35071,7 +35079,7 @@ snapshots: dependencies: lightningcss: 1.32.0 picomatch: 4.0.4 - postcss: 8.5.10 + postcss: 8.5.22 rolldown: 1.0.3 tinyglobby: 0.2.17 optionalDependencies: diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 31828a1e734a5..0c760aabf7fc5 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -37,9 +37,9 @@ catalog: lodash: ^4.18.1 lodash-es: ^4.18.1 monaco-editor: 0.52.2 - next: 16.2.6 + next: ^16.2.11 next-themes: ^0.4.6 - postcss: ^8.5.10 + postcss: ^8.5.18 radix-ui: ^1.4.3 react: ^19.2.6 react-dom: ^19.2.6 @@ -94,12 +94,12 @@ minimumReleaseAgeExclude: overrides: '@ardatan/relay-compiler>immutable': ^3.8.3 'monaco-editor': 'catalog:' - '@mapbox/node-pre-gyp>tar': ^7.5.19 + '@mapbox/node-pre-gyp>tar': ^7.5.21 '@sentry/webpack-plugin>uuid': ^11.1.1 '@usercentrics/cmp-browser-sdk>uuid': ^11.1.1 braintrust>esbuild: ^0.28.1 braintrust>uuid: ^11.1.1 - cacache>tar: ^7.5.19 + cacache>tar: ^7.5.21 dompurify: ^3.3.2 express-rate-limit>ip-address: ^10.1.1 # Pin h3 v1 to a single version so the Nuxt registry example (vue-blocks) @@ -109,12 +109,12 @@ overrides: lodash: 'catalog:' lodash-es: 'catalog:' mdx-bundler>uuid: ^11.1.1 - node-gyp>tar: ^7.5.19 + node-gyp>tar: ^7.5.21 nodemailer: ^7.0.11 postcss: 'catalog:' qs: ^6.15.2 refractor>prismjs: ^1.30.0 - supabase>tar: ^7.5.19 + supabase>tar: ^7.5.21 tmp: ^0.2.7 vite>esbuild: ^0.28.1 webpack: ^5.104.1 From c16c7e94ccd906015a11d6c0d7efcdb87b82f4b8 Mon Sep 17 00:00:00 2001 From: Charis <26616127+charislam@users.noreply.github.com> Date: Thu, 30 Jul 2026 08:38:11 -0400 Subject: [PATCH 07/12] =?UTF-8?q?feat(studio):=20SQL=20editor=20logs=20sou?= =?UTF-8?q?rce=20=E2=80=94=20toolbar=20UI=20+=20creation=20flow=20(#48452)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## What PR 6 of the SQL-editor "query source (Database vs Logs)" stack (builds on the merged PR 5, #48414). Adds the user-facing toolbar surface for the logs query source and consolidates the SQL-editor toolbar into a single **source menu**. Everything stays behind `sqlEditorLogsSource` + `otelLegacyLogs` (dual-flag gated); with the flags off the toolbar is unchanged. ## Changes - **Consolidated source menu** (`QuerySourceMenu`) — one `Database ▾` / `Logs ▾` dropdown that both labels the snippet's source and hosts the source-specific controls as flyout submenus: - Database: database selector (`Primary` / read replicas), `Run as` (role impersonation), and `Row limit`. - Logs: `Time range` — the same relative presets as the Logs Explorer plus a `Custom range…` calendar dialog. - **Source is immutable** — the Database/Logs rows aren't a toggle. An existing (materialized) snippet opens a *fresh* tab of the target source (never reinterpreting a query against the wrong backend); a blank new tab re-flavors in place. Extracted as the pure, unit-tested `resolveSourceSwitch`. - **New-snippet-with-source** threaded through `/sql/new?source=`, the nav "Create a new logs query" entry, and the duplicate flow. Logs snippets hide the (db-dialect) Export action. - **Run-affordance guard** — the Run button is disabled + annotated for a logs snippet on a non-ClickHouse org (sits above PR 5's execution short-circuit). - **Retention entitlement gating** — both preset and custom logs ranges past `log.retention_days` surface the upgrade prompt instead of applying silently. Prettify is disabled for logs (sql-formatter mangles ClickHouse). ## Tests - `querySource.test.ts` — `logDateRangesEqual` (structural relative/absolute matching, incl. the "Last hour" vs "Last 1 hour" label case). - `QuerySourceMenu.utils.test.ts` — `resolveSourceSwitch` push-vs-replace / no-op behavior. `pnpm --filter studio typecheck` · `lint:ratchet` · Prettier · SQL editor suite (307 tests) all green. ## For reviewers To test manually, enable the `sqlEditorLogsSource` feature flag for yourself on local/staging. There is no nav for Log SQL snippets currently (that is by design, this PR is big enough as-is), so to check an existing logs snippet, you can create one using the existing Logs Explorer, copy its UUID, and force navigate to that snippet in the SQL editor via URL. ## Summary by CodeRabbit * **New Features** * Added support for creating and switching between database and logs queries. * Added log time-range presets and custom date-range selection. * Added database, run-as role, and row-limit controls. * Added read-replica selection, including options to create a new replica when available. * **Improvements** * Added clearer explanations when query execution is unavailable. * Disabled SQL formatting and query export where unsupported for logs queries. --------- Co-authored-by: Joshen Lim --- .../interfaces/SQLEditor/SQLEditorLayout.tsx | 1 + .../QuerySourceMenu/DatabaseSubMenu.tsx | 95 ++++++++++ .../QuerySourceMenu/LogsCustomRangeDialog.tsx | 58 ++++++ .../QuerySourceMenu/QuerySourceMenu.tsx | 167 ++++++++++++++++++ .../QuerySourceMenu.utils.test.ts | 60 +++++++ .../QuerySourceMenu/QuerySourceMenu.utils.ts | 43 +++++ .../QuerySourceMenu/RowLimitSubMenu.tsx | 38 ++++ .../QuerySourceMenu/RunAsSubMenu.tsx | 31 ++++ .../QuerySourceMenu/TimeRangeSubMenu.tsx | 88 +++++++++ .../SQLEditor/UtilityPanel/RunButton.tsx | 17 +- .../SQLEditor/UtilityPanel/UtilityActions.tsx | 106 +++++++---- .../interfaces/SQLEditor/querySource.test.ts | 55 ++++++ .../interfaces/SQLEditor/querySource.ts | 26 +++ .../interfaces/SQLEditor/usePrettifyQuery.ts | 7 +- .../interfaces/SQLEditor/useRunSource.ts | 23 ++- .../interfaces/SQLEditor/useSnippetEditor.ts | 6 +- .../layouts/SQLEditorLayout/SQLEditorMenu.tsx | 17 +- .../SQLEditorNavV2/SQLEditorTreeViewItem.tsx | 24 +-- 18 files changed, 800 insertions(+), 62 deletions(-) create mode 100644 apps/studio/components/interfaces/SQLEditor/UtilityPanel/QuerySourceMenu/DatabaseSubMenu.tsx create mode 100644 apps/studio/components/interfaces/SQLEditor/UtilityPanel/QuerySourceMenu/LogsCustomRangeDialog.tsx create mode 100644 apps/studio/components/interfaces/SQLEditor/UtilityPanel/QuerySourceMenu/QuerySourceMenu.tsx create mode 100644 apps/studio/components/interfaces/SQLEditor/UtilityPanel/QuerySourceMenu/QuerySourceMenu.utils.test.ts create mode 100644 apps/studio/components/interfaces/SQLEditor/UtilityPanel/QuerySourceMenu/QuerySourceMenu.utils.ts create mode 100644 apps/studio/components/interfaces/SQLEditor/UtilityPanel/QuerySourceMenu/RowLimitSubMenu.tsx create mode 100644 apps/studio/components/interfaces/SQLEditor/UtilityPanel/QuerySourceMenu/RunAsSubMenu.tsx create mode 100644 apps/studio/components/interfaces/SQLEditor/UtilityPanel/QuerySourceMenu/TimeRangeSubMenu.tsx diff --git a/apps/studio/components/interfaces/SQLEditor/SQLEditorLayout.tsx b/apps/studio/components/interfaces/SQLEditor/SQLEditorLayout.tsx index d149bdeb95e9f..f229f200768d3 100644 --- a/apps/studio/components/interfaces/SQLEditor/SQLEditorLayout.tsx +++ b/apps/studio/components/interfaces/SQLEditor/SQLEditorLayout.tsx @@ -95,6 +95,7 @@ const SQLEditorToolbar = () => { return ( { + const { ref: projectRef } = useParams() + const sessionSnap = useSqlEditorSessionSnapshot() + const dbSelector = useDatabaseSelectorStateSnapshot() + const { infrastructureReadReplicas } = useIsFeatureEnabled(['infrastructure:read_replicas']) + + const [lastSelectedDb, setLastSelectedDb] = useLocalStorageQuery( + LOCAL_STORAGE_KEYS.SQL_EDITOR_LAST_SELECTED_DB(projectRef ?? ''), + '' + ) + + const { data } = useReadReplicasQuery({ projectRef }) + const databases = (data ?? []) + .slice() + .sort((a, b) => (a.inserted_at > b.inserted_at ? 1 : 0)) + .sort((database) => (database.identifier === projectRef ? -1 : 0)) + + const selectedDatabaseId = + lastSelectedDb.length > 0 ? lastSelectedDb : (dbSelector.selectedDatabaseId ?? projectRef) + const selectedDatabase = databases.find((db) => db.identifier === selectedDatabaseId) + + const newReplicaURL = `/project/${projectRef}/database/replication?destinationType=Read+Replica` + + const handleSelect = (databaseId: string) => { + dbSelector.setSelectedDatabaseId(databaseId) + setLastSelectedDb(databaseId) + sessionSnap.resetResult(id) + } + + return ( + + +
+ Database + + {selectedDatabase + ? databaseLabel(selectedDatabase.identifier, selectedDatabase.region, projectRef) + : 'Primary database'} + +
+
+ + {databases.map((database) => { + const isUnhealthy = database.status !== 'ACTIVE_HEALTHY' + return ( + handleSelect(database.identifier)} + > + {databaseLabel(database.identifier, database.region, projectRef)} + {database.identifier === selectedDatabaseId && } + + ) + })} + {infrastructureReadReplicas && ( + <> + + + + + Create a new read replica + + + + )} + +
+ ) +} diff --git a/apps/studio/components/interfaces/SQLEditor/UtilityPanel/QuerySourceMenu/LogsCustomRangeDialog.tsx b/apps/studio/components/interfaces/SQLEditor/UtilityPanel/QuerySourceMenu/LogsCustomRangeDialog.tsx new file mode 100644 index 0000000000000..76ba203f1df71 --- /dev/null +++ b/apps/studio/components/interfaces/SQLEditor/UtilityPanel/QuerySourceMenu/LogsCustomRangeDialog.tsx @@ -0,0 +1,58 @@ +import { useState } from 'react' +import { type DateRange } from 'react-day-picker' +import { + Button, + Calendar, + Dialog, + DialogContent, + DialogFooter, + DialogHeader, + DialogTitle, +} from 'ui' + +export const LogsCustomRangeDialog = ({ + open, + onOpenChange, + onApply, +}: { + open: boolean + onOpenChange: (open: boolean) => void + onApply: (range: { from: Date; to: Date }) => void +}) => { + const [range, setRange] = useState() + + const canApply = range?.from !== undefined && range?.to !== undefined + + const handleApply = () => { + if (range?.from === undefined || range?.to === undefined) return + onApply({ from: range.from, to: range.to }) + onOpenChange(false) + } + + return ( + + + + Custom time range + +
+
+ + + + +
+
+ ) +} diff --git a/apps/studio/components/interfaces/SQLEditor/UtilityPanel/QuerySourceMenu/QuerySourceMenu.tsx b/apps/studio/components/interfaces/SQLEditor/UtilityPanel/QuerySourceMenu/QuerySourceMenu.tsx new file mode 100644 index 0000000000000..027ae76bd2cf1 --- /dev/null +++ b/apps/studio/components/interfaces/SQLEditor/UtilityPanel/QuerySourceMenu/QuerySourceMenu.tsx @@ -0,0 +1,167 @@ +import { useParams } from 'common' +import dayjs from 'dayjs' +import { Check, ChevronDown, Database, ScrollText } from 'lucide-react' +import { useRouter } from 'next/router' +import { useState } from 'react' +import { + Button, + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuTrigger, +} from 'ui' + +import { + datePickerValueToLogDateRange, + type QuerySource, + type SqlSnippetSource, +} from '../../querySource' +import { DatabaseSubMenu } from './DatabaseSubMenu' +import { LogsCustomRangeDialog } from './LogsCustomRangeDialog' +import { resolveSourceSwitch } from './QuerySourceMenu.utils' +import { RowLimitSubMenu } from './RowLimitSubMenu' +import { RunAsSubMenu } from './RunAsSubMenu' +import { TimeRangeSubMenu } from './TimeRangeSubMenu' +import { maybeShowUpgradePromptIfNotEntitled } from '@/components/interfaces/Settings/Logs/Logs.utils' +import UpgradePrompt from '@/components/interfaces/Settings/Logs/UpgradePrompt' +import { useCheckEntitlements } from '@/hooks/misc/useCheckEntitlements' +import { IS_PLATFORM } from '@/lib/constants' +import { useSqlEditorSessionSnapshot } from '@/state/sql-editor/sql-editor-session-state' +import { useSqlEditorV2StateSnapshot } from '@/state/sql-editor/sql-editor-state' + +const SOURCE_LABEL: Record = { + database: 'Database', + logs: 'Logs', +} + +const SourceIcon = ({ source, ...props }: { source: SqlSnippetSource; className?: string }) => + source === 'logs' ? : + +type QuerySourceMenuProps = { + id: string + runSource: QuerySource + /** Whether creating a logs snippet is available (feature-flagged). */ + canCreateLogsSnippet: boolean +} + +/** + * The consolidated SQL-editor source control: a single toolbar dropdown that + * both labels the snippet's source (Database / Logs) and hosts every + * source-specific control as a flyout submenu — database selector + role + * impersonation + row limit for a database snippet, time range for a logs + * snippet. The logs "Custom range…" calendar and the retention upgrade prompt are + * rendered as siblings of the dropdown (not inside it) so they survive the menu + * closing. + * + * A snippet's source is immutable, so the source rows aren't a plain toggle. + * Once a snippet exists — a saved query, or a new one the user has already typed + * into — switching backends opens a *fresh* tab with a new snippet of that + * source, leaving the existing query untouched (there's no sense running a query + * against the wrong backend). Only a brand-new, not-yet-materialized blank tab + * re-flavors in place, so we don't spawn a redundant snippet before the user has + * written anything. + */ +export const QuerySourceMenu = ({ id, runSource, canCreateLogsSnippet }: QuerySourceMenuProps) => { + const { ref } = useParams() + const router = useRouter() + const snapV2 = useSqlEditorV2StateSnapshot() + const sessionSnap = useSqlEditorSessionSnapshot() + + const [isCustomRangeOpen, setIsCustomRangeOpen] = useState(false) + const [showUpgradePrompt, setShowUpgradePrompt] = useState(false) + + const { getEntitlementNumericValue } = useCheckEntitlements('log.retention_days') + const entitledToLogDays = getEntitlementNumericValue() + + const currentSource = runSource.type + const isLogs = currentSource === 'logs' + // A snippet materializes in the store on its first keystroke; until then a + // `/sql/new` tab is a blank scaffold with nothing to preserve. + const isBlankNewTab = snapV2.snippets[id] === undefined + + const switchSource = (target: SqlSnippetSource) => { + const next = resolveSourceSwitch({ ref, target, currentSource, isBlankNewTab }) + if (next === null) return + router[next.method](next.url) + } + + const applyCustomRange = ({ from, to }: { from: Date; to: Date }) => { + const fromIso = dayjs(from).startOf('day').toISOString() + if (maybeShowUpgradePromptIfNotEntitled(fromIso, entitledToLogDays)) { + setShowUpgradePrompt(true) + return + } + sessionSnap.setLogRange( + id, + datePickerValueToLogDateRange({ + from: fromIso, + to: dayjs(to).endOf('day').toISOString(), + isHelper: false, + }) + ) + } + + return ( + <> + + + + + + switchSource('database')}> + + + Database + + {!isLogs && } + + {(canCreateLogsSnippet || isLogs) && ( + switchSource('logs')}> + + + Logs + + {isLogs && } + + )} + + + + {runSource.type === 'logs' ? ( + setIsCustomRangeOpen(true)} + onShowUpgrade={() => setShowUpgradePrompt(true)} + /> + ) : ( + <> + {IS_PLATFORM && } + + + + )} + + + + {isLogs && ( + <> + + + + )} + + ) +} diff --git a/apps/studio/components/interfaces/SQLEditor/UtilityPanel/QuerySourceMenu/QuerySourceMenu.utils.test.ts b/apps/studio/components/interfaces/SQLEditor/UtilityPanel/QuerySourceMenu/QuerySourceMenu.utils.test.ts new file mode 100644 index 0000000000000..d005b5b44b436 --- /dev/null +++ b/apps/studio/components/interfaces/SQLEditor/UtilityPanel/QuerySourceMenu/QuerySourceMenu.utils.test.ts @@ -0,0 +1,60 @@ +import { describe, expect, it } from 'vitest' + +import { resolveSourceSwitch } from './QuerySourceMenu.utils' + +describe('resolveSourceSwitch', () => { + it('opens a new tab (push) when switching source on an existing snippet', () => { + expect( + resolveSourceSwitch({ + ref: 'abc', + target: 'logs', + currentSource: 'database', + isBlankNewTab: false, + }) + ).toEqual({ method: 'push', url: '/project/abc/sql/new?skip=true&source=logs' }) + }) + + it('re-flavors in place (replace) on a brand-new blank tab', () => { + expect( + resolveSourceSwitch({ + ref: 'abc', + target: 'logs', + currentSource: 'database', + isBlankNewTab: true, + }) + ).toEqual({ method: 'replace', url: '/project/abc/sql/new?skip=true&source=logs' }) + }) + + it('omits the source param when switching to database (the default source)', () => { + expect( + resolveSourceSwitch({ + ref: 'abc', + target: 'database', + currentSource: 'logs', + isBlankNewTab: false, + }) + ).toEqual({ method: 'push', url: '/project/abc/sql/new?skip=true' }) + }) + + it('is a no-op when the snippet is already on the target source', () => { + expect( + resolveSourceSwitch({ + ref: 'abc', + target: 'database', + currentSource: 'database', + isBlankNewTab: false, + }) + ).toBeNull() + }) + + it('is a no-op without a project ref', () => { + expect( + resolveSourceSwitch({ + ref: undefined, + target: 'logs', + currentSource: 'database', + isBlankNewTab: true, + }) + ).toBeNull() + }) +}) diff --git a/apps/studio/components/interfaces/SQLEditor/UtilityPanel/QuerySourceMenu/QuerySourceMenu.utils.ts b/apps/studio/components/interfaces/SQLEditor/UtilityPanel/QuerySourceMenu/QuerySourceMenu.utils.ts new file mode 100644 index 0000000000000..0aba7a73b9763 --- /dev/null +++ b/apps/studio/components/interfaces/SQLEditor/UtilityPanel/QuerySourceMenu/QuerySourceMenu.utils.ts @@ -0,0 +1,43 @@ +import { type SqlSnippetSource } from '../../querySource' + +export type SourceSwitchNavigation = { + /** + * `push` opens a new tab (leaving the current snippet intact); `replace` + * re-flavors the current blank tab in place without a history entry. + */ + method: 'push' | 'replace' + url: string +} + +/** + * Decide how switching a snippet's query source should navigate. A snippet's + * source is immutable, so switching never edits the current snippet: + * + * - An existing (materialized) snippet — a saved query, or a new one already + * typed into — opens a *fresh* `/sql/new` tab of the target source (`push`), so + * its query is never reinterpreted against the wrong backend. + * - A brand-new, not-yet-materialized blank tab re-flavors in place (`replace`), + * so we don't spawn a redundant snippet before anything has been written. + * + * Returns `null` when there's nothing to do (no project ref, or the snippet is + * already on the target source). + */ +export function resolveSourceSwitch({ + ref, + target, + currentSource, + isBlankNewTab, +}: { + ref: string | undefined + target: SqlSnippetSource + currentSource: SqlSnippetSource + isBlankNewTab: boolean +}): SourceSwitchNavigation | null { + if (!ref || target === currentSource) return null + const suffix = target === 'logs' ? '&source=logs' : '' + return { + method: isBlankNewTab ? 'replace' : 'push', + // skip=true bypasses the "load last visited snippet" redirect on /sql/new. + url: `/project/${ref}/sql/new?skip=true${suffix}`, + } +} diff --git a/apps/studio/components/interfaces/SQLEditor/UtilityPanel/QuerySourceMenu/RowLimitSubMenu.tsx b/apps/studio/components/interfaces/SQLEditor/UtilityPanel/QuerySourceMenu/RowLimitSubMenu.tsx new file mode 100644 index 0000000000000..9015dbada1357 --- /dev/null +++ b/apps/studio/components/interfaces/SQLEditor/UtilityPanel/QuerySourceMenu/RowLimitSubMenu.tsx @@ -0,0 +1,38 @@ +import { + DropdownMenuRadioGroup, + DropdownMenuRadioItem, + DropdownMenuSub, + DropdownMenuSubContent, + DropdownMenuSubTrigger, +} from 'ui' + +import { ROWS_PER_PAGE_OPTIONS } from '../../SQLEditor.constants' +import { useSqlEditorSessionSnapshot } from '@/state/sql-editor/sql-editor-session-state' + +export const RowLimitSubMenu = () => { + const sessionSnap = useSqlEditorSessionSnapshot() + const currentLabel = ROWS_PER_PAGE_OPTIONS.find((opt) => opt.value === sessionSnap.limit)?.label + + return ( + + +
+ Row limit + {currentLabel} +
+
+ + sessionSnap.setLimit(Number(val))} + > + {ROWS_PER_PAGE_OPTIONS.map((option) => ( + + {option.label} + + ))} + + +
+ ) +} diff --git a/apps/studio/components/interfaces/SQLEditor/UtilityPanel/QuerySourceMenu/RunAsSubMenu.tsx b/apps/studio/components/interfaces/SQLEditor/UtilityPanel/QuerySourceMenu/RunAsSubMenu.tsx new file mode 100644 index 0000000000000..a44a95d2d6010 --- /dev/null +++ b/apps/studio/components/interfaces/SQLEditor/UtilityPanel/QuerySourceMenu/RunAsSubMenu.tsx @@ -0,0 +1,31 @@ +import { DropdownMenuSub, DropdownMenuSubContent, DropdownMenuSubTrigger } from 'ui' + +import { RoleImpersonationSelector } from '@/components/interfaces/RoleImpersonationSelector' +import { useRoleImpersonationStateSnapshot } from '@/state/role-impersonation-state' + +const SERVICE_ROLE_LABEL = 'postgres' + +export const RunAsSubMenu = () => { + const state = useRoleImpersonationStateSnapshot() + const currentRole = state.role?.role ?? SERVICE_ROLE_LABEL + + return ( + + +
+ Run as + {currentRole} +
+
+ {/* Stops propagation so the authenticated-user search input isn't swallowed by the + dropdown's typeahead. */} + e.stopPropagation()}> + + +
+ ) +} diff --git a/apps/studio/components/interfaces/SQLEditor/UtilityPanel/QuerySourceMenu/TimeRangeSubMenu.tsx b/apps/studio/components/interfaces/SQLEditor/UtilityPanel/QuerySourceMenu/TimeRangeSubMenu.tsx new file mode 100644 index 0000000000000..39517f8c7b689 --- /dev/null +++ b/apps/studio/components/interfaces/SQLEditor/UtilityPanel/QuerySourceMenu/TimeRangeSubMenu.tsx @@ -0,0 +1,88 @@ +import { Check, Lock } from 'lucide-react' +import { + DropdownMenuItem, + DropdownMenuSeparator, + DropdownMenuSub, + DropdownMenuSubContent, + DropdownMenuSubTrigger, +} from 'ui' + +import { + datePickerValueToLogDateRange, + logDateRangesEqual, + type LogDateRange, +} from '../../querySource' +import { EXPLORER_DATEPICKER_HELPERS } from '@/components/interfaces/Settings/Logs/Logs.constants' +import { maybeShowUpgradePromptIfNotEntitled } from '@/components/interfaces/Settings/Logs/Logs.utils' +import { useCheckEntitlements } from '@/hooks/misc/useCheckEntitlements' +import { useSqlEditorSessionSnapshot } from '@/state/sql-editor/sql-editor-session-state' + +export const TimeRangeSubMenu = ({ + id, + range, + onOpenCustomRange, + onShowUpgrade, +}: { + id: string + range: LogDateRange + onOpenCustomRange: () => void + onShowUpgrade: () => void +}) => { + const sessionSnap = useSqlEditorSessionSnapshot() + const { getEntitlementNumericValue } = useCheckEntitlements('log.retention_days') + const entitledToLogDays = getEntitlementNumericValue() + + const isCustomRange = range.kind === 'absolute' + const presets = EXPLORER_DATEPICKER_HELPERS.map((helper) => ({ + helper, + range: datePickerValueToLogDateRange({ + from: helper.calcFrom(), + to: helper.calcTo(), + isHelper: true, + text: helper.text, + }), + })) + const selectedPreset = presets.find((preset) => logDateRangesEqual(range, preset.range)) + + return ( + + +
+ Time range + + {isCustomRange ? 'Custom range' : (selectedPreset?.helper.text ?? 'Custom range')} + +
+
+ + {presets.map(({ helper, range: presetRange }) => { + const isSelected = !isCustomRange && logDateRangesEqual(range, presetRange) + const isLocked = maybeShowUpgradePromptIfNotEntitled(helper.calcFrom(), entitledToLogDays) + + return ( + { + if (isLocked) return onShowUpgrade() + sessionSnap.setLogRange(id, presetRange) + }} + > + {helper.text} + {isLocked ? ( + + ) : ( + isSelected && + )} + + ) + })} + + + Custom range… + {isCustomRange && } + + +
+ ) +} diff --git a/apps/studio/components/interfaces/SQLEditor/UtilityPanel/RunButton.tsx b/apps/studio/components/interfaces/SQLEditor/UtilityPanel/RunButton.tsx index 861481f457dc6..6fdaae2365e34 100644 --- a/apps/studio/components/interfaces/SQLEditor/UtilityPanel/RunButton.tsx +++ b/apps/studio/components/interfaces/SQLEditor/UtilityPanel/RunButton.tsx @@ -1,5 +1,7 @@ import { Loader2 } from 'lucide-react' -import { Button, KeyboardShortcut } from 'ui' +import { KeyboardShortcut } from 'ui' + +import { ButtonTooltip } from '@/components/ui/ButtonTooltip' interface SqlRunButtonProps { isDisabled?: boolean @@ -7,6 +9,13 @@ interface SqlRunButtonProps { hasSelection?: boolean className?: string onClick: () => void + /** + * Explanation shown in a tooltip while the button is disabled — e.g. why a + * logs query can't run on this project. A disabled ` + ) } diff --git a/apps/studio/components/interfaces/SQLEditor/UtilityPanel/UtilityActions.tsx b/apps/studio/components/interfaces/SQLEditor/UtilityPanel/UtilityActions.tsx index 4a6b55cf89be8..a5c69be3d4003 100644 --- a/apps/studio/components/interfaces/SQLEditor/UtilityPanel/UtilityActions.tsx +++ b/apps/studio/components/interfaces/SQLEditor/UtilityPanel/UtilityActions.tsx @@ -1,5 +1,5 @@ import { Hotkey } from '@tanstack/react-hotkeys' -import { LOCAL_STORAGE_KEYS, useParams } from 'common' +import { LOCAL_STORAGE_KEYS, useFlag, useParams } from 'common' import { AlignLeft, Check, ChevronDown, Heart, Keyboard, MoreVertical } from 'lucide-react' import { toast } from 'sonner' import { @@ -18,8 +18,10 @@ import { TooltipTrigger, } from 'ui' +import { type QuerySource } from '../querySource' import { ROWS_PER_PAGE_OPTIONS } from '../SQLEditor.constants' import { AutosaveStatus } from './AutosaveStatus' +import { QuerySourceMenu } from './QuerySourceMenu/QuerySourceMenu' import { SqlRunButton } from './RunButton' import { SqlSaveButton } from './SaveButton' import SavingIndicator from './SavingIndicator' @@ -35,6 +37,7 @@ import { useSqlEditorV2StateSnapshot } from '@/state/sql-editor/sql-editor-state export type UtilityActionsProps = { id: string + runSource: QuerySource isExecuting?: boolean isDisabled?: boolean hasSelection?: boolean @@ -45,6 +48,7 @@ export type UtilityActionsProps = { export const UtilityActions = ({ id, + runSource, isExecuting = false, isDisabled = false, hasSelection = false, @@ -57,6 +61,14 @@ export const UtilityActions = ({ const sessionSnap = useSqlEditorSessionSnapshot() const isManualSaveEnabled = useIsSqlEditorManualSaveEnabled() + const isLogsSourceEnabled = useFlag('sqlEditorLogsSource') + const isOtelLogsEnabled = useFlag('otelLegacyLogs') + + const isLogs = runSource.type === 'logs' + const canCreateLogsSnippet = isLogsSourceEnabled && isOtelLogsEnabled + const canShowSourceIndicator = isLogs || canCreateLogsSnippet + const isLogsRunBlocked = isLogs && !isOtelLogsEnabled + const [isAiOpen] = useLocalStorageQuery(LOCAL_STORAGE_KEYS.SQL_EDITOR_AI_OPEN, true) const [intellisenseEnabled, setIntellisenseEnabled] = useLocalStorageQuery( LOCAL_STORAGE_KEYS.SQL_EDITOR_INTELLISENSE, @@ -141,7 +153,7 @@ export const UtilityActions = ({ )} - + Prettify SQL @@ -208,6 +220,7 @@ export const UtilityActions = ({ - - - sessionSnap.setLimit(Number(val))} - > - {ROWS_PER_PAGE_OPTIONS.map((option) => ( - - {option.label} - - ))} - - - + + + + + + sessionSnap.setLimit(Number(val))} + > + {ROWS_PER_PAGE_OPTIONS.map((option) => ( + + {option.label} + + ))} + + + + + )}
{isManualSaveEnabled && } diff --git a/apps/studio/components/interfaces/SQLEditor/querySource.test.ts b/apps/studio/components/interfaces/SQLEditor/querySource.test.ts index 9c63333f64eb5..5b79d3b77683a 100644 --- a/apps/studio/components/interfaces/SQLEditor/querySource.test.ts +++ b/apps/studio/components/interfaces/SQLEditor/querySource.test.ts @@ -6,6 +6,7 @@ import { DEFAULT_LOG_DATE_RANGE, getSnippetSource, isoDateTimeString, + logDateRangesEqual, logDateRangeToDatePickerValue, resolveLogRunRange, type LogDateRange, @@ -228,3 +229,57 @@ describe('querySource.ts:resolveLogRunRange', () => { }) }) }) + +describe('querySource.ts:logDateRangesEqual', () => { + it('matches relative ranges on amount + unit regardless of label formatting', () => { + const lastHourPreset = EXPLORER_DATEPICKER_HELPERS.find((h) => h.text === 'Last hour')! + const presetRange = datePickerValueToLogDateRange({ + from: lastHourPreset.calcFrom(), + to: lastHourPreset.calcTo(), + isHelper: true, + text: lastHourPreset.text, + }) + + expect( + logDateRangesEqual(presetRange, { kind: 'relative', last: { amount: 1, unit: 'hour' } }) + ).toBe(true) + }) + + it('does not match relative ranges with a different amount or unit', () => { + expect( + logDateRangesEqual( + { kind: 'relative', last: { amount: 1, unit: 'hour' } }, + { kind: 'relative', last: { amount: 3, unit: 'hour' } } + ) + ).toBe(false) + expect( + logDateRangesEqual( + { kind: 'relative', last: { amount: 1, unit: 'hour' } }, + { kind: 'relative', last: { amount: 1, unit: 'day' } } + ) + ).toBe(false) + }) + + it('matches absolute ranges on their ISO endpoints', () => { + const from = isoDateTimeString('2025-01-01T00:00:00.000Z')! + const to = isoDateTimeString('2025-01-02T00:00:00.000Z')! + expect(logDateRangesEqual({ kind: 'absolute', from, to }, { kind: 'absolute', from, to })).toBe( + true + ) + }) + + it('never matches a relative range against an absolute one', () => { + const from = isoDateTimeString('2025-01-01T00:00:00.000Z')! + const to = isoDateTimeString('2025-01-02T00:00:00.000Z')! + expect( + logDateRangesEqual( + { kind: 'relative', last: { amount: 1, unit: 'hour' } }, + { + kind: 'absolute', + from, + to, + } + ) + ).toBe(false) + }) +}) diff --git a/apps/studio/components/interfaces/SQLEditor/querySource.ts b/apps/studio/components/interfaces/SQLEditor/querySource.ts index e4d2b305d56b6..1ba1c4fd1ea75 100644 --- a/apps/studio/components/interfaces/SQLEditor/querySource.ts +++ b/apps/studio/components/interfaces/SQLEditor/querySource.ts @@ -25,6 +25,16 @@ export function getSnippetSource(snippet: Pick): SqlSnippetSour return snippet.type === 'log_sql' ? 'logs' : 'database' } +/** + * Parse a raw `source` value (e.g. the `?source=` query param a creation entry + * threads through `/sql/new`) into a `SqlSnippetSource`. Only the explicit + * `'logs'` opts a new snippet into the logs backend; anything else — including an + * absent param — is a database snippet, keeping database the safe default. + */ +export function parseSqlSnippetSource(raw: string | undefined): SqlSnippetSource { + return raw === 'logs' ? 'logs' : 'database' +} + /** * An ISO-8601 datetime proven valid at construction via a dayjs parse. Absolute * log ranges carry these instead of raw strings so an unvalidated datetime can @@ -135,6 +145,22 @@ export function logDateRangeToDatePickerValue(range: LogDateRange): DatePickerVa return { from: range.from, to: range.to, isHelper: false } } +/** + * Structural equality for two log date ranges. Relative ranges match on amount + + * unit, NOT display text — "Last hour" and "Last 1 hour" render differently but + * are the same range, so comparing labels is unreliable. Absolute ranges match on + * their (validated) ISO endpoints. + */ +export function logDateRangesEqual(a: LogDateRange, b: LogDateRange): boolean { + if (a.kind === 'relative' && b.kind === 'relative') { + return a.last.amount === b.last.amount && a.last.unit === b.last.unit + } + if (a.kind === 'absolute' && b.kind === 'absolute') { + return a.from === b.from && a.to === b.to + } + return false +} + /** * Resolve a `LogDateRange` to concrete ISO endpoints for a run. Relative ranges * re-resolve against `now` (so "last hour" is always the hour before the run); diff --git a/apps/studio/components/interfaces/SQLEditor/usePrettifyQuery.ts b/apps/studio/components/interfaces/SQLEditor/usePrettifyQuery.ts index 9a70c33303425..8e28727260064 100644 --- a/apps/studio/components/interfaces/SQLEditor/usePrettifyQuery.ts +++ b/apps/studio/components/interfaces/SQLEditor/usePrettifyQuery.ts @@ -24,9 +24,12 @@ export function usePrettifyQuery({ id, isDiffOpen }: { id: string; isDiffOpen: b const state = getSqlEditorV2StateSnapshot() const snippet = state.snippets[id] + // pg formatting can mangle ClickHouse syntax (backtick identifiers), so + // Prettify is a no-op for logs snippets — the UI also hides the affordance. + if (snippet?.snippet.type === 'log_sql') return + if (editor.isReady() && project) { - const fallback = - snippet?.snippet.type === 'log_sql' ? undefined : snippet?.snippet.content?.unchecked_sql + const fallback = snippet?.snippet.content?.unchecked_sql const sql = editor.getSql(fallback) if (sql === undefined) return diff --git a/apps/studio/components/interfaces/SQLEditor/useRunSource.ts b/apps/studio/components/interfaces/SQLEditor/useRunSource.ts index 9bccf7fb62b08..aa7cbf05b6f0d 100644 --- a/apps/studio/components/interfaces/SQLEditor/useRunSource.ts +++ b/apps/studio/components/interfaces/SQLEditor/useRunSource.ts @@ -1,6 +1,13 @@ +import { useParams } from 'common' import { useMemo } from 'react' -import { DEFAULT_LOG_DATE_RANGE, type QuerySource } from './querySource' +import { + DEFAULT_LOG_DATE_RANGE, + getSnippetSource, + parseSqlSnippetSource, + type QuerySource, + type SqlSnippetSource, +} from './querySource' import { useSqlEditorSessionSnapshot } from '@/state/sql-editor/sql-editor-session-state' import { useSqlEditorV2StateSnapshot } from '@/state/sql-editor/sql-editor-state' @@ -10,18 +17,26 @@ import { useSqlEditorV2StateSnapshot } from '@/state/sql-editor/sql-editor-state * the user hasn't picked one); every other snippet targets the database. Source * is derived from the snippet's content type and is NOT flag-gated here — a * URL-opened logs snippet routes correctly even with the feature flag off. + * + * Before the snippet exists in the store (a fresh `/sql/new` tab, materialized + * lazily on the first keystroke) the source falls back to the `?source=` URL + * param, so a "New logs query" tab shows the logs toolbar and range picker + * immediately rather than flashing the database controls until the user types. */ export function useRunSource(id: string): QuerySource { + const { source: sourceParam } = useParams() const snapV2 = useSqlEditorV2StateSnapshot() const sessionSnap = useSqlEditorSessionSnapshot() - const snippetType = snapV2.snippets[id]?.snippet.type + const snippet = snapV2.snippets[id]?.snippet + const source: SqlSnippetSource = + snippet !== undefined ? getSnippetSource(snippet) : parseSqlSnippetSource(sourceParam) const logRange = sessionSnap.logRange[id] return useMemo(() => { - if (snippetType === 'log_sql') { + if (source === 'logs') { return { type: 'logs', dateRange: logRange ?? DEFAULT_LOG_DATE_RANGE } } return { type: 'database' } - }, [snippetType, logRange]) + }, [source, logRange]) } diff --git a/apps/studio/components/interfaces/SQLEditor/useSnippetEditor.ts b/apps/studio/components/interfaces/SQLEditor/useSnippetEditor.ts index 76c5a13929612..f7bfd296d9c90 100644 --- a/apps/studio/components/interfaces/SQLEditor/useSnippetEditor.ts +++ b/apps/studio/components/interfaces/SQLEditor/useSnippetEditor.ts @@ -2,6 +2,7 @@ import { useParams } from 'common' import { useRouter } from 'next/router' import { useEffect, useEffectEvent } from 'react' +import { parseSqlSnippetSource } from './querySource' import { createSqlSnippetSkeletonV2 } from './SQLEditor.utils' import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject' import { useProfile } from '@/lib/profile' @@ -25,7 +26,7 @@ import { useTabsStateSnapshot } from '@/state/tabs' export function useSnippetEditor({ id, snippetName }: { id: string; snippetName: string }) { const router = useRouter() const { profile } = useProfile() - const { ref, content } = useParams() + const { ref, content, source } = useParams() const { data: project } = useSelectedProjectQuery() const snapV2 = useSqlEditorV2StateSnapshot() @@ -45,6 +46,9 @@ export function useSnippetEditor({ id, snippetName }: { id: string; snippetName: sql: value, owner_id: profile?.id, project_id: project?.id, + // A creation entry (e.g. "New logs query") threads the target backend + // through `/sql/new?source=`; default to a database snippet otherwise. + source: parseSqlSnippetSource(source), }) snapV2.addSnippet({ projectRef: ref, snippet: newSnippet }) // When the editor was seeded from a `content` deep-link, replace rather diff --git a/apps/studio/components/layouts/SQLEditorLayout/SQLEditorMenu.tsx b/apps/studio/components/layouts/SQLEditorLayout/SQLEditorMenu.tsx index a27febc9d524c..0fad5971029ee 100644 --- a/apps/studio/components/layouts/SQLEditorLayout/SQLEditorMenu.tsx +++ b/apps/studio/components/layouts/SQLEditorLayout/SQLEditorMenu.tsx @@ -1,7 +1,7 @@ import { PermissionAction } from '@supabase/shared-types/out/constants' import { useDebounce } from '@uidotdev/usehooks' import { LOCAL_STORAGE_KEYS, useFlag, useParams } from 'common' -import { FilePlus, FolderPlus, Plus, X } from 'lucide-react' +import { FilePlus, FolderPlus, Plus, ScrollText, X } from 'lucide-react' import { useRouter } from 'next/router' import { useEffect, useState } from 'react' import { toast } from 'sonner' @@ -24,6 +24,7 @@ import { import { SearchList } from './SQLEditorNavV2/SearchList' import { SQLEditorNav } from './SQLEditorNavV2/SQLEditorNav' +import { type SqlSnippetSource } from '@/components/interfaces/SQLEditor/querySource' import { useAsyncCheckPermissions } from '@/hooks/misc/useCheckPermissions' import { useLocalStorage } from '@/hooks/misc/useLocalStorage' import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject' @@ -39,6 +40,9 @@ export const SQLEditorMenu = () => { const snapV2 = useSqlEditorV2StateSnapshot() const topForPostgres = useFlag('topForPostgres') + const sqlEditorLogsSource = useFlag('sqlEditorLogsSource') + const otelLegacyLogs = useFlag('otelLegacyLogs') + const canCreateLogsSnippet = sqlEditorLogsSource && otelLegacyLogs const [search, setSearch] = useState('') const [showSearch, setShowSearch] = useState(false) @@ -66,7 +70,7 @@ export const SQLEditorMenu = () => { snapV2.addNewFolder({ projectRef: ref }) } - const handleNewQuery = async () => { + const handleNewQuery = async (source: SqlSnippetSource = 'database') => { if (!ref) return console.error('Project ref is required') if (!project) return console.error('Project is required') if (!profile) return console.error('Profile is required') @@ -74,7 +78,8 @@ export const SQLEditorMenu = () => { return toast('Your queries will not be saved as you do not have sufficient permissions') } try { - router.push(`/project/${ref}/sql/new?skip=true`) + const suffix = source === 'logs' ? '&source=logs' : '' + router.push(`/project/${ref}/sql/new?skip=true${suffix}`) setSearch('') setShowSearch(false) } catch (error: any) { @@ -156,6 +161,12 @@ export const SQLEditorMenu = () => { Create a new snippet + {canCreateLogsSnippet && ( + handleNewQuery('logs')}> + + Create a new logs query + + )} createNewFolder()}> Create a new folder diff --git a/apps/studio/components/layouts/SQLEditorLayout/SQLEditorNavV2/SQLEditorTreeViewItem.tsx b/apps/studio/components/layouts/SQLEditorLayout/SQLEditorNavV2/SQLEditorTreeViewItem.tsx index 828f99b768711..21ae2a5e129db 100644 --- a/apps/studio/components/layouts/SQLEditorLayout/SQLEditorNavV2/SQLEditorTreeViewItem.tsx +++ b/apps/studio/components/layouts/SQLEditorLayout/SQLEditorNavV2/SQLEditorTreeViewItem.tsx @@ -28,6 +28,7 @@ import { TreeViewItem, } from 'ui' +import { getSnippetSource } from '@/components/interfaces/SQLEditor/querySource' import { createSqlSnippetSkeletonV2 } from '@/components/interfaces/SQLEditor/SQLEditor.utils' import { getContentById, getSqlSnippetById } from '@/data/content/content-id-query' import { useSQLSnippetFolderContentsQuery } from '@/data/content/sql-folder-contents-query' @@ -225,6 +226,7 @@ export const SQLEditorTreeViewItem = ({ sql, owner_id: profile?.id, project_id: project?.id, + source: getSnippetSource(snippet), }) snapV2.addSnippet({ projectRef, snippet: snippetCopy }) @@ -420,16 +422,18 @@ export const SQLEditorTreeViewItem = ({ {isFavorite ? 'Remove from' : 'Add to'} favorites )} - {onSelectDownload !== undefined && IS_PLATFORM && ( - onSelectDownload()} - onFocusCapture={(e) => e.stopPropagation()} - > - - Export query - - )} + {onSelectDownload !== undefined && + IS_PLATFORM && + getSnippetSource(element.metadata) !== 'logs' && ( + onSelectDownload()} + onFocusCapture={(e) => e.stopPropagation()} + > + + Export query + + )} {onSelectDelete !== undefined && isOwner && ( <> From bf5a729f2d68dd64c606c078237db5ca2f47b2fe Mon Sep 17 00:00:00 2001 From: Steven Eubank <47563310+smeubank@users.noreply.github.com> Date: Thu, 30 Jul 2026 15:19:00 +0200 Subject: [PATCH 08/12] docs(telemetry): rename section and restructure as Monitoring and Debugging (#48243) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary - Renames the **Telemetry** nav section to **Monitoring and Debugging** (nav label + sidebar title) - Rewrites the section overview (`telemetry.mdx`) as a clean navigation page using `ContentListings` — three panels (Debugging / Monitoring / AI & automation) with no how-to prose - Adds new `telemetry.data.ts` content-listings data file with three groups registered in `index.ts` - Adds a new **Debugging** guide (`debugging.mdx`) — request-stack model, symptom-to-layer router with troubleshooting links for every service, logging guidance - Adds cross-links between `debugging.mdx`, `logs.mdx`, and `advanced-log-filtering.mdx` - Adds a new **AI agents and MCP** page (`ai-agents.mdx`) — MCP tools table, `get_logs` usage, debugging skill workflow - Restructures sidebar into three groups: **Debugging** / **Monitoring** / **AI & automation** ## Motivation - No central entry point existed for debugging — content was scattered across products with no index - The overview page had almost no links for agents to follow - The section name "Telemetry" caused confusion (also used for CLI usage telemetry) - Unblocks the `supabase` debugging skill, which routes agents to this section as its source of truth ## Test plan - [ ] `/docs/guides/telemetry` — three ContentListings panels render, no prose how-to text - [ ] `/docs/guides/telemetry.md` (markdown) — clean link list, navigable by LLMs - [ ] `/docs/guides/telemetry/debugging` — renders correctly, symptom table links resolve - [ ] `/docs/guides/telemetry/ai-agents` — new page renders correctly - [ ] Sidebar shows 3 groups: Debugging / Monitoring / AI & automation - [ ] All cross-links between debugging, logs, and advanced-log-filtering resolve ## Summary by CodeRabbit ## Summary - **New Features** - Added new documentation coverage for AI agent–assisted monitoring and debugging, including an observability-driven troubleshooting workflow. - **Documentation** - Updated the “Telemetry” area to “Monitoring and Debugging” with a refreshed landing page and reorganized sections (Debugging, Monitoring, and AI). - Revised the debugging and logs guides to improve step-by-step guidance and highlight advanced log filtering. - **Navigation** - Renamed and restructured the top-level navigation entry to reflect the new Monitoring and Debugging content layout. --------- Co-authored-by: Claude Sonnet 4.6 Co-authored-by: Jeremias Menichelli --- .../[[...slug]]/page.tsx | 8 ++- .../monitoring-and-debugging/layout.tsx | 5 ++ apps/docs/app/guides/telemetry/layout.tsx | 5 -- .../docs/components/MetricsStackCards.data.ts | 6 +- .../NavigationMenu.constants.ts | 54 ++++++++------- .../NavigationMenu/NavigationMenu.utils.ts | 7 +- .../guides/database/connection-management.mdx | 4 +- .../guides/database/extensions/pgaudit.mdx | 2 +- .../manual-replication-monitoring.mdx | 4 +- .../guides/monitoring-and-debugging.mdx | 9 +++ .../advanced-log-filtering.mdx | 0 .../client-side-tracing.mdx | 2 +- .../debugging.mdx | 23 +++++-- .../log-drains.mdx | 6 +- .../log-field-reference.mdx | 2 +- .../logs.mdx | 12 ++++ .../metrics.mdx | 2 +- .../metrics/grafana-cloud.mdx | 0 .../metrics/grafana-self-hosted.mdx | 0 .../metrics/vendor-agnostic.mdx | 0 .../reports.mdx | 0 .../sentry-monitoring.mdx | 0 .../guides/platform/billing-on-supabase.mdx | 2 +- .../platform/postgres-connection-logging.mdx | 4 +- .../content/guides/platform/read-replicas.mdx | 4 +- .../read-replicas/getting-started.mdx | 2 +- .../guides/security/platform-audit-logs.mdx | 2 +- .../content/guides/storage/cdn/metrics.mdx | 2 +- .../content/guides/storage/debugging/logs.mdx | 2 +- apps/docs/content/guides/telemetry.mdx | 13 ---- .../troubleshooting/exhaust-disk-io.mdx | 2 +- .../content/troubleshooting/exhaust-ram.mdx | 2 +- .../content/troubleshooting/exhaust-swap.mdx | 2 +- .../failed-to-retrieve-tables.mdx | 2 +- ...n-terminated-due-to-connection-timeout.mdx | 2 +- .../troubleshooting/high-cpu-usage.mdx | 2 +- ...t-and-explore-the-postgres-logs-OuCIOj.mdx | 2 +- .../how-to-view-database-metrics-uqf2z_.mdx | 2 +- ...ting-supabase-grafana-io-charts-MUynDR.mdx | 2 +- ...monitor-supavisor-postgres-connections.mdx | 2 +- ...-query-performance-with-indexes-q8PoC9.mdx | 2 +- .../supabase-grafana-memory-charts.mdx | 2 +- .../troubleshooting/supavisor-faq-YyP5tI.mdx | 2 +- apps/docs/data/content-listings/index.ts | 3 + .../data/content-listings/log-drains.data.ts | 18 ++--- .../data/content-listings/telemetry.data.ts | 65 +++++++++++++++++++ apps/docs/features/docs/GuidesMdx.utils.tsx | 2 +- apps/docs/lib/breadcrumbs.ts | 2 +- apps/docs/lib/content-listings.test.ts | 2 +- apps/www/lib/redirects.js | 5 ++ 50 files changed, 202 insertions(+), 103 deletions(-) rename apps/docs/app/guides/{telemetry => monitoring-and-debugging}/[[...slug]]/page.tsx (73%) create mode 100644 apps/docs/app/guides/monitoring-and-debugging/layout.tsx delete mode 100644 apps/docs/app/guides/telemetry/layout.tsx create mode 100644 apps/docs/content/guides/monitoring-and-debugging.mdx rename apps/docs/content/guides/{telemetry => monitoring-and-debugging}/advanced-log-filtering.mdx (100%) rename apps/docs/content/guides/{telemetry => monitoring-and-debugging}/client-side-tracing.mdx (94%) rename apps/docs/content/guides/{telemetry => monitoring-and-debugging}/debugging.mdx (92%) rename apps/docs/content/guides/{telemetry => monitoring-and-debugging}/log-drains.mdx (96%) rename apps/docs/content/guides/{telemetry => monitoring-and-debugging}/log-field-reference.mdx (92%) rename apps/docs/content/guides/{telemetry => monitoring-and-debugging}/logs.mdx (97%) rename apps/docs/content/guides/{telemetry => monitoring-and-debugging}/metrics.mdx (94%) rename apps/docs/content/guides/{telemetry => monitoring-and-debugging}/metrics/grafana-cloud.mdx (100%) rename apps/docs/content/guides/{telemetry => monitoring-and-debugging}/metrics/grafana-self-hosted.mdx (100%) rename apps/docs/content/guides/{telemetry => monitoring-and-debugging}/metrics/vendor-agnostic.mdx (100%) rename apps/docs/content/guides/{telemetry => monitoring-and-debugging}/reports.mdx (100%) rename apps/docs/content/guides/{telemetry => monitoring-and-debugging}/sentry-monitoring.mdx (100%) delete mode 100644 apps/docs/content/guides/telemetry.mdx create mode 100644 apps/docs/data/content-listings/telemetry.data.ts diff --git a/apps/docs/app/guides/telemetry/[[...slug]]/page.tsx b/apps/docs/app/guides/monitoring-and-debugging/[[...slug]]/page.tsx similarity index 73% rename from apps/docs/app/guides/telemetry/[[...slug]]/page.tsx rename to apps/docs/app/guides/monitoring-and-debugging/[[...slug]]/page.tsx index 0aa9feceb0daa..94df4a9b279a6 100644 --- a/apps/docs/app/guides/telemetry/[[...slug]]/page.tsx +++ b/apps/docs/app/guides/monitoring-and-debugging/[[...slug]]/page.tsx @@ -11,15 +11,17 @@ type Params = { slug?: string[] } const MonitoringTroubleshootingGuidePage = async (props: { params: Promise }) => { const params = await props.params - const slug = ['telemetry', ...(params.slug ?? [])] + const slug = ['monitoring-and-debugging', ...(params.slug ?? [])] const data = await getGuidesMarkdown(slug) return } -const generateStaticParams = !IS_DEV ? genGuidesStaticParams('telemetry') : getEmptyArray +const generateStaticParams = !IS_DEV + ? genGuidesStaticParams('monitoring-and-debugging') + : getEmptyArray const generateMetadata = genGuideMeta((params: { slug?: string[] }) => - getGuidesMarkdown(['telemetry', ...(params.slug ?? [])]) + getGuidesMarkdown(['monitoring-and-debugging', ...(params.slug ?? [])]) ) export default MonitoringTroubleshootingGuidePage diff --git a/apps/docs/app/guides/monitoring-and-debugging/layout.tsx b/apps/docs/app/guides/monitoring-and-debugging/layout.tsx new file mode 100644 index 0000000000000..8c99a320c3827 --- /dev/null +++ b/apps/docs/app/guides/monitoring-and-debugging/layout.tsx @@ -0,0 +1,5 @@ +import Layout from '~/layouts/guides' + +export default async function MonitoringAndDebugging({ children }: { children: React.ReactNode }) { + return {children} +} diff --git a/apps/docs/app/guides/telemetry/layout.tsx b/apps/docs/app/guides/telemetry/layout.tsx deleted file mode 100644 index e2fe19972d45f..0000000000000 --- a/apps/docs/app/guides/telemetry/layout.tsx +++ /dev/null @@ -1,5 +0,0 @@ -import Layout from '~/layouts/guides' - -export default async function Telemetry({ children }: { children: React.ReactNode }) { - return {children} -} diff --git a/apps/docs/components/MetricsStackCards.data.ts b/apps/docs/components/MetricsStackCards.data.ts index 637af23172874..d9217a230195d 100644 --- a/apps/docs/components/MetricsStackCards.data.ts +++ b/apps/docs/components/MetricsStackCards.data.ts @@ -13,7 +13,7 @@ export const metricsStackOptions: MetricsStackOption[] = [ title: 'Grafana Cloud (SaaS)', description: 'Use Grafana Cloud’s managed Prometheus (works on Free + Pro tiers) and import the Supabase dashboard without running any infrastructure.', - href: '/guides/telemetry/metrics/grafana-cloud', + href: '/guides/monitoring-and-debugging/metrics/grafana-cloud', iconKind: 'grafana', iconColor: '#F05A28', iconBg: 'rgba(240,90,40,0.1)', @@ -23,7 +23,7 @@ export const metricsStackOptions: MetricsStackOption[] = [ title: 'Grafana + self-hosted Prometheus', description: 'Run Prometheus yourself following the official installation guidance and pair it with Grafana plus our dashboard JSON and alert pack.', - href: '/guides/telemetry/metrics/grafana-self-hosted', + href: '/guides/monitoring-and-debugging/metrics/grafana-self-hosted', iconKind: 'grafana', iconColor: '#F05A28', iconBg: 'rgba(240,90,40,0.1)', @@ -43,7 +43,7 @@ export const metricsStackOptions: MetricsStackOption[] = [ title: 'Vendor-agnostic / BYO Prometheus', description: 'Connect AWS AMP, Grafana Mimir, VictoriaMetrics, or any Prometheus-compatible SaaS with the same scrape job pattern.', - href: '/guides/telemetry/metrics/vendor-agnostic', + href: '/guides/monitoring-and-debugging/metrics/vendor-agnostic', iconKind: 'flame', iconColor: '#0BA678', iconBg: 'rgba(11,166,120,0.1)', diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts index cb2ec0b8c1d58..96e6899ff955e 100644 --- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts +++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts @@ -212,9 +212,9 @@ export const GLOBAL_MENU_ITEMS: GlobalMenuItems = [ level: 'security', }, { - label: 'Telemetry', + label: 'Monitoring and Debugging', icon: 'telemetry', - href: '/guides/telemetry' as `/${string}`, + href: '/guides/monitoring-and-debugging' as `/${string}`, level: 'telemetry', }, { @@ -2983,57 +2983,59 @@ export const platform: NavMenuConstant = { export const telemetry: NavMenuConstant = { icon: 'telemetry', - title: 'Telemetry', - url: '/guides/telemetry', + title: 'Monitoring and Debugging', + url: '/guides/monitoring-and-debugging', items: [ - { name: 'Overview', url: '/guides/telemetry' }, + { name: 'Overview', url: '/guides/monitoring-and-debugging' }, { - name: 'Logging & observability', + name: 'Debugging', url: undefined, items: [ { - name: 'Logging', - url: '/guides/telemetry/logs' as `/${string}`, + name: 'Debugging guide', + url: '/guides/monitoring-and-debugging/debugging' as `/${string}`, }, { - name: 'Debugging', - url: '/guides/telemetry/debugging' as `/${string}`, + name: 'Logging', + url: '/guides/monitoring-and-debugging/logs' as `/${string}`, }, { name: 'Advanced log filtering', - url: '/guides/telemetry/advanced-log-filtering' as `/${string}`, + url: '/guides/monitoring-and-debugging/advanced-log-filtering' as `/${string}`, }, { name: 'Logs field reference', - url: '/guides/telemetry/log-field-reference' as `/${string}`, + url: '/guides/monitoring-and-debugging/log-field-reference' as `/${string}`, }, + ], + }, + { + name: 'Monitoring', + url: undefined, + items: [ { name: 'Log drains', - url: '/guides/telemetry/log-drains' as `/${string}`, - }, - { - name: 'Tracing with the JS SDK', - url: '/guides/telemetry/client-side-tracing' as `/${string}`, + url: '/guides/monitoring-and-debugging/log-drains' as `/${string}`, }, { name: 'Reports', - url: '/guides/telemetry/reports' as `/${string}`, + url: '/guides/monitoring-and-debugging/reports' as `/${string}`, }, { name: 'Metrics', - url: '/guides/telemetry/metrics' as `/${string}`, + url: '/guides/monitoring-and-debugging/metrics' as `/${string}`, items: [ { name: 'Overview', - url: '/guides/telemetry/metrics' as `/${string}`, + url: '/guides/monitoring-and-debugging/metrics' as `/${string}`, }, { name: 'Grafana Cloud', - url: '/guides/telemetry/metrics/grafana-cloud' as `/${string}`, + url: '/guides/monitoring-and-debugging/metrics/grafana-cloud' as `/${string}`, }, { name: 'Grafana self-hosted', - url: '/guides/telemetry/metrics/grafana-self-hosted' as `/${string}`, + url: '/guides/monitoring-and-debugging/metrics/grafana-self-hosted' as `/${string}`, }, { name: 'Datadog', @@ -3041,13 +3043,17 @@ export const telemetry: NavMenuConstant = { }, { name: 'Vendor-agnostic setup', - url: '/guides/telemetry/metrics/vendor-agnostic' as `/${string}`, + url: '/guides/monitoring-and-debugging/metrics/vendor-agnostic' as `/${string}`, }, ], }, { name: 'Sentry integration', - url: '/guides/telemetry/sentry-monitoring' as `/${string}`, + url: '/guides/monitoring-and-debugging/sentry-monitoring' as `/${string}`, + }, + { + name: 'Tracing with the JS SDK', + url: '/guides/monitoring-and-debugging/client-side-tracing' as `/${string}`, }, ], }, diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.utils.ts b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.utils.ts index 556d87971a0f1..a44f85f4fba78 100644 --- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.utils.ts +++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.utils.ts @@ -1,10 +1,11 @@ 'use client' -import { usePathname } from 'next/navigation' -import { useEffect, useState } from 'react' import { MenuId } from '~/components/Navigation/NavigationMenu/NavigationMenu' import type { ICommonItem } from '~/components/reference/Reference.types' import type { Json } from '~/features/helpers.types' +import { usePathname } from 'next/navigation' +import { useEffect, useState } from 'react' + import { menuState } from '../../../hooks/useMenuState' export function getPathWithoutHash(relativePath: string) { @@ -134,7 +135,7 @@ export const getMenuId = (pathname: string | null) => { return MenuId.LocalDevelopment case pathname.startsWith('ai-tools'): return MenuId.AiTools - case pathname.startsWith('telemetry'): + case pathname.startsWith('monitoring-and-debugging'): return MenuId.Telemetry case pathname.startsWith('platform'): return MenuId.Platform diff --git a/apps/docs/content/guides/database/connection-management.mdx b/apps/docs/content/guides/database/connection-management.mdx index 2810bbe7f4b4a..b94395c633834 100644 --- a/apps/docs/content/guides/database/connection-management.mdx +++ b/apps/docs/content/guides/database/connection-management.mdx @@ -47,11 +47,11 @@ For Teams and Enterprise plans, Supabase provides Advanced Telemetry charts dire This chart helps you monitor connection pool usage, identify connection leaks, and plan capacity. It also shows a reference line for your compute size's maximum connection limit. -For more details on using these monitoring charts, see the [Reports guide](/docs/guides/telemetry/reports#advanced-telemetry). +For more details on using these monitoring charts, see the [Reports guide](/docs/guides/monitoring-and-debugging/reports#advanced-telemetry). #### Grafana Dashboard -Supabase offers a Grafana Dashboard that records and visualizes over 200 project metrics, including connections. For setup instructions, check the [metrics docs](/docs/guides/telemetry/metrics). +Supabase offers a Grafana Dashboard that records and visualizes over 200 project metrics, including connections. For setup instructions, check the [metrics docs](/docs/guides/monitoring-and-debugging/metrics). Its "Client Connections" graph displays connections for both Supavisor and Postgres ![client connection graph](/docs/img/database/grafana-connections.png) diff --git a/apps/docs/content/guides/database/extensions/pgaudit.mdx b/apps/docs/content/guides/database/extensions/pgaudit.mdx index a451ef2d1381d..8416bf41c1cfa 100644 --- a/apps/docs/content/guides/database/extensions/pgaudit.mdx +++ b/apps/docs/content/guides/database/extensions/pgaudit.mdx @@ -391,5 +391,5 @@ PGAudit's [official documentation](https://www.pgaudit.org) focuses on system an - [Official `PGAudit` documentation](https://www.pgaudit.org) - [Database Function Logging](/docs/guides/database/functions#general-logging) -- [Supabase Logging](/docs/guides/telemetry/logs) +- [Supabase Logging](/docs/guides/monitoring-and-debugging/logs) - [Self-Hosting Logs](/docs/reference/self-hosting-analytics/introduction) diff --git a/apps/docs/content/guides/database/replication/manual-replication-monitoring.mdx b/apps/docs/content/guides/database/replication/manual-replication-monitoring.mdx index 0e9da551f2ba2..8edf982a0c41f 100644 --- a/apps/docs/content/guides/database/replication/manual-replication-monitoring.mdx +++ b/apps/docs/content/guides/database/replication/manual-replication-monitoring.mdx @@ -8,12 +8,12 @@ sidebar_label: 'Monitoring' Monitoring replication lag is important and there are 3 ways to do this: -1. Dashboard - In [Reports](/docs/guides/telemetry/reports), you can view the replication lag of your project +1. Dashboard - In [Reports](/docs/guides/monitoring-and-debugging/reports), you can view the replication lag of your project 2. Database - - pg_stat_subscription (subscriber) - if PID is null, then the subscription is not active - pg_stat_subscription_stats - look here for error_count to see if there were issues applying or syncing (if yes, check the logs for why) - pg_replication_slots - use this to check if the slot is active and you can also calculate the lag from here -3. [Metrics](/docs/guides/telemetry/metrics) - Using the prometheus endpoint for your project +3. [Metrics](/docs/guides/monitoring-and-debugging/metrics) - Using the prometheus endpoint for your project - replication_slots_max_lag_bytes - this is the more important one - pg_stat_replication_replay_lag - lag to replay WAL files from the source DB on the target DB (throttled by disk or high activity) - pg_stat_replication_send_lag - lag in sending WAL files from the source DB (a high lag means that the publisher is not being asked to send new WAL files OR network issues) diff --git a/apps/docs/content/guides/monitoring-and-debugging.mdx b/apps/docs/content/guides/monitoring-and-debugging.mdx new file mode 100644 index 0000000000000..f6b732836aeb9 --- /dev/null +++ b/apps/docs/content/guides/monitoring-and-debugging.mdx @@ -0,0 +1,9 @@ +--- +title: Monitoring and Debugging +--- + +Monitor your project, debug errors, and understand what's happening across the Supabase stack. + + + + diff --git a/apps/docs/content/guides/telemetry/advanced-log-filtering.mdx b/apps/docs/content/guides/monitoring-and-debugging/advanced-log-filtering.mdx similarity index 100% rename from apps/docs/content/guides/telemetry/advanced-log-filtering.mdx rename to apps/docs/content/guides/monitoring-and-debugging/advanced-log-filtering.mdx diff --git a/apps/docs/content/guides/telemetry/client-side-tracing.mdx b/apps/docs/content/guides/monitoring-and-debugging/client-side-tracing.mdx similarity index 94% rename from apps/docs/content/guides/telemetry/client-side-tracing.mdx rename to apps/docs/content/guides/monitoring-and-debugging/client-side-tracing.mdx index e2e8250c7080b..49fd270ab2488 100644 --- a/apps/docs/content/guides/telemetry/client-side-tracing.mdx +++ b/apps/docs/content/guides/monitoring-and-debugging/client-side-tracing.mdx @@ -73,7 +73,7 @@ Once trace context is flowing through, the `trace_id` appears in: - **API Gateway logs** — every request to PostgREST, Auth, Storage, and Realtime - **Edge Function logs** — invocations and any structured logs emitted from within the function -If you forward Supabase logs to a third-party backend via [Log Drains](/docs/guides/telemetry/log-drains), you can join Supabase logs to your own client and server traces using the shared `trace_id`. This is especially useful for self-hosted setups where you already operate your own OpenTelemetry collector — Supabase logs become first-class citizens in your existing tracing UI. +If you forward Supabase logs to a third-party backend via [Log Drains](/docs/guides/monitoring-and-debugging/log-drains), you can join Supabase logs to your own client and server traces using the shared `trace_id`. This is especially useful for self-hosted setups where you already operate your own OpenTelemetry collector — Supabase logs become first-class citizens in your existing tracing UI. ## Using a vendor tracing SDK diff --git a/apps/docs/content/guides/telemetry/debugging.mdx b/apps/docs/content/guides/monitoring-and-debugging/debugging.mdx similarity index 92% rename from apps/docs/content/guides/telemetry/debugging.mdx rename to apps/docs/content/guides/monitoring-and-debugging/debugging.mdx index 1711e99983364..0c84be99fce20 100644 --- a/apps/docs/content/guides/telemetry/debugging.mdx +++ b/apps/docs/content/guides/monitoring-and-debugging/debugging.mdx @@ -1,22 +1,22 @@ --- id: 'debugging' -title: 'Debugging' +title: 'Debugging guide' description: 'Isolate and fix Supabase issues by reading the error, isolating the failing layer, and gathering evidence from logs.' --- Debug by evidence, not by guessing. A Supabase error almost always surfaces at one layer but originates at another, so the fastest path to a fix is finding _where_ the problem is, not pattern-matching the symptom. Retrying a failed request rarely helps; isolating the layer does. -## The debugging loop +## Follow these debugging steps Work through these steps in order, skipping straight to a fix before you have evidence for the cause is the most common way to waste time on a bug. 1. **Reproduce the issue and read the error precisely.** Capture the exact status code, the error code, and the full message, not a paraphrase. A `401` is not a `403`; `PGRST002` is not `PGRST106`; a Postgres `SQLSTATE` such as `42501`, `42P01`, or `23505` points at the exact failure. The precise error is your strongest clue. If you're using `supabase-js`, remember that errors are **returned, not thrown**, check the `error` field in the `{ data, error }` response object. Make sure your code inspects `error` — a swallowed error is why many bugs look like "nothing happened". 2. **Locate the failing layer.** Use the request stack below. The status code and error code usually name the layer for you. -3. **Gather evidence for that layer.** Query its logs, run the security and performance advisors, and inspect the schema. Logs are the primary tool, and the layer you identified in the previous step tells you which log source to query. See [Reading logs](#reading-logs) below. +3. **Gather evidence for that layer.** Query its logs, run the security and performance advisors, and inspect the schema. Logs are the primary tool, and the layer you identified in the previous step tells you which log source to query. See [Read the logs](#read-the-logs) below. 4. **Isolate the cause** using the troubleshooting guide for that layer (see [Find the guide for your symptom](#find-the-guide-for-your-symptom) below). Confirm your hypothesis against the evidence before you act. Most Supabase issues trace back to a small, known set of causes, and the guide explains how to tell them apart. 5. **Apply the fix, then verify.** Re-run the exact operation that failed and confirm it now succeeds, and that the corresponding log line is clean. A fix you haven't re-run is still a guess. If a couple of attempts don't resolve it, stop and gather more evidence rather than repeating the same change. -## The Supabase request stack +## Check the request stack A request from a client passes through several layers before it reaches your data. Errors propagate upward, so the layer that _reports_ an error is often not the layer that _caused_ it. @@ -44,7 +44,7 @@ A permission error or an unexpectedly empty result at the API layer is often a P -## Reading logs +## Read the logs Once you know the layer, query that layer's log source directly rather than scanning everything. Pick one `source`, bound the time window, and select only the fields you need. @@ -52,7 +52,7 @@ When a query comes up empty, widen along an anchor, such as a timestamp, request A wide, unfiltered query across every source buries the one line you need and, on paid projects, costs more in scanned data. -The [Logging guide](/docs/guides/telemetry/logs) covers the Logs Explorer, the available log sources, and how to write queries against them. +The [Logging guide](/docs/guides/monitoring-and-debugging/logs) covers the Logs Explorer, the available log sources, and how to write queries against them. ## Find the guide for your symptom @@ -71,8 +71,17 @@ Supabase updates these troubleshooting guides continuously, so treat this table | Realtime `TIMED_OUT`; `TooManyChannels`; silent disconnect; missed database changes; broadcast-from-DB warning; heartbeats | Realtime → `realtime_logs` | [TIMED_OUT](/docs/guides/troubleshooting/realtime-connections-timed_out-status) · [TooManyChannels](/docs/guides/troubleshooting/realtime-too-many-channels-error) · [Silent disconnects](/docs/guides/troubleshooting/realtime-handling-silent-disconnections-in-backgrounded-applications-592794) · [Broadcast warning](/docs/guides/troubleshooting/realtime-warn-sending-broadcast-message) · [Heartbeats](/docs/guides/troubleshooting/realtime-heartbeat-messages) · [Logger](/docs/guides/troubleshooting/realtime-debugging-with-logger) | | Upload or list fails; public bucket inaccessible; `relation "objects" does not exist`; file size limit; folder or RLS issue | Storage → `storage_logs`, `postgres_logs` | [Public bucket upload/list](/docs/guides/troubleshooting/why-cant-i-uploadlistetc-my-public-bucket-Z6CmGt) · [403 RLS on upload](/docs/guides/troubleshooting/storage-error-403-forbidden-new-row-violates-row-level-security-policy-on-upload-a94384) · [relation objects does not exist](/docs/guides/troubleshooting/relation-objects-does-not-exist-error-during-storage-uploads-8f21f0) · [File size limits](/docs/guides/troubleshooting/upload-file-size-restrictions-Y4wQLT) · [Folder ops / hierarchical RLS](/docs/guides/troubleshooting/supabase-storage-inefficient-folder-operations-and-hierarchical-rls-challenges-b05a4d) | | Webhook not firing; `pg_cron` job not running; `pg_net` queue stuck; `42501 ... http_request_queue` | Database jobs → `postgres_logs` | [Webhook debugging](/docs/guides/troubleshooting/webhook-debugging-guide-M8sk47) · [pg_cron debugging](/docs/guides/troubleshooting/pgcron-debugging-guide-n1KTaz) · [42501 http_request_queue](/docs/guides/troubleshooting/42501--permission-denied-for-table-httprequestqueue-KnozmQ) | -| Reading or querying logs; interpreting Postgres logs; finding API errors in logs; reading metrics | Diagnostics → any log source | [Logging guide](/docs/guides/telemetry/logs) · [Interpret Postgres logs](/docs/guides/troubleshooting/how-to-interpret-and-explore-the-postgres-logs-OuCIOj) · [API errors in logs](/docs/guides/troubleshooting/discovering-and-interpreting-api-errors-in-the-logs-7xREI9) · [Logging levels](/docs/guides/troubleshooting/understanding-postgresql-logging-levels-and-how-they-impact-your-project-KXiJRm) · [View database metrics](/docs/guides/troubleshooting/how-to-view-database-metrics-uqf2z_) | +| Reading or querying logs; interpreting Postgres logs; finding API errors in logs; reading metrics | Diagnostics → any log source | [Logging guide](/docs/guides/monitoring-and-debugging/logs) · [Interpret Postgres logs](/docs/guides/troubleshooting/how-to-interpret-and-explore-the-postgres-logs-OuCIOj) · [API errors in logs](/docs/guides/troubleshooting/discovering-and-interpreting-api-errors-in-the-logs-7xREI9) · [Logging levels](/docs/guides/troubleshooting/understanding-postgresql-logging-levels-and-how-they-impact-your-project-KXiJRm) · [View database metrics](/docs/guides/troubleshooting/how-to-view-database-metrics-uqf2z_) | For query performance and schema-design questions such as indexing, `EXPLAIN`, N+1 queries, or partitioning, see the [Postgres guides](/docs/guides/database/overview). Debugging is complete only once you've re-run the failing operation, confirmed it succeeds, and checked that the layer's logs show a clean result. + +## Per-product debugging + +Each Supabase product has its own debugging resources. Use these as a starting point when the error originates in a specific service. + +- [Database — Debugging and monitoring](/docs/guides/database/inspect) +- [Auth — Error codes](/docs/guides/auth/debugging/error-codes) +- [Storage — Debugging](/docs/guides/storage/debugging/logs) +- [Edge Functions — Local debugging](/docs/guides/functions/debugging-tools) diff --git a/apps/docs/content/guides/telemetry/log-drains.mdx b/apps/docs/content/guides/monitoring-and-debugging/log-drains.mdx similarity index 96% rename from apps/docs/content/guides/telemetry/log-drains.mdx rename to apps/docs/content/guides/monitoring-and-debugging/log-drains.mdx index 3934c7b5d7d16..8ca351c8bbde2 100644 --- a/apps/docs/content/guides/telemetry/log-drains.mdx +++ b/apps/docs/content/guides/monitoring-and-debugging/log-drains.mdx @@ -9,7 +9,7 @@ Log drains send all logs of the Supabase stack to one or more desired destinatio ## What you can do with log drains - Route Supabase logs (Postgres, Auth, Storage, Edge Functions, and more) to any observability platform. -- Combine Supabase logs with application-level traces — see [Tracing with the JS SDK](/docs/guides/telemetry/client-side-tracing) to extend your traces into Supabase. +- Combine Supabase logs with application-level traces — see [Tracing with the JS SDK](/docs/guides/monitoring-and-debugging/client-side-tracing) to extend your traces into Supabase. - Archive logs to S3 for long-term retention and compliance. - Build alerts and dashboards on top of Supabase log data in your preferred vendor. @@ -335,5 +335,5 @@ Logs are forwarded to a remote Syslog receiver using TCP or TLS, adhering to [RF ## Additional resources - [Log Drains pricing breakdown](/docs/guides/platform/manage-your-usage/log-drains) — cost per drain, per million events, and egress charges. -- [Metrics API](/docs/guides/telemetry/metrics) — export Postgres performance metrics alongside your logs. -- [Tracing with the JS SDK](/docs/guides/telemetry/client-side-tracing) — instrument your application and combine traces with Supabase logs. +- [Metrics API](/docs/guides/monitoring-and-debugging/metrics) — export Postgres performance metrics alongside your logs. +- [Tracing with the JS SDK](/docs/guides/monitoring-and-debugging/client-side-tracing) — instrument your application and combine traces with Supabase logs. diff --git a/apps/docs/content/guides/telemetry/log-field-reference.mdx b/apps/docs/content/guides/monitoring-and-debugging/log-field-reference.mdx similarity index 92% rename from apps/docs/content/guides/telemetry/log-field-reference.mdx rename to apps/docs/content/guides/monitoring-and-debugging/log-field-reference.mdx index c7eb0fa1bfc01..0f18f06eb8674 100644 --- a/apps/docs/content/guides/telemetry/log-field-reference.mdx +++ b/apps/docs/content/guides/monitoring-and-debugging/log-field-reference.mdx @@ -4,7 +4,7 @@ title: 'Logs field reference' description: 'Supabase Logs field reference' --- -Refer to the full field reference for each available source below. To access each nested key, you need to perform the [necessary unnesting joins](/docs/guides/telemetry/advanced-log-filtering#unnesting-arrays) +Refer to the full field reference for each available source below. To access each nested key, you need to perform the [necessary unnesting joins](/docs/guides/monitoring-and-debugging/advanced-log-filtering#unnesting-arrays) {(logConstants) => ( diff --git a/apps/docs/content/guides/telemetry/logs.mdx b/apps/docs/content/guides/monitoring-and-debugging/logs.mdx similarity index 97% rename from apps/docs/content/guides/telemetry/logs.mdx rename to apps/docs/content/guides/monitoring-and-debugging/logs.mdx index 9b945fdf21731..c63d3faf3ed3e 100644 --- a/apps/docs/content/guides/telemetry/logs.mdx +++ b/apps/docs/content/guides/monitoring-and-debugging/logs.mdx @@ -6,10 +6,22 @@ description: 'Getting started with Supabase Log Browser' The Supabase Platform includes a Logs Explorer that allows log tracing and debugging. Log retention is based on your [project's pricing plan](/pricing). For details on how Logs usage is billed, see [Manage Logs usage](/docs/guides/platform/manage-your-usage/logs). + + +If you are debugging a specific error or unexpected behavior, start with the [Debugging guide](/docs/guides/monitoring-and-debugging/debugging) — it routes you to the right log source based on your error code or symptom before you open the Logs Explorer. + + + ## Product logs Supabase provides a logging interface specific to each product. You can use regular expressions for keywords and patterns to search log event messages. You can also export and download the log events matching your query as a spreadsheet. + + +For regular expression filtering, structured-field queries, and field discovery techniques, see [Advanced log filtering](/docs/guides/monitoring-and-debugging/advanced-log-filtering). + + + {/* */} -If you are already ingesting your [project's metrics](/docs/guides/telemetry/metrics) into your own environment, you can also keep track of replication lag and set alarms with the `physical_replication_lag_physical_replica_lag_seconds` metric. +If you are already ingesting your [project's metrics](/docs/guides/monitoring-and-debugging/metrics) into your own environment, you can also keep track of replication lag and set alarms with the `physical_replication_lag_physical_replica_lag_seconds` metric. diff --git a/apps/docs/content/guides/security/platform-audit-logs.mdx b/apps/docs/content/guides/security/platform-audit-logs.mdx index 1ead782aa0d5b..47344d0169693 100644 --- a/apps/docs/content/guides/security/platform-audit-logs.mdx +++ b/apps/docs/content/guides/security/platform-audit-logs.mdx @@ -46,7 +46,7 @@ Each Supabase user account also has access to [Account Audit logs](/dashboard/ac ## Accessing Audit Log Drains -Audit Log Drains can be configured under your [organization's audit log drains](/dashboard/org/_/audit-log-drains). For setup instructions and supported destinations, see the [Log Drains guide](/docs/guides/telemetry/log-drains). +Audit Log Drains can be configured under your [organization's audit log drains](/dashboard/org/_/audit-log-drains). For setup instructions and supported destinations, see the [Log Drains guide](/docs/guides/monitoring-and-debugging/log-drains). ## Limitations diff --git a/apps/docs/content/guides/storage/cdn/metrics.mdx b/apps/docs/content/guides/storage/cdn/metrics.mdx index f6da42077dacd..13818122f1482 100644 --- a/apps/docs/content/guides/storage/cdn/metrics.mdx +++ b/apps/docs/content/guides/storage/cdn/metrics.mdx @@ -5,7 +5,7 @@ description: 'Learn how Supabase Storage caches objects with a CDN.' sidebar_label: 'CDN' --- -Cache hits can be determined via the `metadata.response.headers.cf_cache_status` key in our [Logs Explorer](/docs/guides/telemetry/logs#logs-explorer). Any value that corresponds to either `HIT`, `STALE`, `REVALIDATED`, or `UPDATING` is categorized as a cache hit. +Cache hits can be determined via the `metadata.response.headers.cf_cache_status` key in our [Logs Explorer](/docs/guides/monitoring-and-debugging/logs#logs-explorer). Any value that corresponds to either `HIT`, `STALE`, `REVALIDATED`, or `UPDATING` is categorized as a cache hit. The following example query will show the top cache misses from the `edge_logs`: ```sql diff --git a/apps/docs/content/guides/storage/debugging/logs.mdx b/apps/docs/content/guides/storage/debugging/logs.mdx index ec9e9a36b46ca..9470a55b25e58 100644 --- a/apps/docs/content/guides/storage/debugging/logs.mdx +++ b/apps/docs/content/guides/storage/debugging/logs.mdx @@ -11,7 +11,7 @@ For more advanced filtering needs, use the [Logs Explorer](/dashboard/project/_/ -For more details on filtering the log tables, see [Advanced Log Filtering](/docs/guides/telemetry/advanced-log-filtering) +For more details on filtering the log tables, see [Advanced Log Filtering](/docs/guides/monitoring-and-debugging/advanced-log-filtering) diff --git a/apps/docs/content/guides/telemetry.mdx b/apps/docs/content/guides/telemetry.mdx deleted file mode 100644 index 8fb40504b9f37..0000000000000 --- a/apps/docs/content/guides/telemetry.mdx +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: Telemetry ---- - -Telemetry helps you understand what’s happening inside your app by collecting logs, metrics, and traces. - -- **Logs** capture individual events, such as errors or warnings, providing details about what happened at a specific moment. -- **Metrics** track numerical data over time, like request latency or database query performance, helping you spot trends. -- **Traces** show the flow of a request through different services, helping you debug slow or failing operations. - -Supabase is working towards full support for the [OpenTelemetry](https://opentelemetry.io/) standard, making it easier to integrate with observability tools. - -This section provides guidance on telemetry in Supabase, including how to work with Supabase Logs. diff --git a/apps/docs/content/troubleshooting/exhaust-disk-io.mdx b/apps/docs/content/troubleshooting/exhaust-disk-io.mdx index 555860671bb35..0df86d3eaace3 100644 --- a/apps/docs/content/troubleshooting/exhaust-disk-io.mdx +++ b/apps/docs/content/troubleshooting/exhaust-disk-io.mdx @@ -25,7 +25,7 @@ Running out of Disk IO Budget means that your instance is using more disk than i To check your Disk IO Budget on the Supabase Platform, head over to [Database Health in the Observability section](/dashboard/project/_/observability/database). -It is also possible to monitor your resources and set up alerts using Prometheus/Grafana. With Grafana you will be able to pinpoint potential causes and see more fine-grained metrics like how much of your RAM is used for caching and your Swap usage. Read the [Metrics Guide](/docs/guides/telemetry/metrics) to learn more. +It is also possible to monitor your resources and set up alerts using Prometheus/Grafana. With Grafana you will be able to pinpoint potential causes and see more fine-grained metrics like how much of your RAM is used for caching and your Swap usage. Read the [Metrics Guide](/docs/guides/monitoring-and-debugging/metrics) to learn more. ## Common reasons for high disk IO usage diff --git a/apps/docs/content/troubleshooting/exhaust-ram.mdx b/apps/docs/content/troubleshooting/exhaust-ram.mdx index 51601f7c25628..30351258315a4 100644 --- a/apps/docs/content/troubleshooting/exhaust-ram.mdx +++ b/apps/docs/content/troubleshooting/exhaust-ram.mdx @@ -31,7 +31,7 @@ High RAM usage could come with a range of issues: To check your RAM usage on the Supabase Platform, head over to [Database Health in the Observability section](/dashboard/project/_/observability/database). -It is also possible to monitor your resources and set up alerts using Prometheus/Grafana. With Grafana you will be able to see how much of your RAM is used for caching and you can track other metrics such as your Swap usage. Read the [Metrics Guide](/docs/guides/telemetry/metrics) to learn more. +It is also possible to monitor your resources and set up alerts using Prometheus/Grafana. With Grafana you will be able to see how much of your RAM is used for caching and you can track other metrics such as your Swap usage. Read the [Metrics Guide](/docs/guides/monitoring-and-debugging/metrics) to learn more. ## Common reasons for high RAM usage diff --git a/apps/docs/content/troubleshooting/exhaust-swap.mdx b/apps/docs/content/troubleshooting/exhaust-swap.mdx index f7c0bcf69c51b..5f8b5c60f201d 100644 --- a/apps/docs/content/troubleshooting/exhaust-swap.mdx +++ b/apps/docs/content/troubleshooting/exhaust-swap.mdx @@ -33,7 +33,7 @@ High Swap usage can affect your database performance. For example, you might see ## Monitor your swap -You can monitor your resources and set up alerts using Prometheus/Grafana. See the [metrics guide](/docs/guides/telemetry/metrics) for more information. +You can monitor your resources and set up alerts using Prometheus/Grafana. See the [metrics guide](/docs/guides/monitoring-and-debugging/metrics) for more information. An [example repository](https://github.com/supabase/supabase-grafana) to ingest metrics and visualize them with Grafana is provided in the linked guide, where we maintain a [list of the exported metrics](https://github.com/supabase/supabase-grafana/blob/main/docs/metrics.md). diff --git a/apps/docs/content/troubleshooting/failed-to-retrieve-tables.mdx b/apps/docs/content/troubleshooting/failed-to-retrieve-tables.mdx index 5160ea8cbb5c8..acda37f4d4cc1 100644 --- a/apps/docs/content/troubleshooting/failed-to-retrieve-tables.mdx +++ b/apps/docs/content/troubleshooting/failed-to-retrieve-tables.mdx @@ -43,4 +43,4 @@ Once you are confident there will not be a crash loop, you can review the follow - Continue to monitor your project's [query performance tab](/dashboard/project/_/observability/query-performance) and [enable index advisor](/docs/guides/database/extensions/index_advisor) if you haven't already - especially if there are a lot of select queries. - If after monitoring your changes you still do not notice improvements, consider upgrading compute if you think this level of activity is going to be regular. It will give you more memory overhead to process tasks like this. You can view all compute offerings [here](/dashboard/project/_/settings/infrastructure). -If you want to effectively monitor your project's performance minute by minute, you can use the [Metrics API](/docs/guides/telemetry/metrics). +If you want to effectively monitor your project's performance minute by minute, you can use the [Metrics API](/docs/guides/monitoring-and-debugging/metrics). diff --git a/apps/docs/content/troubleshooting/failed-to-run-sql-query-connection-terminated-due-to-connection-timeout.mdx b/apps/docs/content/troubleshooting/failed-to-run-sql-query-connection-terminated-due-to-connection-timeout.mdx index 83e85220dc7c0..351692dc37c45 100644 --- a/apps/docs/content/troubleshooting/failed-to-run-sql-query-connection-terminated-due-to-connection-timeout.mdx +++ b/apps/docs/content/troubleshooting/failed-to-run-sql-query-connection-terminated-due-to-connection-timeout.mdx @@ -23,4 +23,4 @@ Review the appropriate guides based on your scenario: - [High Disk I/O](/docs/guides/troubleshooting/exhaust-disk-io) - [Query optimization](/docs/guides/database/query-optimization) -You can also set up alerts using a [Prometheus endpoint / Grafana charts](/docs/guides/telemetry/metrics) to monitor vital resources. +You can also set up alerts using a [Prometheus endpoint / Grafana charts](/docs/guides/monitoring-and-debugging/metrics) to monitor vital resources. diff --git a/apps/docs/content/troubleshooting/high-cpu-usage.mdx b/apps/docs/content/troubleshooting/high-cpu-usage.mdx index b80d3dc4e61a3..eedcf49ba233a 100644 --- a/apps/docs/content/troubleshooting/high-cpu-usage.mdx +++ b/apps/docs/content/troubleshooting/high-cpu-usage.mdx @@ -25,7 +25,7 @@ You can check your CPU usage directly on the Supabase Platform. For this go to d ![CPU usage reported on Supabase dashboard](/docs/img/guides/platform/exhaust-cpu-report.png) -It is also possible to monitor your resources and set up alerts using Prometheus/Grafana. You can find a guide for this [here](/docs/guides/telemetry/metrics). +It is also possible to monitor your resources and set up alerts using Prometheus/Grafana. You can find a guide for this [here](/docs/guides/monitoring-and-debugging/metrics). ## Common reasons for high CPU usage diff --git a/apps/docs/content/troubleshooting/how-to-interpret-and-explore-the-postgres-logs-OuCIOj.mdx b/apps/docs/content/troubleshooting/how-to-interpret-and-explore-the-postgres-logs-OuCIOj.mdx index c0ece19c525e5..a05664e26540b 100644 --- a/apps/docs/content/troubleshooting/how-to-interpret-and-explore-the-postgres-logs-OuCIOj.mdx +++ b/apps/docs/content/troubleshooting/how-to-interpret-and-explore-the-postgres-logs-OuCIOj.mdx @@ -398,5 +398,5 @@ To see the default types of events that are logged, you can check this [guide](h - [Debugging with the DB API logs](https://github.com/orgs/supabase/discussions/22849) - [Debugging Database Functions](/docs/guides/database/functions#debugging-functions) - [pg_audit](/docs/guides/database/extensions/pgaudit) -- [Supabase Logging](/docs/guides/telemetry/logs) +- [Supabase Logging](/docs/guides/monitoring-and-debugging/logs) - [Self-Hosting Logs](/docs/reference/self-hosting-analytics/introduction) diff --git a/apps/docs/content/troubleshooting/how-to-view-database-metrics-uqf2z_.mdx b/apps/docs/content/troubleshooting/how-to-view-database-metrics-uqf2z_.mdx index e5a1b47614dfd..ee301203a7d81 100644 --- a/apps/docs/content/troubleshooting/how-to-view-database-metrics-uqf2z_.mdx +++ b/apps/docs/content/troubleshooting/how-to-view-database-metrics-uqf2z_.mdx @@ -7,6 +7,6 @@ keywords = [ "metrics", "grafana", "monitoring" ] database_id = "da2d95e5-abc5-47c8-8389-1554d12abf91" --- -To monitor real-time metrics of your database, like CPU, EBS, active database connections, and memory usage, you can deploy a Grafana Dashboard. Check our [GitHub repo](https://github.com/supabase/supabase-grafana) for setup instructions for local or free [Fly.io](http://fly.io/) deployments. Refer to our concise [documentation](/docs/guides/telemetry/metrics) to learn more about the metrics endpoint. +To monitor real-time metrics of your database, like CPU, EBS, active database connections, and memory usage, you can deploy a Grafana Dashboard. Check our [GitHub repo](https://github.com/supabase/supabase-grafana) for setup instructions for local or free [Fly.io](http://fly.io/) deployments. Refer to our concise [documentation](/docs/guides/monitoring-and-debugging/metrics) to learn more about the metrics endpoint. While the [Dashboard's Reports Page](/dashboard/project/_/observability) displays some metric data, it provides hourly averages, not real-time by the second data. However, it offers query metrics, which the Grafana Dashboard does not include. diff --git a/apps/docs/content/troubleshooting/interpreting-supabase-grafana-io-charts-MUynDR.mdx b/apps/docs/content/troubleshooting/interpreting-supabase-grafana-io-charts-MUynDR.mdx index c84fc4b9776e6..430f998536714 100644 --- a/apps/docs/content/troubleshooting/interpreting-supabase-grafana-io-charts-MUynDR.mdx +++ b/apps/docs/content/troubleshooting/interpreting-supabase-grafana-io-charts-MUynDR.mdx @@ -7,7 +7,7 @@ keywords = [ "io", "disk", "database", "grafana" ] database_id = "0056cd40-df04-4045-bbfb-c245cb15b85d" --- -> [Supabase Grafana Installation Guide](/docs/guides/telemetry/metrics/grafana-self-hosted) +> [Supabase Grafana Installation Guide](/docs/guides/monitoring-and-debugging/metrics/grafana-self-hosted) There are two primary values that matter for IO: diff --git a/apps/docs/content/troubleshooting/monitor-supavisor-postgres-connections.mdx b/apps/docs/content/troubleshooting/monitor-supavisor-postgres-connections.mdx index 8db9630f2d0c0..6b1592a592ad7 100644 --- a/apps/docs/content/troubleshooting/monitor-supavisor-postgres-connections.mdx +++ b/apps/docs/content/troubleshooting/monitor-supavisor-postgres-connections.mdx @@ -19,7 +19,7 @@ _Visual of Grafana Dashboard_ It can be run locally within Docker. Alternatively, you can deploy it to fly.io or Grafana Cloud, which are better for long-term data collection. -Installation instructions can be found in it the [metrics docs ](/docs/guides/telemetry/metrics/grafana-self-hosted) +Installation instructions can be found in it the [metrics docs ](/docs/guides/monitoring-and-debugging/metrics/grafana-self-hosted) ## Observing connections diff --git a/apps/docs/content/troubleshooting/steps-to-improve-query-performance-with-indexes-q8PoC9.mdx b/apps/docs/content/troubleshooting/steps-to-improve-query-performance-with-indexes-q8PoC9.mdx index 0409f56edb801..2abdb07268c5f 100644 --- a/apps/docs/content/troubleshooting/steps-to-improve-query-performance-with-indexes-q8PoC9.mdx +++ b/apps/docs/content/troubleshooting/steps-to-improve-query-performance-with-indexes-q8PoC9.mdx @@ -23,7 +23,7 @@ Supabase has an [open-source Grafana Repo](https://github.com/supabase/supabase- _Visual of Grafana Dashboard_ ![image](/docs/img/troubleshooting/18ed2c88-332e-4e66-b9b4-c37e99a39104.png) -It can be run locally within Docker or can be deployed for free to fly.io. Installation instructions can be found in [Supabase's metrics docs](/docs/guides/telemetry/metrics/grafana-self-hosted) +It can be run locally within Docker or can be deployed for free to fly.io. Installation instructions can be found in [Supabase's metrics docs](/docs/guides/monitoring-and-debugging/metrics/grafana-self-hosted) ### Query optimization through indexes diff --git a/apps/docs/content/troubleshooting/supabase-grafana-memory-charts.mdx b/apps/docs/content/troubleshooting/supabase-grafana-memory-charts.mdx index ffe0ad78aecf7..de577915a8da5 100644 --- a/apps/docs/content/troubleshooting/supabase-grafana-memory-charts.mdx +++ b/apps/docs/content/troubleshooting/supabase-grafana-memory-charts.mdx @@ -7,7 +7,7 @@ date_created = "2024-06-05" database_id = "179d70f3-1e26-4346-9ee8-d340fad382a3" --- -> [Supabase Grafana Installation Guide](/docs/guides/telemetry/metrics/grafana-self-hosted) +> [Supabase Grafana Installation Guide](/docs/guides/monitoring-and-debugging/metrics/grafana-self-hosted) Here are examples of unhealthy memory usage: ![image](https://github.com/supabase/supabase/assets/91111415/baebfc74-642d-4988-992c-bb0f473a05ad) diff --git a/apps/docs/content/troubleshooting/supavisor-faq-YyP5tI.mdx b/apps/docs/content/troubleshooting/supavisor-faq-YyP5tI.mdx index 0bf72e502c815..1b1ed37893bf5 100644 --- a/apps/docs/content/troubleshooting/supavisor-faq-YyP5tI.mdx +++ b/apps/docs/content/troubleshooting/supavisor-faq-YyP5tI.mdx @@ -159,7 +159,7 @@ As a rule of thumb, if you're using the DB REST API or multiple app-based "user+ Connection usage can be monitored with a Supabase Grafana Dashboard. It provides realtime visibility of over 200 database metrics, such as graphs of CPU, EBS, and active direct/pooler connections. It can be extremely useful for monitoring and debugging instances. -You can check our [GitHub repo](https://github.com/supabase/supabase-grafana) for setup instructions for local deployments or free cloud deployments on [Fly.io](http://fly.io/). Refer to Supabase [documentation](/docs/guides/telemetry/metrics) to learn more about the metrics endpoint. +You can check our [GitHub repo](https://github.com/supabase/supabase-grafana) for setup instructions for local deployments or free cloud deployments on [Fly.io](http://fly.io/). Refer to Supabase [documentation](/docs/guides/monitoring-and-debugging/metrics) to learn more about the metrics endpoint. ### **Can Supavisor really support a million connections?** diff --git a/apps/docs/data/content-listings/index.ts b/apps/docs/data/content-listings/index.ts index c4320456003b3..bf0e5f9353750 100644 --- a/apps/docs/data/content-listings/index.ts +++ b/apps/docs/data/content-listings/index.ts @@ -21,6 +21,7 @@ import { selfHostingShareExperience, } from './self-hosting.data' import { storageExamples, storageGetStarted, storageResources } from './storage.data' +import { telemetryDebugging, telemetryMonitoring } from './telemetry.data' const ALL_GROUPS: readonly ContentListingGroup[] = [ aiToolsSupportedAgents, @@ -48,6 +49,8 @@ const ALL_GROUPS: readonly ContentListingGroup[] = [ storageGetStarted, storageExamples, storageResources, + telemetryDebugging, + telemetryMonitoring, ] export const CONTENT_LISTINGS: Readonly> = Object.fromEntries( diff --git a/apps/docs/data/content-listings/log-drains.data.ts b/apps/docs/data/content-listings/log-drains.data.ts index d828ff2e9233f..d8f4b9f7f0c68 100644 --- a/apps/docs/data/content-listings/log-drains.data.ts +++ b/apps/docs/data/content-listings/log-drains.data.ts @@ -9,55 +9,55 @@ export const logDrainsDestinations: ContentListingGroup = { { title: 'Custom Endpoint', description: 'Forward logs as a POST request to any custom HTTP endpoint.', - href: '/guides/telemetry/log-drains#custom-endpoint', + href: '/guides/monitoring-and-debugging/log-drains#custom-endpoint', icon: { kind: 'braces', color: '#3ECF8E', bg: 'rgba(62,207,142,0.1)' }, }, { title: 'OpenTelemetry (OTLP)', description: 'Send logs to any OTLP-compatible endpoint using Protocol Buffers over HTTP.', - href: '/guides/telemetry/log-drains#opentelemetry-otlp', + href: '/guides/monitoring-and-debugging/log-drains#opentelemetry-otlp', icon: { kind: 'otlp', color: '#F5A623', bg: 'rgba(245,166,35,0.1)' }, }, { title: 'Datadog', description: 'Stream logs directly into Datadog for monitoring and analysis.', - href: '/guides/telemetry/log-drains#datadog', + href: '/guides/monitoring-and-debugging/log-drains#datadog', icon: { kind: 'datadog', color: '#632CA6', bg: 'rgba(99,44,166,0.1)' }, }, { title: 'Loki', description: 'Ingest logs into Grafana Loki using the HTTP push API.', - href: '/guides/telemetry/log-drains#loki', + href: '/guides/monitoring-and-debugging/log-drains#loki', icon: { kind: 'grafana', color: '#F05A28', bg: 'rgba(240,90,40,0.1)' }, }, { title: 'Amazon S3', description: 'Write batched log files directly to an S3 bucket you own.', - href: '/guides/telemetry/log-drains#amazon-s3', + href: '/guides/monitoring-and-debugging/log-drains#amazon-s3', icon: { kind: 'cloud', color: '#FF9900', bg: 'rgba(255,153,0,0.1)' }, }, { title: 'Sentry', description: "Send logs to Sentry's Logging product for filtering and grouping.", - href: '/guides/telemetry/log-drains#sentry', + href: '/guides/monitoring-and-debugging/log-drains#sentry', icon: { kind: 'sentry', color: '#362D59', bg: 'rgba(54,45,89,0.1)' }, }, { title: 'Axiom', description: 'Forward logs to an Axiom dataset for storage and analysis.', - href: '/guides/telemetry/log-drains#axiom', + href: '/guides/monitoring-and-debugging/log-drains#axiom', icon: { kind: 'axiom', color: '#6366F1', bg: 'rgba(99,102,241,0.1)' }, }, { title: 'Last9', description: 'Stream logs to Last9 for OpenTelemetry-native observability.', - href: '/guides/telemetry/log-drains#last9', + href: '/guides/monitoring-and-debugging/log-drains#last9', icon: { kind: 'last9', color: '#00B4A0', bg: 'rgba(0,180,160,0.1)' }, }, { title: 'Syslog', description: 'Forward logs to a remote Syslog receiver over TCP or TLS (RFC 5424).', - href: '/guides/telemetry/log-drains#syslog', + href: '/guides/monitoring-and-debugging/log-drains#syslog', icon: { kind: 'server', color: '#64748B', bg: 'rgba(100,116,139,0.1)' }, }, ], diff --git a/apps/docs/data/content-listings/telemetry.data.ts b/apps/docs/data/content-listings/telemetry.data.ts new file mode 100644 index 0000000000000..93ba564a30084 --- /dev/null +++ b/apps/docs/data/content-listings/telemetry.data.ts @@ -0,0 +1,65 @@ +import type { ContentListingGroup } from '~/lib/content-listings.schema' + +export const telemetryDebugging: ContentListingGroup = { + id: 'telemetry-debugging', + heading: 'Debugging', + type: 'grid', + columns: 2, + items: [ + { + title: 'Debugging guide', + href: '/guides/monitoring-and-debugging/debugging', + description: + 'Isolate the failing layer, read logs as evidence, and match symptoms to troubleshooting guides.', + }, + { + title: 'Logging', + href: '/guides/monitoring-and-debugging/logs', + description: 'Query events from any Supabase service using the Logs Explorer.', + }, + { + title: 'Advanced log filtering', + href: '/guides/monitoring-and-debugging/advanced-log-filtering', + description: 'Regex filtering, structured-field queries, and field discovery in ClickHouse.', + }, + { + title: 'Troubleshooting index', + href: '/guides/troubleshooting', + description: 'Searchable index of known error codes, symptoms, and fixes.', + }, + ], +} + +export const telemetryMonitoring: ContentListingGroup = { + id: 'telemetry-monitoring', + heading: 'Monitoring', + type: 'grid', + columns: 2, + items: [ + { + title: 'Log drains', + href: '/guides/monitoring-and-debugging/log-drains', + description: 'Forward logs to Datadog, Loki, Axiom, S3, or a custom HTTP endpoint.', + }, + { + title: 'Reports', + href: '/guides/monitoring-and-debugging/reports', + description: 'Built-in dashboards for API, Auth, Storage, and Realtime activity.', + }, + { + title: 'Metrics', + href: '/guides/monitoring-and-debugging/metrics', + description: 'Prometheus-compatible database metrics for Grafana and other tools.', + }, + { + title: 'Client-side tracing', + href: '/guides/monitoring-and-debugging/client-side-tracing', + description: 'Correlate browser requests end-to-end using W3C Trace Context.', + }, + { + title: 'Sentry integration', + href: '/guides/monitoring-and-debugging/sentry-monitoring', + description: 'Send errors to Sentry for alerting and grouping.', + }, + ], +} diff --git a/apps/docs/features/docs/GuidesMdx.utils.tsx b/apps/docs/features/docs/GuidesMdx.utils.tsx index fc47f2664aeef..70a23ed0961b4 100644 --- a/apps/docs/features/docs/GuidesMdx.utils.tsx +++ b/apps/docs/features/docs/GuidesMdx.utils.tsx @@ -33,6 +33,7 @@ const PUBLISHED_SECTIONS = [ 'graphql', 'integrations', 'local-development', + 'monitoring-and-debugging', 'platform', 'queues', 'realtime', @@ -40,7 +41,6 @@ const PUBLISHED_SECTIONS = [ 'security', 'self-hosting', 'storage', - 'telemetry', ] as const const getGuidesMarkdownInternal = async (slug: string[]) => { diff --git a/apps/docs/lib/breadcrumbs.ts b/apps/docs/lib/breadcrumbs.ts index 6ca51d642bc72..ac6643c80b574 100644 --- a/apps/docs/lib/breadcrumbs.ts +++ b/apps/docs/lib/breadcrumbs.ts @@ -26,7 +26,7 @@ const SECTION_PATH_TO_KEY: Record = { security: 'security', 'self-hosting': 'self_hosting', storage: 'storage', - telemetry: 'telemetry', + 'monitoring-and-debugging': 'telemetry', } function getSectionMenu(pathname: string) { diff --git a/apps/docs/lib/content-listings.test.ts b/apps/docs/lib/content-listings.test.ts index 37d54128d73a4..0c609a60699bb 100644 --- a/apps/docs/lib/content-listings.test.ts +++ b/apps/docs/lib/content-listings.test.ts @@ -189,7 +189,7 @@ describe('dashboard content listing hrefs', () => { describe('contentListingItemSchema icon', () => { const baseItem = { title: 'Datadog', - href: '/guides/telemetry/log-drains#datadog', + href: '/guides/monitoring-and-debugging/log-drains#datadog', description: 'Stream logs directly into Datadog for monitoring and analysis.', } diff --git a/apps/www/lib/redirects.js b/apps/www/lib/redirects.js index ccff21267ae50..33e95d0c4ddcb 100644 --- a/apps/www/lib/redirects.js +++ b/apps/www/lib/redirects.js @@ -119,6 +119,11 @@ module.exports = [ source: '/docs/guides/reports/:match*', destination: '/docs/guides/observability/:match*', }, + { + permanent: true, + source: '/docs/guides/telemetry/:match*', + destination: '/docs/guides/monitoring-and-debugging/:match*', + }, { permanent: false, source: '/blog/2021/03/08/toad-a-link-shorterner-with-simple-apis-for-low-coders', From 5a3e3598d0a383830f7eccd1acf53035081af02c Mon Sep 17 00:00:00 2001 From: Daniel Guerra <15204776+danielmx-dev@users.noreply.github.com> Date: Thu, 30 Jul 2026 07:55:40 -0600 Subject: [PATCH 09/12] feat(billing): Lazy load BillingSettings queries for components that are not in view (#48454) ## What kind of change does this PR introduce? There are some expensive queries that are requested every time the Billing Settings page loads, some of them happen for components that are outside of the initial viewport. We can avoid performing those requests unless the user explicitly scrolls to the relevant section. A similar pattern has been implemented in the past for the Credit Balance section in https://github.com/supabase/supabase/pull/45481. I decided to skip the lazy load pattern in the components that appear at the top of the Billing Settings (Subscription and Cost Control). ## What is the current behavior? When loading the billing settings page, all components (except CreditBalance) will perform requests to load the data they need. ## What is the new behavior? The components will perform the request to load their data until they are inside the viewport. You can verify this by opening the developer tools and monitor the requests as you scroll through the page. ## Testing These changes can be easily tested by making your browser's height very short then opening the org billing settings `/org/{slug}/billing`. Open the developer tools and filter for XHR requests. As you scroll through the page, the requests will be made. To verify that all potential requests are covered, I compared the requests done during a fresh load with another settings page, the only extra requests made by the billing settings page are the ones relevant to the components at the very top (or the BillingSettings container itself, which requests the subscription). ## Summary by CodeRabbit * **Performance Improvements** * Billing, payment methods, billing customer details, upcoming invoices, and invoice lists now load only when their sections scroll into view, reducing initial loading. * Existing access/permission checks are still applied before fetching billing-related data. * **Tests** * Updated billing and invoices tests to mock viewport intersection behavior (IntersectionObserver) to match the new lazy-loading behavior. --- .../Payment/PaymentMethods/PaymentMethods.test.tsx | 3 +++ .../Payment/PaymentMethods/PaymentMethods.tsx | 8 +++++--- .../BillingBreakdown/UpcomingInvoice.tsx | 9 ++++++--- .../BillingCustomerData/BillingCustomerData.test.tsx | 3 +++ .../BillingCustomerData/BillingCustomerData.tsx | 12 +++++++++--- .../Organization/BillingSettings/BillingEmail.tsx | 7 +++++-- .../InvoicesSettings/InvoicesSettings.test.tsx | 3 +++ .../InvoicesSettings/InvoicesSettings.tsx | 10 +++++++--- 8 files changed, 41 insertions(+), 14 deletions(-) diff --git a/apps/studio/components/interfaces/Billing/Payment/PaymentMethods/PaymentMethods.test.tsx b/apps/studio/components/interfaces/Billing/Payment/PaymentMethods/PaymentMethods.test.tsx index fecbfd6e02f66..29dbe25a73c10 100644 --- a/apps/studio/components/interfaces/Billing/Payment/PaymentMethods/PaymentMethods.test.tsx +++ b/apps/studio/components/interfaces/Billing/Payment/PaymentMethods/PaymentMethods.test.tsx @@ -1,10 +1,13 @@ import { screen } from '@testing-library/react' +import { mockIntersectionObserver } from 'jsdom-testing-mocks' import { beforeEach, describe, expect, it, vi } from 'vitest' import PaymentMethods from './PaymentMethods' import { MANAGED_BY } from '@/lib/constants/infrastructure' import { createMockOrganization, render } from '@/tests/helpers' +mockIntersectionObserver() + const { mockSelectedOrganization, mockPaymentMethodsQuery, mockSubscription } = vi.hoisted(() => ({ mockSelectedOrganization: vi.fn(), mockPaymentMethodsQuery: vi.fn(), diff --git a/apps/studio/components/interfaces/Billing/Payment/PaymentMethods/PaymentMethods.tsx b/apps/studio/components/interfaces/Billing/Payment/PaymentMethods/PaymentMethods.tsx index fda065cad1117..09ef026787885 100644 --- a/apps/studio/components/interfaces/Billing/Payment/PaymentMethods/PaymentMethods.tsx +++ b/apps/studio/components/interfaces/Billing/Payment/PaymentMethods/PaymentMethods.tsx @@ -2,6 +2,7 @@ import { PermissionAction, SupportCategories } from '@supabase/shared-types/out/ import { useParams } from 'common' import { CreditCardIcon, ExternalLink, Plus } from 'lucide-react' import { useState } from 'react' +import { useInView } from 'react-intersection-observer' import { toast } from 'sonner' import { Button } from 'ui' import { Admonition } from 'ui-patterns/Admonition' @@ -37,14 +38,15 @@ const PaymentMethods = () => { const [selectedMethodToDelete, setSelectedMethodToDelete] = useState() const [showAddPaymentMethodModal, setShowAddPaymentMethodModal] = useState(false) - const { data: subscription } = useOrgSubscriptionQuery({ orgSlug: slug }) + const { ref, inView } = useInView({ triggerOnce: true }) + const { data: subscription } = useOrgSubscriptionQuery({ orgSlug: slug }, { enabled: inView }) const { data: paymentMethods, error, isPending: isLoading, isError, isSuccess, - } = useOrganizationPaymentMethodsQuery({ slug }) + } = useOrganizationPaymentMethodsQuery({ slug }, { enabled: inView }) const { can: canReadPaymentMethods, isSuccess: isPermissionsLoaded } = useAsyncCheckPermissions( PermissionAction.BILLING_READ, @@ -61,7 +63,7 @@ const PaymentMethods = () => { selectedOrganization?.managed_by === MANAGED_BY.STRIPE_PROJECTS return ( <> - +

Payment Methods

diff --git a/apps/studio/components/interfaces/Organization/BillingSettings/BillingBreakdown/UpcomingInvoice.tsx b/apps/studio/components/interfaces/Organization/BillingSettings/BillingBreakdown/UpcomingInvoice.tsx index 3b8c7f2390ea1..eddb54f469613 100644 --- a/apps/studio/components/interfaces/Organization/BillingSettings/BillingBreakdown/UpcomingInvoice.tsx +++ b/apps/studio/components/interfaces/Organization/BillingSettings/BillingBreakdown/UpcomingInvoice.tsx @@ -1,4 +1,5 @@ import React from 'react' +import { useInView } from 'react-intersection-observer' import { Table, TableBody, TableCell, TableFooter, TableRow } from 'ui' import { InfoTooltip } from 'ui-patterns/info-tooltip' import { ShimmeringLoader } from 'ui-patterns/ShimmeringLoader' @@ -53,13 +54,15 @@ const usageBillingDocsLink: { [K in PricingMetric]?: string } = { } export const UpcomingInvoice = ({ slug }: UpcomingInvoiceProps) => { + const { ref, inView } = useInView({ triggerOnce: true }) + const { data: upcomingInvoice, error: error, isPending: isLoading, isError, isSuccess, - } = useOrgUpcomingInvoiceQuery({ orgSlug: slug }) + } = useOrgUpcomingInvoiceQuery({ orgSlug: slug }, { enabled: inView }) const { data: organization } = useOrganizationQuery({ slug }) @@ -109,7 +112,7 @@ export const UpcomingInvoice = ({ slug }: UpcomingInvoiceProps) => { !planItem && upcomingInvoice?.fixed_fees_billing_mode === 'in_arrears' return ( - <> +
{isLoading && (
@@ -398,7 +401,7 @@ export const UpcomingInvoice = ({ slug }: UpcomingInvoiceProps) => {
)} - +
) } diff --git a/apps/studio/components/interfaces/Organization/BillingSettings/BillingCustomerData/BillingCustomerData.test.tsx b/apps/studio/components/interfaces/Organization/BillingSettings/BillingCustomerData/BillingCustomerData.test.tsx index e2ae0ef10abc1..203c3879cc1fa 100644 --- a/apps/studio/components/interfaces/Organization/BillingSettings/BillingCustomerData/BillingCustomerData.test.tsx +++ b/apps/studio/components/interfaces/Organization/BillingSettings/BillingCustomerData/BillingCustomerData.test.tsx @@ -1,4 +1,5 @@ import { screen } from '@testing-library/react' +import { mockIntersectionObserver } from 'jsdom-testing-mocks' import type { ReactNode } from 'react' import { beforeEach, describe, expect, it, vi } from 'vitest' @@ -6,6 +7,8 @@ import { BillingCustomerData } from './BillingCustomerData' import { MANAGED_BY } from '@/lib/constants/infrastructure' import { createMockOrganization, render } from '@/tests/helpers' +mockIntersectionObserver() + const mockSelectedOrganization = vi.hoisted(() => vi.fn()) vi.mock('common', async (importOriginal) => { diff --git a/apps/studio/components/interfaces/Organization/BillingSettings/BillingCustomerData/BillingCustomerData.tsx b/apps/studio/components/interfaces/Organization/BillingSettings/BillingCustomerData/BillingCustomerData.tsx index 98c584f174484..42f0369936f41 100644 --- a/apps/studio/components/interfaces/Organization/BillingSettings/BillingCustomerData/BillingCustomerData.tsx +++ b/apps/studio/components/interfaces/Organization/BillingSettings/BillingCustomerData/BillingCustomerData.tsx @@ -5,6 +5,7 @@ import { useQueryClient } from '@tanstack/react-query' import { useParams } from 'common' import { useTheme } from 'next-themes' import { useEffect, useMemo, useRef, useState } from 'react' +import { useInView } from 'react-intersection-observer' import { toast } from 'sonner' import { Button, Card, CardFooter, Form } from 'ui' import { ShimmeringLoader } from 'ui-patterns/ShimmeringLoader' @@ -47,19 +48,24 @@ export const BillingCustomerData = () => { 'stripe.customer' ) + const { ref, inView } = useInView({ triggerOnce: true }) + const { data: customerProfile, error, isPending: isLoading, isSuccess, - } = useOrganizationCustomerProfileQuery({ slug }, { enabled: canReadBillingCustomerData }) + } = useOrganizationCustomerProfileQuery( + { slug }, + { enabled: canReadBillingCustomerData && inView } + ) const { data: taxId, error: errorLoadingTaxId, isPending: isLoadingTaxId, isSuccess: loadedTaxId, - } = useOrganizationTaxIdQuery({ slug }) + } = useOrganizationTaxIdQuery({ slug }, { enabled: inView }) const { mutateAsync: updateCustomerProfile } = useOrganizationCustomerProfileUpdateMutation({ onError: () => {}, @@ -165,7 +171,7 @@ export const BillingCustomerData = () => { ) return ( - +

Billing Address & Tax ID

diff --git a/apps/studio/components/interfaces/Organization/BillingSettings/BillingEmail.tsx b/apps/studio/components/interfaces/Organization/BillingSettings/BillingEmail.tsx index 6e3a172b0d4fb..f2b7e943f7611 100644 --- a/apps/studio/components/interfaces/Organization/BillingSettings/BillingEmail.tsx +++ b/apps/studio/components/interfaces/Organization/BillingSettings/BillingEmail.tsx @@ -4,6 +4,7 @@ import { Form, FormControl, FormField } from '@ui/components/shadcn/ui/form' import { useParams } from 'common' import { useEffect } from 'react' import { useForm, useWatch } from 'react-hook-form' +import { useInView } from 'react-intersection-observer' import { toast } from 'sonner' import { FormMessage, Input } from 'ui' import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout' @@ -51,8 +52,10 @@ const BillingEmail = () => { 'organizations' ) + const { ref, inView } = useInView({ triggerOnce: true }) + const { data: billingCustomer, isPending: loadingBillingCustomer } = - useOrganizationCustomerProfileQuery({ slug }, { enabled: canReadBillingEmail }) + useOrganizationCustomerProfileQuery({ slug }, { enabled: canReadBillingEmail && inView }) const form = useForm>({ resolver: zodResolver(formSchema), @@ -103,7 +106,7 @@ const BillingEmail = () => { }, [billingCustomer]) return ( - +

Email Recipient

diff --git a/apps/studio/components/interfaces/Organization/InvoicesSettings/InvoicesSettings.test.tsx b/apps/studio/components/interfaces/Organization/InvoicesSettings/InvoicesSettings.test.tsx index 2c9d8d583442b..baffd645a8049 100644 --- a/apps/studio/components/interfaces/Organization/InvoicesSettings/InvoicesSettings.test.tsx +++ b/apps/studio/components/interfaces/Organization/InvoicesSettings/InvoicesSettings.test.tsx @@ -1,10 +1,13 @@ import { screen } from '@testing-library/react' +import { mockIntersectionObserver } from 'jsdom-testing-mocks' import { beforeEach, describe, expect, it, vi } from 'vitest' import { InvoicesSettings } from './InvoicesSettings' import { MANAGED_BY } from '@/lib/constants/infrastructure' import { createMockOrganization, render } from '@/tests/helpers' +mockIntersectionObserver() + const { mockSelectedOrganization, mockInvoicesQuery, mockInvoicesCountQuery } = vi.hoisted(() => ({ mockSelectedOrganization: vi.fn(), mockInvoicesQuery: vi.fn(), diff --git a/apps/studio/components/interfaces/Organization/InvoicesSettings/InvoicesSettings.tsx b/apps/studio/components/interfaces/Organization/InvoicesSettings/InvoicesSettings.tsx index b25978116dd4a..ebbb793c58d97 100644 --- a/apps/studio/components/interfaces/Organization/InvoicesSettings/InvoicesSettings.tsx +++ b/apps/studio/components/interfaces/Organization/InvoicesSettings/InvoicesSettings.tsx @@ -1,6 +1,7 @@ import dayjs from 'dayjs' import { ChevronLeft, ChevronRight, FileText, Receipt, ScrollText } from 'lucide-react' import { useEffect, useState } from 'react' +import { useInView } from 'react-intersection-observer' import { toast } from 'sonner' import { Button, @@ -56,13 +57,16 @@ export const InvoicesSettings = () => { const isPartnerBilledOrganization = isPartnerBillingOrganization( selectedOrganization?.billing_partner ) + + const { ref, inView } = useInView({ triggerOnce: true }) + const offset = (page - 1) * PAGE_LIMIT const { data: count, isError: isErrorCount } = useInvoicesCountQuery( { slug, }, - { enabled: !isPartnerBilledOrganization } + { enabled: !isPartnerBilledOrganization && inView } ) const { data, @@ -75,7 +79,7 @@ export const InvoicesSettings = () => { offset, limit: PAGE_LIMIT, }, - { enabled: !isPartnerBilledOrganization } + { enabled: !isPartnerBilledOrganization && inView } ) const invoices = data || [] @@ -118,7 +122,7 @@ export const InvoicesSettings = () => { isLoading || invoices.length === 0 ? 'text-foreground-muted' : undefined return ( - + From 3c305148186c311db7ec03f2e17e91ff94de1200 Mon Sep 17 00:00:00 2001 From: Monica Khoury <99693443+monicakh@users.noreply.github.com> Date: Thu, 30 Jul 2026 17:15:52 +0300 Subject: [PATCH 10/12] =?UTF-8?q?fix:=20open=20integrated=20support=20form?= =?UTF-8?q?=20from=20Feedback=20=E2=86=92=20Issue=20=E2=86=92=20Contact=20?= =?UTF-8?q?sup=E2=80=A6=20(#48488)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR description: ## Summary - Clicking Feedback → Issue → Contact support was navigating to `/support/new` (the old full-page form) instead of opening the integrated sidebar support form - Fixed by setting a `helpPanelState.requestedView` signal before opening the Help sidebar, so it opens directly at the support form view - Added a small valtio store (`state/help-panel-state.ts`) to communicate the desired view between `FeedbackDropdown` and `HelpPanel` ## Test plan - [ ] Feedback → Issue → Contact support opens the Help sidebar at the support form (not `/support/new`) - [ ] Help button → Contact support still works as before - [ ] Closing and reopening the Help sidebar via the Help button opens at the home view ## Summary by CodeRabbit * **New Features** * Selecting **Support** from the Help menu now opens the Help Panel directly to the Support view. * The Help Panel automatically updates to the requested section when opened. --- .../FeedbackDropdown/FeedbackDropdown.tsx | 8 +++++++- apps/studio/components/ui/HelpPanel/HelpPanel.tsx | 15 +++++++++++++-- apps/studio/state/help-panel-state.ts | 7 +++++++ 3 files changed, 27 insertions(+), 3 deletions(-) create mode 100644 apps/studio/state/help-panel-state.ts diff --git a/apps/studio/components/layouts/Navigation/LayoutHeader/FeedbackDropdown/FeedbackDropdown.tsx b/apps/studio/components/layouts/Navigation/LayoutHeader/FeedbackDropdown/FeedbackDropdown.tsx index f0df629c90c35..96f4df3b3149c 100644 --- a/apps/studio/components/layouts/Navigation/LayoutHeader/FeedbackDropdown/FeedbackDropdown.tsx +++ b/apps/studio/components/layouts/Navigation/LayoutHeader/FeedbackDropdown/FeedbackDropdown.tsx @@ -13,6 +13,7 @@ import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganizati import { useSelectedProjectQuery } from '@/hooks/misc/useSelectedProject' import { useTrack } from '@/lib/telemetry/track' import { useAiAssistantStateSnapshot } from '@/state/ai-assistant-state' +import { helpPanelState } from '@/state/help-panel-state' import { useSidebarManagerSnapshot } from '@/state/sidebar-manager-state' export const FeedbackDropdown = ({ className }: { className?: string }) => { @@ -98,7 +99,12 @@ export const FeedbackDropdown = ({ className }: { className?: string }) => { snap.newChat(ASSISTANT_SUGGESTIONS) setIsOpen(false) }} - onSupportClick={() => setIsOpen(false)} + onSupportClick={() => { + helpPanelState.requestedView = 'support' + setIsOpen(false) + openSidebar(SIDEBAR_KEYS.HELP_PANEL) + return false + }} /> diff --git a/apps/studio/components/ui/HelpPanel/HelpPanel.tsx b/apps/studio/components/ui/HelpPanel/HelpPanel.tsx index 211639e3e9b79..c5f0a90da1b73 100644 --- a/apps/studio/components/ui/HelpPanel/HelpPanel.tsx +++ b/apps/studio/components/ui/HelpPanel/HelpPanel.tsx @@ -2,9 +2,10 @@ import { IS_PLATFORM } from 'common' import { ChevronLeft, X } from 'lucide-react' import Image from 'next/image' import { useRouter } from 'next/router' -import { useState } from 'react' +import { useEffect, useState } from 'react' import SVG from 'react-inlinesvg' import { Button } from 'ui' +import { useSnapshot } from 'valtio' import { ASSISTANT_SUGGESTIONS } from './HelpPanel.constants' import { HelpSection } from './HelpSection' @@ -16,6 +17,7 @@ import { import { SIDEBAR_KEYS } from '@/components/layouts/ProjectLayout/LayoutSidebar/LayoutSidebarProvider' import { ButtonTooltip } from '@/components/ui/ButtonTooltip' import { useAiAssistantStateSnapshot } from '@/state/ai-assistant-state' +import { helpPanelState } from '@/state/help-panel-state' import { useSidebarManagerSnapshot } from '@/state/sidebar-manager-state' export const HelpPanel = ({ @@ -30,7 +32,16 @@ export const HelpPanel = ({ const snap = useAiAssistantStateSnapshot() const { openSidebar, closeSidebar } = useSidebarManagerSnapshot() const router = useRouter() - const [view, setView] = useState<'home' | 'support'>('home') + const helpSnap = useSnapshot(helpPanelState) + const [view, setView] = useState<'home' | 'support'>(() => helpPanelState.requestedView) + + useEffect(() => { + if (helpSnap.requestedView !== 'home') { + setView(helpSnap.requestedView) + helpPanelState.requestedView = 'home' + } + }, [helpSnap.requestedView]) + const isSupportView = view === 'support' const openAssistant = () => { onClose() diff --git a/apps/studio/state/help-panel-state.ts b/apps/studio/state/help-panel-state.ts new file mode 100644 index 0000000000000..100959fa74b13 --- /dev/null +++ b/apps/studio/state/help-panel-state.ts @@ -0,0 +1,7 @@ +import { proxy } from 'valtio' + +export const helpPanelState = proxy<{ + requestedView: 'home' | 'support' +}>({ + requestedView: 'home', +}) From e5587799692aec7e59849e9e39f0536b1e93fd0d Mon Sep 17 00:00:00 2001 From: Gildas Garcia <1122076+djhi@users.noreply.github.com> Date: Thu, 30 Jul 2026 16:50:06 +0200 Subject: [PATCH 11/12] Fix: RadioGroupCard focus state design (#48494) Fix the `` focus state design Before: image After: image ## Summary by CodeRabbit * **Style** * Updated radio group card selection styling for a cleaner, more consistent focus and checked-state appearance. * Added improved outline handling for radio group card items. --- packages/ui/src/components/radio-group-card.tsx | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/packages/ui/src/components/radio-group-card.tsx b/packages/ui/src/components/radio-group-card.tsx index fc58fa7757c1f..2bf4330a34573 100644 --- a/packages/ui/src/components/radio-group-card.tsx +++ b/packages/ui/src/components/radio-group-card.tsx @@ -38,10 +38,7 @@ const RadioGroupCardItem = React.forwardRef< // 'hover:bg-selection', 'hover:border-foreground-muted', 'hover:z-1 focus-visible:z-1', - 'data-[state=checked]:z-1', - 'data-[state=checked]:ring-2 data-[state=checked]:ring-border', - 'data-[state=checked]:bg-surface-300 dark:data-[state=checked]:bg-surface-300', - 'data-[state=checked]:border-foreground/50', + 'outline-hidden', 'transition-colors', 'group', props.className From 63a74d488f2617865ade2d6131fb2dd34c609148 Mon Sep 17 00:00:00 2001 From: Thomas <31189692+ecktoteckto@users.noreply.github.com> Date: Thu, 30 Jul 2026 17:31:13 +0200 Subject: [PATCH 12/12] chore(billing): rework texts on aws marketplace onboarding page (#47735) --- .../AwsMarketplaceOnboarding.components.tsx | 30 ++++++++++++++++--- packages/api-types/types/platform.d.ts | 5 +++- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/apps/studio/components/interfaces/Organization/CloudMarketplace/AwsMarketplaceOnboarding.components.tsx b/apps/studio/components/interfaces/Organization/CloudMarketplace/AwsMarketplaceOnboarding.components.tsx index 6c679a14c1f4e..e701eb9efd559 100644 --- a/apps/studio/components/interfaces/Organization/CloudMarketplace/AwsMarketplaceOnboarding.components.tsx +++ b/apps/studio/components/interfaces/Organization/CloudMarketplace/AwsMarketplaceOnboarding.components.tsx @@ -94,11 +94,16 @@ export function getContractIneligibilityDescription( ) { switch (reason) { case 'AWS_ACTIVATE_CREDITS_DEAL': - return 'No further action is required for this AWS Activate credits offer' + return 'This private offer grants you credits on the Supabase platform' case 'AGREEMENT_BASED_OFFER': return 'This private offer updated an existing AWS Marketplace subscription' - case 'NO_ACTIVE_CONTRACT_FOUND': + case 'NO_CONTRACT_FOUND': + case 'CONTRACT_IN_SETTLING_WINDOW': return 'AWS is still syncing this Marketplace subscription' + case 'CONTRACT_INACTIVE': + return '' + case 'CONTRACT_TERMINATED_EARLY': + return 'Subscription was terminated' default: return 'This AWS Marketplace subscription cannot be linked right now' } @@ -114,7 +119,7 @@ export function ContractIneligibilityNotice({ return ( ) @@ -126,7 +131,8 @@ export function ContractIneligibilityNotice({ description="Your existing Supabase organization remains linked to AWS Marketplace and your projects will continue to run as usual." /> ) - case 'NO_ACTIVE_CONTRACT_FOUND': + case 'NO_CONTRACT_FOUND': + case 'CONTRACT_IN_SETTLING_WINDOW': return ( ) + case 'CONTRACT_INACTIVE': + return ( + + ) + case 'CONTRACT_TERMINATED_EARLY': + return ( + + ) default: return } diff --git a/packages/api-types/types/platform.d.ts b/packages/api-types/types/platform.d.ts index 8ddbcaaecf496..836d4c4de6d5d 100644 --- a/packages/api-types/types/platform.d.ts +++ b/packages/api-types/types/platform.d.ts @@ -5155,7 +5155,10 @@ export interface components { reasons: ( | 'AWS_ACTIVATE_CREDITS_DEAL' | 'AGREEMENT_BASED_OFFER' - | 'NO_ACTIVE_CONTRACT_FOUND' + | 'NO_CONTRACT_FOUND' + | 'CONTRACT_INACTIVE' + | 'CONTRACT_TERMINATED_EARLY' + | 'CONTRACT_IN_SETTLING_WINDOW' )[] } }