npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

contentful-orm

v1.0.4

Published

A TypeScript-first ORM for Contentful CMS that enables a code-first approach to content modeling

Downloads

649

Readme

Contentful ORM

A TypeScript-first ORM for Contentful CMS that enables a code-first approach to content modeling. Define your content types using TypeScript decorators and automatically sync them with Contentful.

Features

  • 🎯 Code-First Development
  • 📝 TypeScript Stage 3 Decorators
  • 🔄 Automatic Content Type Synchronization
  • 🛠️ CLI Tools
  • 💪 Type Safety
  • 🌐 Localization Support
  • 🔗 Reference Field Support
  • ✨ Rich Text Support

Supported Field Types

The following field types are supported:

  • Symbol - For short text content (Contentful's Symbol type)
  • Text - For long text content (Contentful's Text type)
  • RichText - For rich text content with formatting
  • Number - For decimal numbers
  • Integer - For whole numbers
  • Date - For date and time values
  • Location - For geographical coordinates
  • Media - For media assets (images, videos, etc.)
  • Boolean - For true/false values
  • Reference - For references to other content types
  • Array - For arrays of any other supported type
  • Object - For JSON objects

Each field type can be configured with additional options:

@Field({
  type: ContentfulFieldType.Text,     // The field type
  required: true,                     // Whether the field is required
  localized: false,                   // Whether the field supports localization
  validations: [],                    // Array of validation rules
  disabled: false,                    // Whether the field is read-only
  omitted: false,                     // Whether the field is hidden
  // Array-specific options
  itemsType: ContentfulFieldType.Text,    // Type of array items (for Array type)
  itemsValidations: [],                   // Validations for array items
  itemsLinkType: 'Entry'                  // Link type for Reference/Media arrays
})

Specialized Field Decorators

For better type safety and developer experience, specialized decorators are available for different field types:

Basic Fields

@SymbolField({
  required: true,
  validations: [
    Validations.size(1, 50)
  ]
})
declare name: string;

@IntegerField({
  required: true,
  validations: [
    Validations.range(0, 100)
  ]
})
declare quantity: number;

@ObjectField()
declare metadata: Record<string, any>;

Media Fields

@MediaField({
  required: true,
  validations: [
    Validations.linkMimetypeGroup(['image'])
  ]
})
declare featuredImage: any;

Reference Fields

@ReferenceField({
  linkType: 'Entry',
  required: true,
  validations: [
    Validations.linkContentType(['category'])
  ]
})
declare category: any;

Array Fields

@ArrayField({
  itemsType: ContentfulFieldType.Media,
  itemsLinkType: 'Asset',
  itemsValidations: [
    Validations.linkMimetypeGroup(['image'])
  ]
})
declare gallery?: any[];

Validation Builders

The library provides type-safe validation builders to help prevent runtime errors:

import { Validations } from 'contentful-orm';

// Text validations
Validations.size(10, 100)           // Min/max length
Validations.regexp('^[A-Z]', 'i')   // Regular expression with flags
Validations.unique()                // Unique value

// Number validations
Validations.range(0, 100)           // Min/max value

// Link validations
Validations.linkContentType(['category', 'author'])  // Valid content types
Validations.linkMimetypeGroup(['image', 'video'])    // Valid mime types

// Rich text validations
Validations.enabledMarks(['bold', 'italic'])         // Allowed formatting
Validations.enabledNodeTypes(['paragraph', 'heading-1']) // Allowed blocks

Complete Example

Here's a complete example of a Product content type using all available field types:

@ContentType({
  name: 'product',
  displayField: 'name',
  description: 'A product with all available field types'
})
export class Product {
  @SymbolField({
    required: true,
    validations: [
      Validations.size(1, 50)
    ]
  })
  declare name: string;

  @Field({
    type: ContentfulFieldType.Text,
    required: true
  })
  declare description: string;

  @Field({
    type: ContentfulFieldType.RichText,
    validations: [
      Validations.enabledMarks(['bold', 'italic']),
      Validations.enabledNodeTypes(['paragraph', 'heading-1'])
    ]
  })
  declare details: any;

  @IntegerField({
    required: true,
    validations: [
      Validations.range(0)
    ]
  })
  declare quantity: number;

  @Field({
    type: ContentfulFieldType.Number,
    validations: [
      Validations.range(0.01)
    ]
  })
  declare price: number;

  @Field({
    type: ContentfulFieldType.Date,
    required: true
  })
  declare releaseDate: Date;

  @Field({
    type: ContentfulFieldType.Location
  })
  declare storeLocation: any;

  @MediaField({
    required: true,
    validations: [
      Validations.linkMimetypeGroup(['image'])
    ]
  })
  declare image: any;

  @Field({
    type: ContentfulFieldType.Boolean,
    required: true
  })
  declare isAvailable: boolean;

  @ReferenceField({
    linkType: 'Entry',
    validations: [
      Validations.linkContentType(['category'])
    ]
  })
  declare category: any;

  @ArrayField({
    itemsType: ContentfulFieldType.Reference,
    itemsLinkType: 'Entry',
    itemsValidations: [
      Validations.linkContentType(['tag'])
    ]
  })
  declare tags: any[];

  @ObjectField()
  declare metadata: Record<string, any>;

  @Field({
    type: ContentfulFieldType.Text,
    disabled: true
  })
  declare sku: string;

  @Field({
    type: ContentfulFieldType.Text,
    omitted: true
  })
  declare internalNotes: string;
}

## Examples

The repository includes several examples to help you get started:

### Blog Example
A complete example of a blog implementation using Contentful ORM. Located in `/examples/blog`, this example demonstrates:
- Full project structure
- Entity definitions
- Environment configuration
- TypeScript configuration

### Case Study Example
A single-file example (`/examples/case-study.ts`) showing how to define a case study content type with:
- Rich text content
- Media fields
- Reference fields
- Field validations

### Direct TypeScript Example
Located in `/examples/direct-ts`, this example demonstrates direct TypeScript usage of the ORM.

For more details, check out the examples in the repository's `/examples` directory.

## Requirements

- TypeScript 5.2 or higher
- Node.js 18 or higher

## Setup Guide

### Installation

```bash
# Using npm
npm install contentful-orm reflect-metadata cross-env ts-node --save-dev

# Using pnpm
pnpm add contentful-orm reflect-metadata cross-env ts-node -D

# Using yarn
yarn add contentful-orm reflect-metadata cross-env ts-node --dev

Configuration

1. Environment Variables

Create a .env file in your project root:

CONTENTFUL_SPACE_ID=your_space_id
CONTENTFUL_ACCESS_TOKEN=your_management_access_token
CONTENTFUL_ENVIRONMENT_ID=master  # or your preferred environment

Important: The CONTENTFUL_ACCESS_TOKEN should be a Management Access Token, not a Content Delivery/Preview token. You can generate one from Contentful's web app under Settings > API Keys > Content management tokens.

2. TypeScript Configuration

Your tsconfig.json must include the following settings for decorators and metadata to work properly:

{
  "compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "module": "ESNext",
    "moduleResolution": "node",
    "target": "ESNext"
  }
}

3. Package Configuration

Update your package.json to include the following scripts:

{
  "scripts": {
    "clean": "rimraf dist",
    "build": "npm run clean && tsc",
    "sync": "npm run build && contentful-orm sync --path=\"dist/entities/**/*.js\""
  }
}

Install the required dev dependencies:

pnpm add -D rimraf

Entity Setup

  1. Create your entity files with .ts extension in your entities directory
  2. Export all entities from an index.ts file

Example entity structure:

// src/entities/author.ts
import { ContentType, Field, ContentfulFieldType } from 'contentful-orm';

@ContentType({
  name: 'author',
  displayField: 'name',
  description: 'Author of blog posts'
})
export class Author {
  @Field({
    type: ContentfulFieldType.Text,
    required: true,
    validations: [{
      size: { min: 2, max: 100 }
    }]
  })
  name!: string;
}

Running the Sync

After setting up your entities and configuration:

  1. Build your TypeScript files:
pnpm build
  1. Run the sync command:
pnpm sync

The sync process will:

  • Build your TypeScript files
  • Find all entity files in the specified path
  • Create or update content types in Contentful
  • Handle versioning and publishing automatically

Troubleshooting

If you encounter sync issues:

  1. Ensure your Management Access Token has the correct permissions
  2. Check that all import paths use .js extensions
  3. Verify that your TypeScript configuration includes decorator and metadata settings
  4. Make sure all array field validations use itemsValidations instead of items

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

https://github.com/Moga-Digital-LLC/contentful-orm

License

MIT