gtmesh types
Generates the SSG-facing TypeScript content-types package from schemas/, so your website compiles against the content contract.
gtmesh types [--check] [--dir <path>]What it does
gtmesh types reads your per-type schemas in schemas/ — plus a handful of config-derived constants (the section list, per-environment render set, site base URL, facet axes, and thumbnail projection) — and emits a self-contained, buildable TypeScript package — the content-types package your website (or any TS consumer) imports. Your site’s components type-check against these generated types, so the consumer can’t drift from the content the engine produces.
With --check it writes nothing and instead verifies that the committed package still matches the schemas, exiting non-zero on drift. Wire that into CI so a schema change can’t ship without the regenerated package.
A type defined once and shared by file ($ref: "shared.schema.yaml#/definitions/hero") emits one interface, however many page types use it. Each name maps to a single TS type, so gtmesh types stops and names the files when one name carries two different types: a shared definition and a local copy that differ in any way, or two local copies that differ in structure. Local copies that differ only in titles or descriptions generate a warning instead.
Generating types is the consume step. The schemas it reads are the same ones validate and seal enforce on page content — one source of truth for both the data and its TypeScript shape.
Repo wiring
On a write (not --check), gtmesh types also wires the package into the repo so it’s usable straight away. Each file is created only if it’s missing, so your edits are kept:
pnpm-workspace.yamllisting the package’s parent dir, so consumers depend on it asworkspace:*;- a root
package.jsonwith@benfoster/gtmeshas a devDependency; .npmrcpointing the@benfosterscope at GitHub Packages;.github/workflows/content-types.yml, thetypes --checkCI gate.
A mesh inside a larger pnpm monorepo (a folder such as mesh/ under a repo whose own pnpm-workspace.yaml sits above it) leaves the workspace file, .npmrc and CI to that repo. The search stops at the repo root (the first folder with .git). gtmesh types writes the package and the mesh’s package.json. It warns if the outer pnpm-workspace.yaml doesn’t list the package dir (add e.g. mesh/packages/*), and if an earlier run left a workspace file, .npmrc or workflow inside the mesh (delete them). It also prints the CI step to add to the repo’s own workflow:
pnpm --dir "mesh" exec gtmesh types --checkThe repo’s own .npmrc needs the @benfoster scope line from installation so CI can install gtmesh.
Keep codegen.dir inside the mesh (the default packages/content-types) in both layouts. To skip the package build step, set codegen.exports: source; see built or source entry points.
Configuration
The codegen block in gtmesh.config.yaml shapes the package. Every key is optional.
| Key | Default | What it sets |
|---|---|---|
codegen.dir | packages/content-types | Where the package is written, relative to the mesh. Keep it inside the mesh. |
codegen.name | @<project>/content-types | The package name consumers depend on ("<name>": "workspace:*"). |
codegen.exports | dist | What the package’s entry points name. dist: the compiled dist/, so consumers build the package first. source: the .ts files, compiled by each consumer’s own build, with no build step; every consumer’s tsconfig must use "moduleResolution": "bundler". See built or source entry points. |
gtmesh config set codegen.exports source # then: gtmesh typesType names
A definition in your schemas can share a name with one of the engine’s exports (a shared section definition generates Section; status generates Status). Your type takes the plain name, the engine’s stays reachable as Gtmesh.<Name>, and gtmesh types warns once per shared name, naming the import that now resolves to your type. The one reserved name is Gtmesh. See type names: yours take priority.
Arguments & flags
| Option | Description | Default |
|---|---|---|
--check | Verify the committed package matches the schemas (CI gate); exits non-zero on drift. Writes nothing | off (generates) |
--dir <path> | Override the package output directory | config.codegen.dir |
The global options (--project, --json, --quiet) also apply.
Reads & writes
- Consumes: the per-type schemas in
schemas/(incl. any projection result schema likecard.schema.yaml) and any schema file they$refby file, plus config-derived constants fromgtmesh.config.yaml—taxonomy(sections, axes, facets),environments,site(incl.site.projectionsandsite.assets), andimages(andconfig.codegen.dirandconfig.codegen.exports). - Produces: the generated TypeScript package on disk — unless
--check, which produces only a pass/fail result.--checkis read-only. - Commits: the regenerated package belongs in your commit; CI runs
--checkto confirm it’s in sync.
Examples
gtmesh types # (re)generate the package into config.codegen.dir
gtmesh types --dir packages/content # generate into a specific directory
gtmesh types --check # CI gate: fail if the package is staleRelated
- Content-types package — what this emits and how your site consumes it.
validate— the same schemas, enforced on page content.- Reference — the version-exact flag list.