@itmaster/sdk

One dependency wires a Next.js site to the engine: pull finished articles, serve robots.txt / sitemap.xml / rss.xml / llms.txt, source the engine-managed <head>, host the IndexNow key, and receive publish webhooks — mostly one line per feature.

Quickstart — the init CLI

Scaffold a site by selecting features. It writes only new files (client + the routes you pick + middleware), adds env keys, and prints the two snippets it won't overwrite.

npm i @itmaster/sdk

npx @itmaster/sdk init                 # interactive (y/n per feature)
# or non-interactive:
npx @itmaster/sdk init \
  --site <PUBLISH_SITE> --engine https://itmaster.uk \
  --features robots,sitemap,rss,llms,indexnow,webhook --yes

Setup

Register the site engine-side (issues a pull key), set env, create the shared client. No pull key just means every call returns null and the site still renders.

# .env.local
ITMASTER_API_URL=https://itmaster.uk
PUBLISH_SITE=<your TargetSite id>
PUBLISH_PULL_KEY=<per-site key>
// lib/itmaster.ts
import { createClient } from "@itmaster/sdk";
export const itmaster = createClient({
  baseUrl: process.env.ITMASTER_API_URL!,
  site: process.env.PUBLISH_SITE!,
  pullKey: process.env.PUBLISH_PULL_KEY ?? "",
});

What you get

robots.txt / sitemap.xml / rss.xml / llms.txt
create*Route(itmaster)
app/<name>/route.ts — 1 line each
IndexNow key
createIndexNowKeyRoute(PUBLISH_SITE)
app/api/indexnow-key/route.ts + middleware — no pull key
engine-managed <head>
applyMeta + headTagsFromConfig
app/layout.tsx — verification, analytics, OG, favicon
article metadata + JSON-LD
articleMetadata / articleJsonLd
app/blog/[slug]/page.tsx
publish → live in seconds
createWebhookRoute
app/api/itmaster-webhook/route.ts
write-back (CMS sites)
createProviderRoutes
app/api/external/[slug]/…

The one-liners

Derived feeds are a single re-export:

// app/robots.txt/route.ts   (same shape for sitemap.xml / rss.xml / llms.txt)
import { createRobotsRoute } from "@itmaster/sdk/next";
import { itmaster } from "@/lib/itmaster";
export const GET = createRobotsRoute(itmaster);

IndexNow derives the exact key the engine submits — no secret, no round-trip:

// app/api/indexnow-key/route.ts
import { createIndexNowKeyRoute } from "@itmaster/sdk/next";
export const GET = createIndexNowKeyRoute(process.env.PUBLISH_SITE ?? "your-site");

// middleware.ts
import { NextRequest, NextResponse } from "next/server";
export function middleware(req: NextRequest) {
  if (/^\/[a-f0-9]{32}\.txt$/.test(req.nextUrl.pathname))
    return NextResponse.rewrite(new URL("/api/indexnow-key", req.url));
  return NextResponse.next();
}
export const config = { matcher: ["/((?!_next/|favicon.ico).*)"] };

Engine-managed head — verification/OG/favicon via the Metadata API (the only path that reaches <head> in the App Router):

// app/layout.tsx
import { applyMeta } from "@itmaster/sdk/next";
import { itmaster } from "@/lib/itmaster";
const base = { /* your defaults */ };
export async function generateMetadata() {
  const config = await itmaster.config().catch(() => null);
  return config ? applyMeta(base, config) : base;
}

Then connect Google — zero-click

Once the head + IndexNow routes are live, one engine call verifies the site in Search Console, submits the sitemap, and turns on indexing (Google Indexing API + IndexNow).

curl -X POST "https://itmaster.uk/v1/publish/sites/<site>/connect/google/auto" \
  -H "Authorization: Bearer <INTERNAL_TOKEN>"

Full reference, provider (write-back) mode, and the incremental mirror feed are in the README.