octocms 0.3.4 → 0.3.6
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.
- package/dist/{agentDocs-4DFOPJEP.js → agentDocs-NUEXGXIH.js} +2 -2
- package/dist/{chunk-BSCCWET6.js → chunk-33VA3IFB.js} +2 -2
- package/dist/chunk-33VA3IFB.js.map +1 -0
- package/dist/cli/index.js +5 -5
- package/dist/cli/index.js.map +1 -1
- package/dist/{init-W7KLXTGY.js → init-RQVF5KUT.js} +2 -2
- package/dist/{typesGen-NSSMVJVV.js → typesGen-RDG5SY5R.js} +2 -2
- package/dist/{typesGen-NSSMVJVV.js.map → typesGen-RDG5SY5R.js.map} +1 -1
- package/dist/{update-E4KTUEPW.js → update-4Z3OK3TX.js} +2 -2
- package/github-public.ts +160 -0
- package/package.json +4 -1
- package/utils/parseFileName.ts +30 -0
- package/dist/chunk-BSCCWET6.js.map +0 -1
- /package/dist/{agentDocs-4DFOPJEP.js.map → agentDocs-NUEXGXIH.js.map} +0 -0
- /package/dist/{init-W7KLXTGY.js.map → init-RQVF5KUT.js.map} +0 -0
- /package/dist/{update-E4KTUEPW.js.map → update-4Z3OK3TX.js.map} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
agentsMdSection,
|
|
3
3
|
agentsMdTemplate
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-33VA3IFB.js";
|
|
5
5
|
import {
|
|
6
6
|
log
|
|
7
7
|
} from "./chunk-33PHLOAE.js";
|
|
@@ -34,4 +34,4 @@ async function agentDocsCommand(projectRoot) {
|
|
|
34
34
|
export {
|
|
35
35
|
agentDocsCommand
|
|
36
36
|
};
|
|
37
|
-
//# sourceMappingURL=agentDocs-
|
|
37
|
+
//# sourceMappingURL=agentDocs-NUEXGXIH.js.map
|
|
@@ -76,7 +76,7 @@ import type { EntryMap } from './types';
|
|
|
76
76
|
export const query = createQuery<EntryMap, OctoConfig>(configOctoCMS as unknown as OctoConfig);
|
|
77
77
|
`;
|
|
78
78
|
var generatedConfigInitTemplate = CODEGEN_BANNER + `import { configOctoCMS } from '../octocms.config';
|
|
79
|
-
import { setConfig } from 'octocms/
|
|
79
|
+
import { setConfig } from 'octocms/lib/configStore';
|
|
80
80
|
|
|
81
81
|
setConfig(configOctoCMS);
|
|
82
82
|
`;
|
|
@@ -260,4 +260,4 @@ export {
|
|
|
260
260
|
agentsMdTemplate,
|
|
261
261
|
tsconfigPaths
|
|
262
262
|
};
|
|
263
|
-
//# sourceMappingURL=chunk-
|
|
263
|
+
//# sourceMappingURL=chunk-33VA3IFB.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../cli/lib/templates.ts"],"sourcesContent":["/**\n * File templates used by `octocms init` and `octocms update`.\n */\n\nconst CODEGEN_BANNER = `/*\n * AUTO-GENERATED — DO NOT EDIT.\n * Generated from cms/octocms.config.ts.\n * Run \\`npx octocms types:gen\\` to regenerate.\n */\n\n`;\n\n/** Static cms/__generated__/types.ts for the helloPage demo schema. */\nexport const generatedTypesTemplate =\n CODEGEN_BANNER +\n `import type { EntryStatus } from 'octocms/types';\n\nexport interface HelloPageFields {\n title: string;\n description: string;\n}\n\nexport interface HelloPageEntry {\n sys: { id: string; type: 'helloPage'; status: EntryStatus };\n fields: HelloPageFields;\n}\n\nexport type AnyEntry = HelloPageEntry;\n\nexport type EntryMap = {\n helloPage: HelloPageEntry;\n};\n`;\n\n/** Static cms/__generated__/enums.ts for the helloPage demo schema. */\nexport const generatedEnumsTemplate =\n CODEGEN_BANNER +\n `export const CollectionName = {\n HelloPage: 'helloPage',\n} as const;\nexport type CollectionName = (typeof CollectionName)[keyof typeof CollectionName];\n\nexport const COLLECTION_NAMES = ['helloPage'] as const;\n\nexport const FieldFormat = {\n String: 'string',\n Text: 'text',\n Markdown: 'markdown',\n Boolean: 'boolean',\n Reference: 'reference',\n Image: 'image',\n Number: 'number',\n Datetime: 'datetime',\n Json: 'json',\n Slug: 'slug',\n Select: 'select',\n Url: 'url',\n Color: 'color',\n Conditional: 'conditional',\n Richtext: 'richtext',\n} as const;\nexport type FieldFormat = (typeof FieldFormat)[keyof typeof FieldFormat];\n`;\n\n/** Static cms/__generated__/content.d.ts for the helloPage demo schema. */\nexport const generatedContentDeclsTemplate =\n CODEGEN_BANNER +\n `import type { EntryStatus } from 'octocms/types';\n\n// Raw on-disk types (before query() processing).\nexport interface RawHelloPageFields {\n title: string;\n description: string;\n}\n\nexport interface RawHelloPageEntry {\n sys: { id: string; type: 'helloPage'; status: EntryStatus };\n fields: RawHelloPageFields;\n}\n`;\n\n/** Static cms/__generated__/index.ts — always the same shape. */\nexport const generatedIndexTemplate =\n CODEGEN_BANNER +\n `export * from './types';\nexport * from './enums';\nexport * from './query';\n`;\n\n/** Static cms/__generated__/query.ts — always the same shape (schema-independent). */\nexport const generatedQueryTemplate =\n CODEGEN_BANNER +\n `import { createQuery } from 'octocms/query';\nimport { configOctoCMS, type OctoConfig } from '../octocms.config';\nimport type { EntryMap } from './types';\n\n// configOctoCMS is widened to Config for admin internals; cast back to OctoConfig so\n// createQuery preserves literal collection/field names for type-safe queries.\nexport const query = createQuery<EntryMap, OctoConfig>(configOctoCMS as unknown as OctoConfig);\n`;\n\n/** Static cms/__generated__/configInit.ts — always the same shape (schema-independent). */\nexport const generatedConfigInitTemplate =\n CODEGEN_BANNER +\n `import { configOctoCMS } from '../octocms.config';\nimport { setConfig } from 'octocms/lib/configStore';\n\nsetConfig(configOctoCMS);\n`;\n\nexport const adminLayoutTemplate = `import '../../cms/__generated__/configInit';\n\nexport { AdminLayout as default, metadata } from 'octocms/admin/pages/AdminLayout';\n`;\n\nexport const adminPageTemplate = `export { AdminApp as default } from 'octocms/admin/AdminApp';\n`;\n\nexport function octoConfigTemplate(opts: { projectName: string; baseBranch: string; pointerBranch?: string }): string {\n const gitBlock = opts.pointerBranch\n ? ` git: {\\n baseBranch: '${opts.baseBranch}',\\n publishedPointerBranch: '${opts.pointerBranch}',\\n },`\n : ` git: { baseBranch: '${opts.baseBranch}' },`;\n\n return `import type { Config } from 'octocms/types';\nimport { defineConfig } from 'octocms/config';\n\nconst _typedConfigOctoCMS = defineConfig({\n projectName: '${opts.projectName}',\n${gitBlock}\n contentFolder: 'cms/content',\n mediaFolder: 'public/media',\n mediaAllowedFormats: ['png', 'jpg', 'jpeg', 'gif', 'webp', 'svg', 'avif'],\n collections: {\n helloPage: {\n label: 'Hello Page',\n fields: {\n title: { label: 'Title', format: 'string', entryTitle: true, required: true },\n description: { label: 'Description', format: 'text' },\n },\n },\n },\n});\n\nexport const configOctoCMS: Config = _typedConfigOctoCMS;\nexport type OctoConfig = typeof _typedConfigOctoCMS;\n`;\n}\n\nexport function nextConfigTemplate(): string {\n return `import type { NextConfig } from 'next';\nimport { withOctoCMS } from 'octocms/config';\nimport { configOctoCMS } from './cms/octocms.config';\n\nexport { configOctoCMS } from './cms/octocms.config';\nexport type { OctoConfig } from './cms/octocms.config';\n\nconst nextConfig: NextConfig = {\n transpilePackages: ['octocms'],\n};\n\nexport default withOctoCMS(nextConfig, configOctoCMS);\n`;\n}\n\nexport function demoHelloPageJson(): string {\n return JSON.stringify(\n {\n sys: { id: '0000', type: 'helloPage', status: 'merged' },\n fields: {\n title: 'Hello World',\n description: 'Welcome to your new OctoCMS site! Edit this content in the CMS admin panel.',\n },\n },\n null,\n 2,\n );\n}\n\nexport const helloPageTemplate = `import { query } from 'cms/__generated__/query';\n\nexport default async function HelloPage() {\n const page = await query('helloPage').first();\n if (!page) return null;\n return (\n <main>\n <h1>{page.fields.title}</h1>\n <p>{page.fields.description}</p>\n </main>\n );\n}\n`;\n\nexport function readmeTemplate(projectName: string): string {\n return `# ${projectName}\n\nBuilt with [OctoCMS](https://octocms.com) — a file-based CMS on Next.js.\n\n## Setup\n\n### 1. Create a GitHub App\n\nFollow the [OctoCMS GitHub App setup guide](https://octocms.com/docs/github-app) to create a GitHub App for authentication.\n\n### 2. Configure environment variables\n\nCopy the values from your GitHub App into \\`.env.local\\`:\n\n\\`\\`\\`bash\n# GitHub App credentials (required for CMS auth)\nGITHUB_ID=your_github_app_client_id\nGITHUB_SECRET=your_github_app_client_secret\n\n# NextAuth (generate secret: openssl rand -base64 32)\nNEXTAUTH_SECRET=your_nextauth_secret\nNEXTAUTH_URL=http://localhost:3000\n\n# GitHub repo for content storage (required in production)\nGITHUB_REPO_OWNER=your_github_username_or_org\nGITHUB_REPO_NAME=your_repo_name\n\n# Optional: static GitHub token for private repos / higher API rate limits\n# CMS_GITHUB_TOKEN=your_github_pat\n\\`\\`\\`\n\n### 3. Run the dev server\n\n\\`\\`\\`bash\nnpm run dev\n\\`\\`\\`\n\nOpen [http://localhost:3000/cms](http://localhost:3000/cms) to access the CMS admin.\n`;\n}\n\nexport function envLocalTemplate(): string {\n return `# GitHub App credentials (required for CMS auth)\n# Create a GitHub App at: https://github.com/settings/apps/new\nGITHUB_ID=\nGITHUB_SECRET=\n\n# NextAuth secret — generate with: openssl rand -base64 32\nNEXTAUTH_SECRET=\nNEXTAUTH_URL=http://localhost:3000\n\n# GitHub repo for content storage (required in production)\nGITHUB_REPO_OWNER=\nGITHUB_REPO_NAME=\n\n# Optional: static GitHub token for private repos or higher API rate limits\n# CMS_GITHUB_TOKEN=\n`;\n}\n\nconst AGENT_DOCS_MARKER = '<!-- octocms:agent-docs -->';\n\nexport function agentsMdSection(): string {\n return `${AGENT_DOCS_MARKER}\n## OctoCMS — AI Content Management\n\nFor tasks that involve creating, editing, or deleting CMS content directly (without the admin UI), read the auto-generated agent docs:\n\n- **\\`octocms/docs/overview.md\\`** — How to find, create, update, and delete content entries via file operations\n- **\\`octocms/docs/schema.md\\`** — Per-collection field definitions, example JSON, and file path conventions\n\nThese docs are generated from \\`cms/octocms.config.ts\\`. Regenerate after schema changes: \\`npm run agent-docs:gen\\`.`;\n}\n\nexport function agentsMdTemplate(): string {\n return `# Project Guidelines\n\n${agentsMdSection()}\n`;\n}\n\nexport function tsconfigPaths(): Record<string, string[]> {\n return {\n 'cms/__generated__': ['./cms/__generated__/index.ts'],\n 'cms/__generated__/*': ['./cms/__generated__/*'],\n '@/*': ['./src/*'],\n };\n}\n"],"mappings":";AAIA,IAAM,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAShB,IAAM,yBACX,iBACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoBK,IAAM,yBACX,iBACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA4BK,IAAM,gCACX,iBACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAeK,IAAM,yBACX,iBACA;AAAA;AAAA;AAAA;AAMK,IAAM,yBACX,iBACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUK,IAAM,8BACX,iBACA;AAAA;AAAA;AAAA;AAAA;AAMK,IAAM,sBAAsB;AAAA;AAAA;AAAA;AAK5B,IAAM,oBAAoB;AAAA;AAG1B,SAAS,mBAAmB,MAAmF;AACpH,QAAM,WAAW,KAAK,gBAClB;AAAA,mBAA8B,KAAK,UAAU;AAAA,+BAAoC,KAAK,aAAa;AAAA,QACnG,yBAAyB,KAAK,UAAU;AAE5C,SAAO;AAAA;AAAA;AAAA;AAAA,kBAIS,KAAK,WAAW;AAAA,EAChC,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkBV;AAEO,SAAS,qBAA6B;AAC3C,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAaT;AAEO,SAAS,oBAA4B;AAC1C,SAAO,KAAK;AAAA,IACV;AAAA,MACE,KAAK,EAAE,IAAI,QAAQ,MAAM,aAAa,QAAQ,SAAS;AAAA,MACvD,QAAQ;AAAA,QACN,OAAO;AAAA,QACP,aAAa;AAAA,MACf;AAAA,IACF;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEO,IAAM,oBAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAc1B,SAAS,eAAe,aAA6B;AAC1D,SAAO,KAAK,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAuCzB;AAEO,SAAS,mBAA2B;AACzC,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgBT;AAEA,IAAM,oBAAoB;AAEnB,SAAS,kBAA0B;AACxC,SAAO,GAAG,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAS7B;AAEO,SAAS,mBAA2B;AACzC,SAAO;AAAA;AAAA,EAEP,gBAAgB,CAAC;AAAA;AAEnB;AAEO,SAAS,gBAA0C;AACxD,SAAO;AAAA,IACL,qBAAqB,CAAC,8BAA8B;AAAA,IACpD,uBAAuB,CAAC,uBAAuB;AAAA,IAC/C,OAAO,CAAC,SAAS;AAAA,EACnB;AACF;","names":[]}
|
package/dist/cli/index.js
CHANGED
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
} from "../chunk-33PHLOAE.js";
|
|
9
9
|
|
|
10
10
|
// package.json
|
|
11
|
-
var version = "0.3.
|
|
11
|
+
var version = "0.3.6";
|
|
12
12
|
|
|
13
13
|
// cli/index.ts
|
|
14
14
|
var HELP = `
|
|
@@ -148,7 +148,7 @@ async function main() {
|
|
|
148
148
|
try {
|
|
149
149
|
switch (command) {
|
|
150
150
|
case "init": {
|
|
151
|
-
const { initCommand } = await import("../init-
|
|
151
|
+
const { initCommand } = await import("../init-RQVF5KUT.js");
|
|
152
152
|
await initCommand(process.cwd(), { yes: flags.yes === true });
|
|
153
153
|
break;
|
|
154
154
|
}
|
|
@@ -161,7 +161,7 @@ async function main() {
|
|
|
161
161
|
}
|
|
162
162
|
case "types:gen": {
|
|
163
163
|
const projectRoot = resolveProjectRoot();
|
|
164
|
-
const { typesGenCommand } = await import("../typesGen-
|
|
164
|
+
const { typesGenCommand } = await import("../typesGen-RDG5SY5R.js");
|
|
165
165
|
await typesGenCommand(projectRoot);
|
|
166
166
|
break;
|
|
167
167
|
}
|
|
@@ -173,13 +173,13 @@ async function main() {
|
|
|
173
173
|
}
|
|
174
174
|
case "update": {
|
|
175
175
|
const projectRoot = resolveProjectRoot();
|
|
176
|
-
const { updateCommand } = await import("../update-
|
|
176
|
+
const { updateCommand } = await import("../update-4Z3OK3TX.js");
|
|
177
177
|
await updateCommand(projectRoot);
|
|
178
178
|
break;
|
|
179
179
|
}
|
|
180
180
|
case "agent-docs": {
|
|
181
181
|
const projectRoot = resolveProjectRoot();
|
|
182
|
-
const { agentDocsCommand } = await import("../agentDocs-
|
|
182
|
+
const { agentDocsCommand } = await import("../agentDocs-NUEXGXIH.js");
|
|
183
183
|
await agentDocsCommand(projectRoot);
|
|
184
184
|
break;
|
|
185
185
|
}
|
package/dist/cli/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../package.json","../../cli/index.ts"],"sourcesContent":["{\n \"name\": \"octocms\",\n \"version\": \"0.3.4\",\n \"description\": \"A file-based CMS for Next.js — schema-driven, Git-backed, no database\",\n \"license\": \"MIT\",\n \"type\": \"module\",\n \"keywords\": [\n \"cms\",\n \"nextjs\",\n \"headless-cms\",\n \"git-cms\",\n \"content-management\"\n ],\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/octocms/octocms.git\"\n },\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"require\": \"./dist/index.cjs\",\n \"import\": \"./dist/index.js\"\n },\n \"./query\": {\n \"types\": \"./dist/query.d.ts\",\n \"require\": \"./dist/query.cjs\",\n \"import\": \"./dist/query.js\"\n },\n \"./config\": {\n \"types\": \"./dist/config.d.ts\",\n \"require\": \"./dist/config.cjs\",\n \"import\": \"./dist/config.js\"\n },\n \"./defineConfig\": {\n \"types\": \"./dist/defineConfig.d.ts\",\n \"require\": \"./dist/defineConfig.cjs\",\n \"import\": \"./dist/defineConfig.js\"\n },\n \"./types\": {\n \"types\": \"./dist/types.d.ts\",\n \"require\": \"./dist/types.cjs\",\n \"import\": \"./dist/types.js\"\n },\n \"./withOctoCMS\": {\n \"types\": \"./dist/withOctoCMS.d.ts\",\n \"require\": \"./dist/withOctoCMS.cjs\",\n \"import\": \"./dist/withOctoCMS.js\"\n },\n \"./components/public\": {\n \"types\": \"./dist/components/public/index.d.ts\",\n \"require\": \"./dist/components/public/index.cjs\",\n \"import\": \"./dist/components/public/index.js\"\n },\n \"./admin/AdminApp\": \"./admin/AdminApp.tsx\",\n \"./admin/pages/AdminLayout\": \"./admin/pages/AdminLayout.tsx\",\n \"./globals.css\": \"./globals.css\",\n \"./docs/*\": \"./docs/*\"\n },\n \"bin\": {\n \"octocms\": \"dist/cli/index.js\"\n },\n \"files\": [\n \"dist\",\n \"docs\",\n \"globals.css\",\n \"admin\",\n \"components\",\n \"hooks\",\n \"lib\",\n \"index.ts\",\n \"query.ts\",\n \"config.ts\",\n \"defineConfig.ts\",\n \"types.ts\",\n \"withOctoCMS.ts\"\n ],\n \"scripts\": {\n \"build\": \"tsup\",\n \"prepublishOnly\": \"npm run checks && npm run build\",\n \"lint\": \"oxlint .\",\n \"lint:fix\": \"oxlint --fix .\",\n \"fmt\": \"oxfmt .\",\n \"fmt:check\": \"oxfmt --check .\",\n \"test\": \"vitest\",\n \"test:run\": \"vitest run\",\n \"ts-check\": \"tsc --noEmit --incremental false\",\n \"checks\": \"npm run lint && npm run ts-check && npm run fmt:check && npm run test:run\",\n \"checks:fix\": \"npm run lint:fix && npm run fmt && npm run test:run\"\n },\n \"peerDependencies\": {\n \"next\": \">=15\",\n \"react\": \">=18\",\n \"react-dom\": \">=18\"\n },\n \"dependencies\": {\n \"@mdxeditor/editor\": \"^3.11.4\",\n \"@radix-ui/react-avatar\": \"^1.1.11\",\n \"@radix-ui/react-dialog\": \"^1.1.15\",\n \"@radix-ui/react-dropdown-menu\": \"^2.1.16\",\n \"@radix-ui/react-label\": \"^2.1.8\",\n \"@radix-ui/react-select\": \"^2.2.6\",\n \"@radix-ui/react-slot\": \"^1.2.4\",\n \"@radix-ui/react-tabs\": \"^1.1.13\",\n \"@radix-ui/react-toast\": \"^1.2.15\",\n \"class-variance-authority\": \"^0.7.1\",\n \"clsx\": \"^2.1.1\",\n \"glob\": \"^11.0.0\",\n \"lucide-react\": \"^1.7.0\",\n \"minisearch\": \"^7.2.0\",\n \"next-auth\": \"^4.24.13\",\n \"octokit\": \"^4.1.4\",\n \"react-markdown\": \"^10.1.0\",\n \"rehype-sanitize\": \"^6.0.0\",\n \"remark-gfm\": \"^4.0.1\",\n \"remark-mdx\": \"^3.1.1\",\n \"sharp\": \"^0.34.5\",\n \"slugify\": \"^1.6.9\",\n \"sonner\": \"^2.0.7\",\n \"tailwind-merge\": \"^3.5.0\",\n \"zod\": \"^4.3.6\"\n },\n \"devDependencies\": {\n \"@testing-library/dom\": \"^10.4.1\",\n \"@testing-library/react\": \"^16.3.2\",\n \"@types/node\": \"^20\",\n \"@types/react\": \"^19.2.14\",\n \"@types/react-dom\": \"^19.2.3\",\n \"@vitejs/plugin-react\": \"^6.0.1\",\n \"jsdom\": \"^29.0.1\",\n \"oxfmt\": \"^0.11.0\",\n \"oxlint\": \"^0.17.0\",\n \"tsup\": \"^8.0.0\",\n \"typescript\": \"^5.9.3\",\n \"vite-tsconfig-paths\": \"^6.1.1\",\n \"vitest\": \"^4.1.2\"\n }\n}\n","#!/usr/bin/env node\n/* eslint-disable no-console */\n\n/**\n * OctoCMS CLI — command-line tools for managing an OctoCMS project.\n *\n * Commands:\n * init Initialize OctoCMS in a Next.js project\n * dev Start development server with config watching\n * types:gen Generate TypeScript types from next.config.ts\n * validate Validate all content entries against the schema\n * update Regenerate admin route files\n * agent-docs Inject AI agent doc links into AGENTS.md\n *\n * Usage:\n * octocms <command> [options]\n * octocms --help\n * octocms --version\n */\n\nimport { fmt, log } from './lib/logger';\nimport { resolveProjectRoot } from './lib/project';\nimport { version as VERSION } from '../package.json';\n\nconst HELP = `\n ${fmt.bold('OctoCMS CLI')} v${VERSION}\n\n Usage: octocms <command> [options]\n\n ${fmt.bold('Commands:')}\n init Initialize OctoCMS in a Next.js project\n dev Start development server with config watching\n types:gen Generate TypeScript types from next.config.ts\n validate Validate all content entries against the schema\n update Regenerate admin route files\n agent-docs Inject AI agent doc links into AGENTS.md\n\n ${fmt.bold('Options:')}\n --help Show this help message\n --version Show version number\n\n Run ${fmt.cyan('octocms <command> --help')} for command-specific help.\n`;\n\nconst COMMAND_HELP: Record<string, string> = {\n init: `\n ${fmt.bold('octocms init')} — Initialize OctoCMS in a Next.js project\n\n Creates next.config.ts, admin route files, demo content, and updates\n next.config.ts and tsconfig.json with required configuration.\n\n ${fmt.bold('Usage:')} octocms init [options]\n\n ${fmt.bold('Options:')}\n --yes, -y Accept all defaults (non-interactive)\n --help Show this help message\n`,\n dev: `\n ${fmt.bold('octocms dev')} — Start development server with config watching\n\n Spawns Next.js dev server and watches next.config.ts. When the config\n changes, types are automatically regenerated.\n\n ${fmt.bold('Usage:')} octocms dev [options]\n\n ${fmt.bold('Options:')}\n --port <n> Port number (default: 3000)\n --help Show this help message\n`,\n 'types:gen': `\n ${fmt.bold('octocms types:gen')} — Generate TypeScript types from next.config.ts\n\n Produces cms/__generated__/types.ts, enums.ts, content.d.ts, and index.ts.\n Validates the config before generating.\n\n ${fmt.bold('Usage:')} octocms types:gen\n\n ${fmt.bold('Options:')}\n --help Show this help message\n`,\n validate: `\n ${fmt.bold('octocms validate')} — Validate all content entries against the schema\n\n Reads every JSON file in cms/content/, validates structure, field types,\n required fields, select option values, reference targets, and companion files.\n\n ${fmt.bold('Usage:')} octocms validate\n\n ${fmt.bold('Options:')}\n --help Show this help message\n`,\n 'agent-docs': `\n ${fmt.bold('octocms agent-docs')} — Inject AI agent doc links into AGENTS.md\n\n Creates AGENTS.md if it doesn't exist, or appends the OctoCMS section\n if the file exists but doesn't reference the agent docs yet.\n\n ${fmt.bold('Usage:')} octocms agent-docs\n\n ${fmt.bold('Options:')}\n --help Show this help message\n`,\n update: `\n ${fmt.bold('octocms update')} — Regenerate admin route files\n\n Ensures src/app/cms/layout.tsx and the catch-all page re-export are\n up-to-date with the latest OctoCMS version.\n\n ${fmt.bold('Usage:')} octocms update\n\n ${fmt.bold('Options:')}\n --help Show this help message\n`,\n};\n\nfunction parseArgs(argv: string[]): { command: string | null; flags: Record<string, string | boolean> } {\n const args = argv.slice(2); // skip node + script path\n const flags: Record<string, string | boolean> = {};\n let command: string | null = null;\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n\n if (arg === '--help' || arg === '-h') {\n flags.help = true;\n } else if (arg === '--version' || arg === '-v') {\n flags.version = true;\n } else if (arg === '--yes' || arg === '-y') {\n flags.yes = true;\n } else if (arg === '--port') {\n flags.port = args[++i] ?? '';\n } else if (arg.startsWith('--port=')) {\n flags.port = arg.slice(7);\n } else if (!arg.startsWith('-') && !command) {\n // Handle compound commands as single tokens\n if (arg === 'types:gen' || arg === 'agent-docs') {\n command = arg;\n } else {\n command = arg;\n }\n }\n }\n\n return { command, flags };\n}\n\nasync function main(): Promise<void> {\n const { command, flags } = parseArgs(process.argv);\n\n if (flags.version) {\n console.log(VERSION);\n return;\n }\n\n if (!command || flags.help) {\n if (command && COMMAND_HELP[command]) {\n console.log(COMMAND_HELP[command]);\n } else {\n console.log(HELP);\n }\n return;\n }\n\n if (COMMAND_HELP[command] && flags.help) {\n console.log(COMMAND_HELP[command]);\n return;\n }\n\n try {\n switch (command) {\n case 'init': {\n // init doesn't need an existing project root — use cwd\n const { initCommand } = await import('./commands/init');\n await initCommand(process.cwd(), { yes: flags.yes === true });\n break;\n }\n case 'dev': {\n const projectRoot = resolveProjectRoot();\n const { devCommand } = await import('./commands/dev');\n const port = flags.port ? Number(flags.port) : undefined;\n await devCommand(projectRoot, { port });\n break;\n }\n case 'types:gen': {\n const projectRoot = resolveProjectRoot();\n const { typesGenCommand } = await import('./commands/typesGen');\n await typesGenCommand(projectRoot);\n break;\n }\n case 'validate': {\n const projectRoot = resolveProjectRoot();\n const { validateCommand } = await import('./commands/validate');\n await validateCommand(projectRoot);\n break;\n }\n case 'update': {\n const projectRoot = resolveProjectRoot();\n const { updateCommand } = await import('./commands/update');\n await updateCommand(projectRoot);\n break;\n }\n case 'agent-docs': {\n const projectRoot = resolveProjectRoot();\n const { agentDocsCommand } = await import('./commands/agentDocs');\n await agentDocsCommand(projectRoot);\n break;\n }\n default:\n log.error(`Unknown command: ${command}`);\n console.log(HELP);\n process.exitCode = 1;\n }\n } catch (e) {\n log.error((e as Error).message);\n process.exitCode = 1;\n }\n}\n\nmain();\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../package.json","../../cli/index.ts"],"sourcesContent":["{\n \"name\": \"octocms\",\n \"version\": \"0.3.6\",\n \"description\": \"A file-based CMS for Next.js — schema-driven, Git-backed, no database\",\n \"license\": \"MIT\",\n \"type\": \"module\",\n \"keywords\": [\n \"cms\",\n \"nextjs\",\n \"headless-cms\",\n \"git-cms\",\n \"content-management\"\n ],\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/octocms/octocms.git\"\n },\n \"exports\": {\n \".\": {\n \"types\": \"./dist/index.d.ts\",\n \"require\": \"./dist/index.cjs\",\n \"import\": \"./dist/index.js\"\n },\n \"./query\": {\n \"types\": \"./dist/query.d.ts\",\n \"require\": \"./dist/query.cjs\",\n \"import\": \"./dist/query.js\"\n },\n \"./config\": {\n \"types\": \"./dist/config.d.ts\",\n \"require\": \"./dist/config.cjs\",\n \"import\": \"./dist/config.js\"\n },\n \"./defineConfig\": {\n \"types\": \"./dist/defineConfig.d.ts\",\n \"require\": \"./dist/defineConfig.cjs\",\n \"import\": \"./dist/defineConfig.js\"\n },\n \"./types\": {\n \"types\": \"./dist/types.d.ts\",\n \"require\": \"./dist/types.cjs\",\n \"import\": \"./dist/types.js\"\n },\n \"./withOctoCMS\": {\n \"types\": \"./dist/withOctoCMS.d.ts\",\n \"require\": \"./dist/withOctoCMS.cjs\",\n \"import\": \"./dist/withOctoCMS.js\"\n },\n \"./components/public\": {\n \"types\": \"./dist/components/public/index.d.ts\",\n \"require\": \"./dist/components/public/index.cjs\",\n \"import\": \"./dist/components/public/index.js\"\n },\n \"./admin/AdminApp\": \"./admin/AdminApp.tsx\",\n \"./admin/pages/AdminLayout\": \"./admin/pages/AdminLayout.tsx\",\n \"./lib/configStore\": \"./lib/configStore.ts\",\n \"./globals.css\": \"./globals.css\",\n \"./docs/*\": \"./docs/*\"\n },\n \"bin\": {\n \"octocms\": \"dist/cli/index.js\"\n },\n \"files\": [\n \"dist\",\n \"docs\",\n \"globals.css\",\n \"admin\",\n \"components\",\n \"hooks\",\n \"lib\",\n \"utils\",\n \"index.ts\",\n \"query.ts\",\n \"config.ts\",\n \"defineConfig.ts\",\n \"github-public.ts\",\n \"types.ts\",\n \"withOctoCMS.ts\"\n ],\n \"scripts\": {\n \"build\": \"tsup\",\n \"prepublishOnly\": \"npm run checks && npm run build\",\n \"lint\": \"oxlint .\",\n \"lint:fix\": \"oxlint --fix .\",\n \"fmt\": \"oxfmt .\",\n \"fmt:check\": \"oxfmt --check .\",\n \"test\": \"vitest\",\n \"test:run\": \"vitest run\",\n \"ts-check\": \"tsc --noEmit --incremental false\",\n \"checks\": \"npm run lint && npm run ts-check && npm run fmt:check && npm run test:run\",\n \"checks:fix\": \"npm run lint:fix && npm run fmt && npm run test:run\"\n },\n \"peerDependencies\": {\n \"next\": \">=15\",\n \"react\": \">=18\",\n \"react-dom\": \">=18\"\n },\n \"dependencies\": {\n \"@mdxeditor/editor\": \"^3.11.4\",\n \"@radix-ui/react-avatar\": \"^1.1.11\",\n \"@radix-ui/react-dialog\": \"^1.1.15\",\n \"@radix-ui/react-dropdown-menu\": \"^2.1.16\",\n \"@radix-ui/react-label\": \"^2.1.8\",\n \"@radix-ui/react-select\": \"^2.2.6\",\n \"@radix-ui/react-slot\": \"^1.2.4\",\n \"@radix-ui/react-tabs\": \"^1.1.13\",\n \"@radix-ui/react-toast\": \"^1.2.15\",\n \"class-variance-authority\": \"^0.7.1\",\n \"clsx\": \"^2.1.1\",\n \"glob\": \"^11.0.0\",\n \"lucide-react\": \"^1.7.0\",\n \"minisearch\": \"^7.2.0\",\n \"next-auth\": \"^4.24.13\",\n \"octokit\": \"^4.1.4\",\n \"react-markdown\": \"^10.1.0\",\n \"rehype-sanitize\": \"^6.0.0\",\n \"remark-gfm\": \"^4.0.1\",\n \"remark-mdx\": \"^3.1.1\",\n \"sharp\": \"^0.34.5\",\n \"slugify\": \"^1.6.9\",\n \"sonner\": \"^2.0.7\",\n \"tailwind-merge\": \"^3.5.0\",\n \"zod\": \"^4.3.6\"\n },\n \"devDependencies\": {\n \"@testing-library/dom\": \"^10.4.1\",\n \"@testing-library/react\": \"^16.3.2\",\n \"@types/node\": \"^20\",\n \"@types/react\": \"^19.2.14\",\n \"@types/react-dom\": \"^19.2.3\",\n \"@vitejs/plugin-react\": \"^6.0.1\",\n \"jsdom\": \"^29.0.1\",\n \"oxfmt\": \"^0.11.0\",\n \"oxlint\": \"^0.17.0\",\n \"tsup\": \"^8.0.0\",\n \"typescript\": \"^5.9.3\",\n \"vite-tsconfig-paths\": \"^6.1.1\",\n \"vitest\": \"^4.1.2\"\n }\n}\n","#!/usr/bin/env node\n/* eslint-disable no-console */\n\n/**\n * OctoCMS CLI — command-line tools for managing an OctoCMS project.\n *\n * Commands:\n * init Initialize OctoCMS in a Next.js project\n * dev Start development server with config watching\n * types:gen Generate TypeScript types from next.config.ts\n * validate Validate all content entries against the schema\n * update Regenerate admin route files\n * agent-docs Inject AI agent doc links into AGENTS.md\n *\n * Usage:\n * octocms <command> [options]\n * octocms --help\n * octocms --version\n */\n\nimport { fmt, log } from './lib/logger';\nimport { resolveProjectRoot } from './lib/project';\nimport { version as VERSION } from '../package.json';\n\nconst HELP = `\n ${fmt.bold('OctoCMS CLI')} v${VERSION}\n\n Usage: octocms <command> [options]\n\n ${fmt.bold('Commands:')}\n init Initialize OctoCMS in a Next.js project\n dev Start development server with config watching\n types:gen Generate TypeScript types from next.config.ts\n validate Validate all content entries against the schema\n update Regenerate admin route files\n agent-docs Inject AI agent doc links into AGENTS.md\n\n ${fmt.bold('Options:')}\n --help Show this help message\n --version Show version number\n\n Run ${fmt.cyan('octocms <command> --help')} for command-specific help.\n`;\n\nconst COMMAND_HELP: Record<string, string> = {\n init: `\n ${fmt.bold('octocms init')} — Initialize OctoCMS in a Next.js project\n\n Creates next.config.ts, admin route files, demo content, and updates\n next.config.ts and tsconfig.json with required configuration.\n\n ${fmt.bold('Usage:')} octocms init [options]\n\n ${fmt.bold('Options:')}\n --yes, -y Accept all defaults (non-interactive)\n --help Show this help message\n`,\n dev: `\n ${fmt.bold('octocms dev')} — Start development server with config watching\n\n Spawns Next.js dev server and watches next.config.ts. When the config\n changes, types are automatically regenerated.\n\n ${fmt.bold('Usage:')} octocms dev [options]\n\n ${fmt.bold('Options:')}\n --port <n> Port number (default: 3000)\n --help Show this help message\n`,\n 'types:gen': `\n ${fmt.bold('octocms types:gen')} — Generate TypeScript types from next.config.ts\n\n Produces cms/__generated__/types.ts, enums.ts, content.d.ts, and index.ts.\n Validates the config before generating.\n\n ${fmt.bold('Usage:')} octocms types:gen\n\n ${fmt.bold('Options:')}\n --help Show this help message\n`,\n validate: `\n ${fmt.bold('octocms validate')} — Validate all content entries against the schema\n\n Reads every JSON file in cms/content/, validates structure, field types,\n required fields, select option values, reference targets, and companion files.\n\n ${fmt.bold('Usage:')} octocms validate\n\n ${fmt.bold('Options:')}\n --help Show this help message\n`,\n 'agent-docs': `\n ${fmt.bold('octocms agent-docs')} — Inject AI agent doc links into AGENTS.md\n\n Creates AGENTS.md if it doesn't exist, or appends the OctoCMS section\n if the file exists but doesn't reference the agent docs yet.\n\n ${fmt.bold('Usage:')} octocms agent-docs\n\n ${fmt.bold('Options:')}\n --help Show this help message\n`,\n update: `\n ${fmt.bold('octocms update')} — Regenerate admin route files\n\n Ensures src/app/cms/layout.tsx and the catch-all page re-export are\n up-to-date with the latest OctoCMS version.\n\n ${fmt.bold('Usage:')} octocms update\n\n ${fmt.bold('Options:')}\n --help Show this help message\n`,\n};\n\nfunction parseArgs(argv: string[]): { command: string | null; flags: Record<string, string | boolean> } {\n const args = argv.slice(2); // skip node + script path\n const flags: Record<string, string | boolean> = {};\n let command: string | null = null;\n\n for (let i = 0; i < args.length; i++) {\n const arg = args[i];\n\n if (arg === '--help' || arg === '-h') {\n flags.help = true;\n } else if (arg === '--version' || arg === '-v') {\n flags.version = true;\n } else if (arg === '--yes' || arg === '-y') {\n flags.yes = true;\n } else if (arg === '--port') {\n flags.port = args[++i] ?? '';\n } else if (arg.startsWith('--port=')) {\n flags.port = arg.slice(7);\n } else if (!arg.startsWith('-') && !command) {\n // Handle compound commands as single tokens\n if (arg === 'types:gen' || arg === 'agent-docs') {\n command = arg;\n } else {\n command = arg;\n }\n }\n }\n\n return { command, flags };\n}\n\nasync function main(): Promise<void> {\n const { command, flags } = parseArgs(process.argv);\n\n if (flags.version) {\n console.log(VERSION);\n return;\n }\n\n if (!command || flags.help) {\n if (command && COMMAND_HELP[command]) {\n console.log(COMMAND_HELP[command]);\n } else {\n console.log(HELP);\n }\n return;\n }\n\n if (COMMAND_HELP[command] && flags.help) {\n console.log(COMMAND_HELP[command]);\n return;\n }\n\n try {\n switch (command) {\n case 'init': {\n // init doesn't need an existing project root — use cwd\n const { initCommand } = await import('./commands/init');\n await initCommand(process.cwd(), { yes: flags.yes === true });\n break;\n }\n case 'dev': {\n const projectRoot = resolveProjectRoot();\n const { devCommand } = await import('./commands/dev');\n const port = flags.port ? Number(flags.port) : undefined;\n await devCommand(projectRoot, { port });\n break;\n }\n case 'types:gen': {\n const projectRoot = resolveProjectRoot();\n const { typesGenCommand } = await import('./commands/typesGen');\n await typesGenCommand(projectRoot);\n break;\n }\n case 'validate': {\n const projectRoot = resolveProjectRoot();\n const { validateCommand } = await import('./commands/validate');\n await validateCommand(projectRoot);\n break;\n }\n case 'update': {\n const projectRoot = resolveProjectRoot();\n const { updateCommand } = await import('./commands/update');\n await updateCommand(projectRoot);\n break;\n }\n case 'agent-docs': {\n const projectRoot = resolveProjectRoot();\n const { agentDocsCommand } = await import('./commands/agentDocs');\n await agentDocsCommand(projectRoot);\n break;\n }\n default:\n log.error(`Unknown command: ${command}`);\n console.log(HELP);\n process.exitCode = 1;\n }\n } catch (e) {\n log.error((e as Error).message);\n process.exitCode = 1;\n }\n}\n\nmain();\n"],"mappings":"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","names":[]}
|
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
octoConfigTemplate,
|
|
15
15
|
readmeTemplate,
|
|
16
16
|
tsconfigPaths
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-33VA3IFB.js";
|
|
18
18
|
import {
|
|
19
19
|
log
|
|
20
20
|
} from "./chunk-33PHLOAE.js";
|
|
@@ -190,4 +190,4 @@ async function initCommand(projectRoot, options = {}) {
|
|
|
190
190
|
export {
|
|
191
191
|
initCommand
|
|
192
192
|
};
|
|
193
|
-
//# sourceMappingURL=init-
|
|
193
|
+
//# sourceMappingURL=init-RQVF5KUT.js.map
|
|
@@ -214,7 +214,7 @@ export const query = createQuery<EntryMap, OctoConfig>(configOctoCMS as unknown
|
|
|
214
214
|
}
|
|
215
215
|
function generateConfigInit() {
|
|
216
216
|
return CODEGEN_BANNER + `import { configOctoCMS } from '../octocms.config';
|
|
217
|
-
import { setConfig } from 'octocms/
|
|
217
|
+
import { setConfig } from 'octocms/lib/configStore';
|
|
218
218
|
|
|
219
219
|
setConfig(configOctoCMS);
|
|
220
220
|
`;
|
|
@@ -256,4 +256,4 @@ async function typesGenCommand(projectRoot) {
|
|
|
256
256
|
export {
|
|
257
257
|
typesGenCommand
|
|
258
258
|
};
|
|
259
|
-
//# sourceMappingURL=typesGen-
|
|
259
|
+
//# sourceMappingURL=typesGen-RDG5SY5R.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../cli/commands/typesGen.ts","../cli/lib/codegen.ts"],"sourcesContent":["/**\n * `octocms types:gen` — Generate TypeScript types from next.config.ts.\n *\n * Produces `cms/__generated__/types.ts`, `enums.ts`, `content.d.ts`, and `index.ts`.\n * This is the CLI equivalent of `npm run types:gen`.\n */\n\nimport { mkdirSync, writeFileSync } from 'fs';\nimport { join } from 'path';\n\nimport {\n generateConfigInit,\n generateContentDecls,\n generateEnums,\n generateIndex,\n generateQuery,\n generateTypes,\n} from '../lib/codegen';\nimport { log } from '../lib/logger';\nimport { loadCollections, loadFieldTypes, loadProjectConfig } from '../lib/project';\nimport { validateConfig } from '../lib/validateConfig';\n\nexport async function typesGenCommand(projectRoot: string): Promise<void> {\n log.header('Generate types');\n\n const config = await loadProjectConfig(projectRoot);\n const collections = await loadCollections(projectRoot);\n const fieldTypes = await loadFieldTypes(projectRoot);\n\n log.info('Validating config...');\n try {\n validateConfig(config, collections);\n } catch (e) {\n log.error(String((e as Error).message));\n process.exitCode = 1;\n return;\n }\n log.success(`${collections.length} collections validated`);\n\n log.blank();\n log.info('Generating types...');\n\n const generatedDir = join(projectRoot, 'cms', '__generated__');\n mkdirSync(generatedDir, { recursive: true });\n\n const files = [\n { name: 'types.ts', content: generateTypes(config, collections) },\n { name: 'enums.ts', content: generateEnums(config, collections, fieldTypes) },\n { name: 'content.d.ts', content: generateContentDecls(config, collections) },\n { name: 'index.ts', content: generateIndex() },\n { name: 'query.ts', content: generateQuery() },\n { name: 'configInit.ts', content: generateConfigInit() },\n ];\n\n for (const file of files) {\n writeFileSync(join(generatedDir, file.name), file.content, 'utf8');\n log.success(`cms/__generated__/${file.name}`);\n }\n\n log.blank();\n}\n","/**\n * Type generation functions — pure functions that produce TypeScript source strings.\n *\n * Moved here from `scripts/generate-types.ts` as part of Phase 4 (CLI).\n * The script now imports these functions; the CLI `types:gen` command calls them directly.\n */\n\nimport type { CollectionField, Config, ConditionalBranchConfig } from '../../types';\n\nexport const CODEGEN_BANNER = `/*\n * AUTO-GENERATED — DO NOT EDIT.\n * Generated from cms/octocms.config.ts.\n * Run \\`npx octocms types:gen\\` to regenerate.\n */\n\n`;\n\n/** Capitalize the first letter of a string: `post` → `Post`, `homePage` → `HomePage`. */\nexport function pascalCase(s: string): string {\n return s.charAt(0).toUpperCase() + s.slice(1);\n}\n\n/** Build the TypeScript type string for a single field definition. */\nexport function fieldToTSType(\n field: CollectionField,\n collectionNames: readonly string[],\n mode: 'resolved' | 'raw' = 'resolved',\n): string {\n switch (field.format) {\n case 'string':\n return field.list ? 'string[]' : 'string';\n case 'text':\n case 'markdown':\n case 'slug':\n case 'url':\n case 'color':\n return 'string';\n case 'richtext':\n return 'RichTextDocument';\n case 'boolean':\n return \"'true' | 'false'\";\n case 'number':\n return 'number | null';\n case 'datetime':\n return 'string | null';\n case 'image':\n return mode === 'raw' ? 'string' : 'ResolvedImageField';\n case 'json':\n return 'unknown';\n case 'select': {\n const union = field.options.map((o) => `'${o.value}'`).join(' | ');\n if (field.multiple) {\n return field.options.length > 1 ? `(${union})[]` : `${union}[]`;\n }\n return union;\n }\n case 'reference': {\n if (mode === 'raw') {\n const cardinality = field.reference?.cardinality ?? 'many';\n return cardinality === 'one' ? 'string' : 'string';\n }\n return referenceFieldType(field, collectionNames);\n }\n case 'conditional': {\n if (mode === 'raw') {\n return 'unknown';\n }\n return conditionalFieldType(field, collectionNames);\n }\n default:\n return 'unknown';\n }\n}\n\nfunction referenceFieldType(\n field: Extract<CollectionField, { format: 'reference' }>,\n collectionNames: readonly string[],\n): string {\n const cols = field.reference?.collections ?? (field.collection ? [field.collection] : [...collectionNames]);\n const entryTypes = cols.map((c) => `${pascalCase(c)}Entry`);\n const union = entryTypes.length > 1 ? entryTypes.join(' | ') : entryTypes[0];\n const cardinality = field.reference?.cardinality ?? 'many';\n if (cardinality === 'one') {\n return entryTypes.length > 1 ? `(${union}) | null` : `${union} | null`;\n }\n return entryTypes.length > 1 ? `(${union})[]` : `${union}[]`;\n}\n\nfunction conditionalFieldType(\n field: Extract<CollectionField, { format: 'conditional' }>,\n collectionNames: readonly string[],\n): string {\n const branchTypes = field.conditional.branches.map((branch) => branchValueType(branch, collectionNames));\n return branchTypes.join(' | ');\n}\n\nfunction branchValueType(branch: ConditionalBranchConfig, collectionNames: readonly string[]): string {\n if ('collection' in branch && typeof branch.collection === 'string') {\n return `${pascalCase(branch.collection)}Entry`;\n }\n if (branch.fields) {\n const entries = Object.entries(branch.fields);\n if (entries.length === 0) return '{}';\n const props = entries.map(([name, f]) => ` ${name}: ${fieldToTSType(f, collectionNames)};`);\n return `{\\n${props.join('\\n')}\\n}`;\n }\n return 'unknown';\n}\n\n// ---------------------------------------------------------------------------\n// Generators\n// ---------------------------------------------------------------------------\n\nexport function generateTypes(cfg: Config, collectionNames: readonly string[]): string {\n const lines: string[] = [\n CODEGEN_BANNER + \"import type { EntryStatus, ResolvedImageField } from 'octocms/types';\",\n '',\n ];\n\n // Emit Fields interfaces\n for (const key of collectionNames) {\n const col = cfg.collections[key as keyof typeof cfg.collections];\n const pascal = pascalCase(key);\n lines.push(`export interface ${pascal}Fields {`);\n for (const [fieldName, field] of Object.entries(col.fields)) {\n const tsType = fieldToTSType(field, collectionNames);\n lines.push(` ${fieldName}: ${tsType};`);\n }\n lines.push('}');\n lines.push('');\n }\n\n // Emit Entry interfaces\n for (const key of collectionNames) {\n const pascal = pascalCase(key);\n lines.push(`export interface ${pascal}Entry {`);\n lines.push(` sys: { id: string; type: '${key}'; status: EntryStatus };`);\n lines.push(` fields: ${pascal}Fields;`);\n lines.push('}');\n lines.push('');\n }\n\n // AnyEntry union\n const entryNames = collectionNames.map((k) => `${pascalCase(k)}Entry`);\n lines.push(`export type AnyEntry = ${entryNames.join(' | ')};`);\n lines.push('');\n\n // EntryMap\n lines.push('export type EntryMap = {');\n for (const key of collectionNames) {\n lines.push(` ${key}: ${pascalCase(key)}Entry;`);\n }\n lines.push('};');\n lines.push('');\n\n return lines.join('\\n');\n}\n\nexport function generateEnums(cfg: Config, collectionNames: readonly string[], fieldTypes: readonly string[]): string {\n const lines: string[] = [];\n\n // CollectionName const object\n lines.push('export const CollectionName = {');\n for (const key of collectionNames) {\n lines.push(` ${pascalCase(key)}: '${key}',`);\n }\n lines.push('} as const;');\n lines.push('export type CollectionName = (typeof CollectionName)[keyof typeof CollectionName];');\n lines.push('');\n\n // COLLECTION_NAMES array\n lines.push(`export const COLLECTION_NAMES = [${collectionNames.map((k) => `'${k}'`).join(', ')}] as const;`);\n lines.push('');\n\n // Select option enums per collection\n for (const key of collectionNames) {\n const col = cfg.collections[key as keyof typeof cfg.collections];\n for (const [fieldName, field] of Object.entries(col.fields)) {\n if (field.format !== 'select') continue;\n const enumName = `${pascalCase(key)}${pascalCase(fieldName)}Option`;\n lines.push(`export const ${enumName} = {`);\n for (const opt of field.options) {\n lines.push(` ${pascalCase(opt.value)}: '${opt.value}',`);\n }\n lines.push('} as const;');\n lines.push(`export type ${enumName} = (typeof ${enumName})[keyof typeof ${enumName}];`);\n lines.push('');\n }\n }\n\n // FieldFormat const object\n lines.push('export const FieldFormat = {');\n for (const ft of fieldTypes) {\n lines.push(` ${pascalCase(ft)}: '${ft}',`);\n }\n lines.push('} as const;');\n lines.push('export type FieldFormat = (typeof FieldFormat)[keyof typeof FieldFormat];');\n lines.push('');\n\n return CODEGEN_BANNER + lines.join('\\n');\n}\n\nexport function generateContentDecls(cfg: Config, collectionNames: readonly string[]): string {\n const lines: string[] = [\n CODEGEN_BANNER +\n \"import type { EntryStatus } from 'octocms/types';\\n\\n\" +\n '// Raw on-disk types (before query() processing).\\n' +\n '// Image fields are UUID strings, reference fields are key strings,\\n' +\n '// markdown fields are omitted (stored in companion .md files),\\n' +\n '// richtext fields are omitted (stored in companion .mdx files).\\n',\n ];\n\n for (const key of collectionNames) {\n const col = cfg.collections[key as keyof typeof cfg.collections];\n const pascal = pascalCase(key);\n\n lines.push(`export interface Raw${pascal}Fields {`);\n for (const [fieldName, field] of Object.entries(col.fields)) {\n if (field.format === 'markdown' || field.format === 'richtext') continue; // companion files, not in JSON\n const tsType = fieldToTSType(field, collectionNames, 'raw');\n lines.push(` ${fieldName}: ${tsType};`);\n }\n lines.push('}');\n lines.push('');\n\n lines.push(`export interface Raw${pascal}Entry {`);\n lines.push(` sys: { id: string; type: '${key}'; status: EntryStatus };`);\n lines.push(` fields: Raw${pascal}Fields;`);\n lines.push('}');\n lines.push('');\n }\n\n // RawEntryMap\n lines.push('export type RawEntryMap = {');\n for (const key of collectionNames) {\n lines.push(` ${key}: Raw${pascalCase(key)}Entry;`);\n }\n lines.push('};');\n lines.push('');\n\n return lines.join('\\n');\n}\n\nexport function generateIndex(): string {\n return CODEGEN_BANNER + \"export * from './types';\\nexport * from './enums';\\nexport * from './query';\\n\";\n}\n\n/**\n * Generate the app-specific `query.ts` file that binds `createQuery` from `octocms/query`\n * to the app's config and generated `EntryMap` type.\n *\n * This file is emitted to `cms/__generated__/query.ts` by `npm run types:gen`.\n * Consumers import the typed `query` function from `cms/__generated__/query`.\n */\nexport function generateQuery(): string {\n return (\n CODEGEN_BANNER +\n `import { createQuery } from 'octocms/query';\nimport { configOctoCMS, type OctoConfig } from '../octocms.config';\nimport type { EntryMap } from './types';\n\n// configOctoCMS is widened to Config for admin internals; cast back to OctoConfig so\n// createQuery preserves literal collection/field names for type-safe queries.\nexport const query = createQuery<EntryMap, OctoConfig>(configOctoCMS as unknown as OctoConfig);\n`\n );\n}\n\n/**\n * Generate `configInit.ts` — a side-effect module that imports the app config\n * and registers it with the `octocms` config store.\n *\n * Importing this file ensures the singleton is populated even in serverless\n * cold starts where `cms/octocms.config.ts` (and therefore `withOctoCMS`) has not run.\n *\n * Emitted to `cms/__generated__/configInit.ts` by `npm run types:gen`.\n */\nexport function generateConfigInit(): string {\n return (\n CODEGEN_BANNER +\n `import { configOctoCMS } from '../octocms.config';\nimport { setConfig } from 'octocms/config';\n\nsetConfig(configOctoCMS);\n`\n );\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../cli/commands/typesGen.ts","../cli/lib/codegen.ts"],"sourcesContent":["/**\n * `octocms types:gen` — Generate TypeScript types from next.config.ts.\n *\n * Produces `cms/__generated__/types.ts`, `enums.ts`, `content.d.ts`, and `index.ts`.\n * This is the CLI equivalent of `npm run types:gen`.\n */\n\nimport { mkdirSync, writeFileSync } from 'fs';\nimport { join } from 'path';\n\nimport {\n generateConfigInit,\n generateContentDecls,\n generateEnums,\n generateIndex,\n generateQuery,\n generateTypes,\n} from '../lib/codegen';\nimport { log } from '../lib/logger';\nimport { loadCollections, loadFieldTypes, loadProjectConfig } from '../lib/project';\nimport { validateConfig } from '../lib/validateConfig';\n\nexport async function typesGenCommand(projectRoot: string): Promise<void> {\n log.header('Generate types');\n\n const config = await loadProjectConfig(projectRoot);\n const collections = await loadCollections(projectRoot);\n const fieldTypes = await loadFieldTypes(projectRoot);\n\n log.info('Validating config...');\n try {\n validateConfig(config, collections);\n } catch (e) {\n log.error(String((e as Error).message));\n process.exitCode = 1;\n return;\n }\n log.success(`${collections.length} collections validated`);\n\n log.blank();\n log.info('Generating types...');\n\n const generatedDir = join(projectRoot, 'cms', '__generated__');\n mkdirSync(generatedDir, { recursive: true });\n\n const files = [\n { name: 'types.ts', content: generateTypes(config, collections) },\n { name: 'enums.ts', content: generateEnums(config, collections, fieldTypes) },\n { name: 'content.d.ts', content: generateContentDecls(config, collections) },\n { name: 'index.ts', content: generateIndex() },\n { name: 'query.ts', content: generateQuery() },\n { name: 'configInit.ts', content: generateConfigInit() },\n ];\n\n for (const file of files) {\n writeFileSync(join(generatedDir, file.name), file.content, 'utf8');\n log.success(`cms/__generated__/${file.name}`);\n }\n\n log.blank();\n}\n","/**\n * Type generation functions — pure functions that produce TypeScript source strings.\n *\n * Moved here from `scripts/generate-types.ts` as part of Phase 4 (CLI).\n * The script now imports these functions; the CLI `types:gen` command calls them directly.\n */\n\nimport type { CollectionField, Config, ConditionalBranchConfig } from '../../types';\n\nexport const CODEGEN_BANNER = `/*\n * AUTO-GENERATED — DO NOT EDIT.\n * Generated from cms/octocms.config.ts.\n * Run \\`npx octocms types:gen\\` to regenerate.\n */\n\n`;\n\n/** Capitalize the first letter of a string: `post` → `Post`, `homePage` → `HomePage`. */\nexport function pascalCase(s: string): string {\n return s.charAt(0).toUpperCase() + s.slice(1);\n}\n\n/** Build the TypeScript type string for a single field definition. */\nexport function fieldToTSType(\n field: CollectionField,\n collectionNames: readonly string[],\n mode: 'resolved' | 'raw' = 'resolved',\n): string {\n switch (field.format) {\n case 'string':\n return field.list ? 'string[]' : 'string';\n case 'text':\n case 'markdown':\n case 'slug':\n case 'url':\n case 'color':\n return 'string';\n case 'richtext':\n return 'RichTextDocument';\n case 'boolean':\n return \"'true' | 'false'\";\n case 'number':\n return 'number | null';\n case 'datetime':\n return 'string | null';\n case 'image':\n return mode === 'raw' ? 'string' : 'ResolvedImageField';\n case 'json':\n return 'unknown';\n case 'select': {\n const union = field.options.map((o) => `'${o.value}'`).join(' | ');\n if (field.multiple) {\n return field.options.length > 1 ? `(${union})[]` : `${union}[]`;\n }\n return union;\n }\n case 'reference': {\n if (mode === 'raw') {\n const cardinality = field.reference?.cardinality ?? 'many';\n return cardinality === 'one' ? 'string' : 'string';\n }\n return referenceFieldType(field, collectionNames);\n }\n case 'conditional': {\n if (mode === 'raw') {\n return 'unknown';\n }\n return conditionalFieldType(field, collectionNames);\n }\n default:\n return 'unknown';\n }\n}\n\nfunction referenceFieldType(\n field: Extract<CollectionField, { format: 'reference' }>,\n collectionNames: readonly string[],\n): string {\n const cols = field.reference?.collections ?? (field.collection ? [field.collection] : [...collectionNames]);\n const entryTypes = cols.map((c) => `${pascalCase(c)}Entry`);\n const union = entryTypes.length > 1 ? entryTypes.join(' | ') : entryTypes[0];\n const cardinality = field.reference?.cardinality ?? 'many';\n if (cardinality === 'one') {\n return entryTypes.length > 1 ? `(${union}) | null` : `${union} | null`;\n }\n return entryTypes.length > 1 ? `(${union})[]` : `${union}[]`;\n}\n\nfunction conditionalFieldType(\n field: Extract<CollectionField, { format: 'conditional' }>,\n collectionNames: readonly string[],\n): string {\n const branchTypes = field.conditional.branches.map((branch) => branchValueType(branch, collectionNames));\n return branchTypes.join(' | ');\n}\n\nfunction branchValueType(branch: ConditionalBranchConfig, collectionNames: readonly string[]): string {\n if ('collection' in branch && typeof branch.collection === 'string') {\n return `${pascalCase(branch.collection)}Entry`;\n }\n if (branch.fields) {\n const entries = Object.entries(branch.fields);\n if (entries.length === 0) return '{}';\n const props = entries.map(([name, f]) => ` ${name}: ${fieldToTSType(f, collectionNames)};`);\n return `{\\n${props.join('\\n')}\\n}`;\n }\n return 'unknown';\n}\n\n// ---------------------------------------------------------------------------\n// Generators\n// ---------------------------------------------------------------------------\n\nexport function generateTypes(cfg: Config, collectionNames: readonly string[]): string {\n const lines: string[] = [\n CODEGEN_BANNER + \"import type { EntryStatus, ResolvedImageField } from 'octocms/types';\",\n '',\n ];\n\n // Emit Fields interfaces\n for (const key of collectionNames) {\n const col = cfg.collections[key as keyof typeof cfg.collections];\n const pascal = pascalCase(key);\n lines.push(`export interface ${pascal}Fields {`);\n for (const [fieldName, field] of Object.entries(col.fields)) {\n const tsType = fieldToTSType(field, collectionNames);\n lines.push(` ${fieldName}: ${tsType};`);\n }\n lines.push('}');\n lines.push('');\n }\n\n // Emit Entry interfaces\n for (const key of collectionNames) {\n const pascal = pascalCase(key);\n lines.push(`export interface ${pascal}Entry {`);\n lines.push(` sys: { id: string; type: '${key}'; status: EntryStatus };`);\n lines.push(` fields: ${pascal}Fields;`);\n lines.push('}');\n lines.push('');\n }\n\n // AnyEntry union\n const entryNames = collectionNames.map((k) => `${pascalCase(k)}Entry`);\n lines.push(`export type AnyEntry = ${entryNames.join(' | ')};`);\n lines.push('');\n\n // EntryMap\n lines.push('export type EntryMap = {');\n for (const key of collectionNames) {\n lines.push(` ${key}: ${pascalCase(key)}Entry;`);\n }\n lines.push('};');\n lines.push('');\n\n return lines.join('\\n');\n}\n\nexport function generateEnums(cfg: Config, collectionNames: readonly string[], fieldTypes: readonly string[]): string {\n const lines: string[] = [];\n\n // CollectionName const object\n lines.push('export const CollectionName = {');\n for (const key of collectionNames) {\n lines.push(` ${pascalCase(key)}: '${key}',`);\n }\n lines.push('} as const;');\n lines.push('export type CollectionName = (typeof CollectionName)[keyof typeof CollectionName];');\n lines.push('');\n\n // COLLECTION_NAMES array\n lines.push(`export const COLLECTION_NAMES = [${collectionNames.map((k) => `'${k}'`).join(', ')}] as const;`);\n lines.push('');\n\n // Select option enums per collection\n for (const key of collectionNames) {\n const col = cfg.collections[key as keyof typeof cfg.collections];\n for (const [fieldName, field] of Object.entries(col.fields)) {\n if (field.format !== 'select') continue;\n const enumName = `${pascalCase(key)}${pascalCase(fieldName)}Option`;\n lines.push(`export const ${enumName} = {`);\n for (const opt of field.options) {\n lines.push(` ${pascalCase(opt.value)}: '${opt.value}',`);\n }\n lines.push('} as const;');\n lines.push(`export type ${enumName} = (typeof ${enumName})[keyof typeof ${enumName}];`);\n lines.push('');\n }\n }\n\n // FieldFormat const object\n lines.push('export const FieldFormat = {');\n for (const ft of fieldTypes) {\n lines.push(` ${pascalCase(ft)}: '${ft}',`);\n }\n lines.push('} as const;');\n lines.push('export type FieldFormat = (typeof FieldFormat)[keyof typeof FieldFormat];');\n lines.push('');\n\n return CODEGEN_BANNER + lines.join('\\n');\n}\n\nexport function generateContentDecls(cfg: Config, collectionNames: readonly string[]): string {\n const lines: string[] = [\n CODEGEN_BANNER +\n \"import type { EntryStatus } from 'octocms/types';\\n\\n\" +\n '// Raw on-disk types (before query() processing).\\n' +\n '// Image fields are UUID strings, reference fields are key strings,\\n' +\n '// markdown fields are omitted (stored in companion .md files),\\n' +\n '// richtext fields are omitted (stored in companion .mdx files).\\n',\n ];\n\n for (const key of collectionNames) {\n const col = cfg.collections[key as keyof typeof cfg.collections];\n const pascal = pascalCase(key);\n\n lines.push(`export interface Raw${pascal}Fields {`);\n for (const [fieldName, field] of Object.entries(col.fields)) {\n if (field.format === 'markdown' || field.format === 'richtext') continue; // companion files, not in JSON\n const tsType = fieldToTSType(field, collectionNames, 'raw');\n lines.push(` ${fieldName}: ${tsType};`);\n }\n lines.push('}');\n lines.push('');\n\n lines.push(`export interface Raw${pascal}Entry {`);\n lines.push(` sys: { id: string; type: '${key}'; status: EntryStatus };`);\n lines.push(` fields: Raw${pascal}Fields;`);\n lines.push('}');\n lines.push('');\n }\n\n // RawEntryMap\n lines.push('export type RawEntryMap = {');\n for (const key of collectionNames) {\n lines.push(` ${key}: Raw${pascalCase(key)}Entry;`);\n }\n lines.push('};');\n lines.push('');\n\n return lines.join('\\n');\n}\n\nexport function generateIndex(): string {\n return CODEGEN_BANNER + \"export * from './types';\\nexport * from './enums';\\nexport * from './query';\\n\";\n}\n\n/**\n * Generate the app-specific `query.ts` file that binds `createQuery` from `octocms/query`\n * to the app's config and generated `EntryMap` type.\n *\n * This file is emitted to `cms/__generated__/query.ts` by `npm run types:gen`.\n * Consumers import the typed `query` function from `cms/__generated__/query`.\n */\nexport function generateQuery(): string {\n return (\n CODEGEN_BANNER +\n `import { createQuery } from 'octocms/query';\nimport { configOctoCMS, type OctoConfig } from '../octocms.config';\nimport type { EntryMap } from './types';\n\n// configOctoCMS is widened to Config for admin internals; cast back to OctoConfig so\n// createQuery preserves literal collection/field names for type-safe queries.\nexport const query = createQuery<EntryMap, OctoConfig>(configOctoCMS as unknown as OctoConfig);\n`\n );\n}\n\n/**\n * Generate `configInit.ts` — a side-effect module that imports the app config\n * and registers it with the `octocms` config store.\n *\n * Importing this file ensures the singleton is populated even in serverless\n * cold starts where `cms/octocms.config.ts` (and therefore `withOctoCMS`) has not run.\n *\n * Emitted to `cms/__generated__/configInit.ts` by `npm run types:gen`.\n */\nexport function generateConfigInit(): string {\n return (\n CODEGEN_BANNER +\n `import { configOctoCMS } from '../octocms.config';\nimport { setConfig } from 'octocms/lib/configStore';\n\nsetConfig(configOctoCMS);\n`\n );\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
adminLayoutTemplate,
|
|
3
3
|
adminPageTemplate
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-33VA3IFB.js";
|
|
5
5
|
import {
|
|
6
6
|
log
|
|
7
7
|
} from "./chunk-33PHLOAE.js";
|
|
@@ -53,4 +53,4 @@ async function updateCommand(projectRoot) {
|
|
|
53
53
|
export {
|
|
54
54
|
updateCommand
|
|
55
55
|
};
|
|
56
|
-
//# sourceMappingURL=update-
|
|
56
|
+
//# sourceMappingURL=update-4Z3OK3TX.js.map
|
package/github-public.ts
ADDED
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { Octokit } from 'octokit';
|
|
2
|
+
|
|
3
|
+
import { getConfig } from './lib/configStore';
|
|
4
|
+
import { ContentSourceError, isContentSourceError, mapGitHubApiErrorToContentSource } from './lib/contentSourceError';
|
|
5
|
+
|
|
6
|
+
export { isProductionMode } from './lib/githubContentMode';
|
|
7
|
+
|
|
8
|
+
const getGitHubConfig = () => ({
|
|
9
|
+
owner: process.env.GITHUB_REPO_OWNER || '',
|
|
10
|
+
repo: process.env.GITHUB_REPO_NAME || '',
|
|
11
|
+
branch: getConfig().git.baseBranch,
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
export const assertGitHubConfig = () => {
|
|
15
|
+
const { owner, repo, branch } = getGitHubConfig();
|
|
16
|
+
|
|
17
|
+
if (!owner || !repo) {
|
|
18
|
+
throw new ContentSourceError(
|
|
19
|
+
'github_config',
|
|
20
|
+
'GitHub repository is not configured. Set environment variables GITHUB_REPO_OWNER and GITHUB_REPO_NAME.',
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return { owner, repo, branch };
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Create public-read Octokit clients.
|
|
29
|
+
*
|
|
30
|
+
* 1) Use CMS_GITHUB_TOKEN when available (private repos / higher rate limits).
|
|
31
|
+
* NOTE: Do NOT use GITHUB_TOKEN — Vercel overrides it with its own system token.
|
|
32
|
+
* 2) Also try unauthenticated reads (public repos) to avoid hard dependency.
|
|
33
|
+
*/
|
|
34
|
+
export const getPublicOctokits = (): Octokit[] => {
|
|
35
|
+
const token = process.env.CMS_GITHUB_TOKEN?.trim();
|
|
36
|
+
const clients: Octokit[] = [];
|
|
37
|
+
|
|
38
|
+
if (token) {
|
|
39
|
+
clients.push(new Octokit({ auth: token }));
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
clients.push(new Octokit());
|
|
43
|
+
|
|
44
|
+
return clients;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* When `config.git.publishedPointerBranch` is set, `cms/published.json` is read and written on
|
|
49
|
+
* that branch — use an unprotected branch so Publish avoids a protected base branch.
|
|
50
|
+
*/
|
|
51
|
+
export const getPublishedPointerRef = (): string | undefined => {
|
|
52
|
+
const v = getConfig().git.publishedPointerBranch?.trim();
|
|
53
|
+
return v || undefined;
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Read a file from GitHub using a static server token (no user session required).
|
|
58
|
+
* Used by public pages to fetch content in production.
|
|
59
|
+
*/
|
|
60
|
+
export const readGitHubFilePublic = async (filePath: string, branch?: string): Promise<string | null> => {
|
|
61
|
+
const { owner, repo, branch: configBranch } = assertGitHubConfig();
|
|
62
|
+
const ref = branch ?? configBranch;
|
|
63
|
+
const clients = getPublicOctokits();
|
|
64
|
+
|
|
65
|
+
for (const octokit of clients) {
|
|
66
|
+
try {
|
|
67
|
+
const { data } = await octokit.rest.repos.getContent({
|
|
68
|
+
owner,
|
|
69
|
+
repo,
|
|
70
|
+
path: filePath,
|
|
71
|
+
ref,
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
if ('content' in data && data.type === 'file') {
|
|
75
|
+
return Buffer.from(data.content, 'base64').toString('utf-8');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return null;
|
|
79
|
+
} catch (error: any) {
|
|
80
|
+
if (error.status === 429) {
|
|
81
|
+
throw mapGitHubApiErrorToContentSource(error, { owner, repo, ref });
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (error.status === 401 || error.status === 403) {
|
|
85
|
+
// Try next client (e.g. unauthenticated) before giving up.
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (error.status === 404) {
|
|
90
|
+
// 404 can mean missing file, missing ref, or no repo access.
|
|
91
|
+
// Try next client if available before deciding.
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
throw mapGitHubApiErrorToContentSource(error, { owner, repo, ref });
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// All clients failed — typical for private repos or invalid token permissions.
|
|
100
|
+
throw new ContentSourceError(
|
|
101
|
+
'github_auth',
|
|
102
|
+
`Cannot read ${owner}/${repo} (ref: ${ref}) from GitHub. For private repositories, set CMS_GITHUB_TOKEN with Contents: Read access on this repository.`,
|
|
103
|
+
);
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* List files in a directory from the GitHub repo.
|
|
108
|
+
* Returns an array of file paths.
|
|
109
|
+
*/
|
|
110
|
+
export const listGitHubFiles = async (dirPath: string, extension?: string, branch?: string): Promise<string[]> => {
|
|
111
|
+
const [octokit] = getPublicOctokits();
|
|
112
|
+
const { owner, repo, branch: configBranch } = assertGitHubConfig();
|
|
113
|
+
const ref = branch ?? configBranch;
|
|
114
|
+
|
|
115
|
+
try {
|
|
116
|
+
const { data } = await octokit.rest.repos.getContent({
|
|
117
|
+
owner,
|
|
118
|
+
repo,
|
|
119
|
+
path: dirPath,
|
|
120
|
+
ref,
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
if (!Array.isArray(data)) {
|
|
124
|
+
return [];
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
let files = data.filter((item) => item.type === 'file').map((item) => item.path);
|
|
128
|
+
|
|
129
|
+
if (extension) {
|
|
130
|
+
files = files.filter((f) => f.endsWith(extension));
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
return files;
|
|
134
|
+
} catch (error: any) {
|
|
135
|
+
if (error.status === 404) {
|
|
136
|
+
return [];
|
|
137
|
+
}
|
|
138
|
+
throw mapGitHubApiErrorToContentSource(error, { owner, repo, ref });
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Read cms/published.json to determine which branch public pages read content from.
|
|
144
|
+
* Uses {@link getPublishedPointerRef} when set; otherwise reads from `config.git.baseBranch`.
|
|
145
|
+
* Falls back to base branch on missing file or invalid JSON.
|
|
146
|
+
*/
|
|
147
|
+
export const getPublishedBranch = async (): Promise<string> => {
|
|
148
|
+
const { branch: configBranch } = assertGitHubConfig();
|
|
149
|
+
const pointerRef = getPublishedPointerRef();
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
const content = await readGitHubFilePublic('cms/published.json', pointerRef);
|
|
153
|
+
if (!content) return configBranch;
|
|
154
|
+
const parsed = JSON.parse(content);
|
|
155
|
+
return typeof parsed.branch === 'string' ? parsed.branch : configBranch;
|
|
156
|
+
} catch (e) {
|
|
157
|
+
if (isContentSourceError(e)) throw e;
|
|
158
|
+
return configBranch;
|
|
159
|
+
}
|
|
160
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "octocms",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.6",
|
|
4
4
|
"description": "A file-based CMS for Next.js — schema-driven, Git-backed, no database",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -53,6 +53,7 @@
|
|
|
53
53
|
},
|
|
54
54
|
"./admin/AdminApp": "./admin/AdminApp.tsx",
|
|
55
55
|
"./admin/pages/AdminLayout": "./admin/pages/AdminLayout.tsx",
|
|
56
|
+
"./lib/configStore": "./lib/configStore.ts",
|
|
56
57
|
"./globals.css": "./globals.css",
|
|
57
58
|
"./docs/*": "./docs/*"
|
|
58
59
|
},
|
|
@@ -67,10 +68,12 @@
|
|
|
67
68
|
"components",
|
|
68
69
|
"hooks",
|
|
69
70
|
"lib",
|
|
71
|
+
"utils",
|
|
70
72
|
"index.ts",
|
|
71
73
|
"query.ts",
|
|
72
74
|
"config.ts",
|
|
73
75
|
"defineConfig.ts",
|
|
76
|
+
"github-public.ts",
|
|
74
77
|
"types.ts",
|
|
75
78
|
"withOctoCMS.ts"
|
|
76
79
|
],
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { getConfig } from '../lib/configStore';
|
|
2
|
+
|
|
3
|
+
import { SelectedFile } from '../types';
|
|
4
|
+
|
|
5
|
+
export const parseFileName = (file: string): SelectedFile => {
|
|
6
|
+
const config = getConfig();
|
|
7
|
+
const nameWithoutFolder = file.replace(`${config.contentFolder}/`, '').replace('.json', '');
|
|
8
|
+
const split = nameWithoutFolder.split('/');
|
|
9
|
+
const type = split[0];
|
|
10
|
+
const id = split.pop() as string;
|
|
11
|
+
|
|
12
|
+
return { type, id, path: file };
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const parseMediaFileName = (file: string): SelectedFile => {
|
|
16
|
+
const config = getConfig();
|
|
17
|
+
let nameWithoutFolder = file.replace(`${config.mediaFolder}/`, '');
|
|
18
|
+
(config.mediaAllowedFormats || []).forEach((format) => {
|
|
19
|
+
nameWithoutFolder = nameWithoutFolder.replace(`.${format}`, '');
|
|
20
|
+
});
|
|
21
|
+
const split = nameWithoutFolder.split('/');
|
|
22
|
+
let type = split[0];
|
|
23
|
+
const id = split.pop() as string;
|
|
24
|
+
|
|
25
|
+
if (type === id) {
|
|
26
|
+
type = '/';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return { type, id, path: file };
|
|
30
|
+
};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../cli/lib/templates.ts"],"sourcesContent":["/**\n * File templates used by `octocms init` and `octocms update`.\n */\n\nconst CODEGEN_BANNER = `/*\n * AUTO-GENERATED — DO NOT EDIT.\n * Generated from cms/octocms.config.ts.\n * Run \\`npx octocms types:gen\\` to regenerate.\n */\n\n`;\n\n/** Static cms/__generated__/types.ts for the helloPage demo schema. */\nexport const generatedTypesTemplate =\n CODEGEN_BANNER +\n `import type { EntryStatus } from 'octocms/types';\n\nexport interface HelloPageFields {\n title: string;\n description: string;\n}\n\nexport interface HelloPageEntry {\n sys: { id: string; type: 'helloPage'; status: EntryStatus };\n fields: HelloPageFields;\n}\n\nexport type AnyEntry = HelloPageEntry;\n\nexport type EntryMap = {\n helloPage: HelloPageEntry;\n};\n`;\n\n/** Static cms/__generated__/enums.ts for the helloPage demo schema. */\nexport const generatedEnumsTemplate =\n CODEGEN_BANNER +\n `export const CollectionName = {\n HelloPage: 'helloPage',\n} as const;\nexport type CollectionName = (typeof CollectionName)[keyof typeof CollectionName];\n\nexport const COLLECTION_NAMES = ['helloPage'] as const;\n\nexport const FieldFormat = {\n String: 'string',\n Text: 'text',\n Markdown: 'markdown',\n Boolean: 'boolean',\n Reference: 'reference',\n Image: 'image',\n Number: 'number',\n Datetime: 'datetime',\n Json: 'json',\n Slug: 'slug',\n Select: 'select',\n Url: 'url',\n Color: 'color',\n Conditional: 'conditional',\n Richtext: 'richtext',\n} as const;\nexport type FieldFormat = (typeof FieldFormat)[keyof typeof FieldFormat];\n`;\n\n/** Static cms/__generated__/content.d.ts for the helloPage demo schema. */\nexport const generatedContentDeclsTemplate =\n CODEGEN_BANNER +\n `import type { EntryStatus } from 'octocms/types';\n\n// Raw on-disk types (before query() processing).\nexport interface RawHelloPageFields {\n title: string;\n description: string;\n}\n\nexport interface RawHelloPageEntry {\n sys: { id: string; type: 'helloPage'; status: EntryStatus };\n fields: RawHelloPageFields;\n}\n`;\n\n/** Static cms/__generated__/index.ts — always the same shape. */\nexport const generatedIndexTemplate =\n CODEGEN_BANNER +\n `export * from './types';\nexport * from './enums';\nexport * from './query';\n`;\n\n/** Static cms/__generated__/query.ts — always the same shape (schema-independent). */\nexport const generatedQueryTemplate =\n CODEGEN_BANNER +\n `import { createQuery } from 'octocms/query';\nimport { configOctoCMS, type OctoConfig } from '../octocms.config';\nimport type { EntryMap } from './types';\n\n// configOctoCMS is widened to Config for admin internals; cast back to OctoConfig so\n// createQuery preserves literal collection/field names for type-safe queries.\nexport const query = createQuery<EntryMap, OctoConfig>(configOctoCMS as unknown as OctoConfig);\n`;\n\n/** Static cms/__generated__/configInit.ts — always the same shape (schema-independent). */\nexport const generatedConfigInitTemplate =\n CODEGEN_BANNER +\n `import { configOctoCMS } from '../octocms.config';\nimport { setConfig } from 'octocms/config';\n\nsetConfig(configOctoCMS);\n`;\n\nexport const adminLayoutTemplate = `import '../../cms/__generated__/configInit';\n\nexport { AdminLayout as default, metadata } from 'octocms/admin/pages/AdminLayout';\n`;\n\nexport const adminPageTemplate = `export { AdminApp as default } from 'octocms/admin/AdminApp';\n`;\n\nexport function octoConfigTemplate(opts: { projectName: string; baseBranch: string; pointerBranch?: string }): string {\n const gitBlock = opts.pointerBranch\n ? ` git: {\\n baseBranch: '${opts.baseBranch}',\\n publishedPointerBranch: '${opts.pointerBranch}',\\n },`\n : ` git: { baseBranch: '${opts.baseBranch}' },`;\n\n return `import type { Config } from 'octocms/types';\nimport { defineConfig } from 'octocms/config';\n\nconst _typedConfigOctoCMS = defineConfig({\n projectName: '${opts.projectName}',\n${gitBlock}\n contentFolder: 'cms/content',\n mediaFolder: 'public/media',\n mediaAllowedFormats: ['png', 'jpg', 'jpeg', 'gif', 'webp', 'svg', 'avif'],\n collections: {\n helloPage: {\n label: 'Hello Page',\n fields: {\n title: { label: 'Title', format: 'string', entryTitle: true, required: true },\n description: { label: 'Description', format: 'text' },\n },\n },\n },\n});\n\nexport const configOctoCMS: Config = _typedConfigOctoCMS;\nexport type OctoConfig = typeof _typedConfigOctoCMS;\n`;\n}\n\nexport function nextConfigTemplate(): string {\n return `import type { NextConfig } from 'next';\nimport { withOctoCMS } from 'octocms/config';\nimport { configOctoCMS } from './cms/octocms.config';\n\nexport { configOctoCMS } from './cms/octocms.config';\nexport type { OctoConfig } from './cms/octocms.config';\n\nconst nextConfig: NextConfig = {\n transpilePackages: ['octocms'],\n};\n\nexport default withOctoCMS(nextConfig, configOctoCMS);\n`;\n}\n\nexport function demoHelloPageJson(): string {\n return JSON.stringify(\n {\n sys: { id: '0000', type: 'helloPage', status: 'merged' },\n fields: {\n title: 'Hello World',\n description: 'Welcome to your new OctoCMS site! Edit this content in the CMS admin panel.',\n },\n },\n null,\n 2,\n );\n}\n\nexport const helloPageTemplate = `import { query } from 'cms/__generated__/query';\n\nexport default async function HelloPage() {\n const page = await query('helloPage').first();\n if (!page) return null;\n return (\n <main>\n <h1>{page.fields.title}</h1>\n <p>{page.fields.description}</p>\n </main>\n );\n}\n`;\n\nexport function readmeTemplate(projectName: string): string {\n return `# ${projectName}\n\nBuilt with [OctoCMS](https://octocms.com) — a file-based CMS on Next.js.\n\n## Setup\n\n### 1. Create a GitHub App\n\nFollow the [OctoCMS GitHub App setup guide](https://octocms.com/docs/github-app) to create a GitHub App for authentication.\n\n### 2. Configure environment variables\n\nCopy the values from your GitHub App into \\`.env.local\\`:\n\n\\`\\`\\`bash\n# GitHub App credentials (required for CMS auth)\nGITHUB_ID=your_github_app_client_id\nGITHUB_SECRET=your_github_app_client_secret\n\n# NextAuth (generate secret: openssl rand -base64 32)\nNEXTAUTH_SECRET=your_nextauth_secret\nNEXTAUTH_URL=http://localhost:3000\n\n# GitHub repo for content storage (required in production)\nGITHUB_REPO_OWNER=your_github_username_or_org\nGITHUB_REPO_NAME=your_repo_name\n\n# Optional: static GitHub token for private repos / higher API rate limits\n# CMS_GITHUB_TOKEN=your_github_pat\n\\`\\`\\`\n\n### 3. Run the dev server\n\n\\`\\`\\`bash\nnpm run dev\n\\`\\`\\`\n\nOpen [http://localhost:3000/cms](http://localhost:3000/cms) to access the CMS admin.\n`;\n}\n\nexport function envLocalTemplate(): string {\n return `# GitHub App credentials (required for CMS auth)\n# Create a GitHub App at: https://github.com/settings/apps/new\nGITHUB_ID=\nGITHUB_SECRET=\n\n# NextAuth secret — generate with: openssl rand -base64 32\nNEXTAUTH_SECRET=\nNEXTAUTH_URL=http://localhost:3000\n\n# GitHub repo for content storage (required in production)\nGITHUB_REPO_OWNER=\nGITHUB_REPO_NAME=\n\n# Optional: static GitHub token for private repos or higher API rate limits\n# CMS_GITHUB_TOKEN=\n`;\n}\n\nconst AGENT_DOCS_MARKER = '<!-- octocms:agent-docs -->';\n\nexport function agentsMdSection(): string {\n return `${AGENT_DOCS_MARKER}\n## OctoCMS — AI Content Management\n\nFor tasks that involve creating, editing, or deleting CMS content directly (without the admin UI), read the auto-generated agent docs:\n\n- **\\`octocms/docs/overview.md\\`** — How to find, create, update, and delete content entries via file operations\n- **\\`octocms/docs/schema.md\\`** — Per-collection field definitions, example JSON, and file path conventions\n\nThese docs are generated from \\`cms/octocms.config.ts\\`. Regenerate after schema changes: \\`npm run agent-docs:gen\\`.`;\n}\n\nexport function agentsMdTemplate(): string {\n return `# Project Guidelines\n\n${agentsMdSection()}\n`;\n}\n\nexport function tsconfigPaths(): Record<string, string[]> {\n return {\n 'cms/__generated__': ['./cms/__generated__/index.ts'],\n 'cms/__generated__/*': ['./cms/__generated__/*'],\n '@/*': ['./src/*'],\n };\n}\n"],"mappings":";AAIA,IAAM,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAShB,IAAM,yBACX,iBACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoBK,IAAM,yBACX,iBACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA4BK,IAAM,gCACX,iBACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAeK,IAAM,yBACX,iBACA;AAAA;AAAA;AAAA;AAMK,IAAM,yBACX,iBACA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUK,IAAM,8BACX,iBACA;AAAA;AAAA;AAAA;AAAA;AAMK,IAAM,sBAAsB;AAAA;AAAA;AAAA;AAK5B,IAAM,oBAAoB;AAAA;AAG1B,SAAS,mBAAmB,MAAmF;AACpH,QAAM,WAAW,KAAK,gBAClB;AAAA,mBAA8B,KAAK,UAAU;AAAA,+BAAoC,KAAK,aAAa;AAAA,QACnG,yBAAyB,KAAK,UAAU;AAE5C,SAAO;AAAA;AAAA;AAAA;AAAA,kBAIS,KAAK,WAAW;AAAA,EAChC,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkBV;AAEO,SAAS,qBAA6B;AAC3C,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAaT;AAEO,SAAS,oBAA4B;AAC1C,SAAO,KAAK;AAAA,IACV;AAAA,MACE,KAAK,EAAE,IAAI,QAAQ,MAAM,aAAa,QAAQ,SAAS;AAAA,MACvD,QAAQ;AAAA,QACN,OAAO;AAAA,QACP,aAAa;AAAA,MACf;AAAA,IACF;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;AAEO,IAAM,oBAAoB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAc1B,SAAS,eAAe,aAA6B;AAC1D,SAAO,KAAK,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAuCzB;AAEO,SAAS,mBAA2B;AACzC,SAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgBT;AAEA,IAAM,oBAAoB;AAEnB,SAAS,kBAA0B;AACxC,SAAO,GAAG,iBAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAS7B;AAEO,SAAS,mBAA2B;AACzC,SAAO;AAAA;AAAA,EAEP,gBAAgB,CAAC;AAAA;AAEnB;AAEO,SAAS,gBAA0C;AACxD,SAAO;AAAA,IACL,qBAAqB,CAAC,8BAA8B;AAAA,IACpD,uBAAuB,CAAC,uBAAuB;AAAA,IAC/C,OAAO,CAAC,SAAS;AAAA,EACnB;AACF;","names":[]}
|
|
File without changes
|
|
File without changes
|
|
File without changes
|