Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ jobs:
try {
const address = server.address();
const origin = `http://127.0.0.1:${address.port}`;
const login = await fetch(`${origin}/example-login`);
const login = await fetch(`${origin}/docs/example-login`);
if (!login.ok) throw new Error(`Express demo login returned ${login.status}`);
const setCookie = login.headers.get('set-cookie');
if (!setCookie) throw new Error('Express demo login did not issue a session cookie');
Expand Down
16 changes: 0 additions & 16 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,19 +1,3 @@
SPDX-License-Identifier: Apache-2.0

Copyright 2025 Vishnu R <vishnurajesh45@gmail.com>

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
Expand Down
3 changes: 3 additions & 0 deletions NOTICE
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
FlexDoc
Copyright 2025 Vishnu R <vishnurajesh45@gmail.com>

** tslib; version 2.8.1 -- https://www.typescriptlang.org/
Copyright (c) Microsoft Corporation

Expand Down
49 changes: 41 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,7 @@
<img src="https://flexdoc.prauga.com/brand/flexdoc/wordmark-light.svg" alt="FlexDoc" width="300" />
</picture>

<p><strong>Backend-native OpenAPI documentation, API exploration, and execution.</strong></p>
<p>One canonical renderer. Thin native adapters. No FlexDoc control plane required.</p>
<p><strong>Your OpenAPI says one thing. Your backend may be running another.</strong></p>

<p>
<a href="https://github.com/Prauga/flexdoc/actions/workflows/ci.yml"><img alt="CI" src="https://github.com/Prauga/flexdoc/actions/workflows/ci.yml/badge.svg?branch=main" /></a>
Expand All @@ -22,9 +21,43 @@
</p>
</div>

FlexDoc is Prauga's open-source, self-hosted OpenAPI documentation renderer and API explorer. It ships one canonical browser renderer and thin ecosystem adapters so supported backends expose the same documentation, Try It, API Client, Runtime Intelligence, and backend-produced Contract Validation behavior where the host can genuinely observe it.
FlexDoc runs inside the backend and reads the routes the framework actually registered. **On Node today,** it compares that runtime surface with OpenAPI, fails `flexdoc validate` on unacknowledged disagreement, and lets you open an undocumented runtime route directly in the built-in API Client.

No FlexDoc account, hosted dashboard, telemetry service, or runtime CDN is required.
It also provides self-hosted API documentation, exploration, and execution. No FlexDoc account or control plane required.

Against the Express example, after its demo login:

```text
$ npx @prauga/flexdoc-cli validate \
http://localhost:3000/docs/__flexdoc/runtime \
--header 'Cookie: flexdoc-example-session=demo'

FlexDoc contract validation: FAIL
1 error, 0 warnings, 1 info · discovery complete

[INFO] runtime.operation-undocumented · GET /internal/health · acknowledged
Runtime implements GET /internal/health, but OpenAPI does not document that operation.

[ERROR] runtime.operation-undocumented · POST /internal/reindex
Runtime implements POST /internal/reindex, but OpenAPI does not document that operation.
```

```text
Open FlexDoc
↓
Runtime
↓
POST /internal/reindex
↓
Contract: OpenAPI does not declare this operation
Runtime: POST /internal/reindex is registered
↓
Open in API Client
```

**[Try the disagreement loop with Express](./examples/javascript-express).** That example is the evaluation path. `GET /internal/health` is runtime-only and acknowledged, so it does not fail validation. `POST /internal/reindex` is runtime-only and not acknowledged, so the check fails and the finding opens the route.

Once FlexDoc finds the disagreement, the same screen already has the documentation and API Client you need to investigate it. The package matrix and framework list below are the rest of the surface.

## Published packages

Expand Down Expand Up @@ -57,7 +90,7 @@ No FlexDoc account, hosted dashboard, telemetry service, or runtime CDN is requi
- **Rust:** Axum, Actix Web
- **Elixir:** Plug, Phoenix

The backend-coverage program shipped in 2.3.0 and the coordinated 2.x line culminated in published **2.9.9**. Stable **3.0.0** added backend-native Runtime Intelligence, published **3.1.0** added operation-level Contract Validation on Node Express/Fastify/Hono/NestJS with matching renderer and CLI consumption, and **3.2.0** took the canonical API Client request/script/collection model into headless CLI/CI execution while reusing the existing advertised host-execution contract. **3.3.0** expands hardened native API-host execution across the supported backend ecosystems and makes an available API host the default transport for ordinary interactive API Client sends. See [`docs/releases/3.3.md`](./docs/releases/3.3.md) for the security and operational release notes and [`CHANGELOG.md`](./CHANGELOG.md) for published product releases.
**3.5.0** is the current JavaScript release. On Node, a route the framework registered and OpenAPI does not document fails `flexdoc validate` when discovery is complete, and that finding opens in the API Client. See [`docs/releases/3.5.0.md`](./docs/releases/3.5.0.md). Earlier releases added Runtime Intelligence (**3.0.0**), Node contract validation (**3.1.0**), the headless Runner (**3.2.0**), and native API-host execution (**3.3.0**). [`CHANGELOG.md`](./CHANGELOG.md) records the published line.

## CLI

Expand All @@ -72,7 +105,7 @@ npx @prauga/flexdoc-cli validate http://127.0.0.1:3000/docs/__flexdoc/runtime
node tools/flexdoc-cli/bin/flexdoc.js run ./pets.flexdoc.json --json
```

`validate` consumes the installed Node backend's structured 3.1 validation result rather than reimplementing contract comparison. It supports JSON output, custom headers, bearer/basic authentication for protected Runtime Intelligence endpoints, and opt-in stricter CI failure policies such as `--fail-on warning`. By default it exits `1` only when the backend reports `fail` (or the endpoint/payload cannot be consumed).
`validate` reads the Node backend's validation result. When discovery is complete, an undocumented runtime route is an error, the output names the method and path, and the command exits `1`. An acknowledged route stays in that output as info and does not fail the check. Partial discovery keeps an unacknowledged undocumented route a warning. The command also accepts JSON output, custom headers, and bearer or basic authentication for a protected runtime endpoint. `--fail-on warning` or `--fail-on info` makes the exit stricter.

`run` consumes a versioned artifact exported from the canonical API Client workspace and delegates to the same collection/request executor and `flex.*` script/test runtime. Ordinary reusable/headless requests execute directly from Node unless host semantics are explicitly selected or required. See [`docs/headless-runner.md`](./docs/headless-runner.md) for the artifact, security, reporting, and cancellation contract.

Expand All @@ -97,7 +130,7 @@ node tools/flexdoc-cli/bin/flexdoc.js run ./pets.flexdoc.json --json
| Hex | `prauga_flexdoc` | `0.5.0` |
| Go | `github.com/prauga/flexdoc/adapters/go` | `0.6.0` |

Ecosystem package versions are intentionally independent. FlexDoc 3.3.0 is the coordinated product/source release; native adapters retain their established ecosystem semver histories. Renderer contract v1 remains the cross-language compatibility boundary.
Ecosystem package versions are intentionally independent. Client, backend, and CLI **3.5.0** / **0.8.0** publish the Node disagreement loop. Native adapters keep their own version lines. Renderer contract v1 remains the cross-language compatibility boundary.

> The package table reflects the versions encoded by the current source commit. Release-preparation commits update these source versions only when the matching release is ready; source version numbers alone do not mean an artifact has been published.

Expand Down Expand Up @@ -126,6 +159,6 @@ FlexDoc follows the [Contributor Covenant](./CODE_OF_CONDUCT.md). Bug reports an

## License

FlexDoc is licensed under **Apache-2.0**. See [LICENSE](./LICENSE).
FlexDoc is licensed under **Apache-2.0**. See [LICENSE](./LICENSE). Copyright 2025 Vishnu R is recorded in [NOTICE](./NOTICE).

The renderer, API Client, headless runner, CLI and every framework adapter are permissively licensed and stay that way — you can embed them in a proprietary application without obligation. Any future hosted or fleet control-plane product is separate code and will carry its own license; nothing in this repository depends on it.
8 changes: 5 additions & 3 deletions examples/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
# FlexDoc examples

These examples are the executable capability map for the current FlexDoc 3.3 release. Registry-consuming manifests and generated locks are pinned to the published package release versions listed below so clean standalone installs remain reproducible. Repository CI may substitute packages built from the current commit when validating source changes.
Start with [Try the disagreement loop with Express](./javascript-express). That service registers two routes OpenAPI does not document. `GET /internal/health` is acknowledged and does not fail validation. `POST /internal/reindex` is not acknowledged, so `flexdoc validate` fails and the finding opens in the API Client.

The table is the rest of the integrations. Registry-consuming manifests and generated locks are pinned to the published package versions listed below. Repository CI may substitute packages built from the current commit when validating source changes.

The examples deliberately separate two kinds of capability:

Expand All @@ -13,7 +15,7 @@ The examples deliberately separate two kinds of capability:
| [`interactive-demo`](./interactive-demo) | React + `@prauga/flexdoc-client` `3.5.0` | **Complete framework-neutral renderer**: deep links, preferences, command palette, Try It → API Client, downloads, code samples, responsive/a11y chrome | — client only |
| [`api-client`](./api-client) | Full API Client + `@prauga/flexdoc-client` `3.5.0` | **Complete standalone API Client**: environments, variables, CodeMirror scripts, runner/history, response inspection, persistence, shortcuts | — client only |
| [`nestjs`](./nestjs) | NestJS + `@prauga/flexdoc-backend` `3.5.0` | Code-first OpenAPI + full renderer/API Client | **Yes — underlying Express/Fastify adapter** |
| [`javascript-express`](./javascript-express) | Express + `@prauga/flexdoc-backend` `3.5.0` | Primary backend-native showcase with intentional route drift | **Yes — live Express router** |
| [`javascript-express`](./javascript-express) | Express + `@prauga/flexdoc-backend` `3.5.0` | Evaluation path: acknowledged `GET /internal/health` passes; `POST /internal/reindex` fails and opens in the API Client | **Yes — live Express router** |
| [`javascript-fastify`](./javascript-fastify) | Fastify + `@prauga/flexdoc-backend` `3.5.0` | Shared OpenAPI showcase + intentional runtime-only route | **Yes — live Fastify route tree** |
| [`javascript-hono`](./javascript-hono) | Hono + `@prauga/flexdoc-backend` `3.5.0` | Small inline contract + intentional runtime-only route | **Yes — live Hono route inventory** |
| [`javascript-fleet`](./javascript-fleet) | Express fleet + `@prauga/flexdoc-backend` `3.5.0` | Multi-instance host execution: shared secret, Redis jar store, fleet admission, observation merge | **Yes — live Express router** |
Expand Down Expand Up @@ -41,7 +43,7 @@ The examples deliberately separate two kinds of capability:

## What to run for the current surface

Start with `javascript-express` when evaluating FlexDoc as a product: it demonstrates the full documentation/API Client experience **and** the backend-native distinction, including a route that exists in the running application but not in OpenAPI. Use `javascript-fleet` when you need a horizontally scaled host-execution deployment with a shared session jar and fleet observation merge. Use `interactive-demo` for the framework-neutral renderer surface and `api-client` for focused API-development workflows.
Use [`javascript-express`](./javascript-express) to evaluate the product. The other examples are additional integrations: `javascript-fleet` for a horizontally scaled host-execution deployment, `interactive-demo` for the framework-neutral renderer, and `api-client` for the API Client on its own.

Runtime-capable examples intentionally include either a runtime-only route or a live controller/router inventory so the Runtime panel demonstrates evidence from the running backend rather than repeating the specification.

Expand Down
23 changes: 17 additions & 6 deletions examples/javascript-express/README.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,27 @@
# Express + FlexDoc 3.1
# Try the disagreement loop with Express

This is the primary backend-native FlexDoc 3.1 showcase. Express serves the shared OpenAPI 3.1 contract, while FlexDoc runs inside the same backend and exposes the completed documentation/API Client surface plus live Runtime Intelligence.
This is the evaluation path. Express registers two routes the OpenAPI document does not describe.

`GET /internal/health` is registered and listed in `runtimeIntelligence.acknowledgedUndocumented`. It stays a runtime-only route, the finding is informational, and it does not fail validation. `POST /internal/reindex` is also registered and is not acknowledged, so contract validation fails. Open **Runtime**, then that finding, to see the registered route beside the missing contract and send it from the API Client.
| Route | What FlexDoc records | Validation |
| --- | --- | --- |
| `GET /internal/health` | Runtime-only, acknowledged | Passes. The finding stays informational. |
| `POST /internal/reindex` | Runtime-only, not acknowledged | Fails. The finding names the method and path. |

The renderer also demonstrates the completed documentation/API Client surface: persisted viewer preferences, deep links, keyboard command palette, mobile navigation, JSON/YAML download, Basic/Advanced Try It, handoff to the sibling API Client page, environments, scripts, the CodeMirror-backed editor, response inspection, collection/history workflows, and code samples.
Open **Runtime**, then `POST /internal/reindex`. The page shows that OpenAPI does not declare the operation beside the route Express registered. **Open in API Client** sends that method and path.

```bash
npm install
npm start
```

Open `http://localhost:3000/docs`.
Open `http://localhost:3000/docs/example-login` first. That sets the demo cookie for `/docs`. Then open `http://localhost:3000/docs`.

The standalone FlexDoc dependency is pinned to `3.3.0`, the current published release, for reproducible installs. Repository CI replaces it with the backend package built from the current commit when validating source changes.
```bash
npx @prauga/flexdoc-cli validate \
http://localhost:3000/docs/__flexdoc/runtime \
--header 'Cookie: flexdoc-example-session=demo'
```

The command prints the acknowledged health route and exits `1` on `POST /internal/reindex`.

The same page also includes the documentation and API Client surface: Try It, code samples, environments, and scripts. The standalone dependency is pinned to published `@prauga/flexdoc-backend` `3.5.0`. Repository CI replaces it with the backend package built from the current commit.
14 changes: 7 additions & 7 deletions examples/javascript-express/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ function hasDemoDocsSession(req) {

function requireDocsSession(req, res, next) {
if (!hasDemoDocsSession(req)) {
res.status(401).json({ error: 'Open /example-login before using the protected FlexDoc example.' });
res.status(401).json({ error: 'Open /docs/example-login before using the protected FlexDoc example.' });
return;
}
next();
Expand All @@ -35,7 +35,7 @@ function buildApp() {
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

app.get('/example-login', (_req, res) => {
app.get('/docs/example-login', (_req, res) => {
res.cookie('flexdoc-example-session', 'demo', {
httpOnly: true,
sameSite: 'strict',
Expand Down Expand Up @@ -75,9 +75,9 @@ function buildApp() {
setupExpressFlexDoc(app, '/docs', {
spec,
options: {
title: 'FlexDoc Express 3.3 showcase',
description: 'OpenAPI 3.1 documentation, API Client workflows, native host execution, and live Express Runtime Intelligence in one backend-native example.',
version: '3.3.0',
title: 'FlexDoc Express disagreement loop',
description: 'GET /internal/health is acknowledged. POST /internal/reindex is registered by Express and absent from OpenAPI.',
version: '3.5.0',
favicon: 'data:image/svg+xml,%3Csvg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"%3E%3Crect width="32" height="32" rx="8" fill="%237c3aed"/%3E%3Ctext x="8" y="22" fill="white" font-size="18"%3EF%3C/text%3E%3C/svg%3E',
customCss: '.flexdoc-root { --express-showcase: 1; }',
customJs: 'document.documentElement.dataset.flexdocExample="express";',
Expand All @@ -99,15 +99,15 @@ function buildApp() {
hostExecution: { enabled: true, allowedOrigins: ['http://localhost:3000'] },
},
codeSamples: { enabled: true, languages: ['curl', 'javascript', 'python', 'go', 'java'] },
footer: { copyright: 'Prauga FlexDoc 3.3 showcase', link: [{ text: 'Repository', url: 'https://github.com/prauga/flexdoc' }] },
footer: { copyright: 'Prauga FlexDoc', link: [{ text: 'Repository', url: 'https://github.com/prauga/flexdoc' }] },
},
});

return app;
}

if (require.main === module) {
buildApp().listen(3000, () => console.log('Login: http://localhost:3000/example-login\nAPI: http://localhost:3000/pets\nDocs: http://localhost:3000/docs\nGET /internal/health is acknowledged. POST /internal/reindex is undocumented and fails validation.'));
buildApp().listen(3000, () => console.log('Login: http://localhost:3000/docs/example-login\nAPI: http://localhost:3000/pets\nDocs: http://localhost:3000/docs\nGET /internal/health is acknowledged. POST /internal/reindex is undocumented and fails validation.'));
}

module.exports = { buildApp };
2 changes: 1 addition & 1 deletion examples/javascript-fastify/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ npm start

Open `http://localhost:3000/docs`.

The standalone FlexDoc dependency is pinned to `3.3.0`, the current published release, for reproducible installs. Repository CI substitutes the backend package built from the same commit when validating source changes.
The standalone FlexDoc dependency is pinned to published `@prauga/flexdoc-backend` `3.5.0`. Repository CI substitutes the backend package built from the same commit when validating source changes.
2 changes: 1 addition & 1 deletion examples/javascript-hono/README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Hono + FlexDoc 3.1

This example uses Hono `4.13.x` with the optional `setupHonoFlexDoc` integration. Its registry dependency is pinned to published `@prauga/flexdoc-backend` `3.3.0` for reproducible standalone installs, while repository CI validates against the backend package built from the current commit. Runtime Intelligence reads Hono's actual registered routes instead of inferring them from the OpenAPI document.
This example uses Hono `4.13.x` with the optional `setupHonoFlexDoc` integration. Its registry dependency is pinned to published `@prauga/flexdoc-backend` `3.5.0` for reproducible standalone installs, while repository CI validates against the backend package built from the current commit. Runtime Intelligence reads Hono's actual registered routes instead of inferring them from the OpenAPI document.

The contract documents `/health` and `/pets/{petId}`. `GET /internal/health` is listed in `runtimeIntelligence.acknowledgedUndocumented`, so that finding is informational. `POST /internal/reindex` is registered only in Hono and is not acknowledged, so contract validation fails. The docs surface also enables Basic/Advanced Try It, handoff to the sibling API Client page, persisted workspace state and code samples.

Expand Down
Loading