@bobbykim/manguito-cms-api 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/codegen/index.ts","../../src/codegen/routes.ts"],"sourcesContent":["export { generateRoutes, generateContentSchema, fieldToZodSchema } from './routes.js'\n","// generateRoutes() — pure function that returns a Hono route group from parsed schema\nimport type {\n SchemaRegistry,\n ParsedField,\n ParsedContentType,\n ParsedTaxonomyType,\n ParsedParagraphType,\n} from '@bobbykim/manguito-cms-core'\n\n// ─── Name helpers ─────────────────────────────────────────────────────────────\n\nfunction getSegment(machineName: string): string {\n const idx = machineName.indexOf('--')\n return idx !== -1 ? machineName.slice(idx + 2) : machineName\n}\n\nfunction toPascalCase(snakeOrKebab: string): string {\n return snakeOrKebab\n .split(/[_-]/)\n .filter(Boolean)\n .map((p) => p.charAt(0).toUpperCase() + p.slice(1))\n .join('')\n}\n\nfunction schemaVar(machineName: string): string {\n return toPascalCase(getSegment(machineName)) + 'Schema'\n}\n\nfunction routeVar(prefix: string, machineName: string, suffix: string): string {\n return `${prefix}${toPascalCase(getSegment(machineName))}${suffix}Route`\n}\n\n// Convert Hono :param notation to OpenAPI {param} notation\nfunction openApiPath(honoPath: string): string {\n return honoPath.replace(/:([^/]+)/g, '{$1}')\n}\n\n// ─── Field → Zod type string ──────────────────────────────────────────────────\n\nexport function fieldToZodSchema(field: ParsedField, registry?: SchemaRegistry): string {\n const { field_type, validation } = field\n\n switch (field_type) {\n case 'text/plain': {\n let s = 'z.string()'\n if (validation.limit !== undefined) s += `.max(${validation.limit})`\n if (validation.pattern !== undefined) s += `.regex(new RegExp(${JSON.stringify(validation.pattern)}))`\n return s\n }\n\n case 'text/rich':\n return 'z.string()'\n\n case 'integer': {\n let s = 'z.number().int()'\n if (validation.min !== undefined) s += `.min(${validation.min})`\n if (validation.max !== undefined) s += `.max(${validation.max})`\n return s\n }\n\n case 'float': {\n let s = 'z.number()'\n if (validation.min !== undefined) s += `.min(${validation.min})`\n if (validation.max !== undefined) s += `.max(${validation.max})`\n return s\n }\n\n case 'boolean':\n return 'z.boolean()'\n\n case 'date':\n return 'z.string().datetime()'\n\n case 'image': {\n const fields = [\n 'id: z.string().uuid()',\n 'url: z.string().url()',\n 'mime_type: z.string()',\n 'alt: z.string().optional()',\n 'file_size: z.number().int()',\n 'width: z.number().int().optional()',\n 'height: z.number().int().optional()',\n ]\n return `z.object({ ${fields.join(', ')} })`\n }\n\n case 'video': {\n const fields = [\n 'id: z.string().uuid()',\n 'url: z.string().url()',\n 'mime_type: z.string()',\n 'alt: z.string().optional()',\n 'file_size: z.number().int()',\n 'width: z.number().int().optional()',\n 'height: z.number().int().optional()',\n 'duration: z.number().optional()',\n ]\n return `z.object({ ${fields.join(', ')} })`\n }\n\n case 'file': {\n const fields = [\n 'id: z.string().uuid()',\n 'url: z.string().url()',\n 'mime_type: z.string()',\n 'alt: z.string().optional()',\n 'file_size: z.number().int()',\n ]\n return `z.object({ ${fields.join(', ')} })`\n }\n\n case 'enum': {\n const values = validation.allowed_values ?? []\n if (values.length === 0) return 'z.string()'\n const quoted = values.map((v) => JSON.stringify(v)).join(', ')\n return `z.enum([${quoted}])`\n }\n\n case 'paragraph': {\n const ui = field.ui_component\n if (ui.component !== 'paragraph-embed') return 'z.unknown()'\n const paragraphType = registry?.paragraph_types[ui.ref]\n if (!paragraphType) return 'z.unknown()'\n const inner = generateParagraphObjectSchema(paragraphType, registry)\n return ui.rel === 'one-to-many' ? `z.array(${inner})` : inner\n }\n\n case 'reference': {\n const ui = field.ui_component\n if (ui.component !== 'typeahead-select') return 'z.string().uuid()'\n return ui.rel === 'one-to-many' ? 'z.array(z.string().uuid())' : 'z.string().uuid()'\n }\n\n default:\n return 'z.unknown()'\n }\n}\n\n// Generates inline z.object({...}) for a paragraph type — used recursively inside fieldToZodSchema\nfunction generateParagraphObjectSchema(\n paragraph: ParsedParagraphType,\n registry?: SchemaRegistry\n): string {\n const entries = paragraph.fields.map((f) => {\n const zodType = fieldToZodSchema(f, registry)\n return `${f.name}: ${f.required ? zodType : `${zodType}.optional()`}`\n })\n if (entries.length === 0) return 'z.object({})'\n return `z.object({ ${entries.join(', ')} })`\n}\n\n// ─── Schema declaration generators ───────────────────────────────────────────\n\nfunction systemFieldEntries(schema: ParsedContentType | ParsedTaxonomyType): string[] {\n const entries: string[] = ['id: z.string().uuid()']\n if (schema.schema_type === 'content-type' && !schema.only_one) {\n entries.push('slug: z.string()')\n }\n entries.push('published: z.boolean()')\n entries.push('created_at: z.string().datetime()')\n entries.push('updated_at: z.string().datetime()')\n return entries\n}\n\nfunction schemaFieldEntries(\n fields: ParsedField[],\n registry?: SchemaRegistry\n): string[] {\n return fields.map((f) => {\n const zodType = fieldToZodSchema(f, registry)\n return ` ${f.name}: ${f.required ? zodType : `${zodType}.optional()`}`\n })\n}\n\nexport function generateContentSchema(\n schema: ParsedContentType | ParsedTaxonomyType,\n registry?: SchemaRegistry\n): string {\n const name = schemaVar(schema.name)\n const sysEntries = systemFieldEntries(schema).map((e) => ` ${e}`)\n const fieldEntries = schemaFieldEntries(schema.fields, registry)\n const allEntries = [...sysEntries, ...fieldEntries]\n return `const ${name} = z.object({\\n${allEntries.join(',\\n')},\\n})`\n}\n\n// Internal: paragraph schema const declaration (not exported but emitted into generated file)\nfunction generateParagraphSchemaDecl(\n paragraph: ParsedParagraphType,\n registry?: SchemaRegistry\n): string {\n const name = schemaVar(paragraph.name)\n const inner = generateParagraphObjectSchema(paragraph, registry)\n return `const ${name} = ${inner}`\n}\n\n// ─── Shared schemas block ─────────────────────────────────────────────────────\n\nconst SHARED_SCHEMAS_BLOCK = `const ErrorResponseSchema = z.object({\n ok: z.literal(false),\n error: z.object({\n code: z.string(),\n message: z.string(),\n details: z.unknown().optional(),\n }),\n})\n\nfunction listResponseSchema<T extends z.ZodTypeAny>(dataSchema: T) {\n return z.object({\n ok: z.literal(true),\n data: z.array(dataSchema),\n meta: z.object({\n total: z.number().int(),\n page: z.number().int(),\n per_page: z.number().int(),\n total_pages: z.number().int(),\n has_next: z.boolean(),\n has_prev: z.boolean(),\n }),\n })\n}\n\nfunction itemResponseSchema<T extends z.ZodTypeAny>(dataSchema: T) {\n return z.object({\n ok: z.literal(true),\n data: dataSchema,\n })\n}`\n\n// ─── Query param schema strings ───────────────────────────────────────────────\n\nconst PUBLIC_LIST_QUERY = `z.object({\n page: z.coerce.number().int().min(1).default(1),\n per_page: z.coerce.number().int().min(1).max(100).default(10),\n include: z.string().optional().describe('Comma-separated relation field names to expand'),\n sort_by: z.enum(['title', 'created_at', 'updated_at']).optional().default('created_at'),\n sort_order: z.enum(['asc', 'desc']).optional().default('asc'),\n })`\n\nconst ADMIN_LIST_QUERY = `z.object({\n page: z.coerce.number().int().min(1).default(1),\n per_page: z.coerce.number().int().min(1).max(100).default(10),\n include: z.string().optional().describe('Comma-separated relation field names to expand'),\n sort_by: z.enum(['title', 'created_at', 'updated_at']).optional().default('created_at'),\n sort_order: z.enum(['asc', 'desc']).optional().default('asc'),\n published: z.enum(['true', 'false']).optional().describe('Filter by published state'),\n })`\n\nconst SLUG_PARAMS = `z.object({ slug: z.string() })`\nconst ID_PARAMS = `z.object({ id: z.string().uuid() })`\nconst INCLUDE_QUERY = `z.object({ include: z.string().optional().describe('Comma-separated relation field names to expand') })`\n\n// ─── Content route generators ─────────────────────────────────────────────────\n\nfunction generateContentRoutes(contentType: ParsedContentType): string {\n const sVar = schemaVar(contentType.name)\n const label = contentType.label\n const tag = label\n const lines: string[] = []\n\n if (!contentType.only_one) {\n const collPath = contentType.api.collection_path!\n const itemPath = contentType.api.item_path\n\n // Public — GET list\n lines.push(\n `export const ${routeVar('get', contentType.name, 'List')} = createRoute({\n method: 'get',\n path: '${collPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n query: ${PUBLIC_LIST_QUERY},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: listResponseSchema(${sVar}) } },\n description: 'List of ${label}',\n },\n 400: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Invalid query parameters',\n },\n },\n})`\n )\n\n // Public — GET single by slug\n lines.push(\n `export const ${routeVar('get', contentType.name, '')} = createRoute({\n method: 'get',\n path: '${openApiPath(itemPath)}',\n tags: [${JSON.stringify(tag)}],\n request: {\n params: ${SLUG_PARAMS},\n query: ${INCLUDE_QUERY},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label}',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n },\n})`\n )\n\n // Admin — GET list\n const adminCollPath = '/admin' + collPath\n const adminItemPath = adminCollPath + '/{id}'\n lines.push(\n `export const ${routeVar('adminGet', contentType.name, 'List')} = createRoute({\n method: 'get',\n path: '${adminCollPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n query: ${ADMIN_LIST_QUERY},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: listResponseSchema(${sVar}) } },\n description: 'List of ${label}',\n },\n 400: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Invalid query parameters',\n },\n },\n})`\n )\n\n // Admin — GET single by id\n lines.push(\n `export const ${routeVar('adminGet', contentType.name, '')} = createRoute({\n method: 'get',\n path: '${adminItemPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n params: ${ID_PARAMS},\n query: ${INCLUDE_QUERY},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label}',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n },\n})`\n )\n\n // Admin — POST\n lines.push(\n `export const ${routeVar('adminCreate', contentType.name, '')} = createRoute({\n method: 'post',\n path: '${adminCollPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n body: {\n content: { 'application/json': { schema: ${sVar} } },\n },\n },\n responses: {\n 201: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label} created',\n },\n 422: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Validation error',\n },\n },\n})`\n )\n\n // Admin — PATCH\n lines.push(\n `export const ${routeVar('adminUpdate', contentType.name, '')} = createRoute({\n method: 'patch',\n path: '${adminItemPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n params: ${ID_PARAMS},\n body: {\n content: { 'application/json': { schema: ${sVar}.partial().extend({ published: z.boolean().optional() }) } },\n },\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label} updated',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n 422: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Validation error',\n },\n },\n})`\n )\n\n // Admin — DELETE\n lines.push(\n `export const ${routeVar('adminDelete', contentType.name, '')} = createRoute({\n method: 'delete',\n path: '${adminItemPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n params: ${ID_PARAMS},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: z.object({ ok: z.literal(true) }) } },\n description: '${label} deleted',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n },\n})`\n )\n } else {\n // only_one: true — no list, no slug, fixed paths\n const itemPath = contentType.api.item_path\n const adminItemBase = '/admin' + itemPath\n const adminPatchPath = '/admin/api/' + contentType.default_base_path + '/{id}'\n\n // Public — GET singleton\n lines.push(\n `export const ${routeVar('get', contentType.name, '')} = createRoute({\n method: 'get',\n path: '${itemPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n query: ${INCLUDE_QUERY},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label}',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n },\n})`\n )\n\n // Admin — GET singleton\n lines.push(\n `export const ${routeVar('adminGet', contentType.name, '')} = createRoute({\n method: 'get',\n path: '${adminItemBase}',\n tags: [${JSON.stringify(tag)}],\n request: {\n query: ${INCLUDE_QUERY},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label}',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n },\n})`\n )\n\n // Admin — POST (create singleton)\n const adminPostPath = '/admin/api/' + contentType.default_base_path\n lines.push(\n `export const ${routeVar('adminCreate', contentType.name, '')} = createRoute({\n method: 'post',\n path: '${adminPostPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n body: {\n content: { 'application/json': { schema: ${sVar} } },\n },\n },\n responses: {\n 201: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label} created',\n },\n 409: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Singleton already exists',\n },\n 422: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Validation error',\n },\n },\n})`\n )\n\n // Admin — PATCH\n lines.push(\n `export const ${routeVar('adminUpdate', contentType.name, '')} = createRoute({\n method: 'patch',\n path: '${adminPatchPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n params: ${ID_PARAMS},\n body: {\n content: { 'application/json': { schema: ${sVar}.partial().extend({ published: z.boolean().optional() }) } },\n },\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label} updated',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n 422: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Validation error',\n },\n },\n})`\n )\n }\n\n return lines.join('\\n\\n')\n}\n\n// ─── Taxonomy route generators ────────────────────────────────────────────────\n\nfunction generateTaxonomyRoutes(taxonomyType: ParsedTaxonomyType): string {\n const sVar = schemaVar(taxonomyType.name)\n const label = taxonomyType.label\n const tag = label\n const collPath = taxonomyType.api.collection_path\n const itemPath = taxonomyType.api.item_path\n const adminCollPath = '/admin' + collPath\n const adminItemPath = '/admin' + openApiPath(itemPath)\n const lines: string[] = []\n\n // Public — GET list\n lines.push(\n `export const ${routeVar('get', taxonomyType.name, 'List')} = createRoute({\n method: 'get',\n path: '${collPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n query: ${PUBLIC_LIST_QUERY},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: listResponseSchema(${sVar}) } },\n description: 'List of ${label}',\n },\n 400: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Invalid query parameters',\n },\n },\n})`\n )\n\n // Public — GET single by id\n lines.push(\n `export const ${routeVar('get', taxonomyType.name, '')} = createRoute({\n method: 'get',\n path: '${openApiPath(itemPath)}',\n tags: [${JSON.stringify(tag)}],\n request: {\n params: ${ID_PARAMS},\n query: ${INCLUDE_QUERY},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label}',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n },\n})`\n )\n\n // Admin — GET list\n lines.push(\n `export const ${routeVar('adminGet', taxonomyType.name, 'List')} = createRoute({\n method: 'get',\n path: '${adminCollPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n query: ${ADMIN_LIST_QUERY},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: listResponseSchema(${sVar}) } },\n description: 'List of ${label}',\n },\n 400: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Invalid query parameters',\n },\n },\n})`\n )\n\n // Admin — GET single by id\n lines.push(\n `export const ${routeVar('adminGet', taxonomyType.name, '')} = createRoute({\n method: 'get',\n path: '${adminItemPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n params: ${ID_PARAMS},\n query: ${INCLUDE_QUERY},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label}',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n },\n})`\n )\n\n // Admin — POST\n lines.push(\n `export const ${routeVar('adminCreate', taxonomyType.name, '')} = createRoute({\n method: 'post',\n path: '${adminCollPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n body: {\n content: { 'application/json': { schema: ${sVar} } },\n },\n },\n responses: {\n 201: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label} created',\n },\n 422: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Validation error',\n },\n },\n})`\n )\n\n // Admin — PATCH\n lines.push(\n `export const ${routeVar('adminUpdate', taxonomyType.name, '')} = createRoute({\n method: 'patch',\n path: '${adminItemPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n params: ${ID_PARAMS},\n body: {\n content: { 'application/json': { schema: ${sVar}.partial().extend({ published: z.boolean().optional() }) } },\n },\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label} updated',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n 422: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Validation error',\n },\n },\n})`\n )\n\n // Admin — DELETE\n lines.push(\n `export const ${routeVar('adminDelete', taxonomyType.name, '')} = createRoute({\n method: 'delete',\n path: '${adminItemPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n params: ${ID_PARAMS},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: z.object({ ok: z.literal(true) }) } },\n description: '${label} deleted',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n },\n})`\n )\n\n return lines.join('\\n\\n')\n}\n\n// ─── generateRoutes ───────────────────────────────────────────────────────────\n\nexport function generateRoutes(registry: SchemaRegistry): string {\n const parts: string[] = []\n\n parts.push('// Auto-generated by generateRoutes() — do not hand-edit')\n parts.push(\"import { createRoute, z } from '@hono/zod-openapi'\")\n parts.push('')\n parts.push('// ─── Shared schemas ──────────────────────────────────────────────────────────')\n parts.push('')\n parts.push(SHARED_SCHEMAS_BLOCK)\n parts.push('')\n\n const paragraphEntries = Object.entries(registry.paragraph_types)\n if (paragraphEntries.length > 0) {\n parts.push('// ─── Paragraph schemas ───────────────────────────────────────────────────────')\n parts.push('')\n for (const [, paragraphType] of paragraphEntries) {\n parts.push(generateParagraphSchemaDecl(paragraphType, registry))\n }\n parts.push('')\n }\n\n const contentEntries = Object.entries(registry.content_types)\n if (contentEntries.length > 0) {\n parts.push('// ─── Content type schemas ────────────────────────────────────────────────────')\n parts.push('')\n for (const [, contentType] of contentEntries) {\n parts.push(generateContentSchema(contentType, registry))\n parts.push('')\n }\n }\n\n const taxonomyEntries = Object.entries(registry.taxonomy_types)\n if (taxonomyEntries.length > 0) {\n parts.push('// ─── Taxonomy type schemas ───────────────────────────────────────────────────')\n parts.push('')\n for (const [, taxonomyType] of taxonomyEntries) {\n parts.push(generateContentSchema(taxonomyType, registry))\n parts.push('')\n }\n }\n\n if (contentEntries.length > 0) {\n parts.push('// ─── Content routes ─────────────────────────────────────────────────────────')\n parts.push('')\n for (const [, contentType] of contentEntries) {\n parts.push(generateContentRoutes(contentType))\n parts.push('')\n }\n }\n\n if (taxonomyEntries.length > 0) {\n parts.push('// ─── Taxonomy routes ────────────────────────────────────────────────────────')\n parts.push('')\n for (const [, taxonomyType] of taxonomyEntries) {\n parts.push(generateTaxonomyRoutes(taxonomyType))\n parts.push('')\n }\n }\n\n return parts.join('\\n')\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/codegen/index.ts","../../src/codegen/routes.ts"],"sourcesContent":["export { generateRoutes, generateContentSchema, fieldToZodSchema } from './routes.js'\n","// generateRoutes() — pure function that returns a Hono route group from parsed schema\nimport type {\n SchemaRegistry,\n ParsedField,\n ParsedContentType,\n ParsedTaxonomyType,\n ParsedParagraphType,\n} from '@bobbykim/manguito-cms-core'\nimport { relationCardinality } from '@bobbykim/manguito-cms-core'\n\n// ─── Name helpers ─────────────────────────────────────────────────────────────\n\nfunction getSegment(machineName: string): string {\n const idx = machineName.indexOf('--')\n return idx !== -1 ? machineName.slice(idx + 2) : machineName\n}\n\nfunction toPascalCase(snakeOrKebab: string): string {\n return snakeOrKebab\n .split(/[_-]/)\n .filter(Boolean)\n .map((p) => p.charAt(0).toUpperCase() + p.slice(1))\n .join('')\n}\n\nfunction schemaVar(machineName: string): string {\n return toPascalCase(getSegment(machineName)) + 'Schema'\n}\n\nfunction routeVar(prefix: string, machineName: string, suffix: string): string {\n return `${prefix}${toPascalCase(getSegment(machineName))}${suffix}Route`\n}\n\n// Convert Hono :param notation to OpenAPI {param} notation\nfunction openApiPath(honoPath: string): string {\n return honoPath.replace(/:([^/]+)/g, '{$1}')\n}\n\n// ─── Field → Zod type string ──────────────────────────────────────────────────\n\nexport function fieldToZodSchema(field: ParsedField, registry?: SchemaRegistry): string {\n const { field_type, validation } = field\n\n switch (field_type) {\n case 'text/plain': {\n let s = 'z.string()'\n if (validation.limit !== undefined) s += `.max(${validation.limit})`\n if (validation.pattern !== undefined) s += `.regex(new RegExp(${JSON.stringify(validation.pattern)}))`\n return s\n }\n\n case 'text/rich':\n return 'z.string()'\n\n case 'integer': {\n let s = 'z.number().int()'\n if (validation.min !== undefined) s += `.min(${validation.min})`\n if (validation.max !== undefined) s += `.max(${validation.max})`\n return s\n }\n\n case 'float': {\n let s = 'z.number()'\n if (validation.min !== undefined) s += `.min(${validation.min})`\n if (validation.max !== undefined) s += `.max(${validation.max})`\n return s\n }\n\n case 'boolean':\n return 'z.boolean()'\n\n case 'date':\n return 'z.string().datetime()'\n\n case 'image': {\n const fields = [\n 'id: z.string().uuid()',\n 'url: z.string().url()',\n 'mime_type: z.string()',\n 'alt: z.string().optional()',\n 'file_size: z.number().int()',\n 'width: z.number().int().optional()',\n 'height: z.number().int().optional()',\n ]\n return `z.object({ ${fields.join(', ')} })`\n }\n\n case 'video': {\n const fields = [\n 'id: z.string().uuid()',\n 'url: z.string().url()',\n 'mime_type: z.string()',\n 'alt: z.string().optional()',\n 'file_size: z.number().int()',\n 'width: z.number().int().optional()',\n 'height: z.number().int().optional()',\n 'duration: z.number().optional()',\n ]\n return `z.object({ ${fields.join(', ')} })`\n }\n\n case 'file': {\n const fields = [\n 'id: z.string().uuid()',\n 'url: z.string().url()',\n 'mime_type: z.string()',\n 'alt: z.string().optional()',\n 'file_size: z.number().int()',\n ]\n return `z.object({ ${fields.join(', ')} })`\n }\n\n case 'enum': {\n const values = validation.allowed_values ?? []\n if (values.length === 0) return 'z.string()'\n const quoted = values.map((v) => JSON.stringify(v)).join(', ')\n return `z.enum([${quoted}])`\n }\n\n case 'paragraph': {\n const ui = field.ui_component\n if (ui.component !== 'paragraph-embed') return 'z.unknown()'\n const paragraphType = registry?.paragraph_types[ui.ref]\n if (!paragraphType) return 'z.unknown()'\n const inner = generateParagraphObjectSchema(paragraphType, registry)\n return relationCardinality(field) === 'many' ? `z.array(${inner})` : inner\n }\n\n case 'reference': {\n const ui = field.ui_component\n if (ui.component !== 'typeahead-select') return 'z.string().uuid()'\n return relationCardinality(field) === 'many' ? 'z.array(z.string().uuid())' : 'z.string().uuid()'\n }\n\n default:\n return 'z.unknown()'\n }\n}\n\n// Generates inline z.object({...}) for a paragraph type — used recursively inside fieldToZodSchema\nfunction generateParagraphObjectSchema(\n paragraph: ParsedParagraphType,\n registry?: SchemaRegistry\n): string {\n const entries = paragraph.fields.map((f) => {\n const zodType = fieldToZodSchema(f, registry)\n return `${f.name}: ${f.required ? zodType : `${zodType}.optional()`}`\n })\n if (entries.length === 0) return 'z.object({})'\n return `z.object({ ${entries.join(', ')} })`\n}\n\n// ─── Schema declaration generators ───────────────────────────────────────────\n\nfunction systemFieldEntries(schema: ParsedContentType | ParsedTaxonomyType): string[] {\n const entries: string[] = ['id: z.string().uuid()']\n if (schema.schema_type === 'content-type' && !schema.only_one) {\n entries.push('slug: z.string()')\n }\n entries.push('published: z.boolean()')\n entries.push('created_at: z.string().datetime()')\n entries.push('updated_at: z.string().datetime()')\n return entries\n}\n\nfunction schemaFieldEntries(\n fields: ParsedField[],\n registry?: SchemaRegistry\n): string[] {\n return fields.map((f) => {\n const zodType = fieldToZodSchema(f, registry)\n return ` ${f.name}: ${f.required ? zodType : `${zodType}.optional()`}`\n })\n}\n\nexport function generateContentSchema(\n schema: ParsedContentType | ParsedTaxonomyType,\n registry?: SchemaRegistry\n): string {\n const name = schemaVar(schema.name)\n const sysEntries = systemFieldEntries(schema).map((e) => ` ${e}`)\n const fieldEntries = schemaFieldEntries(schema.fields, registry)\n const allEntries = [...sysEntries, ...fieldEntries]\n return `const ${name} = z.object({\\n${allEntries.join(',\\n')},\\n})`\n}\n\n// Internal: paragraph schema const declaration (not exported but emitted into generated file)\nfunction generateParagraphSchemaDecl(\n paragraph: ParsedParagraphType,\n registry?: SchemaRegistry\n): string {\n const name = schemaVar(paragraph.name)\n const inner = generateParagraphObjectSchema(paragraph, registry)\n return `const ${name} = ${inner}`\n}\n\n// ─── Shared schemas block ─────────────────────────────────────────────────────\n\nconst SHARED_SCHEMAS_BLOCK = `const ErrorResponseSchema = z.object({\n ok: z.literal(false),\n error: z.object({\n code: z.string(),\n message: z.string(),\n details: z.unknown().optional(),\n }),\n})\n\nfunction listResponseSchema<T extends z.ZodTypeAny>(dataSchema: T) {\n return z.object({\n ok: z.literal(true),\n data: z.array(dataSchema),\n meta: z.object({\n total: z.number().int(),\n page: z.number().int(),\n per_page: z.number().int(),\n total_pages: z.number().int(),\n has_next: z.boolean(),\n has_prev: z.boolean(),\n }),\n })\n}\n\nfunction itemResponseSchema<T extends z.ZodTypeAny>(dataSchema: T) {\n return z.object({\n ok: z.literal(true),\n data: dataSchema,\n })\n}`\n\n// ─── Query param schema strings ───────────────────────────────────────────────\n\nconst PUBLIC_LIST_QUERY = `z.object({\n page: z.coerce.number().int().min(1).default(1),\n per_page: z.coerce.number().int().min(1).max(100).default(10),\n include: z.string().optional().describe('Comma-separated relation field names to expand'),\n sort_by: z.enum(['title', 'created_at', 'updated_at']).optional().default('created_at'),\n sort_order: z.enum(['asc', 'desc']).optional().default('asc'),\n })`\n\nconst ADMIN_LIST_QUERY = `z.object({\n page: z.coerce.number().int().min(1).default(1),\n per_page: z.coerce.number().int().min(1).max(100).default(10),\n include: z.string().optional().describe('Comma-separated relation field names to expand'),\n sort_by: z.enum(['title', 'created_at', 'updated_at']).optional().default('created_at'),\n sort_order: z.enum(['asc', 'desc']).optional().default('asc'),\n published: z.enum(['true', 'false']).optional().describe('Filter by published state'),\n })`\n\nconst SLUG_PARAMS = `z.object({ slug: z.string() })`\nconst ID_PARAMS = `z.object({ id: z.string().uuid() })`\nconst INCLUDE_QUERY = `z.object({ include: z.string().optional().describe('Comma-separated relation field names to expand') })`\n\n// ─── Content route generators ─────────────────────────────────────────────────\n\nfunction generateContentRoutes(contentType: ParsedContentType): string {\n const sVar = schemaVar(contentType.name)\n const label = contentType.label\n const tag = label\n const lines: string[] = []\n\n if (!contentType.only_one) {\n const collPath = contentType.api.collection_path!\n const itemPath = contentType.api.item_path\n\n // Public — GET list\n lines.push(\n `export const ${routeVar('get', contentType.name, 'List')} = createRoute({\n method: 'get',\n path: '${collPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n query: ${PUBLIC_LIST_QUERY},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: listResponseSchema(${sVar}) } },\n description: 'List of ${label}',\n },\n 400: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Invalid query parameters',\n },\n },\n})`\n )\n\n // Public — GET single by slug\n lines.push(\n `export const ${routeVar('get', contentType.name, '')} = createRoute({\n method: 'get',\n path: '${openApiPath(itemPath)}',\n tags: [${JSON.stringify(tag)}],\n request: {\n params: ${SLUG_PARAMS},\n query: ${INCLUDE_QUERY},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label}',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n },\n})`\n )\n\n // Admin — GET list\n const adminCollPath = '/admin' + collPath\n const adminItemPath = adminCollPath + '/{id}'\n lines.push(\n `export const ${routeVar('adminGet', contentType.name, 'List')} = createRoute({\n method: 'get',\n path: '${adminCollPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n query: ${ADMIN_LIST_QUERY},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: listResponseSchema(${sVar}) } },\n description: 'List of ${label}',\n },\n 400: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Invalid query parameters',\n },\n },\n})`\n )\n\n // Admin — GET single by id\n lines.push(\n `export const ${routeVar('adminGet', contentType.name, '')} = createRoute({\n method: 'get',\n path: '${adminItemPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n params: ${ID_PARAMS},\n query: ${INCLUDE_QUERY},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label}',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n },\n})`\n )\n\n // Admin — POST\n lines.push(\n `export const ${routeVar('adminCreate', contentType.name, '')} = createRoute({\n method: 'post',\n path: '${adminCollPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n body: {\n content: { 'application/json': { schema: ${sVar} } },\n },\n },\n responses: {\n 201: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label} created',\n },\n 422: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Validation error',\n },\n },\n})`\n )\n\n // Admin — PATCH\n lines.push(\n `export const ${routeVar('adminUpdate', contentType.name, '')} = createRoute({\n method: 'patch',\n path: '${adminItemPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n params: ${ID_PARAMS},\n body: {\n content: { 'application/json': { schema: ${sVar}.partial().extend({ published: z.boolean().optional() }) } },\n },\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label} updated',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n 422: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Validation error',\n },\n },\n})`\n )\n\n // Admin — DELETE\n lines.push(\n `export const ${routeVar('adminDelete', contentType.name, '')} = createRoute({\n method: 'delete',\n path: '${adminItemPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n params: ${ID_PARAMS},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: z.object({ ok: z.literal(true) }) } },\n description: '${label} deleted',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n },\n})`\n )\n } else {\n // only_one: true — no list, no slug, fixed paths\n const itemPath = contentType.api.item_path\n const adminItemBase = '/admin' + itemPath\n const adminPatchPath = '/admin/api/' + contentType.default_base_path + '/{id}'\n\n // Public — GET singleton\n lines.push(\n `export const ${routeVar('get', contentType.name, '')} = createRoute({\n method: 'get',\n path: '${itemPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n query: ${INCLUDE_QUERY},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label}',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n },\n})`\n )\n\n // Admin — GET singleton\n lines.push(\n `export const ${routeVar('adminGet', contentType.name, '')} = createRoute({\n method: 'get',\n path: '${adminItemBase}',\n tags: [${JSON.stringify(tag)}],\n request: {\n query: ${INCLUDE_QUERY},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label}',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n },\n})`\n )\n\n // Admin — POST (create singleton)\n const adminPostPath = '/admin/api/' + contentType.default_base_path\n lines.push(\n `export const ${routeVar('adminCreate', contentType.name, '')} = createRoute({\n method: 'post',\n path: '${adminPostPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n body: {\n content: { 'application/json': { schema: ${sVar} } },\n },\n },\n responses: {\n 201: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label} created',\n },\n 409: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Singleton already exists',\n },\n 422: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Validation error',\n },\n },\n})`\n )\n\n // Admin — PATCH\n lines.push(\n `export const ${routeVar('adminUpdate', contentType.name, '')} = createRoute({\n method: 'patch',\n path: '${adminPatchPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n params: ${ID_PARAMS},\n body: {\n content: { 'application/json': { schema: ${sVar}.partial().extend({ published: z.boolean().optional() }) } },\n },\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label} updated',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n 422: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Validation error',\n },\n },\n})`\n )\n }\n\n return lines.join('\\n\\n')\n}\n\n// ─── Taxonomy route generators ────────────────────────────────────────────────\n\nfunction generateTaxonomyRoutes(taxonomyType: ParsedTaxonomyType): string {\n const sVar = schemaVar(taxonomyType.name)\n const label = taxonomyType.label\n const tag = label\n const collPath = taxonomyType.api.collection_path\n const itemPath = taxonomyType.api.item_path\n const adminCollPath = '/admin' + collPath\n const adminItemPath = '/admin' + openApiPath(itemPath)\n const lines: string[] = []\n\n // Public — GET list\n lines.push(\n `export const ${routeVar('get', taxonomyType.name, 'List')} = createRoute({\n method: 'get',\n path: '${collPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n query: ${PUBLIC_LIST_QUERY},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: listResponseSchema(${sVar}) } },\n description: 'List of ${label}',\n },\n 400: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Invalid query parameters',\n },\n },\n})`\n )\n\n // Public — GET single by id\n lines.push(\n `export const ${routeVar('get', taxonomyType.name, '')} = createRoute({\n method: 'get',\n path: '${openApiPath(itemPath)}',\n tags: [${JSON.stringify(tag)}],\n request: {\n params: ${ID_PARAMS},\n query: ${INCLUDE_QUERY},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label}',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n },\n})`\n )\n\n // Admin — GET list\n lines.push(\n `export const ${routeVar('adminGet', taxonomyType.name, 'List')} = createRoute({\n method: 'get',\n path: '${adminCollPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n query: ${ADMIN_LIST_QUERY},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: listResponseSchema(${sVar}) } },\n description: 'List of ${label}',\n },\n 400: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Invalid query parameters',\n },\n },\n})`\n )\n\n // Admin — GET single by id\n lines.push(\n `export const ${routeVar('adminGet', taxonomyType.name, '')} = createRoute({\n method: 'get',\n path: '${adminItemPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n params: ${ID_PARAMS},\n query: ${INCLUDE_QUERY},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label}',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n },\n})`\n )\n\n // Admin — POST\n lines.push(\n `export const ${routeVar('adminCreate', taxonomyType.name, '')} = createRoute({\n method: 'post',\n path: '${adminCollPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n body: {\n content: { 'application/json': { schema: ${sVar} } },\n },\n },\n responses: {\n 201: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label} created',\n },\n 422: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Validation error',\n },\n },\n})`\n )\n\n // Admin — PATCH\n lines.push(\n `export const ${routeVar('adminUpdate', taxonomyType.name, '')} = createRoute({\n method: 'patch',\n path: '${adminItemPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n params: ${ID_PARAMS},\n body: {\n content: { 'application/json': { schema: ${sVar}.partial().extend({ published: z.boolean().optional() }) } },\n },\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label} updated',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n 422: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Validation error',\n },\n },\n})`\n )\n\n // Admin — DELETE\n lines.push(\n `export const ${routeVar('adminDelete', taxonomyType.name, '')} = createRoute({\n method: 'delete',\n path: '${adminItemPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n params: ${ID_PARAMS},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: z.object({ ok: z.literal(true) }) } },\n description: '${label} deleted',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n },\n})`\n )\n\n return lines.join('\\n\\n')\n}\n\n// ─── generateRoutes ───────────────────────────────────────────────────────────\n\nexport function generateRoutes(registry: SchemaRegistry): string {\n const parts: string[] = []\n\n parts.push('// Auto-generated by generateRoutes() — do not hand-edit')\n parts.push(\"import { createRoute, z } from '@hono/zod-openapi'\")\n parts.push('')\n parts.push('// ─── Shared schemas ──────────────────────────────────────────────────────────')\n parts.push('')\n parts.push(SHARED_SCHEMAS_BLOCK)\n parts.push('')\n\n const paragraphEntries = Object.entries(registry.paragraph_types)\n if (paragraphEntries.length > 0) {\n parts.push('// ─── Paragraph schemas ───────────────────────────────────────────────────────')\n parts.push('')\n for (const [, paragraphType] of paragraphEntries) {\n parts.push(generateParagraphSchemaDecl(paragraphType, registry))\n }\n parts.push('')\n }\n\n const contentEntries = Object.entries(registry.content_types)\n if (contentEntries.length > 0) {\n parts.push('// ─── Content type schemas ────────────────────────────────────────────────────')\n parts.push('')\n for (const [, contentType] of contentEntries) {\n parts.push(generateContentSchema(contentType, registry))\n parts.push('')\n }\n }\n\n const taxonomyEntries = Object.entries(registry.taxonomy_types)\n if (taxonomyEntries.length > 0) {\n parts.push('// ─── Taxonomy type schemas ───────────────────────────────────────────────────')\n parts.push('')\n for (const [, taxonomyType] of taxonomyEntries) {\n parts.push(generateContentSchema(taxonomyType, registry))\n parts.push('')\n }\n }\n\n if (contentEntries.length > 0) {\n parts.push('// ─── Content routes ─────────────────────────────────────────────────────────')\n parts.push('')\n for (const [, contentType] of contentEntries) {\n parts.push(generateContentRoutes(contentType))\n parts.push('')\n }\n }\n\n if (taxonomyEntries.length > 0) {\n parts.push('// ─── Taxonomy routes ────────────────────────────────────────────────────────')\n parts.push('')\n for (const [, taxonomyType] of taxonomyEntries) {\n parts.push(generateTaxonomyRoutes(taxonomyType))\n parts.push('')\n }\n }\n\n return parts.join('\\n')\n}\n"],"mappings":"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","names":[]}
@@ -1,4 +1,5 @@
1
1
  // src/codegen/routes.ts
2
+ import { relationCardinality } from "@bobbykim/manguito-cms-core";
2
3
  function getSegment(machineName) {
3
4
  const idx = machineName.indexOf("--");
4
5
  return idx !== -1 ? machineName.slice(idx + 2) : machineName;
@@ -89,12 +90,12 @@ function fieldToZodSchema(field, registry) {
89
90
  const paragraphType = registry?.paragraph_types[ui.ref];
90
91
  if (!paragraphType) return "z.unknown()";
91
92
  const inner = generateParagraphObjectSchema(paragraphType, registry);
92
- return ui.rel === "one-to-many" ? `z.array(${inner})` : inner;
93
+ return relationCardinality(field) === "many" ? `z.array(${inner})` : inner;
93
94
  }
94
95
  case "reference": {
95
96
  const ui = field.ui_component;
96
97
  if (ui.component !== "typeahead-select") return "z.string().uuid()";
97
- return ui.rel === "one-to-many" ? "z.array(z.string().uuid())" : "z.string().uuid()";
98
+ return relationCardinality(field) === "many" ? "z.array(z.string().uuid())" : "z.string().uuid()";
98
99
  }
99
100
  default:
100
101
  return "z.unknown()";
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/codegen/routes.ts"],"sourcesContent":["// generateRoutes() — pure function that returns a Hono route group from parsed schema\nimport type {\n SchemaRegistry,\n ParsedField,\n ParsedContentType,\n ParsedTaxonomyType,\n ParsedParagraphType,\n} from '@bobbykim/manguito-cms-core'\n\n// ─── Name helpers ─────────────────────────────────────────────────────────────\n\nfunction getSegment(machineName: string): string {\n const idx = machineName.indexOf('--')\n return idx !== -1 ? machineName.slice(idx + 2) : machineName\n}\n\nfunction toPascalCase(snakeOrKebab: string): string {\n return snakeOrKebab\n .split(/[_-]/)\n .filter(Boolean)\n .map((p) => p.charAt(0).toUpperCase() + p.slice(1))\n .join('')\n}\n\nfunction schemaVar(machineName: string): string {\n return toPascalCase(getSegment(machineName)) + 'Schema'\n}\n\nfunction routeVar(prefix: string, machineName: string, suffix: string): string {\n return `${prefix}${toPascalCase(getSegment(machineName))}${suffix}Route`\n}\n\n// Convert Hono :param notation to OpenAPI {param} notation\nfunction openApiPath(honoPath: string): string {\n return honoPath.replace(/:([^/]+)/g, '{$1}')\n}\n\n// ─── Field → Zod type string ──────────────────────────────────────────────────\n\nexport function fieldToZodSchema(field: ParsedField, registry?: SchemaRegistry): string {\n const { field_type, validation } = field\n\n switch (field_type) {\n case 'text/plain': {\n let s = 'z.string()'\n if (validation.limit !== undefined) s += `.max(${validation.limit})`\n if (validation.pattern !== undefined) s += `.regex(new RegExp(${JSON.stringify(validation.pattern)}))`\n return s\n }\n\n case 'text/rich':\n return 'z.string()'\n\n case 'integer': {\n let s = 'z.number().int()'\n if (validation.min !== undefined) s += `.min(${validation.min})`\n if (validation.max !== undefined) s += `.max(${validation.max})`\n return s\n }\n\n case 'float': {\n let s = 'z.number()'\n if (validation.min !== undefined) s += `.min(${validation.min})`\n if (validation.max !== undefined) s += `.max(${validation.max})`\n return s\n }\n\n case 'boolean':\n return 'z.boolean()'\n\n case 'date':\n return 'z.string().datetime()'\n\n case 'image': {\n const fields = [\n 'id: z.string().uuid()',\n 'url: z.string().url()',\n 'mime_type: z.string()',\n 'alt: z.string().optional()',\n 'file_size: z.number().int()',\n 'width: z.number().int().optional()',\n 'height: z.number().int().optional()',\n ]\n return `z.object({ ${fields.join(', ')} })`\n }\n\n case 'video': {\n const fields = [\n 'id: z.string().uuid()',\n 'url: z.string().url()',\n 'mime_type: z.string()',\n 'alt: z.string().optional()',\n 'file_size: z.number().int()',\n 'width: z.number().int().optional()',\n 'height: z.number().int().optional()',\n 'duration: z.number().optional()',\n ]\n return `z.object({ ${fields.join(', ')} })`\n }\n\n case 'file': {\n const fields = [\n 'id: z.string().uuid()',\n 'url: z.string().url()',\n 'mime_type: z.string()',\n 'alt: z.string().optional()',\n 'file_size: z.number().int()',\n ]\n return `z.object({ ${fields.join(', ')} })`\n }\n\n case 'enum': {\n const values = validation.allowed_values ?? []\n if (values.length === 0) return 'z.string()'\n const quoted = values.map((v) => JSON.stringify(v)).join(', ')\n return `z.enum([${quoted}])`\n }\n\n case 'paragraph': {\n const ui = field.ui_component\n if (ui.component !== 'paragraph-embed') return 'z.unknown()'\n const paragraphType = registry?.paragraph_types[ui.ref]\n if (!paragraphType) return 'z.unknown()'\n const inner = generateParagraphObjectSchema(paragraphType, registry)\n return ui.rel === 'one-to-many' ? `z.array(${inner})` : inner\n }\n\n case 'reference': {\n const ui = field.ui_component\n if (ui.component !== 'typeahead-select') return 'z.string().uuid()'\n return ui.rel === 'one-to-many' ? 'z.array(z.string().uuid())' : 'z.string().uuid()'\n }\n\n default:\n return 'z.unknown()'\n }\n}\n\n// Generates inline z.object({...}) for a paragraph type — used recursively inside fieldToZodSchema\nfunction generateParagraphObjectSchema(\n paragraph: ParsedParagraphType,\n registry?: SchemaRegistry\n): string {\n const entries = paragraph.fields.map((f) => {\n const zodType = fieldToZodSchema(f, registry)\n return `${f.name}: ${f.required ? zodType : `${zodType}.optional()`}`\n })\n if (entries.length === 0) return 'z.object({})'\n return `z.object({ ${entries.join(', ')} })`\n}\n\n// ─── Schema declaration generators ───────────────────────────────────────────\n\nfunction systemFieldEntries(schema: ParsedContentType | ParsedTaxonomyType): string[] {\n const entries: string[] = ['id: z.string().uuid()']\n if (schema.schema_type === 'content-type' && !schema.only_one) {\n entries.push('slug: z.string()')\n }\n entries.push('published: z.boolean()')\n entries.push('created_at: z.string().datetime()')\n entries.push('updated_at: z.string().datetime()')\n return entries\n}\n\nfunction schemaFieldEntries(\n fields: ParsedField[],\n registry?: SchemaRegistry\n): string[] {\n return fields.map((f) => {\n const zodType = fieldToZodSchema(f, registry)\n return ` ${f.name}: ${f.required ? zodType : `${zodType}.optional()`}`\n })\n}\n\nexport function generateContentSchema(\n schema: ParsedContentType | ParsedTaxonomyType,\n registry?: SchemaRegistry\n): string {\n const name = schemaVar(schema.name)\n const sysEntries = systemFieldEntries(schema).map((e) => ` ${e}`)\n const fieldEntries = schemaFieldEntries(schema.fields, registry)\n const allEntries = [...sysEntries, ...fieldEntries]\n return `const ${name} = z.object({\\n${allEntries.join(',\\n')},\\n})`\n}\n\n// Internal: paragraph schema const declaration (not exported but emitted into generated file)\nfunction generateParagraphSchemaDecl(\n paragraph: ParsedParagraphType,\n registry?: SchemaRegistry\n): string {\n const name = schemaVar(paragraph.name)\n const inner = generateParagraphObjectSchema(paragraph, registry)\n return `const ${name} = ${inner}`\n}\n\n// ─── Shared schemas block ─────────────────────────────────────────────────────\n\nconst SHARED_SCHEMAS_BLOCK = `const ErrorResponseSchema = z.object({\n ok: z.literal(false),\n error: z.object({\n code: z.string(),\n message: z.string(),\n details: z.unknown().optional(),\n }),\n})\n\nfunction listResponseSchema<T extends z.ZodTypeAny>(dataSchema: T) {\n return z.object({\n ok: z.literal(true),\n data: z.array(dataSchema),\n meta: z.object({\n total: z.number().int(),\n page: z.number().int(),\n per_page: z.number().int(),\n total_pages: z.number().int(),\n has_next: z.boolean(),\n has_prev: z.boolean(),\n }),\n })\n}\n\nfunction itemResponseSchema<T extends z.ZodTypeAny>(dataSchema: T) {\n return z.object({\n ok: z.literal(true),\n data: dataSchema,\n })\n}`\n\n// ─── Query param schema strings ───────────────────────────────────────────────\n\nconst PUBLIC_LIST_QUERY = `z.object({\n page: z.coerce.number().int().min(1).default(1),\n per_page: z.coerce.number().int().min(1).max(100).default(10),\n include: z.string().optional().describe('Comma-separated relation field names to expand'),\n sort_by: z.enum(['title', 'created_at', 'updated_at']).optional().default('created_at'),\n sort_order: z.enum(['asc', 'desc']).optional().default('asc'),\n })`\n\nconst ADMIN_LIST_QUERY = `z.object({\n page: z.coerce.number().int().min(1).default(1),\n per_page: z.coerce.number().int().min(1).max(100).default(10),\n include: z.string().optional().describe('Comma-separated relation field names to expand'),\n sort_by: z.enum(['title', 'created_at', 'updated_at']).optional().default('created_at'),\n sort_order: z.enum(['asc', 'desc']).optional().default('asc'),\n published: z.enum(['true', 'false']).optional().describe('Filter by published state'),\n })`\n\nconst SLUG_PARAMS = `z.object({ slug: z.string() })`\nconst ID_PARAMS = `z.object({ id: z.string().uuid() })`\nconst INCLUDE_QUERY = `z.object({ include: z.string().optional().describe('Comma-separated relation field names to expand') })`\n\n// ─── Content route generators ─────────────────────────────────────────────────\n\nfunction generateContentRoutes(contentType: ParsedContentType): string {\n const sVar = schemaVar(contentType.name)\n const label = contentType.label\n const tag = label\n const lines: string[] = []\n\n if (!contentType.only_one) {\n const collPath = contentType.api.collection_path!\n const itemPath = contentType.api.item_path\n\n // Public — GET list\n lines.push(\n `export const ${routeVar('get', contentType.name, 'List')} = createRoute({\n method: 'get',\n path: '${collPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n query: ${PUBLIC_LIST_QUERY},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: listResponseSchema(${sVar}) } },\n description: 'List of ${label}',\n },\n 400: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Invalid query parameters',\n },\n },\n})`\n )\n\n // Public — GET single by slug\n lines.push(\n `export const ${routeVar('get', contentType.name, '')} = createRoute({\n method: 'get',\n path: '${openApiPath(itemPath)}',\n tags: [${JSON.stringify(tag)}],\n request: {\n params: ${SLUG_PARAMS},\n query: ${INCLUDE_QUERY},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label}',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n },\n})`\n )\n\n // Admin — GET list\n const adminCollPath = '/admin' + collPath\n const adminItemPath = adminCollPath + '/{id}'\n lines.push(\n `export const ${routeVar('adminGet', contentType.name, 'List')} = createRoute({\n method: 'get',\n path: '${adminCollPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n query: ${ADMIN_LIST_QUERY},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: listResponseSchema(${sVar}) } },\n description: 'List of ${label}',\n },\n 400: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Invalid query parameters',\n },\n },\n})`\n )\n\n // Admin — GET single by id\n lines.push(\n `export const ${routeVar('adminGet', contentType.name, '')} = createRoute({\n method: 'get',\n path: '${adminItemPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n params: ${ID_PARAMS},\n query: ${INCLUDE_QUERY},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label}',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n },\n})`\n )\n\n // Admin — POST\n lines.push(\n `export const ${routeVar('adminCreate', contentType.name, '')} = createRoute({\n method: 'post',\n path: '${adminCollPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n body: {\n content: { 'application/json': { schema: ${sVar} } },\n },\n },\n responses: {\n 201: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label} created',\n },\n 422: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Validation error',\n },\n },\n})`\n )\n\n // Admin — PATCH\n lines.push(\n `export const ${routeVar('adminUpdate', contentType.name, '')} = createRoute({\n method: 'patch',\n path: '${adminItemPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n params: ${ID_PARAMS},\n body: {\n content: { 'application/json': { schema: ${sVar}.partial().extend({ published: z.boolean().optional() }) } },\n },\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label} updated',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n 422: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Validation error',\n },\n },\n})`\n )\n\n // Admin — DELETE\n lines.push(\n `export const ${routeVar('adminDelete', contentType.name, '')} = createRoute({\n method: 'delete',\n path: '${adminItemPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n params: ${ID_PARAMS},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: z.object({ ok: z.literal(true) }) } },\n description: '${label} deleted',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n },\n})`\n )\n } else {\n // only_one: true — no list, no slug, fixed paths\n const itemPath = contentType.api.item_path\n const adminItemBase = '/admin' + itemPath\n const adminPatchPath = '/admin/api/' + contentType.default_base_path + '/{id}'\n\n // Public — GET singleton\n lines.push(\n `export const ${routeVar('get', contentType.name, '')} = createRoute({\n method: 'get',\n path: '${itemPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n query: ${INCLUDE_QUERY},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label}',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n },\n})`\n )\n\n // Admin — GET singleton\n lines.push(\n `export const ${routeVar('adminGet', contentType.name, '')} = createRoute({\n method: 'get',\n path: '${adminItemBase}',\n tags: [${JSON.stringify(tag)}],\n request: {\n query: ${INCLUDE_QUERY},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label}',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n },\n})`\n )\n\n // Admin — POST (create singleton)\n const adminPostPath = '/admin/api/' + contentType.default_base_path\n lines.push(\n `export const ${routeVar('adminCreate', contentType.name, '')} = createRoute({\n method: 'post',\n path: '${adminPostPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n body: {\n content: { 'application/json': { schema: ${sVar} } },\n },\n },\n responses: {\n 201: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label} created',\n },\n 409: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Singleton already exists',\n },\n 422: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Validation error',\n },\n },\n})`\n )\n\n // Admin — PATCH\n lines.push(\n `export const ${routeVar('adminUpdate', contentType.name, '')} = createRoute({\n method: 'patch',\n path: '${adminPatchPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n params: ${ID_PARAMS},\n body: {\n content: { 'application/json': { schema: ${sVar}.partial().extend({ published: z.boolean().optional() }) } },\n },\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label} updated',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n 422: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Validation error',\n },\n },\n})`\n )\n }\n\n return lines.join('\\n\\n')\n}\n\n// ─── Taxonomy route generators ────────────────────────────────────────────────\n\nfunction generateTaxonomyRoutes(taxonomyType: ParsedTaxonomyType): string {\n const sVar = schemaVar(taxonomyType.name)\n const label = taxonomyType.label\n const tag = label\n const collPath = taxonomyType.api.collection_path\n const itemPath = taxonomyType.api.item_path\n const adminCollPath = '/admin' + collPath\n const adminItemPath = '/admin' + openApiPath(itemPath)\n const lines: string[] = []\n\n // Public — GET list\n lines.push(\n `export const ${routeVar('get', taxonomyType.name, 'List')} = createRoute({\n method: 'get',\n path: '${collPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n query: ${PUBLIC_LIST_QUERY},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: listResponseSchema(${sVar}) } },\n description: 'List of ${label}',\n },\n 400: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Invalid query parameters',\n },\n },\n})`\n )\n\n // Public — GET single by id\n lines.push(\n `export const ${routeVar('get', taxonomyType.name, '')} = createRoute({\n method: 'get',\n path: '${openApiPath(itemPath)}',\n tags: [${JSON.stringify(tag)}],\n request: {\n params: ${ID_PARAMS},\n query: ${INCLUDE_QUERY},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label}',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n },\n})`\n )\n\n // Admin — GET list\n lines.push(\n `export const ${routeVar('adminGet', taxonomyType.name, 'List')} = createRoute({\n method: 'get',\n path: '${adminCollPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n query: ${ADMIN_LIST_QUERY},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: listResponseSchema(${sVar}) } },\n description: 'List of ${label}',\n },\n 400: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Invalid query parameters',\n },\n },\n})`\n )\n\n // Admin — GET single by id\n lines.push(\n `export const ${routeVar('adminGet', taxonomyType.name, '')} = createRoute({\n method: 'get',\n path: '${adminItemPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n params: ${ID_PARAMS},\n query: ${INCLUDE_QUERY},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label}',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n },\n})`\n )\n\n // Admin — POST\n lines.push(\n `export const ${routeVar('adminCreate', taxonomyType.name, '')} = createRoute({\n method: 'post',\n path: '${adminCollPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n body: {\n content: { 'application/json': { schema: ${sVar} } },\n },\n },\n responses: {\n 201: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label} created',\n },\n 422: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Validation error',\n },\n },\n})`\n )\n\n // Admin — PATCH\n lines.push(\n `export const ${routeVar('adminUpdate', taxonomyType.name, '')} = createRoute({\n method: 'patch',\n path: '${adminItemPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n params: ${ID_PARAMS},\n body: {\n content: { 'application/json': { schema: ${sVar}.partial().extend({ published: z.boolean().optional() }) } },\n },\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label} updated',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n 422: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Validation error',\n },\n },\n})`\n )\n\n // Admin — DELETE\n lines.push(\n `export const ${routeVar('adminDelete', taxonomyType.name, '')} = createRoute({\n method: 'delete',\n path: '${adminItemPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n params: ${ID_PARAMS},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: z.object({ ok: z.literal(true) }) } },\n description: '${label} deleted',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n },\n})`\n )\n\n return lines.join('\\n\\n')\n}\n\n// ─── generateRoutes ───────────────────────────────────────────────────────────\n\nexport function generateRoutes(registry: SchemaRegistry): string {\n const parts: string[] = []\n\n parts.push('// Auto-generated by generateRoutes() — do not hand-edit')\n parts.push(\"import { createRoute, z } from '@hono/zod-openapi'\")\n parts.push('')\n parts.push('// ─── Shared schemas ──────────────────────────────────────────────────────────')\n parts.push('')\n parts.push(SHARED_SCHEMAS_BLOCK)\n parts.push('')\n\n const paragraphEntries = Object.entries(registry.paragraph_types)\n if (paragraphEntries.length > 0) {\n parts.push('// ─── Paragraph schemas ───────────────────────────────────────────────────────')\n parts.push('')\n for (const [, paragraphType] of paragraphEntries) {\n parts.push(generateParagraphSchemaDecl(paragraphType, registry))\n }\n parts.push('')\n }\n\n const contentEntries = Object.entries(registry.content_types)\n if (contentEntries.length > 0) {\n parts.push('// ─── Content type schemas ────────────────────────────────────────────────────')\n parts.push('')\n for (const [, contentType] of contentEntries) {\n parts.push(generateContentSchema(contentType, registry))\n parts.push('')\n }\n }\n\n const taxonomyEntries = Object.entries(registry.taxonomy_types)\n if (taxonomyEntries.length > 0) {\n parts.push('// ─── Taxonomy type schemas ───────────────────────────────────────────────────')\n parts.push('')\n for (const [, taxonomyType] of taxonomyEntries) {\n parts.push(generateContentSchema(taxonomyType, registry))\n parts.push('')\n }\n }\n\n if (contentEntries.length > 0) {\n parts.push('// ─── Content routes ─────────────────────────────────────────────────────────')\n parts.push('')\n for (const [, contentType] of contentEntries) {\n parts.push(generateContentRoutes(contentType))\n parts.push('')\n }\n }\n\n if (taxonomyEntries.length > 0) {\n parts.push('// ─── Taxonomy routes ────────────────────────────────────────────────────────')\n parts.push('')\n for (const [, taxonomyType] of taxonomyEntries) {\n parts.push(generateTaxonomyRoutes(taxonomyType))\n parts.push('')\n }\n }\n\n return parts.join('\\n')\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/codegen/routes.ts"],"sourcesContent":["// generateRoutes() — pure function that returns a Hono route group from parsed schema\nimport type {\n SchemaRegistry,\n ParsedField,\n ParsedContentType,\n ParsedTaxonomyType,\n ParsedParagraphType,\n} from '@bobbykim/manguito-cms-core'\nimport { relationCardinality } from '@bobbykim/manguito-cms-core'\n\n// ─── Name helpers ─────────────────────────────────────────────────────────────\n\nfunction getSegment(machineName: string): string {\n const idx = machineName.indexOf('--')\n return idx !== -1 ? machineName.slice(idx + 2) : machineName\n}\n\nfunction toPascalCase(snakeOrKebab: string): string {\n return snakeOrKebab\n .split(/[_-]/)\n .filter(Boolean)\n .map((p) => p.charAt(0).toUpperCase() + p.slice(1))\n .join('')\n}\n\nfunction schemaVar(machineName: string): string {\n return toPascalCase(getSegment(machineName)) + 'Schema'\n}\n\nfunction routeVar(prefix: string, machineName: string, suffix: string): string {\n return `${prefix}${toPascalCase(getSegment(machineName))}${suffix}Route`\n}\n\n// Convert Hono :param notation to OpenAPI {param} notation\nfunction openApiPath(honoPath: string): string {\n return honoPath.replace(/:([^/]+)/g, '{$1}')\n}\n\n// ─── Field → Zod type string ──────────────────────────────────────────────────\n\nexport function fieldToZodSchema(field: ParsedField, registry?: SchemaRegistry): string {\n const { field_type, validation } = field\n\n switch (field_type) {\n case 'text/plain': {\n let s = 'z.string()'\n if (validation.limit !== undefined) s += `.max(${validation.limit})`\n if (validation.pattern !== undefined) s += `.regex(new RegExp(${JSON.stringify(validation.pattern)}))`\n return s\n }\n\n case 'text/rich':\n return 'z.string()'\n\n case 'integer': {\n let s = 'z.number().int()'\n if (validation.min !== undefined) s += `.min(${validation.min})`\n if (validation.max !== undefined) s += `.max(${validation.max})`\n return s\n }\n\n case 'float': {\n let s = 'z.number()'\n if (validation.min !== undefined) s += `.min(${validation.min})`\n if (validation.max !== undefined) s += `.max(${validation.max})`\n return s\n }\n\n case 'boolean':\n return 'z.boolean()'\n\n case 'date':\n return 'z.string().datetime()'\n\n case 'image': {\n const fields = [\n 'id: z.string().uuid()',\n 'url: z.string().url()',\n 'mime_type: z.string()',\n 'alt: z.string().optional()',\n 'file_size: z.number().int()',\n 'width: z.number().int().optional()',\n 'height: z.number().int().optional()',\n ]\n return `z.object({ ${fields.join(', ')} })`\n }\n\n case 'video': {\n const fields = [\n 'id: z.string().uuid()',\n 'url: z.string().url()',\n 'mime_type: z.string()',\n 'alt: z.string().optional()',\n 'file_size: z.number().int()',\n 'width: z.number().int().optional()',\n 'height: z.number().int().optional()',\n 'duration: z.number().optional()',\n ]\n return `z.object({ ${fields.join(', ')} })`\n }\n\n case 'file': {\n const fields = [\n 'id: z.string().uuid()',\n 'url: z.string().url()',\n 'mime_type: z.string()',\n 'alt: z.string().optional()',\n 'file_size: z.number().int()',\n ]\n return `z.object({ ${fields.join(', ')} })`\n }\n\n case 'enum': {\n const values = validation.allowed_values ?? []\n if (values.length === 0) return 'z.string()'\n const quoted = values.map((v) => JSON.stringify(v)).join(', ')\n return `z.enum([${quoted}])`\n }\n\n case 'paragraph': {\n const ui = field.ui_component\n if (ui.component !== 'paragraph-embed') return 'z.unknown()'\n const paragraphType = registry?.paragraph_types[ui.ref]\n if (!paragraphType) return 'z.unknown()'\n const inner = generateParagraphObjectSchema(paragraphType, registry)\n return relationCardinality(field) === 'many' ? `z.array(${inner})` : inner\n }\n\n case 'reference': {\n const ui = field.ui_component\n if (ui.component !== 'typeahead-select') return 'z.string().uuid()'\n return relationCardinality(field) === 'many' ? 'z.array(z.string().uuid())' : 'z.string().uuid()'\n }\n\n default:\n return 'z.unknown()'\n }\n}\n\n// Generates inline z.object({...}) for a paragraph type — used recursively inside fieldToZodSchema\nfunction generateParagraphObjectSchema(\n paragraph: ParsedParagraphType,\n registry?: SchemaRegistry\n): string {\n const entries = paragraph.fields.map((f) => {\n const zodType = fieldToZodSchema(f, registry)\n return `${f.name}: ${f.required ? zodType : `${zodType}.optional()`}`\n })\n if (entries.length === 0) return 'z.object({})'\n return `z.object({ ${entries.join(', ')} })`\n}\n\n// ─── Schema declaration generators ───────────────────────────────────────────\n\nfunction systemFieldEntries(schema: ParsedContentType | ParsedTaxonomyType): string[] {\n const entries: string[] = ['id: z.string().uuid()']\n if (schema.schema_type === 'content-type' && !schema.only_one) {\n entries.push('slug: z.string()')\n }\n entries.push('published: z.boolean()')\n entries.push('created_at: z.string().datetime()')\n entries.push('updated_at: z.string().datetime()')\n return entries\n}\n\nfunction schemaFieldEntries(\n fields: ParsedField[],\n registry?: SchemaRegistry\n): string[] {\n return fields.map((f) => {\n const zodType = fieldToZodSchema(f, registry)\n return ` ${f.name}: ${f.required ? zodType : `${zodType}.optional()`}`\n })\n}\n\nexport function generateContentSchema(\n schema: ParsedContentType | ParsedTaxonomyType,\n registry?: SchemaRegistry\n): string {\n const name = schemaVar(schema.name)\n const sysEntries = systemFieldEntries(schema).map((e) => ` ${e}`)\n const fieldEntries = schemaFieldEntries(schema.fields, registry)\n const allEntries = [...sysEntries, ...fieldEntries]\n return `const ${name} = z.object({\\n${allEntries.join(',\\n')},\\n})`\n}\n\n// Internal: paragraph schema const declaration (not exported but emitted into generated file)\nfunction generateParagraphSchemaDecl(\n paragraph: ParsedParagraphType,\n registry?: SchemaRegistry\n): string {\n const name = schemaVar(paragraph.name)\n const inner = generateParagraphObjectSchema(paragraph, registry)\n return `const ${name} = ${inner}`\n}\n\n// ─── Shared schemas block ─────────────────────────────────────────────────────\n\nconst SHARED_SCHEMAS_BLOCK = `const ErrorResponseSchema = z.object({\n ok: z.literal(false),\n error: z.object({\n code: z.string(),\n message: z.string(),\n details: z.unknown().optional(),\n }),\n})\n\nfunction listResponseSchema<T extends z.ZodTypeAny>(dataSchema: T) {\n return z.object({\n ok: z.literal(true),\n data: z.array(dataSchema),\n meta: z.object({\n total: z.number().int(),\n page: z.number().int(),\n per_page: z.number().int(),\n total_pages: z.number().int(),\n has_next: z.boolean(),\n has_prev: z.boolean(),\n }),\n })\n}\n\nfunction itemResponseSchema<T extends z.ZodTypeAny>(dataSchema: T) {\n return z.object({\n ok: z.literal(true),\n data: dataSchema,\n })\n}`\n\n// ─── Query param schema strings ───────────────────────────────────────────────\n\nconst PUBLIC_LIST_QUERY = `z.object({\n page: z.coerce.number().int().min(1).default(1),\n per_page: z.coerce.number().int().min(1).max(100).default(10),\n include: z.string().optional().describe('Comma-separated relation field names to expand'),\n sort_by: z.enum(['title', 'created_at', 'updated_at']).optional().default('created_at'),\n sort_order: z.enum(['asc', 'desc']).optional().default('asc'),\n })`\n\nconst ADMIN_LIST_QUERY = `z.object({\n page: z.coerce.number().int().min(1).default(1),\n per_page: z.coerce.number().int().min(1).max(100).default(10),\n include: z.string().optional().describe('Comma-separated relation field names to expand'),\n sort_by: z.enum(['title', 'created_at', 'updated_at']).optional().default('created_at'),\n sort_order: z.enum(['asc', 'desc']).optional().default('asc'),\n published: z.enum(['true', 'false']).optional().describe('Filter by published state'),\n })`\n\nconst SLUG_PARAMS = `z.object({ slug: z.string() })`\nconst ID_PARAMS = `z.object({ id: z.string().uuid() })`\nconst INCLUDE_QUERY = `z.object({ include: z.string().optional().describe('Comma-separated relation field names to expand') })`\n\n// ─── Content route generators ─────────────────────────────────────────────────\n\nfunction generateContentRoutes(contentType: ParsedContentType): string {\n const sVar = schemaVar(contentType.name)\n const label = contentType.label\n const tag = label\n const lines: string[] = []\n\n if (!contentType.only_one) {\n const collPath = contentType.api.collection_path!\n const itemPath = contentType.api.item_path\n\n // Public — GET list\n lines.push(\n `export const ${routeVar('get', contentType.name, 'List')} = createRoute({\n method: 'get',\n path: '${collPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n query: ${PUBLIC_LIST_QUERY},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: listResponseSchema(${sVar}) } },\n description: 'List of ${label}',\n },\n 400: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Invalid query parameters',\n },\n },\n})`\n )\n\n // Public — GET single by slug\n lines.push(\n `export const ${routeVar('get', contentType.name, '')} = createRoute({\n method: 'get',\n path: '${openApiPath(itemPath)}',\n tags: [${JSON.stringify(tag)}],\n request: {\n params: ${SLUG_PARAMS},\n query: ${INCLUDE_QUERY},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label}',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n },\n})`\n )\n\n // Admin — GET list\n const adminCollPath = '/admin' + collPath\n const adminItemPath = adminCollPath + '/{id}'\n lines.push(\n `export const ${routeVar('adminGet', contentType.name, 'List')} = createRoute({\n method: 'get',\n path: '${adminCollPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n query: ${ADMIN_LIST_QUERY},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: listResponseSchema(${sVar}) } },\n description: 'List of ${label}',\n },\n 400: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Invalid query parameters',\n },\n },\n})`\n )\n\n // Admin — GET single by id\n lines.push(\n `export const ${routeVar('adminGet', contentType.name, '')} = createRoute({\n method: 'get',\n path: '${adminItemPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n params: ${ID_PARAMS},\n query: ${INCLUDE_QUERY},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label}',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n },\n})`\n )\n\n // Admin — POST\n lines.push(\n `export const ${routeVar('adminCreate', contentType.name, '')} = createRoute({\n method: 'post',\n path: '${adminCollPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n body: {\n content: { 'application/json': { schema: ${sVar} } },\n },\n },\n responses: {\n 201: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label} created',\n },\n 422: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Validation error',\n },\n },\n})`\n )\n\n // Admin — PATCH\n lines.push(\n `export const ${routeVar('adminUpdate', contentType.name, '')} = createRoute({\n method: 'patch',\n path: '${adminItemPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n params: ${ID_PARAMS},\n body: {\n content: { 'application/json': { schema: ${sVar}.partial().extend({ published: z.boolean().optional() }) } },\n },\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label} updated',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n 422: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Validation error',\n },\n },\n})`\n )\n\n // Admin — DELETE\n lines.push(\n `export const ${routeVar('adminDelete', contentType.name, '')} = createRoute({\n method: 'delete',\n path: '${adminItemPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n params: ${ID_PARAMS},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: z.object({ ok: z.literal(true) }) } },\n description: '${label} deleted',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n },\n})`\n )\n } else {\n // only_one: true — no list, no slug, fixed paths\n const itemPath = contentType.api.item_path\n const adminItemBase = '/admin' + itemPath\n const adminPatchPath = '/admin/api/' + contentType.default_base_path + '/{id}'\n\n // Public — GET singleton\n lines.push(\n `export const ${routeVar('get', contentType.name, '')} = createRoute({\n method: 'get',\n path: '${itemPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n query: ${INCLUDE_QUERY},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label}',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n },\n})`\n )\n\n // Admin — GET singleton\n lines.push(\n `export const ${routeVar('adminGet', contentType.name, '')} = createRoute({\n method: 'get',\n path: '${adminItemBase}',\n tags: [${JSON.stringify(tag)}],\n request: {\n query: ${INCLUDE_QUERY},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label}',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n },\n})`\n )\n\n // Admin — POST (create singleton)\n const adminPostPath = '/admin/api/' + contentType.default_base_path\n lines.push(\n `export const ${routeVar('adminCreate', contentType.name, '')} = createRoute({\n method: 'post',\n path: '${adminPostPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n body: {\n content: { 'application/json': { schema: ${sVar} } },\n },\n },\n responses: {\n 201: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label} created',\n },\n 409: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Singleton already exists',\n },\n 422: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Validation error',\n },\n },\n})`\n )\n\n // Admin — PATCH\n lines.push(\n `export const ${routeVar('adminUpdate', contentType.name, '')} = createRoute({\n method: 'patch',\n path: '${adminPatchPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n params: ${ID_PARAMS},\n body: {\n content: { 'application/json': { schema: ${sVar}.partial().extend({ published: z.boolean().optional() }) } },\n },\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label} updated',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n 422: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Validation error',\n },\n },\n})`\n )\n }\n\n return lines.join('\\n\\n')\n}\n\n// ─── Taxonomy route generators ────────────────────────────────────────────────\n\nfunction generateTaxonomyRoutes(taxonomyType: ParsedTaxonomyType): string {\n const sVar = schemaVar(taxonomyType.name)\n const label = taxonomyType.label\n const tag = label\n const collPath = taxonomyType.api.collection_path\n const itemPath = taxonomyType.api.item_path\n const adminCollPath = '/admin' + collPath\n const adminItemPath = '/admin' + openApiPath(itemPath)\n const lines: string[] = []\n\n // Public — GET list\n lines.push(\n `export const ${routeVar('get', taxonomyType.name, 'List')} = createRoute({\n method: 'get',\n path: '${collPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n query: ${PUBLIC_LIST_QUERY},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: listResponseSchema(${sVar}) } },\n description: 'List of ${label}',\n },\n 400: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Invalid query parameters',\n },\n },\n})`\n )\n\n // Public — GET single by id\n lines.push(\n `export const ${routeVar('get', taxonomyType.name, '')} = createRoute({\n method: 'get',\n path: '${openApiPath(itemPath)}',\n tags: [${JSON.stringify(tag)}],\n request: {\n params: ${ID_PARAMS},\n query: ${INCLUDE_QUERY},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label}',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n },\n})`\n )\n\n // Admin — GET list\n lines.push(\n `export const ${routeVar('adminGet', taxonomyType.name, 'List')} = createRoute({\n method: 'get',\n path: '${adminCollPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n query: ${ADMIN_LIST_QUERY},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: listResponseSchema(${sVar}) } },\n description: 'List of ${label}',\n },\n 400: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Invalid query parameters',\n },\n },\n})`\n )\n\n // Admin — GET single by id\n lines.push(\n `export const ${routeVar('adminGet', taxonomyType.name, '')} = createRoute({\n method: 'get',\n path: '${adminItemPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n params: ${ID_PARAMS},\n query: ${INCLUDE_QUERY},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label}',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n },\n})`\n )\n\n // Admin — POST\n lines.push(\n `export const ${routeVar('adminCreate', taxonomyType.name, '')} = createRoute({\n method: 'post',\n path: '${adminCollPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n body: {\n content: { 'application/json': { schema: ${sVar} } },\n },\n },\n responses: {\n 201: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label} created',\n },\n 422: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Validation error',\n },\n },\n})`\n )\n\n // Admin — PATCH\n lines.push(\n `export const ${routeVar('adminUpdate', taxonomyType.name, '')} = createRoute({\n method: 'patch',\n path: '${adminItemPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n params: ${ID_PARAMS},\n body: {\n content: { 'application/json': { schema: ${sVar}.partial().extend({ published: z.boolean().optional() }) } },\n },\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: itemResponseSchema(${sVar}) } },\n description: '${label} updated',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n 422: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: 'Validation error',\n },\n },\n})`\n )\n\n // Admin — DELETE\n lines.push(\n `export const ${routeVar('adminDelete', taxonomyType.name, '')} = createRoute({\n method: 'delete',\n path: '${adminItemPath}',\n tags: [${JSON.stringify(tag)}],\n request: {\n params: ${ID_PARAMS},\n },\n responses: {\n 200: {\n content: { 'application/json': { schema: z.object({ ok: z.literal(true) }) } },\n description: '${label} deleted',\n },\n 404: {\n content: { 'application/json': { schema: ErrorResponseSchema } },\n description: '${label} not found',\n },\n },\n})`\n )\n\n return lines.join('\\n\\n')\n}\n\n// ─── generateRoutes ───────────────────────────────────────────────────────────\n\nexport function generateRoutes(registry: SchemaRegistry): string {\n const parts: string[] = []\n\n parts.push('// Auto-generated by generateRoutes() — do not hand-edit')\n parts.push(\"import { createRoute, z } from '@hono/zod-openapi'\")\n parts.push('')\n parts.push('// ─── Shared schemas ──────────────────────────────────────────────────────────')\n parts.push('')\n parts.push(SHARED_SCHEMAS_BLOCK)\n parts.push('')\n\n const paragraphEntries = Object.entries(registry.paragraph_types)\n if (paragraphEntries.length > 0) {\n parts.push('// ─── Paragraph schemas ───────────────────────────────────────────────────────')\n parts.push('')\n for (const [, paragraphType] of paragraphEntries) {\n parts.push(generateParagraphSchemaDecl(paragraphType, registry))\n }\n parts.push('')\n }\n\n const contentEntries = Object.entries(registry.content_types)\n if (contentEntries.length > 0) {\n parts.push('// ─── Content type schemas ────────────────────────────────────────────────────')\n parts.push('')\n for (const [, contentType] of contentEntries) {\n parts.push(generateContentSchema(contentType, registry))\n parts.push('')\n }\n }\n\n const taxonomyEntries = Object.entries(registry.taxonomy_types)\n if (taxonomyEntries.length > 0) {\n parts.push('// ─── Taxonomy type schemas ───────────────────────────────────────────────────')\n parts.push('')\n for (const [, taxonomyType] of taxonomyEntries) {\n parts.push(generateContentSchema(taxonomyType, registry))\n parts.push('')\n }\n }\n\n if (contentEntries.length > 0) {\n parts.push('// ─── Content routes ─────────────────────────────────────────────────────────')\n parts.push('')\n for (const [, contentType] of contentEntries) {\n parts.push(generateContentRoutes(contentType))\n parts.push('')\n }\n }\n\n if (taxonomyEntries.length > 0) {\n parts.push('// ─── Taxonomy routes ────────────────────────────────────────────────────────')\n parts.push('')\n for (const [, taxonomyType] of taxonomyEntries) {\n parts.push(generateTaxonomyRoutes(taxonomyType))\n parts.push('')\n }\n }\n\n return parts.join('\\n')\n}\n"],"mappings":"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","names":[]}
@@ -39,6 +39,7 @@ var import_graphql_yoga = require("graphql-yoga");
39
39
 
40
40
  // src/graphql/schema.ts
41
41
  var import_graphql5 = require("graphql");
42
+ var import_manguito_cms_core = require("@bobbykim/manguito-cms-core");
42
43
 
43
44
  // src/graphql/scalars.ts
44
45
  var import_graphql = require("graphql");
@@ -398,7 +399,8 @@ function buildGraphQLSchema(registry, fieldKeyMaps = {}, view, programmaticKeyMa
398
399
  `
399
400
  );
400
401
  }
401
- return new import_graphql5.GraphQLList(new import_graphql5.GraphQLNonNull(target ?? MEDIA));
402
+ const t = target ?? MEDIA;
403
+ return (0, import_manguito_cms_core.relationCardinality)(field) === "one" ? t : new import_graphql5.GraphQLList(new import_graphql5.GraphQLNonNull(t));
402
404
  }
403
405
  if (field.field_type === "reference") {
404
406
  const ref = field.ui_component.component === "typeahead-select" ? field.ui_component.ref : void 0;
@@ -407,8 +409,7 @@ function buildGraphQLSchema(registry, fieldKeyMaps = {}, view, programmaticKeyMa
407
409
  process.stderr.write(`\u26A0 reference field '${field.name}' targets unknown type '${ref}'; exposing as Media
408
410
  `);
409
411
  }
410
- const rel = field.ui_component.component === "typeahead-select" ? field.ui_component.rel : void 0;
411
- const isMany = rel === "many-to-many" || rel === "one-to-many";
412
+ const isMany = (0, import_manguito_cms_core.relationCardinality)(field) === "many";
412
413
  const t = target ?? MEDIA;
413
414
  return isMany ? new import_graphql5.GraphQLList(new import_graphql5.GraphQLNonNull(t)) : t;
414
415
  }
@@ -621,10 +622,14 @@ var import_dataloader = __toESM(require("dataloader"));
621
622
  // src/relations.ts
622
623
  var import_node_crypto = __toESM(require("crypto"));
623
624
  var import_drizzle_orm = require("drizzle-orm");
625
+ var import_manguito_cms_core2 = require("@bobbykim/manguito-cms-core");
624
626
  function quoteIdent(name) {
625
627
  if (!/^[a-z][a-z0-9_-]*$/.test(name)) throw new Error(`Unsafe identifier: ${name}`);
626
628
  return `"${name}"`;
627
629
  }
630
+ function oneOrMany(cardinality, list) {
631
+ return cardinality === "one" ? list[0] ?? null : list;
632
+ }
628
633
  function buildRelationsMap(fields, registry) {
629
634
  const relations = {};
630
635
  for (const field of fields) {
@@ -635,7 +640,11 @@ function buildRelationsMap(fields, registry) {
635
640
  const ref = field.ui_component.ref;
636
641
  const pType = ref ? registry.paragraph_types[ref] : void 0;
637
642
  if (!pType) continue;
638
- relations[field.name] = { type: "paragraph", table: pType.db.table_name };
643
+ relations[field.name] = {
644
+ type: "paragraph",
645
+ table: pType.db.table_name,
646
+ cardinality: (0, import_manguito_cms_core2.relationCardinality)(field) ?? "many"
647
+ };
639
648
  } else if (field.field_type === "reference") {
640
649
  if (!field.db_column) continue;
641
650
  if (field.db_column.junction) {
@@ -683,7 +692,7 @@ async function resolveRelationField(db, rows, fieldName, rel, cache, publishedOn
683
692
  );
684
693
  const byParent = groupBy(result.rows, "parent_id");
685
694
  for (const row of batch) {
686
- row[fieldName] = byParent[row["id"]] ?? [];
695
+ row[fieldName] = oneOrMany(rel.cardinality, byParent[row["id"]] ?? []);
687
696
  }
688
697
  } else if (rel.type === "reference") {
689
698
  const pending = batch.filter((r) => needsFkResolution(r, rel.fk_column));