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
47 changes: 47 additions & 0 deletions .changeset/25159-api-docs-viewer-keys-retired.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
---
'@objectstack/spec': minor
---

feat(spec)!: the docs-viewer keys are retired — `ApiDocumentationConfig.ui` (with `ApiTestingUiConfigSchema` / `ApiTestingUiType`) and the REST API plugin config's `openApi.uiPath` / `openApi.uiFramework` are refused with a prescription naming the OpenAPI document (ADR-0049)

Clause-②: no (narrowing)
Metadata-protocol: narrowed

<!-- adr-0087: registered api-docs-viewer-keys-retired -->

**BREAKING** — an accept-set narrowing on a published authoring surface, shipped as `minor` under the repo's launch-window convention for accept-set narrowings.

Three keys declared an HTML API documentation viewer, and nothing ever read any of them: `ApiDocumentationConfig.ui` (a viewer type such as `swagger-ui`, `redoc` or `scalar`, served at `ui.path`, default `/api-docs`), and on the REST API plugin config `openApi.uiPath` (default `/api/docs`) with its viewer selector `openApi.uiFramework` (default `swagger-ui`). Since the docs viewer page was taken offline, the API origin serves no HTML viewer at all, only the machine-readable OpenAPI document, so none of the three could be honoured. They are retired under ADR-0049 enforce-or-remove, with no staged window.

**What is refused:** each key is a `retiredKey()` tombstone. Authoring it is a `tsc` error at the site, and a parse error at the key's path whose message is the prescription, for every former value including the old defaults. The value schemas `ApiTestingUiConfigSchema` and `ApiTestingUiType`, with the `ApiTestingUiConfig`, `ApiTestingUiConfigParsed` and `ApiTestingUiType` types, are no longer exported: they had no consumer once `ui` was gone.

**What stays accepted:** every other key of `ApiDocumentationConfigSchema`, `OpenApiGenerationConfigSchema` and `RestApiPluginConfigSchema`, byte-identically, defaults included. The mounted REST surface is unchanged: none of the three keys ever reached it.

## FROM → TO

| you wrote | write instead |
|:--|:--|
| `ui: { type: 'swagger-ui', … }` on an `ApiDocumentationConfig` | nothing: delete the key |
| `openApi: { uiPath: '/api/docs' }` on a REST API plugin config | nothing: delete the key |
| `openApi: { uiFramework: 'redoc' }` on a REST API plugin config | nothing: delete the key |
| `import { ApiTestingUiConfigSchema, ApiTestingUiType } from '@objectstack/spec/api'` | nothing: no replacement exists |

The one-line fix: delete `ui`, `uiPath` and `uiFramework`, and point any viewer or client generator you run yourself at the OpenAPI document, `GET /api/v1/openapi.json` under the REST server's default `api.basePath` and `api.version` (the path follows both), mounted while `api.enableOpenApi` is on.

## Who is affected, measured

- **objectstack** at `b93c750c7`: zero readers and zero authorings outside `packages/spec`. The only identifier hits were a local `uiPath` variable for the unrelated `/ui/view` route in `packages/rest`; nothing in the tree parses the three schemas outside their own unit tests. A tree-scoped absence pin now holds that zero.
- **objectui** at the console pin `.objectui-sha` `56cf4d8e89`: zero hits for any of the keys or exported names, so the console build at the pin is unaffected.
- **Deployed configuration** was not measured.

## The ADR-0087 disposition

- `RETIRED_KEYS_BY_MAJOR[18]` gains `api/ApiDocumentationConfig:ui`, `api/OpenApiGenerationConfig:uiPath` and `api/OpenApiGenerationConfig:uiFramework`; `RETIRED_DEFS_BY_MAJOR[18]` gains `api/ApiTestingUiConfig` and `api/ApiTestingUiType`.
- The D3 semantic entry `api-docs-viewer-keys-retired` and its step-18 rationale fragment carry the prescription to `os migrate meta`, the upgrade guide and `spec-changes.json`.
- No D2 conversion: neither config is a stack collection member or a stored row, so no conversion seam would ever see one. `uiPath` and `uiFramework` carried Zod defaults, but nothing parses the REST API plugin config into a stored or built artifact, so no emitted default needs tolerating.

The retirement kit:

- the three tombstones and their retirement records (`packages/spec/src/api/documentation.zod.ts`, `packages/spec/src/api/plugin-rest-api.zod.ts`); the two value defs deleted; `REST_API_PLUGIN.md`'s example and feature list no longer name a viewer
- pin test `docs-viewer-keys-retirement.test.ts`: `code`, `path` and the prescription at each door (each schema and `RestApiPluginConfigSchema.openApi`), the `tsc` channel, the live controls, zero holders for the retired names, the ADR-0087 registration, and a tree-scoped absence walk
- generated artifacts follow the schema: `authorable-surface/`, `authorable-defaults/`, `json-schema.manifest/`, `api-surface/`, `export-origins/`, `declaration-map/`, the strictness-ledger counts and the reference pages for `api/documentation` and `api/plugin-rest-api`
94 changes: 12 additions & 82 deletions content/docs/references/api/documentation.mdx
Original file line number Diff line number Diff line change
@@ -1,27 +1,30 @@
---
title: Documentation schema — API Protocol reference
navTitle: Documentation
description: "Provides schemas for generating interactive API documentation and testing interfaces similar to Swagger UI, Postman, etc."
description: "Provides schemas for describing API documentation and test collections."
---

{/* ⚠️ AUTO-GENERATED — DO NOT EDIT. Run build-docs.ts to regenerate. Hand-written docs live in the module folders under content/docs/. */}

API Documentation & Testing Interface Protocol

Provides schemas for generating interactive API documentation and testing
interfaces similar to Swagger UI, Postman, etc.
Provides schemas for describing API documentation and test collections.

Features:
- OpenAPI/Swagger specification generation
- Interactive API testing playground
- API test requests and collections
- API versioning and changelog
- Code generation templates
- Mock server configuration

Architecture Alignment:
- Swagger UI: Interactive API documentation
- OpenAPI: the machine-readable API description
- Postman: API testing collections
- Redoc: Documentation rendering

The platform serves no HTML documentation viewer: the API origin publishes
the OpenAPI document (`GET {basePath}/openapi.json`) and nothing else, so
this module declares no viewer — the retired `ui` key is refused at parse
with that prescription.

**Documentation Config**
```typescript
Expand All @@ -30,11 +33,6 @@ const docConfig: ApiDocumentationConfig = {
title: 'ObjectStack API',
version: '1.0.0',
servers: [{ url: 'https://api.example.com', description: 'Production' }],
ui: {
type: 'swagger-ui',
theme: 'light',
enableTryItOut: true
}
}
```

Expand All @@ -45,8 +43,8 @@ const docConfig: ApiDocumentationConfig = {
## TypeScript Usage

```typescript
import { ApiChangelogEntrySchema, ApiDocumentationConfigSchema, ApiTestCollectionSchema, ApiTestRequestSchema, ApiTestingUiConfigSchema, ApiTestingUiType, CodeGenerationTemplateSchema, GeneratedApiDocumentationSchema, OpenApiSecuritySchemeSchema, OpenApiServerSchema, OpenApiSpecSchema } from '@objectstack/spec/api';
import type { ApiChangelogEntry, ApiDocumentationConfig, ApiTestCollection, ApiTestRequest, ApiTestingUiConfig, ApiTestingUiType, CodeGenerationTemplate, GeneratedApiDocumentation, OpenApiSecurityScheme, OpenApiServer, OpenApiSpec } from '@objectstack/spec/api';
import { ApiChangelogEntrySchema, ApiDocumentationConfigSchema, ApiTestCollectionSchema, ApiTestRequestSchema, CodeGenerationTemplateSchema, GeneratedApiDocumentationSchema, OpenApiSecuritySchemeSchema, OpenApiServerSchema, OpenApiSpecSchema } from '@objectstack/spec/api';
import type { ApiChangelogEntry, ApiDocumentationConfig, ApiTestCollection, ApiTestRequest, CodeGenerationTemplate, GeneratedApiDocumentation, OpenApiSecurityScheme, OpenApiServer, OpenApiSpec } from '@objectstack/spec/api';

// Validate data
const result = ApiChangelogEntrySchema.parse(data);
Expand Down Expand Up @@ -90,7 +88,7 @@ const result = ApiChangelogEntrySchema.parse(data);
| **version** | `string` | ✅ | API version |
| **description** | `string` | optional | API description |
| **servers** | `{ url: string; description?: string; variables?: Record<string, object> }[]` | optional (default: `[]`) | API server URLs |
| **ui** | `{ type: Enum<'swagger-ui' \| 'redoc' \| 'rapidoc' \| 'stoplight' \| 'scalar' \| 'graphiql' \| 'postman' \| 'custom'>; path?: string; theme?: Enum<'light' \| 'dark' \| 'auto'>; enableTryItOut?: boolean; … }` | optional | Testing UI configuration |
| **ui** | `never` | optional | [REMOVED] `ApiDocumentationConfig.ui` was removed in @objectstack/spec 18.1.0 (ADR-0049 enforce-or-remove) — nothing ever read it: no viewer was ever mounted from it, and the platform serves no HTML API documentation viewer at all, only the machine-readable OpenAPI document. Delete the key. The OpenAPI document is served at `GET /api/v1/openapi.json` under the REST server's default `api.basePath` and `api.version` (the path follows both) while `api.enableOpenApi` is on; point any viewer or client generator you run yourself at that document. |
| **generateOpenApi** | `boolean` | optional (default: `true`) | Generate OpenAPI 3.0 specification |
| **generateTestCollections** | `boolean` | optional (default: `true`) | Generate API test collections |
| **testCollections** | `{ name: string; description?: string; variables?: Record<string, any>; requests: object[]; … }[]` | optional (default: `[]`) | Predefined test collections |
Expand All @@ -111,23 +109,6 @@ const result = ApiChangelogEntrySchema.parse(data);
| **description** | `string` | optional | Server description |
| **variables** | `Record<string, { default: string; description?: string; enum?: string[] }>` | optional | URL template variables |

### Nested Shape: `ApiDocumentationConfig.ui`

| Property | Type | Required | Description |
| :--- | :--- | :--- | :--- |
| **type** | `Enum<'swagger-ui' \| 'redoc' \| 'rapidoc' \| 'stoplight' \| 'scalar' \| 'graphiql' \| 'postman' \| 'custom'>` | ✅ | Testing UI implementation |
| **path** | `string` | optional (default: `"/api-docs"`) | URL path for documentation UI |
| **theme** | `Enum<'light' \| 'dark' \| 'auto'>` | optional (default: `"light"`) | UI color theme |
| **enableTryItOut** | `boolean` | optional (default: `true`) | Enable interactive API testing |
| **enableFilter** | `boolean` | optional (default: `true`) | Enable endpoint filtering |
| **enableCors** | `boolean` | optional (default: `true`) | Enable CORS for browser testing |
| **defaultModelsExpandDepth** | `integer` | optional (default: `1`) | Default expand depth for schemas (-1 = fully expand) |
| **displayRequestDuration** | `boolean` | optional (default: `true`) | Show request duration |
| **syntaxHighlighting** | `boolean` | optional (default: `true`) | Enable syntax highlighting |
| **customCssUrl** | `string` | optional | Custom CSS stylesheet URL |
| **customJsUrl** | `string` | optional | Custom JavaScript URL |
| **layout** | `{ showExtensions?: boolean; showCommonExtensions?: boolean; deepLinking?: boolean; displayOperationId?: boolean; … }` | optional | Layout configuration |

### Nested Shape: `ApiDocumentationConfig.testCollections[number]`

| Property | Type | Required | Description |
Expand Down Expand Up @@ -218,57 +199,6 @@ const result = ApiChangelogEntrySchema.parse(data);
| **expectedResponse** | `{ statusCode: integer; body?: any }` | optional | Expected response for validation |


---

## ApiTestingUiConfig

### Properties

| Property | Type | Required | Description |
| :--- | :--- | :--- | :--- |
| **type** | `Enum<'swagger-ui' \| 'redoc' \| 'rapidoc' \| 'stoplight' \| 'scalar' \| 'graphiql' \| 'postman' \| 'custom'>` | ✅ | Testing UI implementation |
| **path** | `string` | optional (default: `"/api-docs"`) | URL path for documentation UI |
| **theme** | `Enum<'light' \| 'dark' \| 'auto'>` | optional (default: `"light"`) | UI color theme |
| **enableTryItOut** | `boolean` | optional (default: `true`) | Enable interactive API testing |
| **enableFilter** | `boolean` | optional (default: `true`) | Enable endpoint filtering |
| **enableCors** | `boolean` | optional (default: `true`) | Enable CORS for browser testing |
| **defaultModelsExpandDepth** | `integer` | optional (default: `1`) | Default expand depth for schemas (-1 = fully expand) |
| **displayRequestDuration** | `boolean` | optional (default: `true`) | Show request duration |
| **syntaxHighlighting** | `boolean` | optional (default: `true`) | Enable syntax highlighting |
| **customCssUrl** | `string` | optional | Custom CSS stylesheet URL |
| **customJsUrl** | `string` | optional | Custom JavaScript URL |
| **layout** | `{ showExtensions?: boolean; showCommonExtensions?: boolean; deepLinking?: boolean; displayOperationId?: boolean; … }` | optional | Layout configuration |

### Nested Shape: `ApiTestingUiConfig.layout`

| Property | Type | Required | Description |
| :--- | :--- | :--- | :--- |
| **showExtensions** | `boolean` | optional (default: `false`) | Show vendor extensions |
| **showCommonExtensions** | `boolean` | optional (default: `false`) | Show common extensions |
| **deepLinking** | `boolean` | optional (default: `true`) | Enable deep linking |
| **displayOperationId** | `boolean` | optional (default: `false`) | Display operation IDs |
| **defaultModelRendering** | `Enum<'example' \| 'model'>` | optional (default: `"example"`) | Default model rendering mode |
| **defaultModelsExpandDepth** | `integer` | optional (default: `1`) | Models expand depth |
| **defaultModelExpandDepth** | `integer` | optional (default: `1`) | Single model expand depth |
| **docExpansion** | `Enum<'list' \| 'full' \| 'none'>` | optional (default: `"list"`) | Documentation expansion mode |


---

## ApiTestingUiType

### Allowed Values

* `swagger-ui`
* `redoc`
* `rapidoc`
* `stoplight`
* `scalar`
* `graphiql`
* `postman`
* `custom`


---

## CodeGenerationTemplate
Expand Down
8 changes: 4 additions & 4 deletions content/docs/references/api/plugin-rest-api.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -104,8 +104,8 @@ const result = ErrorHandlingConfigSchema.parse(data);
| **description** | `string` | optional | API description |
| **apiVersion** | `string` | optional (default: `"1.0.0"`) | API version |
| **outputPath** | `string` | optional (default: `"/api/docs/openapi.json"`) | URL path to serve OpenAPI JSON |
| **uiPath** | `string` | optional (default: `"/api/docs"`) | URL path to serve documentation UI |
| **uiFramework** | `Enum<'swagger-ui' \| 'redoc' \| 'rapidoc' \| 'elements'>` | optional (default: `"swagger-ui"`) | Documentation UI framework |
| **uiPath** | `never` | optional | [REMOVED] `RestApiPluginConfig.openApi.uiPath` was removed in @objectstack/spec 18.1.0 (ADR-0049 enforce-or-remove) — nothing ever read it: no documentation viewer was ever served at its path, the `/api/docs` default included, and the platform serves no HTML API documentation viewer at all, only the machine-readable OpenAPI document. Delete the key. The OpenAPI document is served at `GET /api/v1/openapi.json` under the REST server's default `api.basePath` and `api.version` (the path follows both) while `api.enableOpenApi` is on; point any viewer or client generator you run yourself at that document. |
| **uiFramework** | `never` | optional | [REMOVED] `RestApiPluginConfig.openApi.uiFramework` was removed in @objectstack/spec 18.1.0 (ADR-0049 enforce-or-remove) — nothing ever read it: no `swagger-ui`, `redoc`, `rapidoc` or `elements` viewer was ever rendered from it, and the platform serves no HTML API documentation viewer at all, only the machine-readable OpenAPI document. Delete the key. The OpenAPI document is served at `GET /api/v1/openapi.json` under the REST server's default `api.basePath` and `api.version` (the path follows both) while `api.enableOpenApi` is on; point any viewer or client generator you run yourself at that document. |
| **includeInternal** | `boolean` | optional (default: `false`) | Include internal endpoints in documentation |
| **generateSchemas** | `boolean` | optional (default: `true`) | Auto-generate schemas from Zod definitions |
| **includeExamples** | `boolean` | optional (default: `true`) | Include request/response examples |
Expand Down Expand Up @@ -279,8 +279,8 @@ const result = ErrorHandlingConfigSchema.parse(data);
| **description** | `string` | optional | API description |
| **apiVersion** | `string` | optional (default: `"1.0.0"`) | API version |
| **outputPath** | `string` | optional (default: `"/api/docs/openapi.json"`) | URL path to serve OpenAPI JSON |
| **uiPath** | `string` | optional (default: `"/api/docs"`) | URL path to serve documentation UI |
| **uiFramework** | `Enum<'swagger-ui' \| 'redoc' \| 'rapidoc' \| 'elements'>` | optional (default: `"swagger-ui"`) | Documentation UI framework |
| **uiPath** | `never` | optional | [REMOVED] `RestApiPluginConfig.openApi.uiPath` was removed in @objectstack/spec 18.1.0 (ADR-0049 enforce-or-remove) — nothing ever read it: no documentation viewer was ever served at its path, the `/api/docs` default included, and the platform serves no HTML API documentation viewer at all, only the machine-readable OpenAPI document. Delete the key. The OpenAPI document is served at `GET /api/v1/openapi.json` under the REST server's default `api.basePath` and `api.version` (the path follows both) while `api.enableOpenApi` is on; point any viewer or client generator you run yourself at that document. |
| **uiFramework** | `never` | optional | [REMOVED] `RestApiPluginConfig.openApi.uiFramework` was removed in @objectstack/spec 18.1.0 (ADR-0049 enforce-or-remove) — nothing ever read it: no `swagger-ui`, `redoc`, `rapidoc` or `elements` viewer was ever rendered from it, and the platform serves no HTML API documentation viewer at all, only the machine-readable OpenAPI document. Delete the key. The OpenAPI document is served at `GET /api/v1/openapi.json` under the REST server's default `api.basePath` and `api.version` (the path follows both) while `api.enableOpenApi` is on; point any viewer or client generator you run yourself at that document. |
| **includeInternal** | `boolean` | optional (default: `false`) | Include internal endpoints in documentation |
| **generateSchemas** | `boolean` | optional (default: `true`) | Auto-generate schemas from Zod definitions |
| **includeExamples** | `boolean` | optional (default: `true`) | Include request/response examples |
Expand Down
Loading
Loading