---
order: 5
section: guides
title: API di Runtime
description: >-
  createScribe e l'intera superficie del client tipizzato: lettura, helper per
  il routing, relazioni, sitemap, reindirizzamenti e integrazione con i
  framework.
noindex: false
canonicalPath: /it/docs/runtime-api
---
```ts
import { createScribe } from "scribe-cms/runtime";
import config from "./scribe.config";

const scribe = createScribe(config);
```

`createScribe()` restituisce un client tipizzato con un accessor per ogni tipo di contenuto (`scribe.blog`, `scribe.author`, ...) oltre a `scribe.sitemap()`. Tutte le letture sono sincrone e in memoria: il contenuto viene caricato una sola volta, memorizzato nella cache e (in fase di sviluppo) riconvalidato quando i file o l'archivio delle traduzioni cambiano.

Il client è in puro Node, senza dipendenze dai framework. Funziona allo stesso modo in Next.js, Astro, Remix, SvelteKit o in uno script di build; gli esempi di pagina qui sotto usano le convenzioni di Next.js puramente a scopo illustrativo.

I documenti presentano questa struttura, dove `frontmatter` è tipizzato a partire dal tuo schema Zod:

```ts
{
  slug: string;        // slug nella lingua di questo documento
  enSlug: string;      // slug genitore in inglese (== slug per i documenti EN)
  locale: string;
  frontmatter: { ... };
  content: string;     // corpo MDX grezzo
  publishedAt?: string;
  updatedAt?: string;
  noindex: boolean;
}
```

## Lettura

### `list(locale?, options?)`

Tutti i documenti per una lingua (predefinita: la lingua predefinita), ordinati in base all'impostazione `orderBy` del tipo.

```ts
scribe.blog.list("it");
scribe.blog.list("it", { limit: 3 });
scribe.blog.list("it", { orderBy: "slug" });   // sovrascrittura per singola chiamata
```

Restituisce `[]` per una lingua senza documenti.

### `get(slug, locale?)`

Ricerca esatta dello slug in una singola lingua. Nessun fallback e nessuna gestione dei reindirizzamenti. Restituisce il documento oppure `null`.

### `resolve(slug, locale)`

La risoluzione completa del percorso di richiesta, ideale da usare all'interno delle pagine:

```ts
const r = scribe.blog.resolve(slug, locale);
// {
//   document: BlogDoc | null,
//   actualLocale: string,        // "en" quando è intervenuto il fallback in EN
//   shouldRedirectTo?: string,   // target 301 (correzione dello slug per lingua errata)
//   canonicalPath?: string,      // percorso del documento che tiene conto della lingua
// }
```

Gestisce, in ordine, la corrispondenza diretta, il reindirizzamento dello slug per lingua errata, la [catena di fallback delle lingue](/docs/configuration#locale-fallback-chains) (attiva per impostazione predefinita) e infine il fallback in inglese (quando `indexFallback: "en"`). Quando una lingua di fallback serve la pagina, `actualLocale` corrisponde a quella lingua e la correzione dello slug tiene conto della catena di fallback. Le migrazioni degli slug e i documenti ritirati vengono gestiti dalle regole di `_redirects.json` nella mappa dei reindirizzamenti statici o del proxy, e non tramite `resolve()`. Un tipico gestore di pagina (nell'esempio, Next.js):

```ts
const resolved = scribe.blog.resolve(slug, locale);
if (resolved.shouldRedirectTo) permanentRedirect(resolved.shouldRedirectTo);
if (!resolved.document) notFound();
```

## Helper per il routing

### `staticParams(options?)`

Ogni coppia `{ locale, slug }` da pre-renderizzare. Inseriscila nell'hook dei percorsi statici del tuo framework (ad esempio `generateStaticParams` per Next.js, `getStaticPaths` per Astro, `entries` per SvelteKit):

```ts
export function generateStaticParams() {
  return scribe.blog.staticParams();
}

// Limita le lingue (es. una rotta per immagini OG che supporta solo alfabeti latini):
scribe.blog.staticParams({ locales: ["en", "fr", "de"] });
```

Per una lingua senza traduzione, lo slug pre-renderizzato proviene dalla prima lingua della [catena di fallback delle lingue](/docs/configuration#locale-fallback-chains) che ne possiede uno (e successivamente dallo slug in inglese), in modo che gli URL pre-renderizzati corrispondano esattamente a ciò che `resolve()` andrà a servire.

### `alternates(doc)`

La mappa hreflang per un documento. Mappa ogni lingua con il suo percorso relativo, per tutte le lingue che presentano una traduzione (la lingua predefinita è sempre inclusa):

```ts
scribe.blog.alternates(doc);
// { en: "/blog/hello-world", it: "/it/blog/ciao-mondo" }
```

Passalo ai tuoi tag hreflang, ad esempio a `metadata.alternates.languages` di Next.js, oppure ad elementi link renderizzati manualmente.

### `translation(doc, targetLocale)`

Lo stesso documento in un'altra lingua, oppure `null` se non è tradotto. Di solito si usa fare un fallback sul documento che si ha già a disposizione:

```ts
const itDoc = scribe.blog.translation(doc, "it") ?? doc;
```

### `url(slug, locale)`

Costruisce un percorso a partire dal template `path` del tipo:

```ts
scribe.blog.url("hello-world", "it");  // "/it/blog/hello-world"
```

`staticParams`, `alternates` e `url` generano un errore per i tipi di solo riferimento (quelli senza parametro `path`).

## Relazioni

### `related(doc, field, locale?)`

Dereferenzia un campo del frontmatter `field.relation()` nel documento o nei documenti del tipo di destinazione. Il tipo restituito viene dedotto dallo schema:

```ts
scribe.blog.related(doc, "author");        // AuthorDoc           (singolo obbligatorio)
scribe.vertical.related(doc, "blogSlug");  // BlogDoc | null      (singolo opzionale)
scribe.glossary.related(doc, "terms");     // GlossaryDoc[]       (multiplo)
```

- Esegue la dereferenziazione in `locale ?? doc.locale`, facendo un fallback sul documento in inglese se la destinazione non risulta tradotta.
- Una relazione **obbligatoria** non restituisce mai `null`: `scribe validate` blocca la compilazione in presenza di relazioni obbligatorie in sospeso, e `related()` genera un'eccezione se una di queste sfugge ai controlli.
- Le relazioni opzionali restituiscono `null`; le relazioni multiple ignorano silenziosamente le destinazioni mancanti.
- Vengono esposti solo i campi dello schema di primo livello (le relazioni annidate vengono comunque convalidate, ma andranno dereferenziate manualmente).

## Sitemap

```ts
const entries = await scribe.sitemap({
  baseUrl: "https://example.com",
  typeDefaults: {
    blog: { priority: 0.7, changeFrequency: "monthly" },
  },
});
```

Restituisce semplici voci JSON (`url`, `lastModified`, `changeFrequency`, `priority`, l'hreflang `alternates.languages` comprensivo di `x-default`). La struttura corrisponde a `MetadataRoute.Sitemap` di Next.js e si serializza direttamente in formato XML per qualsiasi altro stack tecnologico. Viene inclusa una singola voce per ogni documento in inglese su tutti i tipi instradabili; vengono ignorati i documenti `noindex` e gli slug di origine dei reindirizzamenti presenti in `_redirects.json`.

Opzioni: `baseUrl` (obbligatorio), `contentTypes`, `typeDefaults`, `resolveUrl`, `resolvePathname`, `excludeNoindex` (predefinito true), `includeXDefault` (predefinito true).

## Introspezione

Oltre agli accessor specifici per tipo, il client espone la configurazione risolta:

```ts
scribe.config;              // ScribeConfig risolto
scribe.getType("blog");     // un singolo tipo di contenuto risolto
scribe.listTypes();         // tutti i tipi di contenuto
scribe.listRoutableTypes(); // solo i tipi con un template path
```

Utile per strumenti generici, come l'iterazione di ogni tipo instradabile al fine di costruire menu di navigazione o feed.

## Reindirizzamenti

Per le regole di reindirizzamento esportate in modo statico (`_redirects.json`, slug cross-locale), utilizza l'entry point per gli script di build:

```ts
// scripts/generate-redirects.ts (da eseguire prima della build dell'app)
import {
  buildAllContentRedirects,
  createProject,
  createUrlBuilder,
  loadConfigSync,
} from "scribe-cms";

const config = loadConfigSync();
const project = createProject(config);
const urlBuilder = createUrlBuilder(project.config);
const rules = buildAllContentRedirects(project, {
  prefixedLocales: urlBuilder.prefixedLocales,
});
// [{ source, destination, permanent: true }, ...]
// Corrisponde perfettamente alla configurazione dei redirect di Next.js; si può mappare in base alle necessità su regole nginx, _redirects,
// vercel.json o equivalenti del tuo framework.
```

## Esportazioni grezze statiche

Per file MDX grezzi compatibili con i crawler e i modelli LLM e serviti come asset statici (ad esempio `/blog/il-mio-post.mdx`):

```bash
scribe export-static --out public
```

O in modo programmatico:

```ts
import { writeStaticRawExports, createProject, loadConfigSync } from "scribe-cms";

writeStaticRawExports(createProject(loadConfigSync()), { outDir: "public" });
```

`getStaticExportRoots(project)` restituisce le radici delle directory gestite da ripulire prima della scrittura (ad esempio `blog/`, `it/blog/`). I documenti elencati come origini di reindirizzamento in `_redirects.json` vengono ignorati quando `excludeRedirected` è impostato su true (predefinito). I documenti `noindex` sono inclusi, a meno che non sia impostato `excludeNoindex`. Per i vari flag dei comandi, consulta il [riferimento CLI](/docs/cli).

## Scappatoia

`scribe.<type>.load()` restituisce l'indice grezzo `Map<locale, { bySlug, byEnSlug }>`. È consigliabile prediligere `list`, `get` e `resolve`; il metodo `load()` esiste unicamente per la creazione di tool specifici o per modelli di accesso inusuali.

## Integrazione con i framework

Scribe è agnostico rispetto ai framework. Il runtime è sviluppato in puro Node e si integra in qualsiasi stack basato sul rendering lato server o su build statiche. Si applicano sempre tre semplici regole:

1. Importa da **`scribe-cms/runtime`** nel codice dell'applicazione (per escludere i percorsi della CLI o del traduttore dal tracciamento del bundler); usa `scribe-cms` negli script di build.
2. Mantieni **`better-sqlite3`** (un modulo nativo) e Scribe esterni al tuo bundler, ad esempio tramite `serverExternalPackages` di Next.js, `ssr.external` di Vite/Astro o `external` di esbuild.
3. Memorizza il client nella cache all'interno di un singleton di modulo:

```ts
// src/lib/scribe.ts
import { createScribe } from "scribe-cms/runtime";
import type { ScribeClient } from "scribe-cms/runtime";
import config from "../../scribe.config";

let cached: ScribeClient<typeof config> | null = null;
export function getScribe() {
  return (cached ??= createScribe(config));
}
```

Subordina le build allo stato di salute dei contenuti: `"build": "scribe validate && <framework build>"`.

### Esempio con Next.js

```ts
// next.config.ts
const nextConfig = {
  serverExternalPackages: ["better-sqlite3", "scribe-cms", "scribe-cms/runtime"],
  // Obbligatorio su Vercel: Scribe legge content/ e .scribe/ durante il runtime.
  outputFileTracingIncludes: {
    "/**": ["./content/**/*", "./.scribe/**/*"],
  },
  // Anch'esso obbligatorio su Vercel: le letture dei file di runtime di Scribe forzano il tracer
  // a inserire la cache di build webpack di Next in ogni funzione serverless,
  // superando il limite di 250 MB. La cache non è mai necessaria a runtime.
  outputFileTracingExcludes: {
    "/**": ["./.next/cache/**"],
  },
};
```

`staticParams()` si innesta in `generateStaticParams()`, `alternates()` in `metadata.alternates.languages`, `scribe.sitemap()` in `app/sitemap.ts` e `buildAllContentRedirects()` in `redirects()`.
