The Code Kit
17 tested TypeScript modules that implement the checklist. This site consumes every one of them for its own SEO, which is the only claim about code quality worth making.
Module inventory
| Module | Implements |
|---|---|
kit/seo/constants.ts | Canonical normalisation, Open Graph, Twitter cards, the recursive compactor |
kit/seo/schema/graph.ts | The @graph composer, deduplication, and the @id integrity walker |
kit/seo/schema/organization.ts | Organization, WebSite, Person, ProfilePage |
kit/seo/schema/commerce.ts | Product, Offer, AggregateOffer, SoftwareApplication, Service |
kit/seo/schema/content.ts | Article, FAQPage, HowTo, WebPage, CollectionPage, Speakable |
kit/seo/schema/navigation.ts | BreadcrumbList, ItemList, SiteNavigationElement |
kit/seo/schema/terms.ts | DefinedTerm, DefinedTermSet |
kit/seo/robots.ts | The crawler registry and the bot-economics policy generator |
kit/seo/sitemap.ts | Route-group composer, priority ladder, integrity report, XML serialiser |
kit/seo/feeds.ts | RSS from the same entries as the sitemap, XML and CDATA escaping |
kit/seo/llms.ts | llms.txt and llms-full.txt builders from typed config |
kit/seo/indexnow.ts | Batch submission, timing-safe comparison, cron guard |
kit/pseo/gating.ts | Entity gating, alias resolution, duplicate-slug detection |
kit/pseo/facts.ts | Rank and percentile, computed FAQs, ordinals, UTC dates, sibling selection |
kit/pseo/generate.ts | Snapshot rendering, diffing, and the shrink guard |
kit/config/headers.ts | HSTS, nosniff, frame-deny, referrer, permissions, CSP, cache rules |
kit/tests/kit.test.ts | Vitest suites covering every module above |
Two files, in full
Not excerpts. These are the two that are most obviously a day of work each, and they are the two this site depends on most.
The schema graph composer (136 lines)
/**
* Code Kit: the sitewide @graph composer.
* Implements checks: schema-graph-anchors, schema-single-script, schema-no-duplicates
*
* One <script type="application/ld+json"> per page holding one @graph array.
* Nodes cross-reference each other by @id instead of duplicating themselves,
* which is what stops a site from shipping the same Organization object 2,000
* times and lets a crawler resolve one entity across every page.
*/
import { compact } from "../constants";
import { organization, website, type OrganizationOptions, type WebSiteOptions } from "./organization";
import { product, type ProductOptions } from "./commerce";
import { type JsonLdObject, SCHEMA_CONTEXT, nodeId, ref } from "./types";
export type SiteGraphOptions = {
siteUrl: string;
organization: Omit<OrganizationOptions, "siteUrl">;
website: Omit<WebSiteOptions, "siteUrl" | "publisher">;
/** Omit on sites that do not sell a product. */
product?: Omit<ProductOptions, "siteUrl">;
/** Page-level nodes: WebPage, BreadcrumbList, Article, FAQPage, and so on. */
additionalNodes?: Array<JsonLdObject | undefined>;
};
/**
* Compose the sitewide graph.
*
* The three anchors are stable and cross-referenced:
* #organization is the publisher of #website and the brand of #product
* #website is the isPartOf target for every page node
* #product is the thing being sold
*/
export function siteGraph(opts: SiteGraphOptions): JsonLdObject {
const orgId = nodeId(opts.siteUrl, "#organization");
const nodes: Array<JsonLdObject | undefined> = [
organization({ siteUrl: opts.siteUrl, ...opts.organization }),
website({ siteUrl: opts.siteUrl, publisher: ref(orgId), ...opts.website }),
opts.product
? product({
siteUrl: opts.siteUrl,
...opts.product,
brandName: opts.product.brandName,
})
: undefined,
...(opts.additionalNodes ?? []),
];
return {
"@context": SCHEMA_CONTEXT,
"@graph": dedupeById(nodes.filter(isPresent)) as unknown as JsonLdObject[],
} as unknown as JsonLdObject;
}
/**
* Build a page-level graph that references the sitewide anchors without
* repeating them. Use on every page that is not the home page.
*/
export function pageGraph(opts: {
siteUrl: string;
nodes: Array<JsonLdObject | undefined>;
}): JsonLdObject {
return {
"@context": SCHEMA_CONTEXT,
"@graph": dedupeById(opts.nodes.filter(isPresent)) as unknown as JsonLdObject[],
} as unknown as JsonLdObject;
}
function isPresent<T>(value: T | undefined | null): value is T {
return value !== undefined && value !== null;
}
/** Two nodes with the same @id in one graph is a validation error. Last write wins. */
function dedupeById(nodes: JsonLdObject[]): JsonLdObject[] {
const seen = new Map<string, JsonLdObject>();
const anonymous: JsonLdObject[] = [];
for (const node of nodes) {
const id = typeof node["@id"] === "string" ? node["@id"] : undefined;
if (id) seen.set(id, node);
else anonymous.push(node);
}
return [...seen.values(), ...anonymous];
}
/**
* Collect every @id declared in a graph and every @id referenced by it, so a
* test can assert that no reference dangles.
*
* The distinction that matters: an object carrying `@id` plus other properties
* DECLARES a node, at any nesting depth. An object carrying nothing but `@id`
* REFERENCES one. A nested ImageObject with its own `@id` is a declaration, and
* treating it as a dangling reference would be a false positive.
*/
export function graphIdIntegrity(graph: JsonLdObject): {
declared: Set<string>;
referenced: Set<string>;
dangling: string[];
} {
const declared = new Set<string>();
const referenced = new Set<string>();
const nodes = (graph["@graph"] as unknown as JsonLdObject[]) ?? [];
const walk = (value: unknown): void => {
if (Array.isArray(value)) {
for (const item of value) walk(item);
return;
}
if (!value || typeof value !== "object") return;
const obj = value as Record<string, unknown>;
const keys = Object.keys(obj);
const id = typeof obj["@id"] === "string" ? obj["@id"] : undefined;
if (id) {
if (keys.length === 1) referenced.add(id);
else declared.add(id);
}
for (const [key, val] of Object.entries(obj)) {
if (key === "@id") continue;
walk(val);
}
};
for (const node of nodes) walk(node);
return {
declared,
referenced,
dangling: [...referenced].filter((id) => !declared.has(id)),
};
}
export { compact };Per-entity fact computation (207 lines)
Rank, percentile, computed FAQs, the ordinal exception, UTC-safe dates and deterministic sibling selection. This is what makes a programmatic tier pass the strip-the-entity-name test.
/**
* Code Kit: per-entity fact computation.
* Implements checks: pseo-per-entity-numbers, pseo-computed-faqs, pseo-honest-fallbacks
*
* Numbers are the cheapest genuine uniqueness available and the hardest to fake
* at scale. Relational figures, rank and percentile, are the strongest of all,
* because they cannot exist on a page that does not know about its siblings.
*/
export type FactSource = {
id: string;
name: string;
/** Primary count for this entity. */
total: number;
/** Raw values used for the median. Empty is valid and produces a null median. */
values: number[];
previousTotal: number | null;
/** ISO date the source snapshot was generated. */
updatedAt: string;
};
export type EntityFacts = {
total: number;
medianValue: number | null;
rankWithinSet: number;
setSize: number;
percentile: number;
changeVsPreviousPeriod: number | null;
changePercent: number | null;
updatedAt: string;
/** True when the entity fell below the publication threshold. */
suppressed: boolean;
};
export type FactOptions = {
/**
* Minimum record count before a median is published. Computing a median from
* two records is technically true and practically misleading.
*/
minimumForMedian?: number;
};
export function computeFacts(
entity: FactSource,
siblings: readonly FactSource[],
opts: FactOptions = {},
): EntityFacts {
const minimum = opts.minimumForMedian ?? 5;
const ranked = [...siblings].sort((a, b) => b.total - a.total || a.id.localeCompare(b.id));
const rankIndex = ranked.findIndex((candidate) => candidate.id === entity.id);
const rank = rankIndex === -1 ? ranked.length : rankIndex + 1;
const setSize = Math.max(ranked.length, 1);
const change = entity.previousTotal === null ? null : entity.total - entity.previousTotal;
return {
total: entity.total,
medianValue: entity.values.length >= minimum ? median(entity.values) : null,
rankWithinSet: rank,
setSize,
percentile: Math.round((1 - (rank - 1) / setSize) * 100),
changeVsPreviousPeriod: change,
changePercent:
change === null || !entity.previousTotal
? null
: Math.round((change / entity.previousTotal) * 1000) / 10,
updatedAt: entity.updatedAt,
suppressed: entity.values.length < minimum,
};
}
export function median(values: number[]): number | null {
if (values.length === 0) return null;
const sorted = [...values].sort((a, b) => a - b);
const mid = Math.floor(sorted.length / 2);
if (sorted.length % 2 === 1) return sorted[mid] ?? null;
const low = sorted[mid - 1];
const high = sorted[mid];
return low === undefined || high === undefined ? null : (low + high) / 2;
}
/**
* English ordinals.
*
* 11th, 12th and 13th break the 1st/2nd/3rd rule, and so do 111th, 112th and
* 113th. Checking the last two digits handles both.
*/
export function ordinal(n: number): string {
const lastTwo = Math.abs(n) % 100;
if (lastTwo >= 11 && lastTwo <= 13) return `${n}th`;
switch (Math.abs(n) % 10) {
case 1:
return `${n}st`;
case 2:
return `${n}nd`;
case 3:
return `${n}rd`;
default:
return `${n}th`;
}
}
/**
* UTC-safe date parsing.
*
* A bare YYYY-MM-DD is interpreted as UTC by the ECMAScript spec, but a
* date-time string without a zone is interpreted as local time. Mixing the two
* puts pages a day out from the sitemap for anyone west of UTC.
*/
export function parseUtcDate(value: string): Date {
if (/^\d{4}-\d{2}-\d{2}$/.test(value)) return new Date(`${value}T00:00:00.000Z`);
const parsed = new Date(value);
if (Number.isNaN(parsed.getTime())) throw new Error(`Unparseable date: ${value}`);
return parsed;
}
export function formatUtcDate(value: string | Date, locale = "en-US"): string {
const date = typeof value === "string" ? parseUtcDate(value) : value;
return date.toLocaleDateString(locale, {
year: "numeric",
month: "long",
day: "numeric",
timeZone: "UTC",
});
}
export type FaqEntry = { question: string; answer: string };
/**
* Build FAQs from computed facts.
*
* A question is only asked when there is a real answer, so a sparse entity gets
* three FAQs rather than six FAQs with three empty answers. Every answer
* restates its subject so it survives being extracted alone.
*/
export function buildEntityFaqs(
entity: { name: string; unitLabel: string },
facts: EntityFacts,
formatValue: (value: number) => string = (value) => value.toLocaleString("en-US"),
): FaqEntry[] {
const dateLabel = formatUtcDate(facts.updatedAt);
const faqs: FaqEntry[] = [
{
question: `How many ${entity.unitLabel} does ${entity.name} have?`,
answer: `${entity.name} has ${facts.total.toLocaleString("en-US")} ${entity.unitLabel} as of ${dateLabel}, which ranks it ${ordinal(facts.rankWithinSet)} of ${facts.setSize.toLocaleString("en-US")}.`,
},
];
if (facts.medianValue !== null) {
faqs.push({
question: `What is the median value in ${entity.name}?`,
answer: `The median value in ${entity.name} is ${formatValue(facts.medianValue)}, based on ${facts.total.toLocaleString("en-US")} ${entity.unitLabel} as of ${dateLabel}.`,
});
}
if (facts.changePercent !== null) {
const direction = facts.changePercent >= 0 ? "up" : "down";
faqs.push({
question: `Is ${entity.name} growing?`,
answer: `${entity.name} is ${direction} ${Math.abs(facts.changePercent)} percent against the previous period, moving from ${(facts.total - (facts.changeVsPreviousPeriod ?? 0)).toLocaleString("en-US")} to ${facts.total.toLocaleString("en-US")} ${entity.unitLabel} as of ${dateLabel}.`,
});
}
faqs.push({
question: `How does ${entity.name} compare to others?`,
answer: `${entity.name} sits in the ${ordinal(facts.percentile)} percentile of the ${facts.setSize.toLocaleString("en-US")} entries tracked, ranked ${ordinal(facts.rankWithinSet)} by ${entity.unitLabel} as of ${dateLabel}.`,
});
return faqs;
}
/**
* Honest fallback copy. A template that prints 0 when data is missing asserts
* something false; naming the gap is accurate and reads as a real dataset.
*/
export function suppressionNotice(entityName: string, minimum: number): string {
return `No median is published for ${entityName} because fewer than ${minimum} records are available. This page updates automatically when the threshold is met.`;
}
/**
* Deterministic sibling selection.
*
* A random pick per build produces a different link graph on every deploy,
* which looks like instability. Hashing the entity id is stable and still
* distributes inbound links evenly rather than pooling them on a few pages.
*/
export function selectSiblings<T extends { id: string }>(
current: T,
all: readonly T[],
count = 6,
): T[] {
const others = all.filter((item) => item.id !== current.id);
if (others.length === 0) return [];
const start = hashToIndex(current.id, others.length);
const take = Math.min(count, others.length);
return Array.from({ length: take }, (_, index) => others[(start + index) % others.length]!);
}
function hashToIndex(value: string, modulo: number): number {
let hash = 2166136261;
for (let i = 0; i < value.length; i += 1) {
hash ^= value.charCodeAt(i);
hash = Math.imul(hash, 16777619);
}
return Math.abs(hash) % Math.max(modulo, 1);
}RECIPES.md
Every checklist check with an implementation maps to a module and a recipe. You do not read the kit front to back; you look up the check you are on and apply the diff.
| Check id | Module |
|-----------------------------------|----------------------------|
| meta-canonical-absolute | kit/seo/constants.ts |
| schema-graph-anchors | kit/seo/schema/graph.ts |
| crawl-bot-economics | kit/seo/robots.ts |
| crawl-lastmodified-differentiated | kit/seo/sitemap.ts |
| aeo-canonical-answers | kit/seo/llms.ts |
| pseo-per-entity-numbers | kit/pseo/facts.ts |
| sec-csp | kit/config/headers.ts |Licence, in one paragraph
Perpetual, non-exclusive, per seat. Permitted: unlimited projects owned by you or your employer. Prohibited: redistribution, resale, publishing the source, and inclusion in a competing product. Provided as is, with warranty disclaimed.
Read the full licence termsCheckout opens at launch. The free checklist works today.
One-time payment. Lifetime updates. 30 day refund, no questions.
Questions
What is in the Code Kit?
SEO for Solos's Code Kit contains 17 TypeScript modules covering structured data, robots, sitemaps, feeds, llms.txt, IndexNow, programmatic page generation and security headers, with a Vitest suite for each.
Is it framework-specific?
The SEO for Solos Code Kit is framework-agnostic wherever the work is data transformation, which is most of it. Only the route definitions differ per framework, and eight frameworks have worked examples on the site.
How do I get access?
Code Kit buyers get read access to a private GitHub repository plus a versioned zip. Add your GitHub username in your library and the invite is sent within a minute.
What is the licence?
The SEO for Solos Code Kit licence is perpetual and per seat. It permits unlimited projects owned by the licensee or the licensee's employer. It prohibits redistribution, resale, and inclusion in a competing product.