-
Notifications
You must be signed in to change notification settings - Fork 0
docs: documentation website (incubating) #21
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| name: Deploy Documentation | ||
|
|
||
| # Publish docs when a version is released (changesets creates a GitHub Release on publish), so the | ||
| # site documents the latest *released* library — and also when the docs themselves change on main | ||
| # (theme bumps, content edits), since those need no library release to be worth shipping. | ||
| on: | ||
| release: | ||
| types: [published] | ||
| push: | ||
| branches: [main] | ||
| paths: | ||
| - "docs/**" | ||
| - "pnpm-workspace.yaml" | ||
| - ".github/workflows/deploy-docs.yml" | ||
| workflow_dispatch: | ||
|
|
||
| permissions: | ||
| contents: read | ||
| pages: write | ||
| id-token: write | ||
|
|
||
| concurrency: | ||
| # Collapse a burst of Release events for the same commit into a single Pages deploy — the latest | ||
| # run cancels earlier ones. | ||
| group: pages | ||
| cancel-in-progress: true | ||
|
|
||
| env: | ||
| FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true | ||
|
|
||
| jobs: | ||
| build: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: Checkout | ||
| uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 | ||
|
|
||
| - name: Setup | ||
| uses: ./.github/actions/setup | ||
|
|
||
| - name: Build documentation | ||
| run: pnpm --filter ./docs exec turbo build | ||
|
|
||
| - name: Upload artifact | ||
| uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5 | ||
| with: | ||
| path: docs/.vitepress/dist | ||
|
|
||
| deploy: | ||
| environment: | ||
| name: github-pages | ||
| url: ${{ steps.deployment.outputs.page_url }} | ||
| needs: build | ||
| runs-on: ubuntu-latest | ||
| name: Deploy | ||
| steps: | ||
| - name: Deploy to GitHub Pages | ||
| id: deployment | ||
| uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5 | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,96 @@ | ||
| import { defineConfig } from "vitepress"; | ||
|
|
||
| const SITE_DESCRIPTION = | ||
| "Type-safe, 12-factor backend applications for TypeScript: one demesne graph, many transport hosts. A contract, a handler, and a host per invocation — HTTP, AMQP and Temporal over one kernel. Incubating."; | ||
|
|
||
| // https://vitepress.dev/reference/site-config | ||
| export default defineConfig({ | ||
| title: "start", | ||
| description: SITE_DESCRIPTION, | ||
| base: "/start/", | ||
| lang: "en-US", | ||
| cleanUrls: true, | ||
|
|
||
| sitemap: { | ||
| hostname: "https://btravstack.github.io/start/", | ||
| }, | ||
|
btravers marked this conversation as resolved.
|
||
|
|
||
| themeConfig: { | ||
| logo: { light: "/logo-light.svg", dark: "/logo-dark.svg" }, | ||
|
|
||
| nav: [ | ||
| { text: "Guide", link: "/guide/the-idea" }, | ||
| { | ||
| text: "Design RFCs", | ||
| link: "https://github.com/btravstack/start/tree/main/design", | ||
| }, | ||
| // Back to the btravstack hub (links the docs up to the landing page). | ||
| { text: "btravstack", link: "https://btravstack.github.io/" }, | ||
| ], | ||
|
|
||
| sidebar: { | ||
| "/guide/": [ | ||
| { | ||
| text: "Introduction", | ||
| items: [ | ||
| { text: "The idea", link: "/guide/the-idea" }, | ||
| { text: "Status", link: "/guide/status" }, | ||
| ], | ||
| }, | ||
| { | ||
| text: "The pieces", | ||
| items: [ | ||
| { text: "Hosts", link: "/guide/hosts" }, | ||
| { text: "Packages", link: "/guide/packages" }, | ||
| { text: "Examples", link: "/guide/examples" }, | ||
| ], | ||
| }, | ||
| ], | ||
| }, | ||
|
|
||
| socialLinks: [{ icon: "github", link: "https://github.com/btravstack/start" }], | ||
|
|
||
| footer: { | ||
| message: "Released under the MIT License. Incubating — the API is still settling.", | ||
| copyright: `Copyright © ${new Date().getFullYear()} Benoit TRAVERS`, | ||
| }, | ||
|
|
||
| search: { | ||
| provider: "local", | ||
| }, | ||
|
|
||
| editLink: { | ||
| pattern: "https://github.com/btravstack/start/edit/main/docs/:path", | ||
| text: "Edit this page on GitHub", | ||
| }, | ||
| }, | ||
|
|
||
| vite: { | ||
| // @btravstack/theme's entry imports `vitepress/theme` (which pulls in `.css`) | ||
| // and its own `style.css`. VitePress externalizes node_modules deps in the SSR | ||
| // build, so Node's ESM loader would hit those `.css` files and throw | ||
| // ERR_UNKNOWN_FILE_EXTENSION. Bundling the theme through Vite handles the CSS. | ||
| ssr: { noExternal: ["@btravstack/theme"] }, | ||
| }, | ||
|
|
||
| head: [ | ||
| ["link", { rel: "icon", type: "image/svg+xml", href: "/start/logo.svg" }], | ||
| ["meta", { name: "author", content: "Benoit TRAVERS" }], | ||
| ["meta", { name: "robots", content: "index, follow" }], | ||
| [ | ||
| "meta", | ||
| { | ||
| name: "keywords", | ||
| content: | ||
| "typescript, backend, framework, 12-factor, hexagonal, dependency injection, hono, amqp, rabbitmq, temporal, demesne, unthrown, type-safe", | ||
| }, | ||
| ], | ||
| ["meta", { property: "og:type", content: "website" }], | ||
| ["meta", { property: "og:site_name", content: "start" }], | ||
| ["meta", { property: "og:title", content: "start" }], | ||
| ["meta", { property: "og:description", content: SITE_DESCRIPTION }], | ||
| ["meta", { property: "og:image", content: "https://btravstack.github.io/start/og-start.png" }], | ||
| ["meta", { name: "twitter:card", content: "summary_large_image" }], | ||
| ["meta", { name: "twitter:image", content: "https://btravstack.github.io/start/og-start.png" }], | ||
| ], | ||
| }); | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,77 @@ | ||
| /* start accent — cyan. The shared @btravstack/theme derives every accent | ||
| * shade (deep/hover/soft/washes/hero glow/feature icons/AA text) from this | ||
| * single token. */ | ||
| :root { | ||
| --accent: #22b8cf; | ||
| } | ||
|
|
||
| /* Hero name in the package accent — the BtravStack multi-accent rule: the | ||
| * canvas stays neutral, the product glows in its own color (AA via | ||
| * --text-accent, which darkens on light). */ | ||
| :root:root { | ||
| --vp-home-hero-name-color: var(--text-accent); | ||
| } | ||
|
|
||
| /* Home-hero background glyph — the project's motif behind the hero (a play | ||
| * button and a launch trajectory: start). Painted in --accent through a mask, | ||
| * so it always tracks the accent token; the SVG is base64-encoded so no CSS | ||
| * minifier can mangle it. */ | ||
| .VPHome { | ||
| position: relative; | ||
| /* content-column width, and the gutter from the viewport edge in to it — | ||
| defined once so the glow and glyph stay anchored to the same column. */ | ||
| --btv-col: 1152px; | ||
| --btv-gutter: max(0px, calc((100% - var(--btv-col)) / 2)); | ||
| } | ||
| .VPHome::after { | ||
| content: ""; | ||
| position: absolute; | ||
| top: 8px; | ||
| left: var(--btv-gutter); | ||
| right: var(--btv-gutter); | ||
| aspect-ratio: 500 / 300; | ||
| background-color: var(--accent); | ||
| -webkit-mask: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MDAgMzAwIiBmaWxsPSJub25lIj48cGF0aCBkPSJNMzAsMjQwIEg1MDAiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIyIi8+PGNpcmNsZSBjeD0iMTQwIiBjeT0iMTUwIiByPSI3MCIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjIiLz48cGF0aCBkPSJNMTE4LDExMiBMMTg4LDE1MCBMMTE4LDE4OCBaIiBzdHJva2U9IiNmZmYiIHN0cm9rZS13aWR0aD0iMiIvPjxwYXRoIGQ9Ik0yNDAsMjM2IEMzMjAsMjEwIDM5MCwxNTAgNDU4LDY0IiBzdHJva2U9IiNmZmYiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWRhc2hhcnJheT0iMTAgMTIiLz48cGF0aCBkPSJNNDQ2LDg2IEw0NjQsNTYgTTQzNCw2NCBMNDY4LDc2IiBzdHJva2U9IiNmZmYiIHN0cm9rZS13aWR0aD0iMiIvPjwvc3ZnPgo=") | ||
| no-repeat top center / contain; | ||
| mask: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA1MDAgMzAwIiBmaWxsPSJub25lIj48cGF0aCBkPSJNMzAsMjQwIEg1MDAiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIyIi8+PGNpcmNsZSBjeD0iMTQwIiBjeT0iMTUwIiByPSI3MCIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjIiLz48cGF0aCBkPSJNMTE4LDExMiBMMTg4LDE1MCBMMTE4LDE4OCBaIiBzdHJva2U9IiNmZmYiIHN0cm9rZS13aWR0aD0iMiIvPjxwYXRoIGQ9Ik0yNDAsMjM2IEMzMjAsMjEwIDM5MCwxNTAgNDU4LDY0IiBzdHJva2U9IiNmZmYiIHN0cm9rZS13aWR0aD0iMiIgc3Ryb2tlLWRhc2hhcnJheT0iMTAgMTIiLz48cGF0aCBkPSJNNDQ2LDg2IEw0NjQsNTYgTTQzNCw2NCBMNDY4LDc2IiBzdHJva2U9IiNmZmYiIHN0cm9rZS13aWR0aD0iMiIvPjwvc3ZnPgo=") | ||
| no-repeat top center / contain; | ||
| opacity: 0.13; | ||
| pointer-events: none; | ||
| z-index: 0; | ||
| } | ||
| @media (max-width: 768px) { | ||
| .VPHome::after { | ||
| display: none; | ||
| } | ||
| } | ||
|
|
||
| /* The shared theme only enlarges the hero mark at >=960px; below that the | ||
| * mark's small intrinsic size leaves it tiny, so size it up for tablet/mobile | ||
| * too. */ | ||
| @media (max-width: 959px) { | ||
| .VPHero .image-src { | ||
| width: min(208px, 62vw); | ||
| height: min(208px, 62vw); | ||
| object-fit: contain; | ||
| } | ||
| } | ||
|
|
||
| /* Under-construction strip — the worker beet on site beneath the hero. */ | ||
| .btv-wip { | ||
| display: flex; | ||
| align-items: center; | ||
| gap: 18px; | ||
| margin: 12px 0 28px; | ||
| padding: 16px 20px; | ||
| border: 1.5px dashed color-mix(in srgb, var(--accent) 40%, transparent); | ||
| border-radius: 14px; | ||
| } | ||
| .btv-wip img { | ||
| flex: none; | ||
| width: 64px; | ||
| height: 72px; | ||
| } | ||
| .btv-wip p { | ||
| margin: 0; | ||
| line-height: 1.55; | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| import Theme from "@btravstack/theme"; | ||
| import "./custom.css"; | ||
|
|
||
| export default Theme; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| # Examples | ||
|
|
||
| Each example in [`examples/`](https://github.com/btravstack/start/tree/main/examples) is a | ||
| complete application with a `test:integration` suite that runs against **real infrastructure** | ||
| via [testcontainers](https://testcontainers.com): | ||
|
|
||
| - **`start-api-todo`** — plain HTTP + in-memory repo (the base example). | ||
| - **`start-orpc-prisma`** — a typed [oRPC](https://orpc.unnoq.com) API backed by Prisma/Postgres. | ||
| - **`start-amqp-worker`** — a RabbitMQ consumer via a real amqplib driver. | ||
| - **`start-temporal-worker`** — a Temporal worker + deterministic workflow. | ||
|
|
||
| The examples are the executable form of the design RFCs: one demesne graph per app, served through | ||
| a host, with config, wiring, errors and shutdown shared. While the packages are private, the | ||
| examples are the best way to read how start feels to use. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| # Hosts | ||
|
|
||
| A **host** owns the process for one transport: it opens the listener or consumer, opens a demesne | ||
| fork scope per invocation, runs the handler through the kernel's `runHandler`, and maps the | ||
| outcome to the transport's vocabulary through a total `DispositionMap`. | ||
|
|
||
| Hosts contain **no DI, lifecycle, validation, or dispatch logic of their own** — that all lives in | ||
| the kernel, once. A host is pure transport glue. | ||
|
|
||
| | Host | Transport | Disposition `D` | Invocation unit | | ||
| | ---------------------------- | ------------------------------- | --------------------------- | --------------- | | ||
| | `@btravstack/start-api` | HTTP ([Hono](https://hono.dev)) | HTTP status | per request | | ||
| | `@btravstack/start-amqp` | AMQP / RabbitMQ | ack / requeue / dead-letter | per message | | ||
| | `@btravstack/start-temporal` | [Temporal](https://temporal.io) | retryable / non-retryable | per activity | | ||
|
|
||
| ## HTTP — `@btravstack/start-api` | ||
|
|
||
| `createHttpApp` + `httpListener`: contracts become routes, handler outcomes become statuses. The | ||
| listener owns startup and graceful shutdown of the Node server. | ||
|
|
||
| ## AMQP — `@btravstack/start-amqp` | ||
|
|
||
| Settlement dispositions (ack, requeue, dead-letter) over a wire `AmqpDriver`, with an optional | ||
| `IdempotencyStore` for redelivery — a message seen twice runs the use case once. | ||
|
|
||
| ## Temporal — `@btravstack/start-temporal` | ||
|
|
||
| Activities as demesne-wired use cases. Determinism is enforced **structurally**: workflows receive | ||
| activity proxies, never a container, so a workflow cannot accidentally reach non-deterministic | ||
| code. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| # Packages | ||
|
|
||
| All packages are currently `private` while the API settles — see [Status](/guide/status). | ||
|
|
||
| ## `@btravstack/start-kernel` | ||
|
|
||
| The spine. Everything the hosts share lives here, once: | ||
|
|
||
| - `defineConfig` — environment read and validated at the boundary (factor III) | ||
| - `runHost` — process ownership and graceful shutdown (factor IX) | ||
| - `defineContract` / `handler` / `runHandler` — the contract-to-use-case binding | ||
| - `DispositionMap` / `dispatch` — total outcome-to-transport mapping | ||
|
|
||
| ## `@btravstack/start-api` | ||
|
|
||
| HTTP host on [Hono](https://hono.dev): `createHttpApp` + `httpListener`. | ||
|
|
||
| ## `@btravstack/start-amqp` | ||
|
|
||
| AMQP host: settlement dispositions over a wire `AmqpDriver`, with an optional `IdempotencyStore` | ||
| for redelivery. | ||
|
|
||
| ## `@btravstack/start-temporal` | ||
|
|
||
| Temporal host: activities as demesne-wired use cases; determinism enforced structurally — | ||
| workflows get activity proxies, never a container. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| # Status | ||
|
|
||
| <div class="btv-wip"> | ||
| <img src="/beet-worker.svg" alt="A beetroot in a hard hat, digging" /> | ||
| <p><strong>start is incubating.</strong> All packages are currently <code>private</code> while the API settles — nothing is published to npm yet, and everything may change without ceremony.</p> | ||
| </div> | ||
|
|
||
| ## What that means in practice | ||
|
|
||
| - **No install instructions.** The `@btravstack/start-*` packages are not on npm. When the kernel | ||
| API stabilises, they will be published and this site will grow real getting-started guides. | ||
| - **The design RFCs are the source of truth.** The documents in | ||
| [`design/`](https://github.com/btravstack/start/tree/main/design) are invariant-driven and | ||
| reviewed before code; when the code and an RFC disagree, the RFC wins until amended. | ||
| - **The examples are real.** Each example application in the repo ships a `test:integration` | ||
| suite that runs against real infrastructure (Postgres, RabbitMQ, Temporal) via | ||
| [testcontainers](https://testcontainers.com) — the design is exercised end-to-end on every CI | ||
| run, even while incubating. | ||
|
|
||
| ## Following along | ||
|
|
||
| Watch the [GitHub repository](https://github.com/btravstack/start) for progress. The rest of the | ||
| stack — [amqp-contract](https://btravstack.github.io/amqp-contract/), | ||
| [temporal-contract](https://btravstack.github.io/temporal-contract/), | ||
| [unthrown](https://btravstack.github.io/unthrown/) and | ||
| [demesne](https://btravstack.github.io/demesne/) — is published and documented today. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| # The idea | ||
|
|
||
| Your application is a **demesne graph** — pure use cases behind ports, adapters wired at the | ||
| boundary, everything discharged before you run. start adds the process spine and lets you serve | ||
| that _same graph_ over any transport. | ||
|
|
||
| Every invocation, whatever the transport, is the same triple: | ||
|
|
||
| > a **contract** (zod input / output) + a **handler** (a demesne-injected use case) + a **host** | ||
| > (owns the process, opens a fork scope per invocation) | ||
|
|
||
| The host is the only thing that changes between transports. Config, the DI graph, the error | ||
| channel, and graceful shutdown are shared. | ||
|
|
||
| ## Why "12-factor falls out" | ||
|
|
||
| The kernel makes the classic [12-factor](https://12factor.net) disciplines structural rather than | ||
| aspirational: | ||
|
|
||
| - **Factor III (config)** — `defineConfig` reads the environment once, validated, at the boundary. | ||
| Nothing deeper in the graph touches `process.env`. | ||
| - **Factor IX (disposability)** — `runHost` owns startup and graceful shutdown. Resources are | ||
| scoped by demesne and released LIFO; a fork scope opens per invocation and closes with it. | ||
| - **Ports and adapters** — use cases stay pure behind `Context<R>` signatures; transports are | ||
| adapters at the edge, not callers woven through your domain. | ||
|
|
||
| ## Dispositions | ||
|
|
||
| A handler doesn't know its transport, so it can't speak HTTP statuses or AMQP acks. It returns a | ||
| typed outcome; each host maps outcomes to its transport's vocabulary through a **total | ||
| `DispositionMap`** — total meaning the compiler insists every outcome is mapped: | ||
|
|
||
| | Host | Disposition `D` | Invocation unit | | ||
| | ---------------------------- | --------------------------- | --------------- | | ||
| | `@btravstack/start-api` | HTTP status | per request | | ||
| | `@btravstack/start-amqp` | ack / requeue / dead-letter | per message | | ||
| | `@btravstack/start-temporal` | retryable / non-retryable | per activity | | ||
|
|
||
| ## Relationship to demesne | ||
|
|
||
| [demesne](https://btravstack.github.io/demesne/) is a standalone, unbranded DI library; start | ||
| depends on it as a published package — a one-way dependency (demesne knows nothing of start). They | ||
| evolve independently. | ||
|
|
||
| ## Where the design lives | ||
|
|
||
| The RFCs in [`design/`](https://github.com/btravstack/start/tree/main/design) are the source of | ||
| truth (invariant-driven): the thesis, the kernel API, and the handler binding. While start is | ||
| incubating, read those before reading code. |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.