mirror of
https://github.com/hanzo-apps/hanzo.ai.git
synced 2026-10-29 07:20:43 +00:00
Every product page ended on "Start building with X" and a filled Get your API key, then one screen later on the layout's "Build what's next." and a filled Try Hanzo, in a different button shape: two closing calls a reader had to choose between. StartBuilding becomes Related: the product's docs link and its related capabilities, no heading and no button, so the closing call below is the one way in. And the open-source row no longer shows a "0 stars" pill, which read as an abandoned repository.
170 lines
6.8 KiB
TypeScript
170 lines
6.8 KiB
TypeScript
/**
|
|
* The product a page is about, as one value.
|
|
*
|
|
* Assembled from what is already stated elsewhere: the catalog names a product
|
|
* and states the route that answers for it, this site's page index names the
|
|
* pages the catalog does not carry, and `products-metadata` answers for docs —
|
|
* `null` there means docs publishes nothing, and the block drops the link.
|
|
*
|
|
* THE ONE FACT STATED HERE IS THE COMMAND. Every line of `CLI` was run against
|
|
* the binary. A product absent from that table has no command, and the page
|
|
* prints none; nothing composes a verb out of a product's name.
|
|
*
|
|
* `Product` is also the prop type of both blocks that draw it. A structural
|
|
* prop type accepts any object of the same shape, so a page could write its own
|
|
* command inline and typecheck — `AgentPrompt` and `Related` import this
|
|
* type instead of declaring their own, which leaves `CLI` the only place a
|
|
* command can be written.
|
|
*
|
|
* Every product page reads this, by whichever handle it has: the templates by
|
|
* route (`components/product/ProductLanding`) and by catalog slug
|
|
* (`components/cloud/CloudPrimitiveOverview`), a written page by its own slug.
|
|
* So one product answers with one name, one route, one command and one docs
|
|
* page wherever it is drawn.
|
|
*/
|
|
|
|
import { docsUrl } from '@/lib/constants/products-metadata'
|
|
import { getPrimitive } from '@/lib/data/cloud-primitives'
|
|
import pages from '@/lib/data/pages.json' with { type: 'json' }
|
|
|
|
export interface Product {
|
|
/**
|
|
* The catalog's product slug, which is also the last segment of the page's
|
|
* route. It is the key every lookup here uses — `getPrimitive` matches on
|
|
* `slug`, and so does the neighbour lookup — so the field says slug rather
|
|
* than id, and the stated key and the actual key are one field.
|
|
*/
|
|
slug: string
|
|
name: string
|
|
/**
|
|
* What the catalog sells this as. A `client` consumes the API rather than
|
|
* being one, which is why a missing command means something different there.
|
|
*/
|
|
kind?: 'service' | 'client'
|
|
/** What a reader types first. Absent where the CLI has no command for it. */
|
|
cli?: string
|
|
/** The API namespace the catalog proves this product by (`/v1/vector`). */
|
|
api?: string
|
|
/** The product's docs page, or null where docs publishes none. */
|
|
docs: string | null
|
|
}
|
|
|
|
/** The audited command per product, alphabetical by slug for diff sanity. */
|
|
const CLI: Record<string, string> = {
|
|
'agents': 'hanzo agents list',
|
|
'ai-metrics': 'hanzo billing usage get',
|
|
'alerts': 'hanzo o11y alerts list',
|
|
'annotation-queues': 'hanzo o11y reviews list',
|
|
'api-keys': 'hanzo iam keys list',
|
|
'applications': 'hanzo platform apps list',
|
|
'audit': 'hanzo iam audit-logs list',
|
|
'authz': 'hanzo authz check',
|
|
'auto': 'hanzo auto flows list',
|
|
'base': 'hanzo base bases list',
|
|
'billing': 'hanzo billing balance',
|
|
'bot': 'hanzo bot runs list',
|
|
'builds': 'hanzo platform builds',
|
|
'chat': 'hanzo chat create',
|
|
'cli': 'hanzo auth login',
|
|
'clusters': 'hanzo visor clusters list',
|
|
'computer': 'hanzo desktop',
|
|
'crawl': 'hanzo crawl create',
|
|
'dashboards': 'hanzo o11y dashboards list',
|
|
'datasets': 'hanzo eval datasets list',
|
|
'datastore': 'hanzo provisioning datastore create',
|
|
'dev': 'dev',
|
|
'dns': 'hanzo dns zones list',
|
|
'docdb': 'hanzo provisioning docdb create',
|
|
'embeddings': 'hanzo embeddings create',
|
|
'engine': 'hanzo engine serve <model>',
|
|
'enso': 'hanzo chat completions',
|
|
'environments': 'hanzo platform environments',
|
|
'evals': 'hanzo eval runs create',
|
|
'experiments': 'hanzo experiment list',
|
|
'flow': 'hanzo flow workflows list',
|
|
'functions': 'hanzo functions list',
|
|
'gateway': 'hanzo gateway config get',
|
|
'gen': 'gen',
|
|
'gpus': 'hanzo visor gpus get',
|
|
'iam': 'hanzo iam whoami',
|
|
'ide': 'hanzo code',
|
|
'indexer': 'hanzo explorer indexers',
|
|
'inference': 'hanzo chat completions',
|
|
'ingress': 'hanzo ingress routes list',
|
|
'integrations': 'hanzo integrations list',
|
|
'kai': 'hanzo decisions create',
|
|
'kata': 'hanzo kata run',
|
|
'kms': 'hanzo kms secrets create',
|
|
'kubernetes': 'hanzo visor k8s clusters list',
|
|
'kv': 'hanzo kv add',
|
|
'logs': 'hanzo o11y logs get',
|
|
'machines': 'hanzo visor machines list',
|
|
'marketplace': 'hanzo marketplace listings list',
|
|
'mcp': 'hanzo mcp create',
|
|
'memory': 'hanzo ai memory list',
|
|
'metrics': 'hanzo metrics query',
|
|
'models': 'hanzo models list',
|
|
'mq': 'hanzo mq stream list',
|
|
'network': 'hanzo network list',
|
|
'networks': 'hanzo web3 chains list',
|
|
'node': 'hanzo node list',
|
|
'nodes': 'hanzo validator list',
|
|
'o11y': 'hanzo o11y logs get',
|
|
'oracles': 'hanzo explorer oracles',
|
|
'pipelines': 'hanzo platform pipelines',
|
|
'plans': 'hanzo pricing get',
|
|
'projects': 'hanzo projects list',
|
|
'prompts': 'hanzo prompt list',
|
|
'providers': 'hanzo ai providers list',
|
|
'pubsub': 'hanzo pubsub publish',
|
|
'referrals': 'hanzo referral get',
|
|
'registry': 'hanzo registry images',
|
|
'releases': 'hanzo platform releases',
|
|
's3': 'hanzo s3 buckets list',
|
|
'score-configs': 'hanzo eval rubrics create',
|
|
'scores': 'hanzo eval scores create',
|
|
'search': 'hanzo search create',
|
|
'secrets': 'hanzo kms secrets create',
|
|
'sessions': 'hanzo o11y sessions get',
|
|
'settlement': 'hanzo x402 settlements get',
|
|
'skills': 'hanzo tools skills list',
|
|
'sql': 'hanzo provisioning sql create',
|
|
'status': 'hanzo o11y status',
|
|
'storage': 'hanzo s3 buckets list',
|
|
'tasks': 'hanzo tasks create',
|
|
'tokens': 'hanzo web3 tokens chain get',
|
|
'tunnel': 'hanzo share',
|
|
'vector': 'hanzo provisioning vector create',
|
|
'visor': 'hanzo visor machines list',
|
|
'wallet': 'hanzo wallet accounts get',
|
|
'world': 'hanzo world news',
|
|
'zen': 'hanzo chat create',
|
|
}
|
|
|
|
/**
|
|
* What this slug names, or nothing where neither source states a name.
|
|
*
|
|
* The catalog answers first — it is where a product's name is decided, and it
|
|
* is the name the mega-menu, the category landings and the generated overviews
|
|
* already print. `pages.json` covers the products this repo publishes a page
|
|
* for that commerce does not carry; its titles are title-cased route slugs
|
|
* (`scripts/sync-pages.mjs` spells them for the ⌘K palette), so they are a
|
|
* fallback and never a correction. Where the catalog's name is wrong for a
|
|
* product this site publishes a page for, the copy deck states the right one —
|
|
* see `title` in `lib/data/cloud-primitives`.
|
|
*
|
|
* Without a name there is no sentence to write, so the blocks are absent rather
|
|
* than addressed to a slug.
|
|
*/
|
|
export function product(slug: string): Product | null {
|
|
const listed = getPrimitive(slug)
|
|
const name = listed?.title ?? pages.find((p) => p.id === slug)?.title
|
|
if (!name) return null
|
|
return { slug, name, kind: listed?.kind, cli: CLI[slug], api: listed?.api, docs: docsUrl(slug) }
|
|
}
|
|
|
|
/** The product a route is about: a product page's last segment IS the slug. */
|
|
export function at(path: string): Product | null {
|
|
return product(path.split('/').filter(Boolean).pop() ?? '')
|
|
}
|