raffel 1.1.97 → 1.1.98
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/dist/docs/try-it-proxy.d.ts +15 -0
- package/dist/docs/try-it-proxy.d.ts.map +1 -1
- package/dist/docs/try-it-proxy.js +54 -0
- package/dist/docs/try-it-proxy.js.map +1 -1
- package/dist/docs/ui/assets/protocol-console.js +13 -1
- package/dist/docs/ui/assets/raffel-docs.js +167 -1
- package/dist/docs/ui/client-script/index.d.ts.map +1 -1
- package/dist/docs/ui/client-script/index.js +3 -95
- package/dist/docs/ui/client-script/index.js.map +1 -1
- package/dist/docs/ui/html-builder.d.ts.map +1 -1
- package/dist/docs/ui/html-builder.js +6 -3
- package/dist/docs/ui/html-builder.js.map +1 -1
- package/dist/docs/ui/runtime/index.js +167 -1
- package/dist/docs/ui/runtime/index.js.map +1 -1
- package/dist/docs/ui/runtime/protocol-console.d.ts +2 -0
- package/dist/docs/ui/runtime/protocol-console.d.ts.map +1 -1
- package/dist/docs/ui/runtime/protocol-console.js +13 -1
- package/dist/docs/ui/runtime/protocol-console.js.map +1 -1
- package/dist/docs/usd-middleware.d.ts +2 -0
- package/dist/docs/usd-middleware.d.ts.map +1 -1
- package/dist/docs/usd-middleware.js +37 -1
- package/dist/docs/usd-middleware.js.map +1 -1
- package/dist/server/builder/execution-http-docs.d.ts.map +1 -1
- package/dist/server/builder/execution-http-docs.js +8 -0
- package/dist/server/builder/execution-http-docs.js.map +1 -1
- package/dist/server/rest-middleware.d.ts.map +1 -1
- package/dist/server/rest-middleware.js +26 -0
- package/dist/server/rest-middleware.js.map +1 -1
- package/dist/ui/docs/try-it-proxy.d.ts +15 -0
- package/dist/ui/docs/try-it-proxy.d.ts.map +1 -1
- package/dist/ui/docs/ui/client-script/index.d.ts.map +1 -1
- package/dist/ui/docs/ui/html-builder.d.ts.map +1 -1
- package/dist/ui/docs/ui/runtime/protocol-console.d.ts +2 -0
- package/dist/ui/docs/ui/runtime/protocol-console.d.ts.map +1 -1
- package/dist/ui/docs/usd-middleware.d.ts +2 -0
- package/dist/ui/docs/usd-middleware.d.ts.map +1 -1
- package/package.json +1 -1
- package/dist/docs/ui/client-script/cards-and-code.d.ts +0 -5
- package/dist/docs/ui/client-script/cards-and-code.d.ts.map +0 -1
- package/dist/docs/ui/client-script/cards-and-code.js +0 -5
- package/dist/docs/ui/client-script/cards-and-code.js.map +0 -1
- package/dist/docs/ui/client-script/content.d.ts +0 -5
- package/dist/docs/ui/client-script/content.d.ts.map +0 -1
- package/dist/docs/ui/client-script/content.js +0 -412
- package/dist/docs/ui/client-script/content.js.map +0 -1
- package/dist/docs/ui/client-script/docs-pages.d.ts +0 -5
- package/dist/docs/ui/client-script/docs-pages.d.ts.map +0 -1
- package/dist/docs/ui/client-script/docs-pages.js +0 -153
- package/dist/docs/ui/client-script/docs-pages.js.map +0 -1
- package/dist/docs/ui/client-script/endpoint-details.d.ts +0 -5
- package/dist/docs/ui/client-script/endpoint-details.d.ts.map +0 -1
- package/dist/docs/ui/client-script/endpoint-details.js +0 -5
- package/dist/docs/ui/client-script/endpoint-details.js.map +0 -1
- package/dist/docs/ui/client-script/init.d.ts +0 -5
- package/dist/docs/ui/client-script/init.d.ts.map +0 -1
- package/dist/docs/ui/client-script/init.js +0 -227
- package/dist/docs/ui/client-script/init.js.map +0 -1
- package/dist/docs/ui/client-script/markdown.d.ts +0 -5
- package/dist/docs/ui/client-script/markdown.d.ts.map +0 -1
- package/dist/docs/ui/client-script/markdown.js +0 -438
- package/dist/docs/ui/client-script/markdown.js.map +0 -1
- package/dist/docs/ui/client-script/navigation.d.ts +0 -5
- package/dist/docs/ui/client-script/navigation.d.ts.map +0 -1
- package/dist/docs/ui/client-script/navigation.js +0 -548
- package/dist/docs/ui/client-script/navigation.js.map +0 -1
- package/dist/docs/ui/client-script/protocols.d.ts +0 -5
- package/dist/docs/ui/client-script/protocols.d.ts.map +0 -1
- package/dist/docs/ui/client-script/protocols.js +0 -5
- package/dist/docs/ui/client-script/protocols.js.map +0 -1
- package/dist/docs/ui/client-script/schema-rendering.d.ts +0 -5
- package/dist/docs/ui/client-script/schema-rendering.d.ts.map +0 -1
- package/dist/docs/ui/client-script/schema-rendering.js +0 -5
- package/dist/docs/ui/client-script/schema-rendering.js.map +0 -1
- package/dist/docs/ui/client-script/try-it.d.ts +0 -5
- package/dist/docs/ui/client-script/try-it.d.ts.map +0 -1
- package/dist/docs/ui/client-script/try-it.js +0 -5
- package/dist/docs/ui/client-script/try-it.js.map +0 -1
- package/dist/ui/docs/ui/client-script/cards-and-code.d.ts +0 -5
- package/dist/ui/docs/ui/client-script/cards-and-code.d.ts.map +0 -1
- package/dist/ui/docs/ui/client-script/content.d.ts +0 -5
- package/dist/ui/docs/ui/client-script/content.d.ts.map +0 -1
- package/dist/ui/docs/ui/client-script/docs-pages.d.ts +0 -5
- package/dist/ui/docs/ui/client-script/docs-pages.d.ts.map +0 -1
- package/dist/ui/docs/ui/client-script/endpoint-details.d.ts +0 -5
- package/dist/ui/docs/ui/client-script/endpoint-details.d.ts.map +0 -1
- package/dist/ui/docs/ui/client-script/init.d.ts +0 -5
- package/dist/ui/docs/ui/client-script/init.d.ts.map +0 -1
- package/dist/ui/docs/ui/client-script/markdown.d.ts +0 -5
- package/dist/ui/docs/ui/client-script/markdown.d.ts.map +0 -1
- package/dist/ui/docs/ui/client-script/navigation.d.ts +0 -5
- package/dist/ui/docs/ui/client-script/navigation.d.ts.map +0 -1
- package/dist/ui/docs/ui/client-script/protocols.d.ts +0 -5
- package/dist/ui/docs/ui/client-script/protocols.d.ts.map +0 -1
- package/dist/ui/docs/ui/client-script/schema-rendering.d.ts +0 -5
- package/dist/ui/docs/ui/client-script/schema-rendering.d.ts.map +0 -1
- package/dist/ui/docs/ui/client-script/try-it.d.ts +0 -5
- package/dist/ui/docs/ui/client-script/try-it.d.ts.map +0 -1
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Embedded docs UI client script chunk.
|
|
3
|
-
*/
|
|
4
|
-
export declare const cardsAndCodeClientScript = " function createEndpointCard(ep) {\n const section = document.createElement('div');\n section.className = 'endpoint-section';\n section.id = ep.id;\n\n // Header with method + path\n const header = document.createElement('div');\n header.className = 'endpoint-header';\n\n const methodPath = document.createElement('div');\n methodPath.className = 'endpoint-method-path';\n\n const badge = document.createElement('span');\n badge.className = 'badge badge-' + ep.method.toLowerCase();\n badge.textContent = ep.method;\n\n const path = document.createElement('span');\n path.className = 'endpoint-path';\n path.textContent = ep.path;\n\n methodPath.appendChild(badge);\n methodPath.appendChild(path);\n header.appendChild(methodPath);\n\n section.appendChild(header);\n\n // Title (operation summary)\n if (ep.summary) {\n const title = document.createElement('h3');\n title.className = 'endpoint-title';\n title.textContent = ep.summary;\n section.appendChild(title);\n }\n\n // Description if available (rendered as markdown)\n const opData = ep.data;\n if (opData?.description && opData.description !== ep.summary) {\n const desc = document.createElement('div');\n desc.className = 'endpoint-description markdown-content';\n desc.innerHTML = parseMarkdown(opData.description);\n section.appendChild(desc);\n }\n\n // Two-column content layout\n const content = document.createElement('div');\n content.className = 'endpoint-content';\n\n const leftCol = document.createElement('div');\n leftCol.className = 'endpoint-left';\n\n const rightCol = document.createElement('div');\n rightCol.className = 'endpoint-right';\n\n // Render details into left column\n leftCol.appendChild(renderEndpointDetails(ep));\n\n // Render right column content (Request + Response samples)\n rightCol.appendChild(renderRightPanelContent(ep));\n\n content.appendChild(leftCol);\n content.appendChild(rightCol);\n section.appendChild(content);\n\n return section;\n }\n\n // ========== RIGHT PANEL CONTENT (Request + Response Samples) ==========\n\n function renderRightPanelContent(ep) {\n const container = document.createElement('div');\n container.className = 'right-panel-content';\n\n if (activeProtocol === 'http') {\n // Try It Out section\n const tryItSection = document.createElement('div');\n tryItSection.className = 'right-section try-it-section';\n tryItSection.appendChild(renderTryItOut(ep));\n container.appendChild(tryItSection);\n\n // Request section\n const requestSection = document.createElement('div');\n requestSection.className = 'right-section request-section';\n\n const requestHeader = document.createElement('div');\n requestHeader.className = 'right-section-header';\n requestHeader.textContent = 'Request samples';\n requestSection.appendChild(requestHeader);\n\n // Add curl example\n requestSection.appendChild(renderCodeExample(ep));\n container.appendChild(requestSection);\n\n // Response samples section\n const data = ep.data || {};\n const responses = data.responses || {};\n const statusCodes = Object.keys(responses).sort();\n\n if (statusCodes.length > 0) {\n const responseSection = document.createElement('div');\n responseSection.className = 'right-section response-samples-section';\n\n const responseHeader = document.createElement('div');\n responseHeader.className = 'right-section-header';\n responseHeader.textContent = 'Response samples';\n responseSection.appendChild(responseHeader);\n\n // Tabs for status codes\n const tabsContainer = document.createElement('div');\n tabsContainer.className = 'sample-tabs';\n\n const contentContainer = document.createElement('div');\n contentContainer.className = 'sample-contents';\n\n statusCodes.forEach((status, idx) => {\n // Tab button\n const tab = document.createElement('button');\n tab.className = 'sample-tab' + (idx === 0 ? ' active' : '');\n const statusClass = status.startsWith('2') ? 'status-2xx' :\n status.startsWith('4') ? 'status-4xx' :\n status.startsWith('5') ? 'status-5xx' : '';\n tab.innerHTML = '<span class=\"tab-status ' + statusClass + '\">' + esc(status) + '</span>';\n tab.onclick = () => {\n // Remove active from all tabs\n tabsContainer.querySelectorAll('.sample-tab').forEach(t => t.classList.remove('active'));\n tab.classList.add('active');\n // Show corresponding content\n contentContainer.querySelectorAll('.sample-content').forEach((c, i) => {\n c.style.display = i === idx ? 'block' : 'none';\n });\n };\n tabsContainer.appendChild(tab);\n\n // Content for this status\n const content = document.createElement('div');\n content.className = 'sample-content';\n content.style.display = idx === 0 ? 'block' : 'none';\n\n const response = responses[status];\n const respContent = response.content || {};\n const contentType = Object.keys(respContent)[0];\n\n if (contentType && respContent[contentType]) {\n const mediaType = respContent[contentType];\n let example = null;\n\n // Try to get example from various places\n if (mediaType.example) {\n example = mediaType.example;\n } else if (mediaType.examples) {\n const firstExKey = Object.keys(mediaType.examples)[0];\n if (firstExKey && mediaType.examples[firstExKey]) {\n example = mediaType.examples[firstExKey].value;\n }\n } else if (mediaType.schema) {\n // Build example from schema\n example = buildExampleFromSchema(mediaType.schema);\n }\n\n if (example !== null) {\n const pre = document.createElement('pre');\n pre.className = 'sample-json';\n const code = document.createElement('code');\n code.innerHTML = syntaxHighlightJSON(JSON.stringify(example, null, 2));\n pre.appendChild(code);\n content.appendChild(pre);\n } else {\n const noExample = document.createElement('div');\n noExample.className = 'no-example';\n noExample.textContent = 'No example available';\n content.appendChild(noExample);\n }\n } else {\n // No content, just description\n const desc = document.createElement('div');\n desc.className = 'response-desc-only';\n desc.textContent = response.description || 'No content';\n content.appendChild(desc);\n }\n\n contentContainer.appendChild(content);\n });\n\n responseSection.appendChild(tabsContainer);\n responseSection.appendChild(contentContainer);\n container.appendChild(responseSection);\n }\n } else if (activeProtocol === 'websocket') {\n // WebSocket Try It Out\n const tryItSection = document.createElement('div');\n tryItSection.className = 'right-section try-it-section';\n tryItSection.appendChild(renderTryItOutWebSocket(ep));\n container.appendChild(tryItSection);\n\n // Request samples (wscat)\n const requestSection = document.createElement('div');\n requestSection.className = 'right-section request-section';\n const requestHeader = document.createElement('div');\n requestHeader.className = 'right-section-header';\n requestHeader.textContent = 'Request samples';\n requestSection.appendChild(requestHeader);\n requestSection.appendChild(renderCodeExampleWebSocket(ep));\n container.appendChild(requestSection);\n } else if (activeProtocol === 'streams') {\n // Streams (SSE) Try It Out\n const tryItSection = document.createElement('div');\n tryItSection.className = 'right-section try-it-section';\n tryItSection.appendChild(renderTryItOutStreams(ep));\n container.appendChild(tryItSection);\n\n // Request samples (curl, EventSource)\n const requestSection = document.createElement('div');\n requestSection.className = 'right-section request-section';\n const requestHeader = document.createElement('div');\n requestHeader.className = 'right-section-header';\n requestHeader.textContent = 'Request samples';\n requestSection.appendChild(requestHeader);\n requestSection.appendChild(renderCodeExampleStreams(ep));\n container.appendChild(requestSection);\n } else {\n // For other protocols, just show basic code example\n container.appendChild(renderCodeExample(ep));\n }\n\n return container;\n }\n\n // WebSocket code examples (wscat, etc.)\n function renderCodeExampleWebSocket(ep) {\n const container = document.createElement('div');\n container.className = 'code-example';\n\n const baseUrl = (spec.servers && spec.servers[0]?.url) || 'http://localhost:3000';\n // WebSocket URL uses the ws:// scheme and the configured WebSocket path (default: /ws)\n const wsPath = wsSpec?.path || '/ws';\n const wsUrl = baseUrl.replace(/^http/, 'ws') + wsPath;\n\n // Language tabs\n const languages = ['wscat', 'javascript', 'recker', 'python'];\n const tabs = document.createElement('div');\n tabs.className = 'code-tabs';\n\n const contents = document.createElement('div');\n contents.className = 'code-contents';\n\n const langLabels = {\n wscat: 'wscat',\n javascript: 'WebSocket',\n recker: 'Recker',\n python: 'Python'\n };\n\n languages.forEach((lang, i) => {\n // Tab button\n const tab = document.createElement('button');\n tab.className = 'code-tab' + (i === 0 ? ' active' : '');\n tab.textContent = langLabels[lang] || lang;\n tab.onclick = () => {\n tabs.querySelectorAll('.code-tab').forEach(t => t.classList.remove('active'));\n tab.classList.add('active');\n contents.querySelectorAll('.code-content').forEach(c => c.classList.remove('active'));\n contents.querySelector('.code-content[data-lang=\"' + lang + '\"]').classList.add('active');\n };\n tabs.appendChild(tab);\n\n // Content\n const content = document.createElement('div');\n content.className = 'code-content' + (i === 0 ? ' active' : '');\n content.setAttribute('data-lang', lang);\n\n const pre = document.createElement('pre');\n const code = document.createElement('code');\n code.textContent = generateWsCodeSample(lang, wsUrl, ep);\n pre.appendChild(code);\n content.appendChild(pre);\n contents.appendChild(content);\n });\n\n container.appendChild(tabs);\n container.appendChild(contents);\n\n return container;\n }\n\n function generateWsCodeSample(lang, url, ep) {\n const channelName = ep.path;\n const channelType = ep.data?.type || 'public';\n\n // Build subscribe message\n const subscribeMsg = { type: 'subscribe', channel: channelName, id: '1' };\n const subscribeMsgStr = JSON.stringify(subscribeMsg, null, 2);\n\n // Build example publish message if channel supports it\n let publishMsg = null;\n if (ep.data?.publish?.message?.payload) {\n const payload = buildExampleFromSchema(ep.data.publish.message.payload);\n publishMsg = { type: 'publish', channel: channelName, event: 'message', data: payload, id: '2' };\n }\n const publishMsgStr = publishMsg ? JSON.stringify(publishMsg, null, 2) : null;\n\n // For private/presence channels, add token to URL\n const needsAuth = channelType === 'private' || channelType === 'presence';\n const authUrl = needsAuth ? url + '?token=YOUR_TOKEN' : url;\n\n switch (lang) {\n case 'wscat':\n let wscatCode = 'wscat -c \"' + authUrl + '\"\\\\n\\\\n';\n wscatCode += '# Subscribe to channel:\\\\n> ' + JSON.stringify(subscribeMsg);\n if (publishMsgStr) {\n wscatCode += '\\\\n\\\\n# Publish a message:\\\\n> ' + JSON.stringify(publishMsg);\n }\n return wscatCode;\n\n case 'javascript':\n let jsCode = 'const ws = new WebSocket(\"' + authUrl + '\");\\\\n\\\\n';\n jsCode += 'ws.onopen = () => {\\\\n';\n jsCode += ' console.log(\"Connected\");\\\\n';\n jsCode += ' // Subscribe to channel\\\\n';\n jsCode += ' ws.send(JSON.stringify(' + subscribeMsgStr.split('\\\\n').map((l, i) => i === 0 ? l : ' ' + l).join('\\\\n') + '));\\\\n';\n jsCode += '};\\\\n\\\\n';\n jsCode += 'ws.onmessage = (event) => {\\\\n';\n jsCode += ' const msg = JSON.parse(event.data);\\\\n';\n jsCode += ' console.log(\"Received:\", msg);\\\\n';\n if (publishMsgStr) {\n jsCode += '\\\\n // After subscribed, you can publish:\\\\n';\n jsCode += ' // ws.send(JSON.stringify(' + JSON.stringify(publishMsg) + '));\\\\n';\n }\n jsCode += '};\\\\n\\\\n';\n jsCode += 'ws.onclose = () => {\\\\n';\n jsCode += ' console.log(\"Disconnected\");\\\\n';\n jsCode += '};';\n return jsCode;\n\n case 'recker':\n let reckerCode = 'import { ws } from \"recker\";\\\\n\\\\n';\n if (needsAuth) {\n reckerCode += 'const socket = await ws(\"' + url + '\", {\\\\n';\n reckerCode += ' query: { token: \"YOUR_TOKEN\" }\\\\n';\n reckerCode += '});\\\\n\\\\n';\n } else {\n reckerCode += 'const socket = await ws(\"' + url + '\");\\\\n\\\\n';\n }\n reckerCode += '// Subscribe to channel\\\\n';\n reckerCode += 'socket.send(' + subscribeMsgStr.split('\\\\n').map((l, i) => i === 0 ? l : ' ' + l).join('\\\\n') + ');\\\\n\\\\n';\n reckerCode += '// Listen for messages\\\\n';\n reckerCode += 'socket.on(\"message\", (data) => {\\\\n';\n reckerCode += ' console.log(\"Received:\", data);\\\\n';\n reckerCode += '});\\\\n';\n if (publishMsgStr) {\n reckerCode += '\\\\n// Publish a message\\\\n';\n reckerCode += '// socket.send(' + JSON.stringify(publishMsg) + ');\\\\n';\n }\n return reckerCode;\n\n case 'python':\n let pyCode = 'import asyncio\\\\n';\n pyCode += 'import websockets\\\\n';\n pyCode += 'import json\\\\n\\\\n';\n pyCode += 'async def connect():\\\\n';\n pyCode += ' async with websockets.connect(\"' + authUrl + '\") as ws:\\\\n';\n pyCode += ' # Subscribe to channel\\\\n';\n pyCode += ' await ws.send(json.dumps(' + subscribeMsgStr.split('\\\\n').map((l, i) => i === 0 ? l : ' ' + l).join('\\\\n') + '))\\\\n';\n pyCode += ' \\\\n';\n pyCode += ' # Wait for messages\\\\n';\n pyCode += ' async for message in ws:\\\\n';\n pyCode += ' data = json.loads(message)\\\\n';\n pyCode += ' print(f\"Received: {data}\")\\\\n\\\\n';\n pyCode += 'asyncio.run(connect())';\n return pyCode;\n\n default:\n return '// Not implemented';\n }\n }\n\n // Streams (SSE) code examples\n function renderCodeExampleStreams(ep) {\n const container = document.createElement('div');\n container.className = 'code-example';\n\n const baseUrl = (spec.servers && spec.servers[0]?.url) || 'http://localhost:3000';\n // SSE streams are accessed via GET /streams/<procedure-name>\n const streamUrl = baseUrl + '/streams/' + ep.path;\n\n // Language tabs\n const languages = ['curl', 'eventsource', 'recker', 'python'];\n const tabs = document.createElement('div');\n tabs.className = 'code-tabs';\n\n const contents = document.createElement('div');\n contents.className = 'code-contents';\n\n const langLabels = {\n curl: 'cURL',\n eventsource: 'EventSource',\n recker: 'Recker',\n python: 'Python'\n };\n\n languages.forEach((lang, i) => {\n // Tab button\n const tab = document.createElement('button');\n tab.className = 'code-tab' + (i === 0 ? ' active' : '');\n tab.textContent = langLabels[lang] || lang;\n tab.onclick = () => {\n tabs.querySelectorAll('.code-tab').forEach(t => t.classList.remove('active'));\n tab.classList.add('active');\n contents.querySelectorAll('.code-content').forEach(c => c.classList.remove('active'));\n contents.querySelector('.code-content[data-lang=\"' + lang + '\"]').classList.add('active');\n };\n tabs.appendChild(tab);\n\n // Content\n const content = document.createElement('div');\n content.className = 'code-content' + (i === 0 ? ' active' : '');\n content.setAttribute('data-lang', lang);\n\n const pre = document.createElement('pre');\n const code = document.createElement('code');\n code.textContent = generateStreamCodeSample(lang, streamUrl, ep);\n pre.appendChild(code);\n content.appendChild(pre);\n contents.appendChild(content);\n });\n\n container.appendChild(tabs);\n container.appendChild(contents);\n\n return container;\n }\n\n function generateStreamCodeSample(lang, url, ep) {\n switch (lang) {\n case 'curl':\n return 'curl -N \"' + url + '\"\\\\n\\\\n# -N disables buffering for streaming output';\n\n case 'eventsource':\n return 'const eventSource = new EventSource(\"' + url + '\");\\\\n\\\\n' +\n 'eventSource.onmessage = (event) => {\\\\n' +\n ' console.log(\"Received:\", event.data);\\\\n' +\n '};\\\\n\\\\n' +\n 'eventSource.onerror = (error) => {\\\\n' +\n ' console.error(\"Error:\", error);\\\\n' +\n ' eventSource.close();\\\\n' +\n '};\\\\n\\\\n' +\n '// To close the connection:\\\\n' +\n '// eventSource.close();';\n\n case 'recker':\n return 'import { sse } from \"recker\";\\\\n\\\\n' +\n 'const stream = sse(\"' + url + '\");\\\\n\\\\n' +\n 'for await (const event of stream) {\\\\n' +\n ' console.log(\"Received:\", event.data);\\\\n' +\n '}';\n\n case 'python':\n return 'import sseclient\\\\n' +\n 'import requests\\\\n\\\\n' +\n 'response = requests.get(\"' + url + '\", stream=True)\\\\n' +\n 'client = sseclient.SSEClient(response)\\\\n\\\\n' +\n 'for event in client.events():\\\\n' +\n ' print(f\"Event: {event.event}, Data: {event.data}\")';\n\n default:\n return '// Not implemented';\n }\n }\n\n // JSON syntax highlighting\n function syntaxHighlightJSON(json) {\n return json\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/(\"(\\\\\\\\u[a-zA-Z0-9]{4}|\\\\\\\\[^u]|[^\\\\\\\\\"])*\"(\\\\s*:)?)/g, function(match) {\n let cls = 'json-string';\n if (/:$/.test(match)) {\n cls = 'json-key';\n match = match.replace(/:$/, '') + ':';\n }\n return '<span class=\"' + cls + '\">' + match + '</span>';\n })\n .replace(/\\\\b(true|false|null)\\\\b/g, '<span class=\"json-boolean\">$1</span>')\n .replace(/\\\\b(-?\\\\d+\\\\.?\\\\d*)\\\\b/g, '<span class=\"json-number\">$1</span>');\n }\n\n function renderCodeExample(ep) {\n const container = document.createElement('div');\n container.className = 'code-example';\n\n // Build request details\n const method = ep.method.toUpperCase();\n const path = ep.path;\n const baseUrl = (spec.servers && spec.servers[0]?.url) || 'http://localhost:3000';\n\n // Handle JSON-RPC methods specially\n const isJsonRpc = method === 'RPC';\n let fullUrl;\n let exampleBody = null;\n let actualMethod = method;\n\n if (isJsonRpc) {\n // For JSON-RPC, use the /rpc endpoint and POST method\n const rpcEndpoint = jsonrpcSpec?.endpoint || '/rpc';\n fullUrl = baseUrl + rpcEndpoint;\n actualMethod = 'POST';\n\n // Build JSON-RPC request body\n const opData = ep.data;\n let params = {};\n if (opData && opData.params) {\n params = buildExampleFromSchema(opData.params);\n }\n exampleBody = {\n jsonrpc: '2.0',\n method: path, // The method name like \"tasks.list\"\n params: params,\n id: 1\n };\n } else {\n // Ensure path has leading slash for proper URL construction\n const normalizedPath = path.startsWith('/') ? path : '/' + path;\n fullUrl = baseUrl + normalizedPath;\n\n // Get request body if exists\n const opData = ep.data;\n if (opData && opData.requestBody && opData.requestBody.content) {\n const jsonContent = opData.requestBody.content['application/json'];\n if (jsonContent && jsonContent.schema) {\n exampleBody = buildExampleFromSchema(jsonContent.schema);\n }\n }\n }\n\n // Language tabs\n const languages = ['curl', 'fetch', 'recker', 'python', 'go'];\n const tabs = document.createElement('div');\n tabs.className = 'code-tabs';\n\n const contents = document.createElement('div');\n contents.className = 'code-contents';\n\n const langLabels = {\n curl: 'cURL',\n fetch: 'Fetch',\n recker: 'Recker',\n python: 'Python',\n go: 'Go'\n };\n\n languages.forEach((lang, i) => {\n // Tab button\n const tab = document.createElement('button');\n tab.className = 'code-tab' + (i === 0 ? ' active' : '');\n tab.textContent = langLabels[lang] || lang;\n tab.onclick = () => {\n tabs.querySelectorAll('.code-tab').forEach(t => t.classList.remove('active'));\n tab.classList.add('active');\n contents.querySelectorAll('.code-content').forEach(c => c.classList.remove('active'));\n contents.querySelector('.code-content[data-lang=\"' + lang + '\"]').classList.add('active');\n };\n tabs.appendChild(tab);\n\n // Content\n const content = document.createElement('div');\n content.className = 'code-content' + (i === 0 ? ' active' : '');\n content.setAttribute('data-lang', lang);\n\n const pre = document.createElement('pre');\n const code = document.createElement('code');\n code.textContent = generateCodeSample(lang, actualMethod, fullUrl, exampleBody);\n pre.appendChild(code);\n content.appendChild(pre);\n contents.appendChild(content);\n });\n\n container.appendChild(tabs);\n container.appendChild(contents);\n\n return container;\n }\n\n function generateCodeSample(lang, method, url, body) {\n const hasBody = body && ['POST', 'PUT', 'PATCH'].includes(method);\n const bodyStr = body ? JSON.stringify(body, null, 2) : '';\n\n switch (lang) {\n case 'curl':\n const curlLines = [];\n curlLines.push('curl' + (method !== 'GET' ? ' -X ' + method : ''));\n curlLines.push(' \"' + url + '\"');\n if (hasBody) {\n curlLines.push(' -H \"Content-Type: application/json\"');\n curlLines.push(\" -d '\" + bodyStr + \"'\");\n }\n return curlLines.join(' \\\\\\\\\\\\n');\n\n case 'fetch':\n if (hasBody) {\n return 'const response = await fetch(\"' + url + '\", {\\\\n' +\n ' method: \"' + method + '\",\\\\n' +\n ' headers: {\\\\n' +\n ' \"Content-Type\": \"application/json\",\\\\n' +\n ' },\\\\n' +\n ' body: JSON.stringify(' + bodyStr.split('\\\\n').map((l, i) => i === 0 ? l : ' ' + l).join('\\\\n') + '),\\\\n' +\n '});\\\\n\\\\n' +\n 'const data = await response.json();\\\\n' +\n 'console.log(data);';\n }\n return 'const response = await fetch(\"' + url + '\"' +\n (method !== 'GET' ? ', {\\\\n method: \"' + method + '\",\\\\n}' : '') + ');\\\\n\\\\n' +\n 'const data = await response.json();\\\\n' +\n 'console.log(data);';\n\n case 'recker':\n if (hasBody) {\n return 'import { ' + method.toLowerCase() + ' } from \"recker\";\\\\n\\\\n' +\n 'const data = await ' + method.toLowerCase() + '(\"' + url + '\")\\\\n' +\n ' .json(' + bodyStr.split('\\\\n').map((l, i) => i === 0 ? l : ' ' + l).join('\\\\n') + ')\\\\n' +\n ' .json();\\\\n\\\\n' +\n 'console.log(data);';\n }\n return 'import { ' + method.toLowerCase() + ' } from \"recker\";\\\\n\\\\n' +\n 'const data = await ' + method.toLowerCase() + '(\"' + url + '\").json();\\\\n\\\\n' +\n 'console.log(data);';\n\n case 'python':\n if (hasBody) {\n return 'import requests\\\\n\\\\n' +\n 'response = requests.' + method.toLowerCase() + '(\\\\n' +\n ' \"' + url + '\",\\\\n' +\n ' json=' + bodyStr.split('\\\\n').map((l, i) => i === 0 ? l : ' ' + l).join('\\\\n') + ',\\\\n' +\n ')\\\\n\\\\n' +\n 'print(response.json())';\n }\n return 'import requests\\\\n\\\\n' +\n 'response = requests.' + method.toLowerCase() + '(\"' + url + '\")\\\\n\\\\n' +\n 'print(response.json())';\n\n case 'go':\n if (hasBody) {\n return 'package main\\\\n\\\\n' +\n 'import (\\\\n' +\n ' \"bytes\"\\\\n' +\n ' \"encoding/json\"\\\\n' +\n ' \"fmt\"\\\\n' +\n ' \"net/http\"\\\\n' +\n ' \"io\"\\\\n' +\n ')\\\\n\\\\n' +\n 'func main() {\\\\n' +\n ' body, _ := json.Marshal(map[string]interface{}{\\\\n' +\n generateGoMapBody(body) +\n ' })\\\\n\\\\n' +\n ' req, _ := http.NewRequest(\"' + method + '\", \"' + url + '\", bytes.NewBuffer(body))\\\\n' +\n ' req.Header.Set(\"Content-Type\", \"application/json\")\\\\n\\\\n' +\n ' client := &http.Client{}\\\\n' +\n ' resp, _ := client.Do(req)\\\\n' +\n ' defer resp.Body.Close()\\\\n\\\\n' +\n ' data, _ := io.ReadAll(resp.Body)\\\\n' +\n ' fmt.Println(string(data))\\\\n' +\n '}';\n }\n return 'package main\\\\n\\\\n' +\n 'import (\\\\n' +\n ' \"fmt\"\\\\n' +\n ' \"net/http\"\\\\n' +\n ' \"io\"\\\\n' +\n ')\\\\n\\\\n' +\n 'func main() {\\\\n' +\n ' resp, _ := http.Get(\"' + url + '\")\\\\n' +\n ' defer resp.Body.Close()\\\\n\\\\n' +\n ' body, _ := io.ReadAll(resp.Body)\\\\n' +\n ' fmt.Println(string(body))\\\\n' +\n '}';\n\n default:\n return '// Not implemented';\n }\n }\n\n function generateGoMapBody(body) {\n if (!body || typeof body !== 'object') return '';\n const lines = [];\n for (const [key, value] of Object.entries(body)) {\n const goValue = typeof value === 'string' ? '\"' + value + '\"' :\n typeof value === 'number' ? String(value) :\n typeof value === 'boolean' ? String(value) :\n 'nil';\n lines.push(' \"' + key + '\": ' + goValue + ',');\n }\n return lines.join('\\\\n') + '\\\\n';\n }\n\n function buildExampleFromSchema(schema) {\n if (!schema) return null;\n\n // Resolve $ref\n if (schema.$ref) {\n const resolved = resolveRef(schema.$ref);\n return buildExampleFromSchema(resolved);\n }\n\n // Normalize non-standard format\n schema = normalizeSchema(schema);\n\n if (schema.example !== undefined) return schema.example;\n if (schema.default !== undefined) return schema.default;\n\n if (schema.type === 'object' && schema.properties) {\n const obj = {};\n for (const [key, prop] of Object.entries(schema.properties)) {\n obj[key] = buildExampleFromSchema(prop);\n }\n return obj;\n }\n\n if (schema.type === 'array' && schema.items) {\n return [buildExampleFromSchema(schema.items)];\n }\n\n // Primitive defaults\n switch (schema.type) {\n case 'string': return schema.format === 'email' ? 'user@example.com' : 'string';\n case 'number': return 0;\n case 'integer': return 0;\n case 'boolean': return true;\n default: return null;\n }\n }\n\n";
|
|
5
|
-
//# sourceMappingURL=cards-and-code.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cards-and-code.d.ts","sourceRoot":"","sources":["../../../../src/docs/ui/client-script/cards-and-code.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,eAAO,MAAM,wBAAwB,sx6BAAsx6B,CAAA"}
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Embedded docs UI client script chunk.
|
|
3
|
-
*/
|
|
4
|
-
export const cardsAndCodeClientScript = " function createEndpointCard(ep) {\n const section = document.createElement('div');\n section.className = 'endpoint-section';\n section.id = ep.id;\n\n // Header with method + path\n const header = document.createElement('div');\n header.className = 'endpoint-header';\n\n const methodPath = document.createElement('div');\n methodPath.className = 'endpoint-method-path';\n\n const badge = document.createElement('span');\n badge.className = 'badge badge-' + ep.method.toLowerCase();\n badge.textContent = ep.method;\n\n const path = document.createElement('span');\n path.className = 'endpoint-path';\n path.textContent = ep.path;\n\n methodPath.appendChild(badge);\n methodPath.appendChild(path);\n header.appendChild(methodPath);\n\n section.appendChild(header);\n\n // Title (operation summary)\n if (ep.summary) {\n const title = document.createElement('h3');\n title.className = 'endpoint-title';\n title.textContent = ep.summary;\n section.appendChild(title);\n }\n\n // Description if available (rendered as markdown)\n const opData = ep.data;\n if (opData?.description && opData.description !== ep.summary) {\n const desc = document.createElement('div');\n desc.className = 'endpoint-description markdown-content';\n desc.innerHTML = parseMarkdown(opData.description);\n section.appendChild(desc);\n }\n\n // Two-column content layout\n const content = document.createElement('div');\n content.className = 'endpoint-content';\n\n const leftCol = document.createElement('div');\n leftCol.className = 'endpoint-left';\n\n const rightCol = document.createElement('div');\n rightCol.className = 'endpoint-right';\n\n // Render details into left column\n leftCol.appendChild(renderEndpointDetails(ep));\n\n // Render right column content (Request + Response samples)\n rightCol.appendChild(renderRightPanelContent(ep));\n\n content.appendChild(leftCol);\n content.appendChild(rightCol);\n section.appendChild(content);\n\n return section;\n }\n\n // ========== RIGHT PANEL CONTENT (Request + Response Samples) ==========\n\n function renderRightPanelContent(ep) {\n const container = document.createElement('div');\n container.className = 'right-panel-content';\n\n if (activeProtocol === 'http') {\n // Try It Out section\n const tryItSection = document.createElement('div');\n tryItSection.className = 'right-section try-it-section';\n tryItSection.appendChild(renderTryItOut(ep));\n container.appendChild(tryItSection);\n\n // Request section\n const requestSection = document.createElement('div');\n requestSection.className = 'right-section request-section';\n\n const requestHeader = document.createElement('div');\n requestHeader.className = 'right-section-header';\n requestHeader.textContent = 'Request samples';\n requestSection.appendChild(requestHeader);\n\n // Add curl example\n requestSection.appendChild(renderCodeExample(ep));\n container.appendChild(requestSection);\n\n // Response samples section\n const data = ep.data || {};\n const responses = data.responses || {};\n const statusCodes = Object.keys(responses).sort();\n\n if (statusCodes.length > 0) {\n const responseSection = document.createElement('div');\n responseSection.className = 'right-section response-samples-section';\n\n const responseHeader = document.createElement('div');\n responseHeader.className = 'right-section-header';\n responseHeader.textContent = 'Response samples';\n responseSection.appendChild(responseHeader);\n\n // Tabs for status codes\n const tabsContainer = document.createElement('div');\n tabsContainer.className = 'sample-tabs';\n\n const contentContainer = document.createElement('div');\n contentContainer.className = 'sample-contents';\n\n statusCodes.forEach((status, idx) => {\n // Tab button\n const tab = document.createElement('button');\n tab.className = 'sample-tab' + (idx === 0 ? ' active' : '');\n const statusClass = status.startsWith('2') ? 'status-2xx' :\n status.startsWith('4') ? 'status-4xx' :\n status.startsWith('5') ? 'status-5xx' : '';\n tab.innerHTML = '<span class=\"tab-status ' + statusClass + '\">' + esc(status) + '</span>';\n tab.onclick = () => {\n // Remove active from all tabs\n tabsContainer.querySelectorAll('.sample-tab').forEach(t => t.classList.remove('active'));\n tab.classList.add('active');\n // Show corresponding content\n contentContainer.querySelectorAll('.sample-content').forEach((c, i) => {\n c.style.display = i === idx ? 'block' : 'none';\n });\n };\n tabsContainer.appendChild(tab);\n\n // Content for this status\n const content = document.createElement('div');\n content.className = 'sample-content';\n content.style.display = idx === 0 ? 'block' : 'none';\n\n const response = responses[status];\n const respContent = response.content || {};\n const contentType = Object.keys(respContent)[0];\n\n if (contentType && respContent[contentType]) {\n const mediaType = respContent[contentType];\n let example = null;\n\n // Try to get example from various places\n if (mediaType.example) {\n example = mediaType.example;\n } else if (mediaType.examples) {\n const firstExKey = Object.keys(mediaType.examples)[0];\n if (firstExKey && mediaType.examples[firstExKey]) {\n example = mediaType.examples[firstExKey].value;\n }\n } else if (mediaType.schema) {\n // Build example from schema\n example = buildExampleFromSchema(mediaType.schema);\n }\n\n if (example !== null) {\n const pre = document.createElement('pre');\n pre.className = 'sample-json';\n const code = document.createElement('code');\n code.innerHTML = syntaxHighlightJSON(JSON.stringify(example, null, 2));\n pre.appendChild(code);\n content.appendChild(pre);\n } else {\n const noExample = document.createElement('div');\n noExample.className = 'no-example';\n noExample.textContent = 'No example available';\n content.appendChild(noExample);\n }\n } else {\n // No content, just description\n const desc = document.createElement('div');\n desc.className = 'response-desc-only';\n desc.textContent = response.description || 'No content';\n content.appendChild(desc);\n }\n\n contentContainer.appendChild(content);\n });\n\n responseSection.appendChild(tabsContainer);\n responseSection.appendChild(contentContainer);\n container.appendChild(responseSection);\n }\n } else if (activeProtocol === 'websocket') {\n // WebSocket Try It Out\n const tryItSection = document.createElement('div');\n tryItSection.className = 'right-section try-it-section';\n tryItSection.appendChild(renderTryItOutWebSocket(ep));\n container.appendChild(tryItSection);\n\n // Request samples (wscat)\n const requestSection = document.createElement('div');\n requestSection.className = 'right-section request-section';\n const requestHeader = document.createElement('div');\n requestHeader.className = 'right-section-header';\n requestHeader.textContent = 'Request samples';\n requestSection.appendChild(requestHeader);\n requestSection.appendChild(renderCodeExampleWebSocket(ep));\n container.appendChild(requestSection);\n } else if (activeProtocol === 'streams') {\n // Streams (SSE) Try It Out\n const tryItSection = document.createElement('div');\n tryItSection.className = 'right-section try-it-section';\n tryItSection.appendChild(renderTryItOutStreams(ep));\n container.appendChild(tryItSection);\n\n // Request samples (curl, EventSource)\n const requestSection = document.createElement('div');\n requestSection.className = 'right-section request-section';\n const requestHeader = document.createElement('div');\n requestHeader.className = 'right-section-header';\n requestHeader.textContent = 'Request samples';\n requestSection.appendChild(requestHeader);\n requestSection.appendChild(renderCodeExampleStreams(ep));\n container.appendChild(requestSection);\n } else {\n // For other protocols, just show basic code example\n container.appendChild(renderCodeExample(ep));\n }\n\n return container;\n }\n\n // WebSocket code examples (wscat, etc.)\n function renderCodeExampleWebSocket(ep) {\n const container = document.createElement('div');\n container.className = 'code-example';\n\n const baseUrl = (spec.servers && spec.servers[0]?.url) || 'http://localhost:3000';\n // WebSocket URL uses the ws:// scheme and the configured WebSocket path (default: /ws)\n const wsPath = wsSpec?.path || '/ws';\n const wsUrl = baseUrl.replace(/^http/, 'ws') + wsPath;\n\n // Language tabs\n const languages = ['wscat', 'javascript', 'recker', 'python'];\n const tabs = document.createElement('div');\n tabs.className = 'code-tabs';\n\n const contents = document.createElement('div');\n contents.className = 'code-contents';\n\n const langLabels = {\n wscat: 'wscat',\n javascript: 'WebSocket',\n recker: 'Recker',\n python: 'Python'\n };\n\n languages.forEach((lang, i) => {\n // Tab button\n const tab = document.createElement('button');\n tab.className = 'code-tab' + (i === 0 ? ' active' : '');\n tab.textContent = langLabels[lang] || lang;\n tab.onclick = () => {\n tabs.querySelectorAll('.code-tab').forEach(t => t.classList.remove('active'));\n tab.classList.add('active');\n contents.querySelectorAll('.code-content').forEach(c => c.classList.remove('active'));\n contents.querySelector('.code-content[data-lang=\"' + lang + '\"]').classList.add('active');\n };\n tabs.appendChild(tab);\n\n // Content\n const content = document.createElement('div');\n content.className = 'code-content' + (i === 0 ? ' active' : '');\n content.setAttribute('data-lang', lang);\n\n const pre = document.createElement('pre');\n const code = document.createElement('code');\n code.textContent = generateWsCodeSample(lang, wsUrl, ep);\n pre.appendChild(code);\n content.appendChild(pre);\n contents.appendChild(content);\n });\n\n container.appendChild(tabs);\n container.appendChild(contents);\n\n return container;\n }\n\n function generateWsCodeSample(lang, url, ep) {\n const channelName = ep.path;\n const channelType = ep.data?.type || 'public';\n\n // Build subscribe message\n const subscribeMsg = { type: 'subscribe', channel: channelName, id: '1' };\n const subscribeMsgStr = JSON.stringify(subscribeMsg, null, 2);\n\n // Build example publish message if channel supports it\n let publishMsg = null;\n if (ep.data?.publish?.message?.payload) {\n const payload = buildExampleFromSchema(ep.data.publish.message.payload);\n publishMsg = { type: 'publish', channel: channelName, event: 'message', data: payload, id: '2' };\n }\n const publishMsgStr = publishMsg ? JSON.stringify(publishMsg, null, 2) : null;\n\n // For private/presence channels, add token to URL\n const needsAuth = channelType === 'private' || channelType === 'presence';\n const authUrl = needsAuth ? url + '?token=YOUR_TOKEN' : url;\n\n switch (lang) {\n case 'wscat':\n let wscatCode = 'wscat -c \"' + authUrl + '\"\\\\n\\\\n';\n wscatCode += '# Subscribe to channel:\\\\n> ' + JSON.stringify(subscribeMsg);\n if (publishMsgStr) {\n wscatCode += '\\\\n\\\\n# Publish a message:\\\\n> ' + JSON.stringify(publishMsg);\n }\n return wscatCode;\n\n case 'javascript':\n let jsCode = 'const ws = new WebSocket(\"' + authUrl + '\");\\\\n\\\\n';\n jsCode += 'ws.onopen = () => {\\\\n';\n jsCode += ' console.log(\"Connected\");\\\\n';\n jsCode += ' // Subscribe to channel\\\\n';\n jsCode += ' ws.send(JSON.stringify(' + subscribeMsgStr.split('\\\\n').map((l, i) => i === 0 ? l : ' ' + l).join('\\\\n') + '));\\\\n';\n jsCode += '};\\\\n\\\\n';\n jsCode += 'ws.onmessage = (event) => {\\\\n';\n jsCode += ' const msg = JSON.parse(event.data);\\\\n';\n jsCode += ' console.log(\"Received:\", msg);\\\\n';\n if (publishMsgStr) {\n jsCode += '\\\\n // After subscribed, you can publish:\\\\n';\n jsCode += ' // ws.send(JSON.stringify(' + JSON.stringify(publishMsg) + '));\\\\n';\n }\n jsCode += '};\\\\n\\\\n';\n jsCode += 'ws.onclose = () => {\\\\n';\n jsCode += ' console.log(\"Disconnected\");\\\\n';\n jsCode += '};';\n return jsCode;\n\n case 'recker':\n let reckerCode = 'import { ws } from \"recker\";\\\\n\\\\n';\n if (needsAuth) {\n reckerCode += 'const socket = await ws(\"' + url + '\", {\\\\n';\n reckerCode += ' query: { token: \"YOUR_TOKEN\" }\\\\n';\n reckerCode += '});\\\\n\\\\n';\n } else {\n reckerCode += 'const socket = await ws(\"' + url + '\");\\\\n\\\\n';\n }\n reckerCode += '// Subscribe to channel\\\\n';\n reckerCode += 'socket.send(' + subscribeMsgStr.split('\\\\n').map((l, i) => i === 0 ? l : ' ' + l).join('\\\\n') + ');\\\\n\\\\n';\n reckerCode += '// Listen for messages\\\\n';\n reckerCode += 'socket.on(\"message\", (data) => {\\\\n';\n reckerCode += ' console.log(\"Received:\", data);\\\\n';\n reckerCode += '});\\\\n';\n if (publishMsgStr) {\n reckerCode += '\\\\n// Publish a message\\\\n';\n reckerCode += '// socket.send(' + JSON.stringify(publishMsg) + ');\\\\n';\n }\n return reckerCode;\n\n case 'python':\n let pyCode = 'import asyncio\\\\n';\n pyCode += 'import websockets\\\\n';\n pyCode += 'import json\\\\n\\\\n';\n pyCode += 'async def connect():\\\\n';\n pyCode += ' async with websockets.connect(\"' + authUrl + '\") as ws:\\\\n';\n pyCode += ' # Subscribe to channel\\\\n';\n pyCode += ' await ws.send(json.dumps(' + subscribeMsgStr.split('\\\\n').map((l, i) => i === 0 ? l : ' ' + l).join('\\\\n') + '))\\\\n';\n pyCode += ' \\\\n';\n pyCode += ' # Wait for messages\\\\n';\n pyCode += ' async for message in ws:\\\\n';\n pyCode += ' data = json.loads(message)\\\\n';\n pyCode += ' print(f\"Received: {data}\")\\\\n\\\\n';\n pyCode += 'asyncio.run(connect())';\n return pyCode;\n\n default:\n return '// Not implemented';\n }\n }\n\n // Streams (SSE) code examples\n function renderCodeExampleStreams(ep) {\n const container = document.createElement('div');\n container.className = 'code-example';\n\n const baseUrl = (spec.servers && spec.servers[0]?.url) || 'http://localhost:3000';\n // SSE streams are accessed via GET /streams/<procedure-name>\n const streamUrl = baseUrl + '/streams/' + ep.path;\n\n // Language tabs\n const languages = ['curl', 'eventsource', 'recker', 'python'];\n const tabs = document.createElement('div');\n tabs.className = 'code-tabs';\n\n const contents = document.createElement('div');\n contents.className = 'code-contents';\n\n const langLabels = {\n curl: 'cURL',\n eventsource: 'EventSource',\n recker: 'Recker',\n python: 'Python'\n };\n\n languages.forEach((lang, i) => {\n // Tab button\n const tab = document.createElement('button');\n tab.className = 'code-tab' + (i === 0 ? ' active' : '');\n tab.textContent = langLabels[lang] || lang;\n tab.onclick = () => {\n tabs.querySelectorAll('.code-tab').forEach(t => t.classList.remove('active'));\n tab.classList.add('active');\n contents.querySelectorAll('.code-content').forEach(c => c.classList.remove('active'));\n contents.querySelector('.code-content[data-lang=\"' + lang + '\"]').classList.add('active');\n };\n tabs.appendChild(tab);\n\n // Content\n const content = document.createElement('div');\n content.className = 'code-content' + (i === 0 ? ' active' : '');\n content.setAttribute('data-lang', lang);\n\n const pre = document.createElement('pre');\n const code = document.createElement('code');\n code.textContent = generateStreamCodeSample(lang, streamUrl, ep);\n pre.appendChild(code);\n content.appendChild(pre);\n contents.appendChild(content);\n });\n\n container.appendChild(tabs);\n container.appendChild(contents);\n\n return container;\n }\n\n function generateStreamCodeSample(lang, url, ep) {\n switch (lang) {\n case 'curl':\n return 'curl -N \"' + url + '\"\\\\n\\\\n# -N disables buffering for streaming output';\n\n case 'eventsource':\n return 'const eventSource = new EventSource(\"' + url + '\");\\\\n\\\\n' +\n 'eventSource.onmessage = (event) => {\\\\n' +\n ' console.log(\"Received:\", event.data);\\\\n' +\n '};\\\\n\\\\n' +\n 'eventSource.onerror = (error) => {\\\\n' +\n ' console.error(\"Error:\", error);\\\\n' +\n ' eventSource.close();\\\\n' +\n '};\\\\n\\\\n' +\n '// To close the connection:\\\\n' +\n '// eventSource.close();';\n\n case 'recker':\n return 'import { sse } from \"recker\";\\\\n\\\\n' +\n 'const stream = sse(\"' + url + '\");\\\\n\\\\n' +\n 'for await (const event of stream) {\\\\n' +\n ' console.log(\"Received:\", event.data);\\\\n' +\n '}';\n\n case 'python':\n return 'import sseclient\\\\n' +\n 'import requests\\\\n\\\\n' +\n 'response = requests.get(\"' + url + '\", stream=True)\\\\n' +\n 'client = sseclient.SSEClient(response)\\\\n\\\\n' +\n 'for event in client.events():\\\\n' +\n ' print(f\"Event: {event.event}, Data: {event.data}\")';\n\n default:\n return '// Not implemented';\n }\n }\n\n // JSON syntax highlighting\n function syntaxHighlightJSON(json) {\n return json\n .replace(/&/g, '&')\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/(\"(\\\\\\\\u[a-zA-Z0-9]{4}|\\\\\\\\[^u]|[^\\\\\\\\\"])*\"(\\\\s*:)?)/g, function(match) {\n let cls = 'json-string';\n if (/:$/.test(match)) {\n cls = 'json-key';\n match = match.replace(/:$/, '') + ':';\n }\n return '<span class=\"' + cls + '\">' + match + '</span>';\n })\n .replace(/\\\\b(true|false|null)\\\\b/g, '<span class=\"json-boolean\">$1</span>')\n .replace(/\\\\b(-?\\\\d+\\\\.?\\\\d*)\\\\b/g, '<span class=\"json-number\">$1</span>');\n }\n\n function renderCodeExample(ep) {\n const container = document.createElement('div');\n container.className = 'code-example';\n\n // Build request details\n const method = ep.method.toUpperCase();\n const path = ep.path;\n const baseUrl = (spec.servers && spec.servers[0]?.url) || 'http://localhost:3000';\n\n // Handle JSON-RPC methods specially\n const isJsonRpc = method === 'RPC';\n let fullUrl;\n let exampleBody = null;\n let actualMethod = method;\n\n if (isJsonRpc) {\n // For JSON-RPC, use the /rpc endpoint and POST method\n const rpcEndpoint = jsonrpcSpec?.endpoint || '/rpc';\n fullUrl = baseUrl + rpcEndpoint;\n actualMethod = 'POST';\n\n // Build JSON-RPC request body\n const opData = ep.data;\n let params = {};\n if (opData && opData.params) {\n params = buildExampleFromSchema(opData.params);\n }\n exampleBody = {\n jsonrpc: '2.0',\n method: path, // The method name like \"tasks.list\"\n params: params,\n id: 1\n };\n } else {\n // Ensure path has leading slash for proper URL construction\n const normalizedPath = path.startsWith('/') ? path : '/' + path;\n fullUrl = baseUrl + normalizedPath;\n\n // Get request body if exists\n const opData = ep.data;\n if (opData && opData.requestBody && opData.requestBody.content) {\n const jsonContent = opData.requestBody.content['application/json'];\n if (jsonContent && jsonContent.schema) {\n exampleBody = buildExampleFromSchema(jsonContent.schema);\n }\n }\n }\n\n // Language tabs\n const languages = ['curl', 'fetch', 'recker', 'python', 'go'];\n const tabs = document.createElement('div');\n tabs.className = 'code-tabs';\n\n const contents = document.createElement('div');\n contents.className = 'code-contents';\n\n const langLabels = {\n curl: 'cURL',\n fetch: 'Fetch',\n recker: 'Recker',\n python: 'Python',\n go: 'Go'\n };\n\n languages.forEach((lang, i) => {\n // Tab button\n const tab = document.createElement('button');\n tab.className = 'code-tab' + (i === 0 ? ' active' : '');\n tab.textContent = langLabels[lang] || lang;\n tab.onclick = () => {\n tabs.querySelectorAll('.code-tab').forEach(t => t.classList.remove('active'));\n tab.classList.add('active');\n contents.querySelectorAll('.code-content').forEach(c => c.classList.remove('active'));\n contents.querySelector('.code-content[data-lang=\"' + lang + '\"]').classList.add('active');\n };\n tabs.appendChild(tab);\n\n // Content\n const content = document.createElement('div');\n content.className = 'code-content' + (i === 0 ? ' active' : '');\n content.setAttribute('data-lang', lang);\n\n const pre = document.createElement('pre');\n const code = document.createElement('code');\n code.textContent = generateCodeSample(lang, actualMethod, fullUrl, exampleBody);\n pre.appendChild(code);\n content.appendChild(pre);\n contents.appendChild(content);\n });\n\n container.appendChild(tabs);\n container.appendChild(contents);\n\n return container;\n }\n\n function generateCodeSample(lang, method, url, body) {\n const hasBody = body && ['POST', 'PUT', 'PATCH'].includes(method);\n const bodyStr = body ? JSON.stringify(body, null, 2) : '';\n\n switch (lang) {\n case 'curl':\n const curlLines = [];\n curlLines.push('curl' + (method !== 'GET' ? ' -X ' + method : ''));\n curlLines.push(' \"' + url + '\"');\n if (hasBody) {\n curlLines.push(' -H \"Content-Type: application/json\"');\n curlLines.push(\" -d '\" + bodyStr + \"'\");\n }\n return curlLines.join(' \\\\\\\\\\\\n');\n\n case 'fetch':\n if (hasBody) {\n return 'const response = await fetch(\"' + url + '\", {\\\\n' +\n ' method: \"' + method + '\",\\\\n' +\n ' headers: {\\\\n' +\n ' \"Content-Type\": \"application/json\",\\\\n' +\n ' },\\\\n' +\n ' body: JSON.stringify(' + bodyStr.split('\\\\n').map((l, i) => i === 0 ? l : ' ' + l).join('\\\\n') + '),\\\\n' +\n '});\\\\n\\\\n' +\n 'const data = await response.json();\\\\n' +\n 'console.log(data);';\n }\n return 'const response = await fetch(\"' + url + '\"' +\n (method !== 'GET' ? ', {\\\\n method: \"' + method + '\",\\\\n}' : '') + ');\\\\n\\\\n' +\n 'const data = await response.json();\\\\n' +\n 'console.log(data);';\n\n case 'recker':\n if (hasBody) {\n return 'import { ' + method.toLowerCase() + ' } from \"recker\";\\\\n\\\\n' +\n 'const data = await ' + method.toLowerCase() + '(\"' + url + '\")\\\\n' +\n ' .json(' + bodyStr.split('\\\\n').map((l, i) => i === 0 ? l : ' ' + l).join('\\\\n') + ')\\\\n' +\n ' .json();\\\\n\\\\n' +\n 'console.log(data);';\n }\n return 'import { ' + method.toLowerCase() + ' } from \"recker\";\\\\n\\\\n' +\n 'const data = await ' + method.toLowerCase() + '(\"' + url + '\").json();\\\\n\\\\n' +\n 'console.log(data);';\n\n case 'python':\n if (hasBody) {\n return 'import requests\\\\n\\\\n' +\n 'response = requests.' + method.toLowerCase() + '(\\\\n' +\n ' \"' + url + '\",\\\\n' +\n ' json=' + bodyStr.split('\\\\n').map((l, i) => i === 0 ? l : ' ' + l).join('\\\\n') + ',\\\\n' +\n ')\\\\n\\\\n' +\n 'print(response.json())';\n }\n return 'import requests\\\\n\\\\n' +\n 'response = requests.' + method.toLowerCase() + '(\"' + url + '\")\\\\n\\\\n' +\n 'print(response.json())';\n\n case 'go':\n if (hasBody) {\n return 'package main\\\\n\\\\n' +\n 'import (\\\\n' +\n ' \"bytes\"\\\\n' +\n ' \"encoding/json\"\\\\n' +\n ' \"fmt\"\\\\n' +\n ' \"net/http\"\\\\n' +\n ' \"io\"\\\\n' +\n ')\\\\n\\\\n' +\n 'func main() {\\\\n' +\n ' body, _ := json.Marshal(map[string]interface{}{\\\\n' +\n generateGoMapBody(body) +\n ' })\\\\n\\\\n' +\n ' req, _ := http.NewRequest(\"' + method + '\", \"' + url + '\", bytes.NewBuffer(body))\\\\n' +\n ' req.Header.Set(\"Content-Type\", \"application/json\")\\\\n\\\\n' +\n ' client := &http.Client{}\\\\n' +\n ' resp, _ := client.Do(req)\\\\n' +\n ' defer resp.Body.Close()\\\\n\\\\n' +\n ' data, _ := io.ReadAll(resp.Body)\\\\n' +\n ' fmt.Println(string(data))\\\\n' +\n '}';\n }\n return 'package main\\\\n\\\\n' +\n 'import (\\\\n' +\n ' \"fmt\"\\\\n' +\n ' \"net/http\"\\\\n' +\n ' \"io\"\\\\n' +\n ')\\\\n\\\\n' +\n 'func main() {\\\\n' +\n ' resp, _ := http.Get(\"' + url + '\")\\\\n' +\n ' defer resp.Body.Close()\\\\n\\\\n' +\n ' body, _ := io.ReadAll(resp.Body)\\\\n' +\n ' fmt.Println(string(body))\\\\n' +\n '}';\n\n default:\n return '// Not implemented';\n }\n }\n\n function generateGoMapBody(body) {\n if (!body || typeof body !== 'object') return '';\n const lines = [];\n for (const [key, value] of Object.entries(body)) {\n const goValue = typeof value === 'string' ? '\"' + value + '\"' :\n typeof value === 'number' ? String(value) :\n typeof value === 'boolean' ? String(value) :\n 'nil';\n lines.push(' \"' + key + '\": ' + goValue + ',');\n }\n return lines.join('\\\\n') + '\\\\n';\n }\n\n function buildExampleFromSchema(schema) {\n if (!schema) return null;\n\n // Resolve $ref\n if (schema.$ref) {\n const resolved = resolveRef(schema.$ref);\n return buildExampleFromSchema(resolved);\n }\n\n // Normalize non-standard format\n schema = normalizeSchema(schema);\n\n if (schema.example !== undefined) return schema.example;\n if (schema.default !== undefined) return schema.default;\n\n if (schema.type === 'object' && schema.properties) {\n const obj = {};\n for (const [key, prop] of Object.entries(schema.properties)) {\n obj[key] = buildExampleFromSchema(prop);\n }\n return obj;\n }\n\n if (schema.type === 'array' && schema.items) {\n return [buildExampleFromSchema(schema.items)];\n }\n\n // Primitive defaults\n switch (schema.type) {\n case 'string': return schema.format === 'email' ? 'user@example.com' : 'string';\n case 'number': return 0;\n case 'integer': return 0;\n case 'boolean': return true;\n default: return null;\n }\n }\n\n";
|
|
5
|
-
//# sourceMappingURL=cards-and-code.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"cards-and-code.js","sourceRoot":"","sources":["../../../../src/docs/ui/client-script/cards-and-code.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,CAAC,MAAM,wBAAwB,GAAG,mx6BAAmx6B,CAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"content.d.ts","sourceRoot":"","sources":["../../../../src/docs/ui/client-script/content.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,eAAO,MAAM,mBAAmB,QAuZ/B,CAAA"}
|
|
@@ -1,412 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Embedded docs UI client script chunk.
|
|
3
|
-
*/
|
|
4
|
-
export const contentClientScript = String.raw ` function renderContent() {
|
|
5
|
-
const main = document.getElementById('mainContent');
|
|
6
|
-
unmountDocsComponents(main);
|
|
7
|
-
main.textContent = '';
|
|
8
|
-
runVoidHook('beforeRender', getPluginContext());
|
|
9
|
-
|
|
10
|
-
const docsPage = getActiveDocsPage();
|
|
11
|
-
if (docsPage) {
|
|
12
|
-
renderDocsPage(main, docsPage);
|
|
13
|
-
renderTableOfContents(main);
|
|
14
|
-
renderMermaidDiagrams(main);
|
|
15
|
-
mountDocsComponents(main);
|
|
16
|
-
runVoidHook('afterRender', getPluginContext());
|
|
17
|
-
return;
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
document.title = spec.info.title;
|
|
21
|
-
|
|
22
|
-
if (searchQuery) {
|
|
23
|
-
renderDocsPageSearchResults(main);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
// Render API introduction/description (only when not searching)
|
|
27
|
-
if (!searchQuery && spec.info && spec.info.description) {
|
|
28
|
-
const intro = document.createElement('div');
|
|
29
|
-
intro.className = 'intro-section';
|
|
30
|
-
intro.id = 'introduction';
|
|
31
|
-
|
|
32
|
-
const content = document.createElement('div');
|
|
33
|
-
content.className = 'markdown-content';
|
|
34
|
-
content.innerHTML = parseMarkdown(spec.info.description);
|
|
35
|
-
intro.appendChild(content);
|
|
36
|
-
main.appendChild(intro);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const endpoints = getEndpointsForProtocol(activeProtocol);
|
|
40
|
-
const filtered = searchQuery
|
|
41
|
-
? endpoints.filter(e =>
|
|
42
|
-
e.path.toLowerCase().includes(searchQuery) ||
|
|
43
|
-
(e.summary || '').toLowerCase().includes(searchQuery) ||
|
|
44
|
-
(e.description || '').toLowerCase().includes(searchQuery)
|
|
45
|
-
)
|
|
46
|
-
: endpoints;
|
|
47
|
-
|
|
48
|
-
if (filtered.length === 0) {
|
|
49
|
-
if (main.childElementCount === 0) {
|
|
50
|
-
const empty = document.createElement('div');
|
|
51
|
-
empty.className = 'section';
|
|
52
|
-
empty.innerHTML = '<p style="color: var(--text-muted);">No endpoints found' +
|
|
53
|
-
(searchQuery ? ' matching "' + esc(searchQuery) + '"' : '') + '</p>';
|
|
54
|
-
main.appendChild(empty);
|
|
55
|
-
}
|
|
56
|
-
renderTableOfContents(main);
|
|
57
|
-
renderMermaidDiagrams(main);
|
|
58
|
-
mountDocsComponents(main);
|
|
59
|
-
runVoidHook('afterRender', getPluginContext());
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// Group by tags for display
|
|
64
|
-
const tagMap = new Map();
|
|
65
|
-
filtered.forEach(ep => {
|
|
66
|
-
const tag = (ep.tags && ep.tags[0]) || 'Endpoints';
|
|
67
|
-
if (!tagMap.has(tag)) tagMap.set(tag, []);
|
|
68
|
-
tagMap.get(tag).push(ep);
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
tagMap.forEach((eps, tag) => {
|
|
72
|
-
const section = document.createElement('div');
|
|
73
|
-
section.className = 'section';
|
|
74
|
-
|
|
75
|
-
const title = document.createElement('h2');
|
|
76
|
-
title.className = 'section-title';
|
|
77
|
-
title.id = slugifyHeading(tag);
|
|
78
|
-
title.textContent = tag;
|
|
79
|
-
section.appendChild(title);
|
|
80
|
-
|
|
81
|
-
// Find tag description from spec
|
|
82
|
-
const tagDef = (spec.tags || []).find(t => t.name === tag);
|
|
83
|
-
if (tagDef?.description) {
|
|
84
|
-
const desc = document.createElement('p');
|
|
85
|
-
desc.className = 'section-desc';
|
|
86
|
-
desc.textContent = tagDef.description;
|
|
87
|
-
section.appendChild(desc);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
eps.forEach(ep => {
|
|
91
|
-
const card = createEndpointCard(ep);
|
|
92
|
-
section.appendChild(card);
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
main.appendChild(section);
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
renderTableOfContents(main);
|
|
99
|
-
renderMermaidDiagrams(main);
|
|
100
|
-
mountDocsComponents(main);
|
|
101
|
-
runVoidHook('afterRender', getPluginContext());
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
function getActiveDocsPage() {
|
|
105
|
-
if (!activePagePath || !Array.isArray(docsPages)) return null;
|
|
106
|
-
return getDocsPageViews().find(page => normalizeDocsPath(page.path) === activePagePath) || null;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
function renderDocsPage(main, page) {
|
|
110
|
-
const breadcrumb = renderDocsBreadcrumb(page);
|
|
111
|
-
if (breadcrumb) main.appendChild(breadcrumb);
|
|
112
|
-
const article = document.createElement('article');
|
|
113
|
-
article.className = 'docs-page markdown-content';
|
|
114
|
-
article.dataset.path = page.path;
|
|
115
|
-
article.innerHTML = parseMarkdown(getDocsPageMarkdown(page));
|
|
116
|
-
main.appendChild(article);
|
|
117
|
-
document.title = page.title ? page.title + ' - ' + spec.info.title : spec.info.title;
|
|
118
|
-
renderDocsPagination(main, page);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
/* Resolve the breadcrumb chain from the declarative sidebar tree. Pure
|
|
122
|
-
traversal — mirrors src/docs/ui/breadcrumbs.ts. Returns [] when the
|
|
123
|
-
chain has fewer than 2 entries (single-segment / home / not found). */
|
|
124
|
-
function resolveDocsBreadcrumbs(sidebar, activePath) {
|
|
125
|
-
const items = Array.isArray(sidebar) ? sidebar : [];
|
|
126
|
-
const target = normalizeDocsPath(activePath);
|
|
127
|
-
if (!target) return [];
|
|
128
|
-
const chain = findBreadcrumbChain(items, target);
|
|
129
|
-
return chain && chain.length >= 2 ? chain : [];
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
function findBreadcrumbChain(items, target) {
|
|
133
|
-
for (const item of items) {
|
|
134
|
-
const itemPath = item && item.path ? normalizeDocsPath(item.path) : '';
|
|
135
|
-
const isExternalOnly = !item.path && !!item.href;
|
|
136
|
-
const ownEntry = isExternalOnly ? null : { title: String(item.title || item.path || item.href || '').trim(), path: itemPath };
|
|
137
|
-
if (itemPath && itemPath === target && ownEntry) return [ownEntry];
|
|
138
|
-
const children = Array.isArray(item.children) ? item.children : [];
|
|
139
|
-
if (children.length > 0) {
|
|
140
|
-
const sub = findBreadcrumbChain(children, target);
|
|
141
|
-
if (sub) {
|
|
142
|
-
const head = ownEntry || { title: String(item.title || item.path || item.href || '').trim(), path: '' };
|
|
143
|
-
return [head, ...sub];
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
return null;
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
function renderDocsBreadcrumb(page) {
|
|
151
|
-
const config = (typeof breadcrumbsConfig === 'object' && breadcrumbsConfig) || { enabled: true, hideOnHome: true };
|
|
152
|
-
if (config.enabled === false) return null;
|
|
153
|
-
const activePath = normalizeDocsPath(page && page.path);
|
|
154
|
-
if (!activePath) return null;
|
|
155
|
-
if (config.hideOnHome !== false && (activePath === '/' || activePath === '/index' || activePath === '/home')) return null;
|
|
156
|
-
const chain = resolveDocsBreadcrumbs(docsSidebar, activePath);
|
|
157
|
-
if (!chain || chain.length < 2) return null;
|
|
158
|
-
const nav = document.createElement('nav');
|
|
159
|
-
nav.className = 'docs-breadcrumb';
|
|
160
|
-
nav.setAttribute('aria-label', 'Breadcrumb');
|
|
161
|
-
const ol = document.createElement('ol');
|
|
162
|
-
ol.className = 'docs-breadcrumb-list';
|
|
163
|
-
chain.forEach((entry, idx) => {
|
|
164
|
-
const li = document.createElement('li');
|
|
165
|
-
li.className = 'docs-breadcrumb-item';
|
|
166
|
-
const isLast = idx === chain.length - 1;
|
|
167
|
-
if (isLast) {
|
|
168
|
-
const span = document.createElement('span');
|
|
169
|
-
span.className = 'docs-breadcrumb-current';
|
|
170
|
-
span.setAttribute('aria-current', 'page');
|
|
171
|
-
span.textContent = entry.title;
|
|
172
|
-
li.appendChild(span);
|
|
173
|
-
} else if (entry.path) {
|
|
174
|
-
const a = document.createElement('a');
|
|
175
|
-
a.className = 'docs-breadcrumb-link';
|
|
176
|
-
a.href = '#' + entry.path;
|
|
177
|
-
a.textContent = entry.title;
|
|
178
|
-
a.onclick = (event) => {
|
|
179
|
-
event.preventDefault();
|
|
180
|
-
setDocsPage(entry.path);
|
|
181
|
-
};
|
|
182
|
-
li.appendChild(a);
|
|
183
|
-
} else {
|
|
184
|
-
const span = document.createElement('span');
|
|
185
|
-
span.className = 'docs-breadcrumb-label';
|
|
186
|
-
span.textContent = entry.title;
|
|
187
|
-
li.appendChild(span);
|
|
188
|
-
}
|
|
189
|
-
ol.appendChild(li);
|
|
190
|
-
if (!isLast) {
|
|
191
|
-
const sep = document.createElement('span');
|
|
192
|
-
sep.className = 'docs-breadcrumb-separator';
|
|
193
|
-
sep.setAttribute('aria-hidden', 'true');
|
|
194
|
-
sep.textContent = '›';
|
|
195
|
-
ol.appendChild(sep);
|
|
196
|
-
}
|
|
197
|
-
});
|
|
198
|
-
nav.appendChild(ol);
|
|
199
|
-
return nav;
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
function renderDocsPageSearchResults(main) {
|
|
203
|
-
if (!Array.isArray(docsPages) || docsPages.length === 0) return;
|
|
204
|
-
const matches = applySearchResultsHook(getDocsPageViews().filter(page =>
|
|
205
|
-
(page.title || '').toLowerCase().includes(searchQuery) ||
|
|
206
|
-
(page.description || '').toLowerCase().includes(searchQuery) ||
|
|
207
|
-
(page.markdown || '').toLowerCase().includes(searchQuery)
|
|
208
|
-
), getPluginContext());
|
|
209
|
-
if (matches.length === 0) return;
|
|
210
|
-
|
|
211
|
-
const section = document.createElement('section');
|
|
212
|
-
section.className = 'section docs-search-results';
|
|
213
|
-
const title = document.createElement('h2');
|
|
214
|
-
title.className = 'section-title';
|
|
215
|
-
title.id = 'docs-pages';
|
|
216
|
-
title.textContent = 'Documentation pages';
|
|
217
|
-
section.appendChild(title);
|
|
218
|
-
|
|
219
|
-
matches
|
|
220
|
-
.forEach(page => {
|
|
221
|
-
const card = document.createElement('button');
|
|
222
|
-
card.type = 'button';
|
|
223
|
-
card.className = 'docs-page-result';
|
|
224
|
-
card.innerHTML = '<span class="docs-page-result-title">' + esc(page.title || page.path) + '</span>' +
|
|
225
|
-
(page.description ? '<span class="docs-page-result-desc">' + esc(page.description) + '</span>' : '');
|
|
226
|
-
card.onclick = () => setDocsPage(page.path);
|
|
227
|
-
section.appendChild(card);
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
main.appendChild(section);
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
function flattenSidebarReadingOrder(items) {
|
|
234
|
-
const out = [];
|
|
235
|
-
const visit = node => {
|
|
236
|
-
if (!node) return;
|
|
237
|
-
const path = node.path;
|
|
238
|
-
const isExternal = typeof path === 'string' && (/^(?:[a-z][a-z0-9+.-]*:)?\/\//i.test(path) || /^(?:mailto|tel):/i.test(path));
|
|
239
|
-
if (path && !isExternal) {
|
|
240
|
-
const title = String(node.title || path).trim();
|
|
241
|
-
out.push({ title, path });
|
|
242
|
-
}
|
|
243
|
-
if (Array.isArray(node.children)) node.children.forEach(visit);
|
|
244
|
-
};
|
|
245
|
-
(Array.isArray(items) ? items : []).forEach(visit);
|
|
246
|
-
return out;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
function getPageNavOptedOut() {
|
|
250
|
-
const opted = new Set();
|
|
251
|
-
const hide = (pageNavConfig && Array.isArray(pageNavConfig.hide)) ? pageNavConfig.hide : [];
|
|
252
|
-
hide.forEach(path => { if (path) opted.add(normalizeDocsPath(String(path))); });
|
|
253
|
-
(Array.isArray(docsPages) ? docsPages : []).forEach(raw => {
|
|
254
|
-
if (!raw || !raw.path) return;
|
|
255
|
-
const parsed = parsePageFrontmatter(raw.markdown || '');
|
|
256
|
-
const flag = String(parsed.data.pageNav || '').toLowerCase();
|
|
257
|
-
if (flag === 'false' || flag === 'no' || flag === '0') opted.add(normalizeDocsPath(raw.path));
|
|
258
|
-
});
|
|
259
|
-
return opted;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
function renderDocsPagination(main, page) {
|
|
263
|
-
if (pageNavConfig && pageNavConfig.enabled === false) return;
|
|
264
|
-
const sidebar = Array.isArray(docsSidebar) ? docsSidebar : [];
|
|
265
|
-
const order = flattenSidebarReadingOrder(sidebar).map(entry => ({
|
|
266
|
-
title: entry.title,
|
|
267
|
-
path: normalizeDocsPath(entry.path),
|
|
268
|
-
}));
|
|
269
|
-
if (order.length < 2) return;
|
|
270
|
-
const optedOut = getPageNavOptedOut();
|
|
271
|
-
const activePath = normalizeDocsPath(page.path);
|
|
272
|
-
if (optedOut.has(activePath)) return;
|
|
273
|
-
const index = order.findIndex(item => item.path === activePath);
|
|
274
|
-
if (index === -1) return;
|
|
275
|
-
let previous, next;
|
|
276
|
-
for (let i = index - 1; i >= 0; i -= 1) {
|
|
277
|
-
if (!optedOut.has(order[i].path)) { previous = order[i]; break; }
|
|
278
|
-
}
|
|
279
|
-
for (let i = index + 1; i < order.length; i += 1) {
|
|
280
|
-
if (!optedOut.has(order[i].path)) { next = order[i]; break; }
|
|
281
|
-
}
|
|
282
|
-
if (!previous && !next) return;
|
|
283
|
-
|
|
284
|
-
const nav = document.createElement('nav');
|
|
285
|
-
nav.className = 'page-nav-grid docs-pagination';
|
|
286
|
-
nav.setAttribute('aria-label', 'Page navigation');
|
|
287
|
-
|
|
288
|
-
if (previous) nav.appendChild(createDocsPaginationLink(previous, 'Previous', 'prev'));
|
|
289
|
-
else nav.appendChild(document.createElement('span'));
|
|
290
|
-
|
|
291
|
-
if (next) nav.appendChild(createDocsPaginationLink(next, 'Next', 'next'));
|
|
292
|
-
else nav.appendChild(document.createElement('span'));
|
|
293
|
-
|
|
294
|
-
main.appendChild(nav);
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
function createDocsPaginationLink(page, label, direction) {
|
|
298
|
-
const link = document.createElement('button');
|
|
299
|
-
link.type = 'button';
|
|
300
|
-
const legacyDir = direction === 'prev' ? 'previous' : 'next';
|
|
301
|
-
link.className = 'page-nav-card page-nav-card-' + direction + ' docs-pagination-link docs-pagination-' + legacyDir;
|
|
302
|
-
link.innerHTML = '<span class="page-nav-eyebrow docs-pagination-label">' + esc(label) + '</span>' +
|
|
303
|
-
'<span class="page-nav-title docs-pagination-title">' + esc(page.title) + '</span>';
|
|
304
|
-
link.onclick = () => setDocsPage(page.path);
|
|
305
|
-
return link;
|
|
306
|
-
}
|
|
307
|
-
|
|
308
|
-
function renderFooter() {
|
|
309
|
-
const footer = document.getElementById('docsFooter');
|
|
310
|
-
if (!footer || !footerMarkdown) return;
|
|
311
|
-
footer.innerHTML = parseMarkdown(footerMarkdown);
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
function renderTryItOut(endpoint) {
|
|
315
|
-
const toc = document.getElementById('pageToc');
|
|
316
|
-
if (!toc) return;
|
|
317
|
-
toc.textContent = '';
|
|
318
|
-
|
|
319
|
-
const title = document.createElement('div');
|
|
320
|
-
title.className = 'toc-title';
|
|
321
|
-
title.innerHTML = '▶ Try it out';
|
|
322
|
-
toc.appendChild(title);
|
|
323
|
-
|
|
324
|
-
const info = document.createElement('div');
|
|
325
|
-
info.style.fontSize = '12px';
|
|
326
|
-
info.style.lineHeight = '1.6';
|
|
327
|
-
info.style.marginBottom = '12px';
|
|
328
|
-
|
|
329
|
-
// Method + Path
|
|
330
|
-
if (endpoint.method && endpoint.path) {
|
|
331
|
-
const methodEl = document.createElement('div');
|
|
332
|
-
methodEl.style.marginBottom = '8px';
|
|
333
|
-
methodEl.innerHTML = '<span style="background: rgba(255,255,255,0.1); padding: 2px 6px; border-radius: 3px;">' +
|
|
334
|
-
esc(endpoint.method) + '</span> ' +
|
|
335
|
-
'<span style="font-family: monospace; color: #90caf9;">' + esc(endpoint.path) + '</span>';
|
|
336
|
-
info.appendChild(methodEl);
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
// Description
|
|
340
|
-
if (endpoint.summary) {
|
|
341
|
-
const descEl = document.createElement('div');
|
|
342
|
-
descEl.style.marginBottom = '12px';
|
|
343
|
-
descEl.style.color = '#b0bec5';
|
|
344
|
-
descEl.textContent = endpoint.summary;
|
|
345
|
-
info.appendChild(descEl);
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
// cURL example for HTTP
|
|
349
|
-
if (activeProtocol === 'http' && endpoint.method && endpoint.path) {
|
|
350
|
-
const curlTitle = document.createElement('div');
|
|
351
|
-
curlTitle.className = 'toc-title';
|
|
352
|
-
curlTitle.style.marginTop = '16px';
|
|
353
|
-
curlTitle.style.fontSize = '11px';
|
|
354
|
-
curlTitle.textContent = 'Example cURL';
|
|
355
|
-
info.appendChild(curlTitle);
|
|
356
|
-
|
|
357
|
-
const curlCode = document.createElement('div');
|
|
358
|
-
curlCode.style.background = 'rgba(0,0,0,0.3)';
|
|
359
|
-
curlCode.style.padding = '8px';
|
|
360
|
-
curlCode.style.borderRadius = '4px';
|
|
361
|
-
curlCode.style.fontFamily = 'monospace';
|
|
362
|
-
curlCode.style.fontSize = '10px';
|
|
363
|
-
curlCode.style.color = '#a1d82f';
|
|
364
|
-
curlCode.style.overflow = 'auto';
|
|
365
|
-
curlCode.style.whiteSpace = 'pre-wrap';
|
|
366
|
-
curlCode.textContent = 'curl -X ' + endpoint.method + ' \\\n ' +
|
|
367
|
-
(window.location.origin || 'http://localhost:3000') + endpoint.path + ' \\\n -H "Content-Type: application/json"';
|
|
368
|
-
info.appendChild(curlCode);
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
toc.appendChild(info);
|
|
372
|
-
}
|
|
373
|
-
|
|
374
|
-
function renderTableOfContents(root) {
|
|
375
|
-
const toc = document.getElementById('pageToc');
|
|
376
|
-
if (!toc) return;
|
|
377
|
-
toc.textContent = '';
|
|
378
|
-
if (tocConfig.enabled === false) return;
|
|
379
|
-
if (root.querySelector('[data-markdown-ignore-all="true"]')) return;
|
|
380
|
-
|
|
381
|
-
const min = Number(tocConfig.minLevel || 2);
|
|
382
|
-
const max = Number(tocConfig.maxLevel || 3);
|
|
383
|
-
const headings = Array.from(root.querySelectorAll('h1,h2,h3,h4,h5,h6'))
|
|
384
|
-
.filter(heading => {
|
|
385
|
-
const level = Number(heading.tagName.slice(1));
|
|
386
|
-
return level >= min && level <= max && heading.id && heading.dataset.markdownIgnore !== 'true';
|
|
387
|
-
});
|
|
388
|
-
|
|
389
|
-
if (headings.length === 0) return;
|
|
390
|
-
|
|
391
|
-
const title = document.createElement('div');
|
|
392
|
-
title.className = 'toc-title';
|
|
393
|
-
title.textContent = 'On this page';
|
|
394
|
-
toc.appendChild(title);
|
|
395
|
-
|
|
396
|
-
headings.forEach(heading => {
|
|
397
|
-
const level = Number(heading.tagName.slice(1));
|
|
398
|
-
const item = document.createElement('a');
|
|
399
|
-
item.className = 'toc-link toc-level-' + level;
|
|
400
|
-
item.href = '#' + heading.id;
|
|
401
|
-
item.textContent = heading.textContent ? heading.textContent.replace(/^#/, '').trim() : '';
|
|
402
|
-
item.onclick = (event) => {
|
|
403
|
-
event.preventDefault();
|
|
404
|
-
heading.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
|
405
|
-
history.replaceState(null, '', '#' + heading.id);
|
|
406
|
-
};
|
|
407
|
-
toc.appendChild(item);
|
|
408
|
-
});
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
`;
|
|
412
|
-
//# sourceMappingURL=content.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"content.js","sourceRoot":"","sources":["../../../../src/docs/ui/client-script/content.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuZ5C,CAAA"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"docs-pages.d.ts","sourceRoot":"","sources":["../../../../src/docs/ui/client-script/docs-pages.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,eAAO,MAAM,qBAAqB,QAoJjC,CAAA"}
|