@misar/blog (1.3.1)
Installation
@misar:registry=npm install @misar/blog@1.3.1"@misar/blog": "1.3.1"About this package
@misar/blog
The /blogs list and article pages for any Misar product site, rendered on
that site's own domain from api.misar.io/io/blog/*.
Each product shows its own MisarBlog author's articles, and that product's URL is the canonical one:
| platform | MisarBlog author | site |
|---|---|---|
mail |
@misarmail | misarmail.com |
reach |
@misarreach | misarreach.com |
post |
@misarpost | misarpost.com |
seo |
@misarseo | misarseo.com |
dev |
@misar-dev | misar.dev |
ai |
@misar-ai | misar.ai |
misar-io stores them in product_blog_posts (filled hourly by
/api/cron/product-blog-sync); misar.io's own /blogs (platform io) keeps
reading the @misar company feed in blog_posts. A slug that is not that
author's article is a 404 on the product. Publishing a product article means
publishing it on misar.blog under the product's author account.
Next.js
// src/lib/blog.ts
import { createNextBlog } from "@misar/blog/next";
export const blog = createNextBlog({
platform: "mail",
siteUrl: "https://www.misarmail.com",
productName: "MisarMail",
});
// src/app/blogs/page.tsx
import { blog } from "@/lib/blog";
export const revalidate = 3600;
export const generateMetadata = blog.generateIndexMetadata;
export default blog.IndexPage;
// src/app/blogs/[slug]/page.tsx
// No generateStaticParams/dynamicParams: if the root layout reads cookies()
// or headers() (most product layouts do), a prerendered route aborts at
// runtime ("changed from static to dynamic") and every article is a 500.
import { blog } from "@/lib/blog";
export const revalidate = 3600;
export const generateMetadata = blog.generatePostMetadata;
export default blog.PostPage;
// src/app/sitemap.ts — spread `await blog.sitemapEntries()` into the result.
/* globals.css, after @misar/ui/theme.css and base.css */
@import "@misar/blog/styles.css";
Other frameworks (TanStack Start)
Use createBlogApi, BlogIndexView / BlogPostView with your router's link
as Link, and buildIndexMeta / buildPostMeta + toHeadTags for <head>.
Nothing in the root entry imports next/*.
Canonical
canonical: "self" (default) makes each product the canonical home of its
copy. canonical: "misar-io" points posts at misar.io and drops them from the
product's sitemap.
In-house ads
Since 1.2.0 the index and post views render the Misar/Assisters house-ad
network (HouseAdSlot, src/house-ads.ts). Posts get a card after the article
body and a sticky card in the right rail; the index gets a card above the grid.
Each ad promotes another Misar or Assisters product — never the blog's own
(PLATFORM_PRODUCT) — with its exact brand name, its www. domain and a
"7 Days Free Trial" CTA to that product's /pricing, tagged
utm_source=<platform>_blog&utm_medium=house_ad&utm_campaign=<placement>.
The pick is deterministic per page, so markup is stable and cacheable.
createNextBlog({ ...site, ads: false }); // off
createNextBlog({ ...site, ads: { exclude: ["assisters-dev"] } }); // narrow
The creatives use Tailwind classes from this package: a site that does not
already scan it needs @source "<path>/packages/blog/src/**/*.{ts,tsx}" (or the
published styles.css, which does it).
Dependencies
Dependencies
| ID | Version |
|---|---|
| highlight.js | ^11.12.0 |
| html-react-parser | ^6.1.8 |
| lucide-react | ^0.577.0 |
Development dependencies
| ID | Version |
|---|---|
| @misar/ui | 1.8.1 |
| @types/react | ^19.3.0 |
| next | 15.5.28 |
| react | ^19.3.1 |
| react-dom | ^19.3.1 |
| tsup | ^8.5.1 |
| typescript | ^5.9.3 |
Peer dependencies
| ID | Version |
|---|---|
| @misar/ui | >=1.4.0 |
| next | >=15.5.28 |
| react | ^18.0.0 || ^19.0.0 |