Skip to content

Commit 0975944

Browse files
committed
fix(docs): turn off table padding in the markdown serializer and assert exact catalog URLs
1 parent 2423e96 commit 0975944

4 files changed

Lines changed: 28 additions & 39 deletions

File tree

‎apps/docs/lib/llms.ts‎

Lines changed: 1 addition & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -4,36 +4,6 @@ import { getIntegrationLandingPage, INTEGRATION_LANDING_LABEL } from '@/lib/inte
44
import { getApiSpecContent } from '@/lib/openapi'
55
import type { PageData, source } from '@/lib/source'
66

7-
/** A table row, captured as its indentation (tables nest under list items) and its cells. */
8-
const TABLE_ROW = /^(\s*)\|(.*)\|$/
9-
const TABLE_DELIMITER_CELL = /^\s*(:?)-+(:?)\s*$/
10-
const UNESCAPED_PIPE = /(?<!\\)\|/
11-
12-
/**
13-
* The processed-markdown serializer pads every table cell to its column's widest cell, so one long
14-
* enum (a parameter listing every timezone) pads every row of its table and roughly doubles the
15-
* integration reference. Drop that trailing padding; a cell's own leading indentation (the `↳`
16-
* nesting in output tables) and inline code are kept, and the tables stay valid GFM. Tables and
17-
* fences nested under a list item are indented, so both are matched after their indentation.
18-
*/
19-
function compactTables(markdown: string): string {
20-
let inFence = false
21-
return markdown
22-
.split('\n')
23-
.map((line) => {
24-
if (line.trimStart().startsWith('```')) inFence = !inFence
25-
const row = inFence ? null : TABLE_ROW.exec(line)
26-
if (!row) return line
27-
const [, indent, inner] = row
28-
const cells = inner.split(UNESCAPED_PIPE)
29-
if (cells.every((cell) => TABLE_DELIMITER_CELL.test(cell))) {
30-
return `${indent}|${cells.map((cell) => cell.replace(TABLE_DELIMITER_CELL, ' $1---$2 ')).join('|')}|`
31-
}
32-
return `${indent}|${cells.map((cell) => ` ${cell.replace(/^ /, '').trimEnd()} `).join('|')}|`
33-
})
34-
.join('\n')
35-
}
36-
377
type LLMPageData = PageData & { getAPIPageProps?: () => ApiPageProps }
388

399
/**
@@ -66,5 +36,5 @@ export async function getLLMText(page: InferPageType<typeof source>) {
6636
: ''
6737
return `${heading}
6838
69-
${landingLink}${compactTables(processed)}`
39+
${landingLink}${processed}`
7040
}

‎apps/docs/source.config.ts‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { execFileSync } from 'node:child_process'
22
import path from 'node:path'
3+
import { remarkGfm } from 'fumadocs-core/mdx-plugins'
34
import { defineConfig, defineDocs, frontmatterSchema } from 'fumadocs-mdx/config'
45
import lastModified from 'fumadocs-mdx/plugins/last-modified'
56
import { curlJsonBodyGrammar } from './lib/shiki-curl-json'
@@ -66,6 +67,22 @@ export default defineConfig({
6667
lastModified({ versionControl: async (file) => gitLastModified?.get(path.resolve(file)) }),
6768
],
6869
mdxOptions: {
70+
/**
71+
* The processed markdown behind `.md` pages, `llms-full.txt`, and Copy page is serialized by
72+
* remark-gfm, which by default pads every table cell to its column's widest cell — one long
73+
* enum pads a whole table. `tablePipeAlign: false` keeps the table and drops the padding; it
74+
* only affects serializing to markdown, never the rendered page.
75+
*/
76+
remarkPlugins: (plugins) => {
77+
if (!plugins.includes(remarkGfm)) {
78+
throw new Error(
79+
'The fumadocs-mdx preset no longer registers remarkGfm; reapply tablePipeAlign'
80+
)
81+
}
82+
return plugins.map((plugin) =>
83+
plugin === remarkGfm ? [remarkGfm, { tablePipeAlign: false }] : plugin
84+
)
85+
},
6986
/**
7087
* Shiki defaults to `github-light` / `github-dark`, whose blues and purples appear nowhere
7188
* in the product. These themes carry the platform's own token colors instead — see

‎apps/sim/app/.well-known/api-catalog/route.ts‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ const API_CATALOG_CONTENT_TYPE =
1111
* RFC 9727 API catalog: one machine-readable entry point to the v2 REST API, linking its OpenAPI
1212
* document (`service-desc`), reference docs (`service-doc`), and health endpoint (`status`) with
1313
* the RFC 8631 relations. The anchor is this deployment's own origin, so a self-hosted instance
14-
* describes itself; the OpenAPI document is the published contract every deployment serves.
14+
* describes itself. The OpenAPI document is the one published contract; its `servers` names Sim
15+
* Cloud, so a client of another deployment uses the anchor as its base URL, as the API docs say.
1516
* `Link: rel="api-catalog"` makes a HEAD request discoverable too (RFC 9727 §2).
1617
*/
1718
export const GET = withRouteHandler(() => {

‎apps/sim/scripts/test-mcp-host-e2e.ts‎

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { mkdir, writeFile } from 'node:fs/promises'
33
import { dirname } from 'node:path'
44
import { createLogger } from '@sim/logger'
55
import { getErrorMessage } from '@sim/utils/errors'
6+
import { SIM_DOCS_URL } from '@sim/utils/site'
67

78
/**
89
* Exercises the public ownership challenge, host isolation, the RFC 9727 API catalog, and the
@@ -117,15 +118,15 @@ try {
117118
const { response, body } = await request(API_CATALOG_PATH, userAgent, baseUrl.host)
118119
assert.equal(response.status, 200)
119120
assert.equal(response.headers.get('content-type'), API_CATALOG_CONTENT_TYPE)
120-
assert.match(
121-
response.headers.get('link') ?? '',
122-
/\/\.well-known\/api-catalog>; rel="api-catalog"$/
121+
assert.equal(
122+
response.headers.get('link'),
123+
`<${baseUrl.origin}${API_CATALOG_PATH}>; rel="api-catalog"`
123124
)
124125
const [api] = JSON.parse(body).linkset
125-
assert.equal(new URL(api.anchor).pathname, '/api/v2')
126-
assert.equal(new URL(api['service-desc'][0].href).pathname, '/openapi.json')
127-
const status = new URL(api.status[0].href)
128-
const health = await request(status.pathname, 'Mozilla/5.0', baseUrl.host)
126+
assert.equal(api.anchor, `${baseUrl.origin}/api/v2`)
127+
assert.equal(api['service-desc'][0].href, `${SIM_DOCS_URL}/openapi.json`)
128+
assert.equal(api.status[0].href, `${baseUrl.origin}/api/health`)
129+
const health = await request(new URL(api.status[0].href).pathname, userAgent, baseUrl.host)
129130
assert.equal(health.response.status, 200, 'The catalog status link must resolve')
130131
})
131132
}

0 commit comments

Comments
 (0)