@valkyrianlabs/payload-markdown-docs 0.1.0-canary.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (204) hide show
  1. package/README.md +195 -0
  2. package/dist/admin/DocsSetManager.d.ts +2 -0
  3. package/dist/admin/DocsSetManager.js +298 -0
  4. package/dist/admin/DocsSetManager.js.map +1 -0
  5. package/dist/admin/docsSetManagerData.d.ts +25 -0
  6. package/dist/admin/docsSetManagerData.js +266 -0
  7. package/dist/admin/docsSetManagerData.js.map +1 -0
  8. package/dist/admin/docsSetManagerTypes.d.ts +103 -0
  9. package/dist/admin/docsSetManagerTypes.js +3 -0
  10. package/dist/admin/docsSetManagerTypes.js.map +1 -0
  11. package/dist/admin/index.d.ts +3 -0
  12. package/dist/admin/index.js +4 -0
  13. package/dist/admin/index.js.map +1 -0
  14. package/dist/cli/commands/install.d.ts +2 -0
  15. package/dist/cli/commands/install.js +211 -0
  16. package/dist/cli/commands/install.js.map +1 -0
  17. package/dist/cli/commands/keygen.d.ts +2 -0
  18. package/dist/cli/commands/keygen.js +89 -0
  19. package/dist/cli/commands/keygen.js.map +1 -0
  20. package/dist/cli/commands/manifest.d.ts +2 -0
  21. package/dist/cli/commands/manifest.js +50 -0
  22. package/dist/cli/commands/manifest.js.map +1 -0
  23. package/dist/cli/commands/plan.d.ts +2 -0
  24. package/dist/cli/commands/plan.js +110 -0
  25. package/dist/cli/commands/plan.js.map +1 -0
  26. package/dist/cli/commands/push.d.ts +3 -0
  27. package/dist/cli/commands/push.js +308 -0
  28. package/dist/cli/commands/push.js.map +1 -0
  29. package/dist/cli/commands/validate.d.ts +3 -0
  30. package/dist/cli/commands/validate.js +109 -0
  31. package/dist/cli/commands/validate.js.map +1 -0
  32. package/dist/cli/filesystem.d.ts +20 -0
  33. package/dist/cli/filesystem.js +96 -0
  34. package/dist/cli/filesystem.js.map +1 -0
  35. package/dist/cli/format.d.ts +35 -0
  36. package/dist/cli/format.js +76 -0
  37. package/dist/cli/format.js.map +1 -0
  38. package/dist/cli/http.d.ts +19 -0
  39. package/dist/cli/http.js +39 -0
  40. package/dist/cli/http.js.map +1 -0
  41. package/dist/cli/index.d.ts +3 -0
  42. package/dist/cli/index.js +214 -0
  43. package/dist/cli/index.js.map +1 -0
  44. package/dist/cli/parseArgs.d.ts +5 -0
  45. package/dist/cli/parseArgs.js +219 -0
  46. package/dist/cli/parseArgs.js.map +1 -0
  47. package/dist/cli/types.d.ts +51 -0
  48. package/dist/cli/types.js +3 -0
  49. package/dist/cli/types.js.map +1 -0
  50. package/dist/collections/docs.d.ts +9 -0
  51. package/dist/collections/docs.js +168 -0
  52. package/dist/collections/docs.js.map +1 -0
  53. package/dist/collections/docsGroups.d.ts +5 -0
  54. package/dist/collections/docsGroups.js +57 -0
  55. package/dist/collections/docsGroups.js.map +1 -0
  56. package/dist/collections/docsSets.d.ts +8 -0
  57. package/dist/collections/docsSets.js +158 -0
  58. package/dist/collections/docsSets.js.map +1 -0
  59. package/dist/collections/index.d.ts +10 -0
  60. package/dist/collections/index.js +7 -0
  61. package/dist/collections/index.js.map +1 -0
  62. package/dist/collections/nonces.d.ts +6 -0
  63. package/dist/collections/nonces.js +57 -0
  64. package/dist/collections/nonces.js.map +1 -0
  65. package/dist/collections/syncRuns.d.ts +5 -0
  66. package/dist/collections/syncRuns.js +139 -0
  67. package/dist/collections/syncRuns.js.map +1 -0
  68. package/dist/constants.d.ts +21 -0
  69. package/dist/constants.js +23 -0
  70. package/dist/constants.js.map +1 -0
  71. package/dist/endpoints/index.d.ts +2 -0
  72. package/dist/endpoints/index.js +3 -0
  73. package/dist/endpoints/index.js.map +1 -0
  74. package/dist/endpoints/sync.d.ts +47 -0
  75. package/dist/endpoints/sync.js +616 -0
  76. package/dist/endpoints/sync.js.map +1 -0
  77. package/dist/index.d.ts +9 -0
  78. package/dist/index.js +7 -0
  79. package/dist/index.js.map +1 -0
  80. package/dist/next/PayloadMarkdownDocsPage.d.ts +7 -0
  81. package/dist/next/PayloadMarkdownDocsPage.js +142 -0
  82. package/dist/next/PayloadMarkdownDocsPage.js.map +1 -0
  83. package/dist/next/index.d.ts +9 -0
  84. package/dist/next/index.js +7 -0
  85. package/dist/next/index.js.map +1 -0
  86. package/dist/next/markdown.d.ts +14 -0
  87. package/dist/next/markdown.js +232 -0
  88. package/dist/next/markdown.js.map +1 -0
  89. package/dist/next/metadata.d.ts +3 -0
  90. package/dist/next/metadata.js +33 -0
  91. package/dist/next/metadata.js.map +1 -0
  92. package/dist/next/records.d.ts +14 -0
  93. package/dist/next/records.js +146 -0
  94. package/dist/next/records.js.map +1 -0
  95. package/dist/next/route.d.ts +6 -0
  96. package/dist/next/route.js +271 -0
  97. package/dist/next/route.js.map +1 -0
  98. package/dist/next/sidebar.d.ts +15 -0
  99. package/dist/next/sidebar.js +137 -0
  100. package/dist/next/sidebar.js.map +1 -0
  101. package/dist/next/types.d.ts +117 -0
  102. package/dist/next/types.js +3 -0
  103. package/dist/next/types.js.map +1 -0
  104. package/dist/payload/applyDocsSync.d.ts +54 -0
  105. package/dist/payload/applyDocsSync.js +176 -0
  106. package/dist/payload/applyDocsSync.js.map +1 -0
  107. package/dist/payload/docsConflicts.d.ts +12 -0
  108. package/dist/payload/docsConflicts.js +34 -0
  109. package/dist/payload/docsConflicts.js.map +1 -0
  110. package/dist/payload/docsData.d.ts +23 -0
  111. package/dist/payload/docsData.js +59 -0
  112. package/dist/payload/docsData.js.map +1 -0
  113. package/dist/payload/docsSets.d.ts +38 -0
  114. package/dist/payload/docsSets.js +57 -0
  115. package/dist/payload/docsSets.js.map +1 -0
  116. package/dist/payload/existingDocs.d.ts +43 -0
  117. package/dist/payload/existingDocs.js +97 -0
  118. package/dist/payload/existingDocs.js.map +1 -0
  119. package/dist/payload/index.d.ts +15 -0
  120. package/dist/payload/index.js +10 -0
  121. package/dist/payload/index.js.map +1 -0
  122. package/dist/payload/routeCollisions.d.ts +31 -0
  123. package/dist/payload/routeCollisions.js +104 -0
  124. package/dist/payload/routeCollisions.js.map +1 -0
  125. package/dist/payload/syncRuns.d.ts +60 -0
  126. package/dist/payload/syncRuns.js +53 -0
  127. package/dist/payload/syncRuns.js.map +1 -0
  128. package/dist/plugin.d.ts +3 -0
  129. package/dist/plugin.js +165 -0
  130. package/dist/plugin.js.map +1 -0
  131. package/dist/routing/index.d.ts +3 -0
  132. package/dist/routing/index.js +4 -0
  133. package/dist/routing/index.js.map +1 -0
  134. package/dist/routing/paths.d.ts +7 -0
  135. package/dist/routing/paths.js +23 -0
  136. package/dist/routing/paths.js.map +1 -0
  137. package/dist/routing/reservations.d.ts +37 -0
  138. package/dist/routing/reservations.js +79 -0
  139. package/dist/routing/reservations.js.map +1 -0
  140. package/dist/security/canonical.d.ts +12 -0
  141. package/dist/security/canonical.js +24 -0
  142. package/dist/security/canonical.js.map +1 -0
  143. package/dist/security/githubOidc.d.ts +45 -0
  144. package/dist/security/githubOidc.js +177 -0
  145. package/dist/security/githubOidc.js.map +1 -0
  146. package/dist/security/headers.d.ts +22 -0
  147. package/dist/security/headers.js +44 -0
  148. package/dist/security/headers.js.map +1 -0
  149. package/dist/security/index.d.ts +15 -0
  150. package/dist/security/index.js +9 -0
  151. package/dist/security/index.js.map +1 -0
  152. package/dist/security/jwks.d.ts +20 -0
  153. package/dist/security/jwks.js +40 -0
  154. package/dist/security/jwks.js.map +1 -0
  155. package/dist/security/jwt.d.ts +10 -0
  156. package/dist/security/jwt.js +42 -0
  157. package/dist/security/jwt.js.map +1 -0
  158. package/dist/security/nonce.d.ts +34 -0
  159. package/dist/security/nonce.js +43 -0
  160. package/dist/security/nonce.js.map +1 -0
  161. package/dist/security/sign.d.ts +13 -0
  162. package/dist/security/sign.js +39 -0
  163. package/dist/security/sign.js.map +1 -0
  164. package/dist/security/verify.d.ts +28 -0
  165. package/dist/security/verify.js +54 -0
  166. package/dist/security/verify.js.map +1 -0
  167. package/dist/skills/codex/SKILL.md +173 -0
  168. package/dist/skills/codex/examples/docs-page.md +42 -0
  169. package/dist/skills/codex/examples/github-actions.md +64 -0
  170. package/dist/skills/codex/reference/admin.md +28 -0
  171. package/dist/skills/codex/reference/frontmatter.md +39 -0
  172. package/dist/skills/codex/reference/payload-markdown-directives.md +77 -0
  173. package/dist/skills/codex/reference/routing.md +35 -0
  174. package/dist/skills/codex/reference/sync.md +35 -0
  175. package/dist/skills/codex/reference/troubleshooting.md +53 -0
  176. package/dist/skills/codex/reference/workflow.md +39 -0
  177. package/dist/sync/aiExportManifest.d.ts +58 -0
  178. package/dist/sync/aiExportManifest.js +430 -0
  179. package/dist/sync/aiExportManifest.js.map +1 -0
  180. package/dist/sync/frontmatter.d.ts +28 -0
  181. package/dist/sync/frontmatter.js +210 -0
  182. package/dist/sync/frontmatter.js.map +1 -0
  183. package/dist/sync/hash.d.ts +1 -0
  184. package/dist/sync/hash.js +8 -0
  185. package/dist/sync/hash.js.map +1 -0
  186. package/dist/sync/index.d.ts +12 -0
  187. package/dist/sync/index.js +9 -0
  188. package/dist/sync/index.js.map +1 -0
  189. package/dist/sync/manifest.d.ts +58 -0
  190. package/dist/sync/manifest.js +21 -0
  191. package/dist/sync/manifest.js.map +1 -0
  192. package/dist/sync/paths.d.ts +16 -0
  193. package/dist/sync/paths.js +116 -0
  194. package/dist/sync/paths.js.map +1 -0
  195. package/dist/sync/plan.d.ts +29 -0
  196. package/dist/sync/plan.js +72 -0
  197. package/dist/sync/plan.js.map +1 -0
  198. package/dist/sync/validate.d.ts +26 -0
  199. package/dist/sync/validate.js +308 -0
  200. package/dist/sync/validate.js.map +1 -0
  201. package/dist/types.d.ts +84 -0
  202. package/dist/types.js +3 -0
  203. package/dist/types.js.map +1 -0
  204. package/package.json +143 -0
@@ -0,0 +1,26 @@
1
+ import type { DocsManifest, DocsManifestFile, DocsManifestSource, ValidatedDocsManifest } from './manifest.js';
2
+ export type DocsValidationErrorCode = 'duplicate_existing_path' | 'duplicate_path' | 'empty_manifest' | 'file_too_large' | 'invalid_ai_export_manifest' | 'invalid_delete_behavior' | 'invalid_frontmatter' | 'invalid_hash' | 'invalid_manifest' | 'invalid_mode' | 'invalid_path' | 'invalid_source' | 'invalid_version' | 'manifest_too_large' | 'missing_ai_export_order_path' | 'non_markdown_file' | 'path_traversal' | 'too_many_files';
3
+ export type DocsValidationIssue = {
4
+ code: DocsValidationErrorCode;
5
+ message: string;
6
+ path?: string;
7
+ };
8
+ export type DocsValidationResult<T = unknown> = {
9
+ data: T;
10
+ issues: DocsValidationIssue[];
11
+ ok: true;
12
+ warnings: DocsValidationIssue[];
13
+ } | {
14
+ issues: DocsValidationIssue[];
15
+ ok: false;
16
+ warnings: DocsValidationIssue[];
17
+ };
18
+ export type DocsValidationOptions = {
19
+ allowedSourceIds?: string[];
20
+ maxFileBytes?: number;
21
+ maxFiles?: number;
22
+ maxTotalBytes?: number;
23
+ routeBase?: string;
24
+ };
25
+ export declare const validateDocsManifest: (manifest: unknown, options?: DocsValidationOptions) => DocsValidationResult<ValidatedDocsManifest>;
26
+ export type { DocsManifest, DocsManifestFile, DocsManifestSource };
@@ -0,0 +1,308 @@
1
+ import { DEFAULT_DOCS_ROUTE_BASE, DEFAULT_MAX_DOCS_FILE_BYTES, DEFAULT_MAX_DOCS_FILES, DEFAULT_MAX_DOCS_TOTAL_BYTES } from '../constants.js';
2
+ import { validateDocsAiExportManifest } from './aiExportManifest.js';
3
+ import { parseDocsFrontmatter, resolveDocsTitle } from './frontmatter.js';
4
+ import { sha256Hex } from './hash.js';
5
+ import { deriveRouteFromSourcePath, normalizeDocsPath } from './paths.js';
6
+ const syncModes = new Set([
7
+ 'dry-run',
8
+ 'sync'
9
+ ]);
10
+ const deleteBehaviors = new Set([
11
+ 'archive',
12
+ 'delete',
13
+ 'draft',
14
+ 'ignore'
15
+ ]);
16
+ const isRecord = (value)=>typeof value === 'object' && value !== null && !Array.isArray(value);
17
+ const createIssue = ({ code, message, path })=>({
18
+ code,
19
+ message,
20
+ path
21
+ });
22
+ const byteLength = (content)=>Buffer.byteLength(content, 'utf8');
23
+ const validateSource = ({ allowedSourceIds, source })=>{
24
+ if (!isRecord(source) || typeof source.id !== 'string' || source.id.trim() === '') {
25
+ return {
26
+ issues: [
27
+ createIssue({
28
+ code: 'invalid_source',
29
+ message: 'Manifest source.id is required.'
30
+ })
31
+ ]
32
+ };
33
+ }
34
+ if (allowedSourceIds && !allowedSourceIds.includes(source.id)) {
35
+ return {
36
+ issues: [
37
+ createIssue({
38
+ code: 'invalid_source',
39
+ message: `Manifest source.id "${source.id}" is not allowed.`
40
+ })
41
+ ]
42
+ };
43
+ }
44
+ return {
45
+ issues: [],
46
+ source: {
47
+ id: source.id,
48
+ branch: typeof source.branch === 'string' ? source.branch : undefined,
49
+ commit: typeof source.commit === 'string' ? source.commit : undefined,
50
+ repository: typeof source.repository === 'string' ? source.repository : undefined,
51
+ root: typeof source.root === 'string' ? source.root : undefined
52
+ }
53
+ };
54
+ };
55
+ const validateMode = (mode)=>{
56
+ if (mode === undefined) {
57
+ return {
58
+ issues: [],
59
+ mode: 'dry-run'
60
+ };
61
+ }
62
+ if (syncModes.has(mode)) {
63
+ return {
64
+ issues: [],
65
+ mode: mode
66
+ };
67
+ }
68
+ return {
69
+ issues: [
70
+ createIssue({
71
+ code: 'invalid_mode',
72
+ message: 'Manifest mode must be "dry-run" or "sync".'
73
+ })
74
+ ],
75
+ mode: 'dry-run'
76
+ };
77
+ };
78
+ const validateDeleteBehavior = (deleteBehavior)=>{
79
+ if (deleteBehavior === undefined) {
80
+ return {
81
+ deleteBehavior: 'archive',
82
+ issues: []
83
+ };
84
+ }
85
+ if (deleteBehaviors.has(deleteBehavior)) {
86
+ return {
87
+ deleteBehavior: deleteBehavior,
88
+ issues: []
89
+ };
90
+ }
91
+ return {
92
+ deleteBehavior: 'archive',
93
+ issues: [
94
+ createIssue({
95
+ code: 'invalid_delete_behavior',
96
+ message: 'Manifest deleteBehavior must be archive, delete, draft, or ignore.'
97
+ })
98
+ ]
99
+ };
100
+ };
101
+ const validateManifestFile = ({ file, maxFileBytes, routeBase })=>{
102
+ const issues = [];
103
+ const warnings = [];
104
+ if (!isRecord(file)) {
105
+ return {
106
+ fileBytes: 0,
107
+ issues: [
108
+ createIssue({
109
+ code: 'invalid_manifest',
110
+ message: 'Manifest file entries must be objects.'
111
+ })
112
+ ],
113
+ warnings
114
+ };
115
+ }
116
+ const path = typeof file.path === 'string' ? file.path : undefined;
117
+ const content = typeof file.content === 'string' ? file.content : undefined;
118
+ if (!path || content === undefined) {
119
+ return {
120
+ fileBytes: 0,
121
+ issues: [
122
+ createIssue({
123
+ code: 'invalid_manifest',
124
+ message: 'Manifest file entries require string path and content.',
125
+ path
126
+ })
127
+ ],
128
+ warnings
129
+ };
130
+ }
131
+ const normalizedPath = normalizeDocsPath(path);
132
+ if (!normalizedPath.ok) {
133
+ return {
134
+ fileBytes: 0,
135
+ issues: [
136
+ createIssue({
137
+ code: normalizedPath.code,
138
+ message: normalizedPath.message,
139
+ path
140
+ })
141
+ ],
142
+ warnings
143
+ };
144
+ }
145
+ const fileBytes = byteLength(content);
146
+ if (fileBytes > maxFileBytes) {
147
+ issues.push(createIssue({
148
+ code: 'file_too_large',
149
+ message: `File exceeds maximum size of ${maxFileBytes} bytes.`,
150
+ path: normalizedPath.path
151
+ }));
152
+ }
153
+ const computedHash = sha256Hex(content);
154
+ if (file.sha256 !== undefined && (typeof file.sha256 !== 'string' || !/^[a-f0-9]{64}$/i.test(file.sha256) || file.sha256.toLowerCase() !== computedHash)) {
155
+ issues.push(createIssue({
156
+ code: 'invalid_hash',
157
+ message: 'Manifest file sha256 does not match content.',
158
+ path: normalizedPath.path
159
+ }));
160
+ }
161
+ const parsedFrontmatter = parseDocsFrontmatter(content, {
162
+ path: normalizedPath.path
163
+ });
164
+ issues.push(...parsedFrontmatter.issues);
165
+ warnings.push(...parsedFrontmatter.warnings);
166
+ const route = deriveRouteFromSourcePath({
167
+ slug: parsedFrontmatter.frontmatter.slug,
168
+ routeBase,
169
+ sourcePath: normalizedPath.path
170
+ });
171
+ return {
172
+ fileBytes,
173
+ issues,
174
+ normalizedPath: normalizedPath.path,
175
+ validatedFile: {
176
+ content: parsedFrontmatter.content,
177
+ frontmatter: parsedFrontmatter.frontmatter,
178
+ path: normalizedPath.path,
179
+ route,
180
+ sha256: computedHash,
181
+ title: resolveDocsTitle({
182
+ content: parsedFrontmatter.content,
183
+ frontmatter: parsedFrontmatter.frontmatter,
184
+ sourcePath: normalizedPath.path
185
+ })
186
+ },
187
+ warnings
188
+ };
189
+ };
190
+ export const validateDocsManifest = (manifest, options = {})=>{
191
+ const issues = [];
192
+ const warnings = [];
193
+ const maxFileBytes = options.maxFileBytes ?? DEFAULT_MAX_DOCS_FILE_BYTES;
194
+ const maxFiles = options.maxFiles ?? DEFAULT_MAX_DOCS_FILES;
195
+ const maxTotalBytes = options.maxTotalBytes ?? DEFAULT_MAX_DOCS_TOTAL_BYTES;
196
+ const routeBase = options.routeBase ?? DEFAULT_DOCS_ROUTE_BASE;
197
+ if (!isRecord(manifest)) {
198
+ return {
199
+ issues: [
200
+ createIssue({
201
+ code: 'invalid_manifest',
202
+ message: 'Manifest must be an object.'
203
+ })
204
+ ],
205
+ ok: false,
206
+ warnings
207
+ };
208
+ }
209
+ if (manifest.version !== 1) {
210
+ issues.push(createIssue({
211
+ code: 'invalid_version',
212
+ message: 'Manifest version must be 1.'
213
+ }));
214
+ }
215
+ const sourceValidation = validateSource({
216
+ allowedSourceIds: options.allowedSourceIds,
217
+ source: manifest.source
218
+ });
219
+ issues.push(...sourceValidation.issues);
220
+ const modeValidation = validateMode(manifest.mode);
221
+ issues.push(...modeValidation.issues);
222
+ const deleteBehaviorValidation = validateDeleteBehavior(manifest.deleteBehavior);
223
+ issues.push(...deleteBehaviorValidation.issues);
224
+ const publish = manifest.publish === undefined ? false : manifest.publish === true ? true : false;
225
+ if (manifest.publish !== undefined && typeof manifest.publish !== 'boolean') {
226
+ issues.push(createIssue({
227
+ code: 'invalid_manifest',
228
+ message: 'Manifest publish must be a boolean.'
229
+ }));
230
+ }
231
+ const files = Array.isArray(manifest.files) ? manifest.files : undefined;
232
+ if (!files || files.length === 0) {
233
+ issues.push(createIssue({
234
+ code: 'empty_manifest',
235
+ message: 'Manifest must include at least one file.'
236
+ }));
237
+ }
238
+ if (files && files.length > maxFiles) {
239
+ issues.push(createIssue({
240
+ code: 'too_many_files',
241
+ message: `Manifest exceeds maximum file count of ${maxFiles}.`
242
+ }));
243
+ }
244
+ const validatedFiles = [];
245
+ const normalizedPaths = new Set();
246
+ let totalBytes = 0;
247
+ for (const file of files ?? []){
248
+ const fileValidation = validateManifestFile({
249
+ file,
250
+ maxFileBytes,
251
+ routeBase
252
+ });
253
+ totalBytes += fileValidation.fileBytes;
254
+ issues.push(...fileValidation.issues);
255
+ warnings.push(...fileValidation.warnings);
256
+ if (fileValidation.normalizedPath) {
257
+ if (normalizedPaths.has(fileValidation.normalizedPath)) {
258
+ issues.push(createIssue({
259
+ code: 'duplicate_path',
260
+ message: 'Manifest contains duplicate normalized paths.',
261
+ path: fileValidation.normalizedPath
262
+ }));
263
+ }
264
+ normalizedPaths.add(fileValidation.normalizedPath);
265
+ }
266
+ if (fileValidation.validatedFile) {
267
+ validatedFiles.push(fileValidation.validatedFile);
268
+ }
269
+ }
270
+ if (totalBytes > maxTotalBytes) {
271
+ issues.push(createIssue({
272
+ code: 'manifest_too_large',
273
+ message: `Manifest content exceeds maximum total size of ${maxTotalBytes} bytes.`
274
+ }));
275
+ }
276
+ const aiExportValidation = manifest.aiExport === undefined ? undefined : validateDocsAiExportManifest(manifest.aiExport, {
277
+ knownDocsPaths: normalizedPaths
278
+ });
279
+ if (aiExportValidation) {
280
+ issues.push(...aiExportValidation.issues);
281
+ warnings.push(...aiExportValidation.warnings);
282
+ }
283
+ if (issues.length > 0 || !sourceValidation.source || aiExportValidation?.ok === false) {
284
+ return {
285
+ issues,
286
+ ok: false,
287
+ warnings
288
+ };
289
+ }
290
+ return {
291
+ data: {
292
+ deleteBehavior: deleteBehaviorValidation.deleteBehavior,
293
+ ...aiExportValidation?.ok ? {
294
+ aiExport: aiExportValidation.manifest
295
+ } : {},
296
+ files: validatedFiles,
297
+ mode: modeValidation.mode,
298
+ publish,
299
+ source: sourceValidation.source,
300
+ version: 1
301
+ },
302
+ issues,
303
+ ok: true,
304
+ warnings
305
+ };
306
+ };
307
+
308
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/sync/validate.ts"],"sourcesContent":["import type {\n DocsDeleteBehavior,\n DocsManifest,\n DocsManifestFile,\n DocsManifestSource,\n DocsSyncMode,\n ValidatedDocsManifest,\n ValidatedDocsManifestFile,\n} from './manifest.js'\n\nimport {\n DEFAULT_DOCS_ROUTE_BASE,\n DEFAULT_MAX_DOCS_FILE_BYTES,\n DEFAULT_MAX_DOCS_FILES,\n DEFAULT_MAX_DOCS_TOTAL_BYTES,\n} from '../constants.js'\nimport { validateDocsAiExportManifest } from './aiExportManifest.js'\nimport {\n parseDocsFrontmatter,\n resolveDocsTitle,\n} from './frontmatter.js'\nimport { sha256Hex } from './hash.js'\nimport { deriveRouteFromSourcePath, normalizeDocsPath } from './paths.js'\n\nexport type DocsValidationErrorCode =\n | 'duplicate_existing_path'\n | 'duplicate_path'\n | 'empty_manifest'\n | 'file_too_large'\n | 'invalid_ai_export_manifest'\n | 'invalid_delete_behavior'\n | 'invalid_frontmatter'\n | 'invalid_hash'\n | 'invalid_manifest'\n | 'invalid_mode'\n | 'invalid_path'\n | 'invalid_source'\n | 'invalid_version'\n | 'manifest_too_large'\n | 'missing_ai_export_order_path'\n | 'non_markdown_file'\n | 'path_traversal'\n | 'too_many_files'\n\nexport type DocsValidationIssue = {\n code: DocsValidationErrorCode\n message: string\n path?: string\n}\n\nexport type DocsValidationResult<T = unknown> =\n | {\n data: T\n issues: DocsValidationIssue[]\n ok: true\n warnings: DocsValidationIssue[]\n }\n | {\n issues: DocsValidationIssue[]\n ok: false\n warnings: DocsValidationIssue[]\n }\n\nexport type DocsValidationOptions = {\n allowedSourceIds?: string[]\n maxFileBytes?: number\n maxFiles?: number\n maxTotalBytes?: number\n routeBase?: string\n}\n\nconst syncModes = new Set<DocsSyncMode>(['dry-run', 'sync'])\nconst deleteBehaviors = new Set<DocsDeleteBehavior>([\n 'archive',\n 'delete',\n 'draft',\n 'ignore',\n])\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n\nconst createIssue = ({\n code,\n message,\n path,\n}: DocsValidationIssue): DocsValidationIssue => ({\n code,\n message,\n path,\n})\n\nconst byteLength = (content: string): number => Buffer.byteLength(content, 'utf8')\n\nconst validateSource = ({\n allowedSourceIds,\n source,\n}: {\n allowedSourceIds?: string[]\n source: unknown\n}): {\n issues: DocsValidationIssue[]\n source?: DocsManifestSource\n} => {\n if (!isRecord(source) || typeof source.id !== 'string' || source.id.trim() === '') {\n return {\n issues: [\n createIssue({\n code: 'invalid_source',\n message: 'Manifest source.id is required.',\n }),\n ],\n }\n }\n\n if (allowedSourceIds && !allowedSourceIds.includes(source.id)) {\n return {\n issues: [\n createIssue({\n code: 'invalid_source',\n message: `Manifest source.id \"${source.id}\" is not allowed.`,\n }),\n ],\n }\n }\n\n return {\n issues: [],\n source: {\n id: source.id,\n branch: typeof source.branch === 'string' ? source.branch : undefined,\n commit: typeof source.commit === 'string' ? source.commit : undefined,\n repository: typeof source.repository === 'string' ? source.repository : undefined,\n root: typeof source.root === 'string' ? source.root : undefined,\n },\n }\n}\n\nconst validateMode = (mode: unknown): {\n issues: DocsValidationIssue[]\n mode: DocsSyncMode\n} => {\n if (mode === undefined) {\n return {\n issues: [],\n mode: 'dry-run',\n }\n }\n\n if (syncModes.has(mode as DocsSyncMode)) {\n return {\n issues: [],\n mode: mode as DocsSyncMode,\n }\n }\n\n return {\n issues: [\n createIssue({\n code: 'invalid_mode',\n message: 'Manifest mode must be \"dry-run\" or \"sync\".',\n }),\n ],\n mode: 'dry-run',\n }\n}\n\nconst validateDeleteBehavior = (deleteBehavior: unknown): {\n deleteBehavior: DocsDeleteBehavior\n issues: DocsValidationIssue[]\n} => {\n if (deleteBehavior === undefined) {\n return {\n deleteBehavior: 'archive',\n issues: [],\n }\n }\n\n if (deleteBehaviors.has(deleteBehavior as DocsDeleteBehavior)) {\n return {\n deleteBehavior: deleteBehavior as DocsDeleteBehavior,\n issues: [],\n }\n }\n\n return {\n deleteBehavior: 'archive',\n issues: [\n createIssue({\n code: 'invalid_delete_behavior',\n message: 'Manifest deleteBehavior must be archive, delete, draft, or ignore.',\n }),\n ],\n }\n}\n\nconst validateManifestFile = ({\n file,\n maxFileBytes,\n routeBase,\n}: {\n file: unknown\n maxFileBytes: number\n routeBase: string\n}): {\n fileBytes: number\n issues: DocsValidationIssue[]\n normalizedPath?: string\n validatedFile?: ValidatedDocsManifestFile\n warnings: DocsValidationIssue[]\n} => {\n const issues: DocsValidationIssue[] = []\n const warnings: DocsValidationIssue[] = []\n\n if (!isRecord(file)) {\n return {\n fileBytes: 0,\n issues: [\n createIssue({\n code: 'invalid_manifest',\n message: 'Manifest file entries must be objects.',\n }),\n ],\n warnings,\n }\n }\n\n const path = typeof file.path === 'string' ? file.path : undefined\n const content = typeof file.content === 'string' ? file.content : undefined\n\n if (!path || content === undefined) {\n return {\n fileBytes: 0,\n issues: [\n createIssue({\n code: 'invalid_manifest',\n message: 'Manifest file entries require string path and content.',\n path,\n }),\n ],\n warnings,\n }\n }\n\n const normalizedPath = normalizeDocsPath(path)\n\n if (!normalizedPath.ok) {\n return {\n fileBytes: 0,\n issues: [\n createIssue({\n code: normalizedPath.code,\n message: normalizedPath.message,\n path,\n }),\n ],\n warnings,\n }\n }\n\n const fileBytes = byteLength(content)\n\n if (fileBytes > maxFileBytes) {\n issues.push(\n createIssue({\n code: 'file_too_large',\n message: `File exceeds maximum size of ${maxFileBytes} bytes.`,\n path: normalizedPath.path,\n }),\n )\n }\n\n const computedHash = sha256Hex(content)\n\n if (\n file.sha256 !== undefined &&\n (typeof file.sha256 !== 'string' ||\n !/^[a-f0-9]{64}$/i.test(file.sha256) ||\n file.sha256.toLowerCase() !== computedHash)\n ) {\n issues.push(\n createIssue({\n code: 'invalid_hash',\n message: 'Manifest file sha256 does not match content.',\n path: normalizedPath.path,\n }),\n )\n }\n\n const parsedFrontmatter = parseDocsFrontmatter(content, {\n path: normalizedPath.path,\n })\n\n issues.push(...parsedFrontmatter.issues)\n warnings.push(...parsedFrontmatter.warnings)\n\n const route = deriveRouteFromSourcePath({\n slug: parsedFrontmatter.frontmatter.slug,\n routeBase,\n sourcePath: normalizedPath.path,\n })\n\n return {\n fileBytes,\n issues,\n normalizedPath: normalizedPath.path,\n validatedFile: {\n content: parsedFrontmatter.content,\n frontmatter: parsedFrontmatter.frontmatter,\n path: normalizedPath.path,\n route,\n sha256: computedHash,\n title: resolveDocsTitle({\n content: parsedFrontmatter.content,\n frontmatter: parsedFrontmatter.frontmatter,\n sourcePath: normalizedPath.path,\n }),\n },\n warnings,\n }\n}\n\nexport const validateDocsManifest = (\n manifest: unknown,\n options: DocsValidationOptions = {},\n): DocsValidationResult<ValidatedDocsManifest> => {\n const issues: DocsValidationIssue[] = []\n const warnings: DocsValidationIssue[] = []\n const maxFileBytes = options.maxFileBytes ?? DEFAULT_MAX_DOCS_FILE_BYTES\n const maxFiles = options.maxFiles ?? DEFAULT_MAX_DOCS_FILES\n const maxTotalBytes = options.maxTotalBytes ?? DEFAULT_MAX_DOCS_TOTAL_BYTES\n const routeBase = options.routeBase ?? DEFAULT_DOCS_ROUTE_BASE\n\n if (!isRecord(manifest)) {\n return {\n issues: [\n createIssue({\n code: 'invalid_manifest',\n message: 'Manifest must be an object.',\n }),\n ],\n ok: false,\n warnings,\n }\n }\n\n if (manifest.version !== 1) {\n issues.push(\n createIssue({\n code: 'invalid_version',\n message: 'Manifest version must be 1.',\n }),\n )\n }\n\n const sourceValidation = validateSource({\n allowedSourceIds: options.allowedSourceIds,\n source: manifest.source,\n })\n\n issues.push(...sourceValidation.issues)\n\n const modeValidation = validateMode(manifest.mode)\n issues.push(...modeValidation.issues)\n\n const deleteBehaviorValidation = validateDeleteBehavior(manifest.deleteBehavior)\n issues.push(...deleteBehaviorValidation.issues)\n\n const publish =\n manifest.publish === undefined ? false : manifest.publish === true ? true : false\n\n if (manifest.publish !== undefined && typeof manifest.publish !== 'boolean') {\n issues.push(\n createIssue({\n code: 'invalid_manifest',\n message: 'Manifest publish must be a boolean.',\n }),\n )\n }\n\n const files = Array.isArray(manifest.files) ? manifest.files : undefined\n\n if (!files || files.length === 0) {\n issues.push(\n createIssue({\n code: 'empty_manifest',\n message: 'Manifest must include at least one file.',\n }),\n )\n }\n\n if (files && files.length > maxFiles) {\n issues.push(\n createIssue({\n code: 'too_many_files',\n message: `Manifest exceeds maximum file count of ${maxFiles}.`,\n }),\n )\n }\n\n const validatedFiles: ValidatedDocsManifestFile[] = []\n const normalizedPaths = new Set<string>()\n let totalBytes = 0\n\n for (const file of files ?? []) {\n const fileValidation = validateManifestFile({\n file,\n maxFileBytes,\n routeBase,\n })\n\n totalBytes += fileValidation.fileBytes\n issues.push(...fileValidation.issues)\n warnings.push(...fileValidation.warnings)\n\n if (fileValidation.normalizedPath) {\n if (normalizedPaths.has(fileValidation.normalizedPath)) {\n issues.push(\n createIssue({\n code: 'duplicate_path',\n message: 'Manifest contains duplicate normalized paths.',\n path: fileValidation.normalizedPath,\n }),\n )\n }\n\n normalizedPaths.add(fileValidation.normalizedPath)\n }\n\n if (fileValidation.validatedFile) {\n validatedFiles.push(fileValidation.validatedFile)\n }\n }\n\n if (totalBytes > maxTotalBytes) {\n issues.push(\n createIssue({\n code: 'manifest_too_large',\n message: `Manifest content exceeds maximum total size of ${maxTotalBytes} bytes.`,\n }),\n )\n }\n\n const aiExportValidation =\n manifest.aiExport === undefined\n ? undefined\n : validateDocsAiExportManifest(manifest.aiExport, {\n knownDocsPaths: normalizedPaths,\n })\n\n if (aiExportValidation) {\n issues.push(...aiExportValidation.issues)\n warnings.push(...aiExportValidation.warnings)\n }\n\n if (\n issues.length > 0 ||\n !sourceValidation.source ||\n aiExportValidation?.ok === false\n ) {\n return {\n issues,\n ok: false,\n warnings,\n }\n }\n\n return {\n data: {\n deleteBehavior: deleteBehaviorValidation.deleteBehavior,\n ...(aiExportValidation?.ok ? { aiExport: aiExportValidation.manifest } : {}),\n files: validatedFiles,\n mode: modeValidation.mode,\n publish,\n source: sourceValidation.source,\n version: 1,\n },\n issues,\n ok: true,\n warnings,\n }\n}\n\nexport type { DocsManifest, DocsManifestFile, DocsManifestSource }\n"],"names":["DEFAULT_DOCS_ROUTE_BASE","DEFAULT_MAX_DOCS_FILE_BYTES","DEFAULT_MAX_DOCS_FILES","DEFAULT_MAX_DOCS_TOTAL_BYTES","validateDocsAiExportManifest","parseDocsFrontmatter","resolveDocsTitle","sha256Hex","deriveRouteFromSourcePath","normalizeDocsPath","syncModes","Set","deleteBehaviors","isRecord","value","Array","isArray","createIssue","code","message","path","byteLength","content","Buffer","validateSource","allowedSourceIds","source","id","trim","issues","includes","branch","undefined","commit","repository","root","validateMode","mode","has","validateDeleteBehavior","deleteBehavior","validateManifestFile","file","maxFileBytes","routeBase","warnings","fileBytes","normalizedPath","ok","push","computedHash","sha256","test","toLowerCase","parsedFrontmatter","route","slug","frontmatter","sourcePath","validatedFile","title","validateDocsManifest","manifest","options","maxFiles","maxTotalBytes","version","sourceValidation","modeValidation","deleteBehaviorValidation","publish","files","length","validatedFiles","normalizedPaths","totalBytes","fileValidation","add","aiExportValidation","aiExport","knownDocsPaths","data"],"mappings":"AAUA,SACEA,uBAAuB,EACvBC,2BAA2B,EAC3BC,sBAAsB,EACtBC,4BAA4B,QACvB,kBAAiB;AACxB,SAASC,4BAA4B,QAAQ,wBAAuB;AACpE,SACEC,oBAAoB,EACpBC,gBAAgB,QACX,mBAAkB;AACzB,SAASC,SAAS,QAAQ,YAAW;AACrC,SAASC,yBAAyB,EAAEC,iBAAiB,QAAQ,aAAY;AAiDzE,MAAMC,YAAY,IAAIC,IAAkB;IAAC;IAAW;CAAO;AAC3D,MAAMC,kBAAkB,IAAID,IAAwB;IAClD;IACA;IACA;IACA;CACD;AAED,MAAME,WAAW,CAACC,QAChB,OAAOA,UAAU,YAAYA,UAAU,QAAQ,CAACC,MAAMC,OAAO,CAACF;AAEhE,MAAMG,cAAc,CAAC,EACnBC,IAAI,EACJC,OAAO,EACPC,IAAI,EACgB,GAA2B,CAAA;QAC/CF;QACAC;QACAC;IACF,CAAA;AAEA,MAAMC,aAAa,CAACC,UAA4BC,OAAOF,UAAU,CAACC,SAAS;AAE3E,MAAME,iBAAiB,CAAC,EACtBC,gBAAgB,EAChBC,MAAM,EAIP;IAIC,IAAI,CAACb,SAASa,WAAW,OAAOA,OAAOC,EAAE,KAAK,YAAYD,OAAOC,EAAE,CAACC,IAAI,OAAO,IAAI;QACjF,OAAO;YACLC,QAAQ;gBACNZ,YAAY;oBACVC,MAAM;oBACNC,SAAS;gBACX;aACD;QACH;IACF;IAEA,IAAIM,oBAAoB,CAACA,iBAAiBK,QAAQ,CAACJ,OAAOC,EAAE,GAAG;QAC7D,OAAO;YACLE,QAAQ;gBACNZ,YAAY;oBACVC,MAAM;oBACNC,SAAS,CAAC,oBAAoB,EAAEO,OAAOC,EAAE,CAAC,iBAAiB,CAAC;gBAC9D;aACD;QACH;IACF;IAEA,OAAO;QACLE,QAAQ,EAAE;QACVH,QAAQ;YACNC,IAAID,OAAOC,EAAE;YACbI,QAAQ,OAAOL,OAAOK,MAAM,KAAK,WAAWL,OAAOK,MAAM,GAAGC;YAC5DC,QAAQ,OAAOP,OAAOO,MAAM,KAAK,WAAWP,OAAOO,MAAM,GAAGD;YAC5DE,YAAY,OAAOR,OAAOQ,UAAU,KAAK,WAAWR,OAAOQ,UAAU,GAAGF;YACxEG,MAAM,OAAOT,OAAOS,IAAI,KAAK,WAAWT,OAAOS,IAAI,GAAGH;QACxD;IACF;AACF;AAEA,MAAMI,eAAe,CAACC;IAIpB,IAAIA,SAASL,WAAW;QACtB,OAAO;YACLH,QAAQ,EAAE;YACVQ,MAAM;QACR;IACF;IAEA,IAAI3B,UAAU4B,GAAG,CAACD,OAAuB;QACvC,OAAO;YACLR,QAAQ,EAAE;YACVQ,MAAMA;QACR;IACF;IAEA,OAAO;QACLR,QAAQ;YACNZ,YAAY;gBACVC,MAAM;gBACNC,SAAS;YACX;SACD;QACDkB,MAAM;IACR;AACF;AAEA,MAAME,yBAAyB,CAACC;IAI9B,IAAIA,mBAAmBR,WAAW;QAChC,OAAO;YACLQ,gBAAgB;YAChBX,QAAQ,EAAE;QACZ;IACF;IAEA,IAAIjB,gBAAgB0B,GAAG,CAACE,iBAAuC;QAC7D,OAAO;YACLA,gBAAgBA;YAChBX,QAAQ,EAAE;QACZ;IACF;IAEA,OAAO;QACLW,gBAAgB;QAChBX,QAAQ;YACNZ,YAAY;gBACVC,MAAM;gBACNC,SAAS;YACX;SACD;IACH;AACF;AAEA,MAAMsB,uBAAuB,CAAC,EAC5BC,IAAI,EACJC,YAAY,EACZC,SAAS,EAKV;IAOC,MAAMf,SAAgC,EAAE;IACxC,MAAMgB,WAAkC,EAAE;IAE1C,IAAI,CAAChC,SAAS6B,OAAO;QACnB,OAAO;YACLI,WAAW;YACXjB,QAAQ;gBACNZ,YAAY;oBACVC,MAAM;oBACNC,SAAS;gBACX;aACD;YACD0B;QACF;IACF;IAEA,MAAMzB,OAAO,OAAOsB,KAAKtB,IAAI,KAAK,WAAWsB,KAAKtB,IAAI,GAAGY;IACzD,MAAMV,UAAU,OAAOoB,KAAKpB,OAAO,KAAK,WAAWoB,KAAKpB,OAAO,GAAGU;IAElE,IAAI,CAACZ,QAAQE,YAAYU,WAAW;QAClC,OAAO;YACLc,WAAW;YACXjB,QAAQ;gBACNZ,YAAY;oBACVC,MAAM;oBACNC,SAAS;oBACTC;gBACF;aACD;YACDyB;QACF;IACF;IAEA,MAAME,iBAAiBtC,kBAAkBW;IAEzC,IAAI,CAAC2B,eAAeC,EAAE,EAAE;QACtB,OAAO;YACLF,WAAW;YACXjB,QAAQ;gBACNZ,YAAY;oBACVC,MAAM6B,eAAe7B,IAAI;oBACzBC,SAAS4B,eAAe5B,OAAO;oBAC/BC;gBACF;aACD;YACDyB;QACF;IACF;IAEA,MAAMC,YAAYzB,WAAWC;IAE7B,IAAIwB,YAAYH,cAAc;QAC5Bd,OAAOoB,IAAI,CACThC,YAAY;YACVC,MAAM;YACNC,SAAS,CAAC,6BAA6B,EAAEwB,aAAa,OAAO,CAAC;YAC9DvB,MAAM2B,eAAe3B,IAAI;QAC3B;IAEJ;IAEA,MAAM8B,eAAe3C,UAAUe;IAE/B,IACEoB,KAAKS,MAAM,KAAKnB,aACf,CAAA,OAAOU,KAAKS,MAAM,KAAK,YACtB,CAAC,kBAAkBC,IAAI,CAACV,KAAKS,MAAM,KACnCT,KAAKS,MAAM,CAACE,WAAW,OAAOH,YAAW,GAC3C;QACArB,OAAOoB,IAAI,CACThC,YAAY;YACVC,MAAM;YACNC,SAAS;YACTC,MAAM2B,eAAe3B,IAAI;QAC3B;IAEJ;IAEA,MAAMkC,oBAAoBjD,qBAAqBiB,SAAS;QACtDF,MAAM2B,eAAe3B,IAAI;IAC3B;IAEAS,OAAOoB,IAAI,IAAIK,kBAAkBzB,MAAM;IACvCgB,SAASI,IAAI,IAAIK,kBAAkBT,QAAQ;IAE3C,MAAMU,QAAQ/C,0BAA0B;QACtCgD,MAAMF,kBAAkBG,WAAW,CAACD,IAAI;QACxCZ;QACAc,YAAYX,eAAe3B,IAAI;IACjC;IAEA,OAAO;QACL0B;QACAjB;QACAkB,gBAAgBA,eAAe3B,IAAI;QACnCuC,eAAe;YACbrC,SAASgC,kBAAkBhC,OAAO;YAClCmC,aAAaH,kBAAkBG,WAAW;YAC1CrC,MAAM2B,eAAe3B,IAAI;YACzBmC;YACAJ,QAAQD;YACRU,OAAOtD,iBAAiB;gBACtBgB,SAASgC,kBAAkBhC,OAAO;gBAClCmC,aAAaH,kBAAkBG,WAAW;gBAC1CC,YAAYX,eAAe3B,IAAI;YACjC;QACF;QACAyB;IACF;AACF;AAEA,OAAO,MAAMgB,uBAAuB,CAClCC,UACAC,UAAiC,CAAC,CAAC;IAEnC,MAAMlC,SAAgC,EAAE;IACxC,MAAMgB,WAAkC,EAAE;IAC1C,MAAMF,eAAeoB,QAAQpB,YAAY,IAAI1C;IAC7C,MAAM+D,WAAWD,QAAQC,QAAQ,IAAI9D;IACrC,MAAM+D,gBAAgBF,QAAQE,aAAa,IAAI9D;IAC/C,MAAMyC,YAAYmB,QAAQnB,SAAS,IAAI5C;IAEvC,IAAI,CAACa,SAASiD,WAAW;QACvB,OAAO;YACLjC,QAAQ;gBACNZ,YAAY;oBACVC,MAAM;oBACNC,SAAS;gBACX;aACD;YACD6B,IAAI;YACJH;QACF;IACF;IAEA,IAAIiB,SAASI,OAAO,KAAK,GAAG;QAC1BrC,OAAOoB,IAAI,CACThC,YAAY;YACVC,MAAM;YACNC,SAAS;QACX;IAEJ;IAEA,MAAMgD,mBAAmB3C,eAAe;QACtCC,kBAAkBsC,QAAQtC,gBAAgB;QAC1CC,QAAQoC,SAASpC,MAAM;IACzB;IAEAG,OAAOoB,IAAI,IAAIkB,iBAAiBtC,MAAM;IAEtC,MAAMuC,iBAAiBhC,aAAa0B,SAASzB,IAAI;IACjDR,OAAOoB,IAAI,IAAImB,eAAevC,MAAM;IAEpC,MAAMwC,2BAA2B9B,uBAAuBuB,SAAStB,cAAc;IAC/EX,OAAOoB,IAAI,IAAIoB,yBAAyBxC,MAAM;IAE9C,MAAMyC,UACJR,SAASQ,OAAO,KAAKtC,YAAY,QAAQ8B,SAASQ,OAAO,KAAK,OAAO,OAAO;IAE9E,IAAIR,SAASQ,OAAO,KAAKtC,aAAa,OAAO8B,SAASQ,OAAO,KAAK,WAAW;QAC3EzC,OAAOoB,IAAI,CACThC,YAAY;YACVC,MAAM;YACNC,SAAS;QACX;IAEJ;IAEA,MAAMoD,QAAQxD,MAAMC,OAAO,CAAC8C,SAASS,KAAK,IAAIT,SAASS,KAAK,GAAGvC;IAE/D,IAAI,CAACuC,SAASA,MAAMC,MAAM,KAAK,GAAG;QAChC3C,OAAOoB,IAAI,CACThC,YAAY;YACVC,MAAM;YACNC,SAAS;QACX;IAEJ;IAEA,IAAIoD,SAASA,MAAMC,MAAM,GAAGR,UAAU;QACpCnC,OAAOoB,IAAI,CACThC,YAAY;YACVC,MAAM;YACNC,SAAS,CAAC,uCAAuC,EAAE6C,SAAS,CAAC,CAAC;QAChE;IAEJ;IAEA,MAAMS,iBAA8C,EAAE;IACtD,MAAMC,kBAAkB,IAAI/D;IAC5B,IAAIgE,aAAa;IAEjB,KAAK,MAAMjC,QAAQ6B,SAAS,EAAE,CAAE;QAC9B,MAAMK,iBAAiBnC,qBAAqB;YAC1CC;YACAC;YACAC;QACF;QAEA+B,cAAcC,eAAe9B,SAAS;QACtCjB,OAAOoB,IAAI,IAAI2B,eAAe/C,MAAM;QACpCgB,SAASI,IAAI,IAAI2B,eAAe/B,QAAQ;QAExC,IAAI+B,eAAe7B,cAAc,EAAE;YACjC,IAAI2B,gBAAgBpC,GAAG,CAACsC,eAAe7B,cAAc,GAAG;gBACtDlB,OAAOoB,IAAI,CACThC,YAAY;oBACVC,MAAM;oBACNC,SAAS;oBACTC,MAAMwD,eAAe7B,cAAc;gBACrC;YAEJ;YAEA2B,gBAAgBG,GAAG,CAACD,eAAe7B,cAAc;QACnD;QAEA,IAAI6B,eAAejB,aAAa,EAAE;YAChCc,eAAexB,IAAI,CAAC2B,eAAejB,aAAa;QAClD;IACF;IAEA,IAAIgB,aAAaV,eAAe;QAC9BpC,OAAOoB,IAAI,CACThC,YAAY;YACVC,MAAM;YACNC,SAAS,CAAC,+CAA+C,EAAE8C,cAAc,OAAO,CAAC;QACnF;IAEJ;IAEA,MAAMa,qBACJhB,SAASiB,QAAQ,KAAK/C,YAClBA,YACA5B,6BAA6B0D,SAASiB,QAAQ,EAAE;QAC9CC,gBAAgBN;IAClB;IAEN,IAAII,oBAAoB;QACtBjD,OAAOoB,IAAI,IAAI6B,mBAAmBjD,MAAM;QACxCgB,SAASI,IAAI,IAAI6B,mBAAmBjC,QAAQ;IAC9C;IAEA,IACEhB,OAAO2C,MAAM,GAAG,KAChB,CAACL,iBAAiBzC,MAAM,IACxBoD,oBAAoB9B,OAAO,OAC3B;QACA,OAAO;YACLnB;YACAmB,IAAI;YACJH;QACF;IACF;IAEA,OAAO;QACLoC,MAAM;YACJzC,gBAAgB6B,yBAAyB7B,cAAc;YACvD,GAAIsC,oBAAoB9B,KAAK;gBAAE+B,UAAUD,mBAAmBhB,QAAQ;YAAC,IAAI,CAAC,CAAC;YAC3ES,OAAOE;YACPpC,MAAM+B,eAAe/B,IAAI;YACzBiC;YACA5C,QAAQyC,iBAAiBzC,MAAM;YAC/BwC,SAAS;QACX;QACArC;QACAmB,IAAI;QACJH;IACF;AACF,EAAC"}
@@ -0,0 +1,84 @@
1
+ export type PayloadMarkdownDocsConfig = {
2
+ auth?: PayloadMarkdownDocsAuthConfig;
3
+ collections?: PayloadMarkdownDocsCollectionsConfig;
4
+ enabled?: boolean;
5
+ endpoint?: PayloadMarkdownDocsEndpointConfig;
6
+ routing?: PayloadMarkdownDocsRoutingConfig;
7
+ sources?: PayloadMarkdownDocsSourceConfig[];
8
+ sync?: PayloadMarkdownDocsSyncConfig;
9
+ target?: PayloadMarkdownDocsTargetConfig;
10
+ };
11
+ export type PayloadMarkdownDocsEndpointConfig = {
12
+ maxBodyBytes?: number;
13
+ path?: string;
14
+ };
15
+ export type PayloadMarkdownDocsAuthConfig = {
16
+ allowedEnvironments?: string[];
17
+ allowedRefs?: string[];
18
+ allowedRepositories?: string[];
19
+ allowedRepositoryOwners?: string[];
20
+ allowedWorkflowRefs?: string[];
21
+ allowedWorkflows?: string[];
22
+ allowPullRequests?: boolean;
23
+ audience: string;
24
+ issuer?: string;
25
+ jwksUrl?: string;
26
+ maxSkewSeconds?: number;
27
+ mode: 'github-oidc';
28
+ } | {
29
+ keys: PayloadMarkdownDocsEd25519Key[];
30
+ maxSkewSeconds?: number;
31
+ mode: 'ed25519';
32
+ nonceTtlSeconds?: number;
33
+ } | {
34
+ mode: 'disabled';
35
+ };
36
+ export type PayloadMarkdownDocsEd25519Key = {
37
+ id: string;
38
+ publicKey: string;
39
+ };
40
+ export type PayloadMarkdownDocsCollectionConfig = {
41
+ enabled?: boolean;
42
+ slug?: string;
43
+ };
44
+ export type PayloadMarkdownDocsCollectionsConfig = {
45
+ docs?: PayloadMarkdownDocsCollectionConfig;
46
+ docsGroups?: PayloadMarkdownDocsCollectionConfig;
47
+ docsSets?: PayloadMarkdownDocsCollectionConfig;
48
+ nonces?: PayloadMarkdownDocsCollectionConfig;
49
+ syncRuns?: PayloadMarkdownDocsCollectionConfig;
50
+ };
51
+ export type PayloadMarkdownDocsPagesRoutingConfig = {
52
+ allowBridgePages?: boolean;
53
+ bridgeField?: string;
54
+ collection?: string;
55
+ enabled?: boolean;
56
+ routeField?: string;
57
+ };
58
+ export type PayloadMarkdownDocsRoutingConfig = {
59
+ pages?: PayloadMarkdownDocsPagesRoutingConfig;
60
+ };
61
+ export type PayloadMarkdownDocsSourceConfig = {
62
+ id: string;
63
+ root?: string;
64
+ routeBase: string;
65
+ };
66
+ export type PayloadMarkdownDocsTargetConfig = {
67
+ collection: string;
68
+ markdownField: string;
69
+ routeField?: string;
70
+ type: 'existingCollection';
71
+ } | {
72
+ enableDrafts?: boolean;
73
+ markdownField?: string;
74
+ slug?: string;
75
+ type: 'docsCollection';
76
+ };
77
+ export type PayloadMarkdownDocsSyncConfig = {
78
+ allowHardDelete?: boolean;
79
+ allowPublish?: boolean;
80
+ allowWrites?: boolean;
81
+ defaultPublishMode?: 'draft' | 'preserve' | 'published';
82
+ deleteBehavior?: 'archive' | 'delete' | 'draft' | 'ignore';
83
+ requireDryRunBeforeApply?: boolean;
84
+ };
package/dist/types.js ADDED
@@ -0,0 +1,3 @@
1
+ export { };
2
+
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/types.ts"],"sourcesContent":["export type PayloadMarkdownDocsConfig = {\n auth?: PayloadMarkdownDocsAuthConfig\n collections?: PayloadMarkdownDocsCollectionsConfig\n enabled?: boolean\n endpoint?: PayloadMarkdownDocsEndpointConfig\n routing?: PayloadMarkdownDocsRoutingConfig\n sources?: PayloadMarkdownDocsSourceConfig[]\n sync?: PayloadMarkdownDocsSyncConfig\n target?: PayloadMarkdownDocsTargetConfig\n}\n\nexport type PayloadMarkdownDocsEndpointConfig = {\n maxBodyBytes?: number\n path?: string\n}\n\nexport type PayloadMarkdownDocsAuthConfig =\n | {\n allowedEnvironments?: string[]\n allowedRefs?: string[]\n allowedRepositories?: string[]\n allowedRepositoryOwners?: string[]\n allowedWorkflowRefs?: string[]\n allowedWorkflows?: string[]\n allowPullRequests?: boolean\n audience: string\n issuer?: string\n jwksUrl?: string\n maxSkewSeconds?: number\n mode: 'github-oidc'\n }\n | {\n keys: PayloadMarkdownDocsEd25519Key[]\n maxSkewSeconds?: number\n mode: 'ed25519'\n nonceTtlSeconds?: number\n }\n | {\n mode: 'disabled'\n }\n\nexport type PayloadMarkdownDocsEd25519Key = {\n id: string\n publicKey: string\n}\n\nexport type PayloadMarkdownDocsCollectionConfig = {\n enabled?: boolean\n slug?: string\n}\n\nexport type PayloadMarkdownDocsCollectionsConfig = {\n docs?: PayloadMarkdownDocsCollectionConfig\n docsGroups?: PayloadMarkdownDocsCollectionConfig\n docsSets?: PayloadMarkdownDocsCollectionConfig\n nonces?: PayloadMarkdownDocsCollectionConfig\n syncRuns?: PayloadMarkdownDocsCollectionConfig\n}\n\nexport type PayloadMarkdownDocsPagesRoutingConfig = {\n allowBridgePages?: boolean\n bridgeField?: string\n collection?: string\n enabled?: boolean\n routeField?: string\n}\n\nexport type PayloadMarkdownDocsRoutingConfig = {\n pages?: PayloadMarkdownDocsPagesRoutingConfig\n}\n\nexport type PayloadMarkdownDocsSourceConfig = {\n id: string\n root?: string\n routeBase: string\n}\n\nexport type PayloadMarkdownDocsTargetConfig =\n | {\n collection: string\n markdownField: string\n routeField?: string\n type: 'existingCollection'\n }\n | {\n enableDrafts?: boolean\n markdownField?: string\n slug?: string\n type: 'docsCollection'\n }\n\nexport type PayloadMarkdownDocsSyncConfig = {\n allowHardDelete?: boolean\n allowPublish?: boolean\n allowWrites?: boolean\n defaultPublishMode?: 'draft' | 'preserve' | 'published'\n deleteBehavior?: 'archive' | 'delete' | 'draft' | 'ignore'\n requireDryRunBeforeApply?: boolean\n}\n"],"names":[],"mappings":"AA2FA,WAOC"}
package/package.json ADDED
@@ -0,0 +1,143 @@
1
+ {
2
+ "name": "@valkyrianlabs/payload-markdown-docs",
3
+ "version": "0.1.0-canary.0",
4
+ "description": "Git-backed Markdown documentation sync for Payload CMS, powered by payload-markdown.",
5
+ "bin": {
6
+ "payload-markdown-docs": "./dist/cli/index.js"
7
+ },
8
+ "keywords": [
9
+ "payload",
10
+ "payload-plugin",
11
+ "markdown",
12
+ "documentation",
13
+ "docs"
14
+ ],
15
+ "license": "MIT",
16
+ "type": "module",
17
+ "exports": {
18
+ ".": {
19
+ "import": "./src/index.ts",
20
+ "types": "./src/index.ts",
21
+ "default": "./src/index.ts"
22
+ },
23
+ "./admin": {
24
+ "import": "./src/admin/index.ts",
25
+ "types": "./src/admin/index.ts",
26
+ "default": "./src/admin/index.ts"
27
+ },
28
+ "./next": {
29
+ "import": "./src/next/index.ts",
30
+ "types": "./src/next/index.ts",
31
+ "default": "./src/next/index.ts"
32
+ }
33
+ },
34
+ "main": "./src/index.ts",
35
+ "types": "./src/index.ts",
36
+ "files": [
37
+ "dist"
38
+ ],
39
+ "scripts": {
40
+ "build": "pnpm clean && pnpm copyfiles && pnpm build:types && pnpm build:swc",
41
+ "build:swc": "swc ./src -d ./dist --config-file .swcrc --strip-leading-paths --ignore \"**/*.spec.ts\"",
42
+ "build:types": "tsc -p tsconfig.build.json --outDir dist --rootDir ./src",
43
+ "clean": "rimraf {dist,*.tsbuildinfo}",
44
+ "copyfiles": "copyfiles -u 1 \"src/**/*.{html,css,scss,ttf,woff,woff2,eot,svg,jpg,png,json,md}\" dist/",
45
+ "dev": "next dev dev --turbo",
46
+ "dev:docs:keygen": "pnpm dev:payload run ./dev/scripts/create-docs-keypair.ts",
47
+ "dev:docs:manifest": "node --import @swc-node/register/esm-register ./src/cli/index.ts manifest ./dev/docs-fixtures/basic --source payload-markdown-docs --root docs --route-base /plugins/payload-markdown-docs --pretty",
48
+ "dev:docs:plan": "node --import @swc-node/register/esm-register ./src/cli/index.ts plan ./dev/docs-fixtures/basic --source payload-markdown-docs --root docs --route-base /plugins/payload-markdown-docs",
49
+ "dev:docs:reset": "pnpm dev:payload run ./dev/scripts/reset-docs.ts",
50
+ "dev:docs:seed": "pnpm dev:payload run ./dev/scripts/seed-docs.ts",
51
+ "dev:docs:validate": "node --import @swc-node/register/esm-register ./src/cli/index.ts validate ./dev/docs-fixtures/basic --source payload-markdown-docs --root docs --route-base /plugins/payload-markdown-docs",
52
+ "dev:generate-importmap": "pnpm dev:payload generate:importmap",
53
+ "dev:generate-types": "pnpm dev:payload generate:types",
54
+ "dev:payload": "cross-env PAYLOAD_CONFIG_PATH=./dev/payload.config.ts payload",
55
+ "generate:importmap": "pnpm dev:generate-importmap",
56
+ "generate:types": "pnpm dev:generate-types",
57
+ "lint": "eslint",
58
+ "lint:fix": "eslint ./src --fix",
59
+ "prepack": "pnpm build",
60
+ "test": "pnpm test:int && pnpm test:e2e",
61
+ "test:e2e": "playwright test",
62
+ "test:int": "vitest"
63
+ },
64
+ "devDependencies": {
65
+ "@eslint/eslintrc": "^3.3.5",
66
+ "@payloadcms/db-postgres": "latest",
67
+ "@payloadcms/db-sqlite": "latest",
68
+ "@payloadcms/eslint-config": "3.28.0",
69
+ "@payloadcms/next": "latest",
70
+ "@payloadcms/richtext-lexical": "latest",
71
+ "@payloadcms/ui": "latest",
72
+ "@playwright/test": "1.58.2",
73
+ "@swc-node/register": "1.10.9",
74
+ "@swc/cli": "0.6.0",
75
+ "@types/node": "22.19.9",
76
+ "@types/react": "19.2.14",
77
+ "@types/react-dom": "19.2.3",
78
+ "copyfiles": "2.4.1",
79
+ "cross-env": "^7.0.3",
80
+ "eslint": "^9.39.4",
81
+ "eslint-config-next": "16.2.3",
82
+ "graphql": "^16.13.2",
83
+ "mongodb-memory-server": "10.1.4",
84
+ "next": "16.2.3",
85
+ "open": "^10.2.0",
86
+ "payload": "latest",
87
+ "prettier": "^3.8.3",
88
+ "qs-esm": "8.0.1",
89
+ "react": "19.2.4",
90
+ "react-dom": "19.2.4",
91
+ "rimraf": "3.0.2",
92
+ "sharp": "0.34.2",
93
+ "sort-package-json": "^2.15.1",
94
+ "typescript": "5.7.3",
95
+ "vite-tsconfig-paths": "6.0.5",
96
+ "vitest": "4.0.18",
97
+ "tailwindcss": "^4.2.4",
98
+ "@tailwindcss/typography": "^0.5.19",
99
+ "@tailwindcss/postcss": "^4.2.4",
100
+ "postcss": "^8.5.13"
101
+ },
102
+ "peerDependencies": {
103
+ "payload": ">=3.0.0"
104
+ },
105
+ "engines": {
106
+ "node": "^18.20.2 || >=20.9.0",
107
+ "pnpm": "^9 || ^10"
108
+ },
109
+ "publishConfig": {
110
+ "exports": {
111
+ ".": {
112
+ "import": "./dist/index.js",
113
+ "types": "./dist/index.d.ts",
114
+ "default": "./dist/index.js"
115
+ },
116
+ "./admin": {
117
+ "import": "./dist/admin/index.js",
118
+ "types": "./dist/admin/index.d.ts",
119
+ "default": "./dist/admin/index.js"
120
+ },
121
+ "./next": {
122
+ "import": "./dist/next/index.js",
123
+ "types": "./dist/next/index.d.ts",
124
+ "default": "./dist/next/index.js"
125
+ }
126
+ },
127
+ "main": "./dist/index.js",
128
+ "types": "./dist/index.d.ts"
129
+ },
130
+ "pnpm": {
131
+ "onlyBuiltDependencies": [
132
+ "@swc/core",
133
+ "esbuild",
134
+ "mongodb-memory-server",
135
+ "sharp",
136
+ "unrs-resolver"
137
+ ]
138
+ },
139
+ "registry": "https://registry.npmjs.org/",
140
+ "dependencies": {
141
+ "@valkyrianlabs/payload-markdown": "latest"
142
+ }
143
+ }