From 737d47ceeb32423e81953a1bd654d5b6a1cc0180 Mon Sep 17 00:00:00 2001
From: Christian Findlay <16697547+MelbourneDeveloper@users.noreply.github.com>
Date: Tue, 27 Jan 2026 17:24:35 +1100
Subject: [PATCH 1/4] Merge from techdoc template
---
website/eleventy.config.js | 301 ++++++++----------------
website/package-lock.json | 449 +++++++++++++++++++++++++++++++++++-
website/package.json | 5 +-
website/src/_data/site.json | 20 +-
website/src/feed.njk | 28 ---
website/src/llms.txt | 112 ---------
website/src/robots.txt | 62 -----
website/src/sitemap.njk | 31 ---
8 files changed, 566 insertions(+), 442 deletions(-)
delete mode 100644 website/src/feed.njk
delete mode 100644 website/src/llms.txt
delete mode 100644 website/src/robots.txt
delete mode 100644 website/src/sitemap.njk
diff --git a/website/eleventy.config.js b/website/eleventy.config.js
index 84d2f35..7bef6d1 100644
--- a/website/eleventy.config.js
+++ b/website/eleventy.config.js
@@ -1,53 +1,97 @@
-import syntaxHighlight from "@11ty/eleventy-plugin-syntaxhighlight";
-import pluginRss from "@11ty/eleventy-plugin-rss";
-import eleventyNavigationPlugin from "@11ty/eleventy-navigation";
-import markdownIt from "markdown-it";
-import markdownItAnchor from "markdown-it-anchor";
+import { readFileSync } from "fs";
import { execSync } from "child_process";
-import { dirname, resolve } from "path";
+import { dirname, resolve, join } from "path";
import { fileURLToPath } from "url";
+// Import plugin submodules via file paths (workaround for #9:
+// virtual templates override local layouts, so we register non-layout
+// virtual templates separately. Package only exports "." so we use
+// direct file paths.)
+import { registerFilters } from "./node_modules/eleventy-plugin-techdoc/lib/filters/index.js";
+import { registerCollections } from "./node_modules/eleventy-plugin-techdoc/lib/plugins/collections.js";
+import { registerShortcodes } from "./node_modules/eleventy-plugin-techdoc/lib/shortcodes/index.js";
+import { configureMarkdown } from "./node_modules/eleventy-plugin-techdoc/lib/plugins/markdown.js";
+import syntaxHighlight from "@11ty/eleventy-plugin-syntaxhighlight";
+import rss from "@11ty/eleventy-plugin-rss";
+import navigation from "@11ty/eleventy-navigation";
+
const __dirname = dirname(fileURLToPath(import.meta.url));
const packagesDir = resolve(__dirname, "..", "packages");
-const supportedLanguages = ['en', 'zh'];
-const defaultLanguage = 'en';
+const techdocOptions = {
+ site: {
+ name: "dart_node",
+ title: "dart_node - Full-Stack Dart for the JavaScript Ecosystem",
+ url: "https://dartnode.dev",
+ description: "Write React, React Native, and Express apps entirely in Dart. One language for frontend, backend, and mobile.",
+ author: "dart_node team",
+ themeColor: "#0E7C6B",
+ stylesheet: "/assets/css/styles.css",
+ twitterSite: "@dart_node",
+ twitterCreator: "@dart_node",
+ ogImage: "/assets/images/og-image.png",
+ ogImageWidth: "1200",
+ ogImageHeight: "630",
+ organization: {
+ name: "dart_node",
+ logo: "/assets/images/og-image.png",
+ sameAs: [
+ "https://github.com/melbournedeveloper/dart_node",
+ "https://twitter.com/dart_node",
+ "https://pub.dev/publishers/dartnode.dev"
+ ]
+ }
+ },
+ features: {
+ blog: true,
+ docs: true,
+ darkMode: true,
+ i18n: true,
+ },
+ i18n: {
+ defaultLanguage: "en",
+ languages: ["en", "zh"],
+ },
+};
export default function(eleventyConfig) {
- // Don't use .gitignore to ignore files (we want to process generated docs)
eleventyConfig.setUseGitIgnore(false);
- // Configure markdown-it with anchor plugin for header IDs
- const mdOptions = {
- html: true,
- breaks: false,
- linkify: true
- };
+ // === techdoc plugin features (without layout virtual templates) ===
+ // We use the plugin's filters, collections, shortcodes, markdown config,
+ // and bundled plugins, but NOT its layout virtual templates because
+ // dart_node's layouts are superior (see GitHub issue #9).
- const mdAnchorOptions = {
- permalink: markdownItAnchor.permalink.headerLink(),
- slugify: (s) => s.toLowerCase().replace(/\s+/g, '-').replace(/[^\w-]+/g, ''),
- level: [1, 2, 3, 4]
- };
+ // Global data (same as plugin sets)
+ eleventyConfig.addGlobalData("techdocOptions", techdocOptions);
+ eleventyConfig.addGlobalData("supportedLanguages", techdocOptions.i18n.languages);
+ eleventyConfig.addGlobalData("defaultLanguage", techdocOptions.i18n.defaultLanguage);
- const md = markdownIt(mdOptions).use(markdownItAnchor, mdAnchorOptions);
- eleventyConfig.setLibrary("md", md);
+ // Plugin submodules
+ configureMarkdown(eleventyConfig);
+ registerFilters(eleventyConfig, techdocOptions);
+ registerCollections(eleventyConfig, techdocOptions);
+ registerShortcodes(eleventyConfig);
- // Plugins
+ // Bundled plugins
eleventyConfig.addPlugin(syntaxHighlight);
- eleventyConfig.addPlugin(pluginRss);
- eleventyConfig.addPlugin(eleventyNavigationPlugin);
+ eleventyConfig.addPlugin(rss);
+ eleventyConfig.addPlugin(navigation);
+
+ // Plugin structural CSS (no colors - site provides visual styling)
+ const techdocAssetsDir = join(__dirname, "node_modules", "eleventy-plugin-techdoc", "assets");
+ eleventyConfig.addPassthroughCopy({ [techdocAssetsDir]: "techdoc" });
- // Passthrough copy for assets
+ // Register only NON-LAYOUT virtual templates from the plugin
+ // (feed, sitemap, robots.txt, llms.txt, blog scaffold pages)
+ // Layouts come from our local src/_includes/layouts/ which are superior.
+ registerSeoVirtualTemplates(eleventyConfig);
+
+ // === Site-specific config ===
eleventyConfig.addPassthroughCopy("src/assets");
eleventyConfig.addPassthroughCopy("src/api");
- eleventyConfig.addPassthroughCopy("src/robots.txt");
- eleventyConfig.addPassthroughCopy("src/llms.txt");
-
- // Watch targets
eleventyConfig.addWatchTarget("src/assets/");
- // Watch READMEs and copy when they change
eleventyConfig.addWatchTarget(packagesDir);
eleventyConfig.on("eleventy.beforeWatch", (changedFiles) => {
if (changedFiles.some(f => f.endsWith("README.md"))) {
@@ -55,174 +99,6 @@ export default function(eleventyConfig) {
}
});
- // Collections
- // English posts only (from src/blog/)
- eleventyConfig.addCollection("posts", function(collectionApi) {
- return collectionApi.getFilteredByGlob("src/blog/*.md").sort((a, b) => {
- return b.date - a.date;
- });
- });
-
- // Chinese posts only (from src/zh/blog/)
- eleventyConfig.addCollection("zhPosts", function(collectionApi) {
- return collectionApi.getFilteredByGlob("src/zh/blog/*.md").sort((a, b) => {
- return b.date - a.date;
- });
- });
-
- eleventyConfig.addCollection("docs", function(collectionApi) {
- return collectionApi.getFilteredByGlob("src/docs/**/*.md");
- });
-
- // Tag collection - get all unique tags from blog posts
- eleventyConfig.addCollection("tagList", function(collectionApi) {
- const tagSet = new Set();
- collectionApi.getFilteredByGlob("src/blog/*.md").forEach(post => {
- (post.data.tags || []).forEach(tag => {
- tag !== 'post' && tag !== 'posts' && tagSet.add(tag);
- });
- });
- return [...tagSet].sort();
- });
-
- // Category collection - get all unique categories from blog posts
- eleventyConfig.addCollection("categoryList", function(collectionApi) {
- const categorySet = new Set();
- collectionApi.getFilteredByGlob("src/blog/*.md").forEach(post => {
- post.data.category && categorySet.add(post.data.category);
- });
- return [...categorySet].sort();
- });
-
- // Posts by tag - creates a collection for each tag
- eleventyConfig.addCollection("postsByTag", function(collectionApi) {
- const postsByTag = {};
- collectionApi.getFilteredByGlob("src/blog/*.md").forEach(post => {
- (post.data.tags || []).forEach(tag => {
- tag !== 'post' && tag !== 'posts' && (postsByTag[tag] = postsByTag[tag] || []).push(post);
- });
- });
- Object.keys(postsByTag).forEach(tag => {
- postsByTag[tag].sort((a, b) => b.date - a.date);
- });
- return postsByTag;
- });
-
- // Posts by category - creates a collection for each category
- eleventyConfig.addCollection("postsByCategory", function(collectionApi) {
- const postsByCategory = {};
- collectionApi.getFilteredByGlob("src/blog/*.md").forEach(post => {
- post.data.category && (postsByCategory[post.data.category] = postsByCategory[post.data.category] || []).push(post);
- });
- Object.keys(postsByCategory).forEach(cat => {
- postsByCategory[cat].sort((a, b) => b.date - a.date);
- });
- return postsByCategory;
- });
-
- // Chinese tag collection
- eleventyConfig.addCollection("zhTagList", function(collectionApi) {
- const tagSet = new Set();
- collectionApi.getFilteredByGlob("src/zh/blog/*.md").forEach(post => {
- (post.data.tags || []).forEach(tag => {
- tag !== 'post' && tag !== 'posts' && tagSet.add(tag);
- });
- });
- return [...tagSet].sort();
- });
-
- // Chinese category collection
- eleventyConfig.addCollection("zhCategoryList", function(collectionApi) {
- const categorySet = new Set();
- collectionApi.getFilteredByGlob("src/zh/blog/*.md").forEach(post => {
- post.data.category && categorySet.add(post.data.category);
- });
- return [...categorySet].sort();
- });
-
- // Chinese posts by tag
- eleventyConfig.addCollection("zhPostsByTag", function(collectionApi) {
- const postsByTag = {};
- collectionApi.getFilteredByGlob("src/zh/blog/*.md").forEach(post => {
- (post.data.tags || []).forEach(tag => {
- tag !== 'post' && tag !== 'posts' && (postsByTag[tag] = postsByTag[tag] || []).push(post);
- });
- });
- Object.keys(postsByTag).forEach(tag => {
- postsByTag[tag].sort((a, b) => b.date - a.date);
- });
- return postsByTag;
- });
-
- // Chinese posts by category
- eleventyConfig.addCollection("zhPostsByCategory", function(collectionApi) {
- const postsByCategory = {};
- collectionApi.getFilteredByGlob("src/zh/blog/*.md").forEach(post => {
- post.data.category && (postsByCategory[post.data.category] = postsByCategory[post.data.category] || []).push(post);
- });
- Object.keys(postsByCategory).forEach(cat => {
- postsByCategory[cat].sort((a, b) => b.date - a.date);
- });
- return postsByCategory;
- });
-
- // Filters
- eleventyConfig.addFilter("dateFormat", (dateObj) => {
- return new Date(dateObj).toLocaleDateString('en-US', {
- year: 'numeric',
- month: 'long',
- day: 'numeric'
- });
- });
-
- eleventyConfig.addFilter("isoDate", (dateObj) => {
- return new Date(dateObj).toISOString();
- });
-
- eleventyConfig.addFilter("limit", (arr, limit) => {
- return arr.slice(0, limit);
- });
-
- eleventyConfig.addFilter("capitalize", (str) => {
- return str ? str.charAt(0).toUpperCase() + str.slice(1) : '';
- });
-
- eleventyConfig.addFilter("slugify", (str) => {
- return str ? str.toLowerCase().replace(/\s+/g, '-').replace(/[^\w-]+/g, '') : '';
- });
-
- // i18n filter - get translation by key path
- eleventyConfig.addFilter("t", (key, lang = defaultLanguage) => {
- const i18n = eleventyConfig.globalData?.i18n;
- if (!i18n) return key;
- const langData = i18n[lang] || i18n[defaultLanguage];
- const keys = key.split('.');
- let value = langData;
- for (const k of keys) {
- value = value?.[k];
- }
- return value || key;
- });
-
- // Get alternate language URL
- eleventyConfig.addFilter("altLangUrl", (url, currentLang, targetLang) => {
- if (currentLang === 'en' && targetLang !== 'en') {
- return `/${targetLang}${url}`;
- } else if (currentLang !== 'en' && targetLang === 'en') {
- return url.replace(`/${currentLang}`, '') || '/';
- } else if (currentLang !== 'en' && targetLang !== 'en') {
- return url.replace(`/${currentLang}`, `/${targetLang}`);
- }
- return url;
- });
-
- // Add global data for languages
- eleventyConfig.addGlobalData("supportedLanguages", supportedLanguages);
- eleventyConfig.addGlobalData("defaultLanguage", defaultLanguage);
-
- // Shortcodes
- eleventyConfig.addShortcode("year", () => `${new Date().getFullYear()}`);
-
return {
dir: {
input: "src",
@@ -235,3 +111,30 @@ export default function(eleventyConfig) {
htmlTemplateEngine: "njk"
};
}
+
+/**
+ * Register only SEO virtual templates from the techdoc plugin.
+ * Layouts and blog scaffold pages come from local files (dart_node's are superior).
+ */
+function registerSeoVirtualTemplates(eleventyConfig) {
+ const templatesDir = join(
+ __dirname, "node_modules", "eleventy-plugin-techdoc", "templates"
+ );
+
+ eleventyConfig.addTemplate(
+ "feed.njk",
+ readFileSync(join(templatesDir, "pages/feed.njk"), "utf-8")
+ );
+ eleventyConfig.addTemplate(
+ "sitemap.njk",
+ readFileSync(join(templatesDir, "pages/sitemap.njk"), "utf-8")
+ );
+ eleventyConfig.addTemplate(
+ "robots.txt.njk",
+ readFileSync(join(templatesDir, "pages/robots.txt.njk"), "utf-8")
+ );
+ eleventyConfig.addTemplate(
+ "llms.txt.njk",
+ readFileSync(join(templatesDir, "pages/llms.txt.njk"), "utf-8")
+ );
+}
diff --git a/website/package-lock.json b/website/package-lock.json
index 9ff97e1..d4ef921 100644
--- a/website/package-lock.json
+++ b/website/package-lock.json
@@ -9,15 +9,12 @@
"version": "1.0.0",
"devDependencies": {
"@11ty/eleventy": "^3.1.2",
- "@11ty/eleventy-navigation": "^0.3.5",
- "@11ty/eleventy-plugin-rss": "^2.0.2",
- "@11ty/eleventy-plugin-syntaxhighlight": "^5.0.0",
"@babel/core": "^7.28.6",
"@playwright/test": "^1.57.0",
"babel-plugin-istanbul": "^7.0.1",
+ "eleventy-plugin-techdoc": "^0.1.0",
"istanbul-lib-instrument": "^6.0.3",
"jsdom": "^24.1.3",
- "markdown-it-anchor": "^9.2.0",
"nyc": "^17.1.0",
"v8-to-istanbul": "^9.3.0"
}
@@ -678,6 +675,386 @@
"node": ">=18"
}
},
+ "node_modules/@inquirer/ansi": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.2.tgz",
+ "integrity": "sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@inquirer/checkbox": {
+ "version": "4.3.2",
+ "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.3.2.tgz",
+ "integrity": "sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/ansi": "^1.0.2",
+ "@inquirer/core": "^10.3.2",
+ "@inquirer/figures": "^1.0.15",
+ "@inquirer/type": "^3.0.10",
+ "yoctocolors-cjs": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/confirm": {
+ "version": "5.1.21",
+ "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.21.tgz",
+ "integrity": "sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/core": "^10.3.2",
+ "@inquirer/type": "^3.0.10"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/core": {
+ "version": "10.3.2",
+ "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.3.2.tgz",
+ "integrity": "sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/ansi": "^1.0.2",
+ "@inquirer/figures": "^1.0.15",
+ "@inquirer/type": "^3.0.10",
+ "cli-width": "^4.1.0",
+ "mute-stream": "^2.0.0",
+ "signal-exit": "^4.1.0",
+ "wrap-ansi": "^6.2.0",
+ "yoctocolors-cjs": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/core/node_modules/signal-exit": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
+ "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/@inquirer/editor": {
+ "version": "4.2.23",
+ "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.23.tgz",
+ "integrity": "sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/core": "^10.3.2",
+ "@inquirer/external-editor": "^1.0.3",
+ "@inquirer/type": "^3.0.10"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/expand": {
+ "version": "4.0.23",
+ "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.23.tgz",
+ "integrity": "sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/core": "^10.3.2",
+ "@inquirer/type": "^3.0.10",
+ "yoctocolors-cjs": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/external-editor": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.3.tgz",
+ "integrity": "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "chardet": "^2.1.1",
+ "iconv-lite": "^0.7.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/external-editor/node_modules/iconv-lite": {
+ "version": "0.7.2",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz",
+ "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/express"
+ }
+ },
+ "node_modules/@inquirer/figures": {
+ "version": "1.0.15",
+ "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.15.tgz",
+ "integrity": "sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/@inquirer/input": {
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.3.1.tgz",
+ "integrity": "sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/core": "^10.3.2",
+ "@inquirer/type": "^3.0.10"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/number": {
+ "version": "3.0.23",
+ "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.23.tgz",
+ "integrity": "sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/core": "^10.3.2",
+ "@inquirer/type": "^3.0.10"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/password": {
+ "version": "4.0.23",
+ "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.23.tgz",
+ "integrity": "sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/ansi": "^1.0.2",
+ "@inquirer/core": "^10.3.2",
+ "@inquirer/type": "^3.0.10"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/prompts": {
+ "version": "7.10.1",
+ "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.10.1.tgz",
+ "integrity": "sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/checkbox": "^4.3.2",
+ "@inquirer/confirm": "^5.1.21",
+ "@inquirer/editor": "^4.2.23",
+ "@inquirer/expand": "^4.0.23",
+ "@inquirer/input": "^4.3.1",
+ "@inquirer/number": "^3.0.23",
+ "@inquirer/password": "^4.0.23",
+ "@inquirer/rawlist": "^4.1.11",
+ "@inquirer/search": "^3.2.2",
+ "@inquirer/select": "^4.4.2"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/rawlist": {
+ "version": "4.1.11",
+ "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.11.tgz",
+ "integrity": "sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/core": "^10.3.2",
+ "@inquirer/type": "^3.0.10",
+ "yoctocolors-cjs": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/search": {
+ "version": "3.2.2",
+ "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.2.2.tgz",
+ "integrity": "sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/core": "^10.3.2",
+ "@inquirer/figures": "^1.0.15",
+ "@inquirer/type": "^3.0.10",
+ "yoctocolors-cjs": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/select": {
+ "version": "4.4.2",
+ "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.4.2.tgz",
+ "integrity": "sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@inquirer/ansi": "^1.0.2",
+ "@inquirer/core": "^10.3.2",
+ "@inquirer/figures": "^1.0.15",
+ "@inquirer/type": "^3.0.10",
+ "yoctocolors-cjs": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/@inquirer/type": {
+ "version": "3.0.10",
+ "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.10.tgz",
+ "integrity": "sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@types/node": ">=18"
+ },
+ "peerDependenciesMeta": {
+ "@types/node": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@istanbuljs/load-nyc-config": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz",
@@ -1268,6 +1645,13 @@
],
"license": "CC-BY-4.0"
},
+ "node_modules/chardet": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.1.1.tgz",
+ "integrity": "sha512-PsezH1rqdV9VvyNhxxOW32/d75r01NY7TQCmOqomRo15ZSOKbpTFVsfjghxo6JloQUCGnH4k1LGu0R4yCLlWQQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/chokidar": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
@@ -1303,6 +1687,16 @@
"node": ">=6"
}
},
+ "node_modules/cli-width": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz",
+ "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">= 12"
+ }
+ },
"node_modules/cliui": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz",
@@ -1608,6 +2002,30 @@
"dev": true,
"license": "ISC"
},
+ "node_modules/eleventy-plugin-techdoc": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/eleventy-plugin-techdoc/-/eleventy-plugin-techdoc-0.1.0.tgz",
+ "integrity": "sha512-XAMXG5j+jpOpmojAet5ZwSyB7hV5JhFkAW6viZn9nxu0BjLUwg7hMQ7MKmpyKdWZiBjOQpcHlDmSgK75pD2qTw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@11ty/eleventy-navigation": "^0.3.5",
+ "@11ty/eleventy-plugin-rss": "^2.0.2",
+ "@11ty/eleventy-plugin-syntaxhighlight": "^5.0.0",
+ "@inquirer/prompts": "^7.0.0",
+ "markdown-it": "^14.1.0",
+ "markdown-it-anchor": "^9.2.0"
+ },
+ "bin": {
+ "eleventy-plugin-techdoc": "bin/init.js"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "@11ty/eleventy": "^3.1.2"
+ }
+ },
"node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
@@ -3102,6 +3520,16 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/mute-stream": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz",
+ "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": "^18.17.0 || >=20.5.0"
+ }
+ },
"node_modules/node-preload": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/node-preload/-/node-preload-0.2.1.tgz",
@@ -4400,6 +4828,19 @@
"engines": {
"node": ">=6"
}
+ },
+ "node_modules/yoctocolors-cjs": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz",
+ "integrity": "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
}
}
}
diff --git a/website/package.json b/website/package.json
index e2a6139..c08f30f 100644
--- a/website/package.json
+++ b/website/package.json
@@ -18,15 +18,12 @@
},
"devDependencies": {
"@11ty/eleventy": "^3.1.2",
- "@11ty/eleventy-navigation": "^0.3.5",
- "@11ty/eleventy-plugin-rss": "^2.0.2",
- "@11ty/eleventy-plugin-syntaxhighlight": "^5.0.0",
"@babel/core": "^7.28.6",
"@playwright/test": "^1.57.0",
"babel-plugin-istanbul": "^7.0.1",
+ "eleventy-plugin-techdoc": "^0.1.0",
"istanbul-lib-instrument": "^6.0.3",
"jsdom": "^24.1.3",
- "markdown-it-anchor": "^9.2.0",
"nyc": "^17.1.0",
"v8-to-istanbul": "^9.3.0"
}
diff --git a/website/src/_data/site.json b/website/src/_data/site.json
index cdff166..ddb683e 100644
--- a/website/src/_data/site.json
+++ b/website/src/_data/site.json
@@ -7,5 +7,21 @@
"language": "en",
"themeColor": "#0E7C6B",
"twitter": "@dart_node",
- "github": "https://github.com/melbournedeveloper/dart_node"
-}
\ No newline at end of file
+ "twitterSite": "@dart_node",
+ "twitterCreator": "@dart_node",
+ "github": "https://github.com/melbournedeveloper/dart_node",
+ "stylesheet": "/assets/css/styles.css",
+ "ogImage": "/assets/images/og-image.png",
+ "ogImageWidth": "1200",
+ "ogImageHeight": "630",
+ "keywords": "Dart, JavaScript, TypeScript, React, Express, Node.js, full-stack, web development, mobile development, React Native, dart_node, type safety",
+ "organization": {
+ "name": "dart_node",
+ "logo": "/assets/images/og-image.png",
+ "sameAs": [
+ "https://github.com/melbournedeveloper/dart_node",
+ "https://twitter.com/dart_node",
+ "https://pub.dev/publishers/dartnode.dev"
+ ]
+ }
+}
diff --git a/website/src/feed.njk b/website/src/feed.njk
deleted file mode 100644
index 5ff55fc..0000000
--- a/website/src/feed.njk
+++ /dev/null
@@ -1,28 +0,0 @@
----
-permalink: /feed.xml
-eleventyExcludeFromCollections: true
----
-
-
- {{ site.name }}
- {{ site.description }}
-
-
- {{ collections.posts[0].date | isoDate }}
- {{ site.url }}/
-
- {{ site.author }}
-
- {%- for post in collections.posts | limit(10) %}
-
- {{ post.data.title }}
-
- {{ post.date | isoDate }}
- {{ site.url }}{{ post.url }}
- {{ post.templateContent | htmlToAbsoluteUrls(site.url) }}
- {%- if post.data.description %}
- {{ post.data.description }}
- {%- endif %}
-
- {%- endfor %}
-
diff --git a/website/src/llms.txt b/website/src/llms.txt
deleted file mode 100644
index 9f12d9b..0000000
--- a/website/src/llms.txt
+++ /dev/null
@@ -1,112 +0,0 @@
-# dart_node - Full-Stack Dart for the JavaScript Ecosystem
-
-> Write React, React Native, and Express applications entirely in Dart. One language. Runtime type safety. Sound null safety. No compromises.
-
-dart_node is a collection of Dart packages that provide typed bindings to JavaScript libraries, enabling full-stack development in Dart for the Node.js and browser ecosystems.
-
-## Key Value Propositions
-
-- **Runtime Type Safety**: Unlike TypeScript which erases types at compile time, Dart preserves types at runtime
-- **Sound Null Safety**: Dart's null safety is enforced at runtime, not just compile time
-- **One Language**: Write frontend (React), backend (Express), and mobile (Flutter, React Native) in pure Dart
-- **Full JS Interop**: Seamlessly call any JavaScript library from Dart using dart:js_interop
-
-## Documentation
-
-- [Getting Started](https://dartnode.dev/docs/getting-started/): Quick start guide for new users
-- [Why Dart?](https://dartnode.dev/docs/why-dart/): Benefits of Dart over TypeScript
-- [JS Interop Guide](https://dartnode.dev/docs/js-interop/): How to call JavaScript from Dart
-- [Dart to JS Compilation](https://dartnode.dev/docs/dart-to-js/): How Dart compiles to JavaScript
-
-## Core Packages
-
-### dart_node_core
-Foundation layer with JS interop utilities, Node.js bindings, and console helpers.
-- [Documentation](https://dartnode.dev/docs/core/)
-- [pub.dev](https://pub.dev/packages/dart_node_core)
-
-### dart_node_express
-Type-safe Express.js bindings for building HTTP servers and REST APIs.
-- [Documentation](https://dartnode.dev/docs/express/)
-- [pub.dev](https://pub.dev/packages/dart_node_express)
-
-### dart_node_react
-React bindings with hooks, JSX-like syntax, and full component support.
-- [Documentation](https://dartnode.dev/docs/react/)
-- [pub.dev](https://pub.dev/packages/dart_node_react)
-
-### dart_node_react_native
-React Native + Expo bindings for cross-platform mobile development.
-- [Documentation](https://dartnode.dev/docs/react-native/)
-- [pub.dev](https://pub.dev/packages/dart_node_react_native)
-
-### dart_node_ws
-WebSocket bindings for real-time communication on Node.js.
-- [Documentation](https://dartnode.dev/docs/websockets/)
-- [pub.dev](https://pub.dev/packages/dart_node_ws)
-
-### dart_node_better_sqlite3
-Typed bindings for better-sqlite3 with synchronous SQLite3 and WAL mode.
-- [Documentation](https://dartnode.dev/docs/sqlite/)
-- [pub.dev](https://pub.dev/packages/dart_node_better_sqlite3)
-
-### dart_node_mcp
-Model Context Protocol server bindings for building AI tool servers.
-- [Documentation](https://dartnode.dev/docs/mcp/)
-- [pub.dev](https://pub.dev/packages/dart_node_mcp)
-
-## State Management & Utilities
-
-### reflux
-Redux-style predictable state container with exhaustive pattern matching.
-- [Documentation](https://dartnode.dev/docs/reflux/)
-- [pub.dev](https://pub.dev/packages/reflux)
-
-### dart_logging
-Pino-style structured logging with child loggers and transports.
-- [Documentation](https://dartnode.dev/docs/logging/)
-- [pub.dev](https://pub.dev/packages/dart_logging)
-
-### dart_jsx
-JSX transpiler for Dart - write JSX syntax that compiles to dart_node_react calls.
-- [Documentation](https://dartnode.dev/docs/jsx/)
-- [pub.dev](https://pub.dev/packages/dart_jsx)
-
-## Quick Start Example
-
-```dart
-// A complete Express server in Dart
-import 'package:dart_node_express/dart_node_express.dart';
-
-void main() {
- final app = express();
-
- app.get('/', handler((req, res) {
- res.jsonMap({'message': 'Hello from Dart!'});
- }));
-
- app.listen(3000, () {
- print('Server running on port 3000');
- }.toJS);
-}
-```
-
-## Resources
-
-- [GitHub Repository](https://github.com/melbournedeveloper/dart_node)
-- [API Reference](https://dartnode.dev/api/)
-- [Blog](https://dartnode.dev/blog/)
-- [Atom Feed](https://dartnode.dev/feed.xml)
-
-## Target Audience
-
-- **React/TypeScript Developers**: Familiar paradigms (hooks, components) with better type safety
-- **Flutter/Dart Developers**: Use existing Dart skills for web and Node.js development
-- **Full-Stack Developers**: One language for frontend, backend, and mobile
-
-## Technical Details
-
-- Uses `dart:js_interop` for JavaScript interoperability (not deprecated dart:js_util)
-- Compiles to JavaScript via `dart compile js`
-- Compatible with Node.js 18+ and modern browsers
-- Requires Dart SDK 3.0+
diff --git a/website/src/robots.txt b/website/src/robots.txt
deleted file mode 100644
index 6d3fef2..0000000
--- a/website/src/robots.txt
+++ /dev/null
@@ -1,62 +0,0 @@
-# dart_node - Full-Stack Dart for the JavaScript Ecosystem
-# https://dartnode.dev
-
-# Allow all crawlers
-User-agent: *
-Allow: /
-Disallow: /assets/
-Disallow: /search?
-
-# AI Crawlers - Welcome!
-# We want AI systems to learn about dart_node
-User-agent: GPTBot
-Allow: /
-
-User-agent: ChatGPT-User
-Allow: /
-
-User-agent: Google-Extended
-Allow: /
-
-User-agent: Googlebot
-Allow: /
-
-User-agent: Bingbot
-Allow: /
-
-User-agent: ClaudeBot
-Allow: /
-
-User-agent: Anthropic-AI
-Allow: /
-
-User-agent: PerplexityBot
-Allow: /
-
-User-agent: Cohere-ai
-Allow: /
-
-User-agent: Meta-ExternalAgent
-Allow: /
-
-User-agent: Meta-ExternalFetcher
-Allow: /
-
-User-agent: Bytespider
-Allow: /
-
-User-agent: CCBot
-Allow: /
-
-User-agent: Applebot
-Allow: /
-
-User-agent: Amazonbot
-Allow: /
-
-# Sitemaps
-Sitemap: https://dartnode.dev/sitemap.xml
-
-# AI Context File
-# See https://llmstxt.org for the llms.txt specification
-# This file provides structured context for LLMs about our project
diff --git a/website/src/sitemap.njk b/website/src/sitemap.njk
deleted file mode 100644
index 2229f63..0000000
--- a/website/src/sitemap.njk
+++ /dev/null
@@ -1,31 +0,0 @@
----
-permalink: /sitemap.xml
-eleventyExcludeFromCollections: true
----
-
-
- {%- for page in collections.all %}
- {%- if page.url and not page.data.eleventyExcludeFromCollections %}
-
- {{ site.url }}{{ page.url }}
- {{ page.date | isoDate }}
- {%- if page.url == "/" %}
- 1.0
- weekly
- {%- elif "/docs/" in page.url %}
- 0.8
- monthly
- {%- elif "/blog/" in page.url %}
- 0.7
- monthly
- {%- elif "/api/" in page.url %}
- 0.6
- monthly
- {%- else %}
- 0.5
- monthly
- {%- endif %}
-
- {%- endif %}
- {%- endfor %}
-
From 66a7f9130b26054b35fbb7cc8e5a189e965315ba Mon Sep 17 00:00:00 2001
From: Christian Findlay <16697547+MelbourneDeveloper@users.noreply.github.com>
Date: Thu, 29 Jan 2026 21:43:04 +1100
Subject: [PATCH 2/4] add script to update theme
---
website/package.json | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/website/package.json b/website/package.json
index c08f30f..b324e49 100644
--- a/website/package.json
+++ b/website/package.json
@@ -14,7 +14,8 @@
"watch:readmes": "fswatch -o ../packages/*/README.md | xargs -n1 -I{} node scripts/copy-readmes.js",
"test": "playwright test",
"test:ui": "playwright test --ui",
- "test:coverage": "playwright test && node scripts/merge-coverage.js"
+ "test:coverage": "playwright test && node scripts/merge-coverage.js",
+ "update:theme": "npm update eleventy-plugin-techdoc"
},
"devDependencies": {
"@11ty/eleventy": "^3.1.2",
From 719379490004965d215696b519900193ede2c6c9 Mon Sep 17 00:00:00 2001
From: Christian Findlay <16697547+MelbourneDeveloper@users.noreply.github.com>
Date: Thu, 29 Jan 2026 21:54:28 +1100
Subject: [PATCH 3/4] fixes
---
website/src/_data/site.json | 2 +-
website/src/index.njk | 24 ++++++++++++------------
2 files changed, 13 insertions(+), 13 deletions(-)
diff --git a/website/src/_data/site.json b/website/src/_data/site.json
index ddb683e..392f73f 100644
--- a/website/src/_data/site.json
+++ b/website/src/_data/site.json
@@ -2,7 +2,7 @@
"name": "dart_node",
"title": "dart_node - Full-Stack Dart for the JavaScript Ecosystem",
"description": "Write React, React Native, and Express apps entirely in Dart. One language for frontend, backend, and mobile.",
- "url": "https://dartnode.dev",
+ "url": "https://dartnode.org",
"author": "dart_node team",
"language": "en",
"themeColor": "#0E7C6B",
diff --git a/website/src/index.njk b/website/src/index.njk
index 7fd2d1c..5ddf723 100644
--- a/website/src/index.njk
+++ b/website/src/index.njk
@@ -56,18 +56,18 @@ keywords: "dart_node, Dart JavaScript, Dart React, Dart Express, Dart Node.js, T
"description": "The complete dart_node package ecosystem for full-stack Dart development",
"numberOfItems": 12,
"itemListElement": [
- {"@type": "ListItem", "position": 1, "name": "dart_node_core", "description": "Foundation layer with JS interop utilities and Node.js bindings", "url": "https://dartnode.dev/docs/core/"},
- {"@type": "ListItem", "position": 2, "name": "dart_node_express", "description": "Type-safe Express.js bindings for HTTP servers and REST APIs", "url": "https://dartnode.dev/docs/express/"},
- {"@type": "ListItem", "position": 3, "name": "dart_node_react", "description": "React bindings with hooks and JSX-like syntax", "url": "https://dartnode.dev/docs/react/"},
- {"@type": "ListItem", "position": 4, "name": "dart_node_react_native", "description": "React Native + Expo bindings for mobile development", "url": "https://dartnode.dev/docs/react-native/"},
- {"@type": "ListItem", "position": 5, "name": "dart_node_ws", "description": "WebSocket bindings for real-time communication", "url": "https://dartnode.dev/docs/websockets/"},
- {"@type": "ListItem", "position": 6, "name": "dart_node_better_sqlite3", "description": "Synchronous SQLite3 bindings with WAL mode", "url": "https://dartnode.dev/docs/sqlite/"},
- {"@type": "ListItem", "position": 7, "name": "dart_node_mcp", "description": "Model Context Protocol server for AI tools", "url": "https://dartnode.dev/docs/mcp/"},
- {"@type": "ListItem", "position": 8, "name": "reflux", "description": "Redux-style state container with pattern matching", "url": "https://dartnode.dev/docs/reflux/"},
- {"@type": "ListItem", "position": 9, "name": "dart_logging", "description": "Pino-style structured logging", "url": "https://dartnode.dev/docs/logging/"},
- {"@type": "ListItem", "position": 10, "name": "dart_jsx", "description": "JSX transpiler for Dart", "url": "https://dartnode.dev/docs/jsx/"},
- {"@type": "ListItem", "position": 11, "name": "dart_node_vsix", "description": "VSCode extension API bindings for building extensions in Dart", "url": "https://dartnode.dev/docs/vsix/"},
- {"@type": "ListItem", "position": 12, "name": "too-many-cooks", "description": "Multi-agent coordination MCP server", "url": "https://dartnode.dev/docs/too-many-cooks/"}
+ {"@type": "ListItem", "position": 1, "name": "dart_node_core", "description": "Foundation layer with JS interop utilities and Node.js bindings", "url": "https://dartnode.org/docs/core/"},
+ {"@type": "ListItem", "position": 2, "name": "dart_node_express", "description": "Type-safe Express.js bindings for HTTP servers and REST APIs", "url": "https://dartnode.org/docs/express/"},
+ {"@type": "ListItem", "position": 3, "name": "dart_node_react", "description": "React bindings with hooks and JSX-like syntax", "url": "https://dartnode.org/docs/react/"},
+ {"@type": "ListItem", "position": 4, "name": "dart_node_react_native", "description": "React Native + Expo bindings for mobile development", "url": "https://dartnode.org/docs/react-native/"},
+ {"@type": "ListItem", "position": 5, "name": "dart_node_ws", "description": "WebSocket bindings for real-time communication", "url": "https://dartnode.org/docs/websockets/"},
+ {"@type": "ListItem", "position": 6, "name": "dart_node_better_sqlite3", "description": "Synchronous SQLite3 bindings with WAL mode", "url": "https://dartnode.org/docs/sqlite/"},
+ {"@type": "ListItem", "position": 7, "name": "dart_node_mcp", "description": "Model Context Protocol server for AI tools", "url": "https://dartnode.org/docs/mcp/"},
+ {"@type": "ListItem", "position": 8, "name": "reflux", "description": "Redux-style state container with pattern matching", "url": "https://dartnode.org/docs/reflux/"},
+ {"@type": "ListItem", "position": 9, "name": "dart_logging", "description": "Pino-style structured logging", "url": "https://dartnode.org/docs/logging/"},
+ {"@type": "ListItem", "position": 10, "name": "dart_jsx", "description": "JSX transpiler for Dart", "url": "https://dartnode.org/docs/jsx/"},
+ {"@type": "ListItem", "position": 11, "name": "dart_node_vsix", "description": "VSCode extension API bindings for building extensions in Dart", "url": "https://dartnode.org/docs/vsix/"},
+ {"@type": "ListItem", "position": 12, "name": "too-many-cooks", "description": "Multi-agent coordination MCP server", "url": "https://dartnode.org/docs/too-many-cooks/"}
]
}
From 2ed9ef1977dca3d91ee96c5f4c50c5b03c2f1863 Mon Sep 17 00:00:00 2001
From: Christian Findlay <16697547+MelbourneDeveloper@users.noreply.github.com>
Date: Thu, 29 Jan 2026 21:59:26 +1100
Subject: [PATCH 4/4] fixes
---
examples/too_many_cooks/readme.md | 2 +-
website/eleventy.config.js | 4 ++--
website/src/_data/site.json | 2 +-
website/src/_includes/layouts/base.njk | 4 ++--
4 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/examples/too_many_cooks/readme.md b/examples/too_many_cooks/readme.md
index 2bd5c21..5591275 100644
--- a/examples/too_many_cooks/readme.md
+++ b/examples/too_many_cooks/readme.md
@@ -9,7 +9,7 @@ Multi-agent coordination MCP server - enables multiple AI agents to safely edit
- **Messaging**: Inter-agent communication with broadcast support
- **Plan Visibility**: Share goals and current tasks across agents
- **Real-time Status**: System overview of all agents, locks, and plans
-- **Written in Dart**: Made with [dart_node](https://dartnode.dev)
+- **Written in Dart**: Made with [dart_node](https://www.dartnode.org)
## Installation
diff --git a/website/eleventy.config.js b/website/eleventy.config.js
index 7bef6d1..edf96dc 100644
--- a/website/eleventy.config.js
+++ b/website/eleventy.config.js
@@ -22,7 +22,7 @@ const techdocOptions = {
site: {
name: "dart_node",
title: "dart_node - Full-Stack Dart for the JavaScript Ecosystem",
- url: "https://dartnode.dev",
+ url: "https://dartnode.org",
description: "Write React, React Native, and Express apps entirely in Dart. One language for frontend, backend, and mobile.",
author: "dart_node team",
themeColor: "#0E7C6B",
@@ -38,7 +38,7 @@ const techdocOptions = {
sameAs: [
"https://github.com/melbournedeveloper/dart_node",
"https://twitter.com/dart_node",
- "https://pub.dev/publishers/dartnode.dev"
+ "https://pub.dev/publishers/christianfindlay.com/packages"
]
}
},
diff --git a/website/src/_data/site.json b/website/src/_data/site.json
index 392f73f..d4096ed 100644
--- a/website/src/_data/site.json
+++ b/website/src/_data/site.json
@@ -21,7 +21,7 @@
"sameAs": [
"https://github.com/melbournedeveloper/dart_node",
"https://twitter.com/dart_node",
- "https://pub.dev/publishers/dartnode.dev"
+ "https://pub.dev/publishers/christianfindlay.com/packages"
]
}
}
diff --git a/website/src/_includes/layouts/base.njk b/website/src/_includes/layouts/base.njk
index 63542d0..ea09ee8 100644
--- a/website/src/_includes/layouts/base.njk
+++ b/website/src/_includes/layouts/base.njk
@@ -81,8 +81,8 @@
"description": "{{ site.description }}",
"sameAs": [
"{{ site.github }}",
- "https://twitter.com/dart_node",
- "https://pub.dev/publishers/dartnode.dev"
+ "https://x.com/cfdevelop",
+ "https://pub.dev/publishers/christianfindlay.com/packages"
]
}