Files
sim/scripts
Vikhyath Mondreti 498cdb6af0 improvement(api): retire route contracts that no route serves (#7206)
* fix(api): retire route contracts that no route serves

The staging integ alarm fired because the session knowledge-document
inline-create check got a 405. #7179 moved tool operations in process and
deleted the routes that only existed to serve them, but
`createKnowledgeDocumentsContract` kept declaring
`POST /api/knowledge/[id]/documents` — a path whose surviving GET/PATCH make
Next.js answer POST with 405 rather than an honest 404. Nothing in the repo
called it: the KB UI creates documents through the presigned upload flow, and
the capability itself is unaffected because `knowledge_create_document` reaches
the same use case in process.

Audited all 1125 contracts for the same drift. It was the only one whose path
resolves to a live route missing the declared method; 259 others declare paths
of routes that were deleted outright, which 404 honestly and are left alone.

- Drop the create-documents route contract for plain `params`/`body` schemas
  plus a named response schema, so nothing declares an endpoint we do not
  serve. The schemas stay in the contracts tree next to the siblings they share
  (`documentDataSchema` is used by the v2 contracts, and
  `createKnowledgeDocumentsBodySchema` already backed the in-process operation).
- Delete four contracts with no consumer at all — both TTS contracts, docusign,
  and mistral. Their handlers own better schemas: TTS dispatches by `toolId`
  with eight per-provider schemas instead of one passthrough superset, and
  mistral bounds `pages` by the OCR request policy. crowdstrike and windchill
  look similar but are load-bearing (schema and derived types are imported by
  live code), so they stay.
- Add `check:api-contract-routes`, picked up automatically by `run-audits`.
  `check:route-verbs` scans routes to contracts, so a contract whose route
  method was deleted is invisible to it — verified it passes clean against the
  exact regression this catches.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* fix(api): read contracts by import, and retire two more stale declarations

Greptile flagged the audit's brace counter as blind to braces inside strings,
template literals, regexes and comments. It was, but the bigger problem was that
a text scan can only see contracts whose `method`/`path` are inline literals —
the 70-plus built through `definePostSelector(path, …)` and friends were never
checked at all. Comparing raw `defineRouteContract(` occurrences against parsed
ones showed the scanner silently skipping declarations.

Read the contracts by importing each contract module and inspecting its exported
objects instead, the way `check-route-verbs.ts` already resolves the contract
behind a route. Contract modules are pure Zod so importing them is safe; route
files stay a static scan because importing one drags in `@sim/db`, auth and
`next/server`. Barrels re-export the same object, so entries are keyed by
identity. Coverage goes from 1125 contracts to 1283.

That immediately surfaced two more instances of exactly what this PR retires.
`/api/tools/confluence/page` kept its `PUT` and `DELETE` contracts after #7179
reduced the route to the selector `POST`, so both declared verbs the live route
answers with 405. Neither is fetched — `lib/internal/confluence/execute-tool.ts`
is the only consumer — so they become plain schemas like the knowledge one, and
`executeOperation` now delegates to a schema form rather than growing a second
pattern beside it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-28 00:57:02 -07:00
..

Integration documentation generator

generate-docs.ts compiles the per-service integration pages under apps/docs/content/docs/en/integrations/ from the block/tool/trigger registry in apps/sim. The ontology it encodes: everything is a block, and an integration is one block that has Actions and, optionally, a Trigger.

Golden rule: the generated .mdx files are derived artifacts, not the source of truth. Do not hand-edit them — your changes are overwritten on the next run. The only editable region is the MANUAL-CONTENT block (see below). To change what a page says, edit the TypeScript in apps/sim and regenerate.

Where an integration lives canonically

For a service like Gmail, three TS sources define it:

Source What it is What it feeds in the page
apps/sim/blocks/blocks/<service>.ts The block: type, name, category (tools for integrations), bgColor, config sub-blocks, tools.access (which actions it exposes), an optional triggers capability, outputs Header / BlockInfoCard, Usage Instructions, and which actions + trigger appear
apps/sim/tools/<service>/*.ts Each action's params + outputs Every ### <action>#### Input / #### Output under ## Actions
apps/sim/triggers/<provider>/ The trigger's config fields + outputs The ## Triggers section
apps/sim/components/icons.tsx The brand glyph The page icon

The block references actions by id in tools.access; the generator looks each one up in apps/sim/tools/.

What the generator does

Run with cd apps/sim && bun run generate-docs (or bun run scripts/generate-docs.ts from the repo root). One pass (generateAllBlockDocs):

  1. Copies icons apps/sim/components/icons.tsxapps/docs/components/icons.tsx and builds apps/docs/components/ui/icon-mapping.ts.
  2. Block pass — for each integration block (category: 'tools', plus the memory / knowledge / table exceptions), writes integrations/<service>.mdx: BlockInfoCard + Usage Instructions + ## Actions.
  3. Trigger pass (generateAllTriggerDocs) — reads apps/sim/triggers/<provider>/ and appends a ## Triggers section to that service's page, or writes a standalone page for trigger-only services.
  4. Writes integrations/meta.json and regenerates the landing page's integrations.json.

Hand-written pages it never touches

Core block pages (blocks/*), the native trigger pages (triggers/{start,schedule,webhook,rss,table}), the integrations overview (integrations/index.mdx), and the service-account pages are fully hand-written. The generator skips them via HANDWRITTEN_INTEGRATION_DOCS, HANDWRITTEN_TRIGGER_DOCS, and SKIP_TRIGGER_PROVIDERS. Add a page name to those sets if you hand-author a page the generator would otherwise produce.

Manual content (the one editable region)

Each generated page may carry hand-written prose inside marker comments. The generator preserves anything between the markers and overwrites everything else, so this survives every regeneration:

{/* MANUAL-CONTENT-START:intro */}
[AgentMail](https://agentmail.to/) is an API-first email platform…
{/* MANUAL-CONTENT-END */}

Supported section names: intro (after the BlockInfoCard — the most common), usage, configuration, outputs, notes. The merge is by marker name (extractManualContent + mergeWithManualContent), so a section is re-inserted at the matching spot in the freshly generated structure.

If you move the output folder, reseed manual content from the old location first — the generator only preserves markers it finds in the existing output file, so a fresh folder starts with none.

Practical: to change…

  • An action's params/outputs, a trigger, or to add a service → edit apps/sim/{blocks,tools,triggers} and re-run the generator.
  • A page's prose intro → edit its MANUAL-CONTENT:intro block directly; it survives regen.
  • The overview / service-account / core-block / native-trigger pages → hand-edit freely.

Gotchas

  • Never hand-edit apps/docs/components/icons.tsx — step 1 overwrites it from the sim app. Components that need an icon the sim app lacks should define it locally or use @sim/emcn/icons (see components/workflow-preview/block-icons.tsx).
  • The generator is the source of truth for integrations/ and its meta.json; manual edits there are transient.

CI

The generator runs in CI on pushes to the main branch and commits the regenerated docs back. Keep block/tool/trigger metadata accurate in apps/sim and the docs follow.