@valkyrianlabs/payload-markdown-docs 0.3.1 → 0.4.1
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/README.md +79 -171
- package/dist/admin/DocsSetManager.js +5 -3
- package/dist/admin/DocsSetManager.js.map +1 -1
- package/dist/admin/docsSetManagerData.d.ts +6 -5
- package/dist/admin/docsSetManagerData.js +60 -33
- package/dist/admin/docsSetManagerData.js.map +1 -1
- package/dist/admin/docsSetManagerTypes.d.ts +12 -9
- package/dist/admin/docsSetManagerTypes.js.map +1 -1
- package/dist/cli/commands/manifest.js +1 -2
- package/dist/cli/commands/manifest.js.map +1 -1
- package/dist/cli/commands/plan.js +1 -2
- package/dist/cli/commands/plan.js.map +1 -1
- package/dist/cli/commands/push.js +19 -12
- package/dist/cli/commands/push.js.map +1 -1
- package/dist/cli/commands/validate.js +11 -6
- package/dist/cli/commands/validate.js.map +1 -1
- package/dist/cli/index.js +6 -15
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/parseArgs.js +0 -3
- package/dist/cli/parseArgs.js.map +1 -1
- package/dist/cli/types.d.ts +0 -3
- package/dist/cli/types.js.map +1 -1
- package/dist/collections/docs.js +0 -24
- package/dist/collections/docs.js.map +1 -1
- package/dist/collections/docsGroups.js +8 -9
- package/dist/collections/docsGroups.js.map +1 -1
- package/dist/collections/docsKeys.d.ts +5 -0
- package/dist/collections/docsKeys.js +44 -0
- package/dist/collections/docsKeys.js.map +1 -0
- package/dist/collections/docsSets.js +47 -202
- package/dist/collections/docsSets.js.map +1 -1
- package/dist/collections/docsTrusted.d.ts +5 -0
- package/dist/collections/docsTrusted.js +60 -0
- package/dist/collections/docsTrusted.js.map +1 -0
- package/dist/collections/index.d.ts +4 -0
- package/dist/collections/index.js +2 -0
- package/dist/collections/index.js.map +1 -1
- package/dist/constants.d.ts +3 -1
- package/dist/constants.js +3 -1
- package/dist/constants.js.map +1 -1
- package/dist/endpoints/sync.d.ts +6 -7
- package/dist/endpoints/sync.js +57 -124
- package/dist/endpoints/sync.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/next/PayloadMarkdownDocsPage.js +2 -6
- package/dist/next/PayloadMarkdownDocsPage.js.map +1 -1
- package/dist/next/index.d.ts +2 -0
- package/dist/next/index.js +1 -0
- package/dist/next/index.js.map +1 -1
- package/dist/next/links.d.ts +11 -0
- package/dist/next/links.js +79 -0
- package/dist/next/links.js.map +1 -0
- package/dist/next/markdown.js +91 -19
- package/dist/next/markdown.js.map +1 -1
- package/dist/next/metadata.js +6 -6
- package/dist/next/metadata.js.map +1 -1
- package/dist/next/records.js +13 -23
- package/dist/next/records.js.map +1 -1
- package/dist/next/route.js +141 -49
- package/dist/next/route.js.map +1 -1
- package/dist/next/types.d.ts +0 -14
- package/dist/next/types.js.map +1 -1
- package/dist/payload/docsKeys.d.ts +20 -0
- package/dist/payload/docsKeys.js +29 -0
- package/dist/payload/docsKeys.js.map +1 -0
- package/dist/payload/docsSets.d.ts +32 -6
- package/dist/payload/docsSets.js +146 -83
- package/dist/payload/docsSets.js.map +1 -1
- package/dist/payload/docsTrusted.d.ts +16 -0
- package/dist/payload/docsTrusted.js +49 -0
- package/dist/payload/docsTrusted.js.map +1 -0
- package/dist/payload/index.d.ts +5 -1
- package/dist/payload/index.js +3 -1
- package/dist/payload/index.js.map +1 -1
- package/dist/plugin.js +36 -9
- package/dist/plugin.js.map +1 -1
- package/dist/security/ed25519Keys.d.ts +9 -0
- package/dist/security/ed25519Keys.js +183 -0
- package/dist/security/ed25519Keys.js.map +1 -0
- package/dist/security/githubOidc.d.ts +18 -5
- package/dist/security/githubOidc.js +44 -16
- package/dist/security/githubOidc.js.map +1 -1
- package/dist/security/index.d.ts +2 -1
- package/dist/security/index.js +1 -0
- package/dist/security/index.js.map +1 -1
- package/dist/security/sign.js +3 -12
- package/dist/security/sign.js.map +1 -1
- package/dist/security/verify.js +3 -12
- package/dist/security/verify.js.map +1 -1
- package/dist/skills/codex/SKILL.md +3 -4
- package/dist/skills/codex/examples/github-actions.md +0 -2
- package/dist/skills/codex/reference/admin.md +0 -6
- package/dist/skills/codex/reference/routing.md +2 -1
- package/dist/skills/codex/reference/sync.md +7 -5
- package/dist/skills/codex/reference/troubleshooting.md +3 -4
- package/dist/skills/codex/reference/workflow.md +0 -1
- package/dist/sync/manifest.d.ts +1 -3
- package/dist/sync/manifest.js +2 -3
- package/dist/sync/manifest.js.map +1 -1
- package/dist/sync/validate.js +1 -2
- package/dist/sync/validate.js.map +1 -1
- package/dist/types.d.ts +7 -50
- package/dist/types.js.map +1 -1
- package/package.json +6 -4
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/admin/docsSetManagerData.ts"],"sourcesContent":["import type {\n DocsSetManagerData,\n DocsSetManagerDocItem,\n DocsSetManagerPayloadOperations,\n DocsSetManagerWarning,\n RawDocsRecord,\n RawDocsSetRecord,\n} from './docsSetManagerTypes.js'\n\nimport {\n DEFAULT_DOCS_COLLECTION_SLUG,\n DEFAULT_DOCS_SETS_COLLECTION_SLUG,\n} from '../constants.js'\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n\nconst getRecordId = (doc: unknown): string | undefined => {\n if (!isRecord(doc)) {\n return undefined\n }\n\n if (typeof doc.id === 'string' || typeof doc.id === 'number') {\n return String(doc.id)\n }\n\n return undefined\n}\n\nconst getRelationshipId = (value: unknown): string | undefined => {\n if (typeof value === 'string' || typeof value === 'number') {\n return String(value)\n }\n\n return getRecordId(value)\n}\n\nconst normalizeAdminRoute = (adminRoute = '/admin'): string => {\n const trimmed = adminRoute.trim()\n\n if (!trimmed || trimmed === '/') {\n return '/admin'\n }\n\n return `/${trimmed}`.replace(/\\/+/g, '/').replace(/\\/+$/g, '')\n}\n\nexport const getGeneratedDocAdminURL = ({\n id,\n adminRoute,\n docsCollectionSlug,\n}: {\n adminRoute?: string\n docsCollectionSlug: string\n id: string\n}): string =>\n `${normalizeAdminRoute(adminRoute)}/collections/${docsCollectionSlug}/${encodeURIComponent(id)}`\n\nconst hasText = (value: null | string | undefined): value is string =>\n typeof value === 'string' && value.trim().length > 0\n\nconst getOverrideSummary = (overrides: RawDocsRecord['overrides']): string[] => {\n if (!overrides || !isRecord(overrides)) {\n return []\n }\n\n const summary: string[] = []\n\n if (hasText(overrides.navTitle)) {\n summary.push('Nav title override')\n }\n\n if (overrides.hideFromNav === true) {\n summary.push('Hidden from nav')\n }\n\n if (hasText(overrides.theme)) {\n summary.push('Theme override')\n }\n\n if (\n hasText(overrides.heroEyebrow) ||\n hasText(overrides.heroTitle) ||\n hasText(overrides.heroDescription)\n ) {\n summary.push('Hero override')\n }\n\n if (hasText(overrides.seoTitle) || hasText(overrides.seoDescription)) {\n summary.push('SEO override')\n }\n\n return summary\n}\n\nconst getDocStatus = (\n doc: RawDocsRecord,\n): DocsSetManagerDocItem['status'] => {\n if (doc.sync?.archived === true) {\n return 'archived'\n }\n\n if (doc._status === 'draft') {\n return 'draft'\n }\n\n if (doc._status === 'published') {\n return 'published'\n }\n\n return 'synced'\n}\n\nconst getSourcePathSegments = (sourcePath: string): string[] => {\n const withoutExtension = sourcePath.replace(/\\.md$/i, '')\n const segments = withoutExtension.split('/').filter(Boolean)\n\n if (segments.at(-1) === 'index') {\n return segments.slice(0, -1)\n }\n\n return segments\n}\n\nconst titleCaseSegment = (segment: string): string =>\n segment\n .split(/[-_]+/)\n .filter(Boolean)\n .map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`)\n .join(' ')\n\nconst compareDocItems = (\n first: DocsSetManagerDocItem,\n second: DocsSetManagerDocItem,\n): number => {\n if (first.order !== second.order) {\n return first.order - second.order\n }\n\n if (first.sourcePath !== second.sourcePath) {\n return first.sourcePath.localeCompare(second.sourcePath)\n }\n\n return first.route.localeCompare(second.route)\n}\n\nconst getOrCreateFolder = ({\n items,\n order,\n segment,\n sourcePath,\n}: {\n items: DocsSetManagerDocItem[]\n order: number\n segment: string\n sourcePath: string\n}): DocsSetManagerDocItem => {\n const existing = items.find(\n (item) => item.kind === 'folder' && item.sourcePath === sourcePath,\n )\n\n if (existing) {\n existing.order = Math.min(existing.order, order)\n return existing\n }\n\n const folder: DocsSetManagerDocItem = {\n id: `folder:${sourcePath}`,\n children: [],\n kind: 'folder',\n order,\n overrideSummary: [],\n route: '',\n sourcePath,\n status: 'synced',\n title: titleCaseSegment(segment),\n }\n\n items.push(folder)\n\n return folder\n}\n\nconst insertIntoTree = ({\n item,\n tree,\n}: {\n item: DocsSetManagerDocItem\n tree: DocsSetManagerDocItem[]\n}) => {\n const segments = getSourcePathSegments(item.sourcePath)\n\n if (segments.length <= 1) {\n tree.push(item)\n return\n }\n\n let currentItems = tree\n\n for (const [index, segment] of segments.slice(0, -1).entries()) {\n const sourcePath = segments.slice(0, index + 1).join('/')\n const folder = getOrCreateFolder({\n items: currentItems,\n order: item.order,\n segment,\n sourcePath,\n })\n\n folder.children ??= []\n currentItems = folder.children\n }\n\n currentItems.push(item)\n}\n\nconst sortTree = (items: DocsSetManagerDocItem[]) => {\n items.sort(compareDocItems)\n\n for (const item of items) {\n if (item.children) {\n sortTree(item.children)\n }\n }\n}\n\nconst toDocItem = ({\n adminRoute,\n doc,\n docsCollectionSlug,\n index,\n warnings,\n}: {\n adminRoute?: string\n doc: RawDocsRecord\n docsCollectionSlug: string\n index: number\n warnings: DocsSetManagerWarning[]\n}): DocsSetManagerDocItem => {\n const id = getRecordId(doc) ?? `unknown-${index}`\n const route = hasText(doc.route) ? doc.route : ''\n const sourcePath = hasText(doc.sourcePath)\n ? doc.sourcePath\n : `missing-source-path-${id}`\n const title = hasText(doc.title) ? doc.title : sourcePath\n const status = getDocStatus(doc)\n const overrideSummary = getOverrideSummary(doc.overrides)\n\n if (!hasText(doc.route)) {\n warnings.push({\n docId: id,\n message: 'Generated doc is missing a route.',\n sourcePath,\n })\n }\n\n if (!hasText(doc.sourcePath)) {\n warnings.push({\n docId: id,\n message: 'Generated doc is missing a source path.',\n })\n }\n\n if (!hasText(doc.title)) {\n warnings.push({\n docId: id,\n message: 'Generated doc is missing a title.',\n sourcePath,\n })\n }\n\n return {\n id,\n ...(adminRoute\n ? {\n adminURL: getGeneratedDocAdminURL({\n id,\n adminRoute,\n docsCollectionSlug,\n }),\n }\n : {}),\n archived: status === 'archived',\n draft: status === 'draft',\n hiddenFromNav: doc.overrides?.hideFromNav === true,\n kind: 'doc',\n order: typeof doc.order === 'number' ? doc.order : 0,\n overrideSummary,\n published: status === 'published',\n route,\n sourcePath,\n status,\n title,\n }\n}\n\nexport const buildDocsSetManagerData = ({\n adminRoute,\n docs,\n docsCollectionSlug = DEFAULT_DOCS_COLLECTION_SLUG,\n docsSet,\n}: {\n adminRoute?: string\n docs: RawDocsRecord[]\n docsCollectionSlug?: string\n docsSet: RawDocsSetRecord\n}): DocsSetManagerData => {\n const warnings: DocsSetManagerWarning[] = []\n const docsSetId = getRecordId(docsSet) ?? 'unknown'\n const sortedDocs = docs\n .map((doc, index) =>\n toDocItem({\n adminRoute,\n doc,\n docsCollectionSlug,\n index,\n warnings,\n }),\n )\n .sort(compareDocItems)\n const tree: DocsSetManagerDocItem[] = []\n\n for (const item of sortedDocs) {\n insertIntoTree({\n item,\n tree,\n })\n }\n\n sortTree(tree)\n\n return {\n docs: sortedDocs,\n docsSet: {\n id: docsSetId,\n routeBase: docsSet.routeBase ?? '',\n sourceId: docsSet.sourceId ?? '',\n title: docsSet.title ?? docsSetId,\n },\n summary: {\n archived: sortedDocs.filter((doc) => doc.archived).length,\n drafts: sortedDocs.filter((doc) => doc.draft).length,\n hiddenFromNav: sortedDocs.filter((doc) => doc.hiddenFromNav).length,\n published: sortedDocs.filter((doc) => doc.published).length,\n total: sortedDocs.length,\n withOverrides: sortedDocs.filter((doc) => doc.overrideSummary.length > 0)\n .length,\n },\n sync: docsSet.sync\n ? {\n docsCount:\n typeof docsSet.sync.docsCount === 'number'\n ? docsSet.sync.docsCount\n : undefined,\n lastStatus: docsSet.sync.lastStatus ?? undefined,\n lastSyncedAt: docsSet.sync.lastSyncedAt ?? undefined,\n }\n : undefined,\n tree,\n warnings,\n }\n}\n\nexport const isDocsRecordForDocsSet = ({\n doc,\n docsSetId,\n sourceId,\n}: {\n doc: RawDocsRecord\n docsSetId: string\n sourceId: string\n}): boolean => {\n const docDocsSetId = getRelationshipId(doc.docsSet)\n\n if (docDocsSetId) {\n return docDocsSetId === docsSetId\n }\n\n return doc.sync?.sourceId === sourceId\n}\n\nexport const getDocsSetManagerData = async ({\n adminRoute,\n docsCollectionSlug = DEFAULT_DOCS_COLLECTION_SLUG,\n docsSetId,\n docsSetsCollectionSlug = DEFAULT_DOCS_SETS_COLLECTION_SLUG,\n overrideAccess = true,\n payload,\n}: {\n adminRoute?: string\n docsCollectionSlug?: string\n docsSetId: string\n docsSetsCollectionSlug?: string\n overrideAccess?: boolean\n payload: DocsSetManagerPayloadOperations\n}): Promise<DocsSetManagerData> => {\n const docsSet = (await payload.findByID({\n id: docsSetId,\n collection: docsSetsCollectionSlug,\n depth: 0,\n overrideAccess,\n })) as RawDocsSetRecord\n\n const docsResult = await payload.find({\n collection: docsCollectionSlug,\n depth: 0,\n limit: 1000,\n overrideAccess,\n where: {\n or: [\n {\n docsSet: {\n equals: docsSetId,\n },\n },\n {\n 'sync.sourceId': {\n equals: docsSet.sourceId,\n },\n },\n ],\n },\n })\n const docs = docsResult.docs\n .filter(isRecord)\n .map((doc) => doc as RawDocsRecord)\n .filter((doc) =>\n isDocsRecordForDocsSet({\n doc,\n docsSetId,\n sourceId: docsSet.sourceId ?? '',\n }),\n )\n\n return buildDocsSetManagerData({\n adminRoute,\n docs,\n docsCollectionSlug,\n docsSet,\n })\n}\n"],"names":["DEFAULT_DOCS_COLLECTION_SLUG","DEFAULT_DOCS_SETS_COLLECTION_SLUG","isRecord","value","Array","isArray","getRecordId","doc","undefined","id","String","getRelationshipId","normalizeAdminRoute","adminRoute","trimmed","trim","replace","getGeneratedDocAdminURL","docsCollectionSlug","encodeURIComponent","hasText","length","getOverrideSummary","overrides","summary","navTitle","push","hideFromNav","theme","heroEyebrow","heroTitle","heroDescription","seoTitle","seoDescription","getDocStatus","sync","archived","_status","getSourcePathSegments","sourcePath","withoutExtension","segments","split","filter","Boolean","at","slice","titleCaseSegment","segment","map","part","charAt","toUpperCase","join","compareDocItems","first","second","order","localeCompare","route","getOrCreateFolder","items","existing","find","item","kind","Math","min","folder","children","overrideSummary","status","title","insertIntoTree","tree","currentItems","index","entries","sortTree","sort","toDocItem","warnings","docId","message","adminURL","draft","hiddenFromNav","published","buildDocsSetManagerData","docs","docsSet","docsSetId","sortedDocs","routeBase","sourceId","drafts","total","withOverrides","docsCount","lastStatus","lastSyncedAt","isDocsRecordForDocsSet","docDocsSetId","getDocsSetManagerData","docsSetsCollectionSlug","overrideAccess","payload","findByID","collection","depth","docsResult","limit","where","or","equals"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/admin/docsSetManagerData.ts"],"sourcesContent":["import type {\n DocsSetManagerData,\n DocsSetManagerDocItem,\n DocsSetManagerPayloadOperations,\n DocsSetManagerWarning,\n RawDocsGroupRecord,\n RawDocsRecord,\n RawDocsSetRecord,\n} from './docsSetManagerTypes.js'\n\nimport {\n DEFAULT_DOCS_COLLECTION_SLUG,\n DEFAULT_DOCS_GROUPS_COLLECTION_SLUG,\n DEFAULT_DOCS_SETS_COLLECTION_SLUG,\n} from '../constants.js'\nimport {\n deriveDocsSetRouteBase,\n joinRouteSegments,\n} from '../routing/index.js'\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n\nconst getRecordId = (doc: unknown): string | undefined => {\n if (!isRecord(doc)) {\n return undefined\n }\n\n if (typeof doc.id === 'string' || typeof doc.id === 'number') {\n return String(doc.id)\n }\n\n return undefined\n}\n\nconst getRelationshipId = (value: unknown): string | undefined => {\n if (typeof value === 'string' || typeof value === 'number') {\n return String(value)\n }\n\n return getRecordId(value)\n}\n\nconst normalizeAdminRoute = (adminRoute = '/admin'): string => {\n const trimmed = adminRoute.trim()\n\n if (!trimmed || trimmed === '/') {\n return '/admin'\n }\n\n return `/${trimmed}`.replace(/\\/+/g, '/').replace(/\\/+$/g, '')\n}\n\nexport const getGeneratedDocAdminURL = ({\n id,\n adminRoute,\n docsCollectionSlug,\n}: {\n adminRoute?: string\n docsCollectionSlug: string\n id: string\n}): string =>\n `${normalizeAdminRoute(adminRoute)}/collections/${docsCollectionSlug}/${encodeURIComponent(id)}`\n\nconst hasText = (value: null | string | undefined): value is string =>\n typeof value === 'string' && value.trim().length > 0\n\nconst getOverrideSummary = (overrides: RawDocsRecord['overrides']): string[] => {\n if (!overrides || !isRecord(overrides)) {\n return []\n }\n\n const summary: string[] = []\n\n if (hasText(overrides.navTitle)) {\n summary.push('Nav title override')\n }\n\n if (overrides.hideFromNav === true) {\n summary.push('Hidden from nav')\n }\n\n return summary\n}\n\nconst getDocStatus = (\n doc: RawDocsRecord,\n): DocsSetManagerDocItem['status'] => {\n if (doc.sync?.archived === true) {\n return 'archived'\n }\n\n if (doc._status === 'draft') {\n return 'draft'\n }\n\n if (doc._status === 'published') {\n return 'published'\n }\n\n return 'synced'\n}\n\nconst getSourcePathSegments = (sourcePath: string): string[] => {\n const withoutExtension = sourcePath.replace(/\\.md$/i, '')\n const segments = withoutExtension.split('/').filter(Boolean)\n\n if (segments.at(-1) === 'index') {\n return segments.slice(0, -1)\n }\n\n return segments\n}\n\nconst getGroupRoutePath = ({\n groupId,\n groupsById,\n seen = new Set<string>(),\n}: {\n groupId?: string\n groupsById: Map<string, RawDocsGroupRecord>\n seen?: Set<string>\n}): string | undefined => {\n if (!groupId || seen.has(groupId)) {\n return undefined\n }\n\n const group = groupsById.get(groupId)\n\n if (!group?.slug) {\n return undefined\n }\n\n return joinRouteSegments(\n getGroupRoutePath({\n groupId: getRelationshipId(group.parent),\n groupsById,\n seen: new Set([groupId, ...seen]),\n }),\n group.slug,\n )\n}\n\nconst getDocsSetRouteBase = ({\n docsGroups,\n docsSet,\n}: {\n docsGroups: RawDocsGroupRecord[]\n docsSet: RawDocsSetRecord\n}): string => {\n if (!docsSet.slug) {\n return ''\n }\n\n const groupsById = new Map(\n docsGroups.flatMap((group) => {\n const id = getRecordId(group)\n\n return id ? [[id, group]] : []\n }),\n )\n\n return deriveDocsSetRouteBase({\n docsSetSlug: docsSet.slug,\n groupRoutePath: getGroupRoutePath({\n groupId: getRelationshipId(docsSet.group),\n groupsById,\n }),\n })\n}\n\nconst titleCaseSegment = (segment: string): string =>\n segment\n .split(/[-_]+/)\n .filter(Boolean)\n .map((part) => `${part.charAt(0).toUpperCase()}${part.slice(1)}`)\n .join(' ')\n\nconst compareDocItems = (\n first: DocsSetManagerDocItem,\n second: DocsSetManagerDocItem,\n): number => {\n if (first.order !== second.order) {\n return first.order - second.order\n }\n\n if (first.sourcePath !== second.sourcePath) {\n return first.sourcePath.localeCompare(second.sourcePath)\n }\n\n return first.route.localeCompare(second.route)\n}\n\nconst getOrCreateFolder = ({\n items,\n order,\n segment,\n sourcePath,\n}: {\n items: DocsSetManagerDocItem[]\n order: number\n segment: string\n sourcePath: string\n}): DocsSetManagerDocItem => {\n const existing = items.find(\n (item) => item.kind === 'folder' && item.sourcePath === sourcePath,\n )\n\n if (existing) {\n existing.order = Math.min(existing.order, order)\n return existing\n }\n\n const folder: DocsSetManagerDocItem = {\n id: `folder:${sourcePath}`,\n children: [],\n kind: 'folder',\n order,\n overrideSummary: [],\n route: '',\n sourcePath,\n status: 'synced',\n title: titleCaseSegment(segment),\n }\n\n items.push(folder)\n\n return folder\n}\n\nconst insertIntoTree = ({\n item,\n tree,\n}: {\n item: DocsSetManagerDocItem\n tree: DocsSetManagerDocItem[]\n}) => {\n const segments = getSourcePathSegments(item.sourcePath)\n\n if (segments.length <= 1) {\n tree.push(item)\n return\n }\n\n let currentItems = tree\n\n for (const [index, segment] of segments.slice(0, -1).entries()) {\n const sourcePath = segments.slice(0, index + 1).join('/')\n const folder = getOrCreateFolder({\n items: currentItems,\n order: item.order,\n segment,\n sourcePath,\n })\n\n folder.children ??= []\n currentItems = folder.children\n }\n\n currentItems.push(item)\n}\n\nconst sortTree = (items: DocsSetManagerDocItem[]) => {\n items.sort(compareDocItems)\n\n for (const item of items) {\n if (item.children) {\n sortTree(item.children)\n }\n }\n}\n\nconst toDocItem = ({\n adminRoute,\n doc,\n docsCollectionSlug,\n index,\n warnings,\n}: {\n adminRoute?: string\n doc: RawDocsRecord\n docsCollectionSlug: string\n index: number\n warnings: DocsSetManagerWarning[]\n}): DocsSetManagerDocItem => {\n const id = getRecordId(doc) ?? `unknown-${index}`\n const route = hasText(doc.route) ? doc.route : ''\n const sourcePath = hasText(doc.sourcePath)\n ? doc.sourcePath\n : `missing-source-path-${id}`\n const title = hasText(doc.title) ? doc.title : sourcePath\n const status = getDocStatus(doc)\n const overrideSummary = getOverrideSummary(doc.overrides)\n\n if (!hasText(doc.route)) {\n warnings.push({\n docId: id,\n message: 'Generated doc is missing a route.',\n sourcePath,\n })\n }\n\n if (!hasText(doc.sourcePath)) {\n warnings.push({\n docId: id,\n message: 'Generated doc is missing a source path.',\n })\n }\n\n if (!hasText(doc.title)) {\n warnings.push({\n docId: id,\n message: 'Generated doc is missing a title.',\n sourcePath,\n })\n }\n\n return {\n id,\n ...(adminRoute\n ? {\n adminURL: getGeneratedDocAdminURL({\n id,\n adminRoute,\n docsCollectionSlug,\n }),\n }\n : {}),\n archived: status === 'archived',\n draft: status === 'draft',\n hiddenFromNav: doc.overrides?.hideFromNav === true,\n kind: 'doc',\n order: typeof doc.order === 'number' ? doc.order : 0,\n overrideSummary,\n published: status === 'published',\n route,\n sourcePath,\n status,\n title,\n }\n}\n\nexport const buildDocsSetManagerData = ({\n adminRoute,\n docs,\n docsCollectionSlug = DEFAULT_DOCS_COLLECTION_SLUG,\n docsGroups = [],\n docsSet,\n}: {\n adminRoute?: string\n docs: RawDocsRecord[]\n docsCollectionSlug?: string\n docsGroups?: RawDocsGroupRecord[]\n docsSet: RawDocsSetRecord\n}): DocsSetManagerData => {\n const warnings: DocsSetManagerWarning[] = []\n const docsSetId = getRecordId(docsSet) ?? 'unknown'\n const sortedDocs = docs\n .map((doc, index) =>\n toDocItem({\n adminRoute,\n doc,\n docsCollectionSlug,\n index,\n warnings,\n }),\n )\n .sort(compareDocItems)\n const tree: DocsSetManagerDocItem[] = []\n\n for (const item of sortedDocs) {\n insertIntoTree({\n item,\n tree,\n })\n }\n\n sortTree(tree)\n\n return {\n docs: sortedDocs,\n docsSet: {\n id: docsSetId,\n slug: docsSet.slug ?? '',\n routeBase: getDocsSetRouteBase({\n docsGroups,\n docsSet,\n }),\n title: docsSet.title ?? docsSetId,\n },\n summary: {\n archived: sortedDocs.filter((doc) => doc.archived).length,\n drafts: sortedDocs.filter((doc) => doc.draft).length,\n hiddenFromNav: sortedDocs.filter((doc) => doc.hiddenFromNav).length,\n published: sortedDocs.filter((doc) => doc.published).length,\n total: sortedDocs.length,\n withOverrides: sortedDocs.filter((doc) => doc.overrideSummary.length > 0)\n .length,\n },\n sync: docsSet.sync\n ? {\n docsCount:\n typeof docsSet.sync.docsCount === 'number'\n ? docsSet.sync.docsCount\n : undefined,\n lastStatus: docsSet.sync.lastStatus ?? undefined,\n lastSyncedAt: docsSet.sync.lastSyncedAt ?? undefined,\n }\n : undefined,\n tree,\n warnings,\n }\n}\n\nexport const isDocsRecordForDocsSet = ({\n doc,\n docsSetId,\n}: {\n doc: RawDocsRecord\n docsSetId: string\n}): boolean => {\n const docDocsSetId = getRelationshipId(doc.docsSet)\n\n return docDocsSetId === docsSetId\n}\n\nexport const getDocsSetManagerData = async ({\n adminRoute,\n docsCollectionSlug = DEFAULT_DOCS_COLLECTION_SLUG,\n docsGroupsCollectionSlug = DEFAULT_DOCS_GROUPS_COLLECTION_SLUG,\n docsSetId,\n docsSetsCollectionSlug = DEFAULT_DOCS_SETS_COLLECTION_SLUG,\n overrideAccess = true,\n payload,\n}: {\n adminRoute?: string\n docsCollectionSlug?: string\n docsGroupsCollectionSlug?: string\n docsSetId: string\n docsSetsCollectionSlug?: string\n overrideAccess?: boolean\n payload: DocsSetManagerPayloadOperations\n}): Promise<DocsSetManagerData> => {\n const docsSet = (await payload.findByID({\n id: docsSetId,\n collection: docsSetsCollectionSlug,\n depth: 0,\n overrideAccess,\n })) as RawDocsSetRecord\n\n const docsResult = await payload.find({\n collection: docsCollectionSlug,\n depth: 0,\n limit: 1000,\n overrideAccess,\n where: {\n docsSet: {\n equals: docsSetId,\n },\n },\n })\n const docsGroupsResult = await payload.find({\n collection: docsGroupsCollectionSlug,\n depth: 0,\n limit: 1000,\n overrideAccess,\n })\n const docs = docsResult.docs\n .filter(isRecord)\n .map((doc) => doc as RawDocsRecord)\n .filter((doc) =>\n isDocsRecordForDocsSet({\n doc,\n docsSetId,\n }),\n )\n\n return buildDocsSetManagerData({\n adminRoute,\n docs,\n docsCollectionSlug,\n docsGroups: docsGroupsResult.docs\n .filter(isRecord)\n .map((group) => group as RawDocsGroupRecord),\n docsSet,\n })\n}\n"],"names":["DEFAULT_DOCS_COLLECTION_SLUG","DEFAULT_DOCS_GROUPS_COLLECTION_SLUG","DEFAULT_DOCS_SETS_COLLECTION_SLUG","deriveDocsSetRouteBase","joinRouteSegments","isRecord","value","Array","isArray","getRecordId","doc","undefined","id","String","getRelationshipId","normalizeAdminRoute","adminRoute","trimmed","trim","replace","getGeneratedDocAdminURL","docsCollectionSlug","encodeURIComponent","hasText","length","getOverrideSummary","overrides","summary","navTitle","push","hideFromNav","getDocStatus","sync","archived","_status","getSourcePathSegments","sourcePath","withoutExtension","segments","split","filter","Boolean","at","slice","getGroupRoutePath","groupId","groupsById","seen","Set","has","group","get","slug","parent","getDocsSetRouteBase","docsGroups","docsSet","Map","flatMap","docsSetSlug","groupRoutePath","titleCaseSegment","segment","map","part","charAt","toUpperCase","join","compareDocItems","first","second","order","localeCompare","route","getOrCreateFolder","items","existing","find","item","kind","Math","min","folder","children","overrideSummary","status","title","insertIntoTree","tree","currentItems","index","entries","sortTree","sort","toDocItem","warnings","docId","message","adminURL","draft","hiddenFromNav","published","buildDocsSetManagerData","docs","docsSetId","sortedDocs","routeBase","drafts","total","withOverrides","docsCount","lastStatus","lastSyncedAt","isDocsRecordForDocsSet","docDocsSetId","getDocsSetManagerData","docsGroupsCollectionSlug","docsSetsCollectionSlug","overrideAccess","payload","findByID","collection","depth","docsResult","limit","where","equals","docsGroupsResult"],"mappings":"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"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
export type RawDocsSetRecord = {
|
|
2
|
+
group?: {
|
|
3
|
+
id?: number | string;
|
|
4
|
+
} | null | number | string;
|
|
2
5
|
id?: number | string;
|
|
3
|
-
|
|
4
|
-
sourceId?: string;
|
|
6
|
+
slug?: string;
|
|
5
7
|
sync?: {
|
|
6
8
|
docsCount?: null | number;
|
|
7
9
|
lastStatus?: 'failed' | 'pending' | 'success' | null;
|
|
@@ -9,6 +11,13 @@ export type RawDocsSetRecord = {
|
|
|
9
11
|
};
|
|
10
12
|
title?: string;
|
|
11
13
|
};
|
|
14
|
+
export type RawDocsGroupRecord = {
|
|
15
|
+
id?: number | string;
|
|
16
|
+
parent?: {
|
|
17
|
+
id?: number | string;
|
|
18
|
+
} | null | number | string;
|
|
19
|
+
slug?: string;
|
|
20
|
+
};
|
|
12
21
|
export type RawDocsRecord = {
|
|
13
22
|
_status?: 'draft' | 'published';
|
|
14
23
|
description?: null | string;
|
|
@@ -19,14 +28,8 @@ export type RawDocsRecord = {
|
|
|
19
28
|
navTitle?: null | string;
|
|
20
29
|
order?: null | number;
|
|
21
30
|
overrides?: {
|
|
22
|
-
heroDescription?: null | string;
|
|
23
|
-
heroEyebrow?: null | string;
|
|
24
|
-
heroTitle?: null | string;
|
|
25
31
|
hideFromNav?: boolean | null;
|
|
26
32
|
navTitle?: null | string;
|
|
27
|
-
seoDescription?: null | string;
|
|
28
|
-
seoTitle?: null | string;
|
|
29
|
-
theme?: null | string;
|
|
30
33
|
};
|
|
31
34
|
route?: null | string;
|
|
32
35
|
sourcePath?: null | string;
|
|
@@ -65,7 +68,7 @@ export type DocsSetManagerData = {
|
|
|
65
68
|
docsSet: {
|
|
66
69
|
id: string;
|
|
67
70
|
routeBase: string;
|
|
68
|
-
|
|
71
|
+
slug: string;
|
|
69
72
|
title: string;
|
|
70
73
|
};
|
|
71
74
|
summary: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/admin/docsSetManagerTypes.ts"],"sourcesContent":["export type RawDocsSetRecord = {\n id?: number | string\n
|
|
1
|
+
{"version":3,"sources":["../../src/admin/docsSetManagerTypes.ts"],"sourcesContent":["export type RawDocsSetRecord = {\n group?: { id?: number | string } | null | number | string\n id?: number | string\n slug?: string\n sync?: {\n docsCount?: null | number\n lastStatus?: 'failed' | 'pending' | 'success' | null\n lastSyncedAt?: null | string\n }\n title?: string\n}\n\nexport type RawDocsGroupRecord = {\n id?: number | string\n parent?: { id?: number | string } | null | number | string\n slug?: string\n}\n\nexport type RawDocsRecord = {\n _status?: 'draft' | 'published'\n description?: null | string\n docsSet?: { id?: number | string } | null | number | string\n id?: number | string\n navTitle?: null | string\n order?: null | number\n overrides?: {\n hideFromNav?: boolean | null\n navTitle?: null | string\n }\n route?: null | string\n sourcePath?: null | string\n sync?: {\n archived?: boolean | null\n archivedAt?: null | string\n lastSyncedAt?: null | string\n sourceId?: null | string\n }\n title?: null | string\n}\n\nexport type DocsSetManagerWarning = {\n docId?: string\n message: string\n sourcePath?: string\n}\n\nexport type DocsSetManagerDocStatus =\n | 'archived'\n | 'draft'\n | 'published'\n | 'synced'\n\nexport type DocsSetManagerDocItem = {\n adminURL?: string\n archived?: boolean\n children?: DocsSetManagerDocItem[]\n draft?: boolean\n hiddenFromNav?: boolean\n id: string\n kind: 'doc' | 'folder'\n order: number\n overrideSummary: string[]\n published?: boolean\n route: string\n sourcePath: string\n status: DocsSetManagerDocStatus\n title: string\n}\n\nexport type DocsSetManagerData = {\n docs: DocsSetManagerDocItem[]\n docsSet: {\n id: string\n routeBase: string\n slug: string\n title: string\n }\n summary: {\n archived: number\n drafts: number\n hiddenFromNav: number\n published: number\n total: number\n withOverrides: number\n }\n sync?: {\n docsCount?: number\n lastStatus?: 'failed' | 'pending' | 'success'\n lastSyncedAt?: string\n }\n tree: DocsSetManagerDocItem[]\n warnings: DocsSetManagerWarning[]\n}\n\nexport type DocsSetManagerPayloadOperations = {\n find: (args: {\n collection: string\n depth?: number\n limit?: number\n overrideAccess?: boolean\n where?: unknown\n }) => Promise<{\n docs: unknown[]\n }>\n findByID: (args: {\n collection: string\n depth?: number\n id: number | string\n overrideAccess?: boolean\n }) => Promise<unknown>\n}\n"],"names":[],"mappings":"AA8FA,WAgBC"}
|
|
@@ -26,14 +26,13 @@ export const runManifestCommand = async (args)=>{
|
|
|
26
26
|
commit: options.commit,
|
|
27
27
|
files,
|
|
28
28
|
repository: options.repository,
|
|
29
|
-
root: options.sourceRoot,
|
|
30
29
|
sourceId: options.sourceId
|
|
31
30
|
});
|
|
32
31
|
const validation = validateDocsManifest(manifest, {
|
|
33
32
|
maxFileBytes: options.maxFileBytes,
|
|
34
33
|
maxFiles: options.maxFiles,
|
|
35
34
|
maxTotalBytes: options.maxTotalBytes,
|
|
36
|
-
routeBase: options.
|
|
35
|
+
routeBase: `/${options.sourceId}`
|
|
37
36
|
});
|
|
38
37
|
if (!validation.ok) {
|
|
39
38
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/cli/commands/manifest.ts"],"sourcesContent":["import type { CliResult, ParsedCliArgs } from '../types.js'\n\nimport {\n buildDocsManifest,\n validateDocsManifest,\n} from '../../sync/index.js'\nimport {\n readDocsAiExportManifest,\n walkDocsFiles,\n} from '../filesystem.js'\nimport { formatIssues, printJson } from '../format.js'\nimport { getFlagBoolean } from '../parseArgs.js'\nimport { getDocsCommandOptions } from './validate.js'\n\nexport const runManifestCommand = async (\n args: ParsedCliArgs,\n): Promise<CliResult> => {\n const options = getDocsCommandOptions(args)\n\n if ('exitCode' in options) {\n return options\n }\n\n const files = await walkDocsFiles({\n root: options.docsRoot,\n })\n const aiExport = await readDocsAiExportManifest({\n root: options.docsRoot,\n })\n\n if (!aiExport.ok) {\n return {\n exitCode: 1,\n stderr: `AI export manifest is invalid.\\n\\nErrors:\\n${formatIssues(aiExport.issues)}\\n`,\n }\n }\n\n const manifest = buildDocsManifest({\n aiExport: aiExport.manifest,\n branch: options.branch,\n commit: options.commit,\n files,\n repository: options.repository,\n
|
|
1
|
+
{"version":3,"sources":["../../../src/cli/commands/manifest.ts"],"sourcesContent":["import type { CliResult, ParsedCliArgs } from '../types.js'\n\nimport {\n buildDocsManifest,\n validateDocsManifest,\n} from '../../sync/index.js'\nimport {\n readDocsAiExportManifest,\n walkDocsFiles,\n} from '../filesystem.js'\nimport { formatIssues, printJson } from '../format.js'\nimport { getFlagBoolean } from '../parseArgs.js'\nimport { getDocsCommandOptions } from './validate.js'\n\nexport const runManifestCommand = async (\n args: ParsedCliArgs,\n): Promise<CliResult> => {\n const options = getDocsCommandOptions(args)\n\n if ('exitCode' in options) {\n return options\n }\n\n const files = await walkDocsFiles({\n root: options.docsRoot,\n })\n const aiExport = await readDocsAiExportManifest({\n root: options.docsRoot,\n })\n\n if (!aiExport.ok) {\n return {\n exitCode: 1,\n stderr: `AI export manifest is invalid.\\n\\nErrors:\\n${formatIssues(aiExport.issues)}\\n`,\n }\n }\n\n const manifest = buildDocsManifest({\n aiExport: aiExport.manifest,\n branch: options.branch,\n commit: options.commit,\n files,\n repository: options.repository,\n sourceId: options.sourceId,\n })\n const validation = validateDocsManifest(manifest, {\n maxFileBytes: options.maxFileBytes,\n maxFiles: options.maxFiles,\n maxTotalBytes: options.maxTotalBytes,\n routeBase: `/${options.sourceId}`,\n })\n\n if (!validation.ok) {\n return {\n exitCode: 1,\n stderr: `Manifest is invalid.\\n\\nErrors:\\n${formatIssues(validation.issues)}\\n`,\n }\n }\n\n return {\n exitCode: 0,\n stdout: printJson(manifest, getFlagBoolean(args, 'pretty')),\n }\n}\n"],"names":["buildDocsManifest","validateDocsManifest","readDocsAiExportManifest","walkDocsFiles","formatIssues","printJson","getFlagBoolean","getDocsCommandOptions","runManifestCommand","args","options","files","root","docsRoot","aiExport","ok","exitCode","stderr","issues","manifest","branch","commit","repository","sourceId","validation","maxFileBytes","maxFiles","maxTotalBytes","routeBase","stdout"],"mappings":"AAEA,SACEA,iBAAiB,EACjBC,oBAAoB,QACf,sBAAqB;AAC5B,SACEC,wBAAwB,EACxBC,aAAa,QACR,mBAAkB;AACzB,SAASC,YAAY,EAAEC,SAAS,QAAQ,eAAc;AACtD,SAASC,cAAc,QAAQ,kBAAiB;AAChD,SAASC,qBAAqB,QAAQ,gBAAe;AAErD,OAAO,MAAMC,qBAAqB,OAChCC;IAEA,MAAMC,UAAUH,sBAAsBE;IAEtC,IAAI,cAAcC,SAAS;QACzB,OAAOA;IACT;IAEA,MAAMC,QAAQ,MAAMR,cAAc;QAChCS,MAAMF,QAAQG,QAAQ;IACxB;IACA,MAAMC,WAAW,MAAMZ,yBAAyB;QAC9CU,MAAMF,QAAQG,QAAQ;IACxB;IAEA,IAAI,CAACC,SAASC,EAAE,EAAE;QAChB,OAAO;YACLC,UAAU;YACVC,QAAQ,CAAC,2CAA2C,EAAEb,aAAaU,SAASI,MAAM,EAAE,EAAE,CAAC;QACzF;IACF;IAEA,MAAMC,WAAWnB,kBAAkB;QACjCc,UAAUA,SAASK,QAAQ;QAC3BC,QAAQV,QAAQU,MAAM;QACtBC,QAAQX,QAAQW,MAAM;QACtBV;QACAW,YAAYZ,QAAQY,UAAU;QAC9BC,UAAUb,QAAQa,QAAQ;IAC5B;IACA,MAAMC,aAAavB,qBAAqBkB,UAAU;QAChDM,cAAcf,QAAQe,YAAY;QAClCC,UAAUhB,QAAQgB,QAAQ;QAC1BC,eAAejB,QAAQiB,aAAa;QACpCC,WAAW,CAAC,CAAC,EAAElB,QAAQa,QAAQ,EAAE;IACnC;IAEA,IAAI,CAACC,WAAWT,EAAE,EAAE;QAClB,OAAO;YACLC,UAAU;YACVC,QAAQ,CAAC,iCAAiC,EAAEb,aAAaoB,WAAWN,MAAM,EAAE,EAAE,CAAC;QACjF;IACF;IAEA,OAAO;QACLF,UAAU;QACVa,QAAQxB,UAAUc,UAAUb,eAAeG,MAAM;IACnD;AACF,EAAC"}
|
|
@@ -75,14 +75,13 @@ export const runPlanCommand = async (args)=>{
|
|
|
75
75
|
deleteBehavior,
|
|
76
76
|
files,
|
|
77
77
|
repository: options.repository,
|
|
78
|
-
root: options.sourceRoot,
|
|
79
78
|
sourceId: options.sourceId
|
|
80
79
|
});
|
|
81
80
|
const validation = validateDocsManifest(manifest, {
|
|
82
81
|
maxFileBytes: options.maxFileBytes,
|
|
83
82
|
maxFiles: options.maxFiles,
|
|
84
83
|
maxTotalBytes: options.maxTotalBytes,
|
|
85
|
-
routeBase: options.
|
|
84
|
+
routeBase: `/${options.sourceId}`
|
|
86
85
|
});
|
|
87
86
|
if (!validation.ok) {
|
|
88
87
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/cli/commands/plan.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises'\n\nimport type {\n DocsDeleteBehavior,\n ExistingDocsRecord,\n} from '../../sync/index.js'\nimport type { CliResult, ParsedCliArgs } from '../types.js'\n\nimport {\n buildDocsManifest,\n planDocsSync,\n validateDocsManifest,\n} from '../../sync/index.js'\nimport {\n readDocsAiExportManifest,\n walkDocsFiles,\n} from '../filesystem.js'\nimport { formatIssues, formatPlanSummary, printJson } from '../format.js'\nimport { getFlagBoolean, getFlagString } from '../parseArgs.js'\nimport { getDocsCommandOptions } from './validate.js'\n\nconst deleteBehaviors = new Set<DocsDeleteBehavior>([\n 'archive',\n 'delete',\n 'draft',\n 'ignore',\n])\n\nconst isExistingDocsRecord = (value: unknown): value is ExistingDocsRecord => {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n return false\n }\n\n const record = value as Record<string, unknown>\n\n return (\n typeof record.route === 'string' &&\n typeof record.sourcePath === 'string' &&\n (record.sourceHash === undefined || typeof record.sourceHash === 'string') &&\n (record.title === undefined || typeof record.title === 'string') &&\n (record.archived === undefined || typeof record.archived === 'boolean')\n )\n}\n\nconst loadExistingDocs = async (\n existingPath: string | undefined,\n): Promise<CliResult | ExistingDocsRecord[]> => {\n if (!existingPath) {\n return []\n }\n\n let parsed: unknown\n\n try {\n const raw = await readFile(existingPath, 'utf8')\n parsed = JSON.parse(raw) as unknown\n } catch (error) {\n return {\n exitCode: 1,\n stderr:\n error instanceof Error\n ? `Could not read --existing file: ${error.message}\\n`\n : 'Could not read --existing file.\\n',\n }\n }\n\n if (!Array.isArray(parsed) || !parsed.every(isExistingDocsRecord)) {\n return {\n exitCode: 1,\n stderr: '--existing must point to a JSON array of existing docs records.\\n',\n }\n }\n\n return parsed\n}\n\nexport const runPlanCommand = async (args: ParsedCliArgs): Promise<CliResult> => {\n const options = getDocsCommandOptions(args)\n\n if ('exitCode' in options) {\n return options\n }\n\n const deleteBehaviorFlag = getFlagString(args, 'delete-behavior')\n\n if (\n deleteBehaviorFlag !== undefined &&\n !deleteBehaviors.has(deleteBehaviorFlag as DocsDeleteBehavior)\n ) {\n return {\n exitCode: 1,\n stderr: '--delete-behavior must be archive, delete, draft, or ignore.\\n',\n }\n }\n\n const existing = await loadExistingDocs(getFlagString(args, 'existing'))\n\n if ('exitCode' in existing) {\n return existing\n }\n\n const files = await walkDocsFiles({\n root: options.docsRoot,\n })\n const aiExport = await readDocsAiExportManifest({\n root: options.docsRoot,\n })\n\n if (!aiExport.ok) {\n return {\n exitCode: 1,\n stderr: `AI export manifest is invalid.\\n\\nErrors:\\n${formatIssues(aiExport.issues)}\\n`,\n }\n }\n\n const deleteBehavior = deleteBehaviorFlag as DocsDeleteBehavior | undefined\n const manifest = buildDocsManifest({\n aiExport: aiExport.manifest,\n branch: options.branch,\n commit: options.commit,\n deleteBehavior,\n files,\n repository: options.repository,\n
|
|
1
|
+
{"version":3,"sources":["../../../src/cli/commands/plan.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises'\n\nimport type {\n DocsDeleteBehavior,\n ExistingDocsRecord,\n} from '../../sync/index.js'\nimport type { CliResult, ParsedCliArgs } from '../types.js'\n\nimport {\n buildDocsManifest,\n planDocsSync,\n validateDocsManifest,\n} from '../../sync/index.js'\nimport {\n readDocsAiExportManifest,\n walkDocsFiles,\n} from '../filesystem.js'\nimport { formatIssues, formatPlanSummary, printJson } from '../format.js'\nimport { getFlagBoolean, getFlagString } from '../parseArgs.js'\nimport { getDocsCommandOptions } from './validate.js'\n\nconst deleteBehaviors = new Set<DocsDeleteBehavior>([\n 'archive',\n 'delete',\n 'draft',\n 'ignore',\n])\n\nconst isExistingDocsRecord = (value: unknown): value is ExistingDocsRecord => {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n return false\n }\n\n const record = value as Record<string, unknown>\n\n return (\n typeof record.route === 'string' &&\n typeof record.sourcePath === 'string' &&\n (record.sourceHash === undefined || typeof record.sourceHash === 'string') &&\n (record.title === undefined || typeof record.title === 'string') &&\n (record.archived === undefined || typeof record.archived === 'boolean')\n )\n}\n\nconst loadExistingDocs = async (\n existingPath: string | undefined,\n): Promise<CliResult | ExistingDocsRecord[]> => {\n if (!existingPath) {\n return []\n }\n\n let parsed: unknown\n\n try {\n const raw = await readFile(existingPath, 'utf8')\n parsed = JSON.parse(raw) as unknown\n } catch (error) {\n return {\n exitCode: 1,\n stderr:\n error instanceof Error\n ? `Could not read --existing file: ${error.message}\\n`\n : 'Could not read --existing file.\\n',\n }\n }\n\n if (!Array.isArray(parsed) || !parsed.every(isExistingDocsRecord)) {\n return {\n exitCode: 1,\n stderr: '--existing must point to a JSON array of existing docs records.\\n',\n }\n }\n\n return parsed\n}\n\nexport const runPlanCommand = async (args: ParsedCliArgs): Promise<CliResult> => {\n const options = getDocsCommandOptions(args)\n\n if ('exitCode' in options) {\n return options\n }\n\n const deleteBehaviorFlag = getFlagString(args, 'delete-behavior')\n\n if (\n deleteBehaviorFlag !== undefined &&\n !deleteBehaviors.has(deleteBehaviorFlag as DocsDeleteBehavior)\n ) {\n return {\n exitCode: 1,\n stderr: '--delete-behavior must be archive, delete, draft, or ignore.\\n',\n }\n }\n\n const existing = await loadExistingDocs(getFlagString(args, 'existing'))\n\n if ('exitCode' in existing) {\n return existing\n }\n\n const files = await walkDocsFiles({\n root: options.docsRoot,\n })\n const aiExport = await readDocsAiExportManifest({\n root: options.docsRoot,\n })\n\n if (!aiExport.ok) {\n return {\n exitCode: 1,\n stderr: `AI export manifest is invalid.\\n\\nErrors:\\n${formatIssues(aiExport.issues)}\\n`,\n }\n }\n\n const deleteBehavior = deleteBehaviorFlag as DocsDeleteBehavior | undefined\n const manifest = buildDocsManifest({\n aiExport: aiExport.manifest,\n branch: options.branch,\n commit: options.commit,\n deleteBehavior,\n files,\n repository: options.repository,\n sourceId: options.sourceId,\n })\n const validation = validateDocsManifest(manifest, {\n maxFileBytes: options.maxFileBytes,\n maxFiles: options.maxFiles,\n maxTotalBytes: options.maxTotalBytes,\n routeBase: `/${options.sourceId}`,\n })\n\n if (!validation.ok) {\n return {\n exitCode: 1,\n stderr: `Manifest is invalid.\\n\\nErrors:\\n${formatIssues(validation.issues)}\\n`,\n }\n }\n\n const plan = planDocsSync({\n deleteBehavior,\n desired: validation.data,\n existing,\n })\n\n if (getFlagBoolean(args, 'json')) {\n return {\n exitCode: 0,\n stdout: printJson(plan, getFlagBoolean(args, 'pretty')),\n }\n }\n\n return {\n exitCode: 0,\n stdout: formatPlanSummary(plan),\n }\n}\n"],"names":["readFile","buildDocsManifest","planDocsSync","validateDocsManifest","readDocsAiExportManifest","walkDocsFiles","formatIssues","formatPlanSummary","printJson","getFlagBoolean","getFlagString","getDocsCommandOptions","deleteBehaviors","Set","isExistingDocsRecord","value","Array","isArray","record","route","sourcePath","sourceHash","undefined","title","archived","loadExistingDocs","existingPath","parsed","raw","JSON","parse","error","exitCode","stderr","Error","message","every","runPlanCommand","args","options","deleteBehaviorFlag","has","existing","files","root","docsRoot","aiExport","ok","issues","deleteBehavior","manifest","branch","commit","repository","sourceId","validation","maxFileBytes","maxFiles","maxTotalBytes","routeBase","plan","desired","data","stdout"],"mappings":"AAAA,SAASA,QAAQ,QAAQ,mBAAkB;AAQ3C,SACEC,iBAAiB,EACjBC,YAAY,EACZC,oBAAoB,QACf,sBAAqB;AAC5B,SACEC,wBAAwB,EACxBC,aAAa,QACR,mBAAkB;AACzB,SAASC,YAAY,EAAEC,iBAAiB,EAAEC,SAAS,QAAQ,eAAc;AACzE,SAASC,cAAc,EAAEC,aAAa,QAAQ,kBAAiB;AAC/D,SAASC,qBAAqB,QAAQ,gBAAe;AAErD,MAAMC,kBAAkB,IAAIC,IAAwB;IAClD;IACA;IACA;IACA;CACD;AAED,MAAMC,uBAAuB,CAACC;IAC5B,IAAI,OAAOA,UAAU,YAAYA,UAAU,QAAQC,MAAMC,OAAO,CAACF,QAAQ;QACvE,OAAO;IACT;IAEA,MAAMG,SAASH;IAEf,OACE,OAAOG,OAAOC,KAAK,KAAK,YACxB,OAAOD,OAAOE,UAAU,KAAK,YAC5BF,CAAAA,OAAOG,UAAU,KAAKC,aAAa,OAAOJ,OAAOG,UAAU,KAAK,QAAO,KACvEH,CAAAA,OAAOK,KAAK,KAAKD,aAAa,OAAOJ,OAAOK,KAAK,KAAK,QAAO,KAC7DL,CAAAA,OAAOM,QAAQ,KAAKF,aAAa,OAAOJ,OAAOM,QAAQ,KAAK,SAAQ;AAEzE;AAEA,MAAMC,mBAAmB,OACvBC;IAEA,IAAI,CAACA,cAAc;QACjB,OAAO,EAAE;IACX;IAEA,IAAIC;IAEJ,IAAI;QACF,MAAMC,MAAM,MAAM5B,SAAS0B,cAAc;QACzCC,SAASE,KAAKC,KAAK,CAACF;IACtB,EAAE,OAAOG,OAAO;QACd,OAAO;YACLC,UAAU;YACVC,QACEF,iBAAiBG,QACb,CAAC,gCAAgC,EAAEH,MAAMI,OAAO,CAAC,EAAE,CAAC,GACpD;QACR;IACF;IAEA,IAAI,CAACnB,MAAMC,OAAO,CAACU,WAAW,CAACA,OAAOS,KAAK,CAACtB,uBAAuB;QACjE,OAAO;YACLkB,UAAU;YACVC,QAAQ;QACV;IACF;IAEA,OAAON;AACT;AAEA,OAAO,MAAMU,iBAAiB,OAAOC;IACnC,MAAMC,UAAU5B,sBAAsB2B;IAEtC,IAAI,cAAcC,SAAS;QACzB,OAAOA;IACT;IAEA,MAAMC,qBAAqB9B,cAAc4B,MAAM;IAE/C,IACEE,uBAAuBlB,aACvB,CAACV,gBAAgB6B,GAAG,CAACD,qBACrB;QACA,OAAO;YACLR,UAAU;YACVC,QAAQ;QACV;IACF;IAEA,MAAMS,WAAW,MAAMjB,iBAAiBf,cAAc4B,MAAM;IAE5D,IAAI,cAAcI,UAAU;QAC1B,OAAOA;IACT;IAEA,MAAMC,QAAQ,MAAMtC,cAAc;QAChCuC,MAAML,QAAQM,QAAQ;IACxB;IACA,MAAMC,WAAW,MAAM1C,yBAAyB;QAC9CwC,MAAML,QAAQM,QAAQ;IACxB;IAEA,IAAI,CAACC,SAASC,EAAE,EAAE;QAChB,OAAO;YACLf,UAAU;YACVC,QAAQ,CAAC,2CAA2C,EAAE3B,aAAawC,SAASE,MAAM,EAAE,EAAE,CAAC;QACzF;IACF;IAEA,MAAMC,iBAAiBT;IACvB,MAAMU,WAAWjD,kBAAkB;QACjC6C,UAAUA,SAASI,QAAQ;QAC3BC,QAAQZ,QAAQY,MAAM;QACtBC,QAAQb,QAAQa,MAAM;QACtBH;QACAN;QACAU,YAAYd,QAAQc,UAAU;QAC9BC,UAAUf,QAAQe,QAAQ;IAC5B;IACA,MAAMC,aAAapD,qBAAqB+C,UAAU;QAChDM,cAAcjB,QAAQiB,YAAY;QAClCC,UAAUlB,QAAQkB,QAAQ;QAC1BC,eAAenB,QAAQmB,aAAa;QACpCC,WAAW,CAAC,CAAC,EAAEpB,QAAQe,QAAQ,EAAE;IACnC;IAEA,IAAI,CAACC,WAAWR,EAAE,EAAE;QAClB,OAAO;YACLf,UAAU;YACVC,QAAQ,CAAC,iCAAiC,EAAE3B,aAAaiD,WAAWP,MAAM,EAAE,EAAE,CAAC;QACjF;IACF;IAEA,MAAMY,OAAO1D,aAAa;QACxB+C;QACAY,SAASN,WAAWO,IAAI;QACxBpB;IACF;IAEA,IAAIjC,eAAe6B,MAAM,SAAS;QAChC,OAAO;YACLN,UAAU;YACV+B,QAAQvD,UAAUoD,MAAMnD,eAAe6B,MAAM;QAC/C;IACF;IAEA,OAAO;QACLN,UAAU;QACV+B,QAAQxD,kBAAkBqD;IAC5B;AACF,EAAC"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises';
|
|
2
|
-
import {
|
|
3
|
-
import { signDocsSyncRequest } from '../../security/index.js';
|
|
2
|
+
import { DocsSyncKeyError, signDocsSyncRequest } from '../../security/index.js';
|
|
4
3
|
import { buildDocsManifest, sha256Hex, validateDocsManifest } from '../../sync/index.js';
|
|
5
4
|
import { readDocsAiExportManifest, walkDocsFiles } from '../filesystem.js';
|
|
6
5
|
import { formatIssues, formatPushSummary, printJson } from '../format.js';
|
|
@@ -172,7 +171,6 @@ const getPushCommandOptions = async (args)=>{
|
|
|
172
171
|
return {
|
|
173
172
|
...baseOptions,
|
|
174
173
|
authMode: 'github-oidc',
|
|
175
|
-
oidcAudience: getFlagString(args, 'oidc-audience') ?? DEFAULT_GITHUB_OIDC_AUDIENCE,
|
|
176
174
|
oidcTokenEnv: getFlagString(args, 'oidc-token-env')
|
|
177
175
|
};
|
|
178
176
|
}
|
|
@@ -226,14 +224,13 @@ export const runPushCommand = async (args, httpPost = postJson, httpGet = getJso
|
|
|
226
224
|
mode: options.mode,
|
|
227
225
|
publish: options.publish,
|
|
228
226
|
repository: options.repository,
|
|
229
|
-
root: options.sourceRoot,
|
|
230
227
|
sourceId: options.sourceId
|
|
231
228
|
});
|
|
232
229
|
const validation = validateDocsManifest(manifest, {
|
|
233
230
|
maxFileBytes: options.maxFileBytes,
|
|
234
231
|
maxFiles: options.maxFiles,
|
|
235
232
|
maxTotalBytes: options.maxTotalBytes,
|
|
236
|
-
routeBase: options.
|
|
233
|
+
routeBase: `/${options.sourceId}`
|
|
237
234
|
});
|
|
238
235
|
if (!validation.ok) {
|
|
239
236
|
return {
|
|
@@ -246,7 +243,7 @@ export const runPushCommand = async (args, httpPost = postJson, httpGet = getJso
|
|
|
246
243
|
if (options.authMode === 'github-oidc') {
|
|
247
244
|
const oidcToken = await readGithubOidcToken({
|
|
248
245
|
args,
|
|
249
|
-
audience: options.
|
|
246
|
+
audience: options.sourceId,
|
|
250
247
|
httpGet
|
|
251
248
|
});
|
|
252
249
|
if (typeof oidcToken !== 'string') {
|
|
@@ -261,12 +258,22 @@ export const runPushCommand = async (args, httpPost = postJson, httpGet = getJso
|
|
|
261
258
|
}
|
|
262
259
|
};
|
|
263
260
|
} else {
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
261
|
+
try {
|
|
262
|
+
signedRequest = signDocsSyncRequest({
|
|
263
|
+
body,
|
|
264
|
+
endpoint: options.endpoint,
|
|
265
|
+
keyId: options.keyId,
|
|
266
|
+
privateKey: options.privateKey
|
|
267
|
+
});
|
|
268
|
+
} catch (error) {
|
|
269
|
+
if (error instanceof DocsSyncKeyError) {
|
|
270
|
+
return {
|
|
271
|
+
exitCode: 1,
|
|
272
|
+
stderr: `${error.message}\n`
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
throw error;
|
|
276
|
+
}
|
|
270
277
|
}
|
|
271
278
|
const response = await httpPost({
|
|
272
279
|
body: signedRequest.body,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/cli/commands/push.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises'\n\nimport type { DocsDeleteBehavior } from '../../sync/index.js'\nimport type {\n HttpGetJson,\n HttpPostJson,\n} from '../http.js'\nimport type {\n CliResult,\n ParsedCliArgs,\n PushCommandOptions,\n} from '../types.js'\n\nimport { DEFAULT_GITHUB_OIDC_AUDIENCE } from '../../constants.js'\nimport { signDocsSyncRequest } from '../../security/index.js'\nimport {\n buildDocsManifest,\n sha256Hex,\n validateDocsManifest,\n} from '../../sync/index.js'\nimport {\n readDocsAiExportManifest,\n walkDocsFiles,\n} from '../filesystem.js'\nimport { formatIssues, formatPushSummary, printJson } from '../format.js'\nimport {\n getJson,\n postJson,\n} from '../http.js'\nimport { getFlagBoolean, getFlagString } from '../parseArgs.js'\nimport { getDocsCommandOptions } from './validate.js'\n\nconst supportedPushDeleteBehaviors = new Set<DocsDeleteBehavior>([\n 'archive',\n 'delete',\n 'draft',\n 'ignore',\n])\n\ntype ServerPushResponse = {\n deleteBehavior?: string\n effectivePublishMode?: string\n error?: {\n code?: string\n message?: string\n }\n ok?: boolean\n publishRequested?: boolean\n summary?: {\n archive?: number\n create?: number\n delete?: number\n draft?: number\n unchanged?: number\n update?: number\n warnings?: number\n }\n syncRunId?: string\n}\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n\nconst isServerPushResponse = (value: unknown): value is ServerPushResponse =>\n isRecord(value)\n\nconst validateEndpointUrl = (endpoint: string): CliResult | string => {\n try {\n const parsed = new URL(endpoint)\n\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\n return {\n exitCode: 1,\n stderr: '--endpoint must be a full http:// or https:// URL.\\n',\n }\n }\n\n return parsed.toString()\n } catch {\n return {\n exitCode: 1,\n stderr: '--endpoint must be a valid full http:// or https:// URL.\\n',\n }\n }\n}\n\nconst readPrivateKey = async (\n args: ParsedCliArgs,\n): Promise<CliResult | string> => {\n const privateKeyFile = getFlagString(args, 'private-key-file')\n const privateKeyEnv = getFlagString(args, 'private-key-env')\n\n if (privateKeyFile && privateKeyEnv) {\n return {\n exitCode: 1,\n stderr:\n 'Use either --private-key-file or --private-key-env, not both.\\n',\n }\n }\n\n if (!privateKeyFile && !privateKeyEnv) {\n return {\n exitCode: 1,\n stderr: 'Push requires --private-key-file or --private-key-env.\\n',\n }\n }\n\n if (privateKeyEnv) {\n const privateKey = process.env[privateKeyEnv]\n\n if (!privateKey) {\n return {\n exitCode: 1,\n stderr: `Environment variable \"${privateKeyEnv}\" is not set.\\n`,\n }\n }\n\n return privateKey\n }\n\n try {\n return await readFile(privateKeyFile ?? '', 'utf8')\n } catch (error) {\n return {\n exitCode: 1,\n stderr:\n error instanceof Error\n ? `Could not read private key file: ${error.message}\\n`\n : 'Could not read private key file.\\n',\n }\n }\n}\n\nconst getGithubOidcTokenRequestUrl = ({\n audience,\n requestUrl,\n}: {\n audience: string\n requestUrl: string\n}): CliResult | string => {\n try {\n const url = new URL(requestUrl)\n url.searchParams.set('audience', audience)\n\n return url.toString()\n } catch {\n return {\n exitCode: 1,\n stderr: 'ACTIONS_ID_TOKEN_REQUEST_URL is not a valid URL.\\n',\n }\n }\n}\n\nconst readGithubOidcToken = async ({\n args,\n audience,\n httpGet,\n}: {\n args: ParsedCliArgs\n audience: string\n httpGet: HttpGetJson\n}): Promise<CliResult | string> => {\n const tokenEnv = getFlagString(args, 'oidc-token-env')\n\n if (tokenEnv) {\n const token = process.env[tokenEnv]\n\n if (!token) {\n return {\n exitCode: 1,\n stderr: `Environment variable \"${tokenEnv}\" is not set.\\n`,\n }\n }\n\n return token\n }\n\n const requestUrl = process.env.ACTIONS_ID_TOKEN_REQUEST_URL\n const requestToken = process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN\n\n if (!requestUrl || !requestToken) {\n return {\n exitCode: 1,\n stderr:\n 'GitHub OIDC push requires ACTIONS_ID_TOKEN_REQUEST_URL and ACTIONS_ID_TOKEN_REQUEST_TOKEN, or --oidc-token-env.\\n',\n }\n }\n\n const url = getGithubOidcTokenRequestUrl({\n audience,\n requestUrl,\n })\n\n if (typeof url !== 'string') {\n return url\n }\n\n const response = await httpGet({\n headers: {\n Authorization: `bearer ${requestToken}`,\n },\n url,\n })\n\n if (!response.ok || !isRecord(response.body) || typeof response.body.value !== 'string') {\n return {\n exitCode: 1,\n stderr: `Could not retrieve GitHub OIDC token. HTTP status ${response.status}.\\n`,\n }\n }\n\n return response.body.value\n}\n\nconst getPushCommandOptions = async (\n args: ParsedCliArgs,\n): Promise<CliResult | PushCommandOptions> => {\n const docsOptions = getDocsCommandOptions(args)\n\n if ('exitCode' in docsOptions) {\n return docsOptions\n }\n\n const endpointFlag = getFlagString(args, 'endpoint')\n\n if (!endpointFlag) {\n return {\n exitCode: 1,\n stderr: 'Push requires --endpoint <url>.\\n',\n }\n }\n\n const endpoint = validateEndpointUrl(endpointFlag)\n\n if (typeof endpoint !== 'string') {\n return endpoint\n }\n\n if (getFlagBoolean(args, 'dry-run') && getFlagBoolean(args, 'sync')) {\n return {\n exitCode: 1,\n stderr: 'Use either --dry-run or --sync, not both.\\n',\n }\n }\n\n const deleteBehaviorFlag = getFlagString(args, 'delete-behavior')\n\n if (\n deleteBehaviorFlag !== undefined &&\n !supportedPushDeleteBehaviors.has(deleteBehaviorFlag as DocsDeleteBehavior)\n ) {\n return {\n exitCode: 1,\n stderr: '--delete-behavior for push must be archive, delete, draft, or ignore.\\n',\n }\n }\n\n const mode: PushCommandOptions['mode'] = getFlagBoolean(args, 'sync')\n ? 'sync'\n : 'dry-run'\n const baseOptions = {\n ...docsOptions,\n deleteBehavior: deleteBehaviorFlag as DocsDeleteBehavior | undefined,\n endpoint,\n mode,\n publish: getFlagBoolean(args, 'publish'),\n }\n\n if (getFlagBoolean(args, 'github-oidc')) {\n if (getFlagString(args, 'key-id')) {\n return {\n exitCode: 1,\n stderr: 'Do not use --key-id with --github-oidc.\\n',\n }\n }\n\n if (getFlagString(args, 'private-key-file') || getFlagString(args, 'private-key-env')) {\n return {\n exitCode: 1,\n stderr: 'Do not use Ed25519 private key flags with --github-oidc.\\n',\n }\n }\n\n return {\n ...baseOptions,\n authMode: 'github-oidc',\n oidcAudience:\n getFlagString(args, 'oidc-audience') ?? DEFAULT_GITHUB_OIDC_AUDIENCE,\n oidcTokenEnv: getFlagString(args, 'oidc-token-env'),\n }\n }\n\n const keyId = getFlagString(args, 'key-id')\n\n if (!keyId) {\n return {\n exitCode: 1,\n stderr: 'Push requires --key-id <id>.\\n',\n }\n }\n\n const privateKey = await readPrivateKey(args)\n\n if (typeof privateKey !== 'string') {\n return privateKey\n }\n\n return {\n ...baseOptions,\n authMode: 'ed25519',\n keyId,\n privateKey,\n }\n}\n\nconst formatServerFailure = ({\n body,\n status,\n}: {\n body: unknown\n status: number\n}): string => {\n if (isServerPushResponse(body) && body.error?.message) {\n return `${body.error.message}\\n`\n }\n\n return `Sync request failed with HTTP status ${status}.\\n`\n}\n\nexport const runPushCommand = async (\n args: ParsedCliArgs,\n httpPost: HttpPostJson = postJson,\n httpGet: HttpGetJson = getJson,\n): Promise<CliResult> => {\n const options = await getPushCommandOptions(args)\n\n if ('exitCode' in options) {\n return options\n }\n\n const files = await walkDocsFiles({\n root: options.docsRoot,\n })\n const aiExport = await readDocsAiExportManifest({\n root: options.docsRoot,\n })\n\n if (!aiExport.ok) {\n return {\n exitCode: 1,\n stderr: `AI export manifest is invalid.\\n\\nErrors:\\n${formatIssues(aiExport.issues)}\\n`,\n }\n }\n\n const manifest = buildDocsManifest({\n aiExport: aiExport.manifest,\n branch: options.branch,\n commit: options.commit,\n deleteBehavior: options.deleteBehavior ?? 'archive',\n files,\n mode: options.mode,\n publish: options.publish,\n repository: options.repository,\n root: options.sourceRoot,\n sourceId: options.sourceId,\n })\n const validation = validateDocsManifest(manifest, {\n maxFileBytes: options.maxFileBytes,\n maxFiles: options.maxFiles,\n maxTotalBytes: options.maxTotalBytes,\n routeBase: options.routeBase,\n })\n\n if (!validation.ok) {\n return {\n exitCode: 1,\n stderr: `Manifest is invalid.\\n\\nErrors:\\n${formatIssues(validation.issues)}\\n`,\n }\n }\n\n const body = JSON.stringify(manifest)\n let signedRequest:\n | {\n body: string\n headers: Record<string, string>\n }\n | ReturnType<typeof signDocsSyncRequest>\n\n if (options.authMode === 'github-oidc') {\n const oidcToken = await readGithubOidcToken({\n args,\n audience: options.oidcAudience,\n httpGet,\n })\n\n if (typeof oidcToken !== 'string') {\n return oidcToken\n }\n\n signedRequest = {\n body,\n headers: {\n Authorization: `Bearer ${oidcToken}`,\n 'Content-Type': 'application/json',\n 'X-VL-MD-DOCS-Body-SHA256': sha256Hex(body),\n },\n }\n } else {\n signedRequest = signDocsSyncRequest({\n body,\n endpoint: options.endpoint,\n keyId: options.keyId,\n privateKey: options.privateKey,\n })\n }\n\n const response = await httpPost({\n body: signedRequest.body,\n headers: signedRequest.headers,\n url: options.endpoint,\n })\n\n if (getFlagBoolean(args, 'json')) {\n return {\n exitCode:\n response.ok &&\n isServerPushResponse(response.body) &&\n response.body.ok === true\n ? 0\n : 1,\n stdout: printJson(\n {\n endpoint: options.endpoint,\n mode: options.mode,\n response: response.body,\n sourceId: options.sourceId,\n status: response.status,\n },\n getFlagBoolean(args, 'pretty'),\n ),\n }\n }\n\n if (\n !response.ok ||\n !isServerPushResponse(response.body) ||\n response.body.ok !== true\n ) {\n return {\n exitCode: 1,\n stderr: formatServerFailure({\n body: response.body,\n status: response.status,\n }),\n }\n }\n\n return {\n exitCode: 0,\n stdout: formatPushSummary({\n endpoint: options.endpoint,\n mode: options.mode,\n response: response.body,\n sourceId: options.sourceId,\n }),\n }\n}\n"],"names":["readFile","DEFAULT_GITHUB_OIDC_AUDIENCE","signDocsSyncRequest","buildDocsManifest","sha256Hex","validateDocsManifest","readDocsAiExportManifest","walkDocsFiles","formatIssues","formatPushSummary","printJson","getJson","postJson","getFlagBoolean","getFlagString","getDocsCommandOptions","supportedPushDeleteBehaviors","Set","isRecord","value","Array","isArray","isServerPushResponse","validateEndpointUrl","endpoint","parsed","URL","protocol","exitCode","stderr","toString","readPrivateKey","args","privateKeyFile","privateKeyEnv","privateKey","process","env","error","Error","message","getGithubOidcTokenRequestUrl","audience","requestUrl","url","searchParams","set","readGithubOidcToken","httpGet","tokenEnv","token","ACTIONS_ID_TOKEN_REQUEST_URL","requestToken","ACTIONS_ID_TOKEN_REQUEST_TOKEN","response","headers","Authorization","ok","body","status","getPushCommandOptions","docsOptions","endpointFlag","deleteBehaviorFlag","undefined","has","mode","baseOptions","deleteBehavior","publish","authMode","oidcAudience","oidcTokenEnv","keyId","formatServerFailure","runPushCommand","httpPost","options","files","root","docsRoot","aiExport","issues","manifest","branch","commit","repository","sourceRoot","sourceId","validation","maxFileBytes","maxFiles","maxTotalBytes","routeBase","JSON","stringify","signedRequest","oidcToken","stdout"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/cli/commands/push.ts"],"sourcesContent":["import { readFile } from 'node:fs/promises'\n\nimport type { DocsDeleteBehavior } from '../../sync/index.js'\nimport type {\n HttpGetJson,\n HttpPostJson,\n} from '../http.js'\nimport type {\n CliResult,\n ParsedCliArgs,\n PushCommandOptions,\n} from '../types.js'\n\nimport {\n DocsSyncKeyError,\n signDocsSyncRequest,\n} from '../../security/index.js'\nimport {\n buildDocsManifest,\n sha256Hex,\n validateDocsManifest,\n} from '../../sync/index.js'\nimport {\n readDocsAiExportManifest,\n walkDocsFiles,\n} from '../filesystem.js'\nimport { formatIssues, formatPushSummary, printJson } from '../format.js'\nimport {\n getJson,\n postJson,\n} from '../http.js'\nimport { getFlagBoolean, getFlagString } from '../parseArgs.js'\nimport { getDocsCommandOptions } from './validate.js'\n\nconst supportedPushDeleteBehaviors = new Set<DocsDeleteBehavior>([\n 'archive',\n 'delete',\n 'draft',\n 'ignore',\n])\n\ntype ServerPushResponse = {\n deleteBehavior?: string\n effectivePublishMode?: string\n error?: {\n code?: string\n message?: string\n }\n ok?: boolean\n publishRequested?: boolean\n summary?: {\n archive?: number\n create?: number\n delete?: number\n draft?: number\n unchanged?: number\n update?: number\n warnings?: number\n }\n syncRunId?: string\n}\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n\nconst isServerPushResponse = (value: unknown): value is ServerPushResponse =>\n isRecord(value)\n\nconst validateEndpointUrl = (endpoint: string): CliResult | string => {\n try {\n const parsed = new URL(endpoint)\n\n if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {\n return {\n exitCode: 1,\n stderr: '--endpoint must be a full http:// or https:// URL.\\n',\n }\n }\n\n return parsed.toString()\n } catch {\n return {\n exitCode: 1,\n stderr: '--endpoint must be a valid full http:// or https:// URL.\\n',\n }\n }\n}\n\nconst readPrivateKey = async (\n args: ParsedCliArgs,\n): Promise<CliResult | string> => {\n const privateKeyFile = getFlagString(args, 'private-key-file')\n const privateKeyEnv = getFlagString(args, 'private-key-env')\n\n if (privateKeyFile && privateKeyEnv) {\n return {\n exitCode: 1,\n stderr:\n 'Use either --private-key-file or --private-key-env, not both.\\n',\n }\n }\n\n if (!privateKeyFile && !privateKeyEnv) {\n return {\n exitCode: 1,\n stderr: 'Push requires --private-key-file or --private-key-env.\\n',\n }\n }\n\n if (privateKeyEnv) {\n const privateKey = process.env[privateKeyEnv]\n\n if (!privateKey) {\n return {\n exitCode: 1,\n stderr: `Environment variable \"${privateKeyEnv}\" is not set.\\n`,\n }\n }\n\n return privateKey\n }\n\n try {\n return await readFile(privateKeyFile ?? '', 'utf8')\n } catch (error) {\n return {\n exitCode: 1,\n stderr:\n error instanceof Error\n ? `Could not read private key file: ${error.message}\\n`\n : 'Could not read private key file.\\n',\n }\n }\n}\n\nconst getGithubOidcTokenRequestUrl = ({\n audience,\n requestUrl,\n}: {\n audience: string\n requestUrl: string\n}): CliResult | string => {\n try {\n const url = new URL(requestUrl)\n url.searchParams.set('audience', audience)\n\n return url.toString()\n } catch {\n return {\n exitCode: 1,\n stderr: 'ACTIONS_ID_TOKEN_REQUEST_URL is not a valid URL.\\n',\n }\n }\n}\n\nconst readGithubOidcToken = async ({\n args,\n audience,\n httpGet,\n}: {\n args: ParsedCliArgs\n audience: string\n httpGet: HttpGetJson\n}): Promise<CliResult | string> => {\n const tokenEnv = getFlagString(args, 'oidc-token-env')\n\n if (tokenEnv) {\n const token = process.env[tokenEnv]\n\n if (!token) {\n return {\n exitCode: 1,\n stderr: `Environment variable \"${tokenEnv}\" is not set.\\n`,\n }\n }\n\n return token\n }\n\n const requestUrl = process.env.ACTIONS_ID_TOKEN_REQUEST_URL\n const requestToken = process.env.ACTIONS_ID_TOKEN_REQUEST_TOKEN\n\n if (!requestUrl || !requestToken) {\n return {\n exitCode: 1,\n stderr:\n 'GitHub OIDC push requires ACTIONS_ID_TOKEN_REQUEST_URL and ACTIONS_ID_TOKEN_REQUEST_TOKEN, or --oidc-token-env.\\n',\n }\n }\n\n const url = getGithubOidcTokenRequestUrl({\n audience,\n requestUrl,\n })\n\n if (typeof url !== 'string') {\n return url\n }\n\n const response = await httpGet({\n headers: {\n Authorization: `bearer ${requestToken}`,\n },\n url,\n })\n\n if (!response.ok || !isRecord(response.body) || typeof response.body.value !== 'string') {\n return {\n exitCode: 1,\n stderr: `Could not retrieve GitHub OIDC token. HTTP status ${response.status}.\\n`,\n }\n }\n\n return response.body.value\n}\n\nconst getPushCommandOptions = async (\n args: ParsedCliArgs,\n): Promise<CliResult | PushCommandOptions> => {\n const docsOptions = getDocsCommandOptions(args)\n\n if ('exitCode' in docsOptions) {\n return docsOptions\n }\n\n const endpointFlag = getFlagString(args, 'endpoint')\n\n if (!endpointFlag) {\n return {\n exitCode: 1,\n stderr: 'Push requires --endpoint <url>.\\n',\n }\n }\n\n const endpoint = validateEndpointUrl(endpointFlag)\n\n if (typeof endpoint !== 'string') {\n return endpoint\n }\n\n if (getFlagBoolean(args, 'dry-run') && getFlagBoolean(args, 'sync')) {\n return {\n exitCode: 1,\n stderr: 'Use either --dry-run or --sync, not both.\\n',\n }\n }\n\n const deleteBehaviorFlag = getFlagString(args, 'delete-behavior')\n\n if (\n deleteBehaviorFlag !== undefined &&\n !supportedPushDeleteBehaviors.has(deleteBehaviorFlag as DocsDeleteBehavior)\n ) {\n return {\n exitCode: 1,\n stderr: '--delete-behavior for push must be archive, delete, draft, or ignore.\\n',\n }\n }\n\n const mode: PushCommandOptions['mode'] = getFlagBoolean(args, 'sync')\n ? 'sync'\n : 'dry-run'\n const baseOptions = {\n ...docsOptions,\n deleteBehavior: deleteBehaviorFlag as DocsDeleteBehavior | undefined,\n endpoint,\n mode,\n publish: getFlagBoolean(args, 'publish'),\n }\n\n if (getFlagBoolean(args, 'github-oidc')) {\n if (getFlagString(args, 'key-id')) {\n return {\n exitCode: 1,\n stderr: 'Do not use --key-id with --github-oidc.\\n',\n }\n }\n\n if (getFlagString(args, 'private-key-file') || getFlagString(args, 'private-key-env')) {\n return {\n exitCode: 1,\n stderr: 'Do not use Ed25519 private key flags with --github-oidc.\\n',\n }\n }\n\n return {\n ...baseOptions,\n authMode: 'github-oidc',\n oidcTokenEnv: getFlagString(args, 'oidc-token-env'),\n }\n }\n\n const keyId = getFlagString(args, 'key-id')\n\n if (!keyId) {\n return {\n exitCode: 1,\n stderr: 'Push requires --key-id <id>.\\n',\n }\n }\n\n const privateKey = await readPrivateKey(args)\n\n if (typeof privateKey !== 'string') {\n return privateKey\n }\n\n return {\n ...baseOptions,\n authMode: 'ed25519',\n keyId,\n privateKey,\n }\n}\n\nconst formatServerFailure = ({\n body,\n status,\n}: {\n body: unknown\n status: number\n}): string => {\n if (isServerPushResponse(body) && body.error?.message) {\n return `${body.error.message}\\n`\n }\n\n return `Sync request failed with HTTP status ${status}.\\n`\n}\n\nexport const runPushCommand = async (\n args: ParsedCliArgs,\n httpPost: HttpPostJson = postJson,\n httpGet: HttpGetJson = getJson,\n): Promise<CliResult> => {\n const options = await getPushCommandOptions(args)\n\n if ('exitCode' in options) {\n return options\n }\n\n const files = await walkDocsFiles({\n root: options.docsRoot,\n })\n const aiExport = await readDocsAiExportManifest({\n root: options.docsRoot,\n })\n\n if (!aiExport.ok) {\n return {\n exitCode: 1,\n stderr: `AI export manifest is invalid.\\n\\nErrors:\\n${formatIssues(aiExport.issues)}\\n`,\n }\n }\n\n const manifest = buildDocsManifest({\n aiExport: aiExport.manifest,\n branch: options.branch,\n commit: options.commit,\n deleteBehavior: options.deleteBehavior ?? 'archive',\n files,\n mode: options.mode,\n publish: options.publish,\n repository: options.repository,\n sourceId: options.sourceId,\n })\n const validation = validateDocsManifest(manifest, {\n maxFileBytes: options.maxFileBytes,\n maxFiles: options.maxFiles,\n maxTotalBytes: options.maxTotalBytes,\n routeBase: `/${options.sourceId}`,\n })\n\n if (!validation.ok) {\n return {\n exitCode: 1,\n stderr: `Manifest is invalid.\\n\\nErrors:\\n${formatIssues(validation.issues)}\\n`,\n }\n }\n\n const body = JSON.stringify(manifest)\n let signedRequest:\n | {\n body: string\n headers: Record<string, string>\n }\n | ReturnType<typeof signDocsSyncRequest>\n\n if (options.authMode === 'github-oidc') {\n const oidcToken = await readGithubOidcToken({\n args,\n audience: options.sourceId,\n httpGet,\n })\n\n if (typeof oidcToken !== 'string') {\n return oidcToken\n }\n\n signedRequest = {\n body,\n headers: {\n Authorization: `Bearer ${oidcToken}`,\n 'Content-Type': 'application/json',\n 'X-VL-MD-DOCS-Body-SHA256': sha256Hex(body),\n },\n }\n } else {\n try {\n signedRequest = signDocsSyncRequest({\n body,\n endpoint: options.endpoint,\n keyId: options.keyId,\n privateKey: options.privateKey,\n })\n } catch (error) {\n if (error instanceof DocsSyncKeyError) {\n return {\n exitCode: 1,\n stderr: `${error.message}\\n`,\n }\n }\n\n throw error\n }\n }\n\n const response = await httpPost({\n body: signedRequest.body,\n headers: signedRequest.headers,\n url: options.endpoint,\n })\n\n if (getFlagBoolean(args, 'json')) {\n return {\n exitCode:\n response.ok &&\n isServerPushResponse(response.body) &&\n response.body.ok === true\n ? 0\n : 1,\n stdout: printJson(\n {\n endpoint: options.endpoint,\n mode: options.mode,\n response: response.body,\n sourceId: options.sourceId,\n status: response.status,\n },\n getFlagBoolean(args, 'pretty'),\n ),\n }\n }\n\n if (\n !response.ok ||\n !isServerPushResponse(response.body) ||\n response.body.ok !== true\n ) {\n return {\n exitCode: 1,\n stderr: formatServerFailure({\n body: response.body,\n status: response.status,\n }),\n }\n }\n\n return {\n exitCode: 0,\n stdout: formatPushSummary({\n endpoint: options.endpoint,\n mode: options.mode,\n response: response.body,\n sourceId: options.sourceId,\n }),\n }\n}\n"],"names":["readFile","DocsSyncKeyError","signDocsSyncRequest","buildDocsManifest","sha256Hex","validateDocsManifest","readDocsAiExportManifest","walkDocsFiles","formatIssues","formatPushSummary","printJson","getJson","postJson","getFlagBoolean","getFlagString","getDocsCommandOptions","supportedPushDeleteBehaviors","Set","isRecord","value","Array","isArray","isServerPushResponse","validateEndpointUrl","endpoint","parsed","URL","protocol","exitCode","stderr","toString","readPrivateKey","args","privateKeyFile","privateKeyEnv","privateKey","process","env","error","Error","message","getGithubOidcTokenRequestUrl","audience","requestUrl","url","searchParams","set","readGithubOidcToken","httpGet","tokenEnv","token","ACTIONS_ID_TOKEN_REQUEST_URL","requestToken","ACTIONS_ID_TOKEN_REQUEST_TOKEN","response","headers","Authorization","ok","body","status","getPushCommandOptions","docsOptions","endpointFlag","deleteBehaviorFlag","undefined","has","mode","baseOptions","deleteBehavior","publish","authMode","oidcTokenEnv","keyId","formatServerFailure","runPushCommand","httpPost","options","files","root","docsRoot","aiExport","issues","manifest","branch","commit","repository","sourceId","validation","maxFileBytes","maxFiles","maxTotalBytes","routeBase","JSON","stringify","signedRequest","oidcToken","stdout"],"mappings":"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"}
|
|
@@ -3,8 +3,16 @@ import { buildDocsManifest, validateDocsManifest } from '../../sync/index.js';
|
|
|
3
3
|
import { readDocsAiExportManifest, walkDocsFiles } from '../filesystem.js';
|
|
4
4
|
import { formatValidationSummary, printJson } from '../format.js';
|
|
5
5
|
import { getFlagBoolean, getFlagString, parseIntegerFlag } from '../parseArgs.js';
|
|
6
|
+
const getRepositoryName = (repository)=>{
|
|
7
|
+
if (!repository) {
|
|
8
|
+
return undefined;
|
|
9
|
+
}
|
|
10
|
+
const [, name] = repository.split('/', 2);
|
|
11
|
+
return name ?? repository;
|
|
12
|
+
};
|
|
13
|
+
const getDefaultSourceId = (docsRoot)=>getRepositoryName(process.env.GITHUB_REPOSITORY) ?? (path.basename(path.resolve(docsRoot)) === 'docs' ? 'local-docs' : path.basename(path.resolve(docsRoot)));
|
|
6
14
|
export const getDocsCommandOptions = (args)=>{
|
|
7
|
-
const docsRoot = args.positionals[0]
|
|
15
|
+
const docsRoot = args.positionals[0];
|
|
8
16
|
if (!docsRoot) {
|
|
9
17
|
return {
|
|
10
18
|
exitCode: 1,
|
|
@@ -31,9 +39,7 @@ export const getDocsCommandOptions = (args)=>{
|
|
|
31
39
|
maxFiles: typeof maxFiles === 'number' ? maxFiles : undefined,
|
|
32
40
|
maxTotalBytes: typeof maxTotalBytes === 'number' ? maxTotalBytes : undefined,
|
|
33
41
|
repository: getFlagString(args, 'repository'),
|
|
34
|
-
|
|
35
|
-
sourceId: getFlagString(args, 'source') ?? 'local-docs',
|
|
36
|
-
sourceRoot: getFlagString(args, 'root') ?? path.basename(path.resolve(docsRoot))
|
|
42
|
+
sourceId: getFlagString(args, 'source') ?? getDefaultSourceId(docsRoot)
|
|
37
43
|
};
|
|
38
44
|
};
|
|
39
45
|
export const runValidateCommand = async (args)=>{
|
|
@@ -68,14 +74,13 @@ export const runValidateCommand = async (args)=>{
|
|
|
68
74
|
commit: options.commit,
|
|
69
75
|
files,
|
|
70
76
|
repository: options.repository,
|
|
71
|
-
root: options.sourceRoot,
|
|
72
77
|
sourceId: options.sourceId
|
|
73
78
|
});
|
|
74
79
|
const validation = validateDocsManifest(manifest, {
|
|
75
80
|
maxFileBytes: options.maxFileBytes,
|
|
76
81
|
maxFiles: options.maxFiles,
|
|
77
82
|
maxTotalBytes: options.maxTotalBytes,
|
|
78
|
-
routeBase: options.
|
|
83
|
+
routeBase: `/${options.sourceId}`
|
|
79
84
|
});
|
|
80
85
|
const validationWithReadWarnings = {
|
|
81
86
|
...validation,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/cli/commands/validate.ts"],"sourcesContent":["import path from 'node:path'\n\nimport type {\n CliResult,\n DocsCommandOptions,\n ParsedCliArgs,\n} from '../types.js'\n\nimport {\n buildDocsManifest,\n validateDocsManifest,\n} from '../../sync/index.js'\nimport {\n readDocsAiExportManifest,\n walkDocsFiles,\n} from '../filesystem.js'\nimport { formatValidationSummary, printJson } from '../format.js'\nimport {\n getFlagBoolean,\n getFlagString,\n parseIntegerFlag,\n} from '../parseArgs.js'\n\nexport const getDocsCommandOptions = (\n args: ParsedCliArgs,\n): CliResult | DocsCommandOptions => {\n const docsRoot = args.positionals[0]
|
|
1
|
+
{"version":3,"sources":["../../../src/cli/commands/validate.ts"],"sourcesContent":["import path from 'node:path'\n\nimport type {\n CliResult,\n DocsCommandOptions,\n ParsedCliArgs,\n} from '../types.js'\n\nimport {\n buildDocsManifest,\n validateDocsManifest,\n} from '../../sync/index.js'\nimport {\n readDocsAiExportManifest,\n walkDocsFiles,\n} from '../filesystem.js'\nimport { formatValidationSummary, printJson } from '../format.js'\nimport {\n getFlagBoolean,\n getFlagString,\n parseIntegerFlag,\n} from '../parseArgs.js'\n\nconst getRepositoryName = (repository: string | undefined): string | undefined => {\n if (!repository) {\n return undefined\n }\n\n const [, name] = repository.split('/', 2)\n\n return name ?? repository\n}\n\nconst getDefaultSourceId = (docsRoot: string): string =>\n getRepositoryName(process.env.GITHUB_REPOSITORY) ??\n (path.basename(path.resolve(docsRoot)) === 'docs'\n ? 'local-docs'\n : path.basename(path.resolve(docsRoot)))\n\nexport const getDocsCommandOptions = (\n args: ParsedCliArgs,\n): CliResult | DocsCommandOptions => {\n const docsRoot = args.positionals[0]\n\n if (!docsRoot) {\n return {\n exitCode: 1,\n stderr: `Command \"${args.command}\" requires a docs root path.\\n`,\n }\n }\n\n const maxFiles = parseIntegerFlag(args, 'max-files')\n const maxFileBytes = parseIntegerFlag(args, 'max-file-bytes')\n const maxTotalBytes = parseIntegerFlag(args, 'max-total-bytes')\n\n for (const parsed of [maxFiles, maxFileBytes, maxTotalBytes]) {\n if (typeof parsed === 'object' && parsed !== null) {\n return parsed\n }\n }\n\n return {\n branch: getFlagString(args, 'branch'),\n commit: getFlagString(args, 'commit'),\n docsRoot,\n maxFileBytes: typeof maxFileBytes === 'number' ? maxFileBytes : undefined,\n maxFiles: typeof maxFiles === 'number' ? maxFiles : undefined,\n maxTotalBytes: typeof maxTotalBytes === 'number' ? maxTotalBytes : undefined,\n repository: getFlagString(args, 'repository'),\n sourceId: getFlagString(args, 'source') ?? getDefaultSourceId(docsRoot),\n }\n}\n\nexport const runValidateCommand = async (\n args: ParsedCliArgs,\n): Promise<CliResult> => {\n const options = getDocsCommandOptions(args)\n\n if ('exitCode' in options) {\n return options\n }\n\n const files = await walkDocsFiles({\n root: options.docsRoot,\n })\n const aiExport = await readDocsAiExportManifest({\n root: options.docsRoot,\n })\n\n if (!aiExport.ok) {\n return {\n exitCode: 1,\n stdout: formatValidationSummary({\n fileCount: files.length,\n root: options.docsRoot,\n sourceId: options.sourceId,\n validation: {\n issues: aiExport.issues,\n ok: false,\n warnings: aiExport.warnings,\n },\n }),\n }\n }\n\n const manifest = buildDocsManifest({\n aiExport: aiExport.manifest,\n branch: options.branch,\n commit: options.commit,\n files,\n repository: options.repository,\n sourceId: options.sourceId,\n })\n const validation = validateDocsManifest(manifest, {\n maxFileBytes: options.maxFileBytes,\n maxFiles: options.maxFiles,\n maxTotalBytes: options.maxTotalBytes,\n routeBase: `/${options.sourceId}`,\n })\n const validationWithReadWarnings = {\n ...validation,\n warnings: [...aiExport.warnings, ...validation.warnings],\n } as typeof validation\n\n if (getFlagBoolean(args, 'json')) {\n return {\n exitCode: validation.ok ? 0 : 1,\n stdout: printJson({\n fileCount: files.length,\n root: options.docsRoot,\n sourceId: options.sourceId,\n validation: validationWithReadWarnings,\n }, getFlagBoolean(args, 'pretty')),\n }\n }\n\n return {\n exitCode: validation.ok ? 0 : 1,\n stdout: formatValidationSummary({\n fileCount: files.length,\n root: options.docsRoot,\n sourceId: options.sourceId,\n validation: validationWithReadWarnings,\n }),\n }\n}\n"],"names":["path","buildDocsManifest","validateDocsManifest","readDocsAiExportManifest","walkDocsFiles","formatValidationSummary","printJson","getFlagBoolean","getFlagString","parseIntegerFlag","getRepositoryName","repository","undefined","name","split","getDefaultSourceId","docsRoot","process","env","GITHUB_REPOSITORY","basename","resolve","getDocsCommandOptions","args","positionals","exitCode","stderr","command","maxFiles","maxFileBytes","maxTotalBytes","parsed","branch","commit","sourceId","runValidateCommand","options","files","root","aiExport","ok","stdout","fileCount","length","validation","issues","warnings","manifest","routeBase","validationWithReadWarnings"],"mappings":"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"}
|
package/dist/cli/index.js
CHANGED
|
@@ -56,9 +56,7 @@ Options:
|
|
|
56
56
|
manifest: `payload-markdown-docs manifest <docs-root>
|
|
57
57
|
|
|
58
58
|
Options:
|
|
59
|
-
--source <id>
|
|
60
|
-
--root <path> Manifest source root label.
|
|
61
|
-
--route-base <route> Route base for validation. Defaults to /docs.
|
|
59
|
+
--source <id> Docs set slug. Defaults to the GitHub repository name in GitHub Actions, otherwise local-docs.
|
|
62
60
|
--repository <repo> Source repository metadata.
|
|
63
61
|
--branch <branch> Source branch metadata.
|
|
64
62
|
--commit <sha> Source commit metadata.
|
|
@@ -75,9 +73,7 @@ Options:
|
|
|
75
73
|
--delete-behavior <value> archive, delete, draft, or ignore.
|
|
76
74
|
--json Print full plan JSON.
|
|
77
75
|
--pretty Pretty-print JSON output.
|
|
78
|
-
--source <id>
|
|
79
|
-
--root <path> Manifest source root label.
|
|
80
|
-
--route-base <route> Route base for validation. Defaults to /docs.
|
|
76
|
+
--source <id> Docs set slug. Defaults to the GitHub repository name in GitHub Actions, otherwise local-docs.
|
|
81
77
|
--repository <repo> Source repository metadata.
|
|
82
78
|
--branch <branch> Source branch metadata.
|
|
83
79
|
--commit <sha> Source commit metadata.
|
|
@@ -91,10 +87,9 @@ Options:
|
|
|
91
87
|
Options:
|
|
92
88
|
--endpoint <url> Full Payload sync endpoint URL.
|
|
93
89
|
--key-id <id> Server-configured Ed25519 key id.
|
|
94
|
-
--private-key-file <path>
|
|
90
|
+
--private-key-file <path> Private key file from keygen, or an unencrypted OpenSSH Ed25519 key.
|
|
95
91
|
--private-key-env <name> Environment variable containing the private key.
|
|
96
92
|
--github-oidc Use GitHub Actions OIDC bearer auth instead of Ed25519.
|
|
97
|
-
--oidc-audience <value> GitHub OIDC audience. Defaults to payload-markdown-docs.
|
|
98
93
|
--oidc-token-env <name> Environment variable containing an already-fetched OIDC token.
|
|
99
94
|
--dry-run Upload as dry-run mode. This is the default.
|
|
100
95
|
--sync Upload as sync mode. Requires server sync.allowWrites.
|
|
@@ -102,9 +97,7 @@ Options:
|
|
|
102
97
|
--delete-behavior <value> archive, delete, draft, or ignore. Defaults to archive.
|
|
103
98
|
--json Print structured JSON output.
|
|
104
99
|
--pretty Pretty-print JSON output with --json.
|
|
105
|
-
--source <id>
|
|
106
|
-
--root <path> Manifest source root label.
|
|
107
|
-
--route-base <route> Route base for local validation. Defaults to /docs.
|
|
100
|
+
--source <id> Docs set slug. Defaults to the GitHub repository name in GitHub Actions, otherwise local-docs.
|
|
108
101
|
--repository <repo> Source repository metadata.
|
|
109
102
|
--branch <branch> Source branch metadata.
|
|
110
103
|
--commit <sha> Source commit metadata.
|
|
@@ -118,7 +111,7 @@ Examples:
|
|
|
118
111
|
payload-markdown-docs push ./docs --endpoint "$DOCS_SYNC_ENDPOINT" --source main-docs --key-id github-actions-main --private-key-env DOCS_SYNC_PRIVATE_KEY --sync
|
|
119
112
|
|
|
120
113
|
GitHub OIDC:
|
|
121
|
-
payload-markdown-docs push ./docs --endpoint "$DOCS_SYNC_ENDPOINT" --
|
|
114
|
+
payload-markdown-docs push ./docs --endpoint "$DOCS_SYNC_ENDPOINT" --github-oidc --sync
|
|
122
115
|
|
|
123
116
|
GitHub OIDC requires workflow permissions: id-token: write and contents: read.
|
|
124
117
|
Hard delete requires explicit server sync.allowHardDelete. Existing collection and block targets are not supported yet.
|
|
@@ -128,9 +121,7 @@ Hard delete requires explicit server sync.allowHardDelete. Existing collection a
|
|
|
128
121
|
Options:
|
|
129
122
|
--json Print validation JSON.
|
|
130
123
|
--pretty Pretty-print JSON output.
|
|
131
|
-
--source <id>
|
|
132
|
-
--root <path> Manifest source root label.
|
|
133
|
-
--route-base <route> Route base for validation. Defaults to /docs.
|
|
124
|
+
--source <id> Docs set slug. Defaults to the GitHub repository name in GitHub Actions, otherwise local-docs.
|
|
134
125
|
--repository <repo> Source repository metadata.
|
|
135
126
|
--branch <branch> Source branch metadata.
|
|
136
127
|
--commit <sha> Source commit metadata.
|