Skip to content

Releases: dodopayments/dualmark

v0.8.0 — @dualmark/deno + status-page converter + CLI v1.0 JSON

30 May 07:11

Choose a tag to compare

Highlights

Three things land in this release:

  • New package: @dualmark/deno — a Deno Deploy edge adapter that wraps any Deno fetch handler. AI bots get the markdown twin at the edge; lifecycle hooks (analytics/telemetry) are scheduled on info.completed. examples/deno-deploy scores a perfect 125/125 under deno run.
  • New converter: status-page — a built-in converter for public uptime/status pages (component health + incidents). Drop converter: "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/cli now 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 on info.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-page resolver in @dualmark/astro and @dualmark/nextjs — no config beyond converter: "status-page".
  • Separators in the status converter now render conditionally (b2d925e).

@dualmark/cli@0.8.0

  • verify --json now emits the AEO Spec v1.0 JSON contract (65ab17e) and enforces --json mutual exclusivity with --quiet/--color. Required-check failures still exit non-zero.

    Migration note: --json previously emitted the internal VerifyReport shape (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.0

To 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-deploy 125/125, examples/astro-cloudflare-full 125/125, examples/nextjs-app-router 120/125

v0.7.0 — More AI bots + integration converter

20 May 19:05
e048a2c

Choose a tag to compare

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). Drop converter: "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-ExternalFetcher UA pattern to avoid false positives (0377a0e) and classify its purpose as user-action rather than training (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 integration resolver in both @dualmark/astro and @dualmark/nextjs — no config beyond converter: "integration".
  • Refactor: integration categories 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.0

To 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-full still 125/125, examples/nextjs-app-router 120/125

Full changelogs

Full diff: v0.6.0...v0.7.0

v0.6.0 — Astro 6 security upgrade

13 May 09:32
05a9a79

Choose a tag to compare

Highlights

Security release. Bumps the `astro` peer dependency to `^6.1.10` to resolve two upstream advisories that were never backported to Astro 5:

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

v0.5.2 — npm provenance + Astro catalog auto-discovery

12 May 11:50
a16b370

Choose a tag to compare

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

10 May 03:45

Choose a tag to compare

@dualmark/nextjs@0.5.1

Patch Changes

  • fix(nextjs): withDualmark() rejecting typed NextConfig from next.config.ts (#26).

    The internal NextConfigShape constraint had an [key: string]: unknown index
    signature, which TypeScript treats as a structural demand on the input. Next.js's
    NextConfig is a closed interface with no top-level index signature, so any
    caller passing a typed next.config.ts hit:

    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 next devDependency from ^15.0.0 to ^16.2.6 (test/build
      toolchain only — the peerDependencies range is unchanged).
    • Update README to document the Next.js 16 proxy.ts file convention,
      with a note that Next ≤15 should keep using middleware.ts (body is
      identical). No runtime behavior change.

    The reference example at examples/nextjs-app-router was migrated to
    Next.js 16 in the same change and still scores 120/125 under next dev.

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

07 May 11:03

Choose a tag to compare

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

Full PR · Issue #4

v0.3.1 — Hotfix: workspace deps + landing polish

05 May 20:45
bd68f5e

Choose a tag to compare

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 publish lockfile-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):

  1. The version-packages script now chains bun install --lockfile-only after changeset version, so the version PR commits a refreshed lockfile.
  2. release.yml runs 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-b that produced a stray horizontal hairline below the terminal demo.
  • Page rails: promoted z-index from 0 to 10 so rails render above the hero BeamsBackground gradients (previously the bottom radial fade obscured rails inside the hero).
  • Navbar: scoped the bottom border to its inner max-w-7xl column 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 new divider prop, default true). 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


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.1 with correctly resolved cross-package dependencies ("@dualmark/core": "0.3.1").

License

Apache 2.0. See LICENSE and NOTICE.

v0.3.0

05 May 20:11
76b65c3

Choose a tag to compare

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 NOTICE file.

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-hidden so they stop at rail edges instead of bleeding past.
  • Content column widened from max-w-5xl to max-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.description and twitter.description
  • JSON-LD Organization.description
  • llms.txt brand description (the primary AI agent discovery artifact)
  • raw/index.md blockquote (markdown twin of the landing)
  • Fumadocs content/docs/index.mdx frontmatter

Documentation pass

  • README test-count claims corrected: 266 across 5 packages (was incorrectly 253). Breakdown: @dualmark/core 167, @dualmark/astro 35, @dualmark/converters 24, @dualmark/cloudflare 23, @dualmark/cli 17.
  • All npx @dualmark/cli invocations unified to bunx @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.md release flow updated to match the actual release.yml (which uses bun publish per package, not changeset publish).

Migration

  • Code: none required.
  • License notices: redistributors should update LICENSE references from MIT to Apache 2.0 and include the NOTICE file.
  • 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 typecheck 10/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

05 May 16:30

Choose a tag to compare

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.1

Or for a fresh install, just install latest:

bun add @dualmark/astro
# resolves to @dualmark/astro@0.2.1 with valid transitive deps

Packages 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

05 May 16:15
09810c1

Choose a tag to compare

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/solution
  • pseoConverter — programmatic SEO (calculator pages, location pages, etc.)
  • pricingConverter — tier comparison with recommended badge + CTAs
  • compareConverter — "us vs. competitor" / "alternatives" pages
  • caseStudyConverter — customer wins with optional pull-quote
  • changelogConverter — release notes (Keep-a-Changelog style)
  • docsConverter — documentation pages with section grouping
  • blogConverter, glossaryConverter, legalConverter, toolConverter, videoConverter

@dualmark/clidualmark 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/pricing

The 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:

Links