@mansichauhan/next-build-plugins
v1.5.20
Published
Next.js plugins for Mayson: plan guard middleware, remix watermark, and SEO metadata injection via withMayson().
Readme
@mansichauhan/next-build-plugins
Next.js plugins for Mayson-published App Router apps. Wrap next.config with withMayson() — the same shape as @next/bundle-analyzer. Production next build injects SEO tags and the remix pill into the root HTML; middleware blocks expired plans before app HTML is served.
Requires Node 20+ and Next.js 15+.
Install
bun add -d @mansichauhan/next-build-pluginsUsage
// next.config.ts
import type { NextConfig } from "next";
import { withMayson } from "@mansichauhan/next-build-plugins";
const nextConfig: NextConfig = {
turbopack: { root: process.cwd() },
};
export default withMayson(nextConfig);Add plan guard middleware at the app root. Use the /middleware subpath — the main package entry imports Node-only modules (node:fs) and will fail in Edge middleware.
// middleware.ts
import { maysonMiddleware } from "@mansichauhan/next-build-plugins/middleware";
export default maysonMiddleware;
export const config = {
matcher: [
"/((?!_next/static|_next/image|favicon.ico|details_[a-z0-9]{6}|.*\\.(?:svg|png|jpg|jpeg|gif|webp|ico)$).*)",
],
};Next.js requires config.matcher to be a static literal in middleware.ts (do not import or re-export it).
If you already have middleware:
import { withMaysonPlanGuard } from "@mansichauhan/next-build-plugins/middleware";
export default withMaysonPlanGuard(yourExistingMiddleware);Optional flags:
export default withMayson(nextConfig, {
watermark: true, // remix pill (default true)
metadata: true, // SEO inject (default true)
badgeLanding: true, // static /details_<slug> page (default true)
});Environment variables (Vercel)
The Mayson platform sets these on each Vercel project before next build. See .env.example.
| Variable | Required | Purpose |
|----------|----------|---------|
| MAYSON_WORKSPACE_ID | Yes | Workspace identifier |
| MAYSON_COLLECTION_ID | Yes | Collection identifier |
| MAYSON_API_BASE_URL | Yes | Mayson API host |
| MAYSON_APP_BASE_URL | Yes | Mayson web app (remix links, billing) — default https://mayson.dev |
| MAYSON_WEB_TOKEN | Build | Auth for generated-app-metadata fetch |
| MAYSON_ENABLE_PLAN_GUARD | No | false to disable; default on when IDs + API base are set |
| MAYSON_PLAN_CHECK_REVALIDATE_SECONDS | No | Plan API cache TTL (default 60) |
| MAYSON_PLAN_STATUS_URL | No | Override plan API URL for staging |
withMayson() reads these at config load and inlines MAYSON_* vars into next.config.env for middleware.
What it does
| Feature | When | Behavior |
|--------|------|----------|
| Plan guard | Every request (next dev + production) | Middleware calls plan API; expired plans get 402 + upgrade page — app HTML is not served |
| Metadata | After next build | Adds title, description, favicon, OG tags, optional metascript only when missing from root HTML |
| Watermark | After next build | Remix pill iframe (srcdoc) linking to /details_<6-char-slug> |
| Badge landing | After next build | Writes public/details_<slug>/index.html — served at /details_<slug> with build stats + Remix CTA |
Metadata patches .next/server/app/index.html. Watermark + console ASCII inject into all prerendered App Router HTML under .next/server/app/**/*.html. The badge landing page is a static HTML file under public/details_<slug>/ (no App Router route required). The slug is a random 6-character string generated each build. withMayson() adds a rewrite so /details_<slug> resolves to that file — Next.js does not serve public/.../index.html at the directory path by default.
Generated app metadata API
When MAYSON_API_BASE_URL, MAYSON_WORKSPACE_ID, MAYSON_COLLECTION_ID, and MAYSON_WEB_TOKEN are set, inject fetches watermark + SEO settings from:
GET {apiBaseUrl}/sigma/web/v1/generated-app-metadata/workspaces/{workspaceId}/collections/{collectionId}
Header: M-Web-Token: {MAYSON_WEB_TOKEN}
Example response field mapping:
| API (value) | Config |
|---------------|--------|
| show_remix_pill | showRemixPill |
| enable_remix | enableRemix |
| website_title | websiteTitle |
| meta_description | metaDescription |
| website_icon | websiteIcon |
| preview_image | previewImage |
| metascript | metascript |
| time_taken_seconds | timeTakenSeconds (badge landing stats) |
| tokens_used | tokensUsed (badge landing stats) |
If the fetch fails, inject is skipped (watermark off, no metadata, no badge landing). Platform env vars are still used for plan guard.
Plan guard API
Default endpoint (when MAYSON_PLAN_STATUS_URL is unset):
GET {apiBaseUrl}/sigma/web/v1/plan/workspaces/{workspaceId}/collections/{collectionId}
Expected response (either shape):
{ "active": true }{ "response_code": 200, "value": { "active": true } }- 200 +
active: false→ block with "Please upgrade to view" - Non-2xx / timeout / network error → fail open (site stays accessible)
Plan guard is enabled when workspace ID, collection ID, and API base URL are set and MAYSON_ENABLE_PLAN_GUARD is not false.
How inject runs
withMayson registers during Next’s PHASE_PRODUCTION_BUILD. Next calls process.exit() when the build finishes, so the wrapper patches process.exit (and beforeExit as a fallback) and then:
- Reads env vars (and fetches generated-app-metadata when configured)
- Runs metadata, watermark, then badge landing page
- Writes App Router HTML (metadata on root; watermark/console on all route shells) and
public/details_<slug>/index.html
next dev and next start do not inject metadata/watermark. Re-run next build after changing env or API metadata.
CLI (optional)
For a manual/debug run after an existing build:
bunx mayson-next-inject
bunx mayson-next-inject --no-watermark
bunx mayson-next-inject --no-badge
bunx mayson-next-inject --cwd ./apps/web --dist-dir .nextNot required in package.json build.
Programmatic API
import {
runMaysonPlugins,
runMetadataPlugin,
runWatermarkPlugin,
loadMaysonEnvConfig,
} from "@mansichauhan/next-build-plugins";
import {
evaluatePlanGuard,
maysonMiddleware,
} from "@mansichauhan/next-build-plugins/middleware";
runMaysonPlugins({ cwd: process.cwd() });Config timing
Inject bakes pill/meta into static HTML at build time. Plan guard reads live API status at request time via middleware.
| When env vars are set | Result |
|-----------------------|--------|
| Before next build on Vercel | Correct pill/meta + middleware env |
| After deploy only | Live HTML unchanged until another build |
Caveats
- Metadata/watermark inject is production build only — not
next dev. - Metadata inject patches the root App Router HTML only; watermark + console ASCII patch all prerendered route HTML shells. Soft client navigations do not re-run the console script.
- Plan guard requires a root
middleware.tsre-export (Next.js requirement). Excludedetails_[a-z0-9]{6}from the matcher so the badge landing page stays accessible when a plan is expired. - Plan status may be cached for up to
MAYSON_PLAN_CHECK_REVALIDATE_SECONDS(default 60s). metascriptis raw HTML; do not fill it from untrusted input.- Vite sandboxes need a separate Vite plugin, not this package.
Backend coordination
The plan guard endpoint must accept workspace + collection IDs and return { active: boolean }. Coordinate with backend on the exact path under {apiBaseUrl}/sigma/web/v1/plan/....
