Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ feature. That boundary pays rent surprisingly quickly.

- [Getting started](https://vitnode.com/docs/dev/setup)
- [Build your first plugin](https://vitnode.com/docs/guides/first-plugin)
- [Plugin routes](https://vitnode.com/docs/dev/routing)
- [Plugin routes](https://vitnode.com/docs/dev/plugins/routes)
- [Admin Control Panel](https://vitnode.com/docs/dev/plugins/admin)
- [Content delivery and SEO](https://vitnode.com/docs/dev/content-engine/content-delivery-and-seo)
- [Write documentation](https://vitnode.com/docs/dev/documentation)
Expand Down
2 changes: 1 addition & 1 deletion apps/api/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "api",
"version": "1.2.0-canary.78",
"version": "2.0.0-canary.4",
"private": true,
"type": "module",
"scripts": {
Expand Down
19 changes: 0 additions & 19 deletions apps/api/src/i18n.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,5 @@
import type { VitNodeI18nConfig } from "@vitnode/core/lib/i18n/types";

/**
* The languages this installation serves.
*
* This API and `apps/web` are two halves of one installation - the same
* Postgres, the same `core_languages` - and this app is the half that owns the
* schema, so `vitnode db:prepare` seeds the database from *this* list. That is
* why it is spelled out rather than left empty: the bootstrap used to look for
* the web app's `src/vitnode.config.ts` by walking the filesystem, never found
* it from here, and seeded `en` alone into a database serving `en` and `pl`.
* The API config is now the only thing it reads.
*
* It must stay in step with `apps/web/src/i18n.ts`, and
* `apps/web/src/tests/installation-locales.test.ts` fails if the two drift.
* A generated split deployment has the same obligation and the same shape: two
* apps, one declaration each, and no filesystem discovery between them.
*
* Packages ship their own translations, so nothing here lists them - a locale
* with no `messages` entry falls back to `defaultLocale` key by key.
*/
export const i18n = {
defaultLocale: "en",
/**
Expand Down
26 changes: 2 additions & 24 deletions apps/api/src/vitnode.api.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,15 +46,7 @@ export const vitNodeApiConfig = buildApiConfig({
},
],
},
/**
* The installation's languages, from the one module that declares them.
*
* Not optional here, whatever the type says: this app owns the schema, so
* `vitnode db:prepare` seeds `core_languages` from this list. Left unset, the
* API derives its locales from whatever the installed packages ship - which
* answers "what can be translated", not "what does this site serve" - and the
* seed falls back to `en` alone.
*/

i18n,
dbProvider: drizzle({
connection: POSTGRES_URL,
Expand Down Expand Up @@ -100,21 +92,7 @@ export const vitNodeApiConfig = buildApiConfig({
bucket: process.env.SUPABASE_STORAGE_BUCKET,
}),
},
/**
* Sign-in with Discord, Google and Facebook.
*
* Carried over from `apps/docs` when Stage 17 deleted it: that application's
* config was the only place in the repo registering these three adapters, and
* `@vitnode/core/api/adapters/sso/*` would otherwise have had no consumer at
* all - implementations behind a live route (`/login/sso/:providerId`) with
* nothing showing how to switch them on.
*
* Registering one with its environment variables unset is safe and is the
* normal state here: each adapter defaults `clientId`/`clientSecret` to `""`
* and only fails when somebody actually tries that provider, with "Missing
* Discord client ID or secret" rather than a broken login page. So the list is
* what this API *supports*; the environment decides what works.
*/

authorization: {
ssoAdapters: [
DiscordSSOApiPlugin({
Expand Down
27 changes: 26 additions & 1 deletion apps/web/content/docs/dev/architecture.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,26 @@ When a user visits a page (e.g. `/blog`):

---

## The Request Pipeline

Before route matching, every request passes through the middleware
`createVitNodeStart` installs - in this order, and an app cannot get in front of
any of it:

| Order | Middleware | Applies to |
| :--- | :--- | :--- |
| 1 | **CSRF** | Server function calls (`handlerType === 'serverFn'`) |
| 2 | **Locale** | Page requests: canonical `308` redirects and the locale cookie |
| 3 | **Document cache** | HTML responses: forced `Cache-Control: private, no-store` |
| 4 | Your own | Whatever `requestMiddleware` lists |

`/api/*` reaches the same middleware and passes through untouched - no redirect,
no rewrite, no cache directive - so the Hono bridge sees the request exactly as
the client sent it and keeps its own caching policy. See
[Configuration](/docs/dev/configuration).

---

## Plugin System Architecture

VitNode is built around modular plugins located in `plugins/*`:
Expand All @@ -58,12 +78,17 @@ VitNode is built around modular plugins located in `plugins/*`:
/>
<Card
title="Routing"
description="TanStack Start file-based and plugin-manifest routing"
description="TanStack Start file-based and plugin route-tree routing"
href="/docs/dev/routing"
/>
<Card
title="Fetcher"
description="Type-safe RPC communication between frontend and API"
href="/docs/dev/fetcher"
/>
<Card
title="Configuration"
description="The shared config, the server-only companion, and the Start factory"
href="/docs/dev/configuration"
/>
</Cards>
2 changes: 1 addition & 1 deletion apps/web/content/docs/dev/cache.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ instead of one per component.

### Load it from the plugin route

```ts title="plugins/announcements/src/routes/announcements-page.tsx"
```ts title="plugins/announcements/src/pages/announcements-page.tsx"
import { definePluginRoute } from '@vitnode/core/routing'

export const route = definePluginRoute({
Expand Down
2 changes: 1 addition & 1 deletion apps/web/content/docs/dev/captcha/custom-adapter.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -134,7 +134,7 @@ export const createContactRoute = buildRoute({
The site key is public. A plugin page can read it with the shared TanStack Query
definition before rendering its form:

```tsx title="plugins/contact/src/routes/contact-page.tsx"
```tsx title="plugins/contact/src/pages/contact-page.tsx"
import { useSuspenseQuery } from '@tanstack/react-query'
import { middlewareConfigQueryOptions } from '@vitnode/core/tanstack/auth'

Expand Down
Loading