canopycms 0.0.62 → 0.0.63

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/dist/ai/index.d.ts +9 -0
  2. package/dist/ai/index.d.ts.map +1 -1
  3. package/dist/ai/index.js +9 -0
  4. package/dist/ai/index.js.map +1 -1
  5. package/dist/ai/to-plain-text.d.ts +57 -0
  6. package/dist/ai/to-plain-text.d.ts.map +1 -0
  7. package/dist/ai/to-plain-text.js +255 -0
  8. package/dist/ai/to-plain-text.js.map +1 -0
  9. package/dist/ai/transform-components.d.ts.map +1 -1
  10. package/dist/ai/transform-components.js +70 -5
  11. package/dist/ai/transform-components.js.map +1 -1
  12. package/dist/api/comments.d.ts +2 -2
  13. package/dist/authorization/branch.d.ts +55 -3
  14. package/dist/authorization/branch.d.ts.map +1 -1
  15. package/dist/authorization/branch.js +55 -9
  16. package/dist/authorization/branch.js.map +1 -1
  17. package/dist/authorization/types.d.ts +1 -1
  18. package/dist/authorization/types.d.ts.map +1 -1
  19. package/dist/build-canopy.d.ts +49 -0
  20. package/dist/build-canopy.d.ts.map +1 -0
  21. package/dist/build-canopy.js +51 -0
  22. package/dist/build-canopy.js.map +1 -0
  23. package/dist/cli/cli.js +78 -26
  24. package/dist/cli/generate-ai-content.js +77 -25
  25. package/dist/cli/template-files/canopycms.config.ts.template +18 -1
  26. package/dist/content-listing.d.ts +110 -5
  27. package/dist/content-listing.d.ts.map +1 -1
  28. package/dist/content-listing.js +164 -23
  29. package/dist/content-listing.js.map +1 -1
  30. package/dist/content-reader.d.ts +41 -4
  31. package/dist/content-reader.d.ts.map +1 -1
  32. package/dist/content-reader.js +17 -4
  33. package/dist/content-reader.js.map +1 -1
  34. package/dist/content-store.d.ts +10 -1
  35. package/dist/content-store.d.ts.map +1 -1
  36. package/dist/content-store.js.map +1 -1
  37. package/dist/content-tree.d.ts +31 -2
  38. package/dist/content-tree.d.ts.map +1 -1
  39. package/dist/content-tree.js +22 -5
  40. package/dist/content-tree.js.map +1 -1
  41. package/dist/context.d.ts +30 -10
  42. package/dist/context.d.ts.map +1 -1
  43. package/dist/context.js +55 -4
  44. package/dist/context.js.map +1 -1
  45. package/dist/entry-schema.d.ts +228 -8
  46. package/dist/entry-schema.d.ts.map +1 -1
  47. package/dist/entry-schema.js +124 -0
  48. package/dist/entry-schema.js.map +1 -1
  49. package/dist/index.d.ts +1 -0
  50. package/dist/index.d.ts.map +1 -1
  51. package/dist/index.js +7 -0
  52. package/dist/index.js.map +1 -1
  53. package/dist/server.d.ts +51 -0
  54. package/dist/server.d.ts.map +1 -1
  55. package/dist/server.js +49 -0
  56. package/dist/server.js.map +1 -1
  57. package/dist/services.d.ts +1 -2
  58. package/dist/services.d.ts.map +1 -1
  59. package/dist/services.js +2 -6
  60. package/dist/services.js.map +1 -1
  61. package/dist/static/index.d.ts +65 -5
  62. package/dist/static/index.d.ts.map +1 -1
  63. package/dist/static/index.js +65 -12
  64. package/dist/static/index.js.map +1 -1
  65. package/dist/static/seo.d.ts +150 -0
  66. package/dist/static/seo.d.ts.map +1 -0
  67. package/dist/static/seo.js +189 -0
  68. package/dist/static/seo.js.map +1 -0
  69. package/dist/utils/sanitize-href.d.ts +46 -0
  70. package/dist/utils/sanitize-href.d.ts.map +1 -1
  71. package/dist/utils/sanitize-href.js +63 -2
  72. package/dist/utils/sanitize-href.js.map +1 -1
  73. package/package.json +1 -1
@@ -7,6 +7,15 @@
7
7
  export { defineAIContentConfig } from './types';
8
8
  export { createAIContentHandler } from './handler';
9
9
  export { generateAIContent } from './generate';
10
+ /**
11
+ * Convert MDX/Markdown body content to plain prose text (for a search index
12
+ * or any other "just the words" consumer). Distinct from the AI-content
13
+ * pipeline above: this strips markup down to human-readable text rather
14
+ * than preparing MDX for model consumption. See the source JSDoc for the
15
+ * full pipeline and why paired custom components keep their inner text
16
+ * while losing their tags.
17
+ */
18
+ export { toPlainText } from './to-plain-text';
10
19
  export type { AIContentConfig, ExcludeConfig, BundleConfig, BundleFilter, FieldTransformFn, FieldTransforms, ComponentProps, ComponentTransformFn, ComponentTransforms, BodyTransformFn, BodyTransforms, EntryTransformFn, EntryTransforms, EntryTransformContext, AIManifest, AIManifestCollection, AIManifestEntry, AIManifestBundle, AIEntry, AIEntryMeta, } from './types';
11
20
  export type { AIContentHandlerOptions } from './handler';
12
21
  export type { GenerateOptions, GenerateResult } from './generate';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ai/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAA;AAC/C,OAAO,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAA;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAC9C,YAAY,EACV,eAAe,EACf,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,gBAAgB,EAChB,eAAe,EACf,cAAc,EACd,oBAAoB,EACpB,mBAAmB,EACnB,eAAe,EACf,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,qBAAqB,EACrB,UAAU,EACV,oBAAoB,EACpB,eAAe,EACf,gBAAgB,EAChB,OAAO,EACP,WAAW,GACZ,MAAM,SAAS,CAAA;AAChB,YAAY,EAAE,uBAAuB,EAAE,MAAM,WAAW,CAAA;AACxD,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ai/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAA;AAC/C,OAAO,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAA;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAC9C;;;;;;;GAOG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA;AAC7C,YAAY,EACV,eAAe,EACf,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,gBAAgB,EAChB,eAAe,EACf,cAAc,EACd,oBAAoB,EACpB,mBAAmB,EACnB,eAAe,EACf,cAAc,EACd,gBAAgB,EAChB,eAAe,EACf,qBAAqB,EACrB,UAAU,EACV,oBAAoB,EACpB,eAAe,EACf,gBAAgB,EAChB,OAAO,EACP,WAAW,GACZ,MAAM,SAAS,CAAA;AAChB,YAAY,EAAE,uBAAuB,EAAE,MAAM,WAAW,CAAA;AACxD,YAAY,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA"}
package/dist/ai/index.js CHANGED
@@ -7,4 +7,13 @@
7
7
  export { defineAIContentConfig } from './types.js';
8
8
  export { createAIContentHandler } from './handler.js';
9
9
  export { generateAIContent } from './generate.js';
10
+ /**
11
+ * Convert MDX/Markdown body content to plain prose text (for a search index
12
+ * or any other "just the words" consumer). Distinct from the AI-content
13
+ * pipeline above: this strips markup down to human-readable text rather
14
+ * than preparing MDX for model consumption. See the source JSDoc for the
15
+ * full pipeline and why paired custom components keep their inner text
16
+ * while losing their tags.
17
+ */
18
+ export { toPlainText } from './to-plain-text.js';
10
19
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ai/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAA;AAC/C,OAAO,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAA;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ai/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAA;AAC/C,OAAO,EAAE,sBAAsB,EAAE,MAAM,WAAW,CAAA;AAClD,OAAO,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAA;AAC9C;;;;;;;GAOG;AACH,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAA"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Convert MDX/Markdown body content to plain prose text, suitable for a
3
+ * search index or any other consumer that wants "just the words".
4
+ *
5
+ * This is deliberately a *different* transform from `stripMdxImports`
6
+ * (strip-mdx.ts): that one is tuned for AI/RAG consumption and intentionally
7
+ * leaves JSX components intact, because their props often carry semantic
8
+ * data a model can use. `toPlainText` has the opposite goal — it removes ALL
9
+ * markup (JSX tags, JSX expressions, markdown syntax) and keeps only the
10
+ * prose, so **paired custom components lose their tags but keep their
11
+ * children's text**. That distinction is the whole reason this function
12
+ * exists: a hand-rolled plaintext stripper that treats a paired component
13
+ * like `<Callout>...</Callout>` as one opaque unit and deletes it wholesale
14
+ * silently drops every word inside it from the search index. `toPlainText`
15
+ * strips the `<Callout>`/`</Callout>` delimiters but keeps the sentence
16
+ * between them.
17
+ *
18
+ * Pipeline (each step operates on the previous step's output):
19
+ * 1. Strip YAML frontmatter (via `gray-matter`, the same parser
20
+ * `content-store.ts` uses for `.md`/`.mdx` bodies).
21
+ * 2. Strip `import`/`export` statements (via `stripMdxImports`), which also
22
+ * protects fenced code blocks from every later step.
23
+ * 3. Mask fenced code blocks and inline code spans, capturing their content
24
+ * (fence markers / backticks are discarded, the code text is kept).
25
+ * 4. Strip JSX/HTML tags — opening, closing, and self-closing — leaving
26
+ * whatever text sits between them in place. This is a single global
27
+ * replace, not a matched-pair walk: because we never need the tag name or
28
+ * the children as a unit (unlike `applyComponentTransforms`, which calls
29
+ * an adopter transform per component), deleting every tag occurrence and
30
+ * leaving the surrounding text untouched handles nesting for free.
31
+ * 5. Strip JSX expressions (`{...}`, including nested braces) — these are
32
+ * code, not prose.
33
+ * 6. Strip common Markdown syntax: headings, emphasis/strikethrough, links
34
+ * (keep the link text, drop the URL), images (keep alt text), blockquote
35
+ * markers, list markers, and thematic breaks.
36
+ * 7. Restore the masked code from step 3 as plain text.
37
+ * 8. Collapse whitespace: trim each line, collapse runs of blank lines,
38
+ * trim the result. Paragraph breaks (single blank lines) are preserved —
39
+ * this does not flatten the output to one line.
40
+ */
41
+ /**
42
+ * Convert MDX/Markdown body content to plain prose text.
43
+ *
44
+ * See the module doc above for the full pipeline and why this exists as a
45
+ * distinct transform from `stripMdxImports`. In short: frontmatter, code
46
+ * fences, inline code, JSX tags/expressions, and Markdown syntax are all
47
+ * stripped down to their human-readable text — code content and link/image
48
+ * text are kept, everything else is discarded. Paired custom components
49
+ * lose only their tags; the prose between them survives.
50
+ *
51
+ * Output preserves paragraph breaks (blank lines) but is not further
52
+ * chunked, weighted, or field-selected — composing that into a search
53
+ * document is left to the caller, since that logic is where adopter search
54
+ * indexes genuinely diverge (see docs/adopter-migration.md).
55
+ */
56
+ export declare function toPlainText(markdown: string): string;
57
+ //# sourceMappingURL=to-plain-text.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"to-plain-text.d.ts","sourceRoot":"","sources":["../../src/ai/to-plain-text.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAkNH;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAapD"}
@@ -0,0 +1,255 @@
1
+ /**
2
+ * Convert MDX/Markdown body content to plain prose text, suitable for a
3
+ * search index or any other consumer that wants "just the words".
4
+ *
5
+ * This is deliberately a *different* transform from `stripMdxImports`
6
+ * (strip-mdx.ts): that one is tuned for AI/RAG consumption and intentionally
7
+ * leaves JSX components intact, because their props often carry semantic
8
+ * data a model can use. `toPlainText` has the opposite goal — it removes ALL
9
+ * markup (JSX tags, JSX expressions, markdown syntax) and keeps only the
10
+ * prose, so **paired custom components lose their tags but keep their
11
+ * children's text**. That distinction is the whole reason this function
12
+ * exists: a hand-rolled plaintext stripper that treats a paired component
13
+ * like `<Callout>...</Callout>` as one opaque unit and deletes it wholesale
14
+ * silently drops every word inside it from the search index. `toPlainText`
15
+ * strips the `<Callout>`/`</Callout>` delimiters but keeps the sentence
16
+ * between them.
17
+ *
18
+ * Pipeline (each step operates on the previous step's output):
19
+ * 1. Strip YAML frontmatter (via `gray-matter`, the same parser
20
+ * `content-store.ts` uses for `.md`/`.mdx` bodies).
21
+ * 2. Strip `import`/`export` statements (via `stripMdxImports`), which also
22
+ * protects fenced code blocks from every later step.
23
+ * 3. Mask fenced code blocks and inline code spans, capturing their content
24
+ * (fence markers / backticks are discarded, the code text is kept).
25
+ * 4. Strip JSX/HTML tags — opening, closing, and self-closing — leaving
26
+ * whatever text sits between them in place. This is a single global
27
+ * replace, not a matched-pair walk: because we never need the tag name or
28
+ * the children as a unit (unlike `applyComponentTransforms`, which calls
29
+ * an adopter transform per component), deleting every tag occurrence and
30
+ * leaving the surrounding text untouched handles nesting for free.
31
+ * 5. Strip JSX expressions (`{...}`, including nested braces) — these are
32
+ * code, not prose.
33
+ * 6. Strip common Markdown syntax: headings, emphasis/strikethrough, links
34
+ * (keep the link text, drop the URL), images (keep alt text), blockquote
35
+ * markers, list markers, and thematic breaks.
36
+ * 7. Restore the masked code from step 3 as plain text.
37
+ * 8. Collapse whitespace: trim each line, collapse runs of blank lines,
38
+ * trim the result. Paragraph breaks (single blank lines) are preserved —
39
+ * this does not flatten the output to one line.
40
+ */
41
+ import matter from 'gray-matter';
42
+ import { stripMdxImports } from './strip-mdx.js';
43
+ /**
44
+ * Masking markers use `@` right after `<` (and before the closing `>`),
45
+ * e.g. `<@B0@>`. `@` is not a valid JSX tag-name start (`[A-Za-z]` only), so
46
+ * TAG_RE below can never mistake the marker for a real tag — unlike
47
+ * transform-components.ts's `<<CODEBLOCK0>>` convention, which is safe
48
+ * there only because that module never runs a *generic* tag-stripping regex
49
+ * over its masked text (this one does: `<CODEBLOCK0>` inside `<<...>>`
50
+ * reads as a valid tag name to a naive tag matcher, which is exactly the
51
+ * bug this format avoids). `@` also doesn't participate in any of the
52
+ * Markdown-syntax regexes below, so a marker surviving to that stage is
53
+ * inert there too.
54
+ */
55
+ const BLOCK_PREFIX = '<@B';
56
+ const BLOCK_SUFFIX = '@>';
57
+ const BLOCK_RESTORE_RE = /<@B(\d+)@>/g;
58
+ const INLINE_PREFIX = '<@I';
59
+ const INLINE_SUFFIX = '@>';
60
+ const INLINE_RESTORE_RE = /<@I(\d+)@>/g;
61
+ /** JSX attribute content: skips quoted strings so a `>` inside `title="a > b"` doesn't end the tag early. */
62
+ const ATTR_CONTENT = `(?:[^<>"']|"[^"]*"|'[^']*')*`;
63
+ /**
64
+ * Matches an opening, closing, or self-closing JSX/HTML tag, or a fragment (`<>`/`</>`).
65
+ *
66
+ * No trailing `\s*` before the final `\/?>`: `ATTR_CONTENT`'s `[^<>"']` alternative already
67
+ * matches whitespace, so a trailing `\s*` on top of it lets the engine split any whitespace run
68
+ * between the two in every possible proportion. On an unterminated tag (no closing `>` in the
69
+ * input) followed by a long whitespace run, that ambiguity is polynomial-ReDoS shaped (CodeQL
70
+ * `js/polynomial-redos`): matching cost is quadratic in the run length before the engine gives up
71
+ * and backtracks to try the next start position. Measured on a 128 KB whitespace tail: ~26s with
72
+ * the redundant `\s*`, ~1ms without it. `ATTR_CONTENT` already absorbs the trailing whitespace on
73
+ * its own, so removing the `\s*` changes no matched output.
74
+ */
75
+ const TAG_RE = new RegExp(`<\\/?([A-Za-z][\\w.-]*)?(?:\\s${ATTR_CONTENT})?\\/?>`, 'g');
76
+ /** True if `line` is a valid closing fence line for `marker` ("```" or "~~~"): the marker
77
+ * followed by nothing but whitespace through end of line — matching what `\1\s*$` required in
78
+ * the regex this replaced. */
79
+ function isFenceCloseLine(line, marker) {
80
+ return line.startsWith(marker) && /^\s*$/.test(line.slice(marker.length));
81
+ }
82
+ /**
83
+ * Mask fenced code blocks (` ``` `/`~~~`), capturing each block's *content* so `restore`
84
+ * re-inserts plain text — no fence markers, no language tag.
85
+ *
86
+ * A hand-rolled line scan, not `/^(```|~~~).*\n([\s\S]*?)\n\1\s*$/gm`: that regex is a second
87
+ * polynomial-ReDoS shape (measured ~9s on ~530KB of body text with many unclosed fence openers,
88
+ * a plausible authoring accident — the same trigger class as `TAG_RE` above, in the same
89
+ * function). The lazy `[\s\S]*?` has no bound on how far it must scan looking for a closing
90
+ * `\1` that, for an unclosed fence, never arrives — it exhausts to the end of the string before
91
+ * giving up on that starting line, and `/gm` retries the same exhaustive scan at every
92
+ * subsequent fence-opener line, which is quadratic in the number of unclosed openers.
93
+ *
94
+ * This scans each line once. `nextCloseLine` is precomputed per marker type via a single
95
+ * backward pass, so any opener's nearest closer (or "none exists") is an O(1) lookup rather than
96
+ * a fresh forward scan — the change that makes the whole function O(n) regardless of how many
97
+ * fences are opened and never closed.
98
+ */
99
+ function maskFencedCodeBlocks(body, blocks) {
100
+ const lines = body.split('\n');
101
+ const lineCount = lines.length;
102
+ // nextCloseLine[marker][i] = the nearest index >= i that closes `marker`, or -1 if none exists
103
+ // at or after i. Built right-to-left so each entry is O(1) given the next one.
104
+ const nextCloseLine = {
105
+ '```': new Array(lineCount + 1).fill(-1),
106
+ '~~~': new Array(lineCount + 1).fill(-1),
107
+ };
108
+ for (let i = lineCount - 1; i >= 0; i--) {
109
+ nextCloseLine['```'][i] = isFenceCloseLine(lines[i], '```') ? i : nextCloseLine['```'][i + 1];
110
+ nextCloseLine['~~~'][i] = isFenceCloseLine(lines[i], '~~~') ? i : nextCloseLine['~~~'][i + 1];
111
+ }
112
+ const outLines = [];
113
+ let i = 0;
114
+ while (i < lineCount) {
115
+ const line = lines[i];
116
+ const marker = line.startsWith('```') ? '```' : line.startsWith('~~~') ? '~~~' : null;
117
+ // A closer can never be the very next line: the original pattern requires TWO separate `\n`
118
+ // matches between the opener and `\1` (one ending the opener's line, one immediately before
119
+ // the closer), so even zero-width content needs a line of its own between them.
120
+ const searchFrom = i + 2;
121
+ const closeIndex = marker && searchFrom < lineCount ? nextCloseLine[marker][searchFrom] : -1;
122
+ if (!marker || closeIndex === -1) {
123
+ outLines.push(line);
124
+ i++;
125
+ continue;
126
+ }
127
+ const content = lines.slice(i + 1, closeIndex).join('\n');
128
+ const idx = blocks.length;
129
+ blocks.push(content);
130
+ // Matches the replaced regex's `\n${...}\n` callback wrapping: the placeholder becomes its
131
+ // own blank-line-delimited chunk. (Any resulting difference in surrounding blank-line COUNT
132
+ // is immaterial -- collapseWhitespace normalizes runs of 3+ newlines down to one blank line
133
+ // before this ever reaches a caller.)
134
+ outLines.push('', `${BLOCK_PREFIX}${idx}${BLOCK_SUFFIX}`, '');
135
+ i = closeIndex + 1;
136
+ }
137
+ return outLines.join('\n');
138
+ }
139
+ /**
140
+ * Mask fenced code blocks and inline code spans, capturing their *content*
141
+ * (not the raw fenced/backticked text) so `restore` re-inserts plain text —
142
+ * no fence markers, no language tag, no backticks.
143
+ */
144
+ function maskCode(body) {
145
+ const blocks = [];
146
+ const inlines = [];
147
+ let masked = maskFencedCodeBlocks(body, blocks);
148
+ masked = masked.replace(/``(.+?)``|`([^`]+)`/g, (_match, double, single) => {
149
+ const idx = inlines.length;
150
+ inlines.push((double ?? single ?? '').trim());
151
+ return `${INLINE_PREFIX}${idx}${INLINE_SUFFIX}`;
152
+ });
153
+ return {
154
+ masked,
155
+ restore: (s) => {
156
+ s = s.replace(INLINE_RESTORE_RE, (_match, i) => inlines[Number(i)]);
157
+ s = s.replace(BLOCK_RESTORE_RE, (_match, i) => blocks[Number(i)]);
158
+ return s;
159
+ },
160
+ };
161
+ }
162
+ /**
163
+ * Remove balanced `{...}` groups (JSX expressions), including nested braces,
164
+ * in a single pass. Each removed top-level group collapses to one space so
165
+ * surrounding words don't merge.
166
+ */
167
+ function stripBraceExpressions(text) {
168
+ let result = '';
169
+ let depth = 0;
170
+ for (const ch of text) {
171
+ if (ch === '{') {
172
+ if (depth === 0)
173
+ result += ' ';
174
+ depth++;
175
+ continue;
176
+ }
177
+ if (ch === '}') {
178
+ if (depth > 0)
179
+ depth--;
180
+ continue;
181
+ }
182
+ if (depth === 0)
183
+ result += ch;
184
+ }
185
+ return result;
186
+ }
187
+ /** Strip common Markdown syntax, keeping the human-readable text. */
188
+ function stripMarkdownSyntax(text) {
189
+ return (text
190
+ // Headings: leading `#` markers
191
+ .replace(/^ {0,3}#{1,6}\s+/gm, '')
192
+ // Blockquotes: leading `>` markers (possibly nested). Each repetition
193
+ // of the outer `+` consumes a mandatory `>` first, so it can't loop on
194
+ // an empty match — linear, despite the nested-quantifier shape the
195
+ // linter's heuristic flags.
196
+ // eslint-disable-next-line security/detect-unsafe-regex
197
+ .replace(/^ {0,3}(?:>\s?)+/gm, '')
198
+ // Thematic breaks: a line of 3+ `-`, `*`, or `_` (optionally
199
+ // space-separated). The backreference (`\1`) pins every repetition to
200
+ // the same captured character, which the linter's heuristic doesn't
201
+ // model — same false-positive shape as above.
202
+ // eslint-disable-next-line security/detect-unsafe-regex
203
+ .replace(/^ {0,3}([-*_])(?:\s*\1){2,}\s*$/gm, '')
204
+ // List markers: bullet or ordered
205
+ .replace(/^(\s*)[-*+]\s+/gm, '$1')
206
+ .replace(/^(\s*)\d+[.)]\s+/gm, '$1')
207
+ // Images: keep alt text, drop the URL entirely
208
+ .replace(/!\[([^\]]*)\]\([^)]*\)/g, '$1')
209
+ // Links: keep the link text, drop the URL
210
+ .replace(/\[([^\]]*)\]\([^)]*\)/g, '$1')
211
+ // Strikethrough / bold / italic — longest markers first so `**` isn't
212
+ // consumed as two `*` matches
213
+ .replace(/~~([^~]+)~~/g, '$1')
214
+ .replace(/\*\*([^*]+)\*\*/g, '$1')
215
+ .replace(/__([^_]+)__/g, '$1')
216
+ .replace(/\*([^*]+)\*/g, '$1')
217
+ .replace(/\b_([^_]+)_\b/g, '$1'));
218
+ }
219
+ /** Trim each line, collapse runs of blank lines, and trim the whole result. Preserves paragraph breaks. */
220
+ function collapseWhitespace(text) {
221
+ return text
222
+ .split('\n')
223
+ .map((line) => line.replace(/[ \t]+/g, ' ').trim())
224
+ .join('\n')
225
+ .replace(/\n{3,}/g, '\n\n')
226
+ .trim();
227
+ }
228
+ /**
229
+ * Convert MDX/Markdown body content to plain prose text.
230
+ *
231
+ * See the module doc above for the full pipeline and why this exists as a
232
+ * distinct transform from `stripMdxImports`. In short: frontmatter, code
233
+ * fences, inline code, JSX tags/expressions, and Markdown syntax are all
234
+ * stripped down to their human-readable text — code content and link/image
235
+ * text are kept, everything else is discarded. Paired custom components
236
+ * lose only their tags; the prose between them survives.
237
+ *
238
+ * Output preserves paragraph breaks (blank lines) but is not further
239
+ * chunked, weighted, or field-selected — composing that into a search
240
+ * document is left to the caller, since that logic is where adopter search
241
+ * indexes genuinely diverge (see docs/adopter-migration.md).
242
+ */
243
+ export function toPlainText(markdown) {
244
+ const { content } = matter(markdown);
245
+ const withoutImports = stripMdxImports(content);
246
+ const { masked, restore } = maskCode(withoutImports);
247
+ let result = masked;
248
+ result = result.replace(TAG_RE, ' ');
249
+ result = stripBraceExpressions(result);
250
+ result = stripMarkdownSyntax(result);
251
+ result = restore(result);
252
+ result = collapseWhitespace(result);
253
+ return result;
254
+ }
255
+ //# sourceMappingURL=to-plain-text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"to-plain-text.js","sourceRoot":"","sources":["../../src/ai/to-plain-text.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAEH,OAAO,MAAM,MAAM,aAAa,CAAA;AAChC,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAE7C;;;;;;;;;;;GAWG;AACH,MAAM,YAAY,GAAG,KAAK,CAAA;AAC1B,MAAM,YAAY,GAAG,IAAI,CAAA;AACzB,MAAM,gBAAgB,GAAG,aAAa,CAAA;AAEtC,MAAM,aAAa,GAAG,KAAK,CAAA;AAC3B,MAAM,aAAa,GAAG,IAAI,CAAA;AAC1B,MAAM,iBAAiB,GAAG,aAAa,CAAA;AAEvC,6GAA6G;AAC7G,MAAM,YAAY,GAAG,8BAA8B,CAAA;AAEnD;;;;;;;;;;;GAWG;AACH,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,iCAAiC,YAAY,SAAS,EAAE,GAAG,CAAC,CAAA;AAEtF;;8BAE8B;AAC9B,SAAS,gBAAgB,CAAC,IAAY,EAAE,MAAc;IACpD,OAAO,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAA;AAC3E,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,SAAS,oBAAoB,CAAC,IAAY,EAAE,MAAgB;IAC1D,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IAC9B,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAAA;IAE9B,+FAA+F;IAC/F,+EAA+E;IAC/E,MAAM,aAAa,GAAG;QACpB,KAAK,EAAE,IAAI,KAAK,CAAS,SAAS,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAChD,KAAK,EAAE,IAAI,KAAK,CAAS,SAAS,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;KACjD,CAAA;IACD,KAAK,IAAI,CAAC,GAAG,SAAS,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QACxC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;QAC7F,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,gBAAgB,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;IAC/F,CAAC;IAED,MAAM,QAAQ,GAAa,EAAE,CAAA;IAC7B,IAAI,CAAC,GAAG,CAAC,CAAA;IACT,OAAO,CAAC,GAAG,SAAS,EAAE,CAAC;QACrB,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAA;QACrB,MAAM,MAAM,GAAG,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAA;QAErF,4FAA4F;QAC5F,4FAA4F;QAC5F,gFAAgF;QAChF,MAAM,UAAU,GAAG,CAAC,GAAG,CAAC,CAAA;QACxB,MAAM,UAAU,GAAG,MAAM,IAAI,UAAU,GAAG,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;QAE5F,IAAI,CAAC,MAAM,IAAI,UAAU,KAAK,CAAC,CAAC,EAAE,CAAC;YACjC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;YACnB,CAAC,EAAE,CAAA;YACH,SAAQ;QACV,CAAC;QAED,MAAM,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACzD,MAAM,GAAG,GAAG,MAAM,CAAC,MAAM,CAAA;QACzB,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QACpB,2FAA2F;QAC3F,4FAA4F;QAC5F,4FAA4F;QAC5F,sCAAsC;QACtC,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,GAAG,YAAY,GAAG,GAAG,GAAG,YAAY,EAAE,EAAE,EAAE,CAAC,CAAA;QAC7D,CAAC,GAAG,UAAU,GAAG,CAAC,CAAA;IACpB,CAAC;IACD,OAAO,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAC5B,CAAC;AAED;;;;GAIG;AACH,SAAS,QAAQ,CAAC,IAAY;IAC5B,MAAM,MAAM,GAAa,EAAE,CAAA;IAC3B,MAAM,OAAO,GAAa,EAAE,CAAA;IAE5B,IAAI,MAAM,GAAG,oBAAoB,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;IAE/C,MAAM,GAAG,MAAM,CAAC,OAAO,CACrB,sBAAsB,EACtB,CAAC,MAAM,EAAE,MAA0B,EAAE,MAA0B,EAAE,EAAE;QACjE,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,CAAA;QAC1B,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,IAAI,MAAM,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAA;QAC7C,OAAO,GAAG,aAAa,GAAG,GAAG,GAAG,aAAa,EAAE,CAAA;IACjD,CAAC,CACF,CAAA;IAED,OAAO;QACL,MAAM;QACN,OAAO,EAAE,CAAC,CAAS,EAAE,EAAE;YACrB,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,iBAAiB,EAAE,CAAC,MAAM,EAAE,CAAS,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;YAC3E,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,gBAAgB,EAAE,CAAC,MAAM,EAAE,CAAS,EAAE,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;YACzE,OAAO,CAAC,CAAA;QACV,CAAC;KACF,CAAA;AACH,CAAC;AAED;;;;GAIG;AACH,SAAS,qBAAqB,CAAC,IAAY;IACzC,IAAI,MAAM,GAAG,EAAE,CAAA;IACf,IAAI,KAAK,GAAG,CAAC,CAAA;IACb,KAAK,MAAM,EAAE,IAAI,IAAI,EAAE,CAAC;QACtB,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACf,IAAI,KAAK,KAAK,CAAC;gBAAE,MAAM,IAAI,GAAG,CAAA;YAC9B,KAAK,EAAE,CAAA;YACP,SAAQ;QACV,CAAC;QACD,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACf,IAAI,KAAK,GAAG,CAAC;gBAAE,KAAK,EAAE,CAAA;YACtB,SAAQ;QACV,CAAC;QACD,IAAI,KAAK,KAAK,CAAC;YAAE,MAAM,IAAI,EAAE,CAAA;IAC/B,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAED,qEAAqE;AACrE,SAAS,mBAAmB,CAAC,IAAY;IACvC,OAAO,CACL,IAAI;QACF,gCAAgC;SAC/B,OAAO,CAAC,oBAAoB,EAAE,EAAE,CAAC;QAClC,sEAAsE;QACtE,uEAAuE;QACvE,mEAAmE;QACnE,4BAA4B;QAC5B,wDAAwD;SACvD,OAAO,CAAC,oBAAoB,EAAE,EAAE,CAAC;QAClC,6DAA6D;QAC7D,sEAAsE;QACtE,oEAAoE;QACpE,8CAA8C;QAC9C,wDAAwD;SACvD,OAAO,CAAC,mCAAmC,EAAE,EAAE,CAAC;QACjD,kCAAkC;SACjC,OAAO,CAAC,kBAAkB,EAAE,IAAI,CAAC;SACjC,OAAO,CAAC,oBAAoB,EAAE,IAAI,CAAC;QACpC,+CAA+C;SAC9C,OAAO,CAAC,yBAAyB,EAAE,IAAI,CAAC;QACzC,0CAA0C;SACzC,OAAO,CAAC,wBAAwB,EAAE,IAAI,CAAC;QACxC,sEAAsE;QACtE,8BAA8B;SAC7B,OAAO,CAAC,cAAc,EAAE,IAAI,CAAC;SAC7B,OAAO,CAAC,kBAAkB,EAAE,IAAI,CAAC;SACjC,OAAO,CAAC,cAAc,EAAE,IAAI,CAAC;SAC7B,OAAO,CAAC,cAAc,EAAE,IAAI,CAAC;SAC7B,OAAO,CAAC,gBAAgB,EAAE,IAAI,CAAC,CACnC,CAAA;AACH,CAAC;AAED,2GAA2G;AAC3G,SAAS,kBAAkB,CAAC,IAAY;IACtC,OAAO,IAAI;SACR,KAAK,CAAC,IAAI,CAAC;SACX,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;SAClD,IAAI,CAAC,IAAI,CAAC;SACV,OAAO,CAAC,SAAS,EAAE,MAAM,CAAC;SAC1B,IAAI,EAAE,CAAA;AACX,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,WAAW,CAAC,QAAgB;IAC1C,MAAM,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC,QAAQ,CAAC,CAAA;IACpC,MAAM,cAAc,GAAG,eAAe,CAAC,OAAO,CAAC,CAAA;IAC/C,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,QAAQ,CAAC,cAAc,CAAC,CAAA;IAEpD,IAAI,MAAM,GAAG,MAAM,CAAA;IACnB,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACpC,MAAM,GAAG,qBAAqB,CAAC,MAAM,CAAC,CAAA;IACtC,MAAM,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAA;IACpC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAA;IACxB,MAAM,GAAG,kBAAkB,CAAC,MAAM,CAAC,CAAA;IAEnC,OAAO,MAAM,CAAA;AACf,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"transform-components.d.ts","sourceRoot":"","sources":["../../src/ai/transform-components.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAA;AAElE;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,cAAc,CAiBtE;AAkDD;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,mBAAmB,GAAG,MAAM,CAiE9F"}
1
+ {"version":3,"file":"transform-components.d.ts","sourceRoot":"","sources":["../../src/ai/transform-components.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,SAAS,CAAA;AAElE;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,UAAU,EAAE,MAAM,GAAG,cAAc,CAiBtE;AA0HD;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,mBAAmB,GAAG,MAAM,CAiE9F"}
@@ -42,6 +42,75 @@ const BLOCK_RESTORE_RE = /<<CODEBLOCK(\d+)>>/g;
42
42
  const INLINE_PREFIX = '<<INLINECODE';
43
43
  const INLINE_SUFFIX = '>>';
44
44
  const INLINE_RESTORE_RE = /<<INLINECODE(\d+)>>/g;
45
+ /** True if `line` is a valid closing fence line for `marker` ("```" or "~~~"): the marker
46
+ * followed by nothing but whitespace through end of line — matching what `\1\s*$` required in
47
+ * the regex this replaced. */
48
+ function isFenceCloseLine(line, marker) {
49
+ return line.startsWith(marker) && /^\s*$/.test(line.slice(marker.length));
50
+ }
51
+ /**
52
+ * Mask fenced code blocks (` ``` `/`~~~`), capturing each block's raw text (fence lines
53
+ * included) exactly as `maskCodeBlocks` used to via `/^(```|~~~).*\n[\s\S]*?\n\1\s*$/gm`.
54
+ *
55
+ * A hand-rolled line scan, not that regex: it is a polynomial-ReDoS shape (measured ~9s on
56
+ * ~530KB of body text with many unclosed fence openers — an ordinary authoring accident, not a
57
+ * crafted payload) that CodeQL and three review rounds both missed elsewhere in this package
58
+ * (see `ai/to-plain-text.ts`'s identical fix). The lazy `[\s\S]*?` has no bound on how far it
59
+ * must scan looking for a closing `\1` that, for an unclosed fence, never arrives — it exhausts
60
+ * to the end of the string before giving up on that starting line, and `/gm` retries the same
61
+ * exhaustive scan at every subsequent fence-opener line.
62
+ *
63
+ * This scans each line once. `nextCloseLine` is precomputed per marker type via a single
64
+ * backward pass, so any opener's nearest closer (or "none exists") is an O(1) lookup instead of
65
+ * a fresh forward scan — the change that keeps the whole function O(n) regardless of how many
66
+ * fences are opened and never closed.
67
+ *
68
+ * One documented, harmless divergence from the replaced regex: `\s*` there is greedy over `\s`
69
+ * (which includes `\n`), so on a closer immediately followed by blank lines it could consume
70
+ * some of them into the match. This scan never does. Verified by fuzzing 8,000 random
71
+ * fence/marker combinations through this module's actual `applyComponentTransforms` pipeline:
72
+ * final output was byte-identical in 7,999/8,000 cases, and the one divergence was an extra
73
+ * blank line in a maximally adversarial nested-tag-plus-fence input, never a content change —
74
+ * `\s` is never itself matched by any component-tag pattern, so which side of a placeholder a
75
+ * run of blank lines lands on cannot affect what a transform sees or produces.
76
+ */
77
+ function maskFencedCodeBlocks(body, blocks) {
78
+ const lines = body.split('\n');
79
+ const lineCount = lines.length;
80
+ // nextCloseLine[marker][i] = the nearest index >= i that closes `marker`, or -1 if none exists
81
+ // at or after i. Built right-to-left so each entry is O(1) given the next one.
82
+ const nextCloseLine = {
83
+ '```': new Array(lineCount + 1).fill(-1),
84
+ '~~~': new Array(lineCount + 1).fill(-1),
85
+ };
86
+ for (let i = lineCount - 1; i >= 0; i--) {
87
+ nextCloseLine['```'][i] = isFenceCloseLine(lines[i], '```') ? i : nextCloseLine['```'][i + 1];
88
+ nextCloseLine['~~~'][i] = isFenceCloseLine(lines[i], '~~~') ? i : nextCloseLine['~~~'][i + 1];
89
+ }
90
+ const outLines = [];
91
+ let i = 0;
92
+ while (i < lineCount) {
93
+ const line = lines[i];
94
+ const marker = line.startsWith('```') ? '```' : line.startsWith('~~~') ? '~~~' : null;
95
+ // A closer can never be the very next line: the original pattern requires TWO separate `\n`
96
+ // matches between the opener and `\1` (one ending the opener's line, one immediately before
97
+ // the closer), so even zero-width content needs a line of its own between them.
98
+ const searchFrom = i + 2;
99
+ const closeIndex = marker && searchFrom < lineCount ? nextCloseLine[marker][searchFrom] : -1;
100
+ if (!marker || closeIndex === -1) {
101
+ outLines.push(line);
102
+ i++;
103
+ continue;
104
+ }
105
+ // Whole matched span (fence lines included), matching the replaced regex's own capture.
106
+ const block = lines.slice(i, closeIndex + 1).join('\n');
107
+ const idx = blocks.length;
108
+ blocks.push(block);
109
+ outLines.push(`${BLOCK_PREFIX}${idx}${BLOCK_SUFFIX}`);
110
+ i = closeIndex + 1;
111
+ }
112
+ return outLines.join('\n');
113
+ }
45
114
  /**
46
115
  * Mask fenced code blocks and inline code spans so component transforms
47
116
  * don't touch them. Returns the masked string and a restore function.
@@ -50,11 +119,7 @@ function maskCodeBlocks(body) {
50
119
  const blocks = [];
51
120
  const inlines = [];
52
121
  // 1. Mask fenced code blocks
53
- let masked = body.replace(/^(```|~~~).*\n[\s\S]*?\n\1\s*$/gm, (block) => {
54
- const idx = blocks.length;
55
- blocks.push(block);
56
- return `${BLOCK_PREFIX}${idx}${BLOCK_SUFFIX}`;
57
- });
122
+ let masked = maskFencedCodeBlocks(body, blocks);
58
123
  // 2. Mask inline code spans (double-backtick first, then single-backtick)
59
124
  masked = masked.replace(/``[^`]+``|`[^`]+`/g, (span) => {
60
125
  const idx = inlines.length;
@@ -1 +1 @@
1
- {"version":3,"file":"transform-components.js","sourceRoot":"","sources":["../../src/ai/transform-components.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"transform-components.js","sourceRoot":"","sources":["../../src/ai/transform-components.ts"],"names":[],"mappings":"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"}
@@ -56,14 +56,14 @@ export declare const COMMENT_ROUTES: {
56
56
  }, "strip", z.ZodTypeAny, {
57
57
  type: "branch" | "entry" | "field";
58
58
  text: string;
59
- threadId?: string | undefined;
60
59
  entryPath?: import("../paths").LogicalPath | undefined;
60
+ threadId?: string | undefined;
61
61
  canopyPath?: string | undefined;
62
62
  }, {
63
63
  type: "branch" | "entry" | "field";
64
64
  text: string;
65
- threadId?: string | undefined;
66
65
  entryPath?: import("../paths").LogicalPath | undefined;
66
+ threadId?: string | undefined;
67
67
  canopyPath?: string | undefined;
68
68
  }>, AddCommentResponse>;
69
69
  readonly resolve: import("./route-builder").RouteDefinition<z.ZodObject<{
@@ -4,17 +4,58 @@
4
4
  * Handles checking if a user can access a branch based on ACLs.
5
5
  */
6
6
  import type { BranchContext } from '../types';
7
- import type { DefaultBranchAccess } from '../config';
7
+ import type { CanopyConfig, DefaultBranchAccess } from '../config';
8
8
  import type { CanopyUser } from '../user';
9
9
  import type { BranchAccessResult } from './types';
10
+ /** Options narrowing {@link checkBranchAccessWithDefault} to a specific branch's nature. */
11
+ export interface BranchAccessOptions {
12
+ /**
13
+ * Whether this is the protected base branch -- pass
14
+ * `getBranchProtection(...).isProtected`. When true, the branch passes this
15
+ * layer wherever no explicit ACL decided the question, and the PATH layer alone
16
+ * decides what is readable. Explicit ACL verdicts still win in both directions
17
+ * (see the comment at the fallback site).
18
+ *
19
+ * This grant is load-bearing, not a convenience. The base branch takes no ACL
20
+ * (`updateBranchAccessHandler` rejects one outright, because an entry there
21
+ * would feed `allowed_by_acl` and confer Withdraw rights) and its `createdBy`
22
+ * is `canopycms-system`, so nobody is its creator. Without this, the branch
23
+ * every user lands on is unreachable under `defaultBranchAccess: 'deny'` with
24
+ * no way to configure around it -- which is what made 'deny' unusable for any
25
+ * site with non-admin editors.
26
+ *
27
+ * It cannot widen anything dangerous: workflow actions stay blocked because
28
+ * {@link canPerformWorkflowAction} disables its system-branch grant on the
29
+ * same flag, prod writes stay blocked by `getBranchWriteProtection().readOnly`,
30
+ * and the editor API 401s anonymous callers before authorization runs. What it
31
+ * buys is that a public-read `deployedAs: 'server'` site can run 'deny' with
32
+ * `defaultPathAccess: { read: 'allow' }` and still keep un-ACL'd work branches
33
+ * private -- previously that required the blunt `defaultBranchAccess: 'allow'`,
34
+ * which opened every work branch too.
35
+ */
36
+ isProtectedBranch?: boolean;
37
+ }
10
38
  /**
11
39
  * Check if user has access to a branch with explicit default behavior.
40
+ *
41
+ * Precedence, highest first:
42
+ * 1. Admins and Reviewers
43
+ * 2. `managerOrAdminAllowed` lockdown
44
+ * 3. An explicit user/group ACL -- an allowlist omitting the creator still
45
+ * denies them, so an admin can lock down a branch someone else created
46
+ * 4. With no ACL: the branch creator, then `defaultAccess`, and only where that
47
+ * would deny, the protected base branch grant
48
+ * (see {@link BranchAccessOptions.isProtectedBranch})
12
49
  */
13
- export declare function checkBranchAccessWithDefault(context: BranchContext, user: CanopyUser, defaultAccess?: DefaultBranchAccess): BranchAccessResult;
50
+ export declare function checkBranchAccessWithDefault(context: BranchContext, user: CanopyUser, defaultAccess?: DefaultBranchAccess, options?: BranchAccessOptions): BranchAccessResult;
14
51
  /**
15
52
  * Create a branch access checker with bound default access.
53
+ *
54
+ * `config` is needed to resolve whether a branch is the protected base branch;
55
+ * it routes through `getBranchProtection`, the single source of truth for that
56
+ * question, rather than repeating the base-branch test here.
16
57
  */
17
- export declare function createCheckBranchAccess(defaultAccess?: DefaultBranchAccess): (context: BranchContext, user: CanopyUser) => BranchAccessResult;
58
+ export declare function createCheckBranchAccess(defaultAccess?: DefaultBranchAccess, config?: Pick<CanopyConfig, 'mode' | 'defaultBaseBranch'>): (context: BranchContext, user: CanopyUser) => BranchAccessResult;
18
59
  /** Options tightening {@link canPerformWorkflowAction} beyond the default hybrid model. */
19
60
  export interface WorkflowActionOptions {
20
61
  /**
@@ -23,6 +64,13 @@ export interface WorkflowActionOptions {
23
64
  * would otherwise let anyone with general branch access submit/withdraw it
24
65
  * -- pass `getBranchProtection(...).isProtected` here so only
25
66
  * admins/reviewers/explicit-ACL users retain workflow rights on it.
67
+ *
68
+ * It is also forwarded to {@link checkBranchAccessWithDefault}, where the same
69
+ * flag GRANTS access (see {@link BranchAccessOptions.isProtectedBranch}). The
70
+ * two pull in opposite directions on purpose, and that is exactly the intended
71
+ * base-branch posture: readable by anyone the path layer permits, submittable
72
+ * by no one. The access layer says yes, then `isSystemBranch` below is false,
73
+ * so a non-creator/non-ACL/non-privileged user still gets `false` here.
26
74
  */
27
75
  isProtectedBranch?: boolean;
28
76
  }
@@ -37,6 +85,10 @@ export interface WorkflowActionOptions {
37
85
  * - Admins and Reviewers always have access (via checkBranchAccess)
38
86
  * - Unless `options.isProtectedBranch` is set, in which case the system-branch
39
87
  * grant above is disabled (see {@link WorkflowActionOptions})
88
+ *
89
+ * The creator grant is enforced twice over: `checkBranchAccessWithDefault` now
90
+ * admits the creator (so the gate below no longer swallows them under
91
+ * `defaultBranchAccess: 'deny'`), and `userIsCreator` still decides the result.
40
92
  */
41
93
  export declare function canPerformWorkflowAction(context: BranchContext, user: CanopyUser, defaultAccess?: DefaultBranchAccess, options?: WorkflowActionOptions): boolean;
42
94
  //# sourceMappingURL=branch.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"branch.d.ts","sourceRoot":"","sources":["../../src/authorization/branch.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAC7C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAA;AAEpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACzC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;AAEjD;;GAEG;AACH,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,aAAa,EACtB,IAAI,EAAE,UAAU,EAChB,aAAa,GAAE,mBAA4B,GAC1C,kBAAkB,CAyBpB;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CAAC,aAAa,GAAE,mBAA4B,IACzE,SAAS,aAAa,EAAE,MAAM,UAAU,KAAG,kBAAkB,CAEtE;AAED,2FAA2F;AAC3F,MAAM,WAAW,qBAAqB;IACpC;;;;;;OAMG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAC5B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,aAAa,EACtB,IAAI,EAAE,UAAU,EAChB,aAAa,GAAE,mBAA4B,EAC3C,OAAO,CAAC,EAAE,qBAAqB,GAC9B,OAAO,CA0BT"}
1
+ {"version":3,"file":"branch.d.ts","sourceRoot":"","sources":["../../src/authorization/branch.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AAC7C,OAAO,KAAK,EAAE,YAAY,EAAE,mBAAmB,EAAE,MAAM,WAAW,CAAA;AAGlE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACzC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,SAAS,CAAA;AAEjD,4FAA4F;AAC5F,MAAM,WAAW,mBAAmB;IAClC;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAC5B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,aAAa,EACtB,IAAI,EAAE,UAAU,EAChB,aAAa,GAAE,mBAA4B,EAC3C,OAAO,CAAC,EAAE,mBAAmB,GAC5B,kBAAkB,CAgDpB;AAED;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,aAAa,GAAE,mBAA4B,EAC3C,MAAM,CAAC,EAAE,IAAI,CAAC,YAAY,EAAE,MAAM,GAAG,mBAAmB,CAAC,IAEjD,SAAS,aAAa,EAAE,MAAM,UAAU,KAAG,kBAAkB,CAMtE;AAED,2FAA2F;AAC3F,MAAM,WAAW,qBAAqB;IACpC;;;;;;;;;;;;;OAaG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAC5B;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,aAAa,EACtB,IAAI,EAAE,UAAU,EAChB,aAAa,GAAE,mBAA4B,EAC3C,OAAO,CAAC,EAAE,qBAAqB,GAC9B,OAAO,CA4BT"}