{"id":31693760,"url":"https://github.com/alloy-lab/collection-registry","last_synced_at":"2026-01-20T17:31:18.793Z","repository":{"id":316306964,"uuid":"1062652240","full_name":"alloy-lab/collection-registry","owner":"alloy-lab","description":"Automated code generation from Payload CMS collections: TypeScript types, type-safe API clients, and optional React Router routes/components.","archived":false,"fork":false,"pushed_at":"2025-10-02T05:21:29.000Z","size":249,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-10-02T07:16:16.490Z","etag":null,"topics":["api-client","codegen","developer-tools","headless-cms","payloadcms","react-router","scaffolding","typescript"],"latest_commit_sha":null,"homepage":"https://github.com/alloy-lab/collection-registry","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/alloy-lab.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-09-23T14:38:07.000Z","updated_at":"2025-10-02T05:21:32.000Z","dependencies_parsed_at":"2025-10-02T07:08:19.356Z","dependency_job_id":null,"html_url":"https://github.com/alloy-lab/collection-registry","commit_stats":null,"previous_names":["alloy-lab/collection-registry"],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/alloy-lab/collection-registry","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alloy-lab%2Fcollection-registry","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alloy-lab%2Fcollection-registry/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alloy-lab%2Fcollection-registry/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alloy-lab%2Fcollection-registry/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/alloy-lab","download_url":"https://codeload.github.com/alloy-lab/collection-registry/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/alloy-lab%2Fcollection-registry/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278972328,"owners_count":26078017,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-08T02:00:06.501Z","response_time":56,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["api-client","codegen","developer-tools","headless-cms","payloadcms","react-router","scaffolding","typescript"],"created_at":"2025-10-08T15:53:01.347Z","updated_at":"2025-10-08T15:53:06.837Z","avatar_url":"https://github.com/alloy-lab.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# @alloylab/collection-registry\n\n[![npm version](https://badge.fury.io/js/%40alloylab%2Fcollection-registry.svg)](https://badge.fury.io/js/%40alloy-lab%2Fcollection-registry)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n\nAutomated code generation from Payload CMS collections. This tool bridges the gap between Payload CMS collections and web app development by automatically generating TypeScript types, API client methods, React components, and route files.\n\n## Features\n\n- 🔍 **Auto-detection**: Automatically scans and analyzes Payload collection files\n- 📝 **Type Generation**: Generates TypeScript interfaces from collection schemas\n- 🔌 **API Clients**: Creates type-safe API client methods for each collection\n- ⚛️ **React Components**: Generates React Router routes and components\n- 🎨 **Code Formatting**: Automatically formats generated code with Prettier\n- 🔧 **Framework Agnostic**: Works with any frontend framework\n- 📦 **Zero Dependencies**: Minimal dependencies for maximum compatibility\n\n## Installation\n\n```bash\nnpm install @alloylab/collection-registry\n# or\nyarn add @alloylab/collection-registry\n# or\npnpm add @alloylab/collection-registry\n```\n\n## Quick Start\n\n### 1. Basic Usage\n\n```bash\n# Run with default paths\nnpx collection-registry\n\n# Or specify custom paths\nnpx collection-registry \\\n  --collections-path ./cms/src/collections \\\n  --output-path ./web/app/lib \\\n  --types-path ./cms/src/payload-types.ts\n```\n\n### 2. Programmatic Usage\n\n```javascript\nimport { CollectionRegistry } from '@alloylab/collection-registry';\n\nconst registry = new CollectionRegistry({\n  collectionsPath: './src/collections',\n  outputPath: './generated',\n  typesPath: './payload-types.ts',\n  format: true,\n});\n\nawait registry.generate();\n```\n\n## Configuration\n\n### Command Line Options\n\n| Option               | Description                           | Default              |\n| -------------------- | ------------------------------------- | -------------------- |\n| `--collections-path` | Path to Payload collections directory | `./src/collections`  |\n| `--output-path`      | Path to output generated files        | `./generated`        |\n| `--types-path`       | Path to Payload generated types       | `./payload-types.ts` |\n| `--format`           | Format generated files with Prettier  | `false`              |\n| `--help`             | Show help message                     | -                    |\n\n### Programmatic Configuration\n\n```javascript\nconst config = {\n  collectionsPath: './cms/src/collections', // Required\n  outputPath: './web/app/lib', // Required\n  typesPath: './cms/src/payload-types.ts', // Required\n  format: true, // Optional\n  baseUrl: 'process.env.CMS_API_URL', // Optional\n};\n```\n\n### Advanced Configuration Options\n\nThe library is designed to be transparent and customizable. You can override its assumptions:\n\n```javascript\nconst config = {\n  // Basic configuration\n  collectionsPath: './src/collections',\n  outputPath: './generated',\n  typesPath: './payload-types.ts',\n\n  // Field Detection Customization\n  fieldMappings: {\n    slugField: 'urlSlug', // Use 'urlSlug' instead of 'slug'\n    statusField: 'publishStatus', // Use 'publishStatus' instead of 'status'\n    seoField: 'metaData', // Use 'metaData' instead of 'seo'\n    navigationField: 'showInMenu', // Use 'showInMenu' instead of 'showInNavigation'\n    featuredImageField: 'heroImage', // Use 'heroImage' instead of 'featuredImage'\n    excerptField: 'summary', // Use 'summary' instead of 'excerpt'\n    tagsField: 'categories', // Use 'categories' instead of 'tags'\n    authorField: 'writer', // Use 'writer' instead of 'author'\n  },\n\n  // Status Value Customization\n  statusValues: {\n    draft: 'draft',\n    published: 'live', // Use 'live' instead of 'published'\n    scheduled: 'scheduled',\n    archived: 'hidden', // Use 'hidden' instead of 'archived'\n  },\n\n  // Template Customization\n  templates: {\n    collectionType: `\n      export interface {{collectionName}} {\n        id: string;\n        {{#each fields}}\n        {{name}}: {{type}};\n        {{/each}}\n      }\n    `,\n    apiClient: `\n      export class {{collectionName}}Client {\n        async get{{collectionName}}s(): Promise\u003c{{collectionName}}[]\u003e {\n          // Custom implementation\n        }\n      }\n    `,\n  },\n\n  // Debug Mode\n  debug: true, // Enable detailed logging of the analysis process\n};\n```\n\n## Generated Files\n\nThe tool generates the following files in your output directory:\n\n### Types (`types/`)\n\n- `base.ts` - Base types and interfaces\n- `{collection}.ts` - Individual collection types\n- `index.ts` - Exports all types\n\n### API Clients (`clients/`)\n\n- `base.ts` - Base client class\n- `{collection}.ts` - Individual collection clients\n- `index.ts` - Exports all clients\n- `payloadClient.ts` - Main client aggregator\n\n### Routes (optional)\n\n- `{collection}._index.tsx` - Collection index route\n- `{collection}.$slug.tsx` - Collection detail route\n\n## 🔍 How It Works (Transparent Process)\n\nThis library is **not a black box**. Here's exactly what it does:\n\n### 1. Collection Scanning\n\nThe library reads your Payload CMS collection files and extracts:\n\n- Collection metadata (slug, displayName, pluralName)\n- Field definitions and types\n- Common patterns (slug, status, SEO, navigation, etc.)\n\n### 2. Field Analysis\n\nFor each collection, it analyzes fields to detect:\n\n- **Slug fields** - URL-friendly identifiers (`name: 'slug'`, `type: 'text'`)\n- **Status fields** - Draft/published states (`name: 'status'`, `type: 'select'`)\n- **SEO fields** - Meta data groups (`name: 'seo'`, `type: 'group'`)\n- **Navigation fields** - Menu visibility (`name: 'showInNavigation'`, `type: 'checkbox'`)\n- **Media fields** - Featured images (`name: 'featuredImage'`, `type: 'upload'`)\n- **Content fields** - Rich text, excerpts (`name: 'excerpt'`, `type: 'textarea'`)\n- **Taxonomy fields** - Tags, categories, authors (`name: 'tags'`, `type: 'array'`)\n\n### 3. Type Generation\n\nCreates TypeScript interfaces based on:\n\n- Payload field types → TypeScript types\n- Detected patterns → Specialized types\n- Collection structure → Complete interfaces\n\n### 4. Code Generation\n\nGenerates ready-to-use code using configurable templates.\n\n## Collection Analysis\n\nThe tool automatically analyzes your Payload collections and detects:\n\n- ✅ **Slug fields** - For URL-based routing\n- ✅ **Status fields** - For draft/published content\n- ✅ **SEO fields** - For search optimization\n- ✅ **Navigation fields** - For menu generation\n- ✅ **Featured images** - For content previews\n- ✅ **Excerpt fields** - For content summaries\n- ✅ **Tag fields** - For content categorization\n- ✅ **Author fields** - For content attribution\n\n## Example Collection\n\n```typescript\n// src/collections/Posts.ts\nimport type { CollectionConfig } from 'payload';\n\nexport const Posts: CollectionConfig = {\n  slug: 'posts',\n  admin: {\n    useAsTitle: 'title',\n  },\n  fields: [\n    {\n      name: 'title',\n      type: 'text',\n      required: true,\n    },\n    {\n      name: 'slug',\n      type: 'text',\n      required: true,\n      unique: true,\n    },\n    {\n      name: 'status',\n      type: 'select',\n      options: [\n        { label: 'Draft', value: 'draft' },\n        { label: 'Published', value: 'published' },\n      ],\n      defaultValue: 'draft',\n    },\n    {\n      name: 'excerpt',\n      type: 'textarea',\n    },\n    {\n      name: 'featuredImage',\n      type: 'upload',\n      relationTo: 'media',\n    },\n    {\n      name: 'seo',\n      type: 'group',\n      fields: [\n        {\n          name: 'title',\n          type: 'text',\n        },\n        {\n          name: 'description',\n          type: 'textarea',\n        },\n      ],\n    },\n  ],\n};\n```\n\n## Generated Output\n\n### Types\n\n```typescript\n// types/posts.ts\nexport interface Post {\n  id: string;\n  title: string;\n  slug: string;\n  status: 'draft' | 'published';\n  excerpt?: string;\n  featuredImage?: Media;\n  seo?: {\n    title?: string;\n    description?: string;\n  };\n  createdAt: string;\n  updatedAt: string;\n}\n```\n\n### API Client\n\n```typescript\n// clients/posts.ts\nexport class PostsClient extends BasePayloadClient {\n  async getPosts(options?: QueryOptions): Promise\u003cPayloadResponse\u003cPost\u003e\u003e {\n    // Implementation\n  }\n\n  async getPost(slug: string, draft = false): Promise\u003cPost\u003e {\n    // Implementation\n  }\n\n  async getPublishedPosts(\n    options?: Omit\u003cQueryOptions, 'where'\u003e\n  ): Promise\u003cPost[]\u003e {\n    // Implementation\n  }\n}\n```\n\n## Integration Examples\n\n### React Router v7\n\n```typescript\n// app/routes/posts._index.tsx\nimport { postsClient } from '~/lib/clients';\n\nexport async function loader() {\n  const posts = await postsClient.getPublishedPosts();\n  return { posts };\n}\n```\n\n### Next.js\n\n```typescript\n// pages/posts/index.tsx\nimport { postsClient } from '../lib/clients';\n\nexport async function getStaticProps() {\n  const posts = await postsClient.getPublishedPosts();\n  return { props: { posts } };\n}\n```\n\n### SvelteKit\n\n```typescript\n// src/routes/posts/+page.server.ts\nimport { postsClient } from '$lib/clients';\n\nexport async function load() {\n  const posts = await postsClient.getPublishedPosts();\n  return { posts };\n}\n```\n\n## Advanced Usage\n\n### Custom Templates\n\nYou can extend the tool with custom templates:\n\n```javascript\nimport { CollectionRegistry } from '@alloylab/collection-registry';\n\nclass CustomRegistry extends CollectionRegistry {\n  generateCustomFiles() {\n    // Your custom generation logic\n  }\n}\n```\n\n### Field Type Mapping\n\nCustomize TypeScript type mapping:\n\n```javascript\nimport { getTypeScriptType } from '@alloylab/collection-registry';\n\n// Extend the type mapping\nconst customTypeMap = {\n  ...defaultTypeMap,\n  customField: 'CustomType',\n};\n```\n\n## 🔧 Understanding the Internal Logic\n\n### Field Detection Algorithm\n\nThe library uses pattern matching to detect common fields. Here's exactly how it works:\n\n```typescript\n// Slug Detection\nif (field.name === 'slug' \u0026\u0026 field.type === 'text') {\n  return { hasSlug: true, slugField: field.name };\n}\n\n// Status Detection\nif (field.name === 'status' \u0026\u0026 field.type === 'select') {\n  const options = field.options || [];\n  const hasDraft = options.some((opt) =\u003e opt.value === 'draft');\n  const hasPublished = options.some((opt) =\u003e opt.value === 'published');\n  return { hasStatus: true, statusField: field.name };\n}\n\n// SEO Detection\nif (field.name === 'seo' \u0026\u0026 field.type === 'group') {\n  const seoFields = field.fields || [];\n  const hasTitle = seoFields.some((f) =\u003e f.name === 'title');\n  const hasDescription = seoFields.some((f) =\u003e f.name === 'description');\n  return { hasSEO: true, seoField: field.name };\n}\n```\n\n### Type Mapping Logic\n\nThe library maps Payload field types to TypeScript types:\n\n```typescript\nconst typeMap = {\n  text: 'string',\n  textarea: 'string',\n  richText: 'any', // Rich text content\n  number: 'number',\n  date: 'string', // ISO date string\n  select: 'string | undefined',\n  checkbox: 'boolean',\n  upload: 'string | Media', // File ID or Media object\n  relationship: 'string | RelatedType', // ID or related object\n  array: 'ArrayType[]',\n  group: 'GroupType',\n  blocks: 'BlockType[]',\n};\n```\n\n### Customization Points\n\nYou can override any part of the analysis:\n\n```typescript\n// Custom field analyzer\nclass CustomFieldAnalyzer extends FieldAnalyzer {\n  analyzeField(field: any): FieldAnalysis {\n    // Add your custom field detection logic\n    if (field.type === 'customField') {\n      return { type: 'CustomType', hasCustomField: true };\n    }\n    return super.analyzeField(field);\n  }\n}\n\n// Custom type mapper\nclass CustomTypeMapper extends TypeMapper {\n  mapPayloadTypeToTypeScript(payloadType: string): string {\n    if (payloadType === 'customField') {\n      return 'CustomType';\n    }\n    return super.mapPayloadTypeToTypeScript(payloadType);\n  }\n}\n```\n\n## Troubleshooting\n\n### Common Issues\n\n1. **Collections not found**\n   - Ensure the collections path is correct\n   - Check that collection files have `.ts` extension\n   - Verify collection files export a valid `CollectionConfig`\n\n2. **Types not generated**\n   - Run `payload generate:types` first\n   - Check the types path is correct\n   - Ensure Payload types file exists\n\n3. **Formatting errors**\n   - Install Prettier: `npm install prettier`\n   - Check Prettier configuration\n   - Use `--no-format` to skip formatting\n\n4. **Custom field names not detected**\n   - Use `fieldMappings` configuration to map your custom field names\n   - Check the field detection logic in the debug output\n   - Extend the `FieldAnalyzer` class for custom detection\n\n5. **Status values are hard-coded**\n   - Use `statusValues` configuration to customize status values\n   - The library detects status fields but uses configured values for types\n\n### Debug Mode\n\nEnable debug logging to see exactly what the library is doing:\n\n```bash\nDEBUG=collectionRegistry npx collection-registry\n```\n\nOr programmatically:\n\n```javascript\nconst registry = new CollectionRegistry({\n  // ... config\n  debug: true, // Enable detailed logging\n});\n```\n\nThis will show you:\n\n- Which collections were found\n- How each field was analyzed\n- What patterns were detected\n- How types were mapped\n- What code was generated\n\n## 📚 Additional Resources\n\n- 📖 [Customization Examples](./examples/customization.md) - How to customize the library\n- 🔧 [Troubleshooting Guide](./TROUBLESHOOTING.md) - Common issues and solutions\n- 🎯 [How It Works](#-how-it-works-transparent-process) - Understanding the internal logic\n\n## Versioning\n\nThis package uses [Conventional Commits](https://conventionalcommits.org/) for automatic versioning:\n\n- `feat:` → Minor version bump (1.0.0 → 1.1.0)\n- `fix:` → Patch version bump (1.0.0 → 1.0.1)\n- `feat!:` or `BREAKING CHANGE:` → Major version bump (1.0.0 → 2.0.0)\n\nSee [VERSIONING.md](./VERSIONING.md) for detailed information.\n\n## Contributing\n\nContributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) for details.\n\n- 🛡️ [Security Policy](SECURITY.md)\n- 🤝 [Code of Conduct](CODE_OF_CONDUCT.md)\n- 🐛 [Bug Reports](.github/ISSUE_TEMPLATE/bug_report.yml)\n- ✨ [Feature Requests](.github/ISSUE_TEMPLATE/feature_request.yml)\n- ❓ [Questions](.github/ISSUE_TEMPLATE/question.yml)\n\n## License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## Support\n\n- 📖 [Documentation](https://github.com/alloy-lab/collection-registry#readme)\n- 🐛 [Issue Tracker](https://github.com/alloy-lab/collection-registry/issues)\n- 💬 [Discussions](https://github.com/alloy-lab/collection-registry/discussions)\n\n## Related Projects\n\n- [Overland Stack](https://github.com/alloy-lab/overland) - Full-stack template\n- [Payload CMS](https://payloadcms.com/) - Headless CMS\n- [React Router](https://reactrouter.com/) - Web framework\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falloy-lab%2Fcollection-registry","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falloy-lab%2Fcollection-registry","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falloy-lab%2Fcollection-registry/lists"}