This commit is contained in:
seb
2026-10-04 02:14:03 +02:00
parent 9a7f345d8b
commit e5ff4ef307
15 changed files with 1178 additions and 62 deletions

View File

@@ -50,6 +50,24 @@ function isRouteOmitted(method, apiPath) {
return OMITTED_ROUTES.has(`${method.toUpperCase()} ${apiPath}`);
}
/**
* Routes omitted from the main overview because their payload is binary or streaming, which is
* useless to the `dashback_request` tool — but which ARE reachable with `fetch()` from inside
* `javascript_execute`, where the bytes can be decoded, transformed, written to the VFS and shown
* as an image. These are documented separately so the model knows about them without cluttering
* the request-shaped route table.
*
* Deliberately NOT listed: import/export (administrative bulk operations the model must not
* trigger), `/v1/*` (legacy POS compat), `/events` and `/serper/images` (long-lived SSE),
* `/modelconversation/*` and `/posterminal/*` (UI plumbing, recursion risk), `/public/*`, and every
* auth/company mutation.
*/
const JS_FETCH_ONLY_ROUTES = [
'GET /image/{fullHash}',
'GET /thumb/{fullHash}',
'POST /serper/image',
];
const spec = getOpenApiSpec(true);
function ensureDir(dir) {
@@ -681,6 +699,56 @@ function renderRoutesOverview(operations, title = 'Dash API Routes Overview') {
return lines.join('\n');
}
/**
* Extra section appended to routes.md only. `all: false` renders it into the model-facing
* overview; routes-all.md stays a complete listing with no behavioural advice.
*/
function renderJsFetchSection(allOperations) {
const lines = [];
lines.push('### Binary & streaming routes (reachable only via `fetch()` in javascript_execute)');
lines.push('');
lines.push(
'These routes are NOT in the table above because their responses are binary or long-lived ' +
'streams, which the `dashback_request` tool cannot return usefully. They ARE reachable from ' +
'inside `javascript_execute` with `fetch("/route")`, where you can decode the bytes, write ' +
'them to the VFS and embed them in your reply:',
);
lines.push('');
lines.push('| Method | Route | Returns | Notes |');
lines.push('|:---|:---|:---|:---|');
lines.push(
'| `GET` | `/image/{fullHash}` | `image/avif` | Full-size article/brand/category image by SHA-256 hash. ' +
'Use for inspecting or re-encoding an existing image.',
);
lines.push(
'| `GET` | `/thumb/{fullHash}` | `image/avif` | Thumb AVIF by SHA-256 hash — cheaper than the full image. ' +
'Takes the same `fullHash` as `/image/{fullHash}`.',
);
lines.push(
'| `POST` | `/serper/image` | `image/avif` | Crawl an image from a URL, auto-crop transparent/white borders. ' +
'Body: `{ url }`.',
);
lines.push('');
lines.push('Save the bytes to the VFS, then embed them in your reply as `![title](artifacts/thumb.avif)`:');
lines.push('');
lines.push('```js');
lines.push('module.exports = (async () => {');
lines.push(' const hash = "…64-char sha-256…";');
lines.push(' const res = await fetch(`/thumb/${hash}`); // authenticated automatically');
lines.push(' const buf = Buffer.from(await res.arrayBuffer());');
lines.push(' fs.writeFileSync("artifacts/thumb.avif", buf);');
lines.push(' return { bytes: buf.length };');
lines.push('})();');
lines.push('```');
lines.push('');
lines.push(
'`fullHash` appears on articles, brands and categories. `thumbHash` is a base64 blur-up placeholder, ' +
'not a content hash, and is not accepted here.',
);
lines.push('');
return lines.join('\n');
}
// --- generate ---
ensureDir(docsDir);
rmDirContents(routesDocsDir);
@@ -712,7 +780,10 @@ for (const apiPath of paths) {
}
const overviewOperations = operations.filter((op) => !op.omittedFromOverview);
fs.writeFileSync(path.join(docsDir, 'routes.md'), renderRoutesOverview(overviewOperations));
fs.writeFileSync(
path.join(docsDir, 'routes.md'),
renderRoutesOverview(overviewOperations) + renderJsFetchSection(operations)
);
fs.writeFileSync(path.join(docsDir, 'routes-all.md'), renderRoutesOverview(operations, 'Dash API Routes Overview (All)'));
fs.writeFileSync(path.join(docsDir, 'README.md'), renderReadme(operations));
fs.writeFileSync(path.join(docsDir, 'openapi.json'), JSON.stringify(spec, null, 2));