Skip to content

Repository files navigation

@itmaster/sdk

npm versionlicense: MITtypes: TypeScriptNext.jsESM

Official client SDK for IT Master — the AI SEO content engine. IT Master writes, cross-model–validates and publishes expert articles that rank on Google and get cited by AI search (ChatGPT, Perplexity, AI Overviews). This SDK connects any Next.js site to it: pull those articles and serve turnkey sitemap, RSS, llms.txt, JSON-LD, IndexNow, metadata and webhook helpers — no re-implementing the Pull API or rendering layer per site. See how it works · pricing.

The Fabric-Commerce tenants do not use this — they receive optimizations via Fabric's provider endpoints. This SDK is for independent sites that pull and display IT Master content (e.g. itmaster.uk, ai.ukvision.co.uk).

Features

  • Typed Pull API clientlistArticles, getArticle, incremental mirror (listArticlesPage).
  • Next.js App Router helpers — article Metadata, Article/FAQJSON-LD, OG/Twitter tags.
  • Turnkey SEO routes — one-line robots.txt, sitemap.xml, rss.xml, llms.txt, IndexNow key.
  • Dashboard-controlled <head> — title templates, favicons, verification + analytics tags from site_config.
  • Push webhooks — HMAC-verified publish/takedown → revalidatePath, live in seconds.
  • Provider (write-back) mode — HMAC-signed contract for CMS-style sites the engine edits directly.
  • Zero runtime deps, ESM, ships full .d.ts types. next is an optional peer.

Install

npm install @itmaster/sdk
# or: pnpm add @itmaster/sdk / yarn add @itmaster/sdk
Pre-registry / offline installs
# straight from GitHub (builds on install):
npm install github:codedpro/itmaster-sdk
# from a packed tarball:
npm install /path/to/itmaster-sdk-0.2.0.tgz
# or a path dependency (sibling repos):
npm install file:../itmaster/itmaster-sdk

Quickstart — the init CLI

Scaffold a site's integration by selecting features — it writes only new files (client + the routes you pick + middleware), adds the env keys, and prints the two snippets it won't overwrite (layout.tsx<head> and the blog pages). src/app is auto-detected; existing files are skipped unless --force.

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
✚ wrote lib/itmaster.ts
✚ wrote app/robots.txt/route.ts
✚ wrote app/api/indexnow-key/route.ts
✚ wrote middleware.ts
✚ wrote app/api/itmaster-webhook/route.ts
✚ env keys ensured in .env.local + .env.example (fill PULL_KEY)

Then fill PUBLISH_PULL_KEY, wire the two printed snippets, and connect Google (see the end). The sections below are what the CLI generates — reference them to do it by hand or to understand each piece.

Use

// lib/itmaster.ts (server-only)import"server-only";import{createClient}from"@itmaster/sdk";exportconstitmaster=createClient({baseUrl: process.env.ITMASTER_API_URL!,// engine originsite: process.env.PUBLISH_SITE!,// your TargetSite slugpullKey: process.env.PUBLISH_PULL_KEY!,// per-site key (server only)});
// app/blog/page.tsxconstposts=awaititmaster.listArticles({limit: 50});// app/blog/[slug]/page.tsximport{articleMetadata,articleJsonLd}from"@itmaster/sdk/next";consta=awaititmaster.getArticle(slug);exportconstgenerateMetadata=()=>articleMetadata(a!,{siteUrl: "https://itmaster.uk"});constld=articleJsonLd(a!,{siteUrl: "https://itmaster.uk"});

Feeds: itmaster.sitemap(), .rss(), .llmsTxt(), .robots(), .redirects(). Site config: itmaster.config(), .clusters(), .indexnowKey(). Incremental mirror: itmaster.listArticlesPage({ since }){ articles, next_since }. Push webhooks: verifyWebhookSignature(rawBody, sigHeader, secret) from @itmaster/sdk/next.

Turnkey routes (drop-in, dashboard-controlled)

Wire these one-line re-exports and the whole site is controlled from the engine dashboard — robots, feeds, head tags, IndexNow and "publish → live in seconds".

// app/robots.txt/route.tsimport{createRobotsRoute}from"@itmaster/sdk/next";import{itmaster}from"@/lib/itmaster";exportconstGET=createRobotsRoute(itmaster);// app/sitemap.xml/route.tsimport{createSitemapRoute}from"@itmaster/sdk/next";import{itmaster}from"@/lib/itmaster";exportconstGET=createSitemapRoute(itmaster);// app/rss.xml/route.ts — createRssRoute(itmaster)// app/llms.txt/route.ts — createLlmsRoute(itmaster)
// app/api/indexnow-key/route.ts — IndexNow ownership proof (no secret, no round-trip)import{createIndexNowKeyRoute}from"@itmaster/sdk/next";// Pass the engine site id (single-tenant) or a resolver (multi-tenant, from host).// The SDK DERIVES the exact key the engine submits, so only your key resolves.exportconstGET=createIndexNowKeyRoute(process.env.PUBLISH_SITE??"your-site");// middleware.ts — rewrite the /{key}.txt request to the routeimport{NextRequest,NextResponse}from"next/server";exportfunctionmiddleware(req: NextRequest){if(/^\/[a-f0-9]{32}\.txt$/.test(req.nextUrl.pathname))returnNextResponse.rewrite(newURL("/api/indexnow-key",req.url));returnNextResponse.next();}exportconstconfig={matcher: ["/((?!_next/|favicon.ico).*)"]};
// app/api/itmaster-webhook/route.ts — publish/takedown → revalidateimport{createWebhookRoute}from"@itmaster/sdk/next";import{revalidatePath}from"next/cache";exportconstPOST=createWebhookRoute({secret: process.env.PUBLISH_PUSH_SECRET!,revalidate: (a)=>{revalidatePath(`/blog/${a.slug}`);revalidatePath("/blog");},// onUpsert / onDelete are optional if you only rely on revalidation.});

Head tags + metadata from the dashboard site_config. Emit verification/OG/favicon via the Metadata API (applyMeta in generateMetadata) and analytics via next/script — those are the only paths that actually render into <head> in the App Router:

// app/layout.tsximport{applyMeta,headTagsFromConfig}from"@itmaster/sdk/next";importScriptfrom"next/script";import{itmaster}from"@/lib/itmaster";constbase: import("next").Metadata={title: {default: "…",template: "%s · …"}};exportasyncfunctiongenerateMetadata(){constconfig=awaititmaster.config().catch(()=>null);returnconfig ? applyMeta(base,config) : base;// verification + OG + favicon}exportdefaultasyncfunctionRootLayout({ children }){constconfig=awaititmaster.config().catch(()=>null);constscripts=config ? headTagsFromConfig(config).scripts : [];// GA4/GTM/Plausible/…return(<html><body>{children}{scripts.map((s,i)=>s.src ? <Scriptkey={i}src={s.src}strategy="afterInteractive"/>
: <Scriptkey={i}id={`a${i}`}strategy="afterInteractive"dangerouslySetInnerHTML={{__html: s.innerHtml??""}}/>)}</body></html>);}

⚠️ Do not render the tags via <head><Fragment dangerouslySetInnerHTML></head> — a Fragment has no DOM node, so nothing reaches <head>. Use applyMeta + next/script as above. (renderHeadHtml remains for non-App-Router/SSR string use.)

// app/blog/[slug]/page.tsx — compose article metadata with the site configimport{articleMetadata,applyMeta}from"@itmaster/sdk/next";constconfig=awaititmaster.config();letmeta=articleMetadata(a!,{ siteUrl });if(config)meta=applyMeta(meta,config);// title template/suffix, OG, twitter, faviconexportconstgenerateMetadata=()=>meta;

Provider (write-back) mode

For CMS-style sites the engine edits directly, mount the provider contract under app/api/external/[slug]/…. Implement only the handlers you need — the rest answer 501. Every POST is HMAC-verified (X-Thoth-Signature).

// app/api/external/[slug]/_routes.tsimport{createProviderRoutes}from"@itmaster/sdk/provider";exportconstroutes=createProviderRoutes({secret: process.env.PROVIDER_SECRET!,handlers: {snapshot: async(slug)=>[/* SnapshotPage[] — your page inventory */],applySeoPatch: async(slug,patch)=>{/* TODO write title/meta/og/jsonld */return{ok: true};},applyContent: async(slug,patch)=>{/* TODO apply prose blocks */return{ok: true};},revalidate: async(slug)=>{/* TODO purge ISR/CDN */return{ok: true};},},});// app/api/external/[slug]/snapshot/route.tsimport{routes}from"../_routes";exportconstGET=(req: Request,ctx: {params: Promise<{slug: string}>})=>ctx.params.then(({ slug })=>routes.snapshot(req,slug));// …and health/route.ts, seo-patch/route.ts, content/route.ts, revalidate/route.ts likewise.

API surface

ImportExports
@itmaster/sdkcreateClient, types (PublishedArticle, SiteConfig, Redirect, …)
@itmaster/sdk/nextarticleMetadata, articleJsonLd, applyMeta, headTagsFromConfig, renderHeadHtml, deriveIndexNowKey, createRobotsRoute/createSitemapRoute/createRssRoute/createLlmsRoute/createIndexNowKeyRoute, createWebhookRoute, verifyWebhookSignature
@itmaster/sdk/providercreateProviderRoutes (HMAC write-back contract)
npx @itmaster/sdk initCLI scaffolder (client + routes + middleware + env)

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:

curl -X POST "https://itmaster.uk/v1/publish/sites/<site>/connect/google/auto" \
-H "Authorization: Bearer <INTERNAL_TOKEN>"
featureneeds
verification meta / analyticsconfig() working ⇒ pull key set
IndexNowthe key route + middleware rewrite (no pull key)
Google Indexingsite connected (service account + indexing scope)
instant publishwebhook route + engine push_url / push_secret
articles at allengine generating content for the site (automation on)

Build

npm install && npm run build # → dist/ (ESM + .d.ts)

Learn more

This package everywhere:@itmaster/sdk on npm · source on GitHub (codedpro/itmaster-sdk) · report an issue

License

MIT © IT Master.

Releases

Packages

Contributors

Languages