umbraco-delivery-type-gen
v0.1.1
Published
Generate accurate TypeScript types from a live Umbraco Delivery API — including BlockList, BlockGrid, RichText and Media — by sampling real responses instead of relying on the OpenAPI spec.
Maintainers
Readme
umbraco-delivery-type-gen
TypeScript type generator for the Umbraco Delivery API.
Infers types directly from live API responses — no Swagger limitations. Works with Umbraco 13+ and correctly handles BlockList, BlockGrid, RichText, Media, and all nested structures.
How it works
Delivery API responses
│
▼
Fetch N samples per content type
(uses ?filter=contentType:X)
│
▼
Merge samples together
(null in one + string in another = optional string)
│
▼
Detect Umbraco-specific shapes
(RichText, Media, Link, BlockList items...)
│
▼
Generate TypeScript
(discriminated unions, block element types, helpers)Installation
# Global install
npm install -g umbraco-delivery-type-gen
# Or run directly with npx
npx umbraco-delivery-type-gen -u https://mysite.comUsage
# Generate types for all content types
umbraco-delivery-type-gen -u https://mysite.com -o ./types
# With a protected Delivery API
umbraco-delivery-type-gen -u https://mysite.com -k MY_API_KEY
# Fetch more samples for better coverage
umbraco-delivery-type-gen -u https://mysite.com --samples 25
# Only specific content types
umbraco-delivery-type-gen -u https://mysite.com --types blogPost,homePage,newsPage
# Include preview/draft content
umbraco-delivery-type-gen -u https://mysite.com --preview
# Show detailed warnings (null properties, empty arrays, etc.)
umbraco-delivery-type-gen -u https://mysite.com --verboseOptions
| Option | Default | Description |
|---|---|---|
| -u, --base-url | (required) | Umbraco base URL |
| -o, --out | ./umbraco-types | Output directory |
| -k, --api-key | — | Delivery API key |
| -s, --samples | 10 | Samples per content type |
| -t, --types | all | Comma-separated content type aliases |
| -p, --preview | false | Include preview content |
| -v, --verbose | false | Show property-level warnings |
Output
umbraco-types/
├── base.ts — Umbraco base models (RichTextModel, ApiMediaWithCropsModel, etc.)
├── blocks.ts — Block element types (BlockList & BlockGrid variants)
├── content.ts — Content type interfaces + UmbracoContent union
└── index.ts — Re-exports everythingExample output
Given a blogPost content type with two published items, the generator produces:
// blocks.ts
export interface HeroBlock {
content: {
contentType: 'heroBlock';
properties: {
headline: string;
subheadline?: string; // null in some samples → optional
fullWidth: boolean;
};
};
settings: {
darkMode: boolean;
padding: string;
} | null;
}
export interface TextBlock {
content: {
contentType: 'textBlock';
properties: {
body: RichTextModel;
};
};
settings: null;
}
// content.ts
export interface BlogPost {
contentType: 'blogPost';
name: string;
id: string;
route: ApiContentRouteModel;
properties: {
title: string;
subtitle?: string;
publishDate: string;
richBody: RichTextModel;
heroImage?: ApiMediaWithCropsModel | null;
tags: string[];
blocks: (HeroBlock | TextBlock | ImageBlock)[];
};
}
export type UmbracoContent = BlogPost | HomePage | NewsPage;
// Discriminated union helper
export function isContentType<T extends UmbracoContent>(
item: UmbracoContent,
type: T['contentType']
): item is T {
return item.contentType === type;
}Using the types
import type { UmbracoContent, BlogPost, HeroBlock } from './umbraco-types';
import { isContentType } from './umbraco-types';
// Narrowing
function render(item: UmbracoContent) {
if (isContentType<BlogPost>(item, 'blogPost')) {
// item is BlogPost here
console.log(item.properties.title);
for (const block of item.properties.blocks) {
if (block.content.contentType === 'heroBlock') {
// TypeScript knows this is HeroBlock
console.log(block.content.properties.headline);
}
}
}
}Umbraco configuration
The Delivery API must be enabled in appsettings.json:
{
"Umbraco": {
"CMS": {
"DeliveryApi": {
"Enabled": true,
"ApiKey": "optional-if-protected"
}
}
}
}Why not use the Swagger spec?
The Delivery API's OpenAPI spec types BlockList and BlockGrid properties as object — which gives you nothing. This tool instead samples real API responses and infers what's actually inside the blocks.
Multi-sample merging means you get full coverage: if heroImage is null in 3 posts and an image object in 7 others, the generator correctly types it as ApiMediaWithCropsModel | null and marks it optional.
Programmatic API
You can also use the generator in your own build tooling:
import { DeliveryCrawler, mergeSamples, generateContentTypes, generateBlockTypes } from 'umbraco-delivery-type-gen';
const config = { baseUrl: 'https://mysite.com', samplesPerType: 10, outDir: './types', verbose: false };
const crawler = new DeliveryCrawler(config);
const contentTypes = await crawler.discoverContentTypes();
const shapes = await Promise.all(
contentTypes.map(async (ct) => {
const items = await crawler.fetchSamples(ct);
return mergeSamples(ct, items);
})
);
const contentTs = generateContentTypes(shapes);
const { source: blocksTs } = generateBlockTypes(shapes);