Releases: dodopayments/dualmark
v0.8.0 — @dualmark/deno + status-page converter + CLI v1.0 JSON
Highlights
Three things land in this release:
- New package:
@dualmark/deno— a Deno Deploy edge adapter that wraps any Denofetchhandler. AI bots get the markdown twin at the edge; lifecycle hooks (analytics/telemetry) are scheduled oninfo.completed.examples/deno-deployscores a perfect 125/125 underdeno run. - New converter:
status-page— a built-in converter for public uptime/status pages (component health + incidents). Dropconverter: "status-page"into an Astro or Next.js collection and status pages get the same battle-tested markdown layout as the rest. - Stable
dualmark verify --json—@dualmark/clinow emits the public AEO Spec v1.0 JSON contract instead of the internal report shape. See the migration note below.
No breaking API changes for the framework adapters. Drop-in upgrade from 0.7.x. The whole @dualmark/* family moves to 0.8.0 together (linked versioning).
What's new
@dualmark/deno@0.8.0 (new)
- Deno Deploy edge adapter (
6a6bf8a) — wraps any upstream Deno fetch handler, serves markdown to known AI bots at the edge, and schedules lifecycle hooks oninfo.completed. - 23 tests pass. Integration docs included.
@dualmark/converters@0.8.0
- New:
statusPageConverter(dd0512c, closes #12) for uptime/status pages — public component health plus incident history, with the standard brand-footer + breadcrumb conventions. - Registered as the built-in
status-pageresolver in@dualmark/astroand@dualmark/nextjs— no config beyondconverter: "status-page". - Separators in the status converter now render conditionally (
b2d925e).
@dualmark/cli@0.8.0
-
verify --jsonnow emits the AEO Spec v1.0 JSON contract (65ab17e) and enforces--jsonmutual exclusivity with--quiet/--color. Required-check failures still exit non-zero.Migration note:
--jsonpreviously emitted the internalVerifyReportshape (mdUrl,maxScore,passed[],failed[],skippedNegotiation). It now emits the v1.0 public schema (url,markdownUrl,score,max,level,skippedNegotiation,durationMs,checks[]) with checks in canonical evaluation order. Update any CI parsing that read the old field names.
@dualmark/core@0.8.0, @dualmark/astro@0.8.0, @dualmark/nextjs@0.8.0, @dualmark/cloudflare@0.8.0
Version bumps to keep the linked @dualmark/* family in lockstep (and to register the status-page resolver in astro / nextjs). No API changes.
Upgrade
# Astro
bun add @dualmark/astro@^0.8.0
# Next.js
bun add @dualmark/nextjs@^0.8.0
# Cloudflare
bun add @dualmark/cloudflare@^0.8.0
# Deno (new!)
bun add @dualmark/deno@^0.8.0
# CLI
bun add -g @dualmark/cli@^0.8.0To use the new status-page converter:
// astro.config.mjs
dualmark({
siteUrl: "https://yourcompany.com",
collections: {
status: { converter: "status-page" }, // ← new
},
});Verified
- ✅ All package tests pass across
@dualmark/*(build 7/7, test 7/7, typecheck 7/7) - ✅ Conformance E2E:
examples/deno-deploy125/125,examples/astro-cloudflare-full125/125,examples/nextjs-app-router120/125
v0.7.0 — More AI bots + integration converter
Highlights
Two features land together in this release:
- Broader AI bot coverage — the crawler registry now detects DeepSeek, Anthropic's new Claude-SearchBot and Claude-User, Meta's ExternalFetcher, and Perplexity-User. If any of these hit your site, they now get the markdown twin instead of HTML soup.
integrationConverter— a new built-in converter for marketplace-style "Connect X to Y" pages (vendor, categories, capabilities, optional setup, pricing, requirements). Dropconverter: "integration"into an Astro or Next.js collection and integration pages get the same battle-tested markdown layout as blog posts.
No breaking changes. Drop-in upgrade from 0.6.x.
What's new
@dualmark/core@0.7.0
- Extend the AI Agent Registry with 5 new bots (
6155878):DeepSeekBot(DeepSeek)Claude-SearchBot(Anthropic — search-time fetcher)Claude-User(Anthropic — claude.ai on-demand fetch)Meta-ExternalFetcher(Meta — user-action fetch from Meta AI)Perplexity-User(Perplexity — user-action fetch)
- Tighten the
Meta-ExternalFetcherUA pattern to avoid false positives (0377a0e) and classify itspurposeasuser-actionrather thantraining(951f373) — matches Meta's published bot semantics. - AEO spec AI Agent Registry table is synced with the new entries.
@dualmark/converters@0.7.0
- New:
integrationConverter(dbd8ef4) for marketplace integration pages. Handles:- Vendor and integration metadata
- Categories + capabilities
- Optional setup steps, pricing, and requirements blocks
- Same brand-footer + breadcrumb conventions as the other converters
- Registered as the built-in
integrationresolver in both@dualmark/astroand@dualmark/nextjs— no config beyondconverter: "integration". - Refactor:
integrationcategories are now a structured field with a brandFooter test (42cc5f8).
@dualmark/astro@0.7.0, @dualmark/nextjs@0.7.0, @dualmark/cli@0.7.0, @dualmark/cloudflare@0.7.0
Version bumps to pick up the new core + converters (and the integration resolver registration in astro / nextjs). No API changes.
Upgrade
# Astro
bun add @dualmark/astro@^0.7.0
# Next.js
bun add @dualmark/nextjs@^0.7.0
# Cloudflare
bun add @dualmark/cloudflare@^0.7.0
# CLI
bun add -g @dualmark/cli@^0.7.0To use the new integration converter:
// astro.config.mjs
dualmark({
siteUrl: "https://yourcompany.com",
collections: {
integrations: { converter: "integration" }, // ← new
},
});Verified
- ✅ All 313 tests pass across
@dualmark/*packages - ✅ Typecheck clean
- ✅ Conformance E2E:
examples/astro-cloudflare-fullstill 125/125,examples/nextjs-app-router120/125
Full changelogs
- @dualmark/core
- @dualmark/converters
- @dualmark/astro
- @dualmark/nextjs
- @dualmark/cloudflare
- @dualmark/cli
Full diff: v0.6.0...v0.7.0
v0.6.0 — Astro 6 security upgrade
Highlights
Security release. Bumps the `astro` peer dependency to `^6.1.10` to resolve two upstream advisories that were never backported to Astro 5:
- 🔐 GHSA-j687-52p2-xcff (CVE-2026-41067, moderate) — XSS in `define:vars` via incomplete `</script>` tag sanitization. Patched in Astro 6.1.6.
- 🔐 GHSA-xr5h-phrj-8vxv (CVE-2026-45028, low) — Server island encrypted parameters vulnerable to cross-component replay. Patched in Astro 6.1.10.
If you ship `@dualmark/astro` on a public site, upgrade.
Breaking changes
- `@dualmark/astro` now requires `astro@^6.1.10`. Astro 5 is no longer a supported peer. The integration uses only stable hooks (`astro:config:setup`, `injectRoute`, `addMiddleware`) and the Content Layer API — there are no source changes inside `@dualmark/astro` itself, but you'll need to run Astro's v5 → v6 migration guide on your own site.
- `engines.node` is now `>=22.12.0` across every published `@dualmark/*` package, matching Astro 6's hard Node 22 requirement.
Upgrade
```bash
1. Make sure you're on Node 22+
node --version # → v22.x.x
2. Upgrade @dualmark/astro and astro together
bun add @dualmark/astro@^0.6.0 astro@^6.1.10
or: pnpm add / npm install / yarn add equivalents
3. Run Astro's official 5 → 6 codemod / migration
https://docs.astro.build/en/guides/upgrade-to/v6/
```
The other five `@dualmark/*` packages (`core`, `converters`, `cli`, `cloudflare`, `nextjs`) are unchanged and remain at `0.5.2` — no Node bump on their published metadata, no peer-dep changes. If you don't use `@dualmark/astro`, this release is a no-op for you.
Verified end-to-end
The conformance E2E suite (`.github/workflows/conformance.yml`) ran clean against Astro 6 on every push since the upgrade landed:
- ✅ `examples/astro-blog` — boots under `astro dev`, `dualmark verify` passes
- ✅ `examples/astro-cloudflare-full` — boots under `wrangler dev`, full 125/125 conformance
- ✅ All 313 unit/integration tests across `@dualmark/*` pass on Astro 6.3.1 (resolved from `^6.1.10`)
Full changelogs
- @dualmark/astro
- @dualmark/core (unchanged)
- @dualmark/converters (unchanged)
- @dualmark/nextjs (unchanged)
- @dualmark/cloudflare (unchanged)
- @dualmark/cli (unchanged)
v0.5.2 — npm provenance + Astro catalog auto-discovery
Highlights
Supply-chain hardening — every `@dualmark/*` tarball is now signed with npm provenance attestation. Each package on npmjs.com gets a verified "Provenance" badge tying the artifact to this exact GitHub Actions workflow run and commit SHA. Consumers can verify with:
```bash
npm audit signatures
```
No API changes inside any package — this is a release-pipeline upgrade.
Changes
`@dualmark/astro` 0.5.2
- ✨ Added `seo`, `performance`, `optimization` keywords to enable auto-discovery by the Astro Integrations catalog. `@dualmark/astro` will appear under "Performance + SEO" on the next weekly catalog sync (no runtime change).
All `@dualmark/*` packages 0.5.2
- 🔐 Release pipeline switched from `bun publish` to `bun pm pack` + `npm publish --provenance` (because bun 1.3.5 doesn't yet support `--provenance` — see oven-sh/bun#15601).
- 📝 `CONTRIBUTING.md` updated with the new release flow + how to verify provenance.
Full changelogs
v0.5.1 — @dualmark/nextjs
@dualmark/nextjs@0.5.1
Patch Changes
-
fix(nextjs):withDualmark()rejecting typedNextConfigfromnext.config.ts(#26).The internal
NextConfigShapeconstraint had an[key: string]: unknownindex
signature, which TypeScript treats as a structural demand on the input. Next.js's
NextConfigis a closed interface with no top-level index signature, so any
caller passing a typednext.config.tshit:Type 'NextConfig' is not assignable to type 'NextConfigShape'. Index signature for type 'string' is missing in type 'NextConfig'.The constraint was unnecessary — the function only reads
transpilePackages
and spreads the remaining config, neither of which need an index signature.
Removing it unblocks typed configs on Next 14, 15, and 16. Runtime behavior
is unchanged. -
docs(nextjs): Next.js 16 compatibility — package metadata, docs, and example (#27).- Drop the "Next.js 15" reference from the package description; the adapter
works with the Next.js App Router on 14, 15, and 16. - Bump the
nextdevDependency from^15.0.0to^16.2.6(test/build
toolchain only — thepeerDependenciesrange is unchanged). - Update README to document the Next.js 16
proxy.tsfile convention,
with a note that Next ≤15 should keep usingmiddleware.ts(body is
identical). No runtime behavior change.
The reference example at
examples/nextjs-app-routerwas migrated to
Next.js 16 in the same change and still scores 120/125 undernext dev. - Drop the "Next.js 15" reference from the package description; the adapter
Other packages
@dualmark/core, @dualmark/converters, @dualmark/astro, @dualmark/cloudflare, @dualmark/cli are unchanged at 0.5.0 (no changesets touched them this cycle).
Full Changelog: v0.5.0...v0.5.1
v0.5.0 — @dualmark/nextjs
New: `@dualmark/nextjs` — first-class Next.js 15 App Router adapter
Closes #4. Same one-line install as `@dualmark/astro`, with a small surface area:
- `withDualmark(nextConfig, options)` — wraps `next.config.mjs`
- `createDualmarkMiddleware(options)` — drop-in `middleware.ts`
- `createDualmarkRouteHandler(options)` — catch-all markdown twin route handler with `generateStaticParams`
- `createLlmsTxtHandler(options)` — `/llms.txt` route handler
The `collections` / `staticPages` / `parameterizedRoutes` config shape mirrors `@dualmark/astro` so users can copy their config across frameworks. All 12 built-in converters (`blog`, `case-study`, `changelog`, `compare`, `docs`, `feature`, `glossary`, `legal`, `pricing`, `pseo`, `tool`, `video`) work identically. Tree-shakeable, ESM + CJS, zero runtime deps beyond `@dualmark/core` + `@dualmark/converters`. 47 vitest tests cover config validation, middleware negotiation, route dispatch, and `generateStaticParams`.
Install
```bash
bun add @dualmark/nextjs @dualmark/core @dualmark/converters
```
Minimal setup
```ts
// middleware.ts
import { createDualmarkMiddleware } from "@dualmark/nextjs";
export default createDualmarkMiddleware({ siteUrl: "https://example.com\" });
export const config = {
matcher: [
{
source: "/((?!_next/|favicon.ico|md/).*)",
missing: [{ type: "header", key: "next-router-prefetch" }],
},
],
};
```
```ts
// app/md/[...path]/route.ts
import { createDualmarkRouteHandler } from "@dualmark/nextjs";
import { POSTS } from "@/lib/posts";
const handler = createDualmarkRouteHandler({
siteUrl: "https://example.com\",
collections: {
blog: { converter: "blog", getEntries: () => POSTS.map(toEntry) },
},
});
export const dynamic = "force-static";
export const GET = handler.GET;
export const generateStaticParams = handler.generateStaticParams;
```
That's it. Bot UAs get markdown, browsers get HTML with `Link rel="alternate"`, direct `.md` URLs serve markdown.
Migration from manual `@dualmark/core` setup
If you wired `@dualmark/core` into Next.js by hand before this release, the migration is mechanical:
| Before (`@dualmark/core` only) | After (`@dualmark/nextjs`) |
|---|---|
| Hand-rolled `middleware.ts` with `detectAIBot` + `negotiateFormat` + manual rewrite | `createDualmarkMiddleware({ siteUrl })` |
| Hand-rolled `app/md/[...path]/route.ts` with `if`-chains | `createDualmarkRouteHandler({ siteUrl, collections, staticPages, parameterizedRoutes })` |
| Hand-rolled `app/llms.txt/route.ts` calling `renderLlmsTxt` | `createLlmsTxtHandler({ brandName, sections })` |
| Manual `transpilePackages: [...]` | `withDualmark(nextConfig, options)` |
The internal namespace, response headers, and conformance score are unchanged. Full guide: docs.dualmark.dev/docs/integrations/nextjs.
Reference example
`examples/nextjs-app-router` is now built on the new package — ~50 lines instead of ~120 hand-rolled, same 120/125 conformance score under both `next dev` and `next start`. The CI `nextjs-app-router` job verifies this on every PR.
Coordinated patch bumps
The linked `@dualmark/*` changeset group means every package gets a coordinated version bump:
- `@dualmark/nextjs` 0.5.0 (new)
- `@dualmark/core` 0.3.1 → 0.5.0
- `@dualmark/converters` 0.3.1 → 0.5.0
- `@dualmark/astro` 0.3.1 → 0.5.0
- `@dualmark/cloudflare` 0.3.1 → 0.5.0
- `@dualmark/cli` 0.3.1 → 0.5.0
No source-level changes to the other five packages — just version metadata bumps so internal `workspace:*` deps resolve cleanly when consumers install `@dualmark/nextjs`.
Verified
- Full monorepo: 313 tests across 6 packages, build + test + typecheck green on CI
- `examples/nextjs-app-router` E2E in CI: `next dev` + `dualmark verify` → 120/125
- Local verification: `next dev` and `next start` both score 120/125
- Docs site dogfood (`apps/docs`): every doc page ≥ 105/125
v0.3.1 — Hotfix: workspace deps + landing polish
v0.3.1 — Hotfix: workspace dep resolution + landing visual polish
Patch release fixing one critical packaging bug introduced upstream by bun publish and one set of landing-page visual inconsistencies.
Strongly recommended upgrade for anyone on 0.3.0 — fresh installs of 0.3.0 resolve mismatched workspace versions due to a
bun publishlockfile-metadata bug.
Critical: stale @dualmark/core pin in 0.3.0 tarballs
@dualmark/cli@0.3.0, @dualmark/astro@0.3.0, @dualmark/cloudflare@0.3.0, and @dualmark/converters@0.3.0 were published with a stale @dualmark/core dependency pin of "0.2.1" instead of "0.3.0". Running bun add @dualmark/cli@0.3.0 in a fresh project resolves @dualmark/core@0.2.1 alongside it — a mixed-version install. APIs are byte-equivalent across 0.2.1 and 0.3.0 so it does not crash, but the dependency graph is incorrect.
Root cause (full RCA): bun publish reads workspace dependency versions from bun.lock metadata cached at the last install time, not from the current packages/*/package.json files. When changeset version bumps versions but does not regenerate the lockfile, bun publish rewrites workspace:* deps to the previous version. bun install --frozen-lockfile does NOT detect this drift. Tracked upstream as oven-sh/bun#20477 (PR #26797 still open as of bun 1.3.5).
Two-layer fix (defense in depth):
- The
version-packagesscript now chainsbun install --lockfile-onlyafterchangeset version, so the version PR commits a refreshed lockfile. release.ymlruns the same command after checkout/setup as a self-healing safety net for tagged releases.
Verification: bun pm pack on packages/cli with the refreshed lockfile correctly emits "@dualmark/core": "0.3.1" in the packed package.json.
Landing-page visual polish
- Hero: removed full-viewport
border-bthat produced a stray horizontal hairline below the terminal demo. - Page rails: promoted z-index from
0to10so rails render above the heroBeamsBackgroundgradients (previously the bottom radial fade obscured rails inside the hero). - Navbar: scoped the bottom border to its inner
max-w-7xlcolumn so it terminates at the rails instead of running full-viewport. - Section dividers: shared
<Section>component now renders a top hairline between the rails (via newdividerprop, defaulttrue). Every landing-page section transition has a clean ┬ intersection at both rail crossings, giving the page consistent vertical rhythm.
No package source-code changes; landing fixes affect apps/docs/ only.
Commits in this release
fix(landing): rails framing — z-index, scoped borders, section dividersfix(release): refresh bun.lock workspace metadata before publishchore: refresh bun.lock workspace metadata to 0.3.0chore: changeset for 0.3.1 — workspace dep resolution hotfix + landing polishchore: version packages (#3)
Migration
- From 0.3.0:
bun update @dualmark/*(or your equivalent). No code changes required. Strongly recommended. - From 0.2.x: see the v0.3.0 changelog for the relicense + identity changes; this 0.3.1 release rolls those forward with the dep fix.
Verified
- 266 tests pass across 5 packages
- typecheck 10/10 green
- All 5 packages publish at
0.3.1with correctly resolved cross-package dependencies ("@dualmark/core": "0.3.1").
License
Apache 2.0. See LICENSE and NOTICE.
v0.3.0
v0.3.0 — Landing rewrite, Apache 2.0 relicense, /play polish
This is a meta-release. No package source-code changes ship in this version, but we're cutting a minor bump (rather than a patch) because the project's identity, license, and surface have changed substantively in this window. All 5 @dualmark/* packages move 0.2.1 → 0.3.0 in lockstep.
If you're already on 0.2.1 and don't care about the relicense announcement, you can skip this version with no functional impact. The published tarballs are functionally byte-equivalent to 0.2.1.
Highlights
License: MIT → Apache 2.0
- Apache 2.0 includes an explicit patent grant that matters for infrastructure libraries touching standard-tracking work (content negotiation, AI bot UA detection, llms.txt).
- Existing 0.2.x installs are unaffected. Downstream redistributors and forks should now reference Apache 2.0 + the new
NOTICEfile.
Landing page restructured for problem-first positioning
- New tagline: "ChatGPT cites your competitor — that's an infrastructure problem."
- 7-section narrative: Hero → PlaygroundTeaser → Transform → CaseStudy → ConformanceDemo → Adapters → CTA.
- New Dodo Payments case study with a real customer proof point: 5× lift in AI agent traffic over 2 months.
- New page rails — Vercel-style vertical hairlines framing the content column on every page.
- Cut three weak sections (TrustStrip, Architecture diagram, standalone Converters page) and folded Converters into Adapters as an inline chip strip.
- Promoted the playground teaser to second-position so visitors can score their own site immediately.
- Reframed the conformance section from "Verify CLI" to "Catch regressions in CI" with a real GitHub Actions workflow snippet.
Playground (/play) layout aligned with the new landing
- Page rails now render on
/play. - Hero gradient + grid background contained within
max-w-7xl overflow-hiddenso they stop at rail edges instead of bleeding past. - Content column widened from
max-w-5xltomax-w-7xl. - New
?url=query-param support — landing teaser deeplinks straight into a live score.
SEO/AEO surfaces aligned
Every search snippet, social card, and AI crawler artifact now carries the same problem-first hook as the landing:
<head>metadata.descriptionandtwitter.description- JSON-LD
Organization.description llms.txtbrand description (the primary AI agent discovery artifact)raw/index.mdblockquote (markdown twin of the landing)- Fumadocs
content/docs/index.mdxfrontmatter
Documentation pass
- README test-count claims corrected: 266 across 5 packages (was incorrectly 253). Breakdown:
@dualmark/core167,@dualmark/astro35,@dualmark/converters24,@dualmark/cloudflare23,@dualmark/cli17. - All
npx @dualmark/cliinvocations unified tobunx @dualmark/cli(matches the project's bun-first tooling). - Customer proof point injected into the Next.js and Cloudflare integration docs where conformance scores are discussed.
CONTRIBUTING.mdrelease flow updated to match the actualrelease.yml(which usesbun publishper package, notchangeset publish).
Migration
- Code: none required.
- License notices: redistributors should update
LICENSEreferences from MIT to Apache 2.0 and include theNOTICEfile. - CLI: prefer
bunx @dualmark/cli verify <url>for consistency.npx @dualmark/cli verify <url>still works.
Verified
- 266 tests pass across 5 packages
bun run typecheck10/10- Build green; landing page zero horizontal overflow at 1440 / 768 / 390 px
- Playground layout parity verified at all three widths
Atomic commit history (this release window)
76b65c3 chore: version packages (#2)
f1a0eb0 chore: changeset for 0.3.0 — landing rewrite, Apache 2.0, /play polish
1433a41 docs: fix stale claims, version drift, and unify CLI invocation on bunx
3eeead7 fix(seo): align metadata with problem-first positioning
621063c feat(play): align layout with new landing — rails, contained background, max-w-7xl
ba9603a refactor(landing): tighten narrative, add page rails
5d37806 feat(landing): add Dodo Payments case study and playground teaser
6f24c68 feat(play): support `?url=` query param for deeplinking
26def03 feat(landing): restructure for problem-first OSS positioning
deb9b20 chore(license): relicense from MIT to Apache 2.0
Full changelog: v0.2.1...v0.3.0
v0.2.1 — Hotfix: workspace protocol resolution
Hotfix release. 0.2.0 published with broken dependency declarations and is unusable for downstream consumers. Use 0.2.1.
What was broken in 0.2.0
The 0.2.0 tarballs on npm shipped with "@dualmark/core": "workspace:*" in their dependencies. This is bun's workspace protocol, which is only valid inside a workspace — external installers reject it:
bun add @dualmark/cli
# error: @dualmark/core@workspace:* failed to resolve
npm install @dualmark/cli
# npm error code EUNSUPPORTEDPROTOCOL
Root cause
We use @changesets/cli for release orchestration. Changesets only knows about pnpm and falls back to npm publish for everything else (including bun). When we migrated this repo from pnpm → bun, changeset publish started using npm publish under the hood, which does not rewrite the workspace:* protocol.
Fix
Switched the release workflow from changeset publish to a per-package loop using bun publish. Bun correctly rewrites workspace:* → the actual pinned version at pack time. Verified:
| Package | 0.2.0 (broken) | 0.2.1 (fixed) |
|---|---|---|
@dualmark/cli |
"@dualmark/core": "workspace:*" |
"@dualmark/core": "0.2.1" |
@dualmark/astro |
"@dualmark/core": "workspace:*", "@dualmark/converters": "workspace:*" |
"@dualmark/core": "0.2.1", "@dualmark/converters": "0.2.1" |
@dualmark/cloudflare |
"@dualmark/core": "workspace:*" |
"@dualmark/core": "0.2.1" |
Migration
Just upgrade. There are no API or behavioral changes from 0.2.0 to 0.2.1 — only the dependency declarations were broken.
bun add @dualmark/astro@0.2.1 @dualmark/core@0.2.1 @dualmark/converters@0.2.1Or for a fresh install, just install latest:
bun add @dualmark/astro
# resolves to @dualmark/astro@0.2.1 with valid transitive depsPackages republished at 0.2.1
| Package | npm |
|---|---|
@dualmark/core |
npm i @dualmark/core |
@dualmark/converters |
npm i @dualmark/converters |
@dualmark/astro |
npm i @dualmark/astro |
@dualmark/cloudflare |
npm i @dualmark/cloudflare |
@dualmark/cli |
npm i -g @dualmark/cli |
The 0.2.0 versions will be marked npm deprecate after this release lands.
Links
v0.2.0 — First public release
First public release of all five @dualmark/* packages to npm. The AEO Spec v1.0 is authoritative; framework code follows.
Pre-1.0 versioning: Per semver §4, breaking changes are allowed in minor bumps before 1.0. Every release before 1.0 may include API changes; pin exact versions if you need stability.
What ships
| Package | Version | npm |
|---|---|---|
@dualmark/core |
0.2.0 | npm i @dualmark/core |
@dualmark/converters |
0.2.0 | npm i @dualmark/converters |
@dualmark/astro |
0.2.0 | npm i @dualmark/astro |
@dualmark/cloudflare |
0.2.0 | npm i @dualmark/cloudflare |
@dualmark/cli |
0.2.0 | npm i -g @dualmark/cli |
All published with npm provenance.
Highlights
@dualmark/converters — 12 generic converters
Replaces the original fintech-specific factories. Now ships with general-purpose converters for any marketing site:
featureConverter— feature/product pages with siblings, FAQ, problem/solutionpseoConverter— programmatic SEO (calculator pages, location pages, etc.)pricingConverter— tier comparison with recommended badge + CTAscompareConverter— "us vs. competitor" / "alternatives" pagescaseStudyConverter— customer wins with optional pull-quotechangelogConverter— release notes (Keep-a-Changelog style)docsConverter— documentation pages with section groupingblogConverter,glossaryConverter,legalConverter,toolConverter,videoConverter
@dualmark/cli — dualmark verify <url>
dualmark verify --help and dualmark verify -h now work as expected (print help, exit 0). Internal: cli.ts is a thin shim over main.ts to eliminate duplicate parsing logic.
@dualmark/cloudflare — Edge-correct headers
Direct .md URLs now receive the full set of AEO headers when fetched from ASSETS binding (Content-Type, X-Markdown-Tokens, X-Robots-Tag: noindex, Vary: Accept, X-Content-Type-Options: nosniff).
@dualmark/core — API consolidation
Path utilities and analytics types consolidated. Public primitives (detectAIBot, negotiateFormat, buildMarkdownResponse, renderLlmsTxt) unchanged.
Quick start
bun add @dualmark/astro @dualmark/core @dualmark/converters// astro.config.mjs
import dualmark from "@dualmark/astro";
export default defineConfig({
site: "https://yourcompany.com",
integrations: [
dualmark({
siteUrl: "https://yourcompany.com",
collections: { blog: { converter: "blog" } },
llmsTxt: { enabled: true },
}),
],
});bun run build
bunx @dualmark/cli verify https://localhost:4321/blog/your-post
# → Score 80/80 ✓Verify any site
bunx @dualmark/cli verify https://yourcompany.com/pricingThe same engine powers dualmark.dev/play.
Migration from a previous local install
If you'd installed pre-release builds from this repo:
- import { productConverter, taxConverter, countryConverter } from "@dualmark/converters";
+ import { featureConverter, pseoConverter } from "@dualmark/converters";Removed: productConverter, taxConverter, countryConverter, currencyConverter, paymentMethodConverter, caseStudyConverter.paymentProvider.
Use featureConverter for product/feature pages and pseoConverter for programmatic SEO. See per-package CHANGELOGs for full details:
- packages/core/CHANGELOG.md
- packages/converters/CHANGELOG.md
- packages/astro/CHANGELOG.md
- packages/cloudflare/CHANGELOG.md
- packages/cli/CHANGELOG.md