@chatcore/contracts
v0.1.0
Published
Zod schemas, the 88-operation registry and the committed OpenAPI 3.1 document for the chat backend v1 API.
Downloads
183
Readme
@chatcore/contracts
The authoring source for the chat backend's HTTP contract. Every request and
response body is a Zod schema here; every route is one row in one operation
registry here; and openapi.json — an OpenAPI 3.1 document committed next to
this file — is generated from both. Nothing in this package is hand-maintained
twice: the document is an artifact, the schemas are the truth.
Licensed Apache-2.0 — the full text ships inside the package (LICENSE).
Do you need this package directly?
| You are | Install this? |
| --- | --- |
| Using @chatcore/server-sdk from Node | No. It is the SDK's one runtime dependency and comes down with it. You never import from here; the SDK re-exports what a caller needs from its own surface. |
| Generating a client from OpenAPI (a browser SDK, a Flutter client, a mock server) | No — read openapi.json out of the published tarball or the repo. Read the caveat below first, it changes what you generate. |
| Writing TypeScript against this API by hand, without the SDK | Yes. The Zod schemas parse and type both directions, and OPERATION_REGISTRY tells you method, path, auth mode and envelope shape for all 88 operations. |
| Implementing or extending the server | Yes, and this is the package a new route starts in — schema first, registry row second, controller third. |
What is in it
import { OPERATION_REGISTRY, CreateChannelInput, MessageResource } from '@chatcore/contracts';- Schemas — one module per domain (
messages,channels,members,uploads,polls,search,sync,tenants,projects…), all re-exported from the package root. Input schemas usez.inputsemantics — a field with a.default()/.prefault()is optional for the caller; response schemas arez.output, defaults filled in. OPERATION_REGISTRY— the closed table of 88 operations over 77 paths. Each row carriesoperationId,method,path(without the global/v1prefix),summary,exposure,retry,auth,envelope, thepathParams/query/bodyschemas and theresponseschema. It is the single inventory the server, the SDK codegen and the route-coverage tests all read, which is why adding a route without adding a row turns something red.openapi.json— OpenAPI 3.1.0,info.version 1.0.0, 77 paths, 88 operations, 154 component schemas. Committed, not built on demand, so a consumer can read it out of a git tag or an npm tarball without running Node. Every operation carriesx-sdk-exposure, the same classification as the registry'sexposurecolumn.
The registry as it stands today, in numbers worth knowing before you generate anything against it:
| Column | Values |
| --- | --- |
| exposure | facade 44 · namespace 34 · client-only 7 · internal 3 — the first two (78) are what a server SDK reaches; client-only is for end-user clients holding a user token, internal is service-to-service |
| auth | server 75 · user 7 · master 3 · none 3 |
| retry | safe 74 · unsafe 13 · never 1 — this column, not a client's own judgement, decides whether a request may be sent twice |
| envelope | single 63 ({data, request_id}) · list 22 ({items, next_cursor, request_id}) · none 3 |
Caveat: additionalProperties: false on responses, and forward compatibility
Read this before you generate a strict response validator from
openapi.json. It is the one place where the artifact says something narrower
than the server means.
Response schemas in the document are rendered with
z.toJSONSchema(schema, { io: 'output' }), and Zod 4 stamps
additionalProperties: false onto every object in the output direction —
even when the Zod schema is not .strict(). Probed against this repo's own
Zod (4.4.3):
z.object({ a: z.string() }) io: 'input' → no additionalProperties
z.object({ a: z.string() }) io: 'output' → "additionalProperties": falseMeasured on the committed artifact: 41 of the 42 *.Output object component
schemas carry it. The single exception is CustomDataSchema.Output, an open
record, which is correct.
The consequence: a generated validator that honours it will reject a response
from a newer server that added a field — which is exactly the forward
compatibility this API is designed to keep. (The server SDK is unaffected: its
Zod parse strips unknown keys instead of rejecting them, in both
validateResponses modes.) So a codegen consumer must either relax
additionalProperties when emitting response validators, or not emit strict
response validators at all. Request bodies are rendered io: 'input' and do not
carry it, so the input direction needs no special handling.
Two things this caveat does not cover: the envelope wrappers
({data, request_id} and {items, next_cursor, request_id}) are assembled by
the generator rather than by z.toJSONSchema, so they stay open and a new
envelope field would not trip a strict validator; and this is a property of the
artifact, not a defect in either the server or the SDK.
Compatibility
| | |
| --- | --- |
| Contracts | 0.1.x |
| API | v1 — every route under the /v1 prefix |
| @chatcore/server-sdk | Lockstep. The two packages are released together on the same version, and the SDK depends on an exact contracts version. Do not mix a contracts version with a server-sdk version it was not released with. |
| OpenAPI document | openapi.json, info.version 1.0.0 — the API version, which moves on its own schedule and is not the package version |
| Node | >= 24 |
| Module format | CommonJS (main + types from dist/), built with tsc |
| Runtime dependency | zod ^4 — the only one |
0.1.x speaks v1 and only v1; a /v2 prefix would be a new major of this
package, not a minor. The release number itself lives in package.json and is
deliberately not repeated in this prose, where it would go stale at the next one.
A new optional field on a response is a patch here and is not breaking — that is the case the caveat above exists to protect, so treat any tooling that turns it into a break as tooling to fix rather than as a contract change.
Regenerating openapi.json
The document is written from the built output, so build first:
pnpm --filter @chatcore/contracts build
pnpm --filter @chatcore/contracts openapi:writeopenapi:write runs node dist/openapi/cli.js and rewrites openapi.json in
place; commit the result in the same change as the schema edit that caused it.
packages/contracts/test/openapi-document.test.ts and its siblings compare the
committed artifact against the registry, so a schema edit with no regeneration
fails the suite rather than shipping a document that disagrees with the code.
