@valkyrianlabs/payload-markdown-docs 0.3.1 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +79 -171
- package/dist/admin/DocsSetManager.js +5 -3
- package/dist/admin/DocsSetManager.js.map +1 -1
- package/dist/admin/docsSetManagerData.d.ts +6 -5
- package/dist/admin/docsSetManagerData.js +60 -33
- package/dist/admin/docsSetManagerData.js.map +1 -1
- package/dist/admin/docsSetManagerTypes.d.ts +12 -9
- package/dist/admin/docsSetManagerTypes.js.map +1 -1
- package/dist/cli/commands/manifest.js +1 -2
- package/dist/cli/commands/manifest.js.map +1 -1
- package/dist/cli/commands/plan.js +1 -2
- package/dist/cli/commands/plan.js.map +1 -1
- package/dist/cli/commands/push.js +19 -12
- package/dist/cli/commands/push.js.map +1 -1
- package/dist/cli/commands/validate.js +11 -6
- package/dist/cli/commands/validate.js.map +1 -1
- package/dist/cli/index.js +6 -15
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/parseArgs.js +0 -3
- package/dist/cli/parseArgs.js.map +1 -1
- package/dist/cli/types.d.ts +0 -3
- package/dist/cli/types.js.map +1 -1
- package/dist/collections/docs.js +0 -24
- package/dist/collections/docs.js.map +1 -1
- package/dist/collections/docsGroups.js +8 -9
- package/dist/collections/docsGroups.js.map +1 -1
- package/dist/collections/docsKeys.d.ts +5 -0
- package/dist/collections/docsKeys.js +44 -0
- package/dist/collections/docsKeys.js.map +1 -0
- package/dist/collections/docsSets.js +47 -202
- package/dist/collections/docsSets.js.map +1 -1
- package/dist/collections/docsTrusted.d.ts +5 -0
- package/dist/collections/docsTrusted.js +60 -0
- package/dist/collections/docsTrusted.js.map +1 -0
- package/dist/collections/index.d.ts +4 -0
- package/dist/collections/index.js +2 -0
- package/dist/collections/index.js.map +1 -1
- package/dist/constants.d.ts +3 -1
- package/dist/constants.js +3 -1
- package/dist/constants.js.map +1 -1
- package/dist/endpoints/sync.d.ts +6 -7
- package/dist/endpoints/sync.js +57 -124
- package/dist/endpoints/sync.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/next/PayloadMarkdownDocsPage.js +2 -6
- package/dist/next/PayloadMarkdownDocsPage.js.map +1 -1
- package/dist/next/index.d.ts +2 -0
- package/dist/next/index.js +1 -0
- package/dist/next/index.js.map +1 -1
- package/dist/next/links.d.ts +11 -0
- package/dist/next/links.js +79 -0
- package/dist/next/links.js.map +1 -0
- package/dist/next/markdown.js +91 -19
- package/dist/next/markdown.js.map +1 -1
- package/dist/next/metadata.js +6 -6
- package/dist/next/metadata.js.map +1 -1
- package/dist/next/records.js +13 -23
- package/dist/next/records.js.map +1 -1
- package/dist/next/route.js +141 -49
- package/dist/next/route.js.map +1 -1
- package/dist/next/types.d.ts +0 -14
- package/dist/next/types.js.map +1 -1
- package/dist/payload/docsKeys.d.ts +20 -0
- package/dist/payload/docsKeys.js +29 -0
- package/dist/payload/docsKeys.js.map +1 -0
- package/dist/payload/docsSets.d.ts +32 -6
- package/dist/payload/docsSets.js +146 -83
- package/dist/payload/docsSets.js.map +1 -1
- package/dist/payload/docsTrusted.d.ts +16 -0
- package/dist/payload/docsTrusted.js +49 -0
- package/dist/payload/docsTrusted.js.map +1 -0
- package/dist/payload/index.d.ts +5 -1
- package/dist/payload/index.js +3 -1
- package/dist/payload/index.js.map +1 -1
- package/dist/plugin.js +36 -9
- package/dist/plugin.js.map +1 -1
- package/dist/security/ed25519Keys.d.ts +9 -0
- package/dist/security/ed25519Keys.js +183 -0
- package/dist/security/ed25519Keys.js.map +1 -0
- package/dist/security/githubOidc.d.ts +18 -5
- package/dist/security/githubOidc.js +44 -16
- package/dist/security/githubOidc.js.map +1 -1
- package/dist/security/index.d.ts +2 -1
- package/dist/security/index.js +1 -0
- package/dist/security/index.js.map +1 -1
- package/dist/security/sign.js +3 -12
- package/dist/security/sign.js.map +1 -1
- package/dist/security/verify.js +3 -12
- package/dist/security/verify.js.map +1 -1
- package/dist/skills/codex/SKILL.md +3 -4
- package/dist/skills/codex/examples/github-actions.md +0 -2
- package/dist/skills/codex/reference/admin.md +0 -6
- package/dist/skills/codex/reference/routing.md +2 -1
- package/dist/skills/codex/reference/sync.md +7 -5
- package/dist/skills/codex/reference/troubleshooting.md +3 -4
- package/dist/skills/codex/reference/workflow.md +0 -1
- package/dist/sync/manifest.d.ts +1 -3
- package/dist/sync/manifest.js +2 -3
- package/dist/sync/manifest.js.map +1 -1
- package/dist/sync/validate.js +1 -2
- package/dist/sync/validate.js.map +1 -1
- package/dist/types.d.ts +7 -50
- package/dist/types.js.map +1 -1
- package/package.json +6 -4
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"}
|
|
@@ -16,9 +16,9 @@ The docs source lives in `{{docsRoot}}` unless the user says otherwise. Edit Mar
|
|
|
16
16
|
- Run validation before finishing docs edits.
|
|
17
17
|
- Treat sync and publishing as CMS/server-owned. The request may ask; Payload
|
|
18
18
|
docs sets and plugin config decide.
|
|
19
|
-
- Do not hardcode new docs
|
|
20
|
-
to a Payload Admin docs set
|
|
21
|
-
|
|
19
|
+
- Do not hardcode new docs packages into plugin config. A docs package should map
|
|
20
|
+
to a Payload Admin docs set slug. Routes are derived from groups and slugs;
|
|
21
|
+
trust belongs in global Keys and Trusted records.
|
|
22
22
|
|
|
23
23
|
## AI Markdown Export Manifest
|
|
24
24
|
|
|
@@ -135,7 +135,6 @@ Only push when the user asks for an upload and provides endpoint/auth context. P
|
|
|
135
135
|
--endpoint "$DOCS_SYNC_ENDPOINT" \
|
|
136
136
|
--source main-docs \
|
|
137
137
|
--github-oidc \
|
|
138
|
-
--oidc-audience payload-markdown-docs \
|
|
139
138
|
--dry-run
|
|
140
139
|
```
|
|
141
140
|
|
|
@@ -44,7 +44,6 @@ jobs:
|
|
|
44
44
|
--endpoint "$DOCS_SYNC_ENDPOINT" \
|
|
45
45
|
--source main-docs \
|
|
46
46
|
--github-oidc \
|
|
47
|
-
--oidc-audience payload-markdown-docs \
|
|
48
47
|
--dry-run
|
|
49
48
|
env:
|
|
50
49
|
DOCS_SYNC_ENDPOINT: ${{ secrets.DOCS_SYNC_ENDPOINT }}
|
|
@@ -56,7 +55,6 @@ jobs:
|
|
|
56
55
|
--endpoint "$DOCS_SYNC_ENDPOINT" \
|
|
57
56
|
--source main-docs \
|
|
58
57
|
--github-oidc \
|
|
59
|
-
--oidc-audience payload-markdown-docs \
|
|
60
58
|
--sync \
|
|
61
59
|
--publish
|
|
62
60
|
env:
|
|
@@ -18,11 +18,5 @@ Per-doc overrides live on generated docs records:
|
|
|
18
18
|
|
|
19
19
|
- `navTitle`
|
|
20
20
|
- `hideFromNav`
|
|
21
|
-
- `theme`
|
|
22
|
-
- `heroEyebrow`
|
|
23
|
-
- `heroTitle`
|
|
24
|
-
- `heroDescription`
|
|
25
|
-
- `seoTitle`
|
|
26
|
-
- `seoDescription`
|
|
27
21
|
|
|
28
22
|
Inline override editing from the manager is not implemented yet. Open the generated docs record to edit overrides.
|
|
@@ -8,7 +8,8 @@ Docs groups reserve namespaces such as `/plugins` or `/internal/tools`.
|
|
|
8
8
|
|
|
9
9
|
## Docs Sets
|
|
10
10
|
|
|
11
|
-
Docs sets represent one documentation site.
|
|
11
|
+
Docs sets represent one documentation site. Their route base is derived from an
|
|
12
|
+
optional group plus the docs set slug, such as:
|
|
12
13
|
|
|
13
14
|
```text
|
|
14
15
|
/plugins/payload-markdown-docs
|
|
@@ -5,7 +5,8 @@ The sync workflow is authenticated and server-owned.
|
|
|
5
5
|
Important concepts:
|
|
6
6
|
|
|
7
7
|
- `source.id` maps to a Payload Admin docs set.
|
|
8
|
-
- The docs set
|
|
8
|
+
- The docs set slug and optional group determine the route base.
|
|
9
|
+
- Global Keys and Trusted records own reusable authentication trust.
|
|
9
10
|
- The manifest does not choose target collections or fields.
|
|
10
11
|
- `sync.allowWrites: true` is required for `mode: "sync"`.
|
|
11
12
|
- `sync.allowPublish: true` and `target.enableDrafts: true` are required for publishing.
|
|
@@ -25,12 +26,13 @@ Ed25519 signed pushes verify:
|
|
|
25
26
|
GitHub OIDC pushes verify:
|
|
26
27
|
|
|
27
28
|
- bearer JWT signature through GitHub JWKS
|
|
28
|
-
-
|
|
29
|
-
-
|
|
29
|
+
- docs set slug as audience
|
|
30
|
+
- trusted owner/repository and docs set branch
|
|
31
|
+
- advanced workflow refs only when explicitly enabled on the docs set
|
|
30
32
|
- pull request policy
|
|
31
33
|
- JWT `jti` replay protection
|
|
32
34
|
- body SHA-256
|
|
33
35
|
- manifest validity
|
|
34
36
|
|
|
35
|
-
Do not bypass failed auth or body verification. Fix the key, endpoint, docs set
|
|
36
|
-
|
|
37
|
+
Do not bypass failed auth or body verification. Fix the key, endpoint, docs set
|
|
38
|
+
slug, body, or server config.
|
|
@@ -6,12 +6,11 @@ Check key id, private key, endpoint pathname, timestamp, nonce, and exact body s
|
|
|
6
6
|
|
|
7
7
|
## OIDC invalid token
|
|
8
8
|
|
|
9
|
-
Check that the workflow uses `--github-oidc`, grants `id-token: write`, and
|
|
9
|
+
Check that the workflow uses `--github-oidc`, grants `id-token: write`, and uses a source matching the docs set slug.
|
|
10
10
|
|
|
11
11
|
## OIDC repository or ref not allowed
|
|
12
12
|
|
|
13
|
-
Check
|
|
14
|
-
repository and ref are trusted.
|
|
13
|
+
Check `Docs Globals > Trusted` for owner/repository trust and the docs set branch for ref trust.
|
|
15
14
|
|
|
16
15
|
## OIDC replay
|
|
17
16
|
|
|
@@ -27,7 +26,7 @@ Generate a fresh request. Do not reuse signed headers.
|
|
|
27
26
|
|
|
28
27
|
## Source not allowed
|
|
29
28
|
|
|
30
|
-
Create or update a docs set with the expected
|
|
29
|
+
Create or update a docs set with the expected slug.
|
|
31
30
|
|
|
32
31
|
## Publish disabled
|
|
33
32
|
|
package/dist/sync/manifest.d.ts
CHANGED
|
@@ -7,7 +7,6 @@ export type DocsManifestSource = {
|
|
|
7
7
|
commit?: string;
|
|
8
8
|
id: string;
|
|
9
9
|
repository?: string;
|
|
10
|
-
root?: string;
|
|
11
10
|
};
|
|
12
11
|
export type DocsManifestFile = {
|
|
13
12
|
content: string;
|
|
@@ -44,7 +43,7 @@ export type DocsManifestInputFile = {
|
|
|
44
43
|
content: string;
|
|
45
44
|
path: string;
|
|
46
45
|
};
|
|
47
|
-
export declare const buildDocsManifest: ({ aiExport, branch, commit, deleteBehavior, files, mode, publish, repository,
|
|
46
|
+
export declare const buildDocsManifest: ({ aiExport, branch, commit, deleteBehavior, files, mode, publish, repository, sourceId, }: {
|
|
48
47
|
aiExport?: DocsAiExportManifest;
|
|
49
48
|
branch?: string;
|
|
50
49
|
commit?: string;
|
|
@@ -53,6 +52,5 @@ export declare const buildDocsManifest: ({ aiExport, branch, commit, deleteBehav
|
|
|
53
52
|
mode?: DocsSyncMode;
|
|
54
53
|
publish?: boolean;
|
|
55
54
|
repository?: string;
|
|
56
|
-
root?: string;
|
|
57
55
|
sourceId: string;
|
|
58
56
|
}) => DocsManifest;
|
package/dist/sync/manifest.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { sha256Hex } from './hash.js';
|
|
2
|
-
export const buildDocsManifest = ({ aiExport, branch, commit, deleteBehavior, files, mode, publish, repository,
|
|
2
|
+
export const buildDocsManifest = ({ aiExport, branch, commit, deleteBehavior, files, mode, publish, repository, sourceId })=>({
|
|
3
3
|
aiExport,
|
|
4
4
|
deleteBehavior,
|
|
5
5
|
files: files.map((file)=>({
|
|
@@ -12,8 +12,7 @@ export const buildDocsManifest = ({ aiExport, branch, commit, deleteBehavior, fi
|
|
|
12
12
|
id: sourceId,
|
|
13
13
|
branch,
|
|
14
14
|
commit,
|
|
15
|
-
repository
|
|
16
|
-
root
|
|
15
|
+
repository
|
|
17
16
|
},
|
|
18
17
|
version: 1
|
|
19
18
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/sync/manifest.ts"],"sourcesContent":["import type { DocsAiExportManifest } from './aiExportManifest.js'\nimport type { DocsFrontmatter } from './frontmatter.js'\n\nimport { sha256Hex } from './hash.js'\n\nexport type DocsSyncMode = 'dry-run' | 'sync'\n\nexport type DocsDeleteBehavior = 'archive' | 'delete' | 'draft' | 'ignore'\n\nexport type DocsManifestSource = {\n branch?: string\n commit?: string\n id: string\n repository?: string\n
|
|
1
|
+
{"version":3,"sources":["../../src/sync/manifest.ts"],"sourcesContent":["import type { DocsAiExportManifest } from './aiExportManifest.js'\nimport type { DocsFrontmatter } from './frontmatter.js'\n\nimport { sha256Hex } from './hash.js'\n\nexport type DocsSyncMode = 'dry-run' | 'sync'\n\nexport type DocsDeleteBehavior = 'archive' | 'delete' | 'draft' | 'ignore'\n\nexport type DocsManifestSource = {\n branch?: string\n commit?: string\n id: string\n repository?: string\n}\n\nexport type DocsManifestFile = {\n content: string\n path: string\n sha256?: string\n}\n\nexport type DocsManifest = {\n aiExport?: DocsAiExportManifest\n deleteBehavior?: DocsDeleteBehavior\n files: DocsManifestFile[]\n mode?: DocsSyncMode\n publish?: boolean\n source: DocsManifestSource\n version: 1\n}\n\nexport type ValidatedDocsManifestFile = {\n content: string\n frontmatter: DocsFrontmatter\n path: string\n route: string\n sha256: string\n title: string\n}\n\nexport type ValidatedDocsManifest = {\n aiExport?: DocsAiExportManifest\n deleteBehavior: DocsDeleteBehavior\n files: ValidatedDocsManifestFile[]\n mode: DocsSyncMode\n publish: boolean\n source: DocsManifestSource\n version: 1\n}\n\nexport type DocsManifestInputFile = {\n content: string\n path: string\n}\n\nexport const buildDocsManifest = ({\n aiExport,\n branch,\n commit,\n deleteBehavior,\n files,\n mode,\n publish,\n repository,\n sourceId,\n}: {\n aiExport?: DocsAiExportManifest\n branch?: string\n commit?: string\n deleteBehavior?: DocsDeleteBehavior\n files: DocsManifestInputFile[]\n mode?: DocsSyncMode\n publish?: boolean\n repository?: string\n sourceId: string\n}): DocsManifest => ({\n aiExport,\n deleteBehavior,\n files: files.map((file) => ({\n ...file,\n sha256: sha256Hex(file.content),\n })),\n mode,\n publish,\n source: {\n id: sourceId,\n branch,\n commit,\n repository,\n },\n version: 1,\n})\n"],"names":["sha256Hex","buildDocsManifest","aiExport","branch","commit","deleteBehavior","files","mode","publish","repository","sourceId","map","file","sha256","content","source","id","version"],"mappings":"AAGA,SAASA,SAAS,QAAQ,YAAW;AAqDrC,OAAO,MAAMC,oBAAoB,CAAC,EAChCC,QAAQ,EACRC,MAAM,EACNC,MAAM,EACNC,cAAc,EACdC,KAAK,EACLC,IAAI,EACJC,OAAO,EACPC,UAAU,EACVC,QAAQ,EAWT,GAAoB,CAAA;QACnBR;QACAG;QACAC,OAAOA,MAAMK,GAAG,CAAC,CAACC,OAAU,CAAA;gBAC1B,GAAGA,IAAI;gBACPC,QAAQb,UAAUY,KAAKE,OAAO;YAChC,CAAA;QACAP;QACAC;QACAO,QAAQ;YACNC,IAAIN;YACJP;YACAC;YACAK;QACF;QACAQ,SAAS;IACX,CAAA,EAAE"}
|
package/dist/sync/validate.js
CHANGED
|
@@ -47,8 +47,7 @@ const validateSource = ({ allowedSourceIds, source })=>{
|
|
|
47
47
|
id: source.id,
|
|
48
48
|
branch: typeof source.branch === 'string' ? source.branch : undefined,
|
|
49
49
|
commit: typeof source.commit === 'string' ? source.commit : undefined,
|
|
50
|
-
repository: typeof source.repository === 'string' ? source.repository : undefined
|
|
51
|
-
root: typeof source.root === 'string' ? source.root : undefined
|
|
50
|
+
repository: typeof source.repository === 'string' ? source.repository : undefined
|
|
52
51
|
}
|
|
53
52
|
};
|
|
54
53
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/sync/validate.ts"],"sourcesContent":["import type {\n DocsDeleteBehavior,\n DocsManifest,\n DocsManifestFile,\n DocsManifestSource,\n DocsSyncMode,\n ValidatedDocsManifest,\n ValidatedDocsManifestFile,\n} from './manifest.js'\n\nimport {\n DEFAULT_DOCS_ROUTE_BASE,\n DEFAULT_MAX_DOCS_FILE_BYTES,\n DEFAULT_MAX_DOCS_FILES,\n DEFAULT_MAX_DOCS_TOTAL_BYTES,\n} from '../constants.js'\nimport { validateDocsAiExportManifest } from './aiExportManifest.js'\nimport {\n parseDocsFrontmatter,\n resolveDocsTitle,\n} from './frontmatter.js'\nimport { sha256Hex } from './hash.js'\nimport { deriveRouteFromSourcePath, normalizeDocsPath } from './paths.js'\n\nexport type DocsValidationErrorCode =\n | 'duplicate_existing_path'\n | 'duplicate_path'\n | 'empty_manifest'\n | 'file_too_large'\n | 'invalid_ai_export_manifest'\n | 'invalid_delete_behavior'\n | 'invalid_frontmatter'\n | 'invalid_hash'\n | 'invalid_manifest'\n | 'invalid_mode'\n | 'invalid_path'\n | 'invalid_source'\n | 'invalid_version'\n | 'manifest_too_large'\n | 'missing_ai_export_order_path'\n | 'non_markdown_file'\n | 'path_traversal'\n | 'too_many_files'\n\nexport type DocsValidationIssue = {\n code: DocsValidationErrorCode\n message: string\n path?: string\n}\n\nexport type DocsValidationResult<T = unknown> =\n | {\n data: T\n issues: DocsValidationIssue[]\n ok: true\n warnings: DocsValidationIssue[]\n }\n | {\n issues: DocsValidationIssue[]\n ok: false\n warnings: DocsValidationIssue[]\n }\n\nexport type DocsValidationOptions = {\n allowedSourceIds?: string[]\n maxFileBytes?: number\n maxFiles?: number\n maxTotalBytes?: number\n routeBase?: string\n}\n\nconst syncModes = new Set<DocsSyncMode>(['dry-run', 'sync'])\nconst deleteBehaviors = new Set<DocsDeleteBehavior>([\n 'archive',\n 'delete',\n 'draft',\n 'ignore',\n])\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n\nconst createIssue = ({\n code,\n message,\n path,\n}: DocsValidationIssue): DocsValidationIssue => ({\n code,\n message,\n path,\n})\n\nconst byteLength = (content: string): number => Buffer.byteLength(content, 'utf8')\n\nconst validateSource = ({\n allowedSourceIds,\n source,\n}: {\n allowedSourceIds?: string[]\n source: unknown\n}): {\n issues: DocsValidationIssue[]\n source?: DocsManifestSource\n} => {\n if (!isRecord(source) || typeof source.id !== 'string' || source.id.trim() === '') {\n return {\n issues: [\n createIssue({\n code: 'invalid_source',\n message: 'Manifest source.id is required.',\n }),\n ],\n }\n }\n\n if (allowedSourceIds && !allowedSourceIds.includes(source.id)) {\n return {\n issues: [\n createIssue({\n code: 'invalid_source',\n message: `Manifest source.id \"${source.id}\" is not allowed.`,\n }),\n ],\n }\n }\n\n return {\n issues: [],\n source: {\n id: source.id,\n branch: typeof source.branch === 'string' ? source.branch : undefined,\n commit: typeof source.commit === 'string' ? source.commit : undefined,\n repository: typeof source.repository === 'string' ? source.repository : undefined,\n root: typeof source.root === 'string' ? source.root : undefined,\n },\n }\n}\n\nconst validateMode = (mode: unknown): {\n issues: DocsValidationIssue[]\n mode: DocsSyncMode\n} => {\n if (mode === undefined) {\n return {\n issues: [],\n mode: 'dry-run',\n }\n }\n\n if (syncModes.has(mode as DocsSyncMode)) {\n return {\n issues: [],\n mode: mode as DocsSyncMode,\n }\n }\n\n return {\n issues: [\n createIssue({\n code: 'invalid_mode',\n message: 'Manifest mode must be \"dry-run\" or \"sync\".',\n }),\n ],\n mode: 'dry-run',\n }\n}\n\nconst validateDeleteBehavior = (deleteBehavior: unknown): {\n deleteBehavior: DocsDeleteBehavior\n issues: DocsValidationIssue[]\n} => {\n if (deleteBehavior === undefined) {\n return {\n deleteBehavior: 'archive',\n issues: [],\n }\n }\n\n if (deleteBehaviors.has(deleteBehavior as DocsDeleteBehavior)) {\n return {\n deleteBehavior: deleteBehavior as DocsDeleteBehavior,\n issues: [],\n }\n }\n\n return {\n deleteBehavior: 'archive',\n issues: [\n createIssue({\n code: 'invalid_delete_behavior',\n message: 'Manifest deleteBehavior must be archive, delete, draft, or ignore.',\n }),\n ],\n }\n}\n\nconst validateManifestFile = ({\n file,\n maxFileBytes,\n routeBase,\n}: {\n file: unknown\n maxFileBytes: number\n routeBase: string\n}): {\n fileBytes: number\n issues: DocsValidationIssue[]\n normalizedPath?: string\n validatedFile?: ValidatedDocsManifestFile\n warnings: DocsValidationIssue[]\n} => {\n const issues: DocsValidationIssue[] = []\n const warnings: DocsValidationIssue[] = []\n\n if (!isRecord(file)) {\n return {\n fileBytes: 0,\n issues: [\n createIssue({\n code: 'invalid_manifest',\n message: 'Manifest file entries must be objects.',\n }),\n ],\n warnings,\n }\n }\n\n const path = typeof file.path === 'string' ? file.path : undefined\n const content = typeof file.content === 'string' ? file.content : undefined\n\n if (!path || content === undefined) {\n return {\n fileBytes: 0,\n issues: [\n createIssue({\n code: 'invalid_manifest',\n message: 'Manifest file entries require string path and content.',\n path,\n }),\n ],\n warnings,\n }\n }\n\n const normalizedPath = normalizeDocsPath(path)\n\n if (!normalizedPath.ok) {\n return {\n fileBytes: 0,\n issues: [\n createIssue({\n code: normalizedPath.code,\n message: normalizedPath.message,\n path,\n }),\n ],\n warnings,\n }\n }\n\n const fileBytes = byteLength(content)\n\n if (fileBytes > maxFileBytes) {\n issues.push(\n createIssue({\n code: 'file_too_large',\n message: `File exceeds maximum size of ${maxFileBytes} bytes.`,\n path: normalizedPath.path,\n }),\n )\n }\n\n const computedHash = sha256Hex(content)\n\n if (\n file.sha256 !== undefined &&\n (typeof file.sha256 !== 'string' ||\n !/^[a-f0-9]{64}$/i.test(file.sha256) ||\n file.sha256.toLowerCase() !== computedHash)\n ) {\n issues.push(\n createIssue({\n code: 'invalid_hash',\n message: 'Manifest file sha256 does not match content.',\n path: normalizedPath.path,\n }),\n )\n }\n\n const parsedFrontmatter = parseDocsFrontmatter(content, {\n path: normalizedPath.path,\n })\n\n issues.push(...parsedFrontmatter.issues)\n warnings.push(...parsedFrontmatter.warnings)\n\n const route = deriveRouteFromSourcePath({\n slug: parsedFrontmatter.frontmatter.slug,\n routeBase,\n sourcePath: normalizedPath.path,\n })\n\n return {\n fileBytes,\n issues,\n normalizedPath: normalizedPath.path,\n validatedFile: {\n content: parsedFrontmatter.content,\n frontmatter: parsedFrontmatter.frontmatter,\n path: normalizedPath.path,\n route,\n sha256: computedHash,\n title: resolveDocsTitle({\n content: parsedFrontmatter.content,\n frontmatter: parsedFrontmatter.frontmatter,\n sourcePath: normalizedPath.path,\n }),\n },\n warnings,\n }\n}\n\nexport const validateDocsManifest = (\n manifest: unknown,\n options: DocsValidationOptions = {},\n): DocsValidationResult<ValidatedDocsManifest> => {\n const issues: DocsValidationIssue[] = []\n const warnings: DocsValidationIssue[] = []\n const maxFileBytes = options.maxFileBytes ?? DEFAULT_MAX_DOCS_FILE_BYTES\n const maxFiles = options.maxFiles ?? DEFAULT_MAX_DOCS_FILES\n const maxTotalBytes = options.maxTotalBytes ?? DEFAULT_MAX_DOCS_TOTAL_BYTES\n const routeBase = options.routeBase ?? DEFAULT_DOCS_ROUTE_BASE\n\n if (!isRecord(manifest)) {\n return {\n issues: [\n createIssue({\n code: 'invalid_manifest',\n message: 'Manifest must be an object.',\n }),\n ],\n ok: false,\n warnings,\n }\n }\n\n if (manifest.version !== 1) {\n issues.push(\n createIssue({\n code: 'invalid_version',\n message: 'Manifest version must be 1.',\n }),\n )\n }\n\n const sourceValidation = validateSource({\n allowedSourceIds: options.allowedSourceIds,\n source: manifest.source,\n })\n\n issues.push(...sourceValidation.issues)\n\n const modeValidation = validateMode(manifest.mode)\n issues.push(...modeValidation.issues)\n\n const deleteBehaviorValidation = validateDeleteBehavior(manifest.deleteBehavior)\n issues.push(...deleteBehaviorValidation.issues)\n\n const publish =\n manifest.publish === undefined ? false : manifest.publish === true ? true : false\n\n if (manifest.publish !== undefined && typeof manifest.publish !== 'boolean') {\n issues.push(\n createIssue({\n code: 'invalid_manifest',\n message: 'Manifest publish must be a boolean.',\n }),\n )\n }\n\n const files = Array.isArray(manifest.files) ? manifest.files : undefined\n\n if (!files || files.length === 0) {\n issues.push(\n createIssue({\n code: 'empty_manifest',\n message: 'Manifest must include at least one file.',\n }),\n )\n }\n\n if (files && files.length > maxFiles) {\n issues.push(\n createIssue({\n code: 'too_many_files',\n message: `Manifest exceeds maximum file count of ${maxFiles}.`,\n }),\n )\n }\n\n const validatedFiles: ValidatedDocsManifestFile[] = []\n const normalizedPaths = new Set<string>()\n let totalBytes = 0\n\n for (const file of files ?? []) {\n const fileValidation = validateManifestFile({\n file,\n maxFileBytes,\n routeBase,\n })\n\n totalBytes += fileValidation.fileBytes\n issues.push(...fileValidation.issues)\n warnings.push(...fileValidation.warnings)\n\n if (fileValidation.normalizedPath) {\n if (normalizedPaths.has(fileValidation.normalizedPath)) {\n issues.push(\n createIssue({\n code: 'duplicate_path',\n message: 'Manifest contains duplicate normalized paths.',\n path: fileValidation.normalizedPath,\n }),\n )\n }\n\n normalizedPaths.add(fileValidation.normalizedPath)\n }\n\n if (fileValidation.validatedFile) {\n validatedFiles.push(fileValidation.validatedFile)\n }\n }\n\n if (totalBytes > maxTotalBytes) {\n issues.push(\n createIssue({\n code: 'manifest_too_large',\n message: `Manifest content exceeds maximum total size of ${maxTotalBytes} bytes.`,\n }),\n )\n }\n\n const aiExportValidation =\n manifest.aiExport === undefined\n ? undefined\n : validateDocsAiExportManifest(manifest.aiExport, {\n knownDocsPaths: normalizedPaths,\n })\n\n if (aiExportValidation) {\n issues.push(...aiExportValidation.issues)\n warnings.push(...aiExportValidation.warnings)\n }\n\n if (\n issues.length > 0 ||\n !sourceValidation.source ||\n aiExportValidation?.ok === false\n ) {\n return {\n issues,\n ok: false,\n warnings,\n }\n }\n\n return {\n data: {\n deleteBehavior: deleteBehaviorValidation.deleteBehavior,\n ...(aiExportValidation?.ok ? { aiExport: aiExportValidation.manifest } : {}),\n files: validatedFiles,\n mode: modeValidation.mode,\n publish,\n source: sourceValidation.source,\n version: 1,\n },\n issues,\n ok: true,\n warnings,\n }\n}\n\nexport type { DocsManifest, DocsManifestFile, DocsManifestSource }\n"],"names":["DEFAULT_DOCS_ROUTE_BASE","DEFAULT_MAX_DOCS_FILE_BYTES","DEFAULT_MAX_DOCS_FILES","DEFAULT_MAX_DOCS_TOTAL_BYTES","validateDocsAiExportManifest","parseDocsFrontmatter","resolveDocsTitle","sha256Hex","deriveRouteFromSourcePath","normalizeDocsPath","syncModes","Set","deleteBehaviors","isRecord","value","Array","isArray","createIssue","code","message","path","byteLength","content","Buffer","validateSource","allowedSourceIds","source","id","trim","issues","includes","branch","undefined","commit","repository","root","validateMode","mode","has","validateDeleteBehavior","deleteBehavior","validateManifestFile","file","maxFileBytes","routeBase","warnings","fileBytes","normalizedPath","ok","push","computedHash","sha256","test","toLowerCase","parsedFrontmatter","route","slug","frontmatter","sourcePath","validatedFile","title","validateDocsManifest","manifest","options","maxFiles","maxTotalBytes","version","sourceValidation","modeValidation","deleteBehaviorValidation","publish","files","length","validatedFiles","normalizedPaths","totalBytes","fileValidation","add","aiExportValidation","aiExport","knownDocsPaths","data"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../src/sync/validate.ts"],"sourcesContent":["import type {\n DocsDeleteBehavior,\n DocsManifest,\n DocsManifestFile,\n DocsManifestSource,\n DocsSyncMode,\n ValidatedDocsManifest,\n ValidatedDocsManifestFile,\n} from './manifest.js'\n\nimport {\n DEFAULT_DOCS_ROUTE_BASE,\n DEFAULT_MAX_DOCS_FILE_BYTES,\n DEFAULT_MAX_DOCS_FILES,\n DEFAULT_MAX_DOCS_TOTAL_BYTES,\n} from '../constants.js'\nimport { validateDocsAiExportManifest } from './aiExportManifest.js'\nimport {\n parseDocsFrontmatter,\n resolveDocsTitle,\n} from './frontmatter.js'\nimport { sha256Hex } from './hash.js'\nimport { deriveRouteFromSourcePath, normalizeDocsPath } from './paths.js'\n\nexport type DocsValidationErrorCode =\n | 'duplicate_existing_path'\n | 'duplicate_path'\n | 'empty_manifest'\n | 'file_too_large'\n | 'invalid_ai_export_manifest'\n | 'invalid_delete_behavior'\n | 'invalid_frontmatter'\n | 'invalid_hash'\n | 'invalid_manifest'\n | 'invalid_mode'\n | 'invalid_path'\n | 'invalid_source'\n | 'invalid_version'\n | 'manifest_too_large'\n | 'missing_ai_export_order_path'\n | 'non_markdown_file'\n | 'path_traversal'\n | 'too_many_files'\n\nexport type DocsValidationIssue = {\n code: DocsValidationErrorCode\n message: string\n path?: string\n}\n\nexport type DocsValidationResult<T = unknown> =\n | {\n data: T\n issues: DocsValidationIssue[]\n ok: true\n warnings: DocsValidationIssue[]\n }\n | {\n issues: DocsValidationIssue[]\n ok: false\n warnings: DocsValidationIssue[]\n }\n\nexport type DocsValidationOptions = {\n allowedSourceIds?: string[]\n maxFileBytes?: number\n maxFiles?: number\n maxTotalBytes?: number\n routeBase?: string\n}\n\nconst syncModes = new Set<DocsSyncMode>(['dry-run', 'sync'])\nconst deleteBehaviors = new Set<DocsDeleteBehavior>([\n 'archive',\n 'delete',\n 'draft',\n 'ignore',\n])\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null && !Array.isArray(value)\n\nconst createIssue = ({\n code,\n message,\n path,\n}: DocsValidationIssue): DocsValidationIssue => ({\n code,\n message,\n path,\n})\n\nconst byteLength = (content: string): number => Buffer.byteLength(content, 'utf8')\n\nconst validateSource = ({\n allowedSourceIds,\n source,\n}: {\n allowedSourceIds?: string[]\n source: unknown\n}): {\n issues: DocsValidationIssue[]\n source?: DocsManifestSource\n} => {\n if (!isRecord(source) || typeof source.id !== 'string' || source.id.trim() === '') {\n return {\n issues: [\n createIssue({\n code: 'invalid_source',\n message: 'Manifest source.id is required.',\n }),\n ],\n }\n }\n\n if (allowedSourceIds && !allowedSourceIds.includes(source.id)) {\n return {\n issues: [\n createIssue({\n code: 'invalid_source',\n message: `Manifest source.id \"${source.id}\" is not allowed.`,\n }),\n ],\n }\n }\n\n return {\n issues: [],\n source: {\n id: source.id,\n branch: typeof source.branch === 'string' ? source.branch : undefined,\n commit: typeof source.commit === 'string' ? source.commit : undefined,\n repository: typeof source.repository === 'string' ? source.repository : undefined,\n },\n }\n}\n\nconst validateMode = (mode: unknown): {\n issues: DocsValidationIssue[]\n mode: DocsSyncMode\n} => {\n if (mode === undefined) {\n return {\n issues: [],\n mode: 'dry-run',\n }\n }\n\n if (syncModes.has(mode as DocsSyncMode)) {\n return {\n issues: [],\n mode: mode as DocsSyncMode,\n }\n }\n\n return {\n issues: [\n createIssue({\n code: 'invalid_mode',\n message: 'Manifest mode must be \"dry-run\" or \"sync\".',\n }),\n ],\n mode: 'dry-run',\n }\n}\n\nconst validateDeleteBehavior = (deleteBehavior: unknown): {\n deleteBehavior: DocsDeleteBehavior\n issues: DocsValidationIssue[]\n} => {\n if (deleteBehavior === undefined) {\n return {\n deleteBehavior: 'archive',\n issues: [],\n }\n }\n\n if (deleteBehaviors.has(deleteBehavior as DocsDeleteBehavior)) {\n return {\n deleteBehavior: deleteBehavior as DocsDeleteBehavior,\n issues: [],\n }\n }\n\n return {\n deleteBehavior: 'archive',\n issues: [\n createIssue({\n code: 'invalid_delete_behavior',\n message: 'Manifest deleteBehavior must be archive, delete, draft, or ignore.',\n }),\n ],\n }\n}\n\nconst validateManifestFile = ({\n file,\n maxFileBytes,\n routeBase,\n}: {\n file: unknown\n maxFileBytes: number\n routeBase: string\n}): {\n fileBytes: number\n issues: DocsValidationIssue[]\n normalizedPath?: string\n validatedFile?: ValidatedDocsManifestFile\n warnings: DocsValidationIssue[]\n} => {\n const issues: DocsValidationIssue[] = []\n const warnings: DocsValidationIssue[] = []\n\n if (!isRecord(file)) {\n return {\n fileBytes: 0,\n issues: [\n createIssue({\n code: 'invalid_manifest',\n message: 'Manifest file entries must be objects.',\n }),\n ],\n warnings,\n }\n }\n\n const path = typeof file.path === 'string' ? file.path : undefined\n const content = typeof file.content === 'string' ? file.content : undefined\n\n if (!path || content === undefined) {\n return {\n fileBytes: 0,\n issues: [\n createIssue({\n code: 'invalid_manifest',\n message: 'Manifest file entries require string path and content.',\n path,\n }),\n ],\n warnings,\n }\n }\n\n const normalizedPath = normalizeDocsPath(path)\n\n if (!normalizedPath.ok) {\n return {\n fileBytes: 0,\n issues: [\n createIssue({\n code: normalizedPath.code,\n message: normalizedPath.message,\n path,\n }),\n ],\n warnings,\n }\n }\n\n const fileBytes = byteLength(content)\n\n if (fileBytes > maxFileBytes) {\n issues.push(\n createIssue({\n code: 'file_too_large',\n message: `File exceeds maximum size of ${maxFileBytes} bytes.`,\n path: normalizedPath.path,\n }),\n )\n }\n\n const computedHash = sha256Hex(content)\n\n if (\n file.sha256 !== undefined &&\n (typeof file.sha256 !== 'string' ||\n !/^[a-f0-9]{64}$/i.test(file.sha256) ||\n file.sha256.toLowerCase() !== computedHash)\n ) {\n issues.push(\n createIssue({\n code: 'invalid_hash',\n message: 'Manifest file sha256 does not match content.',\n path: normalizedPath.path,\n }),\n )\n }\n\n const parsedFrontmatter = parseDocsFrontmatter(content, {\n path: normalizedPath.path,\n })\n\n issues.push(...parsedFrontmatter.issues)\n warnings.push(...parsedFrontmatter.warnings)\n\n const route = deriveRouteFromSourcePath({\n slug: parsedFrontmatter.frontmatter.slug,\n routeBase,\n sourcePath: normalizedPath.path,\n })\n\n return {\n fileBytes,\n issues,\n normalizedPath: normalizedPath.path,\n validatedFile: {\n content: parsedFrontmatter.content,\n frontmatter: parsedFrontmatter.frontmatter,\n path: normalizedPath.path,\n route,\n sha256: computedHash,\n title: resolveDocsTitle({\n content: parsedFrontmatter.content,\n frontmatter: parsedFrontmatter.frontmatter,\n sourcePath: normalizedPath.path,\n }),\n },\n warnings,\n }\n}\n\nexport const validateDocsManifest = (\n manifest: unknown,\n options: DocsValidationOptions = {},\n): DocsValidationResult<ValidatedDocsManifest> => {\n const issues: DocsValidationIssue[] = []\n const warnings: DocsValidationIssue[] = []\n const maxFileBytes = options.maxFileBytes ?? DEFAULT_MAX_DOCS_FILE_BYTES\n const maxFiles = options.maxFiles ?? DEFAULT_MAX_DOCS_FILES\n const maxTotalBytes = options.maxTotalBytes ?? DEFAULT_MAX_DOCS_TOTAL_BYTES\n const routeBase = options.routeBase ?? DEFAULT_DOCS_ROUTE_BASE\n\n if (!isRecord(manifest)) {\n return {\n issues: [\n createIssue({\n code: 'invalid_manifest',\n message: 'Manifest must be an object.',\n }),\n ],\n ok: false,\n warnings,\n }\n }\n\n if (manifest.version !== 1) {\n issues.push(\n createIssue({\n code: 'invalid_version',\n message: 'Manifest version must be 1.',\n }),\n )\n }\n\n const sourceValidation = validateSource({\n allowedSourceIds: options.allowedSourceIds,\n source: manifest.source,\n })\n\n issues.push(...sourceValidation.issues)\n\n const modeValidation = validateMode(manifest.mode)\n issues.push(...modeValidation.issues)\n\n const deleteBehaviorValidation = validateDeleteBehavior(manifest.deleteBehavior)\n issues.push(...deleteBehaviorValidation.issues)\n\n const publish =\n manifest.publish === undefined ? false : manifest.publish === true ? true : false\n\n if (manifest.publish !== undefined && typeof manifest.publish !== 'boolean') {\n issues.push(\n createIssue({\n code: 'invalid_manifest',\n message: 'Manifest publish must be a boolean.',\n }),\n )\n }\n\n const files = Array.isArray(manifest.files) ? manifest.files : undefined\n\n if (!files || files.length === 0) {\n issues.push(\n createIssue({\n code: 'empty_manifest',\n message: 'Manifest must include at least one file.',\n }),\n )\n }\n\n if (files && files.length > maxFiles) {\n issues.push(\n createIssue({\n code: 'too_many_files',\n message: `Manifest exceeds maximum file count of ${maxFiles}.`,\n }),\n )\n }\n\n const validatedFiles: ValidatedDocsManifestFile[] = []\n const normalizedPaths = new Set<string>()\n let totalBytes = 0\n\n for (const file of files ?? []) {\n const fileValidation = validateManifestFile({\n file,\n maxFileBytes,\n routeBase,\n })\n\n totalBytes += fileValidation.fileBytes\n issues.push(...fileValidation.issues)\n warnings.push(...fileValidation.warnings)\n\n if (fileValidation.normalizedPath) {\n if (normalizedPaths.has(fileValidation.normalizedPath)) {\n issues.push(\n createIssue({\n code: 'duplicate_path',\n message: 'Manifest contains duplicate normalized paths.',\n path: fileValidation.normalizedPath,\n }),\n )\n }\n\n normalizedPaths.add(fileValidation.normalizedPath)\n }\n\n if (fileValidation.validatedFile) {\n validatedFiles.push(fileValidation.validatedFile)\n }\n }\n\n if (totalBytes > maxTotalBytes) {\n issues.push(\n createIssue({\n code: 'manifest_too_large',\n message: `Manifest content exceeds maximum total size of ${maxTotalBytes} bytes.`,\n }),\n )\n }\n\n const aiExportValidation =\n manifest.aiExport === undefined\n ? undefined\n : validateDocsAiExportManifest(manifest.aiExport, {\n knownDocsPaths: normalizedPaths,\n })\n\n if (aiExportValidation) {\n issues.push(...aiExportValidation.issues)\n warnings.push(...aiExportValidation.warnings)\n }\n\n if (\n issues.length > 0 ||\n !sourceValidation.source ||\n aiExportValidation?.ok === false\n ) {\n return {\n issues,\n ok: false,\n warnings,\n }\n }\n\n return {\n data: {\n deleteBehavior: deleteBehaviorValidation.deleteBehavior,\n ...(aiExportValidation?.ok ? { aiExport: aiExportValidation.manifest } : {}),\n files: validatedFiles,\n mode: modeValidation.mode,\n publish,\n source: sourceValidation.source,\n version: 1,\n },\n issues,\n ok: true,\n warnings,\n }\n}\n\nexport type { DocsManifest, DocsManifestFile, DocsManifestSource }\n"],"names":["DEFAULT_DOCS_ROUTE_BASE","DEFAULT_MAX_DOCS_FILE_BYTES","DEFAULT_MAX_DOCS_FILES","DEFAULT_MAX_DOCS_TOTAL_BYTES","validateDocsAiExportManifest","parseDocsFrontmatter","resolveDocsTitle","sha256Hex","deriveRouteFromSourcePath","normalizeDocsPath","syncModes","Set","deleteBehaviors","isRecord","value","Array","isArray","createIssue","code","message","path","byteLength","content","Buffer","validateSource","allowedSourceIds","source","id","trim","issues","includes","branch","undefined","commit","repository","validateMode","mode","has","validateDeleteBehavior","deleteBehavior","validateManifestFile","file","maxFileBytes","routeBase","warnings","fileBytes","normalizedPath","ok","push","computedHash","sha256","test","toLowerCase","parsedFrontmatter","route","slug","frontmatter","sourcePath","validatedFile","title","validateDocsManifest","manifest","options","maxFiles","maxTotalBytes","version","sourceValidation","modeValidation","deleteBehaviorValidation","publish","files","length","validatedFiles","normalizedPaths","totalBytes","fileValidation","add","aiExportValidation","aiExport","knownDocsPaths","data"],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -4,7 +4,6 @@ export type PayloadMarkdownDocsConfig = {
|
|
|
4
4
|
enabled?: boolean;
|
|
5
5
|
endpoint?: PayloadMarkdownDocsEndpointConfig;
|
|
6
6
|
routing?: PayloadMarkdownDocsRoutingConfig;
|
|
7
|
-
sources?: PayloadMarkdownDocsSourceConfig[];
|
|
8
7
|
sync?: PayloadMarkdownDocsSyncConfig;
|
|
9
8
|
target?: PayloadMarkdownDocsTargetConfig;
|
|
10
9
|
};
|
|
@@ -13,47 +12,13 @@ export type PayloadMarkdownDocsEndpointConfig = {
|
|
|
13
12
|
path?: string;
|
|
14
13
|
};
|
|
15
14
|
export type PayloadMarkdownDocsAuthConfig = {
|
|
15
|
+
ed25519?: boolean | PayloadMarkdownDocsAuthToggle;
|
|
16
|
+
githubOidc?: boolean | PayloadMarkdownDocsAuthToggle;
|
|
17
|
+
} | {
|
|
16
18
|
mode: 'disabled';
|
|
17
|
-
} | PayloadMarkdownDocsCombinedAuthConfig | PayloadMarkdownDocsEd25519AuthConfig | PayloadMarkdownDocsGitHubOidcAuthConfig;
|
|
18
|
-
export type PayloadMarkdownDocsCombinedAuthConfig = {
|
|
19
|
-
ed25519?: PayloadMarkdownDocsEd25519AuthOptions;
|
|
20
|
-
githubOidc?: PayloadMarkdownDocsGitHubOidcAuthOptions;
|
|
21
|
-
mode?: 'multi';
|
|
22
|
-
};
|
|
23
|
-
export type PayloadMarkdownDocsDocsSetAuthConfig = {
|
|
24
|
-
ed25519?: PayloadMarkdownDocsEd25519AuthOptions;
|
|
25
|
-
githubOidc?: PayloadMarkdownDocsDocsSetGitHubOidcAuthOptions;
|
|
26
19
|
};
|
|
27
|
-
export type
|
|
20
|
+
export type PayloadMarkdownDocsAuthToggle = {
|
|
28
21
|
enabled?: boolean;
|
|
29
|
-
} & Partial<PayloadMarkdownDocsGitHubOidcAuthOptions>;
|
|
30
|
-
export type PayloadMarkdownDocsEd25519AuthConfig = {
|
|
31
|
-
mode: 'ed25519';
|
|
32
|
-
} & PayloadMarkdownDocsEd25519AuthOptions;
|
|
33
|
-
export type PayloadMarkdownDocsEd25519AuthOptions = {
|
|
34
|
-
keys: PayloadMarkdownDocsEd25519Key[];
|
|
35
|
-
maxSkewSeconds?: number;
|
|
36
|
-
nonceTtlSeconds?: number;
|
|
37
|
-
};
|
|
38
|
-
export type PayloadMarkdownDocsEd25519Key = {
|
|
39
|
-
id: string;
|
|
40
|
-
publicKey: string;
|
|
41
|
-
};
|
|
42
|
-
export type PayloadMarkdownDocsGitHubOidcAuthConfig = {
|
|
43
|
-
mode: 'github-oidc';
|
|
44
|
-
} & PayloadMarkdownDocsGitHubOidcAuthOptions;
|
|
45
|
-
export type PayloadMarkdownDocsGitHubOidcAuthOptions = {
|
|
46
|
-
allowedEnvironments?: string[];
|
|
47
|
-
allowedRefs?: string[];
|
|
48
|
-
allowedRepositories?: string[];
|
|
49
|
-
allowedRepositoryOwners?: string[];
|
|
50
|
-
allowedWorkflowRefs?: string[];
|
|
51
|
-
allowedWorkflows?: string[];
|
|
52
|
-
allowPullRequests?: boolean;
|
|
53
|
-
audience: string;
|
|
54
|
-
issuer?: string;
|
|
55
|
-
jwksUrl?: string;
|
|
56
|
-
maxSkewSeconds?: number;
|
|
57
22
|
};
|
|
58
23
|
export type PayloadMarkdownDocsCollectionConfig = {
|
|
59
24
|
enabled?: boolean;
|
|
@@ -62,7 +27,9 @@ export type PayloadMarkdownDocsCollectionConfig = {
|
|
|
62
27
|
export type PayloadMarkdownDocsCollectionsConfig = {
|
|
63
28
|
docs?: PayloadMarkdownDocsCollectionConfig;
|
|
64
29
|
docsGroups?: PayloadMarkdownDocsCollectionConfig;
|
|
30
|
+
docsKeys?: PayloadMarkdownDocsCollectionConfig;
|
|
65
31
|
docsSets?: PayloadMarkdownDocsCollectionConfig;
|
|
32
|
+
docsTrusted?: PayloadMarkdownDocsCollectionConfig;
|
|
66
33
|
nonces?: PayloadMarkdownDocsCollectionConfig;
|
|
67
34
|
syncRuns?: PayloadMarkdownDocsCollectionConfig;
|
|
68
35
|
};
|
|
@@ -76,21 +43,11 @@ export type PayloadMarkdownDocsPagesRoutingConfig = {
|
|
|
76
43
|
export type PayloadMarkdownDocsRoutingConfig = {
|
|
77
44
|
pages?: PayloadMarkdownDocsPagesRoutingConfig;
|
|
78
45
|
};
|
|
79
|
-
export type PayloadMarkdownDocsSourceConfig = {
|
|
80
|
-
id: string;
|
|
81
|
-
root?: string;
|
|
82
|
-
routeBase: string;
|
|
83
|
-
};
|
|
84
46
|
export type PayloadMarkdownDocsTargetConfig = {
|
|
85
|
-
collection: string;
|
|
86
|
-
markdownField: string;
|
|
87
|
-
routeField?: string;
|
|
88
|
-
type: 'existingCollection';
|
|
89
|
-
} | {
|
|
90
47
|
enableDrafts?: boolean;
|
|
91
48
|
markdownField?: string;
|
|
92
49
|
slug?: string;
|
|
93
|
-
type
|
|
50
|
+
type?: 'docsCollection';
|
|
94
51
|
};
|
|
95
52
|
export type PayloadMarkdownDocsSyncConfig = {
|
|
96
53
|
allowHardDelete?: boolean;
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["export type PayloadMarkdownDocsConfig = {\n auth?: PayloadMarkdownDocsAuthConfig\n collections?: PayloadMarkdownDocsCollectionsConfig\n enabled?: boolean\n endpoint?: PayloadMarkdownDocsEndpointConfig\n routing?: PayloadMarkdownDocsRoutingConfig\n
|
|
1
|
+
{"version":3,"sources":["../src/types.ts"],"sourcesContent":["export type PayloadMarkdownDocsConfig = {\n auth?: PayloadMarkdownDocsAuthConfig\n collections?: PayloadMarkdownDocsCollectionsConfig\n enabled?: boolean\n endpoint?: PayloadMarkdownDocsEndpointConfig\n routing?: PayloadMarkdownDocsRoutingConfig\n sync?: PayloadMarkdownDocsSyncConfig\n target?: PayloadMarkdownDocsTargetConfig\n}\n\nexport type PayloadMarkdownDocsEndpointConfig = {\n maxBodyBytes?: number\n path?: string\n}\n\nexport type PayloadMarkdownDocsAuthConfig =\n | {\n ed25519?: boolean | PayloadMarkdownDocsAuthToggle\n githubOidc?: boolean | PayloadMarkdownDocsAuthToggle\n }\n | {\n mode: 'disabled'\n }\n\nexport type PayloadMarkdownDocsAuthToggle = {\n enabled?: boolean\n}\n\nexport type PayloadMarkdownDocsCollectionConfig = {\n enabled?: boolean\n slug?: string\n}\n\nexport type PayloadMarkdownDocsCollectionsConfig = {\n docs?: PayloadMarkdownDocsCollectionConfig\n docsGroups?: PayloadMarkdownDocsCollectionConfig\n docsKeys?: PayloadMarkdownDocsCollectionConfig\n docsSets?: PayloadMarkdownDocsCollectionConfig\n docsTrusted?: PayloadMarkdownDocsCollectionConfig\n nonces?: PayloadMarkdownDocsCollectionConfig\n syncRuns?: PayloadMarkdownDocsCollectionConfig\n}\n\nexport type PayloadMarkdownDocsPagesRoutingConfig = {\n allowBridgePages?: boolean\n bridgeField?: string\n collection?: string\n enabled?: boolean\n routeField?: string\n}\n\nexport type PayloadMarkdownDocsRoutingConfig = {\n pages?: PayloadMarkdownDocsPagesRoutingConfig\n}\n\nexport type PayloadMarkdownDocsTargetConfig =\n {\n enableDrafts?: boolean\n markdownField?: string\n slug?: string\n type?: 'docsCollection'\n }\n\nexport type PayloadMarkdownDocsSyncConfig = {\n allowHardDelete?: boolean\n allowPublish?: boolean\n allowWrites?: boolean\n defaultPublishMode?: 'draft' | 'preserve' | 'published'\n deleteBehavior?: 'archive' | 'delete' | 'draft' | 'ignore'\n requireDryRunBeforeApply?: boolean\n}\n"],"names":[],"mappings":"AA+DA,WAOC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@valkyrianlabs/payload-markdown-docs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.1",
|
|
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,14 +45,16 @@
|
|
|
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",
|
|
51
|
-
"dev:docs:manifest": "node --import @swc-node/register/esm-register ./src/cli/index.ts manifest ./dev/docs-fixtures/basic --source payload-markdown-docs --
|
|
52
|
-
"dev:docs:plan": "node --import @swc-node/register/esm-register ./src/cli/index.ts plan ./dev/docs-fixtures/basic --source payload-markdown-docs
|
|
53
|
+
"dev:docs:manifest": "node --import @swc-node/register/esm-register ./src/cli/index.ts manifest ./dev/docs-fixtures/basic --source payload-markdown-docs --pretty",
|
|
54
|
+
"dev:docs:plan": "node --import @swc-node/register/esm-register ./src/cli/index.ts plan ./dev/docs-fixtures/basic --source payload-markdown-docs",
|
|
53
55
|
"dev:docs:reset": "pnpm dev:payload run ./dev/scripts/reset-docs.ts",
|
|
54
56
|
"dev:docs:seed": "pnpm dev:payload run ./dev/scripts/seed-docs.ts",
|
|
55
|
-
"dev:docs:validate": "node --import @swc-node/register/esm-register ./src/cli/index.ts validate ./dev/docs-fixtures/basic --source payload-markdown-docs
|
|
57
|
+
"dev:docs:validate": "node --import @swc-node/register/esm-register ./src/cli/index.ts validate ./dev/docs-fixtures/basic --source payload-markdown-docs",
|
|
56
58
|
"dev:generate-importmap": "pnpm dev:payload generate:importmap",
|
|
57
59
|
"dev:generate-types": "pnpm dev:payload generate:types",
|
|
58
60
|
"dev:payload": "cross-env PAYLOAD_CONFIG_PATH=./dev/payload.config.ts payload",
|