@gradial/aci 0.1.52-rc.21 → 0.1.52-rc.22
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 +34 -4
- package/dist/cli/mintlify-render.d.mts +1 -0
- package/dist/cli/mintlify-render.mjs +8 -0
- package/dist/mintlify/blocks.d.ts +6 -0
- package/dist/mintlify/blocks.js +198 -0
- package/dist/mintlify/config.d.ts +3 -0
- package/dist/mintlify/config.js +77 -0
- package/dist/mintlify/index.d.ts +3 -0
- package/dist/mintlify/index.js +2 -0
- package/dist/mintlify/json.d.ts +8 -0
- package/dist/mintlify/json.js +37 -0
- package/dist/mintlify/materialize.d.ts +12 -0
- package/dist/mintlify/materialize.js +159 -0
- package/dist/mintlify/types.d.ts +69 -0
- package/dist/mintlify/types.js +1 -0
- package/dist/mintlify/validate.d.ts +7 -0
- package/dist/mintlify/validate.js +252 -0
- package/dist/react/VideoPlayer.d.ts +1 -1
- package/dist/react/index.d.ts +1 -1
- package/dist/testing/index.js +2 -2
- package/package.json +11 -7
- package/src/cli/mintlify-render.mjs +9 -0
- package/templates/astro/starter-content/src/fixtures/sections.ts +1 -1
- package/templates/common/.agents/skills/aci/SKILL.md +50 -0
- package/templates/common/.agents/skills/authoring/SKILL.md +4 -3
- package/templates/common/.agents/skills/migration/references/selector-map.md +1 -1
- package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_about_hero → 000000000000000000000000101}/asset.json +1 -1
- package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_home_hero → 000000000000000000000000102}/asset.json +1 -1
- package/templates/common/starter-content/.content/pages/404/_index.json +1 -1
- package/templates/common/starter-content/.content/pages/{home/_index.json → _index.json} +2 -2
- package/templates/common/starter-content/.content/pages/about/_index.json +1 -1
- package/templates/common/starter-content/.content/pages/error/_index.json +1 -1
- package/templates/common/starter-content/.content/patterns/components/button.json +2 -2
- package/templates/common/starter-content/.content/patterns/components/container.json +2 -2
- package/templates/common/starter-content/.content/patterns/components/feature_card.json +2 -2
- package/templates/common/starter-content/.content/patterns/components/feature_grid.json +2 -2
- package/templates/common/starter-content/.content/patterns/components/home_hero.json +2 -2
- package/templates/common/starter-content/.content/patterns/components/site-footer.json +2 -2
- package/templates/common/starter-content/.content/patterns/components/site-navigation.json +2 -2
- package/templates/common/starter-content/.content/patterns/components/stats_bar.json +2 -2
- package/templates/common/starter-content/.content/patterns/layouts/default.json +2 -2
- package/templates/common/starter-content/.content/patterns/components/personalization_choice.json +0 -42
- /package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_home_hero → 000000000000000000000000101}/editorial.json +0 -0
- /package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_about_hero → 000000000000000000000000101}/governance.json +0 -0
- /package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_home_hero → 000000000000000000000000101}/versions/v0001.json +0 -0
- /package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_about_hero → 000000000000000000000000102}/editorial.json +0 -0
- /package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_home_hero → 000000000000000000000000102}/governance.json +0 -0
- /package/templates/common/starter-content/.content/dam/folders/seed/{ast_site_about_hero → 000000000000000000000000102}/versions/v0001.json +0 -0
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
export type MintlifyJSONValue = null | boolean | number | string | MintlifyJSONValue[] | {
|
|
2
|
+
[key: string]: MintlifyJSONValue;
|
|
3
|
+
};
|
|
4
|
+
export interface MintlifyNavigationGroup {
|
|
5
|
+
group: string;
|
|
6
|
+
pages: string[];
|
|
7
|
+
}
|
|
8
|
+
/** Native Mintlify docs.json configuration from `.content/config/mintlify.json`. */
|
|
9
|
+
export type MintlifySite = Record<string, MintlifyJSONValue>;
|
|
10
|
+
export interface MintlifyBlock {
|
|
11
|
+
$type: 'component';
|
|
12
|
+
id: string;
|
|
13
|
+
component: 'mintlify.markdown' | 'mintlify.mdx' | 'mintlify.anchor' | 'mintlify.steps' | 'mintlify.step' | 'mintlify.card-group' | 'mintlify.card' | 'mintlify.accordion-group' | 'mintlify.accordion' | 'mintlify.callout' | 'mintlify.tabs' | 'mintlify.tab' | 'mintlify.snippet-ref';
|
|
14
|
+
props: {
|
|
15
|
+
source?: string;
|
|
16
|
+
name?: string;
|
|
17
|
+
variant?: 'info' | 'warning' | 'note' | 'tip' | 'check';
|
|
18
|
+
children?: MintlifyBlock[];
|
|
19
|
+
[key: string]: MintlifyJSONValue | MintlifyBlock[] | undefined;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
export interface MintlifyDocument {
|
|
23
|
+
$type: 'page';
|
|
24
|
+
id: string;
|
|
25
|
+
status: string;
|
|
26
|
+
layout: string;
|
|
27
|
+
path: string;
|
|
28
|
+
metadata: {
|
|
29
|
+
title: string;
|
|
30
|
+
description?: string;
|
|
31
|
+
mintlify?: {
|
|
32
|
+
sidebarTitle?: string;
|
|
33
|
+
icon?: string;
|
|
34
|
+
frontmatter?: Record<string, MintlifyJSONValue>;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
regions: {
|
|
38
|
+
main: MintlifyBlock[];
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
export interface MintlifySnippet {
|
|
42
|
+
$type: 'fragment';
|
|
43
|
+
id: string;
|
|
44
|
+
path: string;
|
|
45
|
+
block: MintlifyBlock;
|
|
46
|
+
}
|
|
47
|
+
export interface MintlifyConfigFragment {
|
|
48
|
+
$type: 'mintlify.config-fragment';
|
|
49
|
+
schemaVersion: 1;
|
|
50
|
+
path: string;
|
|
51
|
+
value: MintlifyJSONValue;
|
|
52
|
+
}
|
|
53
|
+
export interface MintlifyAPISpec {
|
|
54
|
+
$type: 'mintlify.api-spec';
|
|
55
|
+
schemaVersion: 1;
|
|
56
|
+
path: string;
|
|
57
|
+
format: 'openapi' | 'asyncapi' | 'graphql';
|
|
58
|
+
source: string;
|
|
59
|
+
}
|
|
60
|
+
export interface MintlifySource {
|
|
61
|
+
site: MintlifySite;
|
|
62
|
+
documents: MintlifyDocument[];
|
|
63
|
+
snippets?: MintlifySnippet[];
|
|
64
|
+
configFragments?: MintlifyConfigFragment[];
|
|
65
|
+
apiSpecs?: MintlifyAPISpec[];
|
|
66
|
+
}
|
|
67
|
+
export interface MaterializeMintlifySiteOptions extends MintlifySource {
|
|
68
|
+
outputDir: string;
|
|
69
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { MintlifyAPISpec, MintlifyConfigFragment, MintlifyDocument, MintlifyJSONValue, MintlifySite, MintlifySnippet } from './types.js';
|
|
2
|
+
export declare function validateSource(site: MintlifyJSONValue, documents: MintlifyDocument[], snippets: MintlifySnippet[], apiSpecs: MintlifyAPISpec[]): void;
|
|
3
|
+
export declare function validateSite(value: unknown, label: string): MintlifySite;
|
|
4
|
+
export declare function validateDocument(value: unknown, label: string, sourcePath?: string): MintlifyDocument;
|
|
5
|
+
export declare function validateSnippet(value: unknown, label: string, sourcePath?: string): MintlifySnippet;
|
|
6
|
+
export declare function validateConfigFragment(value: unknown, label: string): MintlifyConfigFragment;
|
|
7
|
+
export declare function validateAPISpec(value: unknown, label: string): MintlifyAPISpec;
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import { validateBlock, validateSnippetReferences } from './blocks.js';
|
|
2
|
+
import { cleanDocumentPath, cleanFilePath, isExternalReference, isMintlifyJSONValue, isObject, nonEmptyString, } from './json.js';
|
|
3
|
+
const CONFIG_FRAGMENT_SCHEMA_VERSION = 1;
|
|
4
|
+
const API_SPEC_SCHEMA_VERSION = 1;
|
|
5
|
+
export function validateSource(site, documents, snippets, apiSpecs) {
|
|
6
|
+
const paths = new Set();
|
|
7
|
+
for (const document of documents) {
|
|
8
|
+
if (paths.has(document.path))
|
|
9
|
+
throw new Error(`ACI Mintlify document path is duplicated: ${document.path}`);
|
|
10
|
+
paths.add(document.path);
|
|
11
|
+
}
|
|
12
|
+
const navigated = new Set();
|
|
13
|
+
const navigation = isObject(site) ? site.navigation : undefined;
|
|
14
|
+
validateNavigationPartitions(navigation);
|
|
15
|
+
for (const page of navigationPages(navigation)) {
|
|
16
|
+
// Links are valid Mintlify navigation items but are not ACI documents.
|
|
17
|
+
if (isExternalReference(page))
|
|
18
|
+
continue;
|
|
19
|
+
const normalized = cleanDocumentPath(page);
|
|
20
|
+
if (!normalized || normalized !== page)
|
|
21
|
+
throw new Error(`ACI Mintlify navigation page is invalid: ${page}`);
|
|
22
|
+
if (!paths.has(page))
|
|
23
|
+
throw new Error(`ACI Mintlify navigation references missing document: ${page}`);
|
|
24
|
+
if (navigated.has(page))
|
|
25
|
+
throw new Error(`ACI Mintlify navigation references document more than once: ${page}`);
|
|
26
|
+
navigated.add(page);
|
|
27
|
+
}
|
|
28
|
+
validateRedirects(isObject(site) ? site.redirects : undefined, paths);
|
|
29
|
+
validateSnippetReferences(documents, snippets);
|
|
30
|
+
validateAPISpecReferences(site, apiSpecs);
|
|
31
|
+
}
|
|
32
|
+
export function validateSite(value, label) {
|
|
33
|
+
if (!isObject(value) || !isMintlifyJSONValue(value)) {
|
|
34
|
+
throw new Error(`ACI Mintlify site is invalid: ${label}`);
|
|
35
|
+
}
|
|
36
|
+
if ('$schema' in value && value.$schema !== 'https://mintlify.com/docs.json') {
|
|
37
|
+
throw new Error(`ACI Mintlify site has an unsupported docs schema: ${label}`);
|
|
38
|
+
}
|
|
39
|
+
return value;
|
|
40
|
+
}
|
|
41
|
+
export function validateDocument(value, label, sourcePath) {
|
|
42
|
+
const metadata = isObject(value) && isObject(value.metadata) ? value.metadata : undefined;
|
|
43
|
+
const regions = isObject(value) && isObject(value.regions) ? value.regions : undefined;
|
|
44
|
+
if (!isObject(value) || value.$type !== 'page' || !nonEmptyString(value.id) || !nonEmptyString(value.status) || !nonEmptyString(value.layout) || !nonEmptyString(sourcePath) || !metadata || !nonEmptyString(metadata.title) || !regions || !Array.isArray(regions.main)) {
|
|
45
|
+
throw new Error(`ACI Mintlify document is invalid: ${label}`);
|
|
46
|
+
}
|
|
47
|
+
const documentPath = cleanDocumentPath(sourcePath);
|
|
48
|
+
if (!documentPath || documentPath !== sourcePath)
|
|
49
|
+
throw new Error(`ACI Mintlify document path is invalid: ${sourcePath}`);
|
|
50
|
+
const ids = new Set();
|
|
51
|
+
const blocks = regions.main.map((block, index) => validateBlock(block, `${label}.regions.main[${index}]`, ids));
|
|
52
|
+
const renderer = isObject(metadata.mintlify) ? metadata.mintlify : {};
|
|
53
|
+
return {
|
|
54
|
+
$type: 'page', id: value.id, status: value.status, layout: value.layout, path: documentPath,
|
|
55
|
+
metadata: { title: metadata.title,
|
|
56
|
+
...(nonEmptyString(metadata.description) ? { description: metadata.description } : {}),
|
|
57
|
+
mintlify: {
|
|
58
|
+
...(nonEmptyString(renderer.sidebarTitle) ? { sidebarTitle: renderer.sidebarTitle } : {}),
|
|
59
|
+
...(nonEmptyString(renderer.icon) ? { icon: renderer.icon } : {}),
|
|
60
|
+
...(validFrontmatter(renderer.frontmatter) ? { frontmatter: renderer.frontmatter } : {}),
|
|
61
|
+
},
|
|
62
|
+
}, regions: { main: blocks },
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
export function validateSnippet(value, label, sourcePath) {
|
|
66
|
+
if (!isObject(value) || value.$type !== 'fragment' || !nonEmptyString(value.id) || !nonEmptyString(sourcePath) || !isObject(value.block)) {
|
|
67
|
+
throw new Error(`ACI Mintlify snippet is invalid: ${label}`);
|
|
68
|
+
}
|
|
69
|
+
const snippetPath = cleanFilePath(sourcePath, '.mdx');
|
|
70
|
+
if (!snippetPath || snippetPath !== sourcePath)
|
|
71
|
+
throw new Error(`ACI Mintlify snippet path is invalid: ${sourcePath}`);
|
|
72
|
+
const ids = new Set();
|
|
73
|
+
return {
|
|
74
|
+
$type: 'fragment', id: value.id,
|
|
75
|
+
path: snippetPath, block: validateBlock(value.block, `${label}.block`, ids),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
export function validateConfigFragment(value, label) {
|
|
79
|
+
if (!isObject(value) || value.$type !== 'mintlify.config-fragment' || value.schemaVersion !== CONFIG_FRAGMENT_SCHEMA_VERSION || !nonEmptyString(value.path) || !isMintlifyJSONValue(value.value)) {
|
|
80
|
+
throw new Error(`ACI Mintlify config fragment is invalid: ${label}`);
|
|
81
|
+
}
|
|
82
|
+
const fragmentPath = cleanFilePath(value.path, '.json');
|
|
83
|
+
if (!fragmentPath || fragmentPath !== value.path || fragmentPath === 'docs.json')
|
|
84
|
+
throw new Error(`ACI Mintlify config fragment path is invalid: ${value.path}`);
|
|
85
|
+
return { $type: 'mintlify.config-fragment', schemaVersion: CONFIG_FRAGMENT_SCHEMA_VERSION, path: fragmentPath, value: value.value };
|
|
86
|
+
}
|
|
87
|
+
export function validateAPISpec(value, label) {
|
|
88
|
+
if (!isObject(value) || value.$type !== 'mintlify.api-spec' || value.schemaVersion !== API_SPEC_SCHEMA_VERSION || !nonEmptyString(value.path) || !['openapi', 'asyncapi', 'graphql'].includes(String(value.format)) || !nonEmptyString(value.source)) {
|
|
89
|
+
throw new Error(`ACI Mintlify API specification is invalid: ${label}`);
|
|
90
|
+
}
|
|
91
|
+
const sourcePath = value.path;
|
|
92
|
+
const extensions = value.format === 'graphql' ? ['.graphql', '.gql', '.json'] : ['.json', '.yaml', '.yml'];
|
|
93
|
+
const specPath = extensions.map((extension) => cleanFilePath(sourcePath, extension)).find(Boolean) ?? '';
|
|
94
|
+
if (!specPath || specPath !== sourcePath)
|
|
95
|
+
throw new Error(`ACI Mintlify API specification path is invalid: ${sourcePath}`);
|
|
96
|
+
return {
|
|
97
|
+
$type: 'mintlify.api-spec',
|
|
98
|
+
schemaVersion: API_SPEC_SCHEMA_VERSION,
|
|
99
|
+
path: specPath,
|
|
100
|
+
format: value.format,
|
|
101
|
+
source: value.source,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function validFrontmatter(value) {
|
|
105
|
+
if (value === undefined)
|
|
106
|
+
return false;
|
|
107
|
+
if (!isObject(value))
|
|
108
|
+
throw new Error('ACI Mintlify document frontmatter is invalid');
|
|
109
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
110
|
+
if (!/^[A-Za-z][A-Za-z0-9_-]*$/.test(key) || !isMintlifyJSONValue(entry)) {
|
|
111
|
+
throw new Error('ACI Mintlify document frontmatter is invalid');
|
|
112
|
+
}
|
|
113
|
+
if (['title', 'description', 'sidebarTitle', 'icon'].includes(key))
|
|
114
|
+
throw new Error(`ACI Mintlify document frontmatter key is reserved: ${key}`);
|
|
115
|
+
}
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
function validateRedirects(value, documentPaths) {
|
|
119
|
+
if (value === undefined)
|
|
120
|
+
return;
|
|
121
|
+
if (!Array.isArray(value))
|
|
122
|
+
throw new Error('ACI Mintlify redirects are invalid');
|
|
123
|
+
const redirects = new Map();
|
|
124
|
+
const routes = new Set([...documentPaths].map((documentPath) => `/${documentPath}`));
|
|
125
|
+
for (const entry of value) {
|
|
126
|
+
if (!isObject(entry) || !nonEmptyString(entry.source) || !nonEmptyString(entry.destination) || (entry.permanent !== undefined && typeof entry.permanent !== 'boolean')) {
|
|
127
|
+
throw new Error('ACI Mintlify redirect is invalid');
|
|
128
|
+
}
|
|
129
|
+
if (!entry.source.startsWith('/') || entry.source.includes('?') || entry.source.includes('#')) {
|
|
130
|
+
throw new Error(`ACI Mintlify redirect source is invalid: ${entry.source}`);
|
|
131
|
+
}
|
|
132
|
+
if (!entry.destination.startsWith('/') && !isExternalReference(entry.destination)) {
|
|
133
|
+
throw new Error(`ACI Mintlify redirect destination is invalid: ${entry.destination}`);
|
|
134
|
+
}
|
|
135
|
+
if (redirects.has(entry.source))
|
|
136
|
+
throw new Error(`ACI Mintlify redirect source is duplicated: ${entry.source}`);
|
|
137
|
+
if (!entry.source.includes('*') && !entry.source.includes(':') && routes.has(trimRouteSlash(entry.source))) {
|
|
138
|
+
throw new Error(`ACI Mintlify redirect source collides with a document: ${entry.source}`);
|
|
139
|
+
}
|
|
140
|
+
redirects.set(entry.source, entry.destination);
|
|
141
|
+
}
|
|
142
|
+
for (const [source, destination] of redirects) {
|
|
143
|
+
if (isExternalReference(destination) || destination.includes('*') || destination.includes(':'))
|
|
144
|
+
continue;
|
|
145
|
+
const destinationPath = trimRouteSlash(destination.split(/[?#]/, 1)[0]);
|
|
146
|
+
if (!routes.has(destinationPath) && !redirects.has(destinationPath)) {
|
|
147
|
+
throw new Error(`ACI Mintlify redirect destination is missing: ${destination}`);
|
|
148
|
+
}
|
|
149
|
+
const seen = new Set([source]);
|
|
150
|
+
let next = destinationPath;
|
|
151
|
+
while (redirects.has(next)) {
|
|
152
|
+
if (seen.has(next))
|
|
153
|
+
throw new Error(`ACI Mintlify redirect cycle includes: ${next}`);
|
|
154
|
+
seen.add(next);
|
|
155
|
+
const target = redirects.get(next);
|
|
156
|
+
if (isExternalReference(target) || target.includes('*') || target.includes(':'))
|
|
157
|
+
break;
|
|
158
|
+
next = trimRouteSlash(target.split(/[?#]/, 1)[0]);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
function trimRouteSlash(value) {
|
|
163
|
+
return value.length > 1 ? value.replace(/\/+$/, '') : value;
|
|
164
|
+
}
|
|
165
|
+
function validateAPISpecReferences(site, specs) {
|
|
166
|
+
const byPath = new Map();
|
|
167
|
+
for (const spec of specs) {
|
|
168
|
+
if (byPath.has(spec.path))
|
|
169
|
+
throw new Error(`ACI Mintlify API specification path is duplicated: ${spec.path}`);
|
|
170
|
+
byPath.set(spec.path, spec);
|
|
171
|
+
}
|
|
172
|
+
const visit = (value) => {
|
|
173
|
+
if (Array.isArray(value)) {
|
|
174
|
+
for (const child of value)
|
|
175
|
+
visit(child);
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
if (!isObject(value))
|
|
179
|
+
return;
|
|
180
|
+
for (const [key, child] of Object.entries(value)) {
|
|
181
|
+
if (['openapi', 'asyncapi', 'graphql'].includes(key)) {
|
|
182
|
+
const references = typeof child === 'string' ? [child] : Array.isArray(child) ? child.filter((entry) => typeof entry === 'string') : [];
|
|
183
|
+
for (const reference of references) {
|
|
184
|
+
if (isExternalReference(reference))
|
|
185
|
+
continue;
|
|
186
|
+
const spec = byPath.get(reference);
|
|
187
|
+
if (!spec || spec.format !== key)
|
|
188
|
+
throw new Error(`ACI Mintlify API specification reference is missing or has the wrong format: ${reference}`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
visit(child);
|
|
192
|
+
}
|
|
193
|
+
};
|
|
194
|
+
visit(site);
|
|
195
|
+
}
|
|
196
|
+
function navigationPages(value) {
|
|
197
|
+
if (!isObject(value))
|
|
198
|
+
return [];
|
|
199
|
+
const pages = [];
|
|
200
|
+
visitNavigation(value, pages);
|
|
201
|
+
return pages;
|
|
202
|
+
}
|
|
203
|
+
function visitNavigation(value, pages) {
|
|
204
|
+
if (Array.isArray(value)) {
|
|
205
|
+
for (const item of value)
|
|
206
|
+
visitNavigation(item, pages);
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
if (!isObject(value))
|
|
210
|
+
return;
|
|
211
|
+
for (const [key, child] of Object.entries(value)) {
|
|
212
|
+
if (key === 'pages' && Array.isArray(child)) {
|
|
213
|
+
for (const item of child) {
|
|
214
|
+
if (typeof item === 'string')
|
|
215
|
+
pages.push(item);
|
|
216
|
+
else
|
|
217
|
+
visitNavigation(item, pages);
|
|
218
|
+
}
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
visitNavigation(child, pages);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
function validateNavigationPartitions(value) {
|
|
225
|
+
if (Array.isArray(value)) {
|
|
226
|
+
for (const child of value)
|
|
227
|
+
validateNavigationPartitions(child);
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
if (!isObject(value))
|
|
231
|
+
return;
|
|
232
|
+
for (const [key, child] of Object.entries(value)) {
|
|
233
|
+
if ((key === 'languages' || key === 'versions') && Array.isArray(child)) {
|
|
234
|
+
const identityKey = key === 'languages' ? 'language' : 'version';
|
|
235
|
+
const identities = new Set();
|
|
236
|
+
let defaults = 0;
|
|
237
|
+
for (const entry of child) {
|
|
238
|
+
if (!isObject(entry) || !nonEmptyString(entry[identityKey]))
|
|
239
|
+
throw new Error(`ACI Mintlify ${key} navigation is invalid`);
|
|
240
|
+
const identity = entry[identityKey];
|
|
241
|
+
if (identities.has(identity))
|
|
242
|
+
throw new Error(`ACI Mintlify ${key} navigation is duplicated: ${identity}`);
|
|
243
|
+
identities.add(identity);
|
|
244
|
+
if (entry.default === true)
|
|
245
|
+
defaults += 1;
|
|
246
|
+
}
|
|
247
|
+
if (defaults > 1)
|
|
248
|
+
throw new Error(`ACI Mintlify navigation has multiple default ${key}`);
|
|
249
|
+
}
|
|
250
|
+
validateNavigationPartitions(child);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
@@ -20,10 +20,10 @@ export declare function VideoPlayer({ video, ...attrs }: VideoPlayerProps): impo
|
|
|
20
20
|
style?: import("react").CSSProperties | undefined;
|
|
21
21
|
dir?: string | undefined | undefined;
|
|
22
22
|
hidden?: boolean | undefined | undefined;
|
|
23
|
+
children?: import("react").ReactNode;
|
|
23
24
|
dangerouslySetInnerHTML?: {
|
|
24
25
|
__html: string | TrustedHTML;
|
|
25
26
|
} | undefined | undefined;
|
|
26
|
-
children?: import("react").ReactNode;
|
|
27
27
|
className?: string | undefined | undefined;
|
|
28
28
|
crossOrigin?: "" | "anonymous" | "use-credentials" | undefined;
|
|
29
29
|
defaultChecked?: boolean | undefined | undefined;
|
package/dist/react/index.d.ts
CHANGED
|
@@ -29,10 +29,10 @@ export declare function Image({ image, value, ...attrs }: ImageProps): import("r
|
|
|
29
29
|
style?: import("react").CSSProperties | undefined;
|
|
30
30
|
dir?: string | undefined | undefined;
|
|
31
31
|
hidden?: boolean | undefined | undefined;
|
|
32
|
+
children?: ReactNode;
|
|
32
33
|
dangerouslySetInnerHTML?: {
|
|
33
34
|
__html: string | TrustedHTML;
|
|
34
35
|
} | undefined | undefined;
|
|
35
|
-
children?: ReactNode;
|
|
36
36
|
className?: string | undefined | undefined;
|
|
37
37
|
crossOrigin?: "" | "anonymous" | "use-credentials" | undefined;
|
|
38
38
|
fetchPriority?: "high" | "low" | "auto" | undefined | undefined;
|
package/dist/testing/index.js
CHANGED
|
@@ -53,9 +53,9 @@ export class FixtureContentProvider {
|
|
|
53
53
|
return [...this.pages.entries()]
|
|
54
54
|
.sort(([a], [b]) => a.localeCompare(b))
|
|
55
55
|
.map(([routePath, page]) => ({
|
|
56
|
-
slug: routePath === '/' ? '
|
|
56
|
+
slug: routePath === '/' ? '' : routePath.replace(/^\//, ''),
|
|
57
57
|
path: routePath,
|
|
58
|
-
payloadRef:
|
|
58
|
+
payloadRef: routePath === '/' ? 'routes/index.json' : `routes/${routePath.replace(/^\//, '')}.json`,
|
|
59
59
|
digest: '',
|
|
60
60
|
}));
|
|
61
61
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gradial/aci",
|
|
3
|
-
"version": "0.1.52-rc.
|
|
3
|
+
"version": "0.1.52-rc.22",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "https://github.com/gradial/bare-metal-go.git",
|
|
@@ -45,6 +45,10 @@
|
|
|
45
45
|
"types": "./dist/edge/expression-capabilities.v1.d.ts",
|
|
46
46
|
"import": "./dist/edge/expression-capabilities.v1.js"
|
|
47
47
|
},
|
|
48
|
+
"./mintlify": {
|
|
49
|
+
"types": "./dist/mintlify/index.d.ts",
|
|
50
|
+
"import": "./dist/mintlify/index.js"
|
|
51
|
+
},
|
|
48
52
|
"./providers/file": {
|
|
49
53
|
"types": "./dist/providers/file.d.ts",
|
|
50
54
|
"import": "./dist/providers/file.js"
|
|
@@ -155,11 +159,11 @@
|
|
|
155
159
|
"zod": "^4.0.0"
|
|
156
160
|
},
|
|
157
161
|
"optionalDependencies": {
|
|
158
|
-
"@gradial/aci-cli-darwin-arm64": "0.1.52-rc.
|
|
159
|
-
"@gradial/aci-cli-darwin-x64": "0.1.52-rc.
|
|
160
|
-
"@gradial/aci-cli-linux-arm64": "0.1.52-rc.
|
|
161
|
-
"@gradial/aci-cli-linux-x64": "0.1.52-rc.
|
|
162
|
-
"@gradial/aci-cli-win32-arm64": "0.1.52-rc.
|
|
163
|
-
"@gradial/aci-cli-win32-x64": "0.1.52-rc.
|
|
162
|
+
"@gradial/aci-cli-darwin-arm64": "0.1.52-rc.22",
|
|
163
|
+
"@gradial/aci-cli-darwin-x64": "0.1.52-rc.22",
|
|
164
|
+
"@gradial/aci-cli-linux-arm64": "0.1.52-rc.22",
|
|
165
|
+
"@gradial/aci-cli-linux-x64": "0.1.52-rc.22",
|
|
166
|
+
"@gradial/aci-cli-win32-arm64": "0.1.52-rc.22",
|
|
167
|
+
"@gradial/aci-cli-win32-x64": "0.1.52-rc.22"
|
|
164
168
|
}
|
|
165
169
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { loadCompiledMintlifySource, materializeMintlifySite } from '../../dist/mintlify/index.js';
|
|
3
|
+
|
|
4
|
+
const [sourceArg, compiledArg, outputArg] = process.argv.slice(2);
|
|
5
|
+
if (!sourceArg || !compiledArg || !outputArg) {
|
|
6
|
+
throw new Error('Mintlify renderer requires content, compiled, and output directories');
|
|
7
|
+
}
|
|
8
|
+
const source = await loadCompiledMintlifySource(path.resolve(sourceArg), path.resolve(compiledArg));
|
|
9
|
+
await materializeMintlifySite({ ...source, outputDir: path.resolve(outputArg) });
|
|
@@ -25,7 +25,7 @@ export const sectionStoryFixtures: SectionStoryFixture[] = [
|
|
|
25
25
|
ctaHref: '/docs',
|
|
26
26
|
image: {
|
|
27
27
|
$type: 'gradial.image',
|
|
28
|
-
assetId: '
|
|
28
|
+
assetId: '3Ih26etWBTYfnAd0EjD0pP2h902',
|
|
29
29
|
versionId: 'v0001',
|
|
30
30
|
alt: 'Seattle skyline at dusk',
|
|
31
31
|
sources: [
|
|
@@ -152,6 +152,56 @@ Optional (disabled by default):
|
|
|
152
152
|
|
|
153
153
|
## Troubleshooting
|
|
154
154
|
|
|
155
|
+
### Deploying a starter to a hosted Vercel tenant
|
|
156
|
+
|
|
157
|
+
Run the CLI from the starter repository root (where `.aci.yaml` lives), or
|
|
158
|
+
pass `--site-dir .` from that directory. Do not pass an absolute site path
|
|
159
|
+
from another working directory: older CLI versions can serialize it as a
|
|
160
|
+
`../../../tmp/...` source folder, which makes the server-side build fail with
|
|
161
|
+
a generic HTTP 500. The source ref must also be a pushed, cloneable branch;
|
|
162
|
+
`ref: HEAD` from a detached worktree is not cloneable by the build service.
|
|
163
|
+
|
|
164
|
+
The hosted publish sequence is:
|
|
165
|
+
|
|
166
|
+
1. `GRADIAL_CODE_SOURCE_TOKEN="$(gh auth token)" aci code-build --site-dir . --branch <test-branch> ...`
|
|
167
|
+
2. `aci branch land <test-branch>` to move the artifact link to `main`.
|
|
168
|
+
3. Promote `/config/site.json` and the content paths needed by the release.
|
|
169
|
+
4. Run `aci release publish --activate ...`.
|
|
170
|
+
|
|
171
|
+
Match the tenant rendering mode to the starter's actual route capability. A
|
|
172
|
+
Next starter with `dynamicParams = false` and no release-scoped runtime route
|
|
173
|
+
is an SSG starter and must use `rendering.mode = "ssg"`; `ssr` is only valid
|
|
174
|
+
when the frontend can resolve arbitrary host release routes at request time.
|
|
175
|
+
A mismatch can build successfully but then fail SSG rendering or return a
|
|
176
|
+
live Next 404 after the host rewrites a CMS page.
|
|
177
|
+
|
|
178
|
+
Injected platform functions must be dependency-closed inside their own
|
|
179
|
+
`.vercel/output/functions/<name>.func` mount. A prebuilt Vercel deploy does not
|
|
180
|
+
install a function-local `package.json` after upload. Native dependencies such
|
|
181
|
+
as `sharp` therefore belong to the host-function artifact, built for Vercel's
|
|
182
|
+
Linux/x64 runtime and injected beside the handler; never add them to the
|
|
183
|
+
starter's `package.json` merely to make a platform function resolve.
|
|
184
|
+
|
|
185
|
+
Publish validates `refs/heads/live`, not only `main`. If `main` deletes a
|
|
186
|
+
stale incompatible page or fragment that was previously promoted, promote
|
|
187
|
+
that same path from `main` with `aci promote --path ... --yes`; because the
|
|
188
|
+
source path is absent, the promote records a delete on `live`. This is the
|
|
189
|
+
API-safe way to remove old live content—direct writes to `live` are forbidden.
|
|
190
|
+
|
|
191
|
+
The same rule applies to breaking DAM identifier changes: every
|
|
192
|
+
`dam.assetRef` in `live` is resolved during publish, so one legacy identifier
|
|
193
|
+
blocks the release. Update the reference on a candidate branch through
|
|
194
|
+
`aci content push`, land it, and promote that exact content path before
|
|
195
|
+
publishing again. Do not weaken identifier validation or reactivate an old
|
|
196
|
+
release to bypass the content migration.
|
|
197
|
+
|
|
198
|
+
Legacy assets themselves are replaced through the product API, not rewritten
|
|
199
|
+
in storage: download or retain the needed source bytes, upload them again so
|
|
200
|
+
DAM creates fresh canonical IDs, approve them, replace every content reference,
|
|
201
|
+
then land, promote, and publish the affected paths. This is the supported
|
|
202
|
+
breaking cutover for pre-public tenants; there is no `ast_` alias or bulk
|
|
203
|
+
object-store migration path.
|
|
204
|
+
|
|
155
205
|
### "Unknown component" error during content compile
|
|
156
206
|
|
|
157
207
|
The content JSON references a `component` name that is not in the contract
|
|
@@ -78,12 +78,13 @@ Pages map to URL routes by their folder path under `/pages/`:
|
|
|
78
78
|
|
|
79
79
|
| Page Path | Route |
|
|
80
80
|
|-----------|-------|
|
|
81
|
-
| `/pages/
|
|
81
|
+
| `/pages/_index.json` | `/` |
|
|
82
82
|
| `/pages/about/_index.json` | `/about` |
|
|
83
83
|
| `/pages/products/_index.json` | `/products` |
|
|
84
84
|
| `/pages/products/shoes/_index.json` | `/products/shoes` |
|
|
85
85
|
|
|
86
|
-
The
|
|
86
|
+
The empty slug is the site root. Every named folder maps directly, including
|
|
87
|
+
`/pages/home/_index.json` at `/home`.
|
|
87
88
|
|
|
88
89
|
### Content Rules
|
|
89
90
|
|
|
@@ -486,7 +487,7 @@ framework.
|
|
|
486
487
|
#### 5. Add content
|
|
487
488
|
|
|
488
489
|
```json
|
|
489
|
-
// .content/pages/
|
|
490
|
+
// .content/pages/_index.json (inside regions.main)
|
|
490
491
|
{
|
|
491
492
|
"$type": "component",
|
|
492
493
|
"id": "features",
|
|
@@ -13,7 +13,7 @@ Location: `artifacts/source-vs-target/selector-map.json`
|
|
|
13
13
|
"targetUrl": "http://localhost:3000/",
|
|
14
14
|
"breakpoints": [360, 768, 1024, 1280, 1400],
|
|
15
15
|
"entries": {
|
|
16
|
-
"content/pages/
|
|
16
|
+
"content/pages/_index.json blocks[\"home-hero\"]": {
|
|
17
17
|
"source": ".home-hero",
|
|
18
18
|
"target": ".home-hero",
|
|
19
19
|
"viewport": "both",
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"status": "published",
|
|
5
5
|
"layout": "default",
|
|
6
6
|
"metadata": {
|
|
7
|
-
"title": "Meridian
|
|
7
|
+
"title": "Meridian — Global Satellite Internet",
|
|
8
8
|
"description": "Connect from anywhere on Earth. Low-latency satellite internet for homes, businesses, and beyond.",
|
|
9
9
|
"canonical": "https://www.meridian.local/"
|
|
10
10
|
},
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"ctaHref": "/plans/",
|
|
23
23
|
"image": {
|
|
24
24
|
"$type": "dam.assetRef",
|
|
25
|
-
"assetId": "
|
|
25
|
+
"assetId": "000000000000000000000000101",
|
|
26
26
|
"alt": "Light abstract hero background with satellite constellation"
|
|
27
27
|
}
|
|
28
28
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$type": "componentPattern",
|
|
3
|
-
"buildId": "
|
|
4
|
-
"codeDigest": "sha256:
|
|
3
|
+
"buildId": "codebuild_01a05a33-bcc6-76ac-95bf-0c35b4c55280",
|
|
4
|
+
"codeDigest": "sha256:a19097814cad924bba8b584241b77f19d40c1c70012603e0faf9710853438015",
|
|
5
5
|
"name": "button",
|
|
6
6
|
"schema": {
|
|
7
7
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$type": "componentPattern",
|
|
3
|
-
"buildId": "
|
|
4
|
-
"codeDigest": "sha256:
|
|
3
|
+
"buildId": "codebuild_01a05a33-bcc6-76ac-95bf-0c35b4c55280",
|
|
4
|
+
"codeDigest": "sha256:a19097814cad924bba8b584241b77f19d40c1c70012603e0faf9710853438015",
|
|
5
5
|
"name": "container",
|
|
6
6
|
"schema": {
|
|
7
7
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$type": "componentPattern",
|
|
3
|
-
"buildId": "
|
|
4
|
-
"codeDigest": "sha256:
|
|
3
|
+
"buildId": "codebuild_01a05a33-bcc6-76ac-95bf-0c35b4c55280",
|
|
4
|
+
"codeDigest": "sha256:a19097814cad924bba8b584241b77f19d40c1c70012603e0faf9710853438015",
|
|
5
5
|
"name": "feature_card",
|
|
6
6
|
"schema": {
|
|
7
7
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$type": "componentPattern",
|
|
3
|
-
"buildId": "
|
|
4
|
-
"codeDigest": "sha256:
|
|
3
|
+
"buildId": "codebuild_01a05a33-bcc6-76ac-95bf-0c35b4c55280",
|
|
4
|
+
"codeDigest": "sha256:a19097814cad924bba8b584241b77f19d40c1c70012603e0faf9710853438015",
|
|
5
5
|
"name": "feature_grid",
|
|
6
6
|
"schema": {
|
|
7
7
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$type": "componentPattern",
|
|
3
|
-
"buildId": "
|
|
4
|
-
"codeDigest": "sha256:
|
|
3
|
+
"buildId": "codebuild_01a05a33-bcc6-76ac-95bf-0c35b4c55280",
|
|
4
|
+
"codeDigest": "sha256:a19097814cad924bba8b584241b77f19d40c1c70012603e0faf9710853438015",
|
|
5
5
|
"name": "home_hero",
|
|
6
6
|
"schema": {
|
|
7
7
|
"$schema": "https://json-schema.org/draft/2020-12/schema",
|