Skip to content

defineProjects ​

Type-safe helper for defining project configurations.

Signature ​

tsx
function defineProjects(projects: ProjexProjectInput[], options?: DefineProjectsOptions): DefineProjectsResult

Parameters ​

ParameterTypeDescription
projectsProjexProjectInput[]Array of project input configurations
optionsDefineProjectsOptionsOptional configuration options

Returns ​

DefineProjectsResult - Object containing:

  • projects: ProjexProjectInput[] - The same array (identity function for type inference)
  • options: DefineProjectsOptions - The options passed in

Commits Configuration ​

Projex can fetch recent commits from GitHub repositories for GitHub and hybrid project types.

Global Default ​

Set a default number of commits for all GitHub/hybrid projects:

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

export const projects = defineProjects([
  { id: 'my-project', type: 'github', repo: 'user/repo', status: 'active' },
], { commits: 5 })

Per-Project Override ​

Override global default for specific projects:

tsx
export const projects = defineProjects([
  { id: 'project-1', type: 'github', repo: 'user/repo1', commits: 10 },
  { id: 'project-2', type: 'github', repo: 'user/repo2' }, // uses global default
], { commits: 5 })

Available Types ​

Commits are supported for:

  • github - Fetches commits from GitHub repository
  • hybrid - Fetches commits from GitHub repository

Other project types (manual, npm, product-hunt) do not support commits.

Rate Limits ​

GitHub's unauthenticated API limit is 60 requests/hour. If you have many projects with commits enabled, we recommend setting a GITHUB_TOKEN:

bash
GITHUB_TOKEN=github_pat_xxx pnpm build

This increases your rate limit to 5,000 requests/hour.

NPM Timestamps Configuration ​

By default, npm projects do not use timestamps from the npm registry for sorting. You can opt-in to extract createdAt and updatedAt timestamps from the npm registry.

Enable NPM Timestamps ​

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

export const projects = defineProjects([
  {
    id: 'my-npm-package',
    type: 'npm',
    package: 'my-package',
    status: 'active',
  },
], {
  fetchNpmTimestamps: true,  // Extract timestamps from npm registry
})

Behavior by Project Type ​

TypeTimestamp SourceRequires fetchNpmTimestamps
githubGitHub API (created_at, updated_at)No
hybridGitHub API, npm time (max of both)For npm timestamps
npmnpm time.created, time.modifiedYes
product-huntProduct Hunt API featured_atNo
youtubeYouTube API latestVideoPublishedAtNo
devtoManual createdAt/updatedAt onlyN/A
manualManual createdAt/updatedAt onlyN/A
gumroadManual createdAt/updatedAt onlyN/A
lemonsqueezyManual createdAt/updatedAt onlyN/A

Hybrid Projects ​

For hybrid projects, when fetchNpmTimestamps is enabled, updatedAt is set to the most recent of:

  • GitHub's updated_at
  • npm's time.modified

This accurately reflects the last activity whether it was a code change or a new package version.

Manual Override ​

You can always manually specify timestamps regardless of the fetchNpmTimestamps setting:

tsx
{
  id: 'my-npm-package',
  type: 'npm',
  package: 'my-package',
  status: 'active',
  createdAt: '2024-01-01',
  updatedAt: '2024-06-01',
}

Performance Note ​

The npm registry data is already being fetched to get version and download counts. Enabling fetchNpmTimestamps extracts additional metadata from the existing response with zero extra API calls.

Error Handling Configuration ​

Control how fetch errors are surfaced during normalise() using the onError option.

onError ​

tsx
interface DefineProjectsOptions {
  commits?: number
  fetchNpmTimestamps?: boolean
  onError?: 'throw' | 'warn' | 'silent'
}
ValueBehavior
'warn' (default)Logs fetch error messages to console via console.warn
'throw'Throws an error with all fetch error messages joined
'silent'Suppresses all fetch error output

Example ​

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

// Throw on fetch errors instead of silently continuing
const { projects, options } = defineProjects([
  { id: 'proj-1', type: 'github', repo: 'user/repo', status: 'active' },
], { onError: 'throw' })

// If GitHub fetch fails, this will throw
const normalised = await Promise.all(projects.map(p => normalise(p, options)))

Purpose ​

This is an identity function that provides TypeScript type inference and autocomplete for project configurations. It does not modify the input.

Example ​

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

export const projects = defineProjects([
  {
    id: 'project-1',
    type: 'github',
    repo: 'user/repo',
    status: 'active',
    featured: true,
  },
  {
    id: 'project-2',
    type: 'npm',
    package: 'my-package',
    status: 'shipped',
  },
  {
    id: 'project-3',
    type: 'manual',
    status: 'coming-soon',
    name: 'Secret Project',
    tagline: 'Coming soon...',
  },
  {
    id: 'project-4',
    type: 'hybrid',
    repo: 'user/repo',
    package: 'my-package',
    status: 'active',
  },
  {
    id: 'project-5',
    type: 'product-hunt',
    slug: 'my-product',
    status: 'shipped',
  },
])

With Next.js ​

tsx
// projex.config.ts
import { defineProjects } from '@manningworks/projex'

export const config = defineProjects([
  // ...projects
])

// lib/projects.ts
import { config } from '@/projex.config'
import { normalise } from '@manningworks/projex'

export async function getProjects() {
  return Promise.all(config.projects.map(p => normalise(p, config.options)))
}

Type Safety ​

The function ensures all required fields are present based on the type:

  • github: requires repo
  • npm: requires package
  • product-hunt: requires slug
  • youtube: requires channelId
  • gumroad: requires productId
  • lemonsqueezy: requires storeId
  • devto: requires username
  • hybrid: requires repo and package
  • manual: no additional required fields