mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
Merge branch 'master' into feat-www-vercel-bulk-redirects
This commit is contained in:
commit
9f15ebcdec
15 files changed
+277
-106
No files matched your search
@@ -29,6 +29,8 @@ function useContentListingClickHandler(group: ContentListingGroup) {
|
||||
|
||||
const trackClick = useCallback(
|
||||
(item: ContentListingItem) => {
|
||||
if (!item.href) return
|
||||
|
||||
sendTelemetryEvent({
|
||||
action: 'docs_content_listing_clicked',
|
||||
properties: {
|
||||
@@ -73,8 +75,45 @@ function ContentListingsGroup({ group }: { group: ContentListingGroup }) {
|
||||
)}
|
||||
<ul className={listClassName}>
|
||||
{items.map((item) => {
|
||||
const key = `${group.id}-${item.href ?? item.title}`
|
||||
const panel = (
|
||||
<GlassPanel
|
||||
title={item.title}
|
||||
icon={resolveContentListingIcon(item.icon)}
|
||||
hasLightIcon={item.hasLightIcon ?? typeof item.icon === 'string'}
|
||||
className={item.href ? undefined : 'cursor-default'}
|
||||
badge={
|
||||
item.badge && item.badgePosition !== 'below' ? (
|
||||
<Badge variant="success">{item.badge}</Badge>
|
||||
) : undefined
|
||||
}
|
||||
>
|
||||
{item.badge && item.badgePosition === 'below' && (
|
||||
<Badge variant="success" className="mb-3 block w-fit">
|
||||
{item.badge}
|
||||
</Badge>
|
||||
)}
|
||||
{item.subtitle && (
|
||||
<span className="mb-2 block text-tertiary-foreground">{item.subtitle}</span>
|
||||
)}
|
||||
{item.description}
|
||||
</GlassPanel>
|
||||
)
|
||||
const listContent = (
|
||||
<>
|
||||
<strong>{item.title}</strong>: {item.description}
|
||||
</>
|
||||
)
|
||||
|
||||
if (!item.href) {
|
||||
return (
|
||||
<li key={key} className={gridItemClassName}>
|
||||
{isGrid ? panel : listContent}
|
||||
</li>
|
||||
)
|
||||
}
|
||||
|
||||
const external = isExternalContentListingHref(item.href)
|
||||
const key = `${group.id}-${item.href}`
|
||||
|
||||
if (isGrid) {
|
||||
return (
|
||||
@@ -87,26 +126,7 @@ function ContentListingsGroup({ group }: { group: ContentListingGroup }) {
|
||||
target={external ? '_blank' : undefined}
|
||||
rel={external ? 'noopener noreferrer' : undefined}
|
||||
>
|
||||
<GlassPanel
|
||||
title={item.title}
|
||||
icon={resolveContentListingIcon(item.icon)}
|
||||
hasLightIcon={item.hasLightIcon ?? typeof item.icon === 'string'}
|
||||
badge={
|
||||
item.badge && item.badgePosition !== 'below' ? (
|
||||
<Badge variant="success">{item.badge}</Badge>
|
||||
) : undefined
|
||||
}
|
||||
>
|
||||
{item.badge && item.badgePosition === 'below' && (
|
||||
<Badge variant="success" className="mb-3 block w-fit">
|
||||
{item.badge}
|
||||
</Badge>
|
||||
)}
|
||||
{item.subtitle && (
|
||||
<span className="mb-2 block text-tertiary-foreground">{item.subtitle}</span>
|
||||
)}
|
||||
{item.description}
|
||||
</GlassPanel>
|
||||
{panel}
|
||||
</Link>
|
||||
</li>
|
||||
)
|
||||
@@ -120,7 +140,7 @@ function ContentListingsGroup({ group }: { group: ContentListingGroup }) {
|
||||
target={external ? '_blank' : undefined}
|
||||
rel={external ? 'noopener noreferrer' : undefined}
|
||||
>
|
||||
<strong>{item.title}</strong>: {item.description}
|
||||
{listContent}
|
||||
</Link>
|
||||
</li>
|
||||
)
|
||||
|
||||
@@ -1139,6 +1139,20 @@ export const database: NavMenuConstant = {
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Multigres',
|
||||
url: undefined,
|
||||
items: [
|
||||
{
|
||||
name: 'Overview',
|
||||
url: '/guides/database/multigres' as `/${string}`,
|
||||
},
|
||||
{
|
||||
name: 'Compatibility',
|
||||
url: '/guides/database/multigres/compatibility' as `/${string}`,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Access and security',
|
||||
url: undefined,
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
---
|
||||
id: 'multigres'
|
||||
title: 'Multigres'
|
||||
subtitle: 'Horizontally scalable Postgres for high availability'
|
||||
description: 'Run high availability Postgres across multiple nodes with automatic failover, using Multigres.'
|
||||
---
|
||||
|
||||
<Admonition type="caution">
|
||||
|
||||
Multigres is in [Private Alpha](/docs/guides/getting-started/features#feature-status). It's free during the Alpha for organizations on a paid plan, for up to two projects, but pricing may change once it leaves Alpha. It isn't covered by the [uptime SLA](/sla), and Supabase isn't targeting production or mission-critical workloads with it during this stage.
|
||||
|
||||
</Admonition>
|
||||
|
||||
Multigres gives your project high availability by running Postgres across multiple nodes instead of one, so reads and writes continue if a node fails. It is Supabase's integration of [Multigres](https://multigres.com), an open-source project that brings the same distributed-systems approach Vitess brought to MySQL to Postgres.
|
||||
|
||||
<ContentListings id="database-multigres-what-you-get" />
|
||||
|
||||
## Eligibility
|
||||
|
||||
During the Private Alpha:
|
||||
|
||||
- Multigres is available to organizations on a paid plan. It isn't available on the Free plan.
|
||||
- Availability is being rolled out gradually, so the option to enable it may not yet appear for every eligible organization.
|
||||
- Up to two projects per eligible organization can use Multigres for free during the Alpha.
|
||||
|
||||
## Enabling Multigres
|
||||
|
||||
In the Dashboard, Multigres appears as **High availability** during project creation:
|
||||
|
||||
1. Open [Create a new project](/dashboard/new/_) in the Dashboard.
|
||||
2. Under **High availability**, turn on **Enable high availability**.
|
||||
3. Finish the remaining fields such as database password, region, and compute size, if shown.
|
||||
4. Click **Create new project**.
|
||||
|
||||
If your organization isn't eligible or hasn't been rolled out yet, **High availability** won't appear.
|
||||
|
||||
## What's not included in the alpha
|
||||
|
||||
Some Supabase features and project operations aren't yet available on Multigres-backed projects:
|
||||
|
||||
- **Realtime.** Multigres doesn't yet support the logical replication that Realtime depends on, so Realtime is unavailable.
|
||||
- **Point-in-Time Recovery.** Only the standard daily backups are available.
|
||||
- **Cross-region read replicas.** Multigres projects run in a single region during the Alpha.
|
||||
- **OrioleDB.** A project can use Multigres or [OrioleDB](/docs/guides/database/orioledb), not both.
|
||||
- **Resizing after creation.** Compute size, disk, and the number of replicas can't be changed after a Multigres project is created.
|
||||
- **Sharding and custom durability policies.** These are on the longer-term roadmap but aren't part of the Alpha.
|
||||
|
||||
<Admonition type="caution">
|
||||
|
||||
Enabling Multigres migrates your project's database to run on Multigres. There's currently no managed path to move it back to a standard Postgres project.
|
||||
|
||||
</Admonition>
|
||||
|
||||
## Compatibility
|
||||
|
||||
Multigres aims for full compatibility with standard Postgres, but there are some differences to be aware of. See [Multigres compatibility](/docs/guides/database/multigres/compatibility) for details.
|
||||
|
||||
## Resources
|
||||
|
||||
[Multigres documentation](https://multigres.com/docs) — architecture, self-hosted deployment, and other technical depth that goes beyond the hosted Supabase integration covered on this page.
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
title: 'Multigres compatibility'
|
||||
description: 'Where Multigres-backed Postgres projects differ from standard Postgres.'
|
||||
---
|
||||
|
||||
Multigres targets full compatibility with standard Postgres, verified against the [`pg_regress`](https://www.postgresql.org/docs/current/regress.html) test suite. See the [Multigres documentation](https://multigres.com/docs) for lower-level architecture and compatibility details, and the [Multigres overview](/docs/guides/database/multigres#whats-not-included-in-the-alpha) for what's not yet supported during the Private Alpha.
|
||||
@@ -199,61 +199,62 @@ Features in Beta are tested by an external penetration tester for security issue
|
||||
|
||||
In addition to the Beta requirements, features in GA are covered by the [uptime SLA](/sla).
|
||||
|
||||
| Product | Feature | Stage | Available on self-hosted |
|
||||
| -------------- | -------------------------- | -------------- | ------------------------------------------- |
|
||||
| Database | Postgres | `GA` | ✅ |
|
||||
| Database | Vector Database | `GA` | ✅ |
|
||||
| Database | Auto-generated Rest API | `GA` | ✅ |
|
||||
| Database | Auto-generated GraphQL API | `GA` | ✅ |
|
||||
| Database | Webhooks | `beta` | ✅ |
|
||||
| Database | Vault | `public alpha` | ✅ |
|
||||
| Database | Supabase Pipelines | `public alpha` | N/A |
|
||||
| Platform | | `GA` | ✅ |
|
||||
| Platform | Point-in-Time Recovery | `GA` | 🚧 [wal-g](https://github.com/wal-g/wal-g) |
|
||||
| Platform | Custom Domains | `GA` | N/A |
|
||||
| Platform | Network Restrictions | `GA` | N/A |
|
||||
| Platform | SSL enforcement | `GA` | N/A |
|
||||
| Platform | Branching | `beta` | N/A |
|
||||
| Platform | Terraform Provider | `public alpha` | N/A |
|
||||
| Platform | Read Replicas | `GA` | N/A |
|
||||
| Platform | Log Drains | `public alpha` | ✅ |
|
||||
| Platform | MCP | `public alpha` | ✅ |
|
||||
| Platform | PrivateLink | `beta` | N/A |
|
||||
| Studio | | `GA` | ✅ |
|
||||
| Studio | SSO | `GA` | ✅ |
|
||||
| Studio | Column Privileges | `public alpha` | ✅ |
|
||||
| Realtime | Postgres Changes | `GA` | ✅ |
|
||||
| Realtime | Broadcast | `GA` | ✅ |
|
||||
| Realtime | Presence | `GA` | ✅ |
|
||||
| Realtime | Broadcast Authorization | `public beta` | ✅ |
|
||||
| Realtime | Presence Authorization | `public beta` | ✅ |
|
||||
| Realtime | Broadcast from Database | `public beta` | ✅ |
|
||||
| Storage | | `GA` | ✅ |
|
||||
| Storage | CDN | `GA` | 🚧 [Cloudflare](https://www.cloudflare.com) |
|
||||
| Storage | Smart CDN | `GA` | 🚧 [Cloudflare](https://www.cloudflare.com) |
|
||||
| Storage | Image Transformations | `GA` | ✅ |
|
||||
| Storage | Resumable Uploads | `GA` | ✅ |
|
||||
| Storage | S3 compatibility | `GA` | ✅ |
|
||||
| Edge Functions | | `GA` | ✅ |
|
||||
| Edge Functions | Regional Invocations | `GA` | ✅ |
|
||||
| Edge Functions | NPM compatibility | `GA` | ✅ |
|
||||
| Auth | | `GA` | ✅ |
|
||||
| Auth | Email sign-in | `GA` | ✅ |
|
||||
| Auth | Social login | `GA` | ✅ |
|
||||
| Auth | Phone sign-in | `GA` | ✅ |
|
||||
| Auth | Passwordless sign-in | `GA` | ✅ |
|
||||
| Auth | SSO with SAML | `GA` | ✅ |
|
||||
| Auth | Authorization via RLS | `GA` | ✅ |
|
||||
| Auth | CAPTCHA protection | `GA` | ✅ |
|
||||
| Auth | Server-side Auth | `beta` | ✅ |
|
||||
| Auth | Third-Party Auth | `GA` | ✅ |
|
||||
| Auth | Hooks | `beta` | ✅ |
|
||||
| CLI | | `GA` | ✅ Works with self-hosted |
|
||||
| Management API | | `GA` | N/A |
|
||||
| Client Library | JavaScript | `GA` | N/A |
|
||||
| Client Library | Flutter | `GA` | N/A |
|
||||
| Client Library | Swift | `GA` | N/A |
|
||||
| Client Library | Python | `beta` | N/A |
|
||||
| Product | Feature | Stage | Available on self-hosted |
|
||||
| -------------- | -------------------------- | --------------- | ------------------------------------------- |
|
||||
| Database | Postgres | `GA` | ✅ |
|
||||
| Database | Vector Database | `GA` | ✅ |
|
||||
| Database | Auto-generated Rest API | `GA` | ✅ |
|
||||
| Database | Auto-generated GraphQL API | `GA` | ✅ |
|
||||
| Database | Webhooks | `beta` | ✅ |
|
||||
| Database | Vault | `public alpha` | ✅ |
|
||||
| Database | Supabase Pipelines | `public alpha` | N/A |
|
||||
| Database | Multigres | `private alpha` | N/A |
|
||||
| Platform | | `GA` | ✅ |
|
||||
| Platform | Point-in-Time Recovery | `GA` | 🚧 [wal-g](https://github.com/wal-g/wal-g) |
|
||||
| Platform | Custom Domains | `GA` | N/A |
|
||||
| Platform | Network Restrictions | `GA` | N/A |
|
||||
| Platform | SSL enforcement | `GA` | N/A |
|
||||
| Platform | Branching | `beta` | N/A |
|
||||
| Platform | Terraform Provider | `public alpha` | N/A |
|
||||
| Platform | Read Replicas | `GA` | N/A |
|
||||
| Platform | Log Drains | `public alpha` | ✅ |
|
||||
| Platform | MCP | `public alpha` | ✅ |
|
||||
| Platform | PrivateLink | `beta` | N/A |
|
||||
| Studio | | `GA` | ✅ |
|
||||
| Studio | SSO | `GA` | ✅ |
|
||||
| Studio | Column Privileges | `public alpha` | ✅ |
|
||||
| Realtime | Postgres Changes | `GA` | ✅ |
|
||||
| Realtime | Broadcast | `GA` | ✅ |
|
||||
| Realtime | Presence | `GA` | ✅ |
|
||||
| Realtime | Broadcast Authorization | `public beta` | ✅ |
|
||||
| Realtime | Presence Authorization | `public beta` | ✅ |
|
||||
| Realtime | Broadcast from Database | `public beta` | ✅ |
|
||||
| Storage | | `GA` | ✅ |
|
||||
| Storage | CDN | `GA` | 🚧 [Cloudflare](https://www.cloudflare.com) |
|
||||
| Storage | Smart CDN | `GA` | 🚧 [Cloudflare](https://www.cloudflare.com) |
|
||||
| Storage | Image Transformations | `GA` | ✅ |
|
||||
| Storage | Resumable Uploads | `GA` | ✅ |
|
||||
| Storage | S3 compatibility | `GA` | ✅ |
|
||||
| Edge Functions | | `GA` | ✅ |
|
||||
| Edge Functions | Regional Invocations | `GA` | ✅ |
|
||||
| Edge Functions | NPM compatibility | `GA` | ✅ |
|
||||
| Auth | | `GA` | ✅ |
|
||||
| Auth | Email sign-in | `GA` | ✅ |
|
||||
| Auth | Social login | `GA` | ✅ |
|
||||
| Auth | Phone sign-in | `GA` | ✅ |
|
||||
| Auth | Passwordless sign-in | `GA` | ✅ |
|
||||
| Auth | SSO with SAML | `GA` | ✅ |
|
||||
| Auth | Authorization via RLS | `GA` | ✅ |
|
||||
| Auth | CAPTCHA protection | `GA` | ✅ |
|
||||
| Auth | Server-side Auth | `beta` | ✅ |
|
||||
| Auth | Third-Party Auth | `GA` | ✅ |
|
||||
| Auth | Hooks | `beta` | ✅ |
|
||||
| CLI | | `GA` | ✅ Works with self-hosted |
|
||||
| Management API | | `GA` | N/A |
|
||||
| Client Library | JavaScript | `GA` | N/A |
|
||||
| Client Library | Flutter | `GA` | N/A |
|
||||
| Client Library | Swift | `GA` | N/A |
|
||||
| Client Library | Python | `beta` | N/A |
|
||||
|
||||
- ✅ = Fully Available
|
||||
- 🚧 = Available, but requires external tools or configuration
|
||||
@@ -94,3 +94,27 @@ export const databaseNextSteps: ContentListingGroup = {
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
export const databaseMultigresWhatYouGet: ContentListingGroup = {
|
||||
id: 'database-multigres-what-you-get',
|
||||
heading: 'What you get',
|
||||
description:
|
||||
'When you enable Multigres on a project, your database runs as a small cluster instead of a single instance:',
|
||||
type: 'grid',
|
||||
items: [
|
||||
{
|
||||
title: 'Automatic failover',
|
||||
description:
|
||||
'If a node fails, another in the cluster is promoted within seconds, without you having to intervene.',
|
||||
},
|
||||
{
|
||||
title: 'No connection changes',
|
||||
description:
|
||||
'Use the same connection string. Coordination is transparent to your application.',
|
||||
},
|
||||
{
|
||||
title: 'Consensus-backed durability',
|
||||
description: 'Writes are acknowledged only after the cluster agrees they are durable.',
|
||||
},
|
||||
],
|
||||
}
|
||||
@@ -2,7 +2,7 @@ import type { ContentListingGroup } from '~/lib/content-listings.schema'
|
||||
|
||||
import { aiToolsBuildingIntoApp, aiToolsSupportedAgents } from './ai-tools.data'
|
||||
import { authGetStarted, authNextSteps, authPricing } from './auth.data'
|
||||
import { databaseGetStarted, databaseNextSteps } from './database.data'
|
||||
import { databaseGetStarted, databaseMultigresWhatYouGet, databaseNextSteps } from './database.data'
|
||||
import {
|
||||
functionsExamplesAiMedia,
|
||||
functionsExamplesMessaging,
|
||||
@@ -47,6 +47,7 @@ const ALL_GROUPS: readonly ContentListingGroup[] = [
|
||||
authPricing,
|
||||
authNextSteps,
|
||||
databaseGetStarted,
|
||||
databaseMultigresWhatYouGet,
|
||||
databaseNextSteps,
|
||||
functionsGetStarted,
|
||||
functionsExamplesSupabase,
|
||||
|
||||
@@ -34,6 +34,11 @@ export function serializeContentListingGroupToMarkdown(
|
||||
}
|
||||
|
||||
for (const item of items) {
|
||||
if (!item.href) {
|
||||
lines.push(`- **${item.title}:** ${item.description}`)
|
||||
continue
|
||||
}
|
||||
|
||||
const href = isExternalContentListingHref(item.href)
|
||||
? item.href
|
||||
: `${linkBaseUrl}${withDocsBasePath(item.href)}`
|
||||
|
||||
@@ -147,6 +147,27 @@ describe('serializeContentListingGroupToMarkdown', () => {
|
||||
)
|
||||
})
|
||||
|
||||
it('renders items without href as unlinked list entries', () => {
|
||||
const markdown = serializeContentListingGroupToMarkdown(
|
||||
{
|
||||
id: 'what-you-get',
|
||||
heading: 'What you get',
|
||||
items: [
|
||||
{
|
||||
title: 'Automatic failover',
|
||||
description: 'Another node is promoted if a node goes down.',
|
||||
},
|
||||
],
|
||||
},
|
||||
'https://supabase.com'
|
||||
)
|
||||
|
||||
expect(markdown).toContain(
|
||||
'- **Automatic failover:** Another node is promoted if a node goes down.'
|
||||
)
|
||||
expect(markdown).not.toContain('](')
|
||||
})
|
||||
|
||||
it('omits heading line when heading is not set', () => {
|
||||
const markdown = serializeContentListingGroupToMarkdown(
|
||||
{
|
||||
@@ -260,9 +281,11 @@ describe('dashboard content listing hrefs', () => {
|
||||
// Root-relative /dashboard hrefs get the docs basePath and 404; use absolute URLs.
|
||||
it('uses absolute https://supabase.com dashboard URLs', () => {
|
||||
const dashboardLinks = Object.values(CONTENT_LISTINGS).flatMap((group) =>
|
||||
group.items
|
||||
.filter((item) => isDashboardHref(item.href))
|
||||
.map((item) => ({ listingId: group.id, title: item.title, href: item.href }))
|
||||
group.items.flatMap((item) =>
|
||||
item.href && isDashboardHref(item.href)
|
||||
? [{ listingId: group.id, title: item.title, href: item.href }]
|
||||
: []
|
||||
)
|
||||
)
|
||||
|
||||
expect(dashboardLinks.length).toBeGreaterThan(0)
|
||||
@@ -275,6 +298,16 @@ describe('dashboard content listing hrefs', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('contentListingItemSchema href', () => {
|
||||
it('accepts an item without href', () => {
|
||||
const result = contentListingItemSchema.safeParse({
|
||||
title: 'Automatic failover',
|
||||
description: 'Another node is promoted if a node goes down.',
|
||||
})
|
||||
expect(result.success).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('contentListingItemSchema icon', () => {
|
||||
const baseItem = {
|
||||
title: 'Datadog',
|
||||
|
||||
@@ -22,7 +22,7 @@ export const contentListingIconSchema = z.union([z.string().min(1), contentListi
|
||||
|
||||
export const contentListingItemSchema = z.object({
|
||||
title: z.string().min(1),
|
||||
href: z.string().min(1),
|
||||
href: z.string().min(1).optional(),
|
||||
description: z.string().min(1),
|
||||
/** Shown under the title on grid cards, before the description. */
|
||||
subtitle: z.string().min(1).optional(),
|
||||
|
||||
@@ -539,6 +539,10 @@ Write _microservices_, not _micro-services_.
|
||||
|
||||
Use _might_ for possibility or an uncertain outcome.
|
||||
|
||||
### Multigres
|
||||
|
||||
Use _Multigres_ for the product name. Don't write _multi-gres_ or _MultiGres_.
|
||||
|
||||
### must
|
||||
|
||||
Use _must_ or _need to_ for a requirement. Don't use _must_ for a recommendation.
|
||||
|
||||
@@ -37,7 +37,7 @@ export function HighAvailabilityBadge({ size = 'default' }: HighAvailabilityBadg
|
||||
globally distributed deployments.
|
||||
</p>
|
||||
<Link
|
||||
href={`${DOCS_URL}/guides/deployment/high-availability`}
|
||||
href={`${DOCS_URL}/guides/database/multigres`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="mt-1 inline-flex items-center gap-1 text-xs text-foreground-lighter transition-colors hover:text-foreground"
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
'use client'
|
||||
|
||||
import SectionContainerWithCn from 'components/Layouts/SectionContainerWithCn'
|
||||
import { AnimatePresence, motion, useReducedMotion } from 'framer-motion'
|
||||
import { Database } from 'icons'
|
||||
import type { LucideIcon } from 'lucide-react'
|
||||
@@ -7,7 +8,6 @@ import { Bot, User } from 'lucide-react'
|
||||
import { useCallback, useEffect, useId, useRef, useState } from 'react'
|
||||
import { cn } from 'ui'
|
||||
|
||||
import SectionContainerWithCn from '../../../../components/Layouts/SectionContainerWithCn'
|
||||
import styles from './compute-visual.module.css'
|
||||
import { ComputeLogo } from './ComputeLogo'
|
||||
|
||||
@@ -185,6 +185,7 @@ function ComputeCardHeader({
|
||||
<ComputeIcon />
|
||||
<div className="flex min-w-0 flex-col leading-tight">
|
||||
<span className="truncate text-xs text-foreground">{name}</span>
|
||||
{/* eslint-disable-next-line shadcn/no-arbitrary-values -- 11px is a deliberate micro-size for this diagram's dense card header, not a token gap */}
|
||||
<span className="truncate font-mono text-[11px] text-foreground-muted">{runtime}</span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -513,9 +514,9 @@ function buildConnectors(geometry: Geometry, live: Record<string, boolean>): Con
|
||||
const box = (key: NodeKey) => boxes[key] as Box
|
||||
const top = (key: NodeKey) => box(key).y
|
||||
const bottom = (key: NodeKey) => box(key).y + box(key).height
|
||||
const cx = (key: NodeKey) => box(key).x + box(key).width / 2
|
||||
const cy = (key: NodeKey) => box(key).y + box(key).height / 2
|
||||
const center = (key: NodeKey): Point => ({ x: cx(key), y: cy(key) })
|
||||
const centerX = (key: NodeKey) => box(key).x + box(key).width / 2
|
||||
const centerY = (key: NodeKey) => box(key).y + box(key).height / 2
|
||||
const center = (key: NodeKey): Point => ({ x: centerX(key), y: centerY(key) })
|
||||
const at = (x: number, y: number): Point => ({ x, y })
|
||||
|
||||
// Horizontal bands: the empty strips above and below the card grid, where
|
||||
@@ -533,16 +534,16 @@ function buildConnectors(geometry: Geometry, live: Record<string, boolean>): Con
|
||||
// Each source feeds its own column.
|
||||
connector('human-embeddings', [
|
||||
center('human'),
|
||||
at(cx('human'), sourceBand),
|
||||
at(cx('embeddings'), sourceBand),
|
||||
at(centerX('human'), sourceBand),
|
||||
at(centerX('embeddings'), sourceBand),
|
||||
center('embeddings'),
|
||||
]),
|
||||
connector(
|
||||
'agent1-sandboxBottomMid',
|
||||
[
|
||||
center('agent1'),
|
||||
at(cx('agent1'), sourceBand),
|
||||
at(cx('sandboxBottomMid'), sourceBand),
|
||||
at(centerX('agent1'), sourceBand),
|
||||
at(centerX('sandboxBottomMid'), sourceBand),
|
||||
center('sandboxBottomMid'),
|
||||
],
|
||||
live.sandboxBottomMid
|
||||
@@ -551,8 +552,8 @@ function buildConnectors(geometry: Geometry, live: Record<string, boolean>): Con
|
||||
'agent2-sandboxBottomRight',
|
||||
[
|
||||
center('agent2'),
|
||||
at(cx('agent2'), sourceBand),
|
||||
at(cx('sandboxBottomRight'), sourceBand),
|
||||
at(centerX('agent2'), sourceBand),
|
||||
at(centerX('sandboxBottomRight'), sourceBand),
|
||||
center('sandboxBottomRight'),
|
||||
],
|
||||
live.sandboxBottomRight
|
||||
@@ -561,8 +562,8 @@ function buildConnectors(geometry: Geometry, live: Record<string, boolean>): Con
|
||||
// The always-on column serves the application.
|
||||
connector('api-app', [
|
||||
center('api'),
|
||||
at(cx('api'), appBand),
|
||||
at(cx('app'), appBand),
|
||||
at(centerX('api'), appBand),
|
||||
at(centerX('app'), appBand),
|
||||
center('app'),
|
||||
]),
|
||||
]
|
||||
@@ -592,6 +593,7 @@ function ConnectorLayer({
|
||||
aria-hidden="true"
|
||||
>
|
||||
<mask id={maskId} maskUnits="userSpaceOnUse" x="0" y="0" width={width} height={height}>
|
||||
{/* eslint-disable-next-line shadcn/no-raw-colors -- SVG mask luminance requires literal white, not a theme color */}
|
||||
<rect x="0" y="0" width={width} height={height} fill="white" />
|
||||
{Object.entries(boxes).map(([key, node]) => (
|
||||
<rect
|
||||
@@ -601,6 +603,7 @@ function ConnectorLayer({
|
||||
width={node.width}
|
||||
height={node.height}
|
||||
rx={CARD_RADIUS}
|
||||
// eslint-disable-next-line shadcn/no-raw-colors -- SVG mask luminance requires literal black, not a theme color
|
||||
fill="black"
|
||||
/>
|
||||
))}
|
||||
|
||||
@@ -5,32 +5,32 @@ const features = [
|
||||
{
|
||||
title: 'Short-lived credentials',
|
||||
paragraph: 'Access runs through Supabase Auth with short-lived keys, not standing secrets.',
|
||||
icon: <KeyRound className="w-5 h-5 stroke-[1.4px]" />,
|
||||
icon: <KeyRound className="w-5 h-5" strokeWidth={1.4} />,
|
||||
},
|
||||
{
|
||||
title: 'Zero-config data access',
|
||||
paragraph: 'Reach your database and Storage with the permissions your key already carries.',
|
||||
icon: <Plug className="w-5 h-5 stroke-[1.4px]" />,
|
||||
icon: <Plug className="w-5 h-5" strokeWidth={1.4} />,
|
||||
},
|
||||
{
|
||||
title: 'Per-workload firewalls',
|
||||
paragraph: 'Define which external endpoints and ports each workload can reach.',
|
||||
icon: <Network className="w-5 h-5 stroke-[1.4px]" />,
|
||||
icon: <Network className="w-5 h-5" strokeWidth={1.4} />,
|
||||
},
|
||||
{
|
||||
title: 'Cloaked secrets',
|
||||
paragraph: 'Scope secrets per workload, and cloak values so your code never sees them.',
|
||||
icon: <EyeOff className="w-5 h-5 stroke-[1.4px]" />,
|
||||
icon: <EyeOff className="w-5 h-5" strokeWidth={1.4} />,
|
||||
},
|
||||
{
|
||||
title: 'Patched automatically',
|
||||
paragraph: 'Kernel-level security patches roll out automatically. Nothing to do on your part.',
|
||||
icon: <ShieldCheck className="w-5 h-5 stroke-[1.4px]" />,
|
||||
icon: <ShieldCheck className="w-5 h-5" strokeWidth={1.4} />,
|
||||
},
|
||||
{
|
||||
title: 'Dependency scanning',
|
||||
paragraph: 'Dependencies are scanned at runtime, with alerts as new vulnerabilities land.',
|
||||
icon: <ScanSearch className="w-5 h-5 stroke-[1.4px]" />,
|
||||
icon: <ScanSearch className="w-5 h-5" strokeWidth={1.4} />,
|
||||
},
|
||||
]
|
||||
|
||||
@@ -46,9 +46,9 @@ export function TrustBoundarySection() {
|
||||
<span className="text-foreground-lighter block">preconfigured</span>
|
||||
</h2>
|
||||
<p className="text-foreground-lighter text-sm lg:text-base">
|
||||
Every sandbox and service inherits your project's auth, roles, and permissions the moment
|
||||
it starts, running in its own microVM with dedicated CPU and memory. Agents get a sandbox
|
||||
that is already scoped to the data it is allowed to touch — nothing more.
|
||||
Every sandbox and service inherits your project's auth, roles, and permissions the
|
||||
moment it starts, running in its own microVM with dedicated CPU and memory. Agents get a
|
||||
sandbox that is already scoped to the data it is allowed to touch — nothing more.
|
||||
</p>
|
||||
</div>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3">
|
||||
|
||||
@@ -7,7 +7,6 @@ import {
|
||||
Pause,
|
||||
Server,
|
||||
Shield,
|
||||
Terminal,
|
||||
TrendingUp,
|
||||
} from 'lucide-react'
|
||||
|
||||
@@ -89,7 +88,8 @@ export function WorkloadsSection() {
|
||||
className="flex items-start gap-2 text-foreground-light text-sm"
|
||||
>
|
||||
<Icon
|
||||
className="w-4 h-4 text-brand shrink-0 mt-0.5 stroke-[1.5px]"
|
||||
className="w-4 h-4 text-brand shrink-0 mt-0.5"
|
||||
strokeWidth={1.5}
|
||||
aria-hidden
|
||||
/>
|
||||
{feature.text}
|
||||
|
||||
Reference in new issue
Block a user