@valkyrianlabs/payload-markdown-docs 0.4.0 → 0.4.2
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 +8 -0
- package/dist/admin/DocsSetManager.d.ts +1 -1
- package/dist/admin/DocsSetManager.js +42 -1
- package/dist/admin/DocsSetManager.js.map +1 -1
- package/dist/cli/commands/push.js +17 -7
- package/dist/cli/commands/push.js.map +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/collections/docsSets.d.ts +3 -1
- package/dist/collections/docsSets.js +10 -1
- package/dist/collections/docsSets.js.map +1 -1
- package/dist/endpoints/index.d.ts +3 -1
- package/dist/endpoints/index.js +1 -0
- package/dist/endpoints/index.js.map +1 -1
- package/dist/endpoints/publishGeneratedDocs.d.ts +6 -0
- package/dist/endpoints/publishGeneratedDocs.js +76 -0
- package/dist/endpoints/publishGeneratedDocs.js.map +1 -0
- package/dist/payload/publishGeneratedDocs.d.ts +29 -0
- package/dist/payload/publishGeneratedDocs.js +78 -0
- package/dist/payload/publishGeneratedDocs.js.map +1 -0
- package/dist/plugin.js +2 -0
- 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/index.d.ts +1 -0
- 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/reference/admin.md +2 -1
- package/package.json +3 -1
package/README.md
CHANGED
|
@@ -110,12 +110,20 @@ const docsLinks = await getPayloadMarkdownDocsLinks({ payload })
|
|
|
110
110
|
|
|
111
111
|
## Validate Locally
|
|
112
112
|
|
|
113
|
+
In an app or docs repository that has installed this package:
|
|
114
|
+
|
|
113
115
|
```bash
|
|
114
116
|
pnpm exec payload-markdown-docs validate ./docs --source payload-markdown-docs
|
|
115
117
|
pnpm exec payload-markdown-docs manifest ./docs --source payload-markdown-docs --pretty
|
|
116
118
|
pnpm exec payload-markdown-docs plan ./docs --source payload-markdown-docs
|
|
117
119
|
```
|
|
118
120
|
|
|
121
|
+
From this package source checkout, use the local source CLI instead:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
pnpm cli validate ./docs --source payload-markdown-docs
|
|
125
|
+
```
|
|
126
|
+
|
|
119
127
|
In GitHub Actions, `--source` can be omitted when the docs set slug matches the
|
|
120
128
|
repository name. The CLI infers it from `GITHUB_REPOSITORY`.
|
|
121
129
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { UIFieldServerProps } from 'payload';
|
|
2
|
-
export declare const DocsSetManager: ({ id, field, payload, req
|
|
2
|
+
export declare const DocsSetManager: ({ id, field, payload, req }: UIFieldServerProps) => Promise<import("react/jsx-runtime").JSX.Element>;
|
|
@@ -18,6 +18,15 @@ const formatDate = (value)=>{
|
|
|
18
18
|
}
|
|
19
19
|
return date.toISOString();
|
|
20
20
|
};
|
|
21
|
+
const normalizeRoute = (route = '/')=>{
|
|
22
|
+
const normalized = `/${route.trim()}`.replace(/\/+/g, '/');
|
|
23
|
+
return normalized.length > 1 ? normalized.replace(/\/+$/g, '') : normalized;
|
|
24
|
+
};
|
|
25
|
+
const getPublishAction = ({ apiRoute, docsSetId, docsSetsCollectionSlug, redirect })=>{
|
|
26
|
+
const path = `${normalizeRoute(apiRoute ?? '/api')}/${docsSetsCollectionSlug}/${encodeURIComponent(String(docsSetId))}/publish-generated-docs`;
|
|
27
|
+
return `${path}?redirect=${encodeURIComponent(redirect)}`;
|
|
28
|
+
};
|
|
29
|
+
const getDocsSetAdminURL = ({ adminRoute, docsSetId, docsSetsCollectionSlug })=>`${normalizeRoute(adminRoute ?? '/admin')}/collections/${docsSetsCollectionSlug}/${encodeURIComponent(String(docsSetId))}`;
|
|
21
30
|
const StatusLabel = ({ item })=>{
|
|
22
31
|
if (item.archived) {
|
|
23
32
|
return /*#__PURE__*/ _jsx("span", {
|
|
@@ -210,6 +219,7 @@ export const DocsSetManager = async ({ id, field, payload, req })=>{
|
|
|
210
219
|
const docsCollectionSlug = custom.docsCollectionSlug ?? DEFAULT_DOCS_COLLECTION_SLUG;
|
|
211
220
|
const docsGroupsCollectionSlug = custom.docsGroupsCollectionSlug ?? DEFAULT_DOCS_GROUPS_COLLECTION_SLUG;
|
|
212
221
|
const docsSetsCollectionSlug = custom.docsSetsCollectionSlug ?? DEFAULT_DOCS_SETS_COLLECTION_SLUG;
|
|
222
|
+
const canPublishGeneratedDocs = custom.docsEnableDrafts === true && custom.allowPublish === true;
|
|
213
223
|
if (!id) {
|
|
214
224
|
return /*#__PURE__*/ _jsxs("section", {
|
|
215
225
|
children: [
|
|
@@ -230,6 +240,17 @@ export const DocsSetManager = async ({ id, field, payload, req })=>{
|
|
|
230
240
|
docsSetsCollectionSlug,
|
|
231
241
|
payload: payload
|
|
232
242
|
});
|
|
243
|
+
const docsSetAdminURL = getDocsSetAdminURL({
|
|
244
|
+
adminRoute: req.payload.config.routes.admin,
|
|
245
|
+
docsSetId: id,
|
|
246
|
+
docsSetsCollectionSlug
|
|
247
|
+
});
|
|
248
|
+
const publishAction = getPublishAction({
|
|
249
|
+
apiRoute: req.payload.config.routes.api,
|
|
250
|
+
docsSetId: id,
|
|
251
|
+
docsSetsCollectionSlug,
|
|
252
|
+
redirect: docsSetAdminURL
|
|
253
|
+
});
|
|
233
254
|
return /*#__PURE__*/ _jsxs("section", {
|
|
234
255
|
children: [
|
|
235
256
|
/*#__PURE__*/ _jsxs("header", {
|
|
@@ -263,7 +284,27 @@ export const DocsSetManager = async ({ id, field, payload, req })=>{
|
|
|
263
284
|
}),
|
|
264
285
|
/*#__PURE__*/ _jsx(Summary, {
|
|
265
286
|
data: data
|
|
266
|
-
})
|
|
287
|
+
}),
|
|
288
|
+
data.summary.drafts > 0 ? /*#__PURE__*/ _jsxs("div", {
|
|
289
|
+
children: [
|
|
290
|
+
/*#__PURE__*/ _jsxs("p", {
|
|
291
|
+
children: [
|
|
292
|
+
data.summary.drafts,
|
|
293
|
+
" generated docs records are drafts and are not public."
|
|
294
|
+
]
|
|
295
|
+
}),
|
|
296
|
+
canPublishGeneratedDocs ? /*#__PURE__*/ _jsx("form", {
|
|
297
|
+
action: publishAction,
|
|
298
|
+
method: "post",
|
|
299
|
+
children: /*#__PURE__*/ _jsx("button", {
|
|
300
|
+
type: "submit",
|
|
301
|
+
children: "Publish generated docs"
|
|
302
|
+
})
|
|
303
|
+
}) : /*#__PURE__*/ _jsx("p", {
|
|
304
|
+
children: "Publishing is disabled for this plugin config."
|
|
305
|
+
})
|
|
306
|
+
]
|
|
307
|
+
}) : null
|
|
267
308
|
]
|
|
268
309
|
}),
|
|
269
310
|
data.warnings.length > 0 ? /*#__PURE__*/ _jsxs("section", {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/admin/DocsSetManager.tsx"],"sourcesContent":["import type { UIFieldServerProps } from 'payload'\nimport type { ReactNode } from 'react'\n\nimport type {\n DocsSetManagerData,\n DocsSetManagerDocItem,\n DocsSetManagerPayloadOperations,\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 { getDocsSetManagerData } from './docsSetManagerData.js'\n\ntype DocsSetManagerFieldCustom = {\n docsCollectionSlug?: string\n docsGroupsCollectionSlug?: string\n docsSetsCollectionSlug?: string\n}\n\nconst getFieldCustom = (\n field: UIFieldServerProps['field'],\n): DocsSetManagerFieldCustom => {\n const custom = 'custom' in field ? field.custom : undefined\n\n if (!custom || typeof custom !== 'object') {\n return {}\n }\n\n return custom as DocsSetManagerFieldCustom\n}\n\nconst formatDate = (value?: string): string => {\n if (!value) {\n return 'Never'\n }\n\n const date = new Date(value)\n\n if (Number.isNaN(date.getTime())) {\n return value\n }\n\n return date.toISOString()\n}\n\nconst StatusLabel = ({ item }: { item: DocsSetManagerDocItem }) => {\n if (item.archived) {\n return <span>archived</span>\n }\n\n if (item.draft) {\n return <span>draft</span>\n }\n\n if (item.published) {\n return <span>published</span>\n }\n\n return <span>synced</span>\n}\n\nconst OverrideSummary = ({ item }: { item: DocsSetManagerDocItem }) => {\n if (item.overrideSummary.length === 0) {\n return <span>none</span>\n }\n\n return <span>{item.overrideSummary.join(', ')}</span>\n}\n\nconst renderDocItem = (item: DocsSetManagerDocItem): ReactNode => {\n if (item.kind === 'folder') {\n return (\n <details key={item.id}>\n <summary>{item.title}</summary>\n <div>\n {item.children?.map((child) => renderDocItem(child))}\n </div>\n </details>\n )\n }\n\n return (\n <details key={item.id}>\n <summary>{item.sourcePath}</summary>\n <dl>\n <div>\n <dt>Route</dt>\n <dd>{item.route || 'Missing route'}</dd>\n </div>\n <div>\n <dt>Title</dt>\n <dd>{item.title}</dd>\n </div>\n <div>\n <dt>Status</dt>\n <dd>\n <StatusLabel item={item} />\n </dd>\n </div>\n <div>\n <dt>Overrides</dt>\n <dd>\n <OverrideSummary item={item} />\n </dd>\n </div>\n </dl>\n {item.adminURL ? <a href={item.adminURL}>Open generated doc</a> : null}\n </details>\n )\n}\n\nconst Summary = ({ data }: { data: DocsSetManagerData }) => (\n <dl>\n <div>\n <dt>Docs</dt>\n <dd>{data.summary.total}</dd>\n </div>\n <div>\n <dt>Archived</dt>\n <dd>{data.summary.archived}</dd>\n </div>\n <div>\n <dt>Drafts</dt>\n <dd>{data.summary.drafts}</dd>\n </div>\n <div>\n <dt>Published</dt>\n <dd>{data.summary.published}</dd>\n </div>\n <div>\n <dt>Hidden from nav</dt>\n <dd>{data.summary.hiddenFromNav}</dd>\n </div>\n <div>\n <dt>With overrides</dt>\n <dd>{data.summary.withOverrides}</dd>\n </div>\n <div>\n <dt>Last sync</dt>\n <dd>{formatDate(data.sync?.lastSyncedAt)}</dd>\n </div>\n <div>\n <dt>Last status</dt>\n <dd>{data.sync?.lastStatus ?? 'unknown'}</dd>\n </div>\n </dl>\n)\n\nexport const DocsSetManager = async ({\n id,\n field,\n payload,\n req,\n}: UIFieldServerProps) => {\n const custom = getFieldCustom(field)\n const docsCollectionSlug = custom.docsCollectionSlug ?? DEFAULT_DOCS_COLLECTION_SLUG\n const docsGroupsCollectionSlug =\n custom.docsGroupsCollectionSlug ?? DEFAULT_DOCS_GROUPS_COLLECTION_SLUG\n const docsSetsCollectionSlug =\n custom.docsSetsCollectionSlug ?? DEFAULT_DOCS_SETS_COLLECTION_SLUG\n\n if (!id) {\n return (\n <section>\n <h2>Generated Docs</h2>\n <p>Save this docs set before reviewing generated docs records.</p>\n </section>\n )\n }\n\n const data = await getDocsSetManagerData({\n adminRoute: req.payload.config.routes.admin,\n docsCollectionSlug,\n docsGroupsCollectionSlug,\n docsSetId: String(id),\n docsSetsCollectionSlug,\n payload: payload as DocsSetManagerPayloadOperations,\n })\n\n return (\n <section>\n <header>\n <h2>Generated Docs</h2>\n <p>\n Review generated docs records for {data.docsSet.title}. Source docs remain\n Git-backed; per-doc overrides can be edited by opening a generated doc.\n </p>\n </header>\n\n <section>\n <h3>Effective Route</h3>\n <p>{data.docsSet.routeBase || 'No route available yet'}</p>\n </section>\n\n <section>\n <h3>Sync Summary</h3>\n <Summary data={data} />\n </section>\n\n {data.warnings.length > 0 ? (\n <section>\n <h3>Warnings</h3>\n <ul>\n {data.warnings.map((warning) => (\n <li key={`${warning.docId ?? 'docs-set'}:${warning.message}`}>\n {warning.sourcePath ? `${warning.sourcePath}: ` : null}\n {warning.message}\n </li>\n ))}\n </ul>\n </section>\n ) : null}\n\n <section>\n <h3>Generated Docs</h3>\n {data.tree.length > 0 ? (\n <div>{data.tree.map((item) => renderDocItem(item))}</div>\n ) : (\n <p>No generated docs records are linked to this docs set yet.</p>\n )}\n </section>\n </section>\n )\n}\n"],"names":["DEFAULT_DOCS_COLLECTION_SLUG","DEFAULT_DOCS_GROUPS_COLLECTION_SLUG","DEFAULT_DOCS_SETS_COLLECTION_SLUG","getDocsSetManagerData","getFieldCustom","field","custom","undefined","formatDate","value","date","Date","Number","isNaN","getTime","toISOString","StatusLabel","item","archived","span","draft","published","OverrideSummary","overrideSummary","length","join","renderDocItem","kind","details","summary","title","div","children","map","child","id","sourcePath","dl","dt","dd","route","adminURL","a","href","Summary","data","total","drafts","hiddenFromNav","withOverrides","sync","lastSyncedAt","lastStatus","DocsSetManager","payload","req","docsCollectionSlug","docsGroupsCollectionSlug","docsSetsCollectionSlug","section","h2","p","adminRoute","config","routes","admin","docsSetId","String","header","docsSet","h3","routeBase","warnings","ul","warning","li","message","docId","tree"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/admin/DocsSetManager.tsx"],"sourcesContent":["import type { UIFieldServerProps } from 'payload'\nimport type { ReactNode } from 'react'\n\nimport type {\n DocsSetManagerData,\n DocsSetManagerDocItem,\n DocsSetManagerPayloadOperations,\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 { getDocsSetManagerData } from './docsSetManagerData.js'\n\ntype DocsSetManagerFieldCustom = {\n allowPublish?: boolean\n docsCollectionSlug?: string\n docsEnableDrafts?: boolean\n docsGroupsCollectionSlug?: string\n docsSetsCollectionSlug?: string\n}\n\nconst getFieldCustom = (field: UIFieldServerProps['field']): DocsSetManagerFieldCustom => {\n const custom = 'custom' in field ? field.custom : undefined\n\n if (!custom || typeof custom !== 'object') {\n return {}\n }\n\n return custom as DocsSetManagerFieldCustom\n}\n\nconst formatDate = (value?: string): string => {\n if (!value) {\n return 'Never'\n }\n\n const date = new Date(value)\n\n if (Number.isNaN(date.getTime())) {\n return value\n }\n\n return date.toISOString()\n}\n\nconst normalizeRoute = (route = '/'): string => {\n const normalized = `/${route.trim()}`.replace(/\\/+/g, '/')\n\n return normalized.length > 1 ? normalized.replace(/\\/+$/g, '') : normalized\n}\n\nconst getPublishAction = ({\n apiRoute,\n docsSetId,\n docsSetsCollectionSlug,\n redirect,\n}: {\n apiRoute?: string\n docsSetId: number | string\n docsSetsCollectionSlug: string\n redirect: string\n}): string => {\n const path = `${normalizeRoute(apiRoute ?? '/api')}/${docsSetsCollectionSlug}/${encodeURIComponent(String(docsSetId))}/publish-generated-docs`\n\n return `${path}?redirect=${encodeURIComponent(redirect)}`\n}\n\nconst getDocsSetAdminURL = ({\n adminRoute,\n docsSetId,\n docsSetsCollectionSlug,\n}: {\n adminRoute?: string\n docsSetId: number | string\n docsSetsCollectionSlug: string\n}): string =>\n `${normalizeRoute(adminRoute ?? '/admin')}/collections/${docsSetsCollectionSlug}/${encodeURIComponent(String(docsSetId))}`\n\nconst StatusLabel = ({ item }: { item: DocsSetManagerDocItem }) => {\n if (item.archived) {\n return <span>archived</span>\n }\n\n if (item.draft) {\n return <span>draft</span>\n }\n\n if (item.published) {\n return <span>published</span>\n }\n\n return <span>synced</span>\n}\n\nconst OverrideSummary = ({ item }: { item: DocsSetManagerDocItem }) => {\n if (item.overrideSummary.length === 0) {\n return <span>none</span>\n }\n\n return <span>{item.overrideSummary.join(', ')}</span>\n}\n\nconst renderDocItem = (item: DocsSetManagerDocItem): ReactNode => {\n if (item.kind === 'folder') {\n return (\n <details key={item.id}>\n <summary>{item.title}</summary>\n <div>{item.children?.map((child) => renderDocItem(child))}</div>\n </details>\n )\n }\n\n return (\n <details key={item.id}>\n <summary>{item.sourcePath}</summary>\n <dl>\n <div>\n <dt>Route</dt>\n <dd>{item.route || 'Missing route'}</dd>\n </div>\n <div>\n <dt>Title</dt>\n <dd>{item.title}</dd>\n </div>\n <div>\n <dt>Status</dt>\n <dd>\n <StatusLabel item={item} />\n </dd>\n </div>\n <div>\n <dt>Overrides</dt>\n <dd>\n <OverrideSummary item={item} />\n </dd>\n </div>\n </dl>\n {item.adminURL ? <a href={item.adminURL}>Open generated doc</a> : null}\n </details>\n )\n}\n\nconst Summary = ({ data }: { data: DocsSetManagerData }) => (\n <dl>\n <div>\n <dt>Docs</dt>\n <dd>{data.summary.total}</dd>\n </div>\n <div>\n <dt>Archived</dt>\n <dd>{data.summary.archived}</dd>\n </div>\n <div>\n <dt>Drafts</dt>\n <dd>{data.summary.drafts}</dd>\n </div>\n <div>\n <dt>Published</dt>\n <dd>{data.summary.published}</dd>\n </div>\n <div>\n <dt>Hidden from nav</dt>\n <dd>{data.summary.hiddenFromNav}</dd>\n </div>\n <div>\n <dt>With overrides</dt>\n <dd>{data.summary.withOverrides}</dd>\n </div>\n <div>\n <dt>Last sync</dt>\n <dd>{formatDate(data.sync?.lastSyncedAt)}</dd>\n </div>\n <div>\n <dt>Last status</dt>\n <dd>{data.sync?.lastStatus ?? 'unknown'}</dd>\n </div>\n </dl>\n)\n\nexport const DocsSetManager = async ({ id, field, payload, req }: UIFieldServerProps) => {\n const custom = getFieldCustom(field)\n const docsCollectionSlug = custom.docsCollectionSlug ?? DEFAULT_DOCS_COLLECTION_SLUG\n const docsGroupsCollectionSlug =\n custom.docsGroupsCollectionSlug ?? DEFAULT_DOCS_GROUPS_COLLECTION_SLUG\n const docsSetsCollectionSlug = custom.docsSetsCollectionSlug ?? DEFAULT_DOCS_SETS_COLLECTION_SLUG\n const canPublishGeneratedDocs = custom.docsEnableDrafts === true && custom.allowPublish === true\n\n if (!id) {\n return (\n <section>\n <h2>Generated Docs</h2>\n <p>Save this docs set before reviewing generated docs records.</p>\n </section>\n )\n }\n\n const data = await getDocsSetManagerData({\n adminRoute: req.payload.config.routes.admin,\n docsCollectionSlug,\n docsGroupsCollectionSlug,\n docsSetId: String(id),\n docsSetsCollectionSlug,\n payload: payload as DocsSetManagerPayloadOperations,\n })\n const docsSetAdminURL = getDocsSetAdminURL({\n adminRoute: req.payload.config.routes.admin,\n docsSetId: id,\n docsSetsCollectionSlug,\n })\n const publishAction = getPublishAction({\n apiRoute: req.payload.config.routes.api,\n docsSetId: id,\n docsSetsCollectionSlug,\n redirect: docsSetAdminURL,\n })\n\n return (\n <section>\n <header>\n <h2>Generated Docs</h2>\n <p>\n Review generated docs records for {data.docsSet.title}. Source docs remain Git-backed;\n per-doc overrides can be edited by opening a generated doc.\n </p>\n </header>\n\n <section>\n <h3>Effective Route</h3>\n <p>{data.docsSet.routeBase || 'No route available yet'}</p>\n </section>\n\n <section>\n <h3>Sync Summary</h3>\n <Summary data={data} />\n {data.summary.drafts > 0 ? (\n <div>\n <p>{data.summary.drafts} generated docs records are drafts and are not public.</p>\n {canPublishGeneratedDocs ? (\n <form action={publishAction} method=\"post\">\n <button type=\"submit\">Publish generated docs</button>\n </form>\n ) : (\n <p>Publishing is disabled for this plugin config.</p>\n )}\n </div>\n ) : null}\n </section>\n\n {data.warnings.length > 0 ? (\n <section>\n <h3>Warnings</h3>\n <ul>\n {data.warnings.map((warning) => (\n <li key={`${warning.docId ?? 'docs-set'}:${warning.message}`}>\n {warning.sourcePath ? `${warning.sourcePath}: ` : null}\n {warning.message}\n </li>\n ))}\n </ul>\n </section>\n ) : null}\n\n <section>\n <h3>Generated Docs</h3>\n {data.tree.length > 0 ? (\n <div>{data.tree.map((item) => renderDocItem(item))}</div>\n ) : (\n <p>No generated docs records are linked to this docs set yet.</p>\n )}\n </section>\n </section>\n )\n}\n"],"names":["DEFAULT_DOCS_COLLECTION_SLUG","DEFAULT_DOCS_GROUPS_COLLECTION_SLUG","DEFAULT_DOCS_SETS_COLLECTION_SLUG","getDocsSetManagerData","getFieldCustom","field","custom","undefined","formatDate","value","date","Date","Number","isNaN","getTime","toISOString","normalizeRoute","route","normalized","trim","replace","length","getPublishAction","apiRoute","docsSetId","docsSetsCollectionSlug","redirect","path","encodeURIComponent","String","getDocsSetAdminURL","adminRoute","StatusLabel","item","archived","span","draft","published","OverrideSummary","overrideSummary","join","renderDocItem","kind","details","summary","title","div","children","map","child","id","sourcePath","dl","dt","dd","adminURL","a","href","Summary","data","total","drafts","hiddenFromNav","withOverrides","sync","lastSyncedAt","lastStatus","DocsSetManager","payload","req","docsCollectionSlug","docsGroupsCollectionSlug","canPublishGeneratedDocs","docsEnableDrafts","allowPublish","section","h2","p","config","routes","admin","docsSetAdminURL","publishAction","api","header","docsSet","h3","routeBase","form","action","method","button","type","warnings","ul","warning","li","message","docId","tree"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { readFile } from 'node:fs/promises';
|
|
2
|
-
import { signDocsSyncRequest } from '../../security/index.js';
|
|
2
|
+
import { DocsSyncKeyError, signDocsSyncRequest } from '../../security/index.js';
|
|
3
3
|
import { buildDocsManifest, sha256Hex, validateDocsManifest } from '../../sync/index.js';
|
|
4
4
|
import { readDocsAiExportManifest, walkDocsFiles } from '../filesystem.js';
|
|
5
5
|
import { formatIssues, formatPushSummary, printJson } from '../format.js';
|
|
@@ -258,12 +258,22 @@ export const runPushCommand = async (args, httpPost = postJson, httpGet = getJso
|
|
|
258
258
|
}
|
|
259
259
|
};
|
|
260
260
|
} else {
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
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
|
+
}
|
|
267
277
|
}
|
|
268
278
|
const response = await httpPost({
|
|
269
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 { 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 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 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","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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"}
|
|
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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"}
|
package/dist/cli/index.js
CHANGED
|
@@ -87,7 +87,7 @@ Options:
|
|
|
87
87
|
Options:
|
|
88
88
|
--endpoint <url> Full Payload sync endpoint URL.
|
|
89
89
|
--key-id <id> Server-configured Ed25519 key id.
|
|
90
|
-
--private-key-file <path>
|
|
90
|
+
--private-key-file <path> Private key file from keygen, or an unencrypted OpenSSH Ed25519 key.
|
|
91
91
|
--private-key-env <name> Environment variable containing the private key.
|
|
92
92
|
--github-oidc Use GitHub Actions OIDC bearer auth instead of Ed25519.
|
|
93
93
|
--oidc-token-env <name> Environment variable containing an already-fetched OIDC token.
|
package/dist/cli/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/cli/index.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nimport type { CliCommandName, CliResult, ParsedCliArgs } from './types.js'\n\nimport { runInstallCommand } from './commands/install.js'\nimport { runKeygenCommand } from './commands/keygen.js'\nimport { runManifestCommand } from './commands/manifest.js'\nimport { runPlanCommand } from './commands/plan.js'\nimport { runPushCommand } from './commands/push.js'\nimport { runValidateCommand } from './commands/validate.js'\nimport { getFlagString, parseCliArgs } from './parseArgs.js'\n\nconst helpText = `payload-markdown-docs\n\nUsage:\n payload-markdown-docs validate <docs-root> [options]\n payload-markdown-docs manifest <docs-root> [options]\n payload-markdown-docs plan <docs-root> [options]\n payload-markdown-docs push <docs-root> [options]\n payload-markdown-docs keygen [options]\n payload-markdown-docs install skill --codex [options]\n\nCommands:\n validate Validate a local Markdown docs directory.\n manifest Print a JSON docs manifest for a local Markdown docs directory.\n plan Build a dry sync plan against optional existing docs records.\n push Sign and upload a docs manifest to a Payload sync endpoint.\n keygen Generate Ed25519 keys for signed sync.\n install Install local AI-agent guidance for docs maintenance.\n`\n\nconst commandHelp: Record<Exclude<CliCommandName, 'help'>, string> = {\n install: `payload-markdown-docs install skill --codex\n\nAliases:\n payload-markdown-docs install ai-skill --codex\n payload-markdown-docs install skill --agent codex\n\nOptions:\n --codex Install the Codex skill pack.\n --agent <codex> Agent target. Currently only codex.\n --out <path> Output directory. Defaults to .agents/skills/payload-markdown-docs.\n --docs-root <path> Docs root to mention in installed guidance. Defaults to ./docs.\n --package-manager <name> pnpm, npm, yarn, or bun. Auto-detected when omitted.\n --force Overwrite existing skill files.\n --dry-run Print planned files without writing.\n --help Show this help.\n\nInstalls local AI-agent guidance only. It does not sync docs, call Payload, or run package manager commands.\n`,\n keygen: `payload-markdown-docs keygen\n\nOptions:\n --format <pem|base64> Output key format. Defaults to pem.\n --out <dir> Write docs-sync-public.pem and docs-sync-private.pem.\n --force Overwrite existing key files when used with --out.\n --help Show this help.\n`,\n manifest: `payload-markdown-docs manifest <docs-root>\n\nOptions:\n --source <id> Docs set slug. Defaults to the GitHub repository name in GitHub Actions, otherwise local-docs.\n --repository <repo> Source repository metadata.\n --branch <branch> Source branch metadata.\n --commit <sha> Source commit metadata.\n --pretty Pretty-print JSON.\n --max-files <number> Maximum file count.\n --max-file-bytes <number> Maximum single file size.\n --max-total-bytes <number> Maximum total Markdown bytes.\n --help Show this help.\n`,\n plan: `payload-markdown-docs plan <docs-root>\n\nOptions:\n --existing <path> JSON array of existing docs records.\n --delete-behavior <value> archive, delete, draft, or ignore.\n --json Print full plan JSON.\n --pretty Pretty-print JSON output.\n --source <id> Docs set slug. Defaults to the GitHub repository name in GitHub Actions, otherwise local-docs.\n --repository <repo> Source repository metadata.\n --branch <branch> Source branch metadata.\n --commit <sha> Source commit metadata.\n --max-files <number> Maximum file count.\n --max-file-bytes <number> Maximum single file size.\n --max-total-bytes <number> Maximum total Markdown bytes.\n --help Show this help.\n`,\n push: `payload-markdown-docs push <docs-root>\n\nOptions:\n --endpoint <url> Full Payload sync endpoint URL.\n --key-id <id> Server-configured Ed25519 key id.\n --private-key-file <path> PEM private key file from keygen.\n --private-key-env <name> Environment variable containing the private key.\n --github-oidc Use GitHub Actions OIDC bearer auth instead of Ed25519.\n --oidc-token-env <name> Environment variable containing an already-fetched OIDC token.\n --dry-run Upload as dry-run mode. This is the default.\n --sync Upload as sync mode. Requires server sync.allowWrites.\n --publish Request published output. Server must allow publishing.\n --delete-behavior <value> archive, delete, draft, or ignore. Defaults to archive.\n --json Print structured JSON output.\n --pretty Pretty-print JSON output with --json.\n --source <id> Docs set slug. Defaults to the GitHub repository name in GitHub Actions, otherwise local-docs.\n --repository <repo> Source repository metadata.\n --branch <branch> Source branch metadata.\n --commit <sha> Source commit metadata.\n --max-files <number> Maximum file count.\n --max-file-bytes <number> Maximum single file size.\n --max-total-bytes <number> Maximum total Markdown bytes.\n --help Show this help.\n\nExamples:\n Ed25519:\n 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\n\n GitHub OIDC:\n payload-markdown-docs push ./docs --endpoint \"$DOCS_SYNC_ENDPOINT\" --github-oidc --sync\n\nGitHub OIDC requires workflow permissions: id-token: write and contents: read.\nHard delete requires explicit server sync.allowHardDelete. Existing collection and block targets are not supported yet.\n`,\n validate: `payload-markdown-docs validate <docs-root>\n\nOptions:\n --json Print validation JSON.\n --pretty Pretty-print JSON output.\n --source <id> Docs set slug. Defaults to the GitHub repository name in GitHub Actions, otherwise local-docs.\n --repository <repo> Source repository metadata.\n --branch <branch> Source branch metadata.\n --commit <sha> Source commit metadata.\n --max-files <number> Maximum file count.\n --max-file-bytes <number> Maximum single file size.\n --max-total-bytes <number> Maximum total Markdown bytes.\n --help Show this help.\n`,\n}\n\nconst getHelpForArgs = (args: ParsedCliArgs): string => {\n if (args.command !== 'help') {\n return commandHelp[args.command]\n }\n\n const topic = getFlagString(args, 'topic') ?? args.positionals[0]\n\n if (\n topic === 'keygen' ||\n topic === 'install' ||\n topic === 'manifest' ||\n topic === 'plan' ||\n topic === 'push' ||\n topic === 'validate'\n ) {\n return commandHelp[topic]\n }\n\n return helpText\n}\n\nexport const runCli = async (argv: string[]): Promise<CliResult> => {\n try {\n const parsed = parseCliArgs(argv)\n\n if (!parsed.ok) {\n return {\n exitCode: 1,\n stderr: `${parsed.error}\\n`,\n }\n }\n\n if (parsed.args.command === 'help' || parsed.args.flags.help === true) {\n return {\n exitCode: 0,\n stdout: getHelpForArgs(parsed.args),\n }\n }\n\n if (parsed.args.command === 'keygen') {\n return runKeygenCommand(parsed.args)\n }\n\n if (parsed.args.command === 'install') {\n return runInstallCommand(parsed.args)\n }\n\n if (parsed.args.command === 'manifest') {\n return runManifestCommand(parsed.args)\n }\n\n if (parsed.args.command === 'plan') {\n return runPlanCommand(parsed.args)\n }\n\n if (parsed.args.command === 'push') {\n return runPushCommand(parsed.args)\n }\n\n if (parsed.args.command === 'validate') {\n return runValidateCommand(parsed.args)\n }\n\n return {\n exitCode: 1,\n stderr: 'Unknown command.\\n',\n }\n } catch (error) {\n return {\n exitCode: 2,\n stderr: error instanceof Error ? `${error.message}\\n` : 'Unexpected internal error.\\n',\n }\n }\n}\n\nconst isCliEntrypoint = (): boolean => {\n if (!process.argv[1]) {\n return false\n }\n\n return fileURLToPath(import.meta.url) === path.resolve(process.argv[1])\n}\n\nif (isCliEntrypoint()) {\n const result = await runCli(process.argv.slice(2))\n\n if (result.stdout) {\n process.stdout.write(result.stdout)\n }\n\n if (result.stderr) {\n process.stderr.write(result.stderr)\n }\n\n process.exitCode = result.exitCode\n}\n"],"names":["path","fileURLToPath","runInstallCommand","runKeygenCommand","runManifestCommand","runPlanCommand","runPushCommand","runValidateCommand","getFlagString","parseCliArgs","helpText","commandHelp","install","keygen","manifest","plan","push","validate","getHelpForArgs","args","command","topic","positionals","runCli","argv","parsed","ok","exitCode","stderr","error","flags","help","stdout","Error","message","isCliEntrypoint","process","url","resolve","result","slice","write"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/cli/index.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport path from 'node:path'\nimport { fileURLToPath } from 'node:url'\n\nimport type { CliCommandName, CliResult, ParsedCliArgs } from './types.js'\n\nimport { runInstallCommand } from './commands/install.js'\nimport { runKeygenCommand } from './commands/keygen.js'\nimport { runManifestCommand } from './commands/manifest.js'\nimport { runPlanCommand } from './commands/plan.js'\nimport { runPushCommand } from './commands/push.js'\nimport { runValidateCommand } from './commands/validate.js'\nimport { getFlagString, parseCliArgs } from './parseArgs.js'\n\nconst helpText = `payload-markdown-docs\n\nUsage:\n payload-markdown-docs validate <docs-root> [options]\n payload-markdown-docs manifest <docs-root> [options]\n payload-markdown-docs plan <docs-root> [options]\n payload-markdown-docs push <docs-root> [options]\n payload-markdown-docs keygen [options]\n payload-markdown-docs install skill --codex [options]\n\nCommands:\n validate Validate a local Markdown docs directory.\n manifest Print a JSON docs manifest for a local Markdown docs directory.\n plan Build a dry sync plan against optional existing docs records.\n push Sign and upload a docs manifest to a Payload sync endpoint.\n keygen Generate Ed25519 keys for signed sync.\n install Install local AI-agent guidance for docs maintenance.\n`\n\nconst commandHelp: Record<Exclude<CliCommandName, 'help'>, string> = {\n install: `payload-markdown-docs install skill --codex\n\nAliases:\n payload-markdown-docs install ai-skill --codex\n payload-markdown-docs install skill --agent codex\n\nOptions:\n --codex Install the Codex skill pack.\n --agent <codex> Agent target. Currently only codex.\n --out <path> Output directory. Defaults to .agents/skills/payload-markdown-docs.\n --docs-root <path> Docs root to mention in installed guidance. Defaults to ./docs.\n --package-manager <name> pnpm, npm, yarn, or bun. Auto-detected when omitted.\n --force Overwrite existing skill files.\n --dry-run Print planned files without writing.\n --help Show this help.\n\nInstalls local AI-agent guidance only. It does not sync docs, call Payload, or run package manager commands.\n`,\n keygen: `payload-markdown-docs keygen\n\nOptions:\n --format <pem|base64> Output key format. Defaults to pem.\n --out <dir> Write docs-sync-public.pem and docs-sync-private.pem.\n --force Overwrite existing key files when used with --out.\n --help Show this help.\n`,\n manifest: `payload-markdown-docs manifest <docs-root>\n\nOptions:\n --source <id> Docs set slug. Defaults to the GitHub repository name in GitHub Actions, otherwise local-docs.\n --repository <repo> Source repository metadata.\n --branch <branch> Source branch metadata.\n --commit <sha> Source commit metadata.\n --pretty Pretty-print JSON.\n --max-files <number> Maximum file count.\n --max-file-bytes <number> Maximum single file size.\n --max-total-bytes <number> Maximum total Markdown bytes.\n --help Show this help.\n`,\n plan: `payload-markdown-docs plan <docs-root>\n\nOptions:\n --existing <path> JSON array of existing docs records.\n --delete-behavior <value> archive, delete, draft, or ignore.\n --json Print full plan JSON.\n --pretty Pretty-print JSON output.\n --source <id> Docs set slug. Defaults to the GitHub repository name in GitHub Actions, otherwise local-docs.\n --repository <repo> Source repository metadata.\n --branch <branch> Source branch metadata.\n --commit <sha> Source commit metadata.\n --max-files <number> Maximum file count.\n --max-file-bytes <number> Maximum single file size.\n --max-total-bytes <number> Maximum total Markdown bytes.\n --help Show this help.\n`,\n push: `payload-markdown-docs push <docs-root>\n\nOptions:\n --endpoint <url> Full Payload sync endpoint URL.\n --key-id <id> Server-configured Ed25519 key id.\n --private-key-file <path> Private key file from keygen, or an unencrypted OpenSSH Ed25519 key.\n --private-key-env <name> Environment variable containing the private key.\n --github-oidc Use GitHub Actions OIDC bearer auth instead of Ed25519.\n --oidc-token-env <name> Environment variable containing an already-fetched OIDC token.\n --dry-run Upload as dry-run mode. This is the default.\n --sync Upload as sync mode. Requires server sync.allowWrites.\n --publish Request published output. Server must allow publishing.\n --delete-behavior <value> archive, delete, draft, or ignore. Defaults to archive.\n --json Print structured JSON output.\n --pretty Pretty-print JSON output with --json.\n --source <id> Docs set slug. Defaults to the GitHub repository name in GitHub Actions, otherwise local-docs.\n --repository <repo> Source repository metadata.\n --branch <branch> Source branch metadata.\n --commit <sha> Source commit metadata.\n --max-files <number> Maximum file count.\n --max-file-bytes <number> Maximum single file size.\n --max-total-bytes <number> Maximum total Markdown bytes.\n --help Show this help.\n\nExamples:\n Ed25519:\n 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\n\n GitHub OIDC:\n payload-markdown-docs push ./docs --endpoint \"$DOCS_SYNC_ENDPOINT\" --github-oidc --sync\n\nGitHub OIDC requires workflow permissions: id-token: write and contents: read.\nHard delete requires explicit server sync.allowHardDelete. Existing collection and block targets are not supported yet.\n`,\n validate: `payload-markdown-docs validate <docs-root>\n\nOptions:\n --json Print validation JSON.\n --pretty Pretty-print JSON output.\n --source <id> Docs set slug. Defaults to the GitHub repository name in GitHub Actions, otherwise local-docs.\n --repository <repo> Source repository metadata.\n --branch <branch> Source branch metadata.\n --commit <sha> Source commit metadata.\n --max-files <number> Maximum file count.\n --max-file-bytes <number> Maximum single file size.\n --max-total-bytes <number> Maximum total Markdown bytes.\n --help Show this help.\n`,\n}\n\nconst getHelpForArgs = (args: ParsedCliArgs): string => {\n if (args.command !== 'help') {\n return commandHelp[args.command]\n }\n\n const topic = getFlagString(args, 'topic') ?? args.positionals[0]\n\n if (\n topic === 'keygen' ||\n topic === 'install' ||\n topic === 'manifest' ||\n topic === 'plan' ||\n topic === 'push' ||\n topic === 'validate'\n ) {\n return commandHelp[topic]\n }\n\n return helpText\n}\n\nexport const runCli = async (argv: string[]): Promise<CliResult> => {\n try {\n const parsed = parseCliArgs(argv)\n\n if (!parsed.ok) {\n return {\n exitCode: 1,\n stderr: `${parsed.error}\\n`,\n }\n }\n\n if (parsed.args.command === 'help' || parsed.args.flags.help === true) {\n return {\n exitCode: 0,\n stdout: getHelpForArgs(parsed.args),\n }\n }\n\n if (parsed.args.command === 'keygen') {\n return runKeygenCommand(parsed.args)\n }\n\n if (parsed.args.command === 'install') {\n return runInstallCommand(parsed.args)\n }\n\n if (parsed.args.command === 'manifest') {\n return runManifestCommand(parsed.args)\n }\n\n if (parsed.args.command === 'plan') {\n return runPlanCommand(parsed.args)\n }\n\n if (parsed.args.command === 'push') {\n return runPushCommand(parsed.args)\n }\n\n if (parsed.args.command === 'validate') {\n return runValidateCommand(parsed.args)\n }\n\n return {\n exitCode: 1,\n stderr: 'Unknown command.\\n',\n }\n } catch (error) {\n return {\n exitCode: 2,\n stderr: error instanceof Error ? `${error.message}\\n` : 'Unexpected internal error.\\n',\n }\n }\n}\n\nconst isCliEntrypoint = (): boolean => {\n if (!process.argv[1]) {\n return false\n }\n\n return fileURLToPath(import.meta.url) === path.resolve(process.argv[1])\n}\n\nif (isCliEntrypoint()) {\n const result = await runCli(process.argv.slice(2))\n\n if (result.stdout) {\n process.stdout.write(result.stdout)\n }\n\n if (result.stderr) {\n process.stderr.write(result.stderr)\n }\n\n process.exitCode = result.exitCode\n}\n"],"names":["path","fileURLToPath","runInstallCommand","runKeygenCommand","runManifestCommand","runPlanCommand","runPushCommand","runValidateCommand","getFlagString","parseCliArgs","helpText","commandHelp","install","keygen","manifest","plan","push","validate","getHelpForArgs","args","command","topic","positionals","runCli","argv","parsed","ok","exitCode","stderr","error","flags","help","stdout","Error","message","isCliEntrypoint","process","url","resolve","result","slice","write"],"mappings":";AAEA,OAAOA,UAAU,YAAW;AAC5B,SAASC,aAAa,QAAQ,WAAU;AAIxC,SAASC,iBAAiB,QAAQ,wBAAuB;AACzD,SAASC,gBAAgB,QAAQ,uBAAsB;AACvD,SAASC,kBAAkB,QAAQ,yBAAwB;AAC3D,SAASC,cAAc,QAAQ,qBAAoB;AACnD,SAASC,cAAc,QAAQ,qBAAoB;AACnD,SAASC,kBAAkB,QAAQ,yBAAwB;AAC3D,SAASC,aAAa,EAAEC,YAAY,QAAQ,iBAAgB;AAE5D,MAAMC,WAAW,CAAC;;;;;;;;;;;;;;;;;AAiBlB,CAAC;AAED,MAAMC,cAA+D;IACnEC,SAAS,CAAC;;;;;;;;;;;;;;;;;AAiBZ,CAAC;IACCC,QAAQ,CAAC;;;;;;;AAOX,CAAC;IACCC,UAAU,CAAC;;;;;;;;;;;;AAYb,CAAC;IACCC,MAAM,CAAC;;;;;;;;;;;;;;;AAeT,CAAC;IACCC,MAAM,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiCT,CAAC;IACCC,UAAU,CAAC;;;;;;;;;;;;;AAab,CAAC;AACD;AAEA,MAAMC,iBAAiB,CAACC;IACtB,IAAIA,KAAKC,OAAO,KAAK,QAAQ;QAC3B,OAAOT,WAAW,CAACQ,KAAKC,OAAO,CAAC;IAClC;IAEA,MAAMC,QAAQb,cAAcW,MAAM,YAAYA,KAAKG,WAAW,CAAC,EAAE;IAEjE,IACED,UAAU,YACVA,UAAU,aACVA,UAAU,cACVA,UAAU,UACVA,UAAU,UACVA,UAAU,YACV;QACA,OAAOV,WAAW,CAACU,MAAM;IAC3B;IAEA,OAAOX;AACT;AAEA,OAAO,MAAMa,SAAS,OAAOC;IAC3B,IAAI;QACF,MAAMC,SAAShB,aAAae;QAE5B,IAAI,CAACC,OAAOC,EAAE,EAAE;YACd,OAAO;gBACLC,UAAU;gBACVC,QAAQ,GAAGH,OAAOI,KAAK,CAAC,EAAE,CAAC;YAC7B;QACF;QAEA,IAAIJ,OAAON,IAAI,CAACC,OAAO,KAAK,UAAUK,OAAON,IAAI,CAACW,KAAK,CAACC,IAAI,KAAK,MAAM;YACrE,OAAO;gBACLJ,UAAU;gBACVK,QAAQd,eAAeO,OAAON,IAAI;YACpC;QACF;QAEA,IAAIM,OAAON,IAAI,CAACC,OAAO,KAAK,UAAU;YACpC,OAAOjB,iBAAiBsB,OAAON,IAAI;QACrC;QAEA,IAAIM,OAAON,IAAI,CAACC,OAAO,KAAK,WAAW;YACrC,OAAOlB,kBAAkBuB,OAAON,IAAI;QACtC;QAEA,IAAIM,OAAON,IAAI,CAACC,OAAO,KAAK,YAAY;YACtC,OAAOhB,mBAAmBqB,OAAON,IAAI;QACvC;QAEA,IAAIM,OAAON,IAAI,CAACC,OAAO,KAAK,QAAQ;YAClC,OAAOf,eAAeoB,OAAON,IAAI;QACnC;QAEA,IAAIM,OAAON,IAAI,CAACC,OAAO,KAAK,QAAQ;YAClC,OAAOd,eAAemB,OAAON,IAAI;QACnC;QAEA,IAAIM,OAAON,IAAI,CAACC,OAAO,KAAK,YAAY;YACtC,OAAOb,mBAAmBkB,OAAON,IAAI;QACvC;QAEA,OAAO;YACLQ,UAAU;YACVC,QAAQ;QACV;IACF,EAAE,OAAOC,OAAO;QACd,OAAO;YACLF,UAAU;YACVC,QAAQC,iBAAiBI,QAAQ,GAAGJ,MAAMK,OAAO,CAAC,EAAE,CAAC,GAAG;QAC1D;IACF;AACF,EAAC;AAED,MAAMC,kBAAkB;IACtB,IAAI,CAACC,QAAQZ,IAAI,CAAC,EAAE,EAAE;QACpB,OAAO;IACT;IAEA,OAAOvB,cAAc,YAAYoC,GAAG,MAAMrC,KAAKsC,OAAO,CAACF,QAAQZ,IAAI,CAAC,EAAE;AACxE;AAEA,IAAIW,mBAAmB;IACrB,MAAMI,SAAS,MAAMhB,OAAOa,QAAQZ,IAAI,CAACgB,KAAK,CAAC;IAE/C,IAAID,OAAOP,MAAM,EAAE;QACjBI,QAAQJ,MAAM,CAACS,KAAK,CAACF,OAAOP,MAAM;IACpC;IAEA,IAAIO,OAAOX,MAAM,EAAE;QACjBQ,QAAQR,MAAM,CAACa,KAAK,CAACF,OAAOX,MAAM;IACpC;IAEAQ,QAAQT,QAAQ,GAAGY,OAAOZ,QAAQ;AACpC"}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import type { CollectionConfig } from 'payload';
|
|
2
2
|
export type CreateDocsSetsCollectionOptions = {
|
|
3
|
+
allowPublish?: boolean;
|
|
3
4
|
docsCollectionSlug?: string;
|
|
5
|
+
docsEnableDrafts?: boolean;
|
|
4
6
|
docsGroupsCollectionSlug: string;
|
|
5
7
|
slug: string;
|
|
6
8
|
syncRunsCollectionSlug?: string;
|
|
7
9
|
};
|
|
8
|
-
export declare const createDocsSetsCollection: ({ slug, docsCollectionSlug, docsGroupsCollectionSlug, syncRunsCollectionSlug, }: CreateDocsSetsCollectionOptions) => CollectionConfig;
|
|
10
|
+
export declare const createDocsSetsCollection: ({ slug, allowPublish, docsCollectionSlug, docsEnableDrafts, docsGroupsCollectionSlug, syncRunsCollectionSlug, }: CreateDocsSetsCollectionOptions) => CollectionConfig;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { DOCS_GLOBALS_ADMIN_GROUP, DOCS_SET_MANAGER_COMPONENT } from '../constants.js';
|
|
2
|
-
|
|
2
|
+
import { createPublishGeneratedDocsEndpoint } from '../endpoints/publishGeneratedDocs.js';
|
|
3
|
+
export const createDocsSetsCollection = ({ slug, allowPublish = false, docsCollectionSlug, docsEnableDrafts = false, docsGroupsCollectionSlug, syncRunsCollectionSlug })=>({
|
|
3
4
|
slug,
|
|
4
5
|
admin: {
|
|
5
6
|
defaultColumns: [
|
|
@@ -11,6 +12,12 @@ export const createDocsSetsCollection = ({ slug, docsCollectionSlug, docsGroupsC
|
|
|
11
12
|
group: DOCS_GLOBALS_ADMIN_GROUP,
|
|
12
13
|
useAsTitle: 'title'
|
|
13
14
|
},
|
|
15
|
+
endpoints: docsCollectionSlug && docsEnableDrafts && allowPublish ? [
|
|
16
|
+
createPublishGeneratedDocsEndpoint({
|
|
17
|
+
docsCollectionSlug,
|
|
18
|
+
docsSetsCollectionSlug: slug
|
|
19
|
+
})
|
|
20
|
+
] : undefined,
|
|
14
21
|
fields: [
|
|
15
22
|
{
|
|
16
23
|
name: 'title',
|
|
@@ -135,7 +142,9 @@ export const createDocsSetsCollection = ({ slug, docsCollectionSlug, docsGroupsC
|
|
|
135
142
|
Field: DOCS_SET_MANAGER_COMPONENT
|
|
136
143
|
},
|
|
137
144
|
custom: {
|
|
145
|
+
allowPublish,
|
|
138
146
|
docsCollectionSlug,
|
|
147
|
+
docsEnableDrafts,
|
|
139
148
|
docsGroupsCollectionSlug,
|
|
140
149
|
docsSetsCollectionSlug: slug
|
|
141
150
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/collections/docsSets.ts"],"sourcesContent":["import type { CollectionConfig } from 'payload'\n\nimport {\n DOCS_GLOBALS_ADMIN_GROUP,\n DOCS_SET_MANAGER_COMPONENT,\n} from '../constants.js'\n\nexport type CreateDocsSetsCollectionOptions = {\n docsCollectionSlug?: string\n docsGroupsCollectionSlug: string\n slug: string\n syncRunsCollectionSlug?: string\n}\n\nexport const createDocsSetsCollection = ({\n slug,\n docsCollectionSlug,\n docsGroupsCollectionSlug,\n syncRunsCollectionSlug,\n}: CreateDocsSetsCollectionOptions): CollectionConfig => ({\n slug,\n admin: {\n defaultColumns: ['title', 'slug', 'branch', 'updatedAt'],\n group: DOCS_GLOBALS_ADMIN_GROUP,\n useAsTitle: 'title',\n },\n fields: [\n {\n name: 'title',\n type: 'text',\n required: true,\n },\n {\n name: 'slug',\n type: 'text',\n index: true,\n required: true,\n unique: true,\n },\n {\n name: 'group',\n type: 'relationship',\n relationTo: docsGroupsCollectionSlug,\n },\n {\n name: 'branch',\n type: 'text',\n admin: {\n description:\n 'Git branch allowed to publish this docs set. The full Git ref is handled internally.',\n },\n defaultValue: 'main',\n },\n {\n name: 'allowPullRequests',\n type: 'checkbox',\n admin: {\n description:\n 'Allow GitHub pull request events to dry-run or publish this docs set.',\n },\n defaultValue: false,\n },\n {\n name: 'description',\n type: 'textarea',\n },\n {\n name: 'advancedSecurity',\n type: 'group',\n admin: {\n description:\n 'Optional workflow lock-down. Leave disabled to allow any workflow from a trusted GitHub owner/repository and branch.',\n },\n fields: [\n {\n name: 'enabled',\n type: 'checkbox',\n admin: {\n description:\n 'When enabled, only the workflow refs listed below can publish this docs set.',\n },\n defaultValue: false,\n },\n {\n name: 'allowedWorkflowRefs',\n type: 'array',\n admin: {\n condition: (_data, siblingData) => siblingData?.enabled === true,\n description:\n 'Exact GitHub workflow refs, for example owner/repo/.github/workflows/publish-docs.yml@refs/heads/main.',\n },\n fields: [\n {\n name: 'value',\n type: 'text',\n required: true,\n },\n ],\n validate: (value, { siblingData }) => {\n const advancedSecurityData =\n typeof siblingData === 'object' && siblingData !== null\n ? (siblingData as { enabled?: unknown })\n : undefined\n\n if (\n advancedSecurityData?.enabled === true &&\n (!Array.isArray(value) || value.length === 0)\n ) {\n return 'Add at least one workflow ref or disable advanced security.'\n }\n\n return true\n },\n },\n ],\n },\n {\n name: 'aiExport',\n type: 'json',\n admin: {\n description:\n 'Parsed index.ai.yml control data for the raw Markdown AI export route.',\n },\n },\n {\n name: 'sync',\n type: 'group',\n fields: [\n {\n name: 'lastSyncedAt',\n type: 'date',\n },\n ...(syncRunsCollectionSlug\n ? [\n {\n name: 'lastSyncRunId',\n type: 'relationship' as const,\n relationTo: syncRunsCollectionSlug,\n },\n ]\n : []),\n {\n name: 'lastStatus',\n type: 'select',\n options: ['failed', 'pending', 'success'],\n },\n {\n name: 'docsCount',\n type: 'number',\n defaultValue: 0,\n },\n ],\n },\n ...(docsCollectionSlug\n ? [\n {\n name: 'docsSetManager',\n type: 'ui' as const,\n admin: {\n components: {\n Field: DOCS_SET_MANAGER_COMPONENT,\n },\n custom: {\n docsCollectionSlug,\n docsGroupsCollectionSlug,\n docsSetsCollectionSlug: slug,\n },\n },\n },\n ]\n : []),\n ],\n labels: {\n plural: 'Sets',\n singular: 'Set',\n },\n})\n"],"names":["DOCS_GLOBALS_ADMIN_GROUP","DOCS_SET_MANAGER_COMPONENT","createDocsSetsCollection","slug","docsCollectionSlug","docsGroupsCollectionSlug","syncRunsCollectionSlug","admin","defaultColumns","group","useAsTitle","fields","name","type","required","index","unique","relationTo","description","defaultValue","condition","_data","siblingData","enabled","validate","value","advancedSecurityData","
|
|
1
|
+
{"version":3,"sources":["../../src/collections/docsSets.ts"],"sourcesContent":["import type { CollectionConfig } from 'payload'\n\nimport {\n DOCS_GLOBALS_ADMIN_GROUP,\n DOCS_SET_MANAGER_COMPONENT,\n} from '../constants.js'\nimport { createPublishGeneratedDocsEndpoint } from '../endpoints/publishGeneratedDocs.js'\n\nexport type CreateDocsSetsCollectionOptions = {\n allowPublish?: boolean\n docsCollectionSlug?: string\n docsEnableDrafts?: boolean\n docsGroupsCollectionSlug: string\n slug: string\n syncRunsCollectionSlug?: string\n}\n\nexport const createDocsSetsCollection = ({\n slug,\n allowPublish = false,\n docsCollectionSlug,\n docsEnableDrafts = false,\n docsGroupsCollectionSlug,\n syncRunsCollectionSlug,\n}: CreateDocsSetsCollectionOptions): CollectionConfig => ({\n slug,\n admin: {\n defaultColumns: ['title', 'slug', 'branch', 'updatedAt'],\n group: DOCS_GLOBALS_ADMIN_GROUP,\n useAsTitle: 'title',\n },\n endpoints:\n docsCollectionSlug && docsEnableDrafts && allowPublish\n ? [\n createPublishGeneratedDocsEndpoint({\n docsCollectionSlug,\n docsSetsCollectionSlug: slug,\n }),\n ]\n : undefined,\n fields: [\n {\n name: 'title',\n type: 'text',\n required: true,\n },\n {\n name: 'slug',\n type: 'text',\n index: true,\n required: true,\n unique: true,\n },\n {\n name: 'group',\n type: 'relationship',\n relationTo: docsGroupsCollectionSlug,\n },\n {\n name: 'branch',\n type: 'text',\n admin: {\n description:\n 'Git branch allowed to publish this docs set. The full Git ref is handled internally.',\n },\n defaultValue: 'main',\n },\n {\n name: 'allowPullRequests',\n type: 'checkbox',\n admin: {\n description:\n 'Allow GitHub pull request events to dry-run or publish this docs set.',\n },\n defaultValue: false,\n },\n {\n name: 'description',\n type: 'textarea',\n },\n {\n name: 'advancedSecurity',\n type: 'group',\n admin: {\n description:\n 'Optional workflow lock-down. Leave disabled to allow any workflow from a trusted GitHub owner/repository and branch.',\n },\n fields: [\n {\n name: 'enabled',\n type: 'checkbox',\n admin: {\n description:\n 'When enabled, only the workflow refs listed below can publish this docs set.',\n },\n defaultValue: false,\n },\n {\n name: 'allowedWorkflowRefs',\n type: 'array',\n admin: {\n condition: (_data, siblingData) => siblingData?.enabled === true,\n description:\n 'Exact GitHub workflow refs, for example owner/repo/.github/workflows/publish-docs.yml@refs/heads/main.',\n },\n fields: [\n {\n name: 'value',\n type: 'text',\n required: true,\n },\n ],\n validate: (value, { siblingData }) => {\n const advancedSecurityData =\n typeof siblingData === 'object' && siblingData !== null\n ? (siblingData as { enabled?: unknown })\n : undefined\n\n if (\n advancedSecurityData?.enabled === true &&\n (!Array.isArray(value) || value.length === 0)\n ) {\n return 'Add at least one workflow ref or disable advanced security.'\n }\n\n return true\n },\n },\n ],\n },\n {\n name: 'aiExport',\n type: 'json',\n admin: {\n description:\n 'Parsed index.ai.yml control data for the raw Markdown AI export route.',\n },\n },\n {\n name: 'sync',\n type: 'group',\n fields: [\n {\n name: 'lastSyncedAt',\n type: 'date',\n },\n ...(syncRunsCollectionSlug\n ? [\n {\n name: 'lastSyncRunId',\n type: 'relationship' as const,\n relationTo: syncRunsCollectionSlug,\n },\n ]\n : []),\n {\n name: 'lastStatus',\n type: 'select',\n options: ['failed', 'pending', 'success'],\n },\n {\n name: 'docsCount',\n type: 'number',\n defaultValue: 0,\n },\n ],\n },\n ...(docsCollectionSlug\n ? [\n {\n name: 'docsSetManager',\n type: 'ui' as const,\n admin: {\n components: {\n Field: DOCS_SET_MANAGER_COMPONENT,\n },\n custom: {\n allowPublish,\n docsCollectionSlug,\n docsEnableDrafts,\n docsGroupsCollectionSlug,\n docsSetsCollectionSlug: slug,\n },\n },\n },\n ]\n : []),\n ],\n labels: {\n plural: 'Sets',\n singular: 'Set',\n },\n})\n"],"names":["DOCS_GLOBALS_ADMIN_GROUP","DOCS_SET_MANAGER_COMPONENT","createPublishGeneratedDocsEndpoint","createDocsSetsCollection","slug","allowPublish","docsCollectionSlug","docsEnableDrafts","docsGroupsCollectionSlug","syncRunsCollectionSlug","admin","defaultColumns","group","useAsTitle","endpoints","docsSetsCollectionSlug","undefined","fields","name","type","required","index","unique","relationTo","description","defaultValue","condition","_data","siblingData","enabled","validate","value","advancedSecurityData","Array","isArray","length","options","components","Field","custom","labels","plural","singular"],"mappings":"AAEA,SACEA,wBAAwB,EACxBC,0BAA0B,QACrB,kBAAiB;AACxB,SAASC,kCAAkC,QAAQ,uCAAsC;AAWzF,OAAO,MAAMC,2BAA2B,CAAC,EACvCC,IAAI,EACJC,eAAe,KAAK,EACpBC,kBAAkB,EAClBC,mBAAmB,KAAK,EACxBC,wBAAwB,EACxBC,sBAAsB,EACU,GAAwB,CAAA;QACxDL;QACAM,OAAO;YACLC,gBAAgB;gBAAC;gBAAS;gBAAQ;gBAAU;aAAY;YACxDC,OAAOZ;YACPa,YAAY;QACd;QACAC,WACER,sBAAsBC,oBAAoBF,eACtC;YACEH,mCAAmC;gBACjCI;gBACAS,wBAAwBX;YAC1B;SACD,GACDY;QACNC,QAAQ;YACN;gBACEC,MAAM;gBACNC,MAAM;gBACNC,UAAU;YACZ;YACA;gBACEF,MAAM;gBACNC,MAAM;gBACNE,OAAO;gBACPD,UAAU;gBACVE,QAAQ;YACV;YACA;gBACEJ,MAAM;gBACNC,MAAM;gBACNI,YAAYf;YACd;YACA;gBACEU,MAAM;gBACNC,MAAM;gBACNT,OAAO;oBACLc,aACE;gBACJ;gBACAC,cAAc;YAChB;YACA;gBACEP,MAAM;gBACNC,MAAM;gBACNT,OAAO;oBACLc,aACE;gBACJ;gBACAC,cAAc;YAChB;YACA;gBACEP,MAAM;gBACNC,MAAM;YACR;YACA;gBACED,MAAM;gBACNC,MAAM;gBACNT,OAAO;oBACLc,aACE;gBACJ;gBACAP,QAAQ;oBACN;wBACEC,MAAM;wBACNC,MAAM;wBACNT,OAAO;4BACLc,aACE;wBACJ;wBACAC,cAAc;oBAChB;oBACA;wBACEP,MAAM;wBACNC,MAAM;wBACNT,OAAO;4BACLgB,WAAW,CAACC,OAAOC,cAAgBA,aAAaC,YAAY;4BAC5DL,aACE;wBACJ;wBACAP,QAAQ;4BACN;gCACEC,MAAM;gCACNC,MAAM;gCACNC,UAAU;4BACZ;yBACD;wBACDU,UAAU,CAACC,OAAO,EAAEH,WAAW,EAAE;4BAC/B,MAAMI,uBACJ,OAAOJ,gBAAgB,YAAYA,gBAAgB,OAC9CA,cACDZ;4BAEN,IACEgB,sBAAsBH,YAAY,QACjC,CAAA,CAACI,MAAMC,OAAO,CAACH,UAAUA,MAAMI,MAAM,KAAK,CAAA,GAC3C;gCACA,OAAO;4BACT;4BAEA,OAAO;wBACT;oBACF;iBACD;YACH;YACA;gBACEjB,MAAM;gBACNC,MAAM;gBACNT,OAAO;oBACLc,aACE;gBACJ;YACF;YACA;gBACEN,MAAM;gBACNC,MAAM;gBACNF,QAAQ;oBACN;wBACEC,MAAM;wBACNC,MAAM;oBACR;uBACIV,yBACA;wBACE;4BACES,MAAM;4BACNC,MAAM;4BACNI,YAAYd;wBACd;qBACD,GACD,EAAE;oBACN;wBACES,MAAM;wBACNC,MAAM;wBACNiB,SAAS;4BAAC;4BAAU;4BAAW;yBAAU;oBAC3C;oBACA;wBACElB,MAAM;wBACNC,MAAM;wBACNM,cAAc;oBAChB;iBACD;YACH;eACInB,qBACA;gBACE;oBACEY,MAAM;oBACNC,MAAM;oBACNT,OAAO;wBACL2B,YAAY;4BACVC,OAAOrC;wBACT;wBACAsC,QAAQ;4BACNlC;4BACAC;4BACAC;4BACAC;4BACAO,wBAAwBX;wBAC1B;oBACF;gBACF;aACD,GACD,EAAE;SACP;QACDoC,QAAQ;YACNC,QAAQ;YACRC,UAAU;QACZ;IACF,CAAA,EAAE"}
|
|
@@ -1,2 +1,4 @@
|
|
|
1
|
+
export { createPublishGeneratedDocsEndpoint } from './publishGeneratedDocs.js';
|
|
2
|
+
export type { CreatePublishGeneratedDocsEndpointOptions } from './publishGeneratedDocs.js';
|
|
1
3
|
export { createSyncEndpoint } from './sync.js';
|
|
2
|
-
export type { CreateSyncEndpointOptions, DocsSyncEndpointErrorCode
|
|
4
|
+
export type { CreateSyncEndpointOptions, DocsSyncEndpointErrorCode } from './sync.js';
|
package/dist/endpoints/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/endpoints/index.ts"],"sourcesContent":["export { createSyncEndpoint } from './sync.js'\nexport type {
|
|
1
|
+
{"version":3,"sources":["../../src/endpoints/index.ts"],"sourcesContent":["export { createPublishGeneratedDocsEndpoint } from './publishGeneratedDocs.js'\nexport type { CreatePublishGeneratedDocsEndpointOptions } from './publishGeneratedDocs.js'\nexport { createSyncEndpoint } from './sync.js'\nexport type { CreateSyncEndpointOptions, DocsSyncEndpointErrorCode } from './sync.js'\n"],"names":["createPublishGeneratedDocsEndpoint","createSyncEndpoint"],"mappings":"AAAA,SAASA,kCAAkC,QAAQ,4BAA2B;AAE9E,SAASC,kBAAkB,QAAQ,YAAW"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Endpoint } from 'payload';
|
|
2
|
+
export type CreatePublishGeneratedDocsEndpointOptions = {
|
|
3
|
+
docsCollectionSlug: string;
|
|
4
|
+
docsSetsCollectionSlug: string;
|
|
5
|
+
};
|
|
6
|
+
export declare const createPublishGeneratedDocsEndpoint: ({ docsCollectionSlug, docsSetsCollectionSlug, }: CreatePublishGeneratedDocsEndpointOptions) => Endpoint;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { publishGeneratedDocsForSet } from '../payload/publishGeneratedDocs.js';
|
|
2
|
+
const jsonResponse = (body, status = 200)=>Response.json(body, {
|
|
3
|
+
status
|
|
4
|
+
});
|
|
5
|
+
const getRouteParam = (req, key)=>{
|
|
6
|
+
const value = req.routeParams?.[key];
|
|
7
|
+
if (typeof value === 'string' || typeof value === 'number') {
|
|
8
|
+
return value;
|
|
9
|
+
}
|
|
10
|
+
return undefined;
|
|
11
|
+
};
|
|
12
|
+
const getRedirectTarget = (req)=>{
|
|
13
|
+
if (!req.url) {
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
const url = new URL(req.url);
|
|
17
|
+
const redirect = url.searchParams.get('redirect');
|
|
18
|
+
if (!redirect || !redirect.startsWith('/') || redirect.startsWith('//')) {
|
|
19
|
+
return undefined;
|
|
20
|
+
}
|
|
21
|
+
return redirect;
|
|
22
|
+
};
|
|
23
|
+
const redirectResponse = (location)=>new Response(null, {
|
|
24
|
+
headers: {
|
|
25
|
+
Location: location
|
|
26
|
+
},
|
|
27
|
+
status: 303
|
|
28
|
+
});
|
|
29
|
+
export const createPublishGeneratedDocsEndpoint = ({ docsCollectionSlug, docsSetsCollectionSlug })=>({
|
|
30
|
+
handler: async (req)=>{
|
|
31
|
+
if (!req.user) {
|
|
32
|
+
return jsonResponse({
|
|
33
|
+
error: 'Unauthorized',
|
|
34
|
+
ok: false
|
|
35
|
+
}, 401);
|
|
36
|
+
}
|
|
37
|
+
const docsSetId = getRouteParam(req, 'id');
|
|
38
|
+
if (docsSetId === undefined) {
|
|
39
|
+
return jsonResponse({
|
|
40
|
+
error: 'Missing docs set id.',
|
|
41
|
+
ok: false
|
|
42
|
+
}, 400);
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
await req.payload.findByID({
|
|
46
|
+
id: docsSetId,
|
|
47
|
+
collection: docsSetsCollectionSlug,
|
|
48
|
+
depth: 0,
|
|
49
|
+
overrideAccess: false,
|
|
50
|
+
user: req.user
|
|
51
|
+
});
|
|
52
|
+
} catch {
|
|
53
|
+
return jsonResponse({
|
|
54
|
+
error: 'Forbidden',
|
|
55
|
+
ok: false
|
|
56
|
+
}, 403);
|
|
57
|
+
}
|
|
58
|
+
const summary = await publishGeneratedDocsForSet({
|
|
59
|
+
docsCollectionSlug,
|
|
60
|
+
docsSetId,
|
|
61
|
+
payload: req.payload
|
|
62
|
+
});
|
|
63
|
+
const redirect = getRedirectTarget(req);
|
|
64
|
+
if (redirect) {
|
|
65
|
+
return redirectResponse(redirect);
|
|
66
|
+
}
|
|
67
|
+
return jsonResponse({
|
|
68
|
+
ok: true,
|
|
69
|
+
summary
|
|
70
|
+
});
|
|
71
|
+
},
|
|
72
|
+
method: 'post',
|
|
73
|
+
path: '/:id/publish-generated-docs'
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
//# sourceMappingURL=publishGeneratedDocs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/endpoints/publishGeneratedDocs.ts"],"sourcesContent":["import type { Endpoint, PayloadRequest } from 'payload'\n\nimport type { PublishGeneratedDocsPayloadOperations } from '../payload/publishGeneratedDocs.js'\n\nimport { publishGeneratedDocsForSet } from '../payload/publishGeneratedDocs.js'\n\nexport type CreatePublishGeneratedDocsEndpointOptions = {\n docsCollectionSlug: string\n docsSetsCollectionSlug: string\n}\n\ntype AccessCheckedPayload = {\n findByID: (args: Record<string, unknown>) => Promise<unknown>\n}\n\nconst jsonResponse = (body: Record<string, unknown>, status = 200): Response =>\n Response.json(body, {\n status,\n })\n\nconst getRouteParam = (req: PayloadRequest, key: string): number | string | undefined => {\n const value = req.routeParams?.[key]\n\n if (typeof value === 'string' || typeof value === 'number') {\n return value\n }\n\n return undefined\n}\n\nconst getRedirectTarget = (req: PayloadRequest): string | undefined => {\n if (!req.url) {\n return undefined\n }\n\n const url = new URL(req.url)\n const redirect = url.searchParams.get('redirect')\n\n if (!redirect || !redirect.startsWith('/') || redirect.startsWith('//')) {\n return undefined\n }\n\n return redirect\n}\n\nconst redirectResponse = (location: string): Response =>\n new Response(null, {\n headers: {\n Location: location,\n },\n status: 303,\n })\n\nexport const createPublishGeneratedDocsEndpoint = ({\n docsCollectionSlug,\n docsSetsCollectionSlug,\n}: CreatePublishGeneratedDocsEndpointOptions): Endpoint => ({\n handler: async (req) => {\n if (!req.user) {\n return jsonResponse(\n {\n error: 'Unauthorized',\n ok: false,\n },\n 401,\n )\n }\n\n const docsSetId = getRouteParam(req, 'id')\n\n if (docsSetId === undefined) {\n return jsonResponse(\n {\n error: 'Missing docs set id.',\n ok: false,\n },\n 400,\n )\n }\n\n try {\n await (req.payload as unknown as AccessCheckedPayload).findByID({\n id: docsSetId,\n collection: docsSetsCollectionSlug,\n depth: 0,\n overrideAccess: false,\n user: req.user,\n })\n } catch {\n return jsonResponse(\n {\n error: 'Forbidden',\n ok: false,\n },\n 403,\n )\n }\n\n const summary = await publishGeneratedDocsForSet({\n docsCollectionSlug,\n docsSetId,\n payload: req.payload as unknown as PublishGeneratedDocsPayloadOperations,\n })\n const redirect = getRedirectTarget(req)\n\n if (redirect) {\n return redirectResponse(redirect)\n }\n\n return jsonResponse({\n ok: true,\n summary,\n })\n },\n method: 'post',\n path: '/:id/publish-generated-docs',\n})\n"],"names":["publishGeneratedDocsForSet","jsonResponse","body","status","Response","json","getRouteParam","req","key","value","routeParams","undefined","getRedirectTarget","url","URL","redirect","searchParams","get","startsWith","redirectResponse","location","headers","Location","createPublishGeneratedDocsEndpoint","docsCollectionSlug","docsSetsCollectionSlug","handler","user","error","ok","docsSetId","payload","findByID","id","collection","depth","overrideAccess","summary","method","path"],"mappings":"AAIA,SAASA,0BAA0B,QAAQ,qCAAoC;AAW/E,MAAMC,eAAe,CAACC,MAA+BC,SAAS,GAAG,GAC/DC,SAASC,IAAI,CAACH,MAAM;QAClBC;IACF;AAEF,MAAMG,gBAAgB,CAACC,KAAqBC;IAC1C,MAAMC,QAAQF,IAAIG,WAAW,EAAE,CAACF,IAAI;IAEpC,IAAI,OAAOC,UAAU,YAAY,OAAOA,UAAU,UAAU;QAC1D,OAAOA;IACT;IAEA,OAAOE;AACT;AAEA,MAAMC,oBAAoB,CAACL;IACzB,IAAI,CAACA,IAAIM,GAAG,EAAE;QACZ,OAAOF;IACT;IAEA,MAAME,MAAM,IAAIC,IAAIP,IAAIM,GAAG;IAC3B,MAAME,WAAWF,IAAIG,YAAY,CAACC,GAAG,CAAC;IAEtC,IAAI,CAACF,YAAY,CAACA,SAASG,UAAU,CAAC,QAAQH,SAASG,UAAU,CAAC,OAAO;QACvE,OAAOP;IACT;IAEA,OAAOI;AACT;AAEA,MAAMI,mBAAmB,CAACC,WACxB,IAAIhB,SAAS,MAAM;QACjBiB,SAAS;YACPC,UAAUF;QACZ;QACAjB,QAAQ;IACV;AAEF,OAAO,MAAMoB,qCAAqC,CAAC,EACjDC,kBAAkB,EAClBC,sBAAsB,EACoB,GAAgB,CAAA;QAC1DC,SAAS,OAAOnB;YACd,IAAI,CAACA,IAAIoB,IAAI,EAAE;gBACb,OAAO1B,aACL;oBACE2B,OAAO;oBACPC,IAAI;gBACN,GACA;YAEJ;YAEA,MAAMC,YAAYxB,cAAcC,KAAK;YAErC,IAAIuB,cAAcnB,WAAW;gBAC3B,OAAOV,aACL;oBACE2B,OAAO;oBACPC,IAAI;gBACN,GACA;YAEJ;YAEA,IAAI;gBACF,MAAM,AAACtB,IAAIwB,OAAO,CAAqCC,QAAQ,CAAC;oBAC9DC,IAAIH;oBACJI,YAAYT;oBACZU,OAAO;oBACPC,gBAAgB;oBAChBT,MAAMpB,IAAIoB,IAAI;gBAChB;YACF,EAAE,OAAM;gBACN,OAAO1B,aACL;oBACE2B,OAAO;oBACPC,IAAI;gBACN,GACA;YAEJ;YAEA,MAAMQ,UAAU,MAAMrC,2BAA2B;gBAC/CwB;gBACAM;gBACAC,SAASxB,IAAIwB,OAAO;YACtB;YACA,MAAMhB,WAAWH,kBAAkBL;YAEnC,IAAIQ,UAAU;gBACZ,OAAOI,iBAAiBJ;YAC1B;YAEA,OAAOd,aAAa;gBAClB4B,IAAI;gBACJQ;YACF;QACF;QACAC,QAAQ;QACRC,MAAM;IACR,CAAA,EAAE"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export type PublishGeneratedDocsPayloadOperations = {
|
|
2
|
+
find: (args: {
|
|
3
|
+
collection: string;
|
|
4
|
+
depth?: number;
|
|
5
|
+
limit?: number;
|
|
6
|
+
overrideAccess?: boolean;
|
|
7
|
+
where?: unknown;
|
|
8
|
+
}) => Promise<{
|
|
9
|
+
docs: unknown[];
|
|
10
|
+
}>;
|
|
11
|
+
update: (args: {
|
|
12
|
+
collection: string;
|
|
13
|
+
data: Record<string, unknown>;
|
|
14
|
+
id: number | string;
|
|
15
|
+
overrideAccess?: boolean;
|
|
16
|
+
}) => Promise<unknown>;
|
|
17
|
+
};
|
|
18
|
+
export type PublishGeneratedDocsResult = {
|
|
19
|
+
archived: number;
|
|
20
|
+
drafts: number;
|
|
21
|
+
published: number;
|
|
22
|
+
total: number;
|
|
23
|
+
updated: number;
|
|
24
|
+
};
|
|
25
|
+
export declare const publishGeneratedDocsForSet: ({ docsCollectionSlug, docsSetId, payload, }: {
|
|
26
|
+
docsCollectionSlug: string;
|
|
27
|
+
docsSetId: number | string;
|
|
28
|
+
payload: PublishGeneratedDocsPayloadOperations;
|
|
29
|
+
}) => Promise<PublishGeneratedDocsResult>;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
const isRecord = (value)=>typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
2
|
+
const getRecordId = (doc)=>{
|
|
3
|
+
if (typeof doc.id === 'string' || typeof doc.id === 'number') {
|
|
4
|
+
return doc.id;
|
|
5
|
+
}
|
|
6
|
+
return undefined;
|
|
7
|
+
};
|
|
8
|
+
const getRelationshipId = (value)=>{
|
|
9
|
+
if (typeof value === 'string' || typeof value === 'number') {
|
|
10
|
+
return String(value);
|
|
11
|
+
}
|
|
12
|
+
if (isRecord(value)) {
|
|
13
|
+
const id = getRecordId(value);
|
|
14
|
+
return id === undefined ? undefined : String(id);
|
|
15
|
+
}
|
|
16
|
+
return undefined;
|
|
17
|
+
};
|
|
18
|
+
const isArchived = (doc)=>{
|
|
19
|
+
const sync = isRecord(doc.sync) ? doc.sync : undefined;
|
|
20
|
+
return sync?.archived === true;
|
|
21
|
+
};
|
|
22
|
+
export const publishGeneratedDocsForSet = async ({ docsCollectionSlug, docsSetId, payload })=>{
|
|
23
|
+
const result = await payload.find({
|
|
24
|
+
collection: docsCollectionSlug,
|
|
25
|
+
depth: 0,
|
|
26
|
+
limit: 1000,
|
|
27
|
+
overrideAccess: true,
|
|
28
|
+
where: {
|
|
29
|
+
docsSet: {
|
|
30
|
+
equals: docsSetId
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
const summary = {
|
|
35
|
+
archived: 0,
|
|
36
|
+
drafts: 0,
|
|
37
|
+
published: 0,
|
|
38
|
+
total: 0,
|
|
39
|
+
updated: 0
|
|
40
|
+
};
|
|
41
|
+
for (const rawDoc of result.docs){
|
|
42
|
+
if (!isRecord(rawDoc)) {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
if (getRelationshipId(rawDoc.docsSet) !== String(docsSetId)) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
summary.total += 1;
|
|
49
|
+
if (isArchived(rawDoc)) {
|
|
50
|
+
summary.archived += 1;
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (rawDoc._status === 'published') {
|
|
54
|
+
summary.published += 1;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if (rawDoc._status === 'draft') {
|
|
58
|
+
summary.drafts += 1;
|
|
59
|
+
}
|
|
60
|
+
const id = getRecordId(rawDoc);
|
|
61
|
+
if (id === undefined) {
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
await payload.update({
|
|
65
|
+
id,
|
|
66
|
+
collection: docsCollectionSlug,
|
|
67
|
+
data: {
|
|
68
|
+
_status: 'published'
|
|
69
|
+
},
|
|
70
|
+
overrideAccess: true
|
|
71
|
+
});
|
|
72
|
+
summary.updated += 1;
|
|
73
|
+
summary.published += 1;
|
|
74
|
+
}
|
|
75
|
+
return summary;
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
//# sourceMappingURL=publishGeneratedDocs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/payload/publishGeneratedDocs.ts"],"sourcesContent":["export type PublishGeneratedDocsPayloadOperations = {\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 update: (args: {\n collection: string\n data: Record<string, unknown>\n id: number | string\n overrideAccess?: boolean\n }) => Promise<unknown>\n}\n\nexport type PublishGeneratedDocsResult = {\n archived: number\n drafts: number\n published: number\n total: number\n updated: number\n}\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n\nconst getRecordId = (doc: Record<string, unknown>): number | string | undefined => {\n if (typeof doc.id === 'string' || typeof doc.id === 'number') {\n return 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 if (isRecord(value)) {\n const id = getRecordId(value)\n\n return id === undefined ? undefined : String(id)\n }\n\n return undefined\n}\n\nconst isArchived = (doc: Record<string, unknown>): boolean => {\n const sync = isRecord(doc.sync) ? doc.sync : undefined\n\n return sync?.archived === true\n}\n\nexport const publishGeneratedDocsForSet = async ({\n docsCollectionSlug,\n docsSetId,\n payload,\n}: {\n docsCollectionSlug: string\n docsSetId: number | string\n payload: PublishGeneratedDocsPayloadOperations\n}): Promise<PublishGeneratedDocsResult> => {\n const result = await payload.find({\n collection: docsCollectionSlug,\n depth: 0,\n limit: 1000,\n overrideAccess: true,\n where: {\n docsSet: {\n equals: docsSetId,\n },\n },\n })\n\n const summary: PublishGeneratedDocsResult = {\n archived: 0,\n drafts: 0,\n published: 0,\n total: 0,\n updated: 0,\n }\n\n for (const rawDoc of result.docs) {\n if (!isRecord(rawDoc)) {\n continue\n }\n\n if (getRelationshipId(rawDoc.docsSet) !== String(docsSetId)) {\n continue\n }\n\n summary.total += 1\n\n if (isArchived(rawDoc)) {\n summary.archived += 1\n continue\n }\n\n if (rawDoc._status === 'published') {\n summary.published += 1\n continue\n }\n\n if (rawDoc._status === 'draft') {\n summary.drafts += 1\n }\n\n const id = getRecordId(rawDoc)\n\n if (id === undefined) {\n continue\n }\n\n await payload.update({\n id,\n collection: docsCollectionSlug,\n data: {\n _status: 'published',\n },\n overrideAccess: true,\n })\n summary.updated += 1\n summary.published += 1\n }\n\n return summary\n}\n"],"names":["isRecord","value","Array","isArray","getRecordId","doc","id","undefined","getRelationshipId","String","isArchived","sync","archived","publishGeneratedDocsForSet","docsCollectionSlug","docsSetId","payload","result","find","collection","depth","limit","overrideAccess","where","docsSet","equals","summary","drafts","published","total","updated","rawDoc","docs","_status","update","data"],"mappings":"AA0BA,MAAMA,WAAW,CAACC,QAChB,OAAOA,UAAU,YAAYA,UAAU,QAAQ,CAACC,MAAMC,OAAO,CAACF;AAEhE,MAAMG,cAAc,CAACC;IACnB,IAAI,OAAOA,IAAIC,EAAE,KAAK,YAAY,OAAOD,IAAIC,EAAE,KAAK,UAAU;QAC5D,OAAOD,IAAIC,EAAE;IACf;IAEA,OAAOC;AACT;AAEA,MAAMC,oBAAoB,CAACP;IACzB,IAAI,OAAOA,UAAU,YAAY,OAAOA,UAAU,UAAU;QAC1D,OAAOQ,OAAOR;IAChB;IAEA,IAAID,SAASC,QAAQ;QACnB,MAAMK,KAAKF,YAAYH;QAEvB,OAAOK,OAAOC,YAAYA,YAAYE,OAAOH;IAC/C;IAEA,OAAOC;AACT;AAEA,MAAMG,aAAa,CAACL;IAClB,MAAMM,OAAOX,SAASK,IAAIM,IAAI,IAAIN,IAAIM,IAAI,GAAGJ;IAE7C,OAAOI,MAAMC,aAAa;AAC5B;AAEA,OAAO,MAAMC,6BAA6B,OAAO,EAC/CC,kBAAkB,EAClBC,SAAS,EACTC,OAAO,EAKR;IACC,MAAMC,SAAS,MAAMD,QAAQE,IAAI,CAAC;QAChCC,YAAYL;QACZM,OAAO;QACPC,OAAO;QACPC,gBAAgB;QAChBC,OAAO;YACLC,SAAS;gBACPC,QAAQV;YACV;QACF;IACF;IAEA,MAAMW,UAAsC;QAC1Cd,UAAU;QACVe,QAAQ;QACRC,WAAW;QACXC,OAAO;QACPC,SAAS;IACX;IAEA,KAAK,MAAMC,UAAUd,OAAOe,IAAI,CAAE;QAChC,IAAI,CAAChC,SAAS+B,SAAS;YACrB;QACF;QAEA,IAAIvB,kBAAkBuB,OAAOP,OAAO,MAAMf,OAAOM,YAAY;YAC3D;QACF;QAEAW,QAAQG,KAAK,IAAI;QAEjB,IAAInB,WAAWqB,SAAS;YACtBL,QAAQd,QAAQ,IAAI;YACpB;QACF;QAEA,IAAImB,OAAOE,OAAO,KAAK,aAAa;YAClCP,QAAQE,SAAS,IAAI;YACrB;QACF;QAEA,IAAIG,OAAOE,OAAO,KAAK,SAAS;YAC9BP,QAAQC,MAAM,IAAI;QACpB;QAEA,MAAMrB,KAAKF,YAAY2B;QAEvB,IAAIzB,OAAOC,WAAW;YACpB;QACF;QAEA,MAAMS,QAAQkB,MAAM,CAAC;YACnB5B;YACAa,YAAYL;YACZqB,MAAM;gBACJF,SAAS;YACX;YACAX,gBAAgB;QAClB;QACAI,QAAQI,OAAO,IAAI;QACnBJ,QAAQE,SAAS,IAAI;IACvB;IAEA,OAAOF;AACT,EAAC"}
|
package/dist/plugin.js
CHANGED
|
@@ -106,7 +106,9 @@ export const payloadMarkdownDocs = (pluginOptions = {})=>(incomingConfig)=>{
|
|
|
106
106
|
...docsSetsEnabled ? [
|
|
107
107
|
createDocsSetsCollection({
|
|
108
108
|
slug: docsSetsCollectionSlug,
|
|
109
|
+
allowPublish: pluginOptions.sync?.allowPublish === true,
|
|
109
110
|
docsCollectionSlug: docsEnabled ? docsCollectionSlug : undefined,
|
|
111
|
+
docsEnableDrafts: enableDrafts,
|
|
110
112
|
docsGroupsCollectionSlug,
|
|
111
113
|
syncRunsCollectionSlug: syncRunsEnabled ? syncRunsCollectionSlug : undefined
|
|
112
114
|
})
|
package/dist/plugin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/plugin.ts"],"sourcesContent":["import type { Config, Plugin } from 'payload'\n\nimport type { PayloadMarkdownDocsConfig } from './types.js'\n\nimport {\n createDocsCollection,\n createDocsGroupsCollection,\n createDocsKeysCollection,\n createDocsSetsCollection,\n createDocsTrustedCollection,\n createNoncesCollection,\n createSyncRunsCollection,\n} from './collections/index.js'\nimport {\n DEFAULT_DOCS_COLLECTION_SLUG,\n DEFAULT_DOCS_GROUPS_COLLECTION_SLUG,\n DEFAULT_DOCS_KEYS_COLLECTION_SLUG,\n DEFAULT_DOCS_SETS_COLLECTION_SLUG,\n DEFAULT_DOCS_SYNC_ENDPOINT_PATH,\n DEFAULT_DOCS_SYNC_NONCES_COLLECTION_SLUG,\n DEFAULT_DOCS_SYNC_RUNS_COLLECTION_SLUG,\n DEFAULT_DOCS_TRUSTED_COLLECTION_SLUG,\n DEFAULT_MARKDOWN_FIELD_NAME,\n DEFAULT_MAX_BODY_BYTES,\n DEFAULT_PAGES_BRIDGE_FIELD,\n DEFAULT_PAGES_COLLECTION_SLUG,\n DEFAULT_PAGES_ROUTE_FIELD,\n} from './constants.js'\nimport { createSyncEndpoint } from './endpoints/index.js'\n\ntype ResolvedCollectionOptions = {\n docsCollectionSlug: string\n docsEnabled: boolean\n docsGroupsCollectionSlug: string\n docsGroupsEnabled: boolean\n docsKeysCollectionSlug: string\n docsKeysEnabled: boolean\n docsSetsCollectionSlug: string\n docsSetsEnabled: boolean\n docsTrustedCollectionSlug: string\n docsTrustedEnabled: boolean\n enableDrafts: boolean\n markdownFieldName: string\n noncesCollectionSlug: string\n noncesEnabled: boolean\n syncRunsCollectionSlug: string\n syncRunsEnabled: boolean\n}\n\nconst normalizeEndpointPath = (path: string): string => {\n const normalized = `/${path.trim()}`.replace(/\\/+/g, '/')\n\n return normalized.length > 1 ? normalized.replace(/\\/+$/g, '') : normalized\n}\n\nconst resolveCollectionOptions = (\n pluginOptions: PayloadMarkdownDocsConfig,\n): ResolvedCollectionOptions => {\n if (\n pluginOptions.target?.type !== undefined &&\n pluginOptions.target.type !== 'docsCollection'\n ) {\n throw new Error(\n 'payloadMarkdownDocs: target.type only supports \"docsCollection\". existingCollection is not supported.',\n )\n }\n\n const docsSlugFromTarget = pluginOptions.target?.slug\n const docsSlugFromCollections = pluginOptions.collections?.docs?.slug\n\n if (\n docsSlugFromTarget &&\n docsSlugFromCollections &&\n docsSlugFromTarget !== docsSlugFromCollections\n ) {\n throw new Error(\n 'payloadMarkdownDocs: target.slug and collections.docs.slug must match when both are provided.',\n )\n }\n\n return {\n docsCollectionSlug:\n docsSlugFromTarget ?? docsSlugFromCollections ?? DEFAULT_DOCS_COLLECTION_SLUG,\n docsEnabled: pluginOptions.collections?.docs?.enabled !== false,\n docsGroupsCollectionSlug:\n pluginOptions.collections?.docsGroups?.slug ?? DEFAULT_DOCS_GROUPS_COLLECTION_SLUG,\n docsGroupsEnabled: pluginOptions.collections?.docsGroups?.enabled !== false,\n docsKeysCollectionSlug:\n pluginOptions.collections?.docsKeys?.slug ?? DEFAULT_DOCS_KEYS_COLLECTION_SLUG,\n docsKeysEnabled: pluginOptions.collections?.docsKeys?.enabled !== false,\n docsSetsCollectionSlug:\n pluginOptions.collections?.docsSets?.slug ?? DEFAULT_DOCS_SETS_COLLECTION_SLUG,\n docsSetsEnabled: pluginOptions.collections?.docsSets?.enabled !== false,\n docsTrustedCollectionSlug:\n pluginOptions.collections?.docsTrusted?.slug ?? DEFAULT_DOCS_TRUSTED_COLLECTION_SLUG,\n docsTrustedEnabled: pluginOptions.collections?.docsTrusted?.enabled !== false,\n enableDrafts:\n pluginOptions.target?.enableDrafts === true,\n markdownFieldName:\n pluginOptions.target?.markdownField ?? DEFAULT_MARKDOWN_FIELD_NAME,\n noncesCollectionSlug:\n pluginOptions.collections?.nonces?.slug ?? DEFAULT_DOCS_SYNC_NONCES_COLLECTION_SLUG,\n noncesEnabled: pluginOptions.collections?.nonces?.enabled !== false,\n syncRunsCollectionSlug:\n pluginOptions.collections?.syncRuns?.slug ?? DEFAULT_DOCS_SYNC_RUNS_COLLECTION_SLUG,\n syncRunsEnabled: pluginOptions.collections?.syncRuns?.enabled !== false,\n }\n}\n\nconst assertCollectionOptionCompatibility = ({\n docsGroupsEnabled,\n docsSetsEnabled,\n}: ResolvedCollectionOptions) => {\n if (docsSetsEnabled && !docsGroupsEnabled) {\n throw new Error(\n 'payloadMarkdownDocs: collections.docsSets requires collections.docsGroups to be enabled.',\n )\n }\n}\n\nconst assertNoCollectionSlugConflicts = (\n incomingConfig: Config,\n collectionSlugsToAdd: string[],\n) => {\n const duplicateRequestedSlug = collectionSlugsToAdd.find(\n (slug, index) => collectionSlugsToAdd.indexOf(slug) !== index,\n )\n\n if (duplicateRequestedSlug) {\n throw new Error(\n `payloadMarkdownDocs: collection slug \"${duplicateRequestedSlug}\" is configured more than once.`,\n )\n }\n\n const existingCollectionSlugs = new Set(\n incomingConfig.collections?.map((collection) => collection.slug) ?? [],\n )\n\n const conflictingSlug = collectionSlugsToAdd.find((slug) =>\n existingCollectionSlugs.has(slug),\n )\n\n if (conflictingSlug) {\n throw new Error(\n `payloadMarkdownDocs: collection slug \"${conflictingSlug}\" already exists in the Payload config.`,\n )\n }\n}\n\nexport const payloadMarkdownDocs =\n (pluginOptions: PayloadMarkdownDocsConfig = {}): Plugin =>\n (incomingConfig: Config): Config => {\n if (pluginOptions.enabled === false) {\n return incomingConfig\n }\n\n const {\n docsCollectionSlug,\n docsEnabled,\n docsGroupsCollectionSlug,\n docsGroupsEnabled,\n docsKeysCollectionSlug,\n docsKeysEnabled,\n docsSetsCollectionSlug,\n docsSetsEnabled,\n docsTrustedCollectionSlug,\n docsTrustedEnabled,\n enableDrafts,\n markdownFieldName,\n noncesCollectionSlug,\n noncesEnabled,\n syncRunsCollectionSlug,\n syncRunsEnabled,\n } = resolveCollectionOptions(pluginOptions)\n assertCollectionOptionCompatibility({\n docsCollectionSlug,\n docsEnabled,\n docsGroupsCollectionSlug,\n docsGroupsEnabled,\n docsKeysCollectionSlug,\n docsKeysEnabled,\n docsSetsCollectionSlug,\n docsSetsEnabled,\n docsTrustedCollectionSlug,\n docsTrustedEnabled,\n enableDrafts,\n markdownFieldName,\n noncesCollectionSlug,\n noncesEnabled,\n syncRunsCollectionSlug,\n syncRunsEnabled,\n })\n const endpointPath = normalizeEndpointPath(\n pluginOptions.endpoint?.path ?? DEFAULT_DOCS_SYNC_ENDPOINT_PATH,\n )\n\n const collectionSlugsToAdd = [\n ...(docsGroupsEnabled ? [docsGroupsCollectionSlug] : []),\n ...(docsSetsEnabled ? [docsSetsCollectionSlug] : []),\n ...(docsKeysEnabled ? [docsKeysCollectionSlug] : []),\n ...(docsTrustedEnabled ? [docsTrustedCollectionSlug] : []),\n ...(docsEnabled ? [docsCollectionSlug] : []),\n ...(syncRunsEnabled ? [syncRunsCollectionSlug] : []),\n ...(noncesEnabled ? [noncesCollectionSlug] : []),\n ]\n\n assertNoCollectionSlugConflicts(incomingConfig, collectionSlugsToAdd)\n\n const addedCollections = [\n ...(docsGroupsEnabled\n ? [\n createDocsGroupsCollection({\n slug: docsGroupsCollectionSlug,\n }),\n ]\n : []),\n ...(docsSetsEnabled\n ? [\n createDocsSetsCollection({\n slug: docsSetsCollectionSlug,\n docsCollectionSlug: docsEnabled ? docsCollectionSlug : undefined,\n docsGroupsCollectionSlug,\n syncRunsCollectionSlug: syncRunsEnabled ? syncRunsCollectionSlug : undefined,\n }),\n ]\n : []),\n ...(docsKeysEnabled\n ? [\n createDocsKeysCollection({\n slug: docsKeysCollectionSlug,\n }),\n ]\n : []),\n ...(docsTrustedEnabled\n ? [\n createDocsTrustedCollection({\n slug: docsTrustedCollectionSlug,\n }),\n ]\n : []),\n ...(docsEnabled\n ? [\n createDocsCollection({\n slug: docsCollectionSlug,\n docsSetsCollectionSlug: docsSetsEnabled\n ? docsSetsCollectionSlug\n : undefined,\n enableDrafts,\n markdownFieldName,\n syncRunsCollectionSlug: syncRunsEnabled ? syncRunsCollectionSlug : undefined,\n }),\n ]\n : []),\n ...(syncRunsEnabled\n ? [\n createSyncRunsCollection({\n slug: syncRunsCollectionSlug,\n }),\n ]\n : []),\n ...(noncesEnabled\n ? [\n createNoncesCollection({\n slug: noncesCollectionSlug,\n syncRunsCollectionSlug: syncRunsEnabled ? syncRunsCollectionSlug : undefined,\n }),\n ]\n : []),\n ]\n\n return {\n ...incomingConfig,\n collections: [...(incomingConfig.collections ?? []), ...addedCollections],\n endpoints: [\n ...(incomingConfig.endpoints ?? []),\n createSyncEndpoint({\n allowHardDelete: pluginOptions.sync?.allowHardDelete,\n allowPublish: pluginOptions.sync?.allowPublish,\n allowWrites: pluginOptions.sync?.allowWrites,\n auth: pluginOptions.auth,\n defaultPublishMode: pluginOptions.sync?.defaultPublishMode,\n deleteBehavior: pluginOptions.sync?.deleteBehavior,\n docsCollectionSlug,\n docsEnabled,\n docsEnableDrafts: enableDrafts,\n docsGroupsCollectionSlug,\n docsKeysCollectionSlug,\n docsKeysEnabled,\n docsSetsCollectionSlug,\n docsSetsEnabled,\n docsTrustedCollectionSlug,\n docsTrustedEnabled,\n endpointPath,\n markdownFieldName,\n maxBodyBytes: pluginOptions.endpoint?.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES,\n noncesCollectionSlug,\n noncesEnabled,\n requireDryRunBeforeApply: pluginOptions.sync?.requireDryRunBeforeApply,\n routing: {\n pages: {\n allowBridgePages:\n pluginOptions.routing?.pages?.allowBridgePages ?? true,\n bridgeField:\n pluginOptions.routing?.pages?.bridgeField ?? DEFAULT_PAGES_BRIDGE_FIELD,\n collection:\n pluginOptions.routing?.pages?.collection ?? DEFAULT_PAGES_COLLECTION_SLUG,\n enabled: pluginOptions.routing?.pages?.enabled === true,\n routeField:\n pluginOptions.routing?.pages?.routeField ?? DEFAULT_PAGES_ROUTE_FIELD,\n },\n },\n syncRunsCollectionSlug,\n syncRunsEnabled,\n }),\n ],\n }\n }\n"],"names":["createDocsCollection","createDocsGroupsCollection","createDocsKeysCollection","createDocsSetsCollection","createDocsTrustedCollection","createNoncesCollection","createSyncRunsCollection","DEFAULT_DOCS_COLLECTION_SLUG","DEFAULT_DOCS_GROUPS_COLLECTION_SLUG","DEFAULT_DOCS_KEYS_COLLECTION_SLUG","DEFAULT_DOCS_SETS_COLLECTION_SLUG","DEFAULT_DOCS_SYNC_ENDPOINT_PATH","DEFAULT_DOCS_SYNC_NONCES_COLLECTION_SLUG","DEFAULT_DOCS_SYNC_RUNS_COLLECTION_SLUG","DEFAULT_DOCS_TRUSTED_COLLECTION_SLUG","DEFAULT_MARKDOWN_FIELD_NAME","DEFAULT_MAX_BODY_BYTES","DEFAULT_PAGES_BRIDGE_FIELD","DEFAULT_PAGES_COLLECTION_SLUG","DEFAULT_PAGES_ROUTE_FIELD","createSyncEndpoint","normalizeEndpointPath","path","normalized","trim","replace","length","resolveCollectionOptions","pluginOptions","target","type","undefined","Error","docsSlugFromTarget","slug","docsSlugFromCollections","collections","docs","docsCollectionSlug","docsEnabled","enabled","docsGroupsCollectionSlug","docsGroups","docsGroupsEnabled","docsKeysCollectionSlug","docsKeys","docsKeysEnabled","docsSetsCollectionSlug","docsSets","docsSetsEnabled","docsTrustedCollectionSlug","docsTrusted","docsTrustedEnabled","enableDrafts","markdownFieldName","markdownField","noncesCollectionSlug","nonces","noncesEnabled","syncRunsCollectionSlug","syncRuns","syncRunsEnabled","assertCollectionOptionCompatibility","assertNoCollectionSlugConflicts","incomingConfig","collectionSlugsToAdd","duplicateRequestedSlug","find","index","indexOf","existingCollectionSlugs","Set","map","collection","conflictingSlug","has","payloadMarkdownDocs","endpointPath","endpoint","addedCollections","endpoints","allowHardDelete","sync","allowPublish","allowWrites","auth","defaultPublishMode","deleteBehavior","docsEnableDrafts","maxBodyBytes","requireDryRunBeforeApply","routing","pages","allowBridgePages","bridgeField","routeField"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../src/plugin.ts"],"sourcesContent":["import type { Config, Plugin } from 'payload'\n\nimport type { PayloadMarkdownDocsConfig } from './types.js'\n\nimport {\n createDocsCollection,\n createDocsGroupsCollection,\n createDocsKeysCollection,\n createDocsSetsCollection,\n createDocsTrustedCollection,\n createNoncesCollection,\n createSyncRunsCollection,\n} from './collections/index.js'\nimport {\n DEFAULT_DOCS_COLLECTION_SLUG,\n DEFAULT_DOCS_GROUPS_COLLECTION_SLUG,\n DEFAULT_DOCS_KEYS_COLLECTION_SLUG,\n DEFAULT_DOCS_SETS_COLLECTION_SLUG,\n DEFAULT_DOCS_SYNC_ENDPOINT_PATH,\n DEFAULT_DOCS_SYNC_NONCES_COLLECTION_SLUG,\n DEFAULT_DOCS_SYNC_RUNS_COLLECTION_SLUG,\n DEFAULT_DOCS_TRUSTED_COLLECTION_SLUG,\n DEFAULT_MARKDOWN_FIELD_NAME,\n DEFAULT_MAX_BODY_BYTES,\n DEFAULT_PAGES_BRIDGE_FIELD,\n DEFAULT_PAGES_COLLECTION_SLUG,\n DEFAULT_PAGES_ROUTE_FIELD,\n} from './constants.js'\nimport { createSyncEndpoint } from './endpoints/index.js'\n\ntype ResolvedCollectionOptions = {\n docsCollectionSlug: string\n docsEnabled: boolean\n docsGroupsCollectionSlug: string\n docsGroupsEnabled: boolean\n docsKeysCollectionSlug: string\n docsKeysEnabled: boolean\n docsSetsCollectionSlug: string\n docsSetsEnabled: boolean\n docsTrustedCollectionSlug: string\n docsTrustedEnabled: boolean\n enableDrafts: boolean\n markdownFieldName: string\n noncesCollectionSlug: string\n noncesEnabled: boolean\n syncRunsCollectionSlug: string\n syncRunsEnabled: boolean\n}\n\nconst normalizeEndpointPath = (path: string): string => {\n const normalized = `/${path.trim()}`.replace(/\\/+/g, '/')\n\n return normalized.length > 1 ? normalized.replace(/\\/+$/g, '') : normalized\n}\n\nconst resolveCollectionOptions = (\n pluginOptions: PayloadMarkdownDocsConfig,\n): ResolvedCollectionOptions => {\n if (\n pluginOptions.target?.type !== undefined &&\n pluginOptions.target.type !== 'docsCollection'\n ) {\n throw new Error(\n 'payloadMarkdownDocs: target.type only supports \"docsCollection\". existingCollection is not supported.',\n )\n }\n\n const docsSlugFromTarget = pluginOptions.target?.slug\n const docsSlugFromCollections = pluginOptions.collections?.docs?.slug\n\n if (\n docsSlugFromTarget &&\n docsSlugFromCollections &&\n docsSlugFromTarget !== docsSlugFromCollections\n ) {\n throw new Error(\n 'payloadMarkdownDocs: target.slug and collections.docs.slug must match when both are provided.',\n )\n }\n\n return {\n docsCollectionSlug:\n docsSlugFromTarget ?? docsSlugFromCollections ?? DEFAULT_DOCS_COLLECTION_SLUG,\n docsEnabled: pluginOptions.collections?.docs?.enabled !== false,\n docsGroupsCollectionSlug:\n pluginOptions.collections?.docsGroups?.slug ?? DEFAULT_DOCS_GROUPS_COLLECTION_SLUG,\n docsGroupsEnabled: pluginOptions.collections?.docsGroups?.enabled !== false,\n docsKeysCollectionSlug:\n pluginOptions.collections?.docsKeys?.slug ?? DEFAULT_DOCS_KEYS_COLLECTION_SLUG,\n docsKeysEnabled: pluginOptions.collections?.docsKeys?.enabled !== false,\n docsSetsCollectionSlug:\n pluginOptions.collections?.docsSets?.slug ?? DEFAULT_DOCS_SETS_COLLECTION_SLUG,\n docsSetsEnabled: pluginOptions.collections?.docsSets?.enabled !== false,\n docsTrustedCollectionSlug:\n pluginOptions.collections?.docsTrusted?.slug ?? DEFAULT_DOCS_TRUSTED_COLLECTION_SLUG,\n docsTrustedEnabled: pluginOptions.collections?.docsTrusted?.enabled !== false,\n enableDrafts:\n pluginOptions.target?.enableDrafts === true,\n markdownFieldName:\n pluginOptions.target?.markdownField ?? DEFAULT_MARKDOWN_FIELD_NAME,\n noncesCollectionSlug:\n pluginOptions.collections?.nonces?.slug ?? DEFAULT_DOCS_SYNC_NONCES_COLLECTION_SLUG,\n noncesEnabled: pluginOptions.collections?.nonces?.enabled !== false,\n syncRunsCollectionSlug:\n pluginOptions.collections?.syncRuns?.slug ?? DEFAULT_DOCS_SYNC_RUNS_COLLECTION_SLUG,\n syncRunsEnabled: pluginOptions.collections?.syncRuns?.enabled !== false,\n }\n}\n\nconst assertCollectionOptionCompatibility = ({\n docsGroupsEnabled,\n docsSetsEnabled,\n}: ResolvedCollectionOptions) => {\n if (docsSetsEnabled && !docsGroupsEnabled) {\n throw new Error(\n 'payloadMarkdownDocs: collections.docsSets requires collections.docsGroups to be enabled.',\n )\n }\n}\n\nconst assertNoCollectionSlugConflicts = (\n incomingConfig: Config,\n collectionSlugsToAdd: string[],\n) => {\n const duplicateRequestedSlug = collectionSlugsToAdd.find(\n (slug, index) => collectionSlugsToAdd.indexOf(slug) !== index,\n )\n\n if (duplicateRequestedSlug) {\n throw new Error(\n `payloadMarkdownDocs: collection slug \"${duplicateRequestedSlug}\" is configured more than once.`,\n )\n }\n\n const existingCollectionSlugs = new Set(\n incomingConfig.collections?.map((collection) => collection.slug) ?? [],\n )\n\n const conflictingSlug = collectionSlugsToAdd.find((slug) =>\n existingCollectionSlugs.has(slug),\n )\n\n if (conflictingSlug) {\n throw new Error(\n `payloadMarkdownDocs: collection slug \"${conflictingSlug}\" already exists in the Payload config.`,\n )\n }\n}\n\nexport const payloadMarkdownDocs =\n (pluginOptions: PayloadMarkdownDocsConfig = {}): Plugin =>\n (incomingConfig: Config): Config => {\n if (pluginOptions.enabled === false) {\n return incomingConfig\n }\n\n const {\n docsCollectionSlug,\n docsEnabled,\n docsGroupsCollectionSlug,\n docsGroupsEnabled,\n docsKeysCollectionSlug,\n docsKeysEnabled,\n docsSetsCollectionSlug,\n docsSetsEnabled,\n docsTrustedCollectionSlug,\n docsTrustedEnabled,\n enableDrafts,\n markdownFieldName,\n noncesCollectionSlug,\n noncesEnabled,\n syncRunsCollectionSlug,\n syncRunsEnabled,\n } = resolveCollectionOptions(pluginOptions)\n assertCollectionOptionCompatibility({\n docsCollectionSlug,\n docsEnabled,\n docsGroupsCollectionSlug,\n docsGroupsEnabled,\n docsKeysCollectionSlug,\n docsKeysEnabled,\n docsSetsCollectionSlug,\n docsSetsEnabled,\n docsTrustedCollectionSlug,\n docsTrustedEnabled,\n enableDrafts,\n markdownFieldName,\n noncesCollectionSlug,\n noncesEnabled,\n syncRunsCollectionSlug,\n syncRunsEnabled,\n })\n const endpointPath = normalizeEndpointPath(\n pluginOptions.endpoint?.path ?? DEFAULT_DOCS_SYNC_ENDPOINT_PATH,\n )\n\n const collectionSlugsToAdd = [\n ...(docsGroupsEnabled ? [docsGroupsCollectionSlug] : []),\n ...(docsSetsEnabled ? [docsSetsCollectionSlug] : []),\n ...(docsKeysEnabled ? [docsKeysCollectionSlug] : []),\n ...(docsTrustedEnabled ? [docsTrustedCollectionSlug] : []),\n ...(docsEnabled ? [docsCollectionSlug] : []),\n ...(syncRunsEnabled ? [syncRunsCollectionSlug] : []),\n ...(noncesEnabled ? [noncesCollectionSlug] : []),\n ]\n\n assertNoCollectionSlugConflicts(incomingConfig, collectionSlugsToAdd)\n\n const addedCollections = [\n ...(docsGroupsEnabled\n ? [\n createDocsGroupsCollection({\n slug: docsGroupsCollectionSlug,\n }),\n ]\n : []),\n ...(docsSetsEnabled\n ? [\n createDocsSetsCollection({\n slug: docsSetsCollectionSlug,\n allowPublish: pluginOptions.sync?.allowPublish === true,\n docsCollectionSlug: docsEnabled ? docsCollectionSlug : undefined,\n docsEnableDrafts: enableDrafts,\n docsGroupsCollectionSlug,\n syncRunsCollectionSlug: syncRunsEnabled ? syncRunsCollectionSlug : undefined,\n }),\n ]\n : []),\n ...(docsKeysEnabled\n ? [\n createDocsKeysCollection({\n slug: docsKeysCollectionSlug,\n }),\n ]\n : []),\n ...(docsTrustedEnabled\n ? [\n createDocsTrustedCollection({\n slug: docsTrustedCollectionSlug,\n }),\n ]\n : []),\n ...(docsEnabled\n ? [\n createDocsCollection({\n slug: docsCollectionSlug,\n docsSetsCollectionSlug: docsSetsEnabled\n ? docsSetsCollectionSlug\n : undefined,\n enableDrafts,\n markdownFieldName,\n syncRunsCollectionSlug: syncRunsEnabled ? syncRunsCollectionSlug : undefined,\n }),\n ]\n : []),\n ...(syncRunsEnabled\n ? [\n createSyncRunsCollection({\n slug: syncRunsCollectionSlug,\n }),\n ]\n : []),\n ...(noncesEnabled\n ? [\n createNoncesCollection({\n slug: noncesCollectionSlug,\n syncRunsCollectionSlug: syncRunsEnabled ? syncRunsCollectionSlug : undefined,\n }),\n ]\n : []),\n ]\n\n return {\n ...incomingConfig,\n collections: [...(incomingConfig.collections ?? []), ...addedCollections],\n endpoints: [\n ...(incomingConfig.endpoints ?? []),\n createSyncEndpoint({\n allowHardDelete: pluginOptions.sync?.allowHardDelete,\n allowPublish: pluginOptions.sync?.allowPublish,\n allowWrites: pluginOptions.sync?.allowWrites,\n auth: pluginOptions.auth,\n defaultPublishMode: pluginOptions.sync?.defaultPublishMode,\n deleteBehavior: pluginOptions.sync?.deleteBehavior,\n docsCollectionSlug,\n docsEnabled,\n docsEnableDrafts: enableDrafts,\n docsGroupsCollectionSlug,\n docsKeysCollectionSlug,\n docsKeysEnabled,\n docsSetsCollectionSlug,\n docsSetsEnabled,\n docsTrustedCollectionSlug,\n docsTrustedEnabled,\n endpointPath,\n markdownFieldName,\n maxBodyBytes: pluginOptions.endpoint?.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES,\n noncesCollectionSlug,\n noncesEnabled,\n requireDryRunBeforeApply: pluginOptions.sync?.requireDryRunBeforeApply,\n routing: {\n pages: {\n allowBridgePages:\n pluginOptions.routing?.pages?.allowBridgePages ?? true,\n bridgeField:\n pluginOptions.routing?.pages?.bridgeField ?? DEFAULT_PAGES_BRIDGE_FIELD,\n collection:\n pluginOptions.routing?.pages?.collection ?? DEFAULT_PAGES_COLLECTION_SLUG,\n enabled: pluginOptions.routing?.pages?.enabled === true,\n routeField:\n pluginOptions.routing?.pages?.routeField ?? DEFAULT_PAGES_ROUTE_FIELD,\n },\n },\n syncRunsCollectionSlug,\n syncRunsEnabled,\n }),\n ],\n }\n }\n"],"names":["createDocsCollection","createDocsGroupsCollection","createDocsKeysCollection","createDocsSetsCollection","createDocsTrustedCollection","createNoncesCollection","createSyncRunsCollection","DEFAULT_DOCS_COLLECTION_SLUG","DEFAULT_DOCS_GROUPS_COLLECTION_SLUG","DEFAULT_DOCS_KEYS_COLLECTION_SLUG","DEFAULT_DOCS_SETS_COLLECTION_SLUG","DEFAULT_DOCS_SYNC_ENDPOINT_PATH","DEFAULT_DOCS_SYNC_NONCES_COLLECTION_SLUG","DEFAULT_DOCS_SYNC_RUNS_COLLECTION_SLUG","DEFAULT_DOCS_TRUSTED_COLLECTION_SLUG","DEFAULT_MARKDOWN_FIELD_NAME","DEFAULT_MAX_BODY_BYTES","DEFAULT_PAGES_BRIDGE_FIELD","DEFAULT_PAGES_COLLECTION_SLUG","DEFAULT_PAGES_ROUTE_FIELD","createSyncEndpoint","normalizeEndpointPath","path","normalized","trim","replace","length","resolveCollectionOptions","pluginOptions","target","type","undefined","Error","docsSlugFromTarget","slug","docsSlugFromCollections","collections","docs","docsCollectionSlug","docsEnabled","enabled","docsGroupsCollectionSlug","docsGroups","docsGroupsEnabled","docsKeysCollectionSlug","docsKeys","docsKeysEnabled","docsSetsCollectionSlug","docsSets","docsSetsEnabled","docsTrustedCollectionSlug","docsTrusted","docsTrustedEnabled","enableDrafts","markdownFieldName","markdownField","noncesCollectionSlug","nonces","noncesEnabled","syncRunsCollectionSlug","syncRuns","syncRunsEnabled","assertCollectionOptionCompatibility","assertNoCollectionSlugConflicts","incomingConfig","collectionSlugsToAdd","duplicateRequestedSlug","find","index","indexOf","existingCollectionSlugs","Set","map","collection","conflictingSlug","has","payloadMarkdownDocs","endpointPath","endpoint","addedCollections","allowPublish","sync","docsEnableDrafts","endpoints","allowHardDelete","allowWrites","auth","defaultPublishMode","deleteBehavior","maxBodyBytes","requireDryRunBeforeApply","routing","pages","allowBridgePages","bridgeField","routeField"],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare class DocsSyncKeyError extends Error {
|
|
2
|
+
constructor(message: string);
|
|
3
|
+
}
|
|
4
|
+
export declare const getEd25519PrivateKeyInput: (privateKey: string) => import("crypto").KeyObject;
|
|
5
|
+
export declare const getEd25519PublicKeyInput: (publicKey: string) => string | import("crypto").KeyObject;
|
|
6
|
+
export declare const buildOpenSshEd25519PublicKey: ({ comment, publicKey, }: {
|
|
7
|
+
comment?: string;
|
|
8
|
+
publicKey: Buffer;
|
|
9
|
+
}) => string;
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { createPrivateKey, createPublicKey } from 'node:crypto';
|
|
2
|
+
const opensshPrivateKeyBegin = '-----BEGIN OPENSSH PRIVATE KEY-----';
|
|
3
|
+
const opensshPrivateKeyEnd = '-----END OPENSSH PRIVATE KEY-----';
|
|
4
|
+
const pkcs8Ed25519PrivateKeyDerPrefix = Buffer.from('302e020100300506032b657004220420', 'hex');
|
|
5
|
+
const spkiEd25519PublicKeyDerPrefix = Buffer.from('302a300506032b6570032100', 'hex');
|
|
6
|
+
class BufferReader {
|
|
7
|
+
buffer;
|
|
8
|
+
offset = 0;
|
|
9
|
+
constructor(buffer){
|
|
10
|
+
this.buffer = buffer;
|
|
11
|
+
}
|
|
12
|
+
readBytes(length) {
|
|
13
|
+
if (length < 0 || this.remaining < length) {
|
|
14
|
+
throw new DocsSyncKeyError('OpenSSH key data is truncated.');
|
|
15
|
+
}
|
|
16
|
+
const value = this.buffer.subarray(this.offset, this.offset + length);
|
|
17
|
+
this.offset += length;
|
|
18
|
+
return value;
|
|
19
|
+
}
|
|
20
|
+
readString() {
|
|
21
|
+
const length = this.readUInt32();
|
|
22
|
+
return this.readBytes(length);
|
|
23
|
+
}
|
|
24
|
+
readUInt32() {
|
|
25
|
+
if (this.remaining < 4) {
|
|
26
|
+
throw new DocsSyncKeyError('OpenSSH key data is truncated.');
|
|
27
|
+
}
|
|
28
|
+
const value = this.buffer.readUInt32BE(this.offset);
|
|
29
|
+
this.offset += 4;
|
|
30
|
+
return value;
|
|
31
|
+
}
|
|
32
|
+
get remaining() {
|
|
33
|
+
return this.buffer.length - this.offset;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
export class DocsSyncKeyError extends Error {
|
|
37
|
+
constructor(message){
|
|
38
|
+
super(message);
|
|
39
|
+
this.name = 'DocsSyncKeyError';
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const packOpenSshString = (value)=>{
|
|
43
|
+
const buffer = typeof value === 'string' ? Buffer.from(value, 'utf8') : value;
|
|
44
|
+
const length = Buffer.alloc(4);
|
|
45
|
+
length.writeUInt32BE(buffer.length, 0);
|
|
46
|
+
return Buffer.concat([
|
|
47
|
+
length,
|
|
48
|
+
buffer
|
|
49
|
+
]);
|
|
50
|
+
};
|
|
51
|
+
const normalizeBase64 = (value)=>value.replace(/\s+/g, '');
|
|
52
|
+
const createEd25519PrivateKeyFromSeed = (seed)=>{
|
|
53
|
+
if (seed.length !== 32) {
|
|
54
|
+
throw new DocsSyncKeyError('OpenSSH Ed25519 private key seed is invalid.');
|
|
55
|
+
}
|
|
56
|
+
return createPrivateKey({
|
|
57
|
+
type: 'pkcs8',
|
|
58
|
+
format: 'der',
|
|
59
|
+
key: Buffer.concat([
|
|
60
|
+
pkcs8Ed25519PrivateKeyDerPrefix,
|
|
61
|
+
seed
|
|
62
|
+
])
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
const createEd25519PublicKeyFromRaw = (publicKey)=>{
|
|
66
|
+
if (publicKey.length !== 32) {
|
|
67
|
+
throw new DocsSyncKeyError('OpenSSH Ed25519 public key is invalid.');
|
|
68
|
+
}
|
|
69
|
+
return createPublicKey({
|
|
70
|
+
type: 'spki',
|
|
71
|
+
format: 'der',
|
|
72
|
+
key: Buffer.concat([
|
|
73
|
+
spkiEd25519PublicKeyDerPrefix,
|
|
74
|
+
publicKey
|
|
75
|
+
])
|
|
76
|
+
});
|
|
77
|
+
};
|
|
78
|
+
const parseOpenSshPrivateKey = (privateKey)=>{
|
|
79
|
+
const begin = privateKey.indexOf(opensshPrivateKeyBegin);
|
|
80
|
+
const end = privateKey.indexOf(opensshPrivateKeyEnd);
|
|
81
|
+
if (begin < 0 || end < 0 || end <= begin) {
|
|
82
|
+
throw new DocsSyncKeyError('OpenSSH private key PEM is invalid.');
|
|
83
|
+
}
|
|
84
|
+
const base64Body = privateKey.slice(begin + opensshPrivateKeyBegin.length, end);
|
|
85
|
+
const data = Buffer.from(normalizeBase64(base64Body), 'base64');
|
|
86
|
+
const authMagic = Buffer.from('openssh-key-v1\0', 'utf8');
|
|
87
|
+
if (!data.subarray(0, authMagic.length).equals(authMagic)) {
|
|
88
|
+
throw new DocsSyncKeyError('OpenSSH private key magic header is invalid.');
|
|
89
|
+
}
|
|
90
|
+
const reader = new BufferReader(data.subarray(authMagic.length));
|
|
91
|
+
const cipherName = reader.readString().toString('utf8');
|
|
92
|
+
const kdfName = reader.readString().toString('utf8');
|
|
93
|
+
reader.readString();
|
|
94
|
+
if (cipherName !== 'none' || kdfName !== 'none') {
|
|
95
|
+
throw new DocsSyncKeyError('Encrypted OpenSSH private keys are not supported. Use `payload-markdown-docs keygen --out .docs-sync` or provide an unencrypted PKCS#8 PEM Ed25519 private key.');
|
|
96
|
+
}
|
|
97
|
+
const keyCount = reader.readUInt32();
|
|
98
|
+
if (keyCount !== 1) {
|
|
99
|
+
throw new DocsSyncKeyError('OpenSSH private key must contain exactly one key.');
|
|
100
|
+
}
|
|
101
|
+
reader.readString();
|
|
102
|
+
const privateBlob = reader.readString();
|
|
103
|
+
const privateReader = new BufferReader(privateBlob);
|
|
104
|
+
const checkInt = privateReader.readUInt32();
|
|
105
|
+
const repeatedCheckInt = privateReader.readUInt32();
|
|
106
|
+
if (checkInt !== repeatedCheckInt) {
|
|
107
|
+
throw new DocsSyncKeyError('OpenSSH private key check values do not match.');
|
|
108
|
+
}
|
|
109
|
+
const keyType = privateReader.readString().toString('utf8');
|
|
110
|
+
if (keyType !== 'ssh-ed25519') {
|
|
111
|
+
throw new DocsSyncKeyError('Only Ed25519 private keys are supported for docs sync signing.');
|
|
112
|
+
}
|
|
113
|
+
const publicKey = privateReader.readString();
|
|
114
|
+
const privateKeyBytes = privateReader.readString();
|
|
115
|
+
if (privateKeyBytes.length !== 64) {
|
|
116
|
+
throw new DocsSyncKeyError('OpenSSH Ed25519 private key payload is invalid.');
|
|
117
|
+
}
|
|
118
|
+
if (!privateKeyBytes.subarray(32).equals(publicKey)) {
|
|
119
|
+
throw new DocsSyncKeyError('OpenSSH Ed25519 private/public key data does not match.');
|
|
120
|
+
}
|
|
121
|
+
return createEd25519PrivateKeyFromSeed(privateKeyBytes.subarray(0, 32));
|
|
122
|
+
};
|
|
123
|
+
const parseOpenSshPublicKey = (publicKey)=>{
|
|
124
|
+
const [keyType, base64Key] = publicKey.trim().split(/\s+/, 3);
|
|
125
|
+
if (keyType !== 'ssh-ed25519' || !base64Key) {
|
|
126
|
+
throw new DocsSyncKeyError('Only Ed25519 public keys are supported for docs sync verification.');
|
|
127
|
+
}
|
|
128
|
+
const reader = new BufferReader(Buffer.from(base64Key, 'base64'));
|
|
129
|
+
const parsedKeyType = reader.readString().toString('utf8');
|
|
130
|
+
if (parsedKeyType !== 'ssh-ed25519') {
|
|
131
|
+
throw new DocsSyncKeyError('OpenSSH public key type does not match ssh-ed25519.');
|
|
132
|
+
}
|
|
133
|
+
return createEd25519PublicKeyFromRaw(reader.readString());
|
|
134
|
+
};
|
|
135
|
+
export const getEd25519PrivateKeyInput = (privateKey)=>{
|
|
136
|
+
const trimmed = privateKey.trim();
|
|
137
|
+
if (trimmed.includes('BEGIN OPENSSH PRIVATE KEY')) {
|
|
138
|
+
return parseOpenSshPrivateKey(trimmed);
|
|
139
|
+
}
|
|
140
|
+
if (trimmed.includes('BEGIN')) {
|
|
141
|
+
try {
|
|
142
|
+
return createPrivateKey(trimmed);
|
|
143
|
+
} catch {
|
|
144
|
+
throw new DocsSyncKeyError('Private key must be an Ed25519 PKCS#8 PEM key, base64 PKCS#8 DER key, or unencrypted OpenSSH Ed25519 private key.');
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
try {
|
|
148
|
+
return createPrivateKey({
|
|
149
|
+
type: 'pkcs8',
|
|
150
|
+
format: 'der',
|
|
151
|
+
key: Buffer.from(normalizeBase64(trimmed), 'base64')
|
|
152
|
+
});
|
|
153
|
+
} catch {
|
|
154
|
+
throw new DocsSyncKeyError('Private key must be an Ed25519 PKCS#8 PEM key, base64 PKCS#8 DER key, or unencrypted OpenSSH Ed25519 private key.');
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
export const getEd25519PublicKeyInput = (publicKey)=>{
|
|
158
|
+
const trimmed = publicKey.trim();
|
|
159
|
+
if (trimmed.startsWith('ssh-ed25519 ')) {
|
|
160
|
+
return parseOpenSshPublicKey(trimmed);
|
|
161
|
+
}
|
|
162
|
+
if (trimmed.includes('BEGIN PUBLIC KEY')) {
|
|
163
|
+
return trimmed;
|
|
164
|
+
}
|
|
165
|
+
return createPublicKey({
|
|
166
|
+
type: 'spki',
|
|
167
|
+
format: 'der',
|
|
168
|
+
key: Buffer.from(normalizeBase64(trimmed), 'base64')
|
|
169
|
+
});
|
|
170
|
+
};
|
|
171
|
+
export const buildOpenSshEd25519PublicKey = ({ comment, publicKey })=>{
|
|
172
|
+
const blob = Buffer.concat([
|
|
173
|
+
packOpenSshString('ssh-ed25519'),
|
|
174
|
+
packOpenSshString(publicKey)
|
|
175
|
+
]);
|
|
176
|
+
return [
|
|
177
|
+
'ssh-ed25519',
|
|
178
|
+
blob.toString('base64'),
|
|
179
|
+
comment
|
|
180
|
+
].filter(Boolean).join(' ');
|
|
181
|
+
};
|
|
182
|
+
|
|
183
|
+
//# sourceMappingURL=ed25519Keys.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/security/ed25519Keys.ts"],"sourcesContent":["import {\n createPrivateKey,\n createPublicKey,\n} from 'node:crypto'\n\nconst opensshPrivateKeyBegin = '-----BEGIN OPENSSH PRIVATE KEY-----'\nconst opensshPrivateKeyEnd = '-----END OPENSSH PRIVATE KEY-----'\nconst pkcs8Ed25519PrivateKeyDerPrefix = Buffer.from(\n '302e020100300506032b657004220420',\n 'hex',\n)\nconst spkiEd25519PublicKeyDerPrefix = Buffer.from(\n '302a300506032b6570032100',\n 'hex',\n)\n\nclass BufferReader {\n private offset = 0\n\n constructor(private readonly buffer: Buffer) {}\n\n readBytes(length: number): Buffer {\n if (length < 0 || this.remaining < length) {\n throw new DocsSyncKeyError('OpenSSH key data is truncated.')\n }\n\n const value = this.buffer.subarray(this.offset, this.offset + length)\n this.offset += length\n\n return value\n }\n\n readString(): Buffer {\n const length = this.readUInt32()\n\n return this.readBytes(length)\n }\n\n readUInt32(): number {\n if (this.remaining < 4) {\n throw new DocsSyncKeyError('OpenSSH key data is truncated.')\n }\n\n const value = this.buffer.readUInt32BE(this.offset)\n this.offset += 4\n\n return value\n }\n\n get remaining(): number {\n return this.buffer.length - this.offset\n }\n}\n\nexport class DocsSyncKeyError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'DocsSyncKeyError'\n }\n}\n\nconst packOpenSshString = (value: Buffer | string): Buffer => {\n const buffer = typeof value === 'string' ? Buffer.from(value, 'utf8') : value\n const length = Buffer.alloc(4)\n length.writeUInt32BE(buffer.length, 0)\n\n return Buffer.concat([length, buffer])\n}\n\nconst normalizeBase64 = (value: string): string => value.replace(/\\s+/g, '')\n\nconst createEd25519PrivateKeyFromSeed = (seed: Buffer) => {\n if (seed.length !== 32) {\n throw new DocsSyncKeyError('OpenSSH Ed25519 private key seed is invalid.')\n }\n\n return createPrivateKey({\n type: 'pkcs8',\n format: 'der',\n key: Buffer.concat([pkcs8Ed25519PrivateKeyDerPrefix, seed]),\n })\n}\n\nconst createEd25519PublicKeyFromRaw = (publicKey: Buffer) => {\n if (publicKey.length !== 32) {\n throw new DocsSyncKeyError('OpenSSH Ed25519 public key is invalid.')\n }\n\n return createPublicKey({\n type: 'spki',\n format: 'der',\n key: Buffer.concat([spkiEd25519PublicKeyDerPrefix, publicKey]),\n })\n}\n\nconst parseOpenSshPrivateKey = (privateKey: string) => {\n const begin = privateKey.indexOf(opensshPrivateKeyBegin)\n const end = privateKey.indexOf(opensshPrivateKeyEnd)\n\n if (begin < 0 || end < 0 || end <= begin) {\n throw new DocsSyncKeyError('OpenSSH private key PEM is invalid.')\n }\n\n const base64Body = privateKey.slice(begin + opensshPrivateKeyBegin.length, end)\n const data = Buffer.from(normalizeBase64(base64Body), 'base64')\n const authMagic = Buffer.from('openssh-key-v1\\0', 'utf8')\n\n if (!data.subarray(0, authMagic.length).equals(authMagic)) {\n throw new DocsSyncKeyError('OpenSSH private key magic header is invalid.')\n }\n\n const reader = new BufferReader(data.subarray(authMagic.length))\n const cipherName = reader.readString().toString('utf8')\n const kdfName = reader.readString().toString('utf8')\n reader.readString()\n\n if (cipherName !== 'none' || kdfName !== 'none') {\n throw new DocsSyncKeyError(\n 'Encrypted OpenSSH private keys are not supported. Use `payload-markdown-docs keygen --out .docs-sync` or provide an unencrypted PKCS#8 PEM Ed25519 private key.',\n )\n }\n\n const keyCount = reader.readUInt32()\n\n if (keyCount !== 1) {\n throw new DocsSyncKeyError('OpenSSH private key must contain exactly one key.')\n }\n\n reader.readString()\n const privateBlob = reader.readString()\n const privateReader = new BufferReader(privateBlob)\n const checkInt = privateReader.readUInt32()\n const repeatedCheckInt = privateReader.readUInt32()\n\n if (checkInt !== repeatedCheckInt) {\n throw new DocsSyncKeyError('OpenSSH private key check values do not match.')\n }\n\n const keyType = privateReader.readString().toString('utf8')\n\n if (keyType !== 'ssh-ed25519') {\n throw new DocsSyncKeyError(\n 'Only Ed25519 private keys are supported for docs sync signing.',\n )\n }\n\n const publicKey = privateReader.readString()\n const privateKeyBytes = privateReader.readString()\n\n if (privateKeyBytes.length !== 64) {\n throw new DocsSyncKeyError('OpenSSH Ed25519 private key payload is invalid.')\n }\n\n if (!privateKeyBytes.subarray(32).equals(publicKey)) {\n throw new DocsSyncKeyError('OpenSSH Ed25519 private/public key data does not match.')\n }\n\n return createEd25519PrivateKeyFromSeed(privateKeyBytes.subarray(0, 32))\n}\n\nconst parseOpenSshPublicKey = (publicKey: string) => {\n const [keyType, base64Key] = publicKey.trim().split(/\\s+/, 3)\n\n if (keyType !== 'ssh-ed25519' || !base64Key) {\n throw new DocsSyncKeyError(\n 'Only Ed25519 public keys are supported for docs sync verification.',\n )\n }\n\n const reader = new BufferReader(Buffer.from(base64Key, 'base64'))\n const parsedKeyType = reader.readString().toString('utf8')\n\n if (parsedKeyType !== 'ssh-ed25519') {\n throw new DocsSyncKeyError('OpenSSH public key type does not match ssh-ed25519.')\n }\n\n return createEd25519PublicKeyFromRaw(reader.readString())\n}\n\nexport const getEd25519PrivateKeyInput = (privateKey: string) => {\n const trimmed = privateKey.trim()\n\n if (trimmed.includes('BEGIN OPENSSH PRIVATE KEY')) {\n return parseOpenSshPrivateKey(trimmed)\n }\n\n if (trimmed.includes('BEGIN')) {\n try {\n return createPrivateKey(trimmed)\n } catch {\n throw new DocsSyncKeyError(\n 'Private key must be an Ed25519 PKCS#8 PEM key, base64 PKCS#8 DER key, or unencrypted OpenSSH Ed25519 private key.',\n )\n }\n }\n\n try {\n return createPrivateKey({\n type: 'pkcs8',\n format: 'der',\n key: Buffer.from(normalizeBase64(trimmed), 'base64'),\n })\n } catch {\n throw new DocsSyncKeyError(\n 'Private key must be an Ed25519 PKCS#8 PEM key, base64 PKCS#8 DER key, or unencrypted OpenSSH Ed25519 private key.',\n )\n }\n}\n\nexport const getEd25519PublicKeyInput = (publicKey: string) => {\n const trimmed = publicKey.trim()\n\n if (trimmed.startsWith('ssh-ed25519 ')) {\n return parseOpenSshPublicKey(trimmed)\n }\n\n if (trimmed.includes('BEGIN PUBLIC KEY')) {\n return trimmed\n }\n\n return createPublicKey({\n type: 'spki',\n format: 'der',\n key: Buffer.from(normalizeBase64(trimmed), 'base64'),\n })\n}\n\nexport const buildOpenSshEd25519PublicKey = ({\n comment,\n publicKey,\n}: {\n comment?: string\n publicKey: Buffer\n}): string => {\n const blob = Buffer.concat([\n packOpenSshString('ssh-ed25519'),\n packOpenSshString(publicKey),\n ])\n\n return ['ssh-ed25519', blob.toString('base64'), comment].filter(Boolean).join(' ')\n}\n"],"names":["createPrivateKey","createPublicKey","opensshPrivateKeyBegin","opensshPrivateKeyEnd","pkcs8Ed25519PrivateKeyDerPrefix","Buffer","from","spkiEd25519PublicKeyDerPrefix","BufferReader","offset","buffer","readBytes","length","remaining","DocsSyncKeyError","value","subarray","readString","readUInt32","readUInt32BE","Error","message","name","packOpenSshString","alloc","writeUInt32BE","concat","normalizeBase64","replace","createEd25519PrivateKeyFromSeed","seed","type","format","key","createEd25519PublicKeyFromRaw","publicKey","parseOpenSshPrivateKey","privateKey","begin","indexOf","end","base64Body","slice","data","authMagic","equals","reader","cipherName","toString","kdfName","keyCount","privateBlob","privateReader","checkInt","repeatedCheckInt","keyType","privateKeyBytes","parseOpenSshPublicKey","base64Key","trim","split","parsedKeyType","getEd25519PrivateKeyInput","trimmed","includes","getEd25519PublicKeyInput","startsWith","buildOpenSshEd25519PublicKey","comment","blob","filter","Boolean","join"],"mappings":"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"}
|
package/dist/security/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export { buildCanonicalSigningString, getCanonicalPathFromRequestUrl, } from './canonical.js';
|
|
2
2
|
export type { CanonicalSigningStringInput } from './canonical.js';
|
|
3
|
+
export { buildOpenSshEd25519PublicKey, DocsSyncKeyError, getEd25519PrivateKeyInput, getEd25519PublicKeyInput, } from './ed25519Keys.js';
|
|
3
4
|
export { verifyGitHubOidcToken } from './githubOidc.js';
|
|
4
5
|
export type { GitHubOidcClaims, GitHubOidcErrorCode, GitHubOidcTrustedSource, GitHubOidcVerifyConfig, VerifiedGitHubOidcToken, VerifyGitHubOidcTokenResult, } from './githubOidc.js';
|
|
5
6
|
export { extractSyncRequestHeaders, syncHeaderNames } from './headers.js';
|
package/dist/security/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { buildCanonicalSigningString, getCanonicalPathFromRequestUrl } from './canonical.js';
|
|
2
|
+
export { buildOpenSshEd25519PublicKey, DocsSyncKeyError, getEd25519PrivateKeyInput, getEd25519PublicKeyInput } from './ed25519Keys.js';
|
|
2
3
|
export { verifyGitHubOidcToken } from './githubOidc.js';
|
|
3
4
|
export { extractSyncRequestHeaders, syncHeaderNames } from './headers.js';
|
|
4
5
|
export { decodeJwt, toBase64Url } from './jwt.js';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/security/index.ts"],"sourcesContent":["export {\n buildCanonicalSigningString,\n getCanonicalPathFromRequestUrl,\n} from './canonical.js'\nexport type { CanonicalSigningStringInput } from './canonical.js'\nexport { verifyGitHubOidcToken } from './githubOidc.js'\nexport type {\n GitHubOidcClaims,\n GitHubOidcErrorCode,\n GitHubOidcTrustedSource,\n GitHubOidcVerifyConfig,\n VerifiedGitHubOidcToken,\n VerifyGitHubOidcTokenResult,\n} from './githubOidc.js'\nexport { extractSyncRequestHeaders, syncHeaderNames } from './headers.js'\nexport type {\n ExtractSyncHeadersResult,\n SyncRequestHeaders,\n} from './headers.js'\nexport type { FetchJson } from './jwks.js'\nexport {\n decodeJwt,\n toBase64Url,\n} from './jwt.js'\nexport type { DecodedJwt } from './jwt.js'\nexport {\n assertNonceNotReplayed,\n storeAcceptedNonce,\n} from './nonce.js'\nexport type { NoncePayloadOperations } from './nonce.js'\nexport { signDocsSyncRequest } from './sign.js'\nexport type {\n SignDocsSyncRequestOptions,\n SignedDocsSyncRequest,\n} from './sign.js'\nexport {\n validateTimestampSkew,\n verifyBodySha256,\n verifyEd25519Signature,\n} from './verify.js'\nexport type {\n ValidateTimestampResult,\n VerifyBodyHashResult,\n} from './verify.js'\n"],"names":["buildCanonicalSigningString","getCanonicalPathFromRequestUrl","verifyGitHubOidcToken","extractSyncRequestHeaders","syncHeaderNames","decodeJwt","toBase64Url","assertNonceNotReplayed","storeAcceptedNonce","signDocsSyncRequest","validateTimestampSkew","verifyBodySha256","verifyEd25519Signature"],"mappings":"AAAA,SACEA,2BAA2B,EAC3BC,8BAA8B,QACzB,iBAAgB;AAEvB,SAASC,qBAAqB,QAAQ,kBAAiB;AASvD,SAASC,yBAAyB,EAAEC,eAAe,QAAQ,eAAc;AAMzE,SACEC,SAAS,EACTC,WAAW,QACN,WAAU;AAEjB,SACEC,sBAAsB,EACtBC,kBAAkB,QACb,aAAY;AAEnB,SAASC,mBAAmB,QAAQ,YAAW;AAK/C,SACEC,qBAAqB,EACrBC,gBAAgB,EAChBC,sBAAsB,QACjB,cAAa"}
|
|
1
|
+
{"version":3,"sources":["../../src/security/index.ts"],"sourcesContent":["export {\n buildCanonicalSigningString,\n getCanonicalPathFromRequestUrl,\n} from './canonical.js'\nexport type { CanonicalSigningStringInput } from './canonical.js'\nexport {\n buildOpenSshEd25519PublicKey,\n DocsSyncKeyError,\n getEd25519PrivateKeyInput,\n getEd25519PublicKeyInput,\n} from './ed25519Keys.js'\nexport { verifyGitHubOidcToken } from './githubOidc.js'\nexport type {\n GitHubOidcClaims,\n GitHubOidcErrorCode,\n GitHubOidcTrustedSource,\n GitHubOidcVerifyConfig,\n VerifiedGitHubOidcToken,\n VerifyGitHubOidcTokenResult,\n} from './githubOidc.js'\nexport { extractSyncRequestHeaders, syncHeaderNames } from './headers.js'\nexport type {\n ExtractSyncHeadersResult,\n SyncRequestHeaders,\n} from './headers.js'\nexport type { FetchJson } from './jwks.js'\nexport {\n decodeJwt,\n toBase64Url,\n} from './jwt.js'\nexport type { DecodedJwt } from './jwt.js'\nexport {\n assertNonceNotReplayed,\n storeAcceptedNonce,\n} from './nonce.js'\nexport type { NoncePayloadOperations } from './nonce.js'\nexport { signDocsSyncRequest } from './sign.js'\nexport type {\n SignDocsSyncRequestOptions,\n SignedDocsSyncRequest,\n} from './sign.js'\nexport {\n validateTimestampSkew,\n verifyBodySha256,\n verifyEd25519Signature,\n} from './verify.js'\nexport type {\n ValidateTimestampResult,\n VerifyBodyHashResult,\n} from './verify.js'\n"],"names":["buildCanonicalSigningString","getCanonicalPathFromRequestUrl","buildOpenSshEd25519PublicKey","DocsSyncKeyError","getEd25519PrivateKeyInput","getEd25519PublicKeyInput","verifyGitHubOidcToken","extractSyncRequestHeaders","syncHeaderNames","decodeJwt","toBase64Url","assertNonceNotReplayed","storeAcceptedNonce","signDocsSyncRequest","validateTimestampSkew","verifyBodySha256","verifyEd25519Signature"],"mappings":"AAAA,SACEA,2BAA2B,EAC3BC,8BAA8B,QACzB,iBAAgB;AAEvB,SACEC,4BAA4B,EAC5BC,gBAAgB,EAChBC,yBAAyB,EACzBC,wBAAwB,QACnB,mBAAkB;AACzB,SAASC,qBAAqB,QAAQ,kBAAiB;AASvD,SAASC,yBAAyB,EAAEC,eAAe,QAAQ,eAAc;AAMzE,SACEC,SAAS,EACTC,WAAW,QACN,WAAU;AAEjB,SACEC,sBAAsB,EACtBC,kBAAkB,QACb,aAAY;AAEnB,SAASC,mBAAmB,QAAQ,YAAW;AAK/C,SACEC,qBAAqB,EACrBC,gBAAgB,EAChBC,sBAAsB,QACjB,cAAa"}
|
package/dist/security/sign.js
CHANGED
|
@@ -1,16 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { randomUUID, sign } from 'node:crypto';
|
|
2
2
|
import { sha256Hex } from '../sync/index.js';
|
|
3
3
|
import { buildCanonicalSigningString } from './canonical.js';
|
|
4
|
-
|
|
5
|
-
if (privateKey.includes('BEGIN PRIVATE KEY')) {
|
|
6
|
-
return privateKey;
|
|
7
|
-
}
|
|
8
|
-
return createPrivateKey({
|
|
9
|
-
type: 'pkcs8',
|
|
10
|
-
format: 'der',
|
|
11
|
-
key: Buffer.from(privateKey, 'base64')
|
|
12
|
-
});
|
|
13
|
-
};
|
|
4
|
+
import { getEd25519PrivateKeyInput } from './ed25519Keys.js';
|
|
14
5
|
const getEndpointPathname = (endpoint)=>new URL(endpoint).pathname;
|
|
15
6
|
export const signDocsSyncRequest = ({ body, endpoint, keyId, nonce = randomUUID(), now = new Date(), privateKey })=>{
|
|
16
7
|
const bodySha256 = sha256Hex(body);
|
|
@@ -22,7 +13,7 @@ export const signDocsSyncRequest = ({ body, endpoint, keyId, nonce = randomUUID(
|
|
|
22
13
|
path: getEndpointPathname(endpoint),
|
|
23
14
|
timestamp
|
|
24
15
|
});
|
|
25
|
-
const signature = sign(null, Buffer.from(canonicalString, 'utf8'),
|
|
16
|
+
const signature = sign(null, Buffer.from(canonicalString, 'utf8'), getEd25519PrivateKeyInput(privateKey)).toString('base64');
|
|
26
17
|
return {
|
|
27
18
|
body,
|
|
28
19
|
headers: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/security/sign.ts"],"sourcesContent":["import {\n
|
|
1
|
+
{"version":3,"sources":["../../src/security/sign.ts"],"sourcesContent":["import {\n randomUUID,\n sign,\n} from 'node:crypto'\n\nimport { sha256Hex } from '../sync/index.js'\nimport { buildCanonicalSigningString } from './canonical.js'\nimport { getEd25519PrivateKeyInput } from './ed25519Keys.js'\n\nexport type SignDocsSyncRequestOptions = {\n body: string\n endpoint: string\n keyId: string\n nonce?: string\n now?: Date\n privateKey: string\n}\n\nexport type SignedDocsSyncRequest = {\n body: string\n headers: Record<string, string>\n}\n\nconst getEndpointPathname = (endpoint: string): string => new URL(endpoint).pathname\n\nexport const signDocsSyncRequest = ({\n body,\n endpoint,\n keyId,\n nonce = randomUUID(),\n now = new Date(),\n privateKey,\n}: SignDocsSyncRequestOptions): SignedDocsSyncRequest => {\n const bodySha256 = sha256Hex(body)\n const timestamp = now.toISOString()\n const canonicalString = buildCanonicalSigningString({\n bodySha256,\n method: 'POST',\n nonce,\n path: getEndpointPathname(endpoint),\n timestamp,\n })\n const signature = sign(\n null,\n Buffer.from(canonicalString, 'utf8'),\n getEd25519PrivateKeyInput(privateKey),\n ).toString('base64')\n\n return {\n body,\n headers: {\n 'Content-Type': 'application/json',\n 'X-VL-MD-DOCS-Body-SHA256': bodySha256,\n 'X-VL-MD-DOCS-Key-Id': keyId,\n 'X-VL-MD-DOCS-Nonce': nonce,\n 'X-VL-MD-DOCS-Signature': signature,\n 'X-VL-MD-DOCS-Timestamp': timestamp,\n },\n }\n}\n"],"names":["randomUUID","sign","sha256Hex","buildCanonicalSigningString","getEd25519PrivateKeyInput","getEndpointPathname","endpoint","URL","pathname","signDocsSyncRequest","body","keyId","nonce","now","Date","privateKey","bodySha256","timestamp","toISOString","canonicalString","method","path","signature","Buffer","from","toString","headers"],"mappings":"AAAA,SACEA,UAAU,EACVC,IAAI,QACC,cAAa;AAEpB,SAASC,SAAS,QAAQ,mBAAkB;AAC5C,SAASC,2BAA2B,QAAQ,iBAAgB;AAC5D,SAASC,yBAAyB,QAAQ,mBAAkB;AAgB5D,MAAMC,sBAAsB,CAACC,WAA6B,IAAIC,IAAID,UAAUE,QAAQ;AAEpF,OAAO,MAAMC,sBAAsB,CAAC,EAClCC,IAAI,EACJJ,QAAQ,EACRK,KAAK,EACLC,QAAQZ,YAAY,EACpBa,MAAM,IAAIC,MAAM,EAChBC,UAAU,EACiB;IAC3B,MAAMC,aAAad,UAAUQ;IAC7B,MAAMO,YAAYJ,IAAIK,WAAW;IACjC,MAAMC,kBAAkBhB,4BAA4B;QAClDa;QACAI,QAAQ;QACRR;QACAS,MAAMhB,oBAAoBC;QAC1BW;IACF;IACA,MAAMK,YAAYrB,KAChB,MACAsB,OAAOC,IAAI,CAACL,iBAAiB,SAC7Bf,0BAA0BW,aAC1BU,QAAQ,CAAC;IAEX,OAAO;QACLf;QACAgB,SAAS;YACP,gBAAgB;YAChB,4BAA4BV;YAC5B,uBAAuBL;YACvB,sBAAsBC;YACtB,0BAA0BU;YAC1B,0BAA0BL;QAC5B;IACF;AACF,EAAC"}
|
package/dist/security/verify.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { verify } from 'node:crypto';
|
|
2
2
|
import { sha256Hex } from '../sync/index.js';
|
|
3
|
+
import { getEd25519PublicKeyInput } from './ed25519Keys.js';
|
|
3
4
|
export const verifyBodySha256 = ({ body, expectedHash })=>{
|
|
4
5
|
const computedHash = sha256Hex(body);
|
|
5
6
|
if (!/^[a-f0-9]{64}$/i.test(expectedHash)) {
|
|
@@ -33,19 +34,9 @@ export const validateTimestampSkew = ({ maxSkewSeconds, now = new Date(), timest
|
|
|
33
34
|
ok: true
|
|
34
35
|
};
|
|
35
36
|
};
|
|
36
|
-
const getPublicKeyInput = (publicKey)=>{
|
|
37
|
-
if (publicKey.includes('BEGIN PUBLIC KEY')) {
|
|
38
|
-
return publicKey;
|
|
39
|
-
}
|
|
40
|
-
return createPublicKey({
|
|
41
|
-
type: 'spki',
|
|
42
|
-
format: 'der',
|
|
43
|
-
key: Buffer.from(publicKey, 'base64')
|
|
44
|
-
});
|
|
45
|
-
};
|
|
46
37
|
export const verifyEd25519Signature = ({ canonicalString, publicKey, signature })=>{
|
|
47
38
|
try {
|
|
48
|
-
return verify(null, Buffer.from(canonicalString, 'utf8'),
|
|
39
|
+
return verify(null, Buffer.from(canonicalString, 'utf8'), getEd25519PublicKeyInput(publicKey), Buffer.from(signature, 'base64'));
|
|
49
40
|
} catch {
|
|
50
41
|
return false;
|
|
51
42
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/security/verify.ts"],"sourcesContent":["import {
|
|
1
|
+
{"version":3,"sources":["../../src/security/verify.ts"],"sourcesContent":["import { verify } from 'node:crypto'\n\nimport { sha256Hex } from '../sync/index.js'\nimport { getEd25519PublicKeyInput } from './ed25519Keys.js'\n\nexport type VerifyBodyHashResult =\n | {\n computedHash: string\n ok: false\n }\n | {\n computedHash: string\n ok: true\n }\n\nexport type ValidateTimestampResult =\n | {\n date: Date\n ok: true\n }\n | {\n message: string\n ok: false\n }\n\nexport const verifyBodySha256 = ({\n body,\n expectedHash,\n}: {\n body: string\n expectedHash: string\n}): VerifyBodyHashResult => {\n const computedHash = sha256Hex(body)\n\n if (!/^[a-f0-9]{64}$/i.test(expectedHash)) {\n return {\n computedHash,\n ok: false,\n }\n }\n\n return {\n computedHash,\n ok: computedHash === expectedHash.toLowerCase(),\n }\n}\n\nexport const validateTimestampSkew = ({\n maxSkewSeconds,\n now = new Date(),\n timestamp,\n}: {\n maxSkewSeconds: number\n now?: Date\n timestamp: string\n}): ValidateTimestampResult => {\n const date = new Date(timestamp)\n\n if (Number.isNaN(date.getTime())) {\n return {\n message: 'Sync request timestamp is invalid.',\n ok: false,\n }\n }\n\n const skewMs = Math.abs(now.getTime() - date.getTime())\n\n if (skewMs > maxSkewSeconds * 1000) {\n return {\n message: 'Sync request timestamp is outside the allowed skew.',\n ok: false,\n }\n }\n\n return {\n date,\n ok: true,\n }\n}\n\nexport const verifyEd25519Signature = ({\n canonicalString,\n publicKey,\n signature,\n}: {\n canonicalString: string\n publicKey: string\n signature: string\n}): boolean => {\n try {\n return verify(\n null,\n Buffer.from(canonicalString, 'utf8'),\n getEd25519PublicKeyInput(publicKey),\n Buffer.from(signature, 'base64'),\n )\n } catch {\n return false\n }\n}\n"],"names":["verify","sha256Hex","getEd25519PublicKeyInput","verifyBodySha256","body","expectedHash","computedHash","test","ok","toLowerCase","validateTimestampSkew","maxSkewSeconds","now","Date","timestamp","date","Number","isNaN","getTime","message","skewMs","Math","abs","verifyEd25519Signature","canonicalString","publicKey","signature","Buffer","from"],"mappings":"AAAA,SAASA,MAAM,QAAQ,cAAa;AAEpC,SAASC,SAAS,QAAQ,mBAAkB;AAC5C,SAASC,wBAAwB,QAAQ,mBAAkB;AAsB3D,OAAO,MAAMC,mBAAmB,CAAC,EAC/BC,IAAI,EACJC,YAAY,EAIb;IACC,MAAMC,eAAeL,UAAUG;IAE/B,IAAI,CAAC,kBAAkBG,IAAI,CAACF,eAAe;QACzC,OAAO;YACLC;YACAE,IAAI;QACN;IACF;IAEA,OAAO;QACLF;QACAE,IAAIF,iBAAiBD,aAAaI,WAAW;IAC/C;AACF,EAAC;AAED,OAAO,MAAMC,wBAAwB,CAAC,EACpCC,cAAc,EACdC,MAAM,IAAIC,MAAM,EAChBC,SAAS,EAKV;IACC,MAAMC,OAAO,IAAIF,KAAKC;IAEtB,IAAIE,OAAOC,KAAK,CAACF,KAAKG,OAAO,KAAK;QAChC,OAAO;YACLC,SAAS;YACTX,IAAI;QACN;IACF;IAEA,MAAMY,SAASC,KAAKC,GAAG,CAACV,IAAIM,OAAO,KAAKH,KAAKG,OAAO;IAEpD,IAAIE,SAAST,iBAAiB,MAAM;QAClC,OAAO;YACLQ,SAAS;YACTX,IAAI;QACN;IACF;IAEA,OAAO;QACLO;QACAP,IAAI;IACN;AACF,EAAC;AAED,OAAO,MAAMe,yBAAyB,CAAC,EACrCC,eAAe,EACfC,SAAS,EACTC,SAAS,EAKV;IACC,IAAI;QACF,OAAO1B,OACL,MACA2B,OAAOC,IAAI,CAACJ,iBAAiB,SAC7BtB,yBAAyBuB,YACzBE,OAAOC,IAAI,CAACF,WAAW;IAE3B,EAAE,OAAM;QACN,OAAO;IACT;AACF,EAAC"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Admin Manager
|
|
2
2
|
|
|
3
|
-
The Docs Set Admin Manager is
|
|
3
|
+
The Docs Set Admin Manager is an overview on the docs set edit view.
|
|
4
4
|
|
|
5
5
|
It shows:
|
|
6
6
|
|
|
@@ -13,6 +13,7 @@ It shows:
|
|
|
13
13
|
- docs with overrides
|
|
14
14
|
- generated docs grouped by source path
|
|
15
15
|
- links to generated docs records
|
|
16
|
+
- a publish action for draft generated docs when draft publishing is enabled
|
|
16
17
|
|
|
17
18
|
Per-doc overrides live on generated docs records:
|
|
18
19
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@valkyrianlabs/payload-markdown-docs",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.2",
|
|
4
4
|
"description": "Git-backed Markdown documentation sync for Payload CMS, powered by payload-markdown.",
|
|
5
5
|
"bin": {
|
|
6
6
|
"payload-markdown-docs": "./dist/cli/index.js"
|
|
@@ -45,6 +45,8 @@
|
|
|
45
45
|
"build:swc": "swc ./src -d ./dist --config-file .swcrc --strip-leading-paths --ignore \"**/*.spec.ts\"",
|
|
46
46
|
"build:types": "tsc -p tsconfig.build.json --outDir dist --rootDir ./src",
|
|
47
47
|
"clean": "rimraf {dist,*.tsbuildinfo}",
|
|
48
|
+
"cli": "node --import @swc-node/register/esm-register ./src/cli/index.ts",
|
|
49
|
+
"cli:dist": "node ./dist/cli/index.js",
|
|
48
50
|
"copyfiles": "copyfiles -u 1 \"src/**/*.{html,css,scss,ttf,woff,woff2,eot,svg,jpg,png,json,md}\" dist/",
|
|
49
51
|
"dev": "next dev dev --turbo",
|
|
50
52
|
"dev:docs:keygen": "pnpm dev:payload run ./dev/scripts/create-docs-keypair.ts",
|