Skip to content

normalise

Transform a ProjexProjectInput into a normalized ProjexProject by fetching external data.

Signature

tsx
function normalise(
  input: ProjexProjectInput,
  options?: DefineProjectsOptions,
): Promise<ProjexProject>

Parameters

ParameterTypeDescription
inputProjexProjectInputProject input configuration
optionsDefineProjectsOptionsOptional configuration controlling commits fetching and npm timestamp behavior

DefineProjectsOptions

tsx
interface DefineProjectsOptions {
  commits?: number
  fetchNpmTimestamps?: boolean
}
  • commits: Number of recent commits to fetch for github and hybrid projects. Defaults to 0 (no commits). Per-project commits values override this global default.
  • fetchNpmTimestamps: When true, extracts createdAt and updatedAt timestamps from the npm registry for npm and hybrid projects. Defaults to false.

Returns

Promise<ProjexProject> - Normalized project with fetched data

Behavior

The function fetches external data based on the project type:

TypeFetches
githubGitHub repository data
npmnpm package data
product-huntProduct Hunt post data
youtubeYouTube channel data
gumroadGumroad product data
lemonsqueezyLemon Squeezy store data
devtoDev.to user article data
hybridGitHub + npm data
manualNo external fetch

Data Merging

For fetched types, the function merges external API data with your input config using a consistent priority chain:

  1. override object — highest priority (only available for github and hybrid types)
  2. Input config valuesname, tagline, description, stack from your project config
  3. Fetched API data — auto-populated from external sources as fallbacks
  4. Default — empty string or empty array

Auto-populated fields by type:

Typenametaglinedescriptionstatslinks
github
hybrid
npm
product-hunt
youtube
gumroad
lemonsqueezy
devto
manual

Null Safety

The function handles fetch failures gracefully:

  • If GitHub/npm/Product Hunt fetch fails, uses input data only
  • Returns null for missing optional fields

Example

tsx
import { normalise, defineProjects } from '@manningworks/projex'

// Single project
const project = await normalise({
  id: 'my-project',
  type: 'github',
  repo: 'user/repo',
  status: 'active'
})

// Multiple projects
const { projects, options } = defineProjects([
  { id: 'proj-1', type: 'github', repo: 'user/repo', status: 'active' },
  { id: 'proj-2', type: 'npm', package: 'my-package', status: 'shipped' },
  { id: 'proj-3', type: 'manual', status: 'coming-soon', name: 'Secret Project' },
])
const normalised = await Promise.all(projects.map(p => normalise(p, options)))

Environment Variables

VariableRequiredDescription
GITHUB_TOKENOptionalGitHub API token (5000/hr vs 60/hr rate limit)
PRODUCT_HUNT_TOKENRequired for product-huntProduct Hunt API token
YOUTUBE_TOKENRequired for youtubeYouTube Data API v3 key
GUMROAD_TOKENRequired for gumroadGumroad access token
LS_TOKENRequired for lemonsqueezyLemon Squeezy API key
DEV_TO_API_KEYOptionalDev.to API key (enables page_views_count for totalViews)

Note: Dev.to (devto) works without environment variables (public API), but DEV_TO_API_KEY is recommended to enable page_views_count for accurate totalViews. The manual type does not require any environment variables.

Override Example

tsx
const project = await normalise({
  id: 'my-project',
  type: 'github',
  repo: 'user/repo',
  status: 'active',
  override: {
    name: 'Custom Name',
    description: 'Custom description overrides GitHub description',
    stack: ['React', 'TypeScript', 'Tailwind']
  }
})