This document explains how to integrate the CMS Connector into a TypeScript project, with a example on Next.js with Directus. The pattern is simple: create a single shared instance (e.g., cmsInstance.ts) and reuse it across your application.
- A typed interface to read and (optionally) write content to your CMS.
- First-class Directus support via
cmsType: "directus". - Strong TypeScript types for resources, dictionaries, and configuration.
Create a file such as src/lib/cms/cmsInstance.ts and export a single shared instance. This instance can be imported wherever you need to access the CMS.
import { CmsFactory } from "cms-connector";
const cmsInstance = CmsFactory.createResource({
cmsType: "directus",
configuration: {
languages: ["it"],
url: process.env.FRONTEND_CMS_URL as string,
// staticToken: process.env.DIRECTUS_STATIC_TOKEN, // optional; required only for write operations
},
});
export default cmsInstance;Environment variables (example for Next.js .env):
FRONTEND_CMS_URL=https://your-directus.example.com
# DIRECTUS_STATIC_TOKEN=your-static-token # optional, only if you need write/patch/uploadKeep tokens server-side only; never expose them to the browser.
You can import the shared instance into Server Components, Route Handlers, and Server Actions.
// app/(site)/page.tsx
import cms from "@/lib/cms/cmsInstance";
export default async function HomePage() {
const page = await cms.getResource({
entityName: "page",
language: "it",
queryParameters: {
filter: { slug: { _eq: "home" } },
limit: 1,
},
includeDraft: false,
});
if (!page) return <div>Not found</div>;
return <main>{page.title}</main>;
}// app/api/pages/[slug]/route.ts
import cms from "@/lib/cms/cmsInstance";
import { NextResponse } from "next/server";
export async function GET(_: Request, { params }: { params: { slug: string } }) {
const page = await cms.getResource({
entityName: "page",
language: "it",
queryParameters: { filter: { slug: { _eq: params.slug } }, limit: 1 },
includeDraft: false,
// Pass Next.js caching hints if needed via fetchOptions (see below)
});
return NextResponse.json(page ?? null);
}All read methods accept an optional fetchOptions?: RequestInit, which Next.js understands for caching and revalidation:
await cms.getResources({
entityName: "page",
language: "it",
queryParameters: { limit: 10 },
includeDraft: false,
fetchOptions: { next: { revalidate: 60 } }, // ISR every 60 seconds
});The same instance pattern works in any Node/TypeScript setup (e.g., Express, server-side scripts):
import cms from "./cmsInstance";
async function main() {
const dictionary = await cms.getDictionary({ language: "it" });
console.log(dictionary);
}
main().catch(console.error);These are the main read methods you will use (types are strongly inferred from the underlying Directus schema):
getResource({ entityName, language, queryParameters, includeDraft, fetchOptions })getResources({ entityName, language, queryParameters, includeDraft, fetchOptions })getResourceById({ entityName, id, language, queryParameters, fetchOptions })getResourcesCount({ entityName, filterParameters, fetchOptions })getDictionary({ language, fetchOptions })getConfiguration({ language, fetchOptions })
Notes:
- If you configured
languagesin the instance, passing a language that is not in the allowed list will throw an error. includeDrafttoggles draft-vs-published behavior where supported.queryParametersandfilterParametersmirror Directus query shapes.
To use write operations, provide a staticToken in the configuration. Keep it server-side only.
uploadFile({ formData })createResource({ entityName, item })patchResource({ id, entityName, item })
Example (Server Action / Route Handler only):
import cms from "@/lib/cms/cmsInstance";
export async function createExample() {
const id = await cms.createResource({
entityName: "page",
item: { title: "Hello" },
});
return id;
}When using Directus, the factory expects:
CmsFactory.createResource({
cmsType: "directus",
configuration: {
url: string; // required
staticToken?: string; // optional (required for write ops)
languages?: readonly string[]; // optional (enables language guard)
},
});Currently supported cmsType values:
"directus"
- Create a shared instance file, e.g.
src/lib/cms/cmsInstance.ts. - Reuse the exported instance everywhere (Server Components, Route Handlers, services).
- Keep CMS environment variables in
.env.local(Next.js) or your server env.
- “Unknown CMS type …”: Ensure
cmsTypeis exactly"directus". - “Missing or invalid language”: If you configured
languages, pass only those values to read methods. - Write methods throwing: Provide
staticTokenin configuration; use them only on the server. - Network issues: Verify
FRONTEND_CMS_URLpoints to the correct Directus REST endpoint.
Here is the minimal instance example again for quick copy–paste:
import { CmsFactory } from "cms-connector";
const cmsInstance = CmsFactory.createResource({
cmsType: "directus",
configuration: {
languages: ["it"],
url: process.env.FRONTEND_CMS_URL as string,
},
});
export default cmsInstance;