@colspec/server
v0.1.1
Published
Store, version, publish and serve colspec table definitions from any database or Node.js framework.
Maintainers
Readme
@colspec/server
Store, version and serve colspec table definitions from your own backend. It works with any database and any Node.js framework, and needs no ORM or separate service.
npm install @colspec/server @colspec/core1. Implement storage
One row or document per revision, unique by (tableId, revision).
import type { TableDefinitionRepository } from "@colspec/server";
const repository: TableDefinitionRepository = {
find: (tableId, revision) => /* one record or undefined */,
findLatest: (tableId, status) => /* highest revision with that status */,
list: (tableId) => /* all revisions, oldest first */,
save: (record) => /* insert or replace */,
};createMemoryRepository() is included for tests and prototypes.
2. Manage definitions
import { createTableDefinitionService } from "@colspec/server";
const definitions = createTableDefinitionService(repository);
await definitions.saveDraft(json); // validates; throws ContractError if invalid
await definitions.publish("inventory.products", 4);
await definitions.getPublished("inventory.products"); // latest published revision
await definitions.listRevisions("inventory.products");Drafts can be saved repeatedly. A published revision is immutable; change a table by saving a new revision number.
3. Serve them
getDefinitionResponse returns { status, headers, body } with an ETag and
304 Not Modified handling.
app.get("/api/table-definitions/:tableId", async (req, res) => {
const { status, headers, body } = await getDefinitionResponse(definitions, {
tableId: req.params.tableId,
ifNoneMatch: req.get("if-none-match"),
});
res.status(status).set(headers).json(body);
});4. Accept sort and filter requests safely
Clients send operation keys, not field names. Map every key through a list you control.
import { resolveServerQuery } from "@colspec/server";
const result = resolveServerQuery(untrustedJson, {
"product.created_at": "products.created_at",
status: "products.status",
});
if (!result.ok) return badRequest(result.diagnostics);
const { sort, filters, page } = result.value; // only fields from your listMalformed input and unlisted keys are rejected. Filter values are still untrusted: validate or coerce them before they reach a query.
Not included
Authentication and authorization. Decide in your application who may save, publish and read definitions.
