mirror of
https://github.com/hanzo-apps/hanzo.ai.git
synced 2026-10-30 14:58:08 +00:00
Pages from /machines to /risk, the model pages, and the kits they are made of
(page-kit, ProductLanding, LayerPage, Stack, the models kit, band's Head) mark
authored copy where it is written and draw it in the reader's language. A server
page marks a literal phrase('…') or wraps it in <T>; a client page calls t. The
kits translate a string prop through useSay (components/marketing/say), so a
page passes phrase('…') and markup passes as written. An arrow that points
turns over right to left (data-i18n-mirror).
Rebased on main: the fold-based heroes (Fold, PageHero, MachinesHero, the
product and layer pages) keep main's structure and copy, with their label,
title and lede marked phrase. /platform is main's CloudLanding; the deleted
/platform/layers and the old referral components stay deleted.
Claude-Session: https://claude.ai/code/session_015XYKLjZtDTJEnMo4eK3AFH
103 lines
5.3 KiB
TypeScript
103 lines
5.3 KiB
TypeScript
'use client'
|
|
|
|
import type { ReactNode } from 'react'
|
|
import { ArrowRight, BarChart3, Clock, Layers, Radio, Server, Shield, Zap } from 'lucide-react'
|
|
import { OSSRevenueBanner } from '@/components/oss/OSSRevenueBanner'
|
|
import { ProductLanding } from '@/components/product/ProductLanding'
|
|
import { ProductFooter } from '@/components/products/ProductFooter'
|
|
import { phrase } from '@hanzo/i18n'
|
|
|
|
/**
|
|
* PubSub, through the ONE product kit.
|
|
*
|
|
* One of NINE pages — console, insights, kms, kv, mq, pubsub, sql, storage,
|
|
* stream — that shared a class set 100%: the same hero, stat row, six-card
|
|
* grid, terminal and call to action, written out nine times in ~310 utility
|
|
* classes each. They now pass one typed props object to `ProductLanding` and
|
|
* carry zero layout classes. See LLM.md, "Tailwind is NOT gone", for the rule.
|
|
*
|
|
* EVERY WORD IS THE ONE THAT WAS HERE, the four stat tiles included: 28 of the
|
|
* group's 36 carry a port, a version, a licence or a coding the prose does not
|
|
* (measured), so unlike /ledger's four they are not restatements and they stay.
|
|
*
|
|
* One fix the move makes by construction: ProductFooter sat INSIDE the final
|
|
* card's `max-w-4xl` wrapper on all nine, so the OSS attribution and deploy
|
|
* block rendered narrower here than on every other product page.
|
|
*/
|
|
|
|
export default function PubSubPage({ source }: { source: ReactNode }) {
|
|
return (
|
|
<>
|
|
<ProductLanding
|
|
badge={"NATS JetStream"}
|
|
badgeIcon={Radio}
|
|
title={"Hanzo PubSub"}
|
|
tagline={phrase("The bus everything else rides")}
|
|
lede={phrase("PubSub moves messages between services on port 4222. Publish to a subject and everyone listening on it — or on a pattern that matches it — has the message. Add a stream and those same messages are written down too, so a consumer that was offline can start from the beginning, from a sequence number, or from a timestamp. Streams, key-value buckets, an object store and request-reply are one server, not four.")}
|
|
ctas={[
|
|
{ label: "GitHub", href: "https://github.com/hanzoai/pubsub" },
|
|
]}
|
|
what={{
|
|
title: phrase("More than pub/sub"),
|
|
sub: phrase("Durable streams, key-value, an object store and request-reply — one server, one connection, one set of credentials."),
|
|
pillars: [
|
|
{
|
|
icon: Layers,
|
|
title: phrase("Streams write it down"),
|
|
body: phrase("A stream captures the subjects you name and keeps them by age, by count or by bytes. A consumer starts at the beginning, at the newest message, at a sequence number or at a wall-clock time, and reads at the original pace or as fast as it can take them."),
|
|
},
|
|
{
|
|
icon: Zap,
|
|
title: phrase("Acked, so nothing goes quiet"),
|
|
body: phrase("A message is redelivered until a consumer acknowledges it. Publishers that stamp a message id get duplicates collapsed inside a window — two minutes unless you say otherwise. Ack every message, ack a sequence to cover everything below it, or ask for no acks at all when fire-and-forget is what you meant."),
|
|
},
|
|
{
|
|
icon: Server,
|
|
title: phrase("Key-value buckets"),
|
|
body: phrase("A bucket is a stream that keeps the last value per key, so you get watches, per-key history and expiry from the same server and the same connection. It is where Hanzo Stream keeps its consumer offsets."),
|
|
},
|
|
{
|
|
icon: Clock,
|
|
title: phrase("Request-Reply"),
|
|
body: phrase("Send to a subject and wait for one answer. Put several instances of a service in a queue group on that subject and each request goes to exactly one of them — load balancing with nothing in front of them doing it."),
|
|
},
|
|
{
|
|
icon: BarChart3,
|
|
title: phrase("Object Store"),
|
|
body: phrase("Payloads too big to be a message are chunked into a stream and put back together on the way out, with a watch for when one changes. Same connection, same credentials, no second system to stand up."),
|
|
},
|
|
{
|
|
icon: Shield,
|
|
title: phrase("Accounts, not passwords"),
|
|
body: phrase("An account walls one tenant's subjects off from another's. Credentials are nkeys or signed JWTs rather than a shared secret, permissions are granted per subject, and TLS covers the wire."),
|
|
},
|
|
],
|
|
}}
|
|
stats={{
|
|
items: [
|
|
{ value: "4222", label: phrase("Client port") },
|
|
{ value: phrase("Replay"), label: phrase("From any point") },
|
|
{ value: phrase("Durable"), label: phrase("Written to disk") },
|
|
{ value: phrase("Replicas"), label: phrase("Set per stream") },
|
|
],
|
|
}}
|
|
code={{
|
|
head: { title: phrase("Publish and Subscribe") },
|
|
name: "events.go",
|
|
source,
|
|
}}
|
|
finalCta={{
|
|
title: phrase("Put it between your services"),
|
|
sub: phrase("Free tier includes 1M messages/month."),
|
|
buttons: [
|
|
{ label: phrase("View on GitHub"), href: "https://github.com/hanzoai/pubsub" },
|
|
],
|
|
}}
|
|
>
|
|
<OSSRevenueBanner />
|
|
</ProductLanding>
|
|
<ProductFooter slug={"pubsub"} name={"PubSub"} />
|
|
</>
|
|
)
|
|
}
|