octocms 0.1.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.
Files changed (64) hide show
  1. package/dist/agentDocs-Z5BI2Y2G.js +38 -0
  2. package/dist/agentDocs-Z5BI2Y2G.js.map +1 -0
  3. package/dist/chunk-4MPOTHTY.js +9 -0
  4. package/dist/chunk-4MPOTHTY.js.map +1 -0
  5. package/dist/chunk-4VLN5EX2.js +9204 -0
  6. package/dist/chunk-4VLN5EX2.js.map +1 -0
  7. package/dist/chunk-6PHFHGTZ.js +35 -0
  8. package/dist/chunk-6PHFHGTZ.js.map +1 -0
  9. package/dist/chunk-7CFFE2I6.js +55 -0
  10. package/dist/chunk-7CFFE2I6.js.map +1 -0
  11. package/dist/chunk-B47VXAHT.js +28 -0
  12. package/dist/chunk-B47VXAHT.js.map +1 -0
  13. package/dist/chunk-BRTXBBVQ.js +46 -0
  14. package/dist/chunk-BRTXBBVQ.js.map +1 -0
  15. package/dist/chunk-C62C776U.js +79 -0
  16. package/dist/chunk-C62C776U.js.map +1 -0
  17. package/dist/chunk-I7KNSICQ.js +114 -0
  18. package/dist/chunk-I7KNSICQ.js.map +1 -0
  19. package/dist/chunk-Q73JSGXV.js +123 -0
  20. package/dist/chunk-Q73JSGXV.js.map +1 -0
  21. package/dist/chunk-W6QJTGBC.js +57 -0
  22. package/dist/chunk-W6QJTGBC.js.map +1 -0
  23. package/dist/cli/index.js +196 -0
  24. package/dist/cli/index.js.map +1 -0
  25. package/dist/components/public/index.d.mts +40 -0
  26. package/dist/components/public/index.js +401 -0
  27. package/dist/components/public/index.js.map +1 -0
  28. package/dist/config.d.mts +4 -0
  29. package/dist/config.js +13 -0
  30. package/dist/config.js.map +1 -0
  31. package/dist/defineConfig.d.mts +126 -0
  32. package/dist/defineConfig.js +8 -0
  33. package/dist/defineConfig.js.map +1 -0
  34. package/dist/dev-QY534GEH.js +87 -0
  35. package/dist/dev-QY534GEH.js.map +1 -0
  36. package/dist/index.d.mts +5 -0
  37. package/dist/index.js +17 -0
  38. package/dist/index.js.map +1 -0
  39. package/dist/init-UGUTJFFI.js +145 -0
  40. package/dist/init-UGUTJFFI.js.map +1 -0
  41. package/dist/jiti-VYEW7A6R.js +3068 -0
  42. package/dist/jiti-VYEW7A6R.js.map +1 -0
  43. package/dist/localReader-I2THES24.js +40 -0
  44. package/dist/localReader-I2THES24.js.map +1 -0
  45. package/dist/query.d.mts +112 -0
  46. package/dist/query.js +11 -0
  47. package/dist/query.js.map +1 -0
  48. package/dist/types.d.mts +352 -0
  49. package/dist/types.js +1 -0
  50. package/dist/types.js.map +1 -0
  51. package/dist/typesGen-WBC6CNBG.js +241 -0
  52. package/dist/typesGen-WBC6CNBG.js.map +1 -0
  53. package/dist/update-RMGZMS56.js +57 -0
  54. package/dist/update-RMGZMS56.js.map +1 -0
  55. package/dist/validate-OTJ6ULMP.js +297 -0
  56. package/dist/validate-OTJ6ULMP.js.map +1 -0
  57. package/dist/withOctoCMS.d.mts +6 -0
  58. package/dist/withOctoCMS.js +9 -0
  59. package/dist/withOctoCMS.js.map +1 -0
  60. package/docs/index.md +27 -0
  61. package/docs/overview.md +113 -0
  62. package/docs/schema.md +279 -0
  63. package/globals.css +198 -0
  64. package/package.json +116 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../components/public/MarkdownContent.tsx","../../../lib/utils.ts","../../../components/public/RichTextContent.tsx","../../../components/public/SearchBox.tsx"],"sourcesContent":["import React from 'react';\n\nimport Markdown from 'react-markdown';\nimport rehypeSanitize, { defaultSchema } from 'rehype-sanitize';\nimport remarkGfm from 'remark-gfm';\n\nimport { cn } from '../../lib/utils';\n\n/**\n * Sanitization schema: extends the default GitHub-flavoured schema with\n * the same tag/attribute allowlist that was previously applied via sanitize-html.\n */\nconst sanitizeSchema = {\n ...defaultSchema,\n tagNames: [\n ...(defaultSchema.tagNames ?? []),\n 'u', // underline — not in GitHub default\n ],\n attributes: {\n ...defaultSchema.attributes,\n code: [...(defaultSchema.attributes?.code ?? []), 'className'],\n img: ['src', 'alt', 'title'],\n },\n};\n\ntype MarkdownContentProps = {\n children: string | undefined | null;\n className?: string;\n};\n\n/**\n * Renders raw Markdown as React elements using react-markdown with GFM support\n * and HTML sanitization. Replaces the previous `dangerouslySetInnerHTML` approach.\n */\nconst MarkdownContent = ({ children, className }: MarkdownContentProps) => {\n if (!children) {\n return null;\n }\n\n return (\n <div className={cn(className)}>\n <Markdown remarkPlugins={[remarkGfm]} rehypePlugins={[[rehypeSanitize, sanitizeSchema]]}>\n {children}\n </Markdown>\n </div>\n );\n};\n\nexport default MarkdownContent;\n","import { type ClassValue, clsx } from 'clsx';\nimport { twMerge } from 'tailwind-merge';\n\n/**\n * Merge Tailwind classes with clsx — the standard utility for Radix UI + Tailwind components.\n * Handles conditional classes, deduplication, and conflict resolution.\n *\n * @example\n * cn('px-4 py-2', isActive && 'bg-primary text-primary-foreground', className)\n */\nexport const cn = (...inputs: ClassValue[]) => twMerge(clsx(inputs));\n","import React from 'react';\nimport Image from 'next/image';\n\nimport type { RichTextDocument, RichTextNode, ResolvedImageField } from '../../types';\nimport { cn } from '../../lib/utils';\n\ntype RichTextContentProps = {\n document: RichTextDocument | null | undefined;\n /** Map custom component names to React components for rendering `{ type: 'component' }` nodes. */\n components?: Record<string, React.ComponentType<any>>;\n /** Variable substitutions for `{ type: 'variable' }` nodes. */\n variables?: Record<string, string>;\n /** Condition branch selections: map condition field names to the branch key to render. */\n conditions?: Record<string, string>;\n className?: string;\n};\n\n/**\n * Renders a `RichTextDocument` AST to React elements.\n *\n * Standard markdown nodes become HTML elements.\n * `CmsImage` embeds render as `next/image`.\n * Custom components and variables are resolved from the provided props.\n */\nconst RichTextContent = ({ document, components, variables, conditions, className }: RichTextContentProps) => {\n if (!document || !document.content?.length) return null;\n return (\n <div className={cn(className)}>\n {document.content.map((node, i) => (\n <RenderNode key={i} node={node} components={components} variables={variables} conditions={conditions} />\n ))}\n </div>\n );\n};\n\nexport default RichTextContent;\n\n// ---------------------------------------------------------------------------\n// Internal node renderer\n// ---------------------------------------------------------------------------\n\ntype NodeProps = {\n node: RichTextNode;\n components?: Record<string, React.ComponentType<any>>;\n variables?: Record<string, string>;\n conditions?: Record<string, string>;\n};\n\nfunction RenderNode({ node, components, variables, conditions }: NodeProps) {\n switch (node.type) {\n case 'paragraph':\n return (\n <p>\n <RenderChildren nodes={node.children} components={components} variables={variables} conditions={conditions} />\n </p>\n );\n\n case 'heading': {\n const Tag = `h${node.level}` as 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';\n return (\n <Tag>\n <RenderChildren nodes={node.children} components={components} variables={variables} conditions={conditions} />\n </Tag>\n );\n }\n\n case 'blockquote':\n return (\n <blockquote>\n <RenderChildren nodes={node.children} components={components} variables={variables} conditions={conditions} />\n </blockquote>\n );\n\n case 'list':\n if (node.ordered) {\n return (\n <ol>\n <RenderChildren\n nodes={node.children}\n components={components}\n variables={variables}\n conditions={conditions}\n />\n </ol>\n );\n }\n return (\n <ul>\n <RenderChildren nodes={node.children} components={components} variables={variables} conditions={conditions} />\n </ul>\n );\n\n case 'listItem':\n return (\n <li>\n <RenderChildren nodes={node.children} components={components} variables={variables} conditions={conditions} />\n </li>\n );\n\n case 'thematicBreak':\n return <hr />;\n\n case 'code':\n return (\n <pre>\n <code className={node.lang ? `language-${node.lang}` : undefined}>{node.value}</code>\n </pre>\n );\n\n case 'text':\n return <RenderText node={node} />;\n\n case 'link':\n return (\n <a href={node.url}>\n <RenderChildren nodes={node.children} components={components} variables={variables} conditions={conditions} />\n </a>\n );\n\n case 'image':\n return <RenderImage image={node.image} />;\n\n case 'break':\n return <br />;\n\n case 'html':\n return null;\n\n case 'variable': {\n const value = variables?.[node.name];\n return <>{value ?? `{${node.name}}`}</>;\n }\n\n case 'component': {\n const Component = components?.[node.name];\n if (!Component) return null;\n return (\n <Component {...node.props}>\n {node.children?.length ? (\n <RenderChildren\n nodes={node.children}\n components={components}\n variables={variables}\n conditions={conditions}\n />\n ) : null}\n </Component>\n );\n }\n\n case 'reference':\n return <RenderReference node={node} components={components} />;\n\n case 'condition':\n return <RenderCondition node={node} components={components} variables={variables} conditions={conditions} />;\n\n default:\n return null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Inline text with marks\n// ---------------------------------------------------------------------------\n\nfunction RenderText({ node }: { node: Extract<RichTextNode, { type: 'text' }> }) {\n let element: React.ReactNode = node.value;\n if (node.marks) {\n for (const mark of node.marks) {\n switch (mark) {\n case 'bold':\n element = <strong>{element}</strong>;\n break;\n case 'italic':\n element = <em>{element}</em>;\n break;\n case 'underline':\n element = <u>{element}</u>;\n break;\n case 'code':\n element = <code>{element}</code>;\n break;\n }\n }\n }\n return <>{element}</>;\n}\n\n// ---------------------------------------------------------------------------\n// Image rendering via next/image\n// ---------------------------------------------------------------------------\n\nfunction RenderImage({ image }: { image: ResolvedImageField }) {\n if (!image.src) return null;\n\n const hasSize = image.width != null && image.height != null;\n\n if (hasSize) {\n return (\n <Image\n src={image.src}\n alt={image.alt}\n width={image.width!}\n height={image.height!}\n {...(image.blurDataURL ? { placeholder: 'blur' as const, blurDataURL: image.blurDataURL } : {})}\n />\n );\n }\n\n // Fallback for images without dimensions — use fill with a container\n return (\n <span className=\"relative block w-full\" style={{ aspectRatio: '16/9' }}>\n <Image\n src={image.src}\n alt={image.alt}\n fill\n className=\"object-cover\"\n {...(image.blurDataURL ? { placeholder: 'blur' as const, blurDataURL: image.blurDataURL } : {})}\n />\n </span>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Reference rendering — embedded entry references\n// ---------------------------------------------------------------------------\n\ntype ReferenceNode = Extract<RichTextNode, { type: 'reference' }>;\n\nfunction RenderReference({\n node,\n components,\n}: {\n node: ReferenceNode;\n components?: Record<string, React.ComponentType<any>>;\n}) {\n const entry = node.entry as { sys?: { type?: string }; fields?: Record<string, unknown> } | null;\n if (!entry) return null;\n\n const collectionType = entry.sys?.type;\n\n // If consumer provided a custom component for this collection type, use it\n if (collectionType && components?.[collectionType]) {\n const Component = components[collectionType];\n return node.display === 'inline' ? (\n <Component entry={entry} display={node.display} />\n ) : (\n <div>\n <Component entry={entry} display={node.display} />\n </div>\n );\n }\n\n // Default fallback: show the entry's title field if available\n const title = entry.fields\n ? (Object.values(entry.fields).find((v) => typeof v === 'string' && v.length > 0) as string | undefined)\n : null;\n\n if (node.display === 'inline') {\n return <span>{title ?? collectionType ?? 'Reference'}</span>;\n }\n\n return (\n <div className=\"rounded border border-border p-3 my-2 bg-muted/30\">\n {collectionType && <span className=\"text-xs text-muted-foreground block mb-0.5\">{collectionType}</span>}\n <span className=\"text-sm font-medium\">{title ?? 'Untitled entry'}</span>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Condition rendering — select and render the appropriate branch\n// ---------------------------------------------------------------------------\n\ntype ConditionNode = Extract<RichTextNode, { type: 'condition' }>;\n\nfunction RenderCondition({\n node,\n components,\n variables,\n conditions,\n}: {\n node: ConditionNode;\n components?: Record<string, React.ComponentType<any>>;\n variables?: Record<string, string>;\n conditions?: Record<string, string>;\n}) {\n const branches = node.branches;\n if (!branches || typeof branches !== 'object') return null;\n\n // If a condition selection was provided, render only the selected branch\n const selectedKey = node.field && conditions ? conditions[node.field] : undefined;\n\n if (selectedKey) {\n const doc = (branches as Record<string, RichTextDocument>)[selectedKey];\n if (!doc || !doc.content?.length) return null;\n return (\n <>\n {doc.content.map((child, i) => (\n <RenderNode key={i} node={child} components={components} variables={variables} conditions={conditions} />\n ))}\n </>\n );\n }\n\n // No condition provided — render nothing (consumer must specify which branch to show)\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Helper: render a list of child nodes\n// ---------------------------------------------------------------------------\n\nfunction RenderChildren({\n nodes,\n components,\n variables,\n conditions,\n}: { nodes: RichTextNode[] } & Pick<NodeProps, 'components' | 'variables' | 'conditions'>) {\n return (\n <>\n {nodes.map((child, i) => (\n <RenderNode key={i} node={child} components={components} variables={variables} conditions={conditions} />\n ))}\n </>\n );\n}\n","'use client';\n\nimport React, { useCallback, useEffect, useRef, useState } from 'react';\nimport { Search, X } from 'lucide-react';\n\nimport type { SearchResult } from '../../lib/searchIndex';\nimport { cn } from '../../lib/utils';\n\n/** Escape special regex characters in a string. */\nfunction escapeRegex(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/**\n * Split text into alternating non-match/match segments and wrap matches in <mark>.\n * Uses prefix matching (term\\w*) to support MiniSearch's prefix: true behavior.\n */\nfunction highlightTerms(text: string, terms: string[]): React.ReactNode {\n const filtered = terms.filter((t) => t.length > 0);\n if (filtered.length === 0) return text;\n\n const pattern = filtered.map((t) => escapeRegex(t) + '\\\\w*').join('|');\n const parts = text.split(new RegExp(`(${pattern})`, 'gi'));\n\n return parts.map((part, i) =>\n i % 2 === 1 ? (\n <mark key={i} className=\"bg-yellow-200 dark:bg-yellow-800 text-inherit rounded-sm px-0.5\">\n {part}\n </mark>\n ) : (\n part\n ),\n );\n}\n\nexport interface SearchBoxProps {\n placeholder?: string;\n className?: string;\n}\n\nexport default function SearchBox({ placeholder = 'Search...', className = '' }: SearchBoxProps) {\n const inputRef = useRef<HTMLInputElement>(null);\n const dropdownRef = useRef<HTMLDivElement>(null);\n const [query, setQuery] = useState('');\n const [results, setResults] = useState<SearchResult[]>([]);\n const [isOpen, setIsOpen] = useState(false);\n const [isSearching, setIsSearching] = useState(false);\n const [selectedIndex, setSelectedIndex] = useState(-1);\n const debounceRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n\n // Fetch search results\n const doSearch = useCallback(async (q: string) => {\n if (!q.trim()) {\n setResults([]);\n setIsOpen(false);\n setSelectedIndex(-1);\n return;\n }\n\n setIsSearching(true);\n try {\n const response = await fetch(`/api/search?q=${encodeURIComponent(q)}&limit=10`);\n if (response.ok) {\n const data = await response.json();\n setResults(data.results || []);\n setIsOpen(true);\n setSelectedIndex(-1);\n } else {\n setResults([]);\n setIsOpen(false);\n }\n } catch {\n setResults([]);\n setIsOpen(false);\n } finally {\n setIsSearching(false);\n }\n }, []);\n\n // Handle input change with debounce\n const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {\n const value = e.target.value;\n setQuery(value);\n\n if (debounceRef.current) clearTimeout(debounceRef.current);\n debounceRef.current = setTimeout(() => doSearch(value), 300);\n };\n\n // Handle keyboard navigation\n const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {\n if (!isOpen || results.length === 0) {\n return;\n }\n\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault();\n setSelectedIndex((prev) => (prev < results.length - 1 ? prev + 1 : 0));\n break;\n case 'ArrowUp':\n e.preventDefault();\n setSelectedIndex((prev) => (prev > 0 ? prev - 1 : results.length - 1));\n break;\n case 'Enter':\n e.preventDefault();\n if (selectedIndex >= 0 && results[selectedIndex]) {\n navigateToResult(results[selectedIndex]);\n }\n break;\n case 'Escape':\n e.preventDefault();\n setIsOpen(false);\n setSelectedIndex(-1);\n break;\n default:\n break;\n }\n };\n\n // Navigate to a result\n const navigateToResult = (result: SearchResult) => {\n window.location.href = result.url;\n };\n\n // Close dropdown when clicking outside\n useEffect(() => {\n const handleClickOutside = (event: MouseEvent) => {\n if (\n dropdownRef.current &&\n !dropdownRef.current.contains(event.target as Node) &&\n inputRef.current &&\n !inputRef.current.contains(event.target as Node)\n ) {\n setIsOpen(false);\n }\n };\n\n document.addEventListener('mousedown', handleClickOutside);\n return () => document.removeEventListener('mousedown', handleClickOutside);\n }, []);\n\n // Scroll selected result into view\n useEffect(() => {\n if (selectedIndex >= 0 && dropdownRef.current) {\n const items = dropdownRef.current.querySelectorAll('[data-result-item]');\n if (items[selectedIndex]) {\n items[selectedIndex].scrollIntoView({ block: 'nearest' });\n }\n }\n }, [selectedIndex]);\n\n const handleClear = () => {\n setQuery('');\n setResults([]);\n setIsOpen(false);\n setSelectedIndex(-1);\n inputRef.current?.focus();\n };\n\n return (\n <div className={cn('relative w-full', className)}>\n <div className=\"relative\">\n <Search className=\"absolute left-3 top-1/2 -translate-y-1/2 text-gray-400\" size={18} />\n <input\n ref={inputRef}\n type=\"text\"\n value={query}\n onChange={handleChange}\n onKeyDown={handleKeyDown}\n onFocus={() => {\n if (query.trim() && results.length > 0) {\n setIsOpen(true);\n }\n }}\n placeholder={placeholder}\n className={cn(\n 'w-full pl-10 pr-10 py-2 text-sm border border-gray-200 rounded-lg',\n 'bg-white text-gray-900 placeholder-gray-400',\n 'focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent',\n 'dark:bg-gray-900 dark:border-gray-700 dark:text-gray-100 dark:placeholder-gray-500',\n )}\n autoComplete=\"off\"\n />\n {query && (\n <button\n type=\"button\"\n onClick={handleClear}\n className=\"absolute right-3 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 transition-colors\"\n aria-label=\"Clear search\"\n >\n <X size={18} />\n </button>\n )}\n </div>\n\n {/* Dropdown results */}\n {isOpen && (results.length > 0 || isSearching) && (\n <div\n ref={dropdownRef}\n className={cn(\n 'absolute top-full left-0 right-0 mt-2 bg-white dark:bg-gray-900 border border-gray-200 dark:border-gray-700',\n 'rounded-lg shadow-lg z-50 max-h-96 overflow-y-auto',\n )}\n >\n {isSearching && results.length === 0 && (\n <div className=\"px-4 py-3 text-sm text-gray-500 dark:text-gray-400 text-center\">Searching...</div>\n )}\n\n {results.length > 0 && (\n <ul className=\"divide-y divide-gray-100 dark:divide-gray-800\">\n {results.map((result, index) => (\n <li\n key={result.id}\n data-result-item\n className={cn(\n 'p-0 transition-colors',\n index === selectedIndex\n ? 'bg-blue-50 dark:bg-blue-900/30'\n : 'bg-white dark:bg-gray-900 hover:bg-gray-50 dark:hover:bg-gray-800',\n )}\n >\n <button\n type=\"button\"\n onClick={() => navigateToResult(result)}\n className=\"w-full text-left px-4 py-3 flex flex-col gap-1\"\n >\n <div className=\"flex items-center justify-between gap-2\">\n <span className=\"font-medium text-gray-900 dark:text-gray-100 truncate text-sm\">\n {highlightTerms(result.title, Object.keys(result.match))}\n </span>\n <span className=\"shrink-0 text-xs text-gray-500 dark:text-gray-400 bg-gray-100 dark:bg-gray-800 px-2 py-0.5 rounded\">\n {result.typeLabel}\n </span>\n </div>\n {Object.values(result.match).flat().includes('content') && result.snippet && (\n <p className=\"text-xs text-gray-500 dark:text-gray-400 line-clamp-2 text-left\">\n {highlightTerms(result.snippet, Object.keys(result.match))}\n </p>\n )}\n </button>\n </li>\n ))}\n </ul>\n )}\n </div>\n )}\n </div>\n );\n}\n"],"mappings":"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","names":["jsx","document","_a","_b","jsx","jsxs","_a"]}
@@ -0,0 +1,4 @@
1
+ export { CollectionNames, InferEntry, InferFields, defineConfig } from './defineConfig.mjs';
2
+ export { withOctoCMS } from './withOctoCMS.mjs';
3
+ import './types.mjs';
4
+ import 'next';
package/dist/config.js ADDED
@@ -0,0 +1,13 @@
1
+ import {
2
+ defineConfig
3
+ } from "./chunk-4MPOTHTY.js";
4
+ import {
5
+ withOctoCMS
6
+ } from "./chunk-BRTXBBVQ.js";
7
+ import "./chunk-B47VXAHT.js";
8
+ import "./chunk-7CFFE2I6.js";
9
+ export {
10
+ defineConfig,
11
+ withOctoCMS
12
+ };
13
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,126 @@
1
+ import { Config, RichTextDocument, ResolvedImageField } from './types.mjs';
2
+
3
+ /**
4
+ * Define the CMS configuration with full literal type inference.
5
+ *
6
+ * Wrapping your config in `defineConfig()` preserves exact collection names,
7
+ * field names, and field formats as literal types — enabling type-safe queries
8
+ * with autocomplete in `cms/query.ts`.
9
+ *
10
+ * Use `as const` on `select` field `options` (and `defaultOptions`) so option
11
+ * `value`s infer as string literal unions in `InferFields`.
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * // cms/octocms.config.ts
16
+ * import { defineConfig } from 'octocms/defineConfig';
17
+ *
18
+ * export const config = defineConfig({
19
+ * projectName: 'My Site',
20
+ * git: { baseBranch: 'main', publishedPointerBranch: 'cms/publish-pointer' },
21
+ * collections: { post: { label: 'Post', hasMany: true, fields: { ... } } },
22
+ * // ...
23
+ * });
24
+ * ```
25
+ */
26
+ declare function defineConfig<T extends Config>(config: T): T;
27
+ /** Map a field `format` string to the runtime TypeScript type it produces after processing. */
28
+ type FieldFormatToType = {
29
+ string: string;
30
+ text: string;
31
+ markdown: string;
32
+ richtext: RichTextDocument;
33
+ boolean: 'true' | 'false';
34
+ number: number | null;
35
+ datetime: string | null;
36
+ image: ResolvedImageField;
37
+ reference: unknown;
38
+ json: unknown;
39
+ slug: string;
40
+ select: string;
41
+ url: string;
42
+ color: string;
43
+ conditional: unknown;
44
+ };
45
+ /** Union of option `value` literals when `options` is a readonly tuple. */
46
+ type OptionValues<Opts> = Opts extends ReadonlyArray<{
47
+ readonly value: infer V;
48
+ }> ? (V extends string ? V : string) : string;
49
+ /** Extract the collection names defined in a config object. */
50
+ type CollectionNames<C extends Config> = Extract<keyof C['collections'], string>;
51
+ /** Infer the resolved value type for a single field definition. */
52
+ type InferSingleFieldType<F> = F extends {
53
+ format: 'string';
54
+ list: true;
55
+ } ? string[] : F extends {
56
+ format: 'boolean';
57
+ } ? 'true' | 'false' : F extends {
58
+ format: 'select';
59
+ multiple: true;
60
+ options: infer Opts;
61
+ } ? OptionValues<Opts>[] : F extends {
62
+ format: 'select';
63
+ options: infer Opts;
64
+ } ? OptionValues<Opts> : F extends {
65
+ format: 'conditional';
66
+ conditional: {
67
+ branches: infer B;
68
+ };
69
+ } ? InferConditionalValue<B> : F extends {
70
+ format: infer Fmt;
71
+ } ? Fmt extends keyof FieldFormatToType ? FieldFormatToType[Fmt] : unknown : unknown;
72
+ /** Infer the inline fields type for a branch's fields record. */
73
+ type InferBranchInlineFields<Fields> = {
74
+ [K in Extract<keyof Fields, string>]: InferSingleFieldType<Fields[K]>;
75
+ };
76
+ /**
77
+ * Infer the value type for a single branch.
78
+ * - Inline branch (`fields`): produces an object type mapping field names to their inferred types.
79
+ * - Reference branch (`collection`): produces `unknown` (resolved at runtime to the referenced entry).
80
+ */
81
+ type InferBranchValue<B> = B extends {
82
+ fields: infer F;
83
+ } ? InferBranchInlineFields<F> : unknown;
84
+ /**
85
+ * Infer the union of all branch value types for a conditional field.
86
+ * This is the type the consumer gets after selecting a branch at query time.
87
+ */
88
+ type InferConditionalValue<Branches> = Branches extends readonly [infer Head, ...infer Tail] ? InferBranchValue<Head> | InferConditionalValue<Tail> : never;
89
+ /**
90
+ * Extract the literal union of branch `key` strings from a conditional field's branches tuple.
91
+ * Requires `as const` on the branches array in `cms/octocms.config.ts` for literal inference.
92
+ */
93
+ type InferConditionalKeys<Branches> = Branches extends readonly [infer Head, ...infer Tail] ? (Head extends {
94
+ key: infer K;
95
+ } ? (K extends string ? K : never) : never) | InferConditionalKeys<Tail> : never;
96
+ /** Infer the `fields` shape for a collection, mapping each field format to its TS type. */
97
+ type InferFields<C extends Config, Name extends CollectionNames<C>> = C['collections'][Name] extends {
98
+ fields: infer F;
99
+ } ? {
100
+ [K in Extract<keyof F, string>]: InferSingleFieldType<F[K]>;
101
+ } : Record<string, unknown>;
102
+ /** A fully-typed content entry for a given collection. */
103
+ type InferEntry<C extends Config, Name extends CollectionNames<C>> = {
104
+ sys: {
105
+ id: string;
106
+ type: Name;
107
+ };
108
+ fields: InferFields<C, Name>;
109
+ };
110
+ /**
111
+ * For a single collection, build `Record<fieldName, branchKeyUnion>` for every `format: 'conditional'` field.
112
+ * If the collection has no conditional fields this resolves to `{}` (empty object / `never` keys).
113
+ */
114
+ type InferConditions<C extends Config, Name extends CollectionNames<C>> = C['collections'][Name] extends {
115
+ fields: infer F;
116
+ } ? {
117
+ [K in Extract<keyof F, string> as F[K] extends {
118
+ format: 'conditional';
119
+ } ? K : never]: F[K] extends {
120
+ conditional: {
121
+ branches: infer B;
122
+ };
123
+ } ? InferConditionalKeys<B> : never;
124
+ } : {};
125
+
126
+ export { type CollectionNames, type FieldFormatToType, type InferConditionalKeys, type InferConditions, type InferEntry, type InferFields, defineConfig };
@@ -0,0 +1,8 @@
1
+ import {
2
+ defineConfig
3
+ } from "./chunk-4MPOTHTY.js";
4
+ import "./chunk-7CFFE2I6.js";
5
+ export {
6
+ defineConfig
7
+ };
8
+ //# sourceMappingURL=defineConfig.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,87 @@
1
+ import {
2
+ log
3
+ } from "./chunk-6PHFHGTZ.js";
4
+ import {
5
+ __spreadValues
6
+ } from "./chunk-W6QJTGBC.js";
7
+
8
+ // cli/commands/dev.ts
9
+ import { spawn } from "child_process";
10
+ import { existsSync, watch } from "fs";
11
+ import { join } from "path";
12
+ async function devCommand(projectRoot, options = {}) {
13
+ var _a;
14
+ const port = (_a = options.port) != null ? _a : 3001;
15
+ log.header("Development server");
16
+ const nextConfigPath = join(projectRoot, "next.config.ts");
17
+ const octoConfigPath = join(projectRoot, "cms", "octocms.config.ts");
18
+ if (!existsSync(nextConfigPath)) {
19
+ log.error("next.config.ts not found \u2014 run `octocms init` first.");
20
+ process.exitCode = 1;
21
+ return;
22
+ }
23
+ log.info(`Starting Next.js dev server on port ${port}...`);
24
+ log.info("Watching next.config.ts and cms/octocms.config.ts for changes...");
25
+ log.blank();
26
+ const nextBin = join(projectRoot, "node_modules", ".bin", "next");
27
+ const child = spawn(nextBin, ["dev", "-p", String(port)], {
28
+ cwd: projectRoot,
29
+ stdio: "inherit",
30
+ env: __spreadValues({}, process.env)
31
+ });
32
+ let debounceTimer = null;
33
+ const onConfigChange = () => {
34
+ if (debounceTimer) clearTimeout(debounceTimer);
35
+ debounceTimer = setTimeout(() => {
36
+ regenerateTypes(projectRoot);
37
+ }, 300);
38
+ };
39
+ const nextWatcher = watch(nextConfigPath, onConfigChange);
40
+ const octoWatcher = existsSync(octoConfigPath) ? watch(octoConfigPath, onConfigChange) : null;
41
+ const cleanup = () => {
42
+ nextWatcher.close();
43
+ octoWatcher == null ? void 0 : octoWatcher.close();
44
+ if (debounceTimer) clearTimeout(debounceTimer);
45
+ child.kill();
46
+ };
47
+ process.on("SIGINT", cleanup);
48
+ process.on("SIGTERM", cleanup);
49
+ child.on("exit", (code) => {
50
+ nextWatcher.close();
51
+ octoWatcher == null ? void 0 : octoWatcher.close();
52
+ if (debounceTimer) clearTimeout(debounceTimer);
53
+ process.exitCode = code != null ? code : 0;
54
+ });
55
+ }
56
+ function regenerateTypes(projectRoot) {
57
+ var _a;
58
+ log.blank();
59
+ log.step("Config changed \u2014 regenerating types...");
60
+ const jitiBin = join(projectRoot, "node_modules", ".bin", "jiti");
61
+ const scriptPath = join(projectRoot, "scripts", "generate-types.ts");
62
+ const child = spawn(jitiBin, [scriptPath], {
63
+ cwd: projectRoot,
64
+ stdio: "pipe"
65
+ });
66
+ let stderr = "";
67
+ (_a = child.stderr) == null ? void 0 : _a.on("data", (data) => {
68
+ stderr += data.toString();
69
+ });
70
+ child.on("exit", (code) => {
71
+ if (code === 0) {
72
+ log.success("Types regenerated");
73
+ } else {
74
+ log.error("Type generation failed:");
75
+ if (stderr.trim()) {
76
+ for (const line of stderr.trim().split("\n")) {
77
+ log.info(` ${line}`);
78
+ }
79
+ }
80
+ }
81
+ log.blank();
82
+ });
83
+ }
84
+ export {
85
+ devCommand
86
+ };
87
+ //# sourceMappingURL=dev-QY534GEH.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../cli/commands/dev.ts"],"sourcesContent":["/**\n * `octocms dev` — Start Next.js dev server with next.config.ts watching.\n *\n * Spawns `next dev` and watches the config file for changes. When the\n * config changes, types are automatically regenerated.\n */\n\nimport { spawn } from 'child_process';\nimport { existsSync, watch } from 'fs';\nimport { join } from 'path';\n\nimport { log } from '../lib/logger';\n\nexport type DevOptions = {\n port?: number;\n};\n\nexport async function devCommand(projectRoot: string, options: DevOptions = {}): Promise<void> {\n const port = options.port ?? 3001;\n\n log.header('Development server');\n\n const nextConfigPath = join(projectRoot, 'next.config.ts');\n const octoConfigPath = join(projectRoot, 'cms', 'octocms.config.ts');\n if (!existsSync(nextConfigPath)) {\n log.error('next.config.ts not found — run `octocms init` first.');\n process.exitCode = 1;\n return;\n }\n\n log.info(`Starting Next.js dev server on port ${port}...`);\n log.info('Watching next.config.ts and cms/octocms.config.ts for changes...');\n log.blank();\n\n // Spawn next dev\n const nextBin = join(projectRoot, 'node_modules', '.bin', 'next');\n const child = spawn(nextBin, ['dev', '-p', String(port)], {\n cwd: projectRoot,\n stdio: 'inherit',\n env: { ...process.env },\n });\n\n // Watch both config files for changes and regenerate types\n let debounceTimer: ReturnType<typeof setTimeout> | null = null;\n\n const onConfigChange = () => {\n if (debounceTimer) clearTimeout(debounceTimer);\n debounceTimer = setTimeout(() => {\n regenerateTypes(projectRoot);\n }, 300);\n };\n\n const nextWatcher = watch(nextConfigPath, onConfigChange);\n const octoWatcher = existsSync(octoConfigPath) ? watch(octoConfigPath, onConfigChange) : null;\n\n // Forward signals to child\n const cleanup = () => {\n nextWatcher.close();\n octoWatcher?.close();\n if (debounceTimer) clearTimeout(debounceTimer);\n child.kill();\n };\n\n process.on('SIGINT', cleanup);\n process.on('SIGTERM', cleanup);\n\n child.on('exit', (code) => {\n nextWatcher.close();\n octoWatcher?.close();\n if (debounceTimer) clearTimeout(debounceTimer);\n process.exitCode = code ?? 0;\n });\n}\n\nfunction regenerateTypes(projectRoot: string): void {\n log.blank();\n log.step('Config changed — regenerating types...');\n\n const jitiBin = join(projectRoot, 'node_modules', '.bin', 'jiti');\n const scriptPath = join(projectRoot, 'scripts', 'generate-types.ts');\n\n const child = spawn(jitiBin, [scriptPath], {\n cwd: projectRoot,\n stdio: 'pipe',\n });\n\n let stderr = '';\n child.stderr?.on('data', (data: Buffer) => {\n stderr += data.toString();\n });\n\n child.on('exit', (code) => {\n if (code === 0) {\n log.success('Types regenerated');\n } else {\n log.error('Type generation failed:');\n if (stderr.trim()) {\n for (const line of stderr.trim().split('\\n')) {\n log.info(` ${line}`);\n }\n }\n }\n log.blank();\n });\n}\n"],"mappings":";;;;;;;;AAOA,SAAS,aAAa;AACtB,SAAS,YAAY,aAAa;AAClC,SAAS,YAAY;AAQrB,eAAsB,WAAW,aAAqB,UAAsB,CAAC,GAAkB;AAjB/F;AAkBE,QAAM,QAAO,aAAQ,SAAR,YAAgB;AAE7B,MAAI,OAAO,oBAAoB;AAE/B,QAAM,iBAAiB,KAAK,aAAa,gBAAgB;AACzD,QAAM,iBAAiB,KAAK,aAAa,OAAO,mBAAmB;AACnE,MAAI,CAAC,WAAW,cAAc,GAAG;AAC/B,QAAI,MAAM,2DAAsD;AAChE,YAAQ,WAAW;AACnB;AAAA,EACF;AAEA,MAAI,KAAK,uCAAuC,IAAI,KAAK;AACzD,MAAI,KAAK,kEAAkE;AAC3E,MAAI,MAAM;AAGV,QAAM,UAAU,KAAK,aAAa,gBAAgB,QAAQ,MAAM;AAChE,QAAM,QAAQ,MAAM,SAAS,CAAC,OAAO,MAAM,OAAO,IAAI,CAAC,GAAG;AAAA,IACxD,KAAK;AAAA,IACL,OAAO;AAAA,IACP,KAAK,mBAAK,QAAQ;AAAA,EACpB,CAAC;AAGD,MAAI,gBAAsD;AAE1D,QAAM,iBAAiB,MAAM;AAC3B,QAAI,cAAe,cAAa,aAAa;AAC7C,oBAAgB,WAAW,MAAM;AAC/B,sBAAgB,WAAW;AAAA,IAC7B,GAAG,GAAG;AAAA,EACR;AAEA,QAAM,cAAc,MAAM,gBAAgB,cAAc;AACxD,QAAM,cAAc,WAAW,cAAc,IAAI,MAAM,gBAAgB,cAAc,IAAI;AAGzF,QAAM,UAAU,MAAM;AACpB,gBAAY,MAAM;AAClB,+CAAa;AACb,QAAI,cAAe,cAAa,aAAa;AAC7C,UAAM,KAAK;AAAA,EACb;AAEA,UAAQ,GAAG,UAAU,OAAO;AAC5B,UAAQ,GAAG,WAAW,OAAO;AAE7B,QAAM,GAAG,QAAQ,CAAC,SAAS;AACzB,gBAAY,MAAM;AAClB,+CAAa;AACb,QAAI,cAAe,cAAa,aAAa;AAC7C,YAAQ,WAAW,sBAAQ;AAAA,EAC7B,CAAC;AACH;AAEA,SAAS,gBAAgB,aAA2B;AA1EpD;AA2EE,MAAI,MAAM;AACV,MAAI,KAAK,6CAAwC;AAEjD,QAAM,UAAU,KAAK,aAAa,gBAAgB,QAAQ,MAAM;AAChE,QAAM,aAAa,KAAK,aAAa,WAAW,mBAAmB;AAEnE,QAAM,QAAQ,MAAM,SAAS,CAAC,UAAU,GAAG;AAAA,IACzC,KAAK;AAAA,IACL,OAAO;AAAA,EACT,CAAC;AAED,MAAI,SAAS;AACb,cAAM,WAAN,mBAAc,GAAG,QAAQ,CAAC,SAAiB;AACzC,cAAU,KAAK,SAAS;AAAA,EAC1B;AAEA,QAAM,GAAG,QAAQ,CAAC,SAAS;AACzB,QAAI,SAAS,GAAG;AACd,UAAI,QAAQ,mBAAmB;AAAA,IACjC,OAAO;AACL,UAAI,MAAM,yBAAyB;AACnC,UAAI,OAAO,KAAK,GAAG;AACjB,mBAAW,QAAQ,OAAO,KAAK,EAAE,MAAM,IAAI,GAAG;AAC5C,cAAI,KAAK,KAAK,IAAI,EAAE;AAAA,QACtB;AAAA,MACF;AAAA,IACF;AACA,QAAI,MAAM;AAAA,EACZ,CAAC;AACH;","names":[]}
@@ -0,0 +1,5 @@
1
+ export { createQuery } from './query.mjs';
2
+ export { CollectionNames, FieldFormatToType, InferConditions, InferEntry, InferFields, defineConfig } from './defineConfig.mjs';
3
+ export { withOctoCMS } from './withOctoCMS.mjs';
4
+ export { Collection, CollectionField, Config, EntryStatus, FieldFormat, GitIntegrationConfig, ReferenceFieldConfig, ResolvedImageField, RichTextDocument, RichTextNode, SearchConfig, SelectOption } from './types.mjs';
5
+ import 'next';
package/dist/index.js ADDED
@@ -0,0 +1,17 @@
1
+ import {
2
+ createQuery
3
+ } from "./chunk-4VLN5EX2.js";
4
+ import {
5
+ defineConfig
6
+ } from "./chunk-4MPOTHTY.js";
7
+ import {
8
+ withOctoCMS
9
+ } from "./chunk-BRTXBBVQ.js";
10
+ import "./chunk-B47VXAHT.js";
11
+ import "./chunk-7CFFE2I6.js";
12
+ export {
13
+ createQuery,
14
+ defineConfig,
15
+ withOctoCMS
16
+ };
17
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,145 @@
1
+ import {
2
+ adminLayoutTemplate,
3
+ adminPageTemplate,
4
+ demoPostJson,
5
+ demoPostMarkdown,
6
+ nextConfigTemplate,
7
+ octoConfigTemplate,
8
+ tsconfigPaths
9
+ } from "./chunk-I7KNSICQ.js";
10
+ import {
11
+ log
12
+ } from "./chunk-6PHFHGTZ.js";
13
+ import "./chunk-W6QJTGBC.js";
14
+
15
+ // cli/commands/init.ts
16
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
17
+ import { join } from "path";
18
+ import readline from "readline";
19
+ async function prompt(rl, question, defaultValue) {
20
+ const suffix = defaultValue ? ` (${defaultValue})` : "";
21
+ return new Promise((resolve) => {
22
+ rl.question(` ? ${question}${suffix}: `, (answer) => {
23
+ resolve(answer.trim() || defaultValue || "");
24
+ });
25
+ });
26
+ }
27
+ async function confirm(rl, question, defaultYes = false) {
28
+ const hint = defaultYes ? "Y/n" : "y/N";
29
+ const answer = await prompt(rl, `${question} (${hint})`);
30
+ if (!answer) return defaultYes;
31
+ return answer.toLowerCase().startsWith("y");
32
+ }
33
+ async function gatherAnswers(options) {
34
+ if (options.yes) {
35
+ return {
36
+ projectName: "My CMS",
37
+ baseBranch: "main",
38
+ usePointerBranch: false,
39
+ pointerBranch: ""
40
+ };
41
+ }
42
+ const rl = readline.createInterface({
43
+ input: process.stdin,
44
+ output: process.stdout
45
+ });
46
+ try {
47
+ const projectName = await prompt(rl, "Project name", "My CMS");
48
+ const baseBranch = await prompt(rl, "Git base branch", "main");
49
+ const usePointerBranch = await confirm(rl, "Use a separate published pointer branch?");
50
+ let pointerBranch = "";
51
+ if (usePointerBranch) {
52
+ pointerBranch = await prompt(rl, "Pointer branch name", "cms/publish-pointer");
53
+ }
54
+ return { projectName, baseBranch, usePointerBranch, pointerBranch };
55
+ } finally {
56
+ rl.close();
57
+ }
58
+ }
59
+ async function initCommand(projectRoot, options = {}) {
60
+ log.header("Initialize a new project");
61
+ const octoConfigPath = join(projectRoot, "cms", "octocms.config.ts");
62
+ if (existsSync(octoConfigPath) && readFileSync(octoConfigPath, "utf8").includes("defineConfig")) {
63
+ log.error("cms/octocms.config.ts already contains defineConfig \u2014 this project is already initialized.");
64
+ log.info("Use `octocms update` to regenerate admin route files.");
65
+ process.exitCode = 1;
66
+ return;
67
+ }
68
+ const nextConfigPath = join(projectRoot, "next.config.ts");
69
+ if (!existsSync(join(projectRoot, "package.json"))) {
70
+ log.error("No package.json found \u2014 run this inside a Next.js project.");
71
+ process.exitCode = 1;
72
+ return;
73
+ }
74
+ const answers = await gatherAnswers(options);
75
+ log.blank();
76
+ log.info("Creating files...");
77
+ const cmsRouteDir = join(projectRoot, "src", "app", "cms");
78
+ mkdirSync(join(cmsRouteDir, "[[...path]]"), { recursive: true });
79
+ writeFileSync(join(cmsRouteDir, "layout.tsx"), adminLayoutTemplate, "utf8");
80
+ log.success("src/app/cms/layout.tsx");
81
+ writeFileSync(join(cmsRouteDir, "[[...path]]", "page.tsx"), adminPageTemplate, "utf8");
82
+ log.success("src/app/cms/[[...path]]/page.tsx");
83
+ const demoId = "001";
84
+ const contentDir = join(projectRoot, "cms", "content", "post");
85
+ mkdirSync(contentDir, { recursive: true });
86
+ writeFileSync(join(contentDir, `post-${demoId}.json`), demoPostJson(demoId), "utf8");
87
+ log.success(`cms/content/post/post-${demoId}.json`);
88
+ writeFileSync(join(contentDir, `post-${demoId}.body.md`), demoPostMarkdown, "utf8");
89
+ log.success(`cms/content/post/post-${demoId}.body.md`);
90
+ mkdirSync(join(projectRoot, "cms", "__generated__"), { recursive: true });
91
+ mkdirSync(join(projectRoot, "public", "media"), { recursive: true });
92
+ log.blank();
93
+ log.info("Updating configuration...");
94
+ mkdirSync(join(projectRoot, "cms"), { recursive: true });
95
+ writeFileSync(
96
+ octoConfigPath,
97
+ octoConfigTemplate({
98
+ projectName: answers.projectName,
99
+ baseBranch: answers.baseBranch,
100
+ pointerBranch: answers.usePointerBranch ? answers.pointerBranch : void 0
101
+ }),
102
+ "utf8"
103
+ );
104
+ log.success("cms/octocms.config.ts \u2014 OctoCMS schema");
105
+ writeFileSync(nextConfigPath, nextConfigTemplate(), "utf8");
106
+ log.success("next.config.ts \u2014 Next.js wrapper");
107
+ const tsconfigPath = join(projectRoot, "tsconfig.json");
108
+ if (existsSync(tsconfigPath)) {
109
+ try {
110
+ const raw = readFileSync(tsconfigPath, "utf8");
111
+ const tsconfig = JSON.parse(raw);
112
+ if (!tsconfig.compilerOptions) tsconfig.compilerOptions = {};
113
+ if (!tsconfig.compilerOptions.paths) tsconfig.compilerOptions.paths = {};
114
+ const requiredPaths = tsconfigPaths();
115
+ let changed = false;
116
+ for (const [alias, targets] of Object.entries(requiredPaths)) {
117
+ if (!tsconfig.compilerOptions.paths[alias]) {
118
+ tsconfig.compilerOptions.paths[alias] = targets;
119
+ changed = true;
120
+ }
121
+ }
122
+ if (changed) {
123
+ writeFileSync(tsconfigPath, JSON.stringify(tsconfig, null, 2) + "\n", "utf8");
124
+ log.success("tsconfig.json \u2014 added octocms/* path aliases");
125
+ } else {
126
+ log.success("tsconfig.json \u2014 path aliases already present");
127
+ }
128
+ } catch (e) {
129
+ log.warn("tsconfig.json \u2014 could not parse; add octocms/* paths manually");
130
+ }
131
+ } else {
132
+ log.warn("tsconfig.json not found \u2014 create one with octocms/* path aliases");
133
+ }
134
+ log.blank();
135
+ log.info("Next steps:");
136
+ log.info(" 1. Add GitHub App credentials to .env.local (see README.md)");
137
+ log.info(" 2. Run: npm run octocms types:gen");
138
+ log.info(" 3. Run: npm run dev");
139
+ log.info(" 4. Visit: http://localhost:3001/cms");
140
+ log.blank();
141
+ }
142
+ export {
143
+ initCommand
144
+ };
145
+ //# sourceMappingURL=init-UGUTJFFI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../cli/commands/init.ts"],"sourcesContent":["/**\n * `octocms init` — Initialize OctoCMS in a Next.js project.\n *\n * Writes the full CMS config inline into `next.config.ts`, creates admin\n * route files, demo content, and updates `tsconfig.json` with required\n * path aliases.\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';\nimport { join } from 'path';\nimport readline from 'readline';\n\nimport { log } from '../lib/logger';\nimport {\n adminLayoutTemplate,\n adminPageTemplate,\n demoPostJson,\n demoPostMarkdown,\n nextConfigTemplate,\n octoConfigTemplate,\n tsconfigPaths,\n} from '../lib/templates';\n\nexport type InitOptions = {\n /** Accept all defaults without prompting. */\n yes?: boolean;\n};\n\ntype InitAnswers = {\n projectName: string;\n baseBranch: string;\n usePointerBranch: boolean;\n pointerBranch: string;\n};\n\nasync function prompt(rl: readline.Interface, question: string, defaultValue?: string): Promise<string> {\n const suffix = defaultValue ? ` (${defaultValue})` : '';\n return new Promise((resolve) => {\n rl.question(` ? ${question}${suffix}: `, (answer) => {\n resolve(answer.trim() || defaultValue || '');\n });\n });\n}\n\nasync function confirm(rl: readline.Interface, question: string, defaultYes = false): Promise<boolean> {\n const hint = defaultYes ? 'Y/n' : 'y/N';\n const answer = await prompt(rl, `${question} (${hint})`);\n if (!answer) return defaultYes;\n return answer.toLowerCase().startsWith('y');\n}\n\nasync function gatherAnswers(options: InitOptions): Promise<InitAnswers> {\n if (options.yes) {\n return {\n projectName: 'My CMS',\n baseBranch: 'main',\n usePointerBranch: false,\n pointerBranch: '',\n };\n }\n\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stdout,\n });\n\n try {\n const projectName = await prompt(rl, 'Project name', 'My CMS');\n const baseBranch = await prompt(rl, 'Git base branch', 'main');\n const usePointerBranch = await confirm(rl, 'Use a separate published pointer branch?');\n let pointerBranch = '';\n if (usePointerBranch) {\n pointerBranch = await prompt(rl, 'Pointer branch name', 'cms/publish-pointer');\n }\n\n return { projectName, baseBranch, usePointerBranch, pointerBranch };\n } finally {\n rl.close();\n }\n}\n\nexport async function initCommand(projectRoot: string, options: InitOptions = {}): Promise<void> {\n log.header('Initialize a new project');\n\n // Already initialized if cms/octocms.config.ts already contains defineConfig\n const octoConfigPath = join(projectRoot, 'cms', 'octocms.config.ts');\n if (existsSync(octoConfigPath) && readFileSync(octoConfigPath, 'utf8').includes('defineConfig')) {\n log.error('cms/octocms.config.ts already contains defineConfig — this project is already initialized.');\n log.info('Use `octocms update` to regenerate admin route files.');\n process.exitCode = 1;\n return;\n }\n const nextConfigPath = join(projectRoot, 'next.config.ts');\n\n if (!existsSync(join(projectRoot, 'package.json'))) {\n log.error('No package.json found — run this inside a Next.js project.');\n process.exitCode = 1;\n return;\n }\n\n const answers = await gatherAnswers(options);\n\n log.blank();\n log.info('Creating files...');\n\n // Admin route files\n const cmsRouteDir = join(projectRoot, 'src', 'app', 'cms');\n mkdirSync(join(cmsRouteDir, '[[...path]]'), { recursive: true });\n\n writeFileSync(join(cmsRouteDir, 'layout.tsx'), adminLayoutTemplate, 'utf8');\n log.success('src/app/cms/layout.tsx');\n\n writeFileSync(join(cmsRouteDir, '[[...path]]', 'page.tsx'), adminPageTemplate, 'utf8');\n log.success('src/app/cms/[[...path]]/page.tsx');\n\n // Demo content\n const demoId = '001';\n const contentDir = join(projectRoot, 'cms', 'content', 'post');\n mkdirSync(contentDir, { recursive: true });\n\n writeFileSync(join(contentDir, `post-${demoId}.json`), demoPostJson(demoId), 'utf8');\n log.success(`cms/content/post/post-${demoId}.json`);\n\n writeFileSync(join(contentDir, `post-${demoId}.body.md`), demoPostMarkdown, 'utf8');\n log.success(`cms/content/post/post-${demoId}.body.md`);\n\n // Generated types directory\n mkdirSync(join(projectRoot, 'cms', '__generated__'), { recursive: true });\n\n // Media directory\n mkdirSync(join(projectRoot, 'public', 'media'), { recursive: true });\n\n // cms/octocms.config.ts — write the OctoCMS schema\n log.blank();\n log.info('Updating configuration...');\n mkdirSync(join(projectRoot, 'cms'), { recursive: true });\n writeFileSync(\n octoConfigPath,\n octoConfigTemplate({\n projectName: answers.projectName,\n baseBranch: answers.baseBranch,\n pointerBranch: answers.usePointerBranch ? answers.pointerBranch : undefined,\n }),\n 'utf8',\n );\n log.success('cms/octocms.config.ts — OctoCMS schema');\n\n // next.config.ts — write the thin Next.js wrapper\n writeFileSync(nextConfigPath, nextConfigTemplate(), 'utf8');\n log.success('next.config.ts — Next.js wrapper');\n\n // tsconfig.json\n const tsconfigPath = join(projectRoot, 'tsconfig.json');\n if (existsSync(tsconfigPath)) {\n try {\n const raw = readFileSync(tsconfigPath, 'utf8');\n const tsconfig = JSON.parse(raw);\n if (!tsconfig.compilerOptions) tsconfig.compilerOptions = {};\n if (!tsconfig.compilerOptions.paths) tsconfig.compilerOptions.paths = {};\n const requiredPaths = tsconfigPaths();\n let changed = false;\n for (const [alias, targets] of Object.entries(requiredPaths)) {\n if (!tsconfig.compilerOptions.paths[alias]) {\n tsconfig.compilerOptions.paths[alias] = targets;\n changed = true;\n }\n }\n if (changed) {\n writeFileSync(tsconfigPath, JSON.stringify(tsconfig, null, 2) + '\\n', 'utf8');\n log.success('tsconfig.json — added octocms/* path aliases');\n } else {\n log.success('tsconfig.json — path aliases already present');\n }\n } catch {\n log.warn('tsconfig.json — could not parse; add octocms/* paths manually');\n }\n } else {\n log.warn('tsconfig.json not found — create one with octocms/* path aliases');\n }\n\n log.blank();\n log.info('Next steps:');\n log.info(' 1. Add GitHub App credentials to .env.local (see README.md)');\n log.info(' 2. Run: npm run octocms types:gen');\n log.info(' 3. Run: npm run dev');\n log.info(' 4. Visit: http://localhost:3001/cms');\n log.blank();\n}\n"],"mappings":"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","names":[]}