@mintlify/common 1.0.1197 → 1.0.1199

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.
@@ -1,3 +1,4 @@
1
+ import { isVisibilityElement, resolveVisibilityFor, } from '../plugins/remark/remarkVisibilityForMarkdown.js';
1
2
  export const createMdxJsxAttribute = (key, value) => {
2
3
  return {
3
4
  type: 'mdxJsxAttribute',
@@ -24,6 +25,13 @@ export const getTableOfContentsTitle = (node, index = 1, children = EMPTY_CHILDR
24
25
  const labelAttr = node.attributes.find((attr) => 'name' in attr && attr.name === 'label' && typeof attr.value === 'string');
25
26
  return (_a = labelAttr === null || labelAttr === void 0 ? void 0 : labelAttr.value) !== null && _a !== void 0 ? _a : '';
26
27
  }
28
+ if (isVisibilityElement(node)) {
29
+ const resolution = resolveVisibilityFor(node);
30
+ const visibleToEveryone = resolution.kind === 'dynamic' ||
31
+ (resolution.kind === 'audience' && resolution.audience === 'humans');
32
+ if (!visibleToEveryone)
33
+ return '';
34
+ }
27
35
  const lastChild = children[index - 1];
28
36
  const isText = node.type === 'text';
29
37
  const isInlineCode = node.type === 'inlineCode';
@@ -3,7 +3,7 @@ import { safeCleanHeadingId, slugify } from '../../../slugify.js';
3
3
  import { createMdxJsxAttribute, getTableOfContentsTitle, getTitleMarkdownText, } from '../../lib/remark-utils.js';
4
4
  import { isMdxJsxFragment } from '../../utils.js';
5
5
  import { AVOIDED_PAGE_MODES, HEADING_LEVELS } from './remarkComponentIds.js';
6
- import { isHiddenFromHumans, isVisibilityElement, resolveVisibilityFor, } from './remarkVisibilityForMarkdown.js';
6
+ import { isHiddenFromHumans, isVisibilityElement, resolveVisibilityFor, toVisibilityAuthRule, } from './remarkVisibilityForMarkdown.js';
7
7
  import { isVariationElement, resolveVariationIds } from './variation.js';
8
8
  export const HEADING_NAMES = ['h1', 'h2', 'h3', 'h4'];
9
9
  const COMPONENTS_TO_EXCLUDE_HEADINGS = [
@@ -20,6 +20,13 @@ function getStringAttribute(attributes, name) {
20
20
  }
21
21
  return undefined;
22
22
  }
23
+ const authRuleKey = (rule) => typeof rule === 'string' ? rule : JSON.stringify([...rule.groups].sort());
24
+ const hasAuthRules = (childRules, parentRules) => {
25
+ if (parentRules === undefined)
26
+ return true;
27
+ const childKeys = new Set(childRules === null || childRules === void 0 ? void 0 : childRules.map(authRuleKey));
28
+ return parentRules.every((rule) => childKeys.has(authRuleKey(rule)));
29
+ };
23
30
  export const remarkExtractTableOfContents = (mdxExtracts, pageMetadata) => {
24
31
  // Unified slug deduplication: both custom IDs and auto-generated slugs
25
32
  // share the same seen-slug state so they cannot collide.
@@ -46,6 +53,7 @@ export const remarkExtractTableOfContents = (mdxExtracts, pageMetadata) => {
46
53
  const tabContentMap = new Map();
47
54
  const viewContentMap = new Map();
48
55
  const variationContentMap = new Map();
56
+ const authRulesContentMap = new Map();
49
57
  // Maps a Step node to the titleSize inherited from its parent <Steps>.
50
58
  // At render time <Steps titleSize> is forwarded to each child <Step> that
51
59
  // doesn't set its own titleSize, so the TOC must honor the same fallback.
@@ -61,12 +69,26 @@ export const remarkExtractTableOfContents = (mdxExtracts, pageMetadata) => {
61
69
  });
62
70
  }
63
71
  const visibilityNode = node;
64
- if (isVisibilityElement(visibilityNode) &&
65
- isHiddenFromHumans(resolveVisibilityFor(visibilityNode))) {
66
- visit(node, (childNode) => {
67
- if (childNode !== node)
68
- excludedNodes.add(childNode);
69
- });
72
+ if (isVisibilityElement(visibilityNode)) {
73
+ const resolution = resolveVisibilityFor(visibilityNode);
74
+ const authRule = toVisibilityAuthRule(resolution);
75
+ if (isHiddenFromHumans(resolution)) {
76
+ visit(node, (childNode) => {
77
+ if (childNode !== node)
78
+ excludedNodes.add(childNode);
79
+ });
80
+ }
81
+ else if (authRule) {
82
+ visit(node, (childNode) => {
83
+ var _a;
84
+ if (childNode === node)
85
+ return;
86
+ authRulesContentMap.set(childNode, [
87
+ ...((_a = authRulesContentMap.get(childNode)) !== null && _a !== void 0 ? _a : []),
88
+ authRule,
89
+ ]);
90
+ });
91
+ }
70
92
  }
71
93
  if (node.type === 'mdxJsxFlowElement' && node.name === 'Steps') {
72
94
  const stepsTitleSize = getStringAttribute(node.attributes, 'titleSize');
@@ -123,6 +145,8 @@ export const remarkExtractTableOfContents = (mdxExtracts, pageMetadata) => {
123
145
  }
124
146
  });
125
147
  const pushEntry = (entry, level) => {
148
+ if (!entry.title.trim())
149
+ return;
126
150
  if (level !== undefined && Number(level) <= 2) {
127
151
  hasTopLayer = true;
128
152
  contents.push(entry);
@@ -133,23 +157,26 @@ export const remarkExtractTableOfContents = (mdxExtracts, pageMetadata) => {
133
157
  if (hasTopLayer) {
134
158
  const lastTopLevel = contents.at(-1);
135
159
  if (lastTopLevel &&
160
+ !(lastTopLevel.depth > 2 && lastTopLevel.depth >= entry.depth) &&
136
161
  (lastTopLevel.tabId === undefined || lastTopLevel.tabId === entry.tabId) &&
137
162
  (lastTopLevel.viewId === undefined || lastTopLevel.viewId === entry.viewId) &&
138
163
  (lastTopLevel.variationIds === undefined ||
139
164
  (entry.variationIds !== undefined &&
140
- entry.variationIds.every((id) => { var _a; return (_a = lastTopLevel.variationIds) === null || _a === void 0 ? void 0 : _a.includes(id); })))) {
165
+ entry.variationIds.every((id) => { var _a; return (_a = lastTopLevel.variationIds) === null || _a === void 0 ? void 0 : _a.includes(id); }))) &&
166
+ hasAuthRules(entry.authRules, lastTopLevel.authRules)) {
141
167
  arrToPushInto = lastTopLevel.children;
142
168
  }
143
169
  }
144
170
  arrToPushInto.push(entry);
145
171
  };
146
172
  visit(tree, (node) => {
147
- var _a, _b, _c, _d, _e, _f, _g;
173
+ var _a, _b, _c, _d, _e, _f, _g, _h;
148
174
  if (excludedNodes.has(node))
149
175
  return;
150
176
  const currentTabId = tabContentMap.get(node);
151
177
  const currentViewId = viewContentMap.get(node);
152
178
  const currentVariationIds = variationContentMap.get(node);
179
+ const currentAuthRules = authRulesContentMap.get(node);
153
180
  if (node.type === 'mdxFlowExpression' || node.type === 'mdxTextExpression') {
154
181
  const fragmentHeadings = (_a = node.data) === null || _a === void 0 ? void 0 : _a.tableOfContents;
155
182
  if (!(fragmentHeadings === null || fragmentHeadings === void 0 ? void 0 : fragmentHeadings.length))
@@ -165,18 +192,20 @@ export const remarkExtractTableOfContents = (mdxExtracts, pageMetadata) => {
165
192
  };
166
193
  register(fragmentHeadings);
167
194
  for (const heading of fragmentHeadings) {
168
- pushEntry(Object.assign(Object.assign({}, heading), { tabId: currentTabId, viewId: currentViewId, variationIds: currentVariationIds }), heading.depth);
195
+ pushEntry(Object.assign(Object.assign({}, heading), { tabId: currentTabId, viewId: currentViewId, variationIds: currentVariationIds, authRules: currentAuthRules || heading.authRules
196
+ ? [...(currentAuthRules !== null && currentAuthRules !== void 0 ? currentAuthRules : []), ...((_b = heading.authRules) !== null && _b !== void 0 ? _b : [])]
197
+ : undefined }), heading.depth);
169
198
  }
170
199
  return;
171
200
  }
172
201
  const isValidHeading = node.type === 'heading' && HEADING_LEVELS.includes(node.depth);
173
- const isValidMdxHeading = node.type === 'mdxJsxFlowElement' && HEADING_NAMES.includes((_b = node.name) !== null && _b !== void 0 ? _b : '');
202
+ const isValidMdxHeading = node.type === 'mdxJsxFlowElement' && HEADING_NAMES.includes((_c = node.name) !== null && _c !== void 0 ? _c : '');
174
203
  const isTransformedHeading = node.type === 'mdxJsxFlowElement' && node.name === 'Heading';
175
204
  const isValidUpdate = node.type === 'mdxJsxFlowElement' &&
176
205
  node.name === 'Update' &&
177
206
  node.attributes.some((attr) => 'name' in attr && attr.name === 'label');
178
207
  const stepTitleSize = node.type === 'mdxJsxFlowElement' && node.name === 'Step'
179
- ? ((_c = getStringAttribute(node.attributes, 'titleSize')) !== null && _c !== void 0 ? _c : inheritedStepTitleSizeMap.get(node))
208
+ ? ((_d = getStringAttribute(node.attributes, 'titleSize')) !== null && _d !== void 0 ? _d : inheritedStepTitleSizeMap.get(node))
180
209
  : undefined;
181
210
  const hasNoAnchor = node.type === 'mdxJsxFlowElement' &&
182
211
  node.attributes.some((attr) => 'name' in attr &&
@@ -185,7 +214,7 @@ export const remarkExtractTableOfContents = (mdxExtracts, pageMetadata) => {
185
214
  attr.value === 'true' ||
186
215
  (typeof attr.value === 'object' && attr.value.value === 'true')));
187
216
  const stepTitle = node.type === 'mdxJsxFlowElement' && node.name === 'Step'
188
- ? getTitleMarkdownText(node, (_d = getStringAttribute(node.attributes, 'title')) !== null && _d !== void 0 ? _d : '')
217
+ ? getTitleMarkdownText(node, (_e = getStringAttribute(node.attributes, 'title')) !== null && _e !== void 0 ? _e : '')
189
218
  : undefined;
190
219
  const isValidStep = node.type === 'mdxJsxFlowElement' &&
191
220
  node.name === 'Step' &&
@@ -194,7 +223,7 @@ export const remarkExtractTableOfContents = (mdxExtracts, pageMetadata) => {
194
223
  (stepTitle === null || stepTitle === void 0 ? void 0 : stepTitle.trim()) !== '';
195
224
  const hasIdAttribute = node.type === 'mdxJsxFlowElement' &&
196
225
  node.attributes.some((attr) => 'name' in attr && attr.name === 'id');
197
- const isAvoidedPageMode = AVOIDED_PAGE_MODES.includes((_e = pageMetadata === null || pageMetadata === void 0 ? void 0 : pageMetadata.mode) !== null && _e !== void 0 ? _e : '');
226
+ const isAvoidedPageMode = AVOIDED_PAGE_MODES.includes((_f = pageMetadata === null || pageMetadata === void 0 ? void 0 : pageMetadata.mode) !== null && _f !== void 0 ? _f : '');
198
227
  if (!isValidHeading &&
199
228
  !isValidMdxHeading &&
200
229
  !isTransformedHeading &&
@@ -212,7 +241,7 @@ export const remarkExtractTableOfContents = (mdxExtracts, pageMetadata) => {
212
241
  }
213
242
  else if ('name' in node && node.name === 'Step') {
214
243
  const titleSizeToLevel = { h2: 2, h3: 3, h4: 4 };
215
- level = (_f = titleSizeToLevel[stepTitleSize !== null && stepTitleSize !== void 0 ? stepTitleSize : '']) !== null && _f !== void 0 ? _f : 3;
244
+ level = (_g = titleSizeToLevel[stepTitleSize !== null && stepTitleSize !== void 0 ? stepTitleSize : '']) !== null && _g !== void 0 ? _g : 3;
216
245
  // @ts-expect-error we're assigning to depth despite the node not containing depth in the type
217
246
  node.depth = level;
218
247
  }
@@ -225,7 +254,7 @@ export const remarkExtractTableOfContents = (mdxExtracts, pageMetadata) => {
225
254
  level = levelAttr.value;
226
255
  }
227
256
  }
228
- else if ('name' in node && ((_g = node.name) === null || _g === void 0 ? void 0 : _g[1])) {
257
+ else if ('name' in node && ((_h = node.name) === null || _h === void 0 ? void 0 : _h[1])) {
229
258
  const num = Number(node.name[1]);
230
259
  level = !isNaN(num) ? num : undefined;
231
260
  if (level !== undefined) {
@@ -300,6 +329,7 @@ export const remarkExtractTableOfContents = (mdxExtracts, pageMetadata) => {
300
329
  tabId: currentTabId,
301
330
  viewId: currentViewId,
302
331
  variationIds: currentVariationIds,
332
+ authRules: currentAuthRules,
303
333
  }, level);
304
334
  });
305
335
  if (mdxExtracts) {
@@ -1,4 +1,4 @@
1
1
  import type { Root } from 'mdast';
2
2
  export declare const remarkMdxRemoveUnknownJsx: ({ allowlist }?: {
3
3
  allowlist?: string[];
4
- }) => (tree: Root) => Root | import("mdast").Link | import("mdast").Delete | import("mdast").Code | import("mdast").Text | import("mdast").Heading | import("mdast-util-mdx").MdxJsxFlowElement | import("mdast-util-mdx").MdxJsxTextElement | import("mdast").Blockquote | import("mdast").Break | import("mdast").Definition | import("mdast").Emphasis | import("mdast").FootnoteDefinition | import("mdast").FootnoteReference | import("mdast").Html | import("mdast").Image | import("mdast").ImageReference | import("mdast").InlineCode | import("mdast").LinkReference | import("mdast").List | import("mdast").ListItem | import("mdast").Paragraph | import("mdast").Strong | import("mdast").Table | import("mdast").TableCell | import("mdast").TableRow | import("mdast").ThematicBreak | import("mdast").Yaml | import("mdast-util-math").InlineMath | import("mdast-util-math").Math | import("mdast-util-mdx-expression").MdxTextExpression | import("mdast-util-mdx-expression").MdxFlowExpression | import("mdast-util-mdxjs-esm").MdxjsEsm;
4
+ }) => (tree: Root) => Root | import("mdast-util-mdx-jsx").MdxJsxFlowElement | import("mdast-util-mdx-jsx").MdxJsxTextElement | import("mdast").Link | import("mdast").Delete | import("mdast").Code | import("mdast").Blockquote | import("mdast").Break | import("mdast").Definition | import("mdast").Emphasis | import("mdast").FootnoteDefinition | import("mdast").FootnoteReference | import("mdast").Heading | import("mdast").Html | import("mdast").Image | import("mdast").ImageReference | import("mdast").InlineCode | import("mdast").LinkReference | import("mdast").List | import("mdast").ListItem | import("mdast").Paragraph | import("mdast").Strong | import("mdast").Table | import("mdast").TableCell | import("mdast").TableRow | import("mdast").Text | import("mdast").ThematicBreak | import("mdast").Yaml | import("mdast-util-math").InlineMath | import("mdast-util-math").Math | import("mdast-util-mdx-expression").MdxTextExpression | import("mdast-util-mdx-expression").MdxFlowExpression | import("mdast-util-mdxjs-esm").MdxjsEsm;
@@ -1,15 +1,15 @@
1
1
  import { visit } from 'unist-util-visit';
2
- import { isVisibilityElement, resolveVisibilityFor } from './remarkVisibilityForMarkdown.js';
2
+ import { VISIBILITY_FOR_EXPECTED, isVisibilityElement, resolveVisibilityFor, } from './remarkVisibilityForMarkdown.js';
3
3
  export const remarkValidateVisibility = () => (tree) => {
4
4
  visit(tree, (node) => {
5
5
  if (!isVisibilityElement(node))
6
6
  return;
7
7
  const resolution = resolveVisibilityFor(node);
8
8
  if (resolution.kind === 'invalid') {
9
- console.warn(`<Visibility for="${resolution.raw}"> has an unknown audience — expected "humans" or "agents". The content will be hidden from humans.`);
9
+ console.warn(`<Visibility for="${resolution.raw}"> has an unknown audience — expected ${VISIBILITY_FOR_EXPECTED}. The content will be hidden from humans.`);
10
10
  }
11
11
  if (resolution.kind === 'missing') {
12
- console.warn('<Visibility> is missing its "for" audience — expected "humans" or "agents". The content will be hidden from humans.');
12
+ console.warn(`<Visibility> is missing its "for" audience — expected ${VISIBILITY_FOR_EXPECTED}. The content will be hidden from humans.`);
13
13
  }
14
14
  });
15
15
  };
@@ -5,9 +5,22 @@ export declare function isVisibilityElement(node: {
5
5
  type: string;
6
6
  name?: string | null;
7
7
  }): node is MdxJsxElement;
8
+ export declare const VISIBILITY_AUDIENCES: readonly ["humans", "agents", "signed-in", "signed-out"];
9
+ export type VisibilityAudience = (typeof VISIBILITY_AUDIENCES)[number];
10
+ export declare const VISIBILITY_FOR_EXPECTED = "\"humans\", \"agents\", \"signed-in\", \"signed-out\", or { groups: [...] }";
11
+ export type VisibilityAuthRule = 'signed-in' | 'signed-out' | {
12
+ groups: string[];
13
+ };
14
+ export type VisibilityViewer = {
15
+ signedIn: boolean;
16
+ groups: readonly string[];
17
+ };
8
18
  export type VisibilityResolution = {
9
19
  kind: 'audience';
10
- audience: 'humans' | 'agents';
20
+ audience: VisibilityAudience;
21
+ } | {
22
+ kind: 'groups';
23
+ groups: string[];
11
24
  } | {
12
25
  kind: 'invalid';
13
26
  raw: string;
@@ -16,6 +29,10 @@ export type VisibilityResolution = {
16
29
  } | {
17
30
  kind: 'missing';
18
31
  };
32
+ export declare function isVisibilityAudience(value: unknown): value is VisibilityAudience;
19
33
  export declare function resolveVisibilityFor(node: MdxJsxElement): VisibilityResolution;
20
34
  export declare function isHiddenFromHumans(resolution: VisibilityResolution): boolean;
35
+ export declare function isHiddenFromAgents(resolution: VisibilityResolution): boolean;
36
+ export declare function toVisibilityAuthRule(resolution: VisibilityResolution): VisibilityAuthRule | undefined;
37
+ export declare function matchesVisibilityAuthRule(rule: VisibilityAuthRule, viewer: VisibilityViewer): boolean;
21
38
  export declare const remarkVisibilityForMarkdown: () => (tree: Root) => void;
@@ -5,17 +5,88 @@ export function isVisibilityElement(node) {
5
5
  function isMdxJsxElement(node) {
6
6
  return node.type === 'mdxJsxFlowElement' || node.type === 'mdxJsxTextElement';
7
7
  }
8
+ export const VISIBILITY_AUDIENCES = ['humans', 'agents', 'signed-in', 'signed-out'];
9
+ export const VISIBILITY_FOR_EXPECTED = '"humans", "agents", "signed-in", "signed-out", or { groups: [...] }';
10
+ export function isVisibilityAudience(value) {
11
+ return VISIBILITY_AUDIENCES.some((audience) => audience === value);
12
+ }
13
+ function expressionOf(value) {
14
+ var _a, _b;
15
+ const statement = (_b = (_a = value.data) === null || _a === void 0 ? void 0 : _a.estree) === null || _b === void 0 ? void 0 : _b.body[0];
16
+ return (statement === null || statement === void 0 ? void 0 : statement.type) === 'ExpressionStatement' ? statement.expression : undefined;
17
+ }
18
+ function foldString(node) {
19
+ var _a, _b, _c;
20
+ switch (node === null || node === void 0 ? void 0 : node.type) {
21
+ case 'Literal':
22
+ return typeof node.value === 'string' ? node.value : undefined;
23
+ case 'TemplateLiteral': {
24
+ let out = (_b = (_a = node.quasis[0]) === null || _a === void 0 ? void 0 : _a.value.cooked) !== null && _b !== void 0 ? _b : undefined;
25
+ for (const [index, expression] of node.expressions.entries()) {
26
+ const folded = foldString(expression);
27
+ const next = (_c = node.quasis[index + 1]) === null || _c === void 0 ? void 0 : _c.value.cooked;
28
+ if (out === undefined || folded === undefined || next == null)
29
+ return undefined;
30
+ out += folded + next;
31
+ }
32
+ return out;
33
+ }
34
+ case 'BinaryExpression': {
35
+ if (node.operator !== '+')
36
+ return undefined;
37
+ const left = foldString(node.left);
38
+ const right = foldString(node.right);
39
+ return left === undefined || right === undefined ? undefined : left + right;
40
+ }
41
+ default:
42
+ return undefined;
43
+ }
44
+ }
45
+ function resolveGroups(value) {
46
+ const expression = expressionOf(value);
47
+ if ((expression === null || expression === void 0 ? void 0 : expression.type) !== 'ObjectExpression' || expression.properties.length !== 1)
48
+ return undefined;
49
+ const [property] = expression.properties;
50
+ if ((property === null || property === void 0 ? void 0 : property.type) !== 'Property' || property.computed)
51
+ return undefined;
52
+ const key = property.key.type === 'Identifier' ? property.key.name : undefined;
53
+ const literalKey = property.key.type === 'Literal' ? property.key.value : undefined;
54
+ if ((key !== null && key !== void 0 ? key : literalKey) !== 'groups' || property.value.type !== 'ArrayExpression')
55
+ return undefined;
56
+ const groups = property.value.elements.map((element) => { var _a, _b; return (_b = (_a = foldString(element)) === null || _a === void 0 ? void 0 : _a.trim()) !== null && _b !== void 0 ? _b : ''; });
57
+ return groups.length > 0 && groups.every(Boolean) ? [...new Set(groups)] : undefined;
58
+ }
59
+ function mayOverrideFor(attr) {
60
+ if (attr.type !== 'mdxJsxExpressionAttribute')
61
+ return false;
62
+ const expression = expressionOf(attr);
63
+ const spread = (expression === null || expression === void 0 ? void 0 : expression.type) === 'ObjectExpression' && expression.properties.length === 1
64
+ ? expression.properties[0]
65
+ : undefined;
66
+ if ((spread === null || spread === void 0 ? void 0 : spread.type) !== 'SpreadElement' || spread.argument.type !== 'ObjectExpression')
67
+ return true;
68
+ return spread.argument.properties.some((property) => {
69
+ if (property.type !== 'Property' || property.computed)
70
+ return true;
71
+ const key = property.key.type === 'Identifier' ? property.key.name : undefined;
72
+ const literalKey = property.key.type === 'Literal' ? property.key.value : undefined;
73
+ return (key !== null && key !== void 0 ? key : literalKey) === 'for';
74
+ });
75
+ }
8
76
  export function resolveVisibilityFor(node) {
9
- var _a;
77
+ var _a, _b;
10
78
  let invalidRaw;
11
79
  let sawDynamic = false;
12
80
  let sawAttribute = false;
81
+ const lastFor = node.attributes.findLastIndex((attr) => attr.type === 'mdxJsxAttribute' && attr.name === 'for');
82
+ if (node.attributes.slice(lastFor + 1).some(mayOverrideFor))
83
+ return { kind: 'dynamic' };
13
84
  for (const attr of node.attributes) {
14
85
  if (attr.type !== 'mdxJsxAttribute' || attr.name !== 'for')
15
86
  continue;
16
87
  sawAttribute = true;
17
88
  if (typeof attr.value === 'string') {
18
- if (attr.value === 'humans' || attr.value === 'agents') {
89
+ if (isVisibilityAudience(attr.value)) {
19
90
  return { kind: 'audience', audience: attr.value };
20
91
  }
21
92
  invalidRaw !== null && invalidRaw !== void 0 ? invalidRaw : (invalidRaw = attr.value);
@@ -24,18 +95,32 @@ export function resolveVisibilityFor(node) {
24
95
  if (attr.value && typeof attr.value === 'object') {
25
96
  if ('value' in attr.value && typeof attr.value.value === 'string') {
26
97
  const raw = attr.value.value.trim();
98
+ const folded = foldString(expressionOf(attr.value));
99
+ if (folded !== undefined) {
100
+ if (isVisibilityAudience(folded))
101
+ return { kind: 'audience', audience: folded };
102
+ invalidRaw !== null && invalidRaw !== void 0 ? invalidRaw : (invalidRaw = folded);
103
+ continue;
104
+ }
27
105
  const quoted = raw.match(/^(["'`])((?:\\.|(?!\1)[^\\])*)\1$/);
28
106
  if (quoted) {
29
107
  const inner = (_a = quoted[2]) !== null && _a !== void 0 ? _a : '';
30
108
  const isTemplateWithInterpolation = quoted[1] === '`' && inner.includes('${');
31
109
  if (!isTemplateWithInterpolation) {
32
- if (inner === 'humans' || inner === 'agents') {
110
+ if (isVisibilityAudience(inner)) {
33
111
  return { kind: 'audience', audience: inner };
34
112
  }
35
113
  invalidRaw !== null && invalidRaw !== void 0 ? invalidRaw : (invalidRaw = inner);
36
114
  continue;
37
115
  }
38
116
  }
117
+ const groups = resolveGroups(attr.value);
118
+ if (groups)
119
+ return { kind: 'groups', groups };
120
+ if (((_b = expressionOf(attr.value)) === null || _b === void 0 ? void 0 : _b.type) === 'ObjectExpression' || raw.startsWith('{')) {
121
+ invalidRaw !== null && invalidRaw !== void 0 ? invalidRaw : (invalidRaw = raw);
122
+ continue;
123
+ }
39
124
  }
40
125
  sawDynamic = true;
41
126
  }
@@ -52,6 +137,8 @@ export function isHiddenFromHumans(resolution) {
52
137
  switch (resolution.kind) {
53
138
  case 'audience':
54
139
  return resolution.audience === 'agents';
140
+ case 'groups':
141
+ return false;
55
142
  case 'invalid':
56
143
  case 'missing':
57
144
  return true;
@@ -59,6 +146,34 @@ export function isHiddenFromHumans(resolution) {
59
146
  return false;
60
147
  }
61
148
  }
149
+ export function isHiddenFromAgents(resolution) {
150
+ switch (resolution.kind) {
151
+ case 'audience':
152
+ return resolution.audience === 'humans' || resolution.audience === 'signed-in';
153
+ case 'groups':
154
+ case 'invalid':
155
+ case 'dynamic':
156
+ case 'missing':
157
+ return true;
158
+ }
159
+ }
160
+ export function toVisibilityAuthRule(resolution) {
161
+ if (resolution.kind === 'groups')
162
+ return { groups: resolution.groups };
163
+ if (resolution.kind !== 'audience')
164
+ return undefined;
165
+ if (resolution.audience === 'signed-in' || resolution.audience === 'signed-out') {
166
+ return resolution.audience;
167
+ }
168
+ return undefined;
169
+ }
170
+ export function matchesVisibilityAuthRule(rule, viewer) {
171
+ if (rule === 'signed-in')
172
+ return viewer.signedIn;
173
+ if (rule === 'signed-out')
174
+ return !viewer.signedIn;
175
+ return viewer.signedIn && rule.groups.some((group) => viewer.groups.includes(group));
176
+ }
62
177
  // `export * from` is intentionally ignored: it exposes no statically-knowable
63
178
  // names and creates no page-local JSX bindings in MDX, so there is nothing to
64
179
  // collect.
@@ -163,9 +278,7 @@ function collectJsxUsage(nodes, insideHumans, hiddenNames, visibleNames) {
163
278
  if (isMdxJsxElement(node)) {
164
279
  if (node.name === 'Visibility') {
165
280
  const resolution = resolveVisibilityFor(node);
166
- const isHidden = resolution.kind === 'invalid' ||
167
- (resolution.kind === 'audience' && resolution.audience === 'humans');
168
- if (isHidden)
281
+ if (isHiddenFromAgents(resolution))
169
282
  childInsideHumans = true;
170
283
  }
171
284
  else {
@@ -206,15 +319,14 @@ function transformNode(node, esmToStrip) {
206
319
  }
207
320
  if (isMdxJsxElement(node) && node.name === 'Visibility') {
208
321
  const resolution = resolveVisibilityFor(node);
209
- if (resolution.kind === 'audience' && resolution.audience === 'humans') {
322
+ if (resolution.kind === 'invalid') {
323
+ console.warn(`<Visibility for="${resolution.raw}"> has an unknown audience — expected ${VISIBILITY_FOR_EXPECTED}. The content was removed from the markdown output.`);
210
324
  return [];
211
325
  }
212
- if (resolution.kind === 'audience' && resolution.audience === 'agents') {
213
- return transformChildren(node.children, esmToStrip);
214
- }
215
- if (resolution.kind === 'invalid') {
216
- console.warn(`<Visibility for="${resolution.raw}"> has an unknown audience — expected "humans" or "agents". The content was removed from the markdown output.`);
326
+ if (isHiddenFromAgents(resolution))
217
327
  return [];
328
+ if (resolution.kind === 'audience') {
329
+ return transformChildren(node.children, esmToStrip);
218
330
  }
219
331
  }
220
332
  if ('children' in node && Array.isArray(node.children)) {
@@ -1,6 +1,12 @@
1
- import { pageGroupsSchema } from '@mintlify/validation';
1
+ import * as v from 'valibot';
2
2
  export const WILDCARD_GROUP = '*';
3
- export const isPageGroups = (value) => pageGroupsSchema.safeParse(value).success;
3
+ const groupNameSchema = v.pipe(v.string(), v.minLength(1));
4
+ const groupRuleSchema = v.strictObject({
5
+ includes: v.optional(v.pipe(v.array(groupNameSchema), v.minLength(1))),
6
+ excludes: v.optional(v.pipe(v.array(groupNameSchema), v.check((excludes) => !excludes.includes(WILDCARD_GROUP)))),
7
+ });
8
+ const pageGroupsSchema = v.union([v.array(groupNameSchema), v.array(groupRuleSchema)]);
9
+ export const isPageGroups = (value) => v.is(pageGroupsSchema, value);
4
10
  const isStringArray = (groups) => groups.every((entry) => typeof entry === 'string');
5
11
  const DENY_ALL = { includes: [], excludes: [] };
6
12
  export function normalizeGroups(groups) {