diff --git a/README.md b/README.md
index a85136b..5a55be1 100644
--- a/README.md
+++ b/README.md
@@ -49,7 +49,7 @@ Register the repository in `content-sources.yaml`:
sources:
- owner: thiagogcm
repo: adf4j
- slug: adf4j-docs
+ slug: adf4j
order: 0
```
@@ -74,11 +74,11 @@ During sync, the site validates frontmatter and page order, removes source-owned
Cloudflare Workers is both the request entrypoint and the runtime for the few features that need server-side behavior:
-| Runtime path | Cloudflare responsibility | Result |
-| --- | --- | --- |
-| Normal page request | Serve the built site and run server-rendered fragments | Most content remains pre-rendered; dynamic work stays isolated. |
-| Scheduled event | Query GitHub every six hours and write the aggregate to KV | Page requests read cached activity data instead of calling GitHub. |
-| Cold stats cache | Start a background refresh with the request context | The response can show a fallback without waiting on GitHub. |
+| Runtime path | Cloudflare responsibility | Result |
+| -------------------------- | ------------------------------------------------------------- | ------------------------------------------------------------------------------------------- |
+| Normal page request | Serve the built site and run server-rendered fragments | Most content remains pre-rendered; dynamic work stays isolated. |
+| Scheduled event | Query GitHub every six hours and write the aggregate to KV | Page requests read cached activity data instead of calling GitHub. |
+| Cold stats cache | Start a background refresh with the request context | The response can show a fallback without waiting on GitHub. |
| `/api/confluence-adf.json` | Validate a public Confluence Cloud URL and fetch its ADF body | The browser receives a narrow JSON response, then performs the Markdown conversion locally. |
The Worker delegates regular requests to the site runtime. Its scheduled handler refreshes GitHub statistics. The status island reads those statistics from the `GITHUB_STATS` KV namespace, while the Confluence route accepts only HTTPS `*.atlassian.net` wiki page URLs containing a numeric page ID.
@@ -87,14 +87,14 @@ This boundary is intentional: content assembly belongs to the build, presentatio
## Working locally
-| Command | Purpose |
-| --- | --- |
-| `npm run dev` | Sync external content, then start the development server. |
-| `npm run sync:content` | Rebuild generated content from registered sources. |
-| `npm run validate:sources` | Validate sources without writing generated output. |
-| `npm run test:content-sync` | Test content normalization and link rewriting. |
-| `npm run check` | Type-check the site and Worker integration. |
-| `npm run build` | Sync content and produce the deployment build. |
+| Command | Purpose |
+| --------------------------- | --------------------------------------------------------- |
+| `npm run dev` | Sync external content, then start the development server. |
+| `npm run sync:content` | Rebuild generated content from registered sources. |
+| `npm run validate:sources` | Validate sources without writing generated output. |
+| `npm run test:content-sync` | Test content normalization and link rewriting. |
+| `npm run check` | Type-check the site and Worker integration. |
+| `npm run build` | Sync content and produce the deployment build. |
## Deployment
diff --git a/astro.config.mjs b/astro.config.mjs
index c0c88c5..fe74856 100644
--- a/astro.config.mjs
+++ b/astro.config.mjs
@@ -1,11 +1,11 @@
-import { defineConfig, fontProviders } from 'astro/config';
-import cloudflare from '@astrojs/cloudflare';
-import { unified } from '@astrojs/markdown-remark';
-import adf4jWasm from '@nthings.dev/adf4j-wasm/vite';
-import tailwindcss from '@tailwindcss/vite';
+import cloudflare from "@astrojs/cloudflare";
+import { unified } from "@astrojs/markdown-remark";
+import adf4jWasm from "@nthings.dev/adf4j-wasm/vite";
+import tailwindcss from "@tailwindcss/vite";
+import { defineConfig, fontProviders } from "astro/config";
export default defineConfig({
- site: 'https://nthings.dev',
+ site: "https://nthings.dev",
adapter: cloudflare({
platformProxy: { enabled: true },
}),
@@ -13,40 +13,40 @@ export default defineConfig({
plugins: [tailwindcss(), adf4jWasm()],
},
markdown: {
- syntaxHighlight: 'shiki',
+ syntaxHighlight: "shiki",
// Dual themes: light colors inline, dark swapped via --shiki-dark in global.css.
shikiConfig: {
themes: {
- light: 'github-light',
- dark: 'github-dark',
+ light: "github-light",
+ dark: "github-dark",
},
},
processor: unified({
smartypants: {
- dashes: 'oldschool',
+ dashes: "oldschool",
},
}),
},
prefetch: {
prefetchAll: true,
- defaultStrategy: 'hover',
+ defaultStrategy: "hover",
},
fonts: [
{
provider: fontProviders.google(),
- name: 'Inter',
- cssVariable: '--font-body',
+ name: "Inter",
+ cssVariable: "--font-body",
weights: [400, 500, 600, 700],
- subsets: ['latin'],
- fallbacks: ['system-ui', '-apple-system', 'sans-serif'],
+ subsets: ["latin"],
+ fallbacks: ["system-ui", "-apple-system", "sans-serif"],
},
{
provider: fontProviders.google(),
- name: 'JetBrains Mono',
- cssVariable: '--font-code',
+ name: "JetBrains Mono",
+ cssVariable: "--font-code",
weights: [400, 500],
- subsets: ['latin'],
- fallbacks: ['ui-monospace', 'monospace'],
+ subsets: ["latin"],
+ fallbacks: ["ui-monospace", "monospace"],
},
],
});
diff --git a/biome.json b/biome.json
new file mode 100644
index 0000000..093aeb9
--- /dev/null
+++ b/biome.json
@@ -0,0 +1,64 @@
+{
+ "$schema": "https://biomejs.dev/schemas/2.5.0/schema.json",
+ "vcs": {
+ "enabled": true,
+ "clientKind": "git",
+ "useIgnoreFile": true
+ },
+ "files": {
+ "ignoreUnknown": true,
+ "includes": [
+ "src/**",
+ "!src/**/*.css",
+ "astro.config.mjs",
+ "tsconfig.json",
+ "package.json"
+ ]
+ },
+ "formatter": {
+ "enabled": true,
+ "indentStyle": "space",
+ "indentWidth": 2,
+ "lineWidth": 80,
+ "lineEnding": "lf"
+ },
+ "linter": {
+ "enabled": true,
+ "rules": {
+ "preset": "recommended",
+ "style": {
+ "noNonNullAssertion": "off"
+ }
+ }
+ },
+ "javascript": {
+ "formatter": {
+ "quoteStyle": "double",
+ "semicolons": "always"
+ }
+ },
+ "assist": {
+ "enabled": true,
+ "actions": {
+ "source": {
+ "organizeImports": "on"
+ }
+ }
+ },
+ "overrides": [
+ {
+ "includes": [
+ "**/*.astro"
+ ],
+ "linter": {
+ "rules": {
+ "correctness": {
+ "noUnusedVariables": "off",
+ "noUnusedImports": "off",
+ "noUnusedFunctionParameters": "off"
+ }
+ }
+ }
+ }
+ ]
+}
diff --git a/content-sources.yaml b/content-sources.yaml
index 00fad30..cbd1c35 100644
--- a/content-sources.yaml
+++ b/content-sources.yaml
@@ -14,4 +14,3 @@ sources:
- owner: thiagogcm
repo: helm4j
order: 2
-
diff --git a/package-lock.json b/package-lock.json
index 143ad69..f3f8bcb 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11,10 +11,10 @@
"@astrojs/cloudflare": "13.7.0",
"@nthings.dev/adf4j-wasm": "1.0.2",
"astro": "6.4.8",
- "chart.js": "^4.5.1",
+ "chart.js": "4.5.1",
"dompurify": "3.4.11",
"markdown-it": "14.2.0",
- "markdown-it-github-alerts": "^1.0.1",
+ "markdown-it-github-alerts": "1.0.1",
"mermaid": "11.15.0",
"prismjs": "1.30.0",
"wrangler": "4.103.0"
@@ -22,8 +22,10 @@
"devDependencies": {
"@astrojs/check": "0.9.9",
"@astrojs/markdown-remark": "7.2.0",
+ "@biomejs/biome": "2.5.0",
"@tailwindcss/vite": "4.3.1",
- "@types/markdown-it": "^14.1.2",
+ "@types/markdown-it": "14.1.2",
+ "@types/node": "24.13.0",
"@types/prismjs": "1.26.6",
"degit": "3.4.7",
"tailwindcss": "4.3.1",
@@ -294,6 +296,181 @@
"node": ">=6.9.0"
}
},
+ "node_modules/@biomejs/biome": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/@biomejs/biome/-/biome-2.5.0.tgz",
+ "integrity": "sha512-4kURkd9hAPrdDM3C9n82ycYgx8hvQcW6MjKTEejruj8rK0N8P3OPpdy8BvI8kt3KWY4ycF5XtDOrktetEfhfuw==",
+ "dev": true,
+ "license": "MIT OR Apache-2.0",
+ "bin": {
+ "biome": "bin/biome"
+ },
+ "engines": {
+ "node": ">=14.21.3"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/biome"
+ },
+ "optionalDependencies": {
+ "@biomejs/cli-darwin-arm64": "2.5.0",
+ "@biomejs/cli-darwin-x64": "2.5.0",
+ "@biomejs/cli-linux-arm64": "2.5.0",
+ "@biomejs/cli-linux-arm64-musl": "2.5.0",
+ "@biomejs/cli-linux-x64": "2.5.0",
+ "@biomejs/cli-linux-x64-musl": "2.5.0",
+ "@biomejs/cli-win32-arm64": "2.5.0",
+ "@biomejs/cli-win32-x64": "2.5.0"
+ }
+ },
+ "node_modules/@biomejs/cli-darwin-arm64": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-arm64/-/cli-darwin-arm64-2.5.0.tgz",
+ "integrity": "sha512-Mn3Fwi3SA5fgmfCPqmzpWF2DLZnms3BVAhM088nTnGrTZmHS3wwIjcoZPqpXeNgd3DrrLH6xp8vTLIBuJoZiXw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT OR Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=14.21.3"
+ }
+ },
+ "node_modules/@biomejs/cli-darwin-x64": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-darwin-x64/-/cli-darwin-x64-2.5.0.tgz",
+ "integrity": "sha512-rg3VPL5P8mYro6pqlXYXuJWph21slVp3SZtAqWSrkZs40d2gTzYmHF8E/X1iTID25btmNKltNDJ926sqVBp7DQ==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT OR Apache-2.0",
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": ">=14.21.3"
+ }
+ },
+ "node_modules/@biomejs/cli-linux-arm64": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64/-/cli-linux-arm64-2.5.0.tgz",
+ "integrity": "sha512-tl+LW8fdD96/xdeWtWwc82LIOc5CoY7N2AsogLTp5R4ECErYt+8Jl/N68ezN9vzSiqPTxw6vjcihoLPYKZHrlw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "MIT OR Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=14.21.3"
+ }
+ },
+ "node_modules/@biomejs/cli-linux-arm64-musl": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-arm64-musl/-/cli-linux-arm64-musl-2.5.0.tgz",
+ "integrity": "sha512-vQdM4oSGaf7ZNeGO9w5+Y8SBtyser9M6znxYbm7Ec8wInxJu1WiKxFYZW5Auj2d80bcVvefuGGRxoFOE0eee8g==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "libc": [
+ "musl"
+ ],
+ "license": "MIT OR Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=14.21.3"
+ }
+ },
+ "node_modules/@biomejs/cli-linux-x64": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64/-/cli-linux-x64-2.5.0.tgz",
+ "integrity": "sha512-zpEGf4RQbFEh8Vt7OmavLyyOzRbtcE9osCqrS1kfvt8jDvxwhKXLSf7n0ebr/ov0RJ9ssP+lhs6C8a9WwFvrQA==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "libc": [
+ "glibc"
+ ],
+ "license": "MIT OR Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=14.21.3"
+ }
+ },
+ "node_modules/@biomejs/cli-linux-x64-musl": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-linux-x64-musl/-/cli-linux-x64-musl-2.5.0.tgz",
+ "integrity": "sha512-+9hIcMngJ+yGUahXqZuZ8CoWKJE9SAZsFsM3QDvXpNsLbXZ9lqVzgBhOk/jTSYkOA0GLP9eu3teukqpLUojHMg==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "libc": [
+ "musl"
+ ],
+ "license": "MIT OR Apache-2.0",
+ "optional": true,
+ "os": [
+ "linux"
+ ],
+ "engines": {
+ "node": ">=14.21.3"
+ }
+ },
+ "node_modules/@biomejs/cli-win32-arm64": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-arm64/-/cli-win32-arm64-2.5.0.tgz",
+ "integrity": "sha512-jB0wAvTLI4itx5VidqVUejPQFhRUxiZ9l9FvZ26D5fl6t3qme+ZB4PD3bTSeL1vZ8NI2Rx/zj6H9zcESuGHKGw==",
+ "cpu": [
+ "arm64"
+ ],
+ "dev": true,
+ "license": "MIT OR Apache-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=14.21.3"
+ }
+ },
+ "node_modules/@biomejs/cli-win32-x64": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/@biomejs/cli-win32-x64/-/cli-win32-x64-2.5.0.tgz",
+ "integrity": "sha512-VT/lF+GId+67j8aDfLkxdxNoVApsPSTbyAtB3jJq0IWTrY77WXfbPfpngxq0bA6JCEv/7k8C9qWjDRKRznDlyw==",
+ "cpu": [
+ "x64"
+ ],
+ "dev": true,
+ "license": "MIT OR Apache-2.0",
+ "optional": true,
+ "os": [
+ "win32"
+ ],
+ "engines": {
+ "node": ">=14.21.3"
+ }
+ },
"node_modules/@braintree/sanitize-url": {
"version": "7.1.2",
"resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-7.1.2.tgz",
@@ -3234,6 +3411,16 @@
"@types/unist": "*"
}
},
+ "node_modules/@types/node": {
+ "version": "24.13.0",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.0.tgz",
+ "integrity": "sha512-5vtOqGQr4NJKeEzV441FcOi2MeG9UTWq9LqVLGneDdu4vlX17H8kQ2PA2UmNwCUGPVDj4oBjNhS7ReVEIWJJrg==",
+ "devOptional": true,
+ "license": "MIT",
+ "dependencies": {
+ "undici-types": "~7.18.0"
+ }
+ },
"node_modules/@types/prismjs": {
"version": "1.26.6",
"resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.6.tgz",
@@ -7690,6 +7877,13 @@
"node": ">=20.18.1"
}
},
+ "node_modules/undici-types": {
+ "version": "7.18.2",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz",
+ "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==",
+ "devOptional": true,
+ "license": "MIT"
+ },
"node_modules/unenv": {
"version": "2.0.0-rc.24",
"resolved": "https://registry.npmjs.org/unenv/-/unenv-2.0.0-rc.24.tgz",
diff --git a/package.json b/package.json
index 5a92f53..4754013 100644
--- a/package.json
+++ b/package.json
@@ -8,6 +8,8 @@
"scripts": {
"dev": "astro dev",
"check": "astro check",
+ "lint": "biome check .",
+ "format": "biome format --write .",
"sync:content": "node scripts/sync-content-sources.mjs",
"validate:sources": "node scripts/sync-content-sources.mjs --validate-only",
"test:content-sync": "node --test \"scripts/content-sources/**/*.test.mjs\"",
@@ -22,10 +24,10 @@
"@astrojs/cloudflare": "13.7.0",
"@nthings.dev/adf4j-wasm": "1.0.2",
"astro": "6.4.8",
- "chart.js": "^4.5.1",
+ "chart.js": "4.5.1",
"dompurify": "3.4.11",
"markdown-it": "14.2.0",
- "markdown-it-github-alerts": "^1.0.1",
+ "markdown-it-github-alerts": "1.0.1",
"mermaid": "11.15.0",
"prismjs": "1.30.0",
"wrangler": "4.103.0"
@@ -33,8 +35,10 @@
"devDependencies": {
"@astrojs/check": "0.9.9",
"@astrojs/markdown-remark": "7.2.0",
+ "@biomejs/biome": "2.5.0",
"@tailwindcss/vite": "4.3.1",
- "@types/markdown-it": "^14.1.2",
+ "@types/markdown-it": "14.1.2",
+ "@types/node": "24.13.0",
"@types/prismjs": "1.26.6",
"degit": "3.4.7",
"tailwindcss": "4.3.1",
diff --git a/src/components/Adf4jDemo.astro b/src/components/Adf4jDemo.astro
index 63ea794..a5f9182 100644
--- a/src/components/Adf4jDemo.astro
+++ b/src/components/Adf4jDemo.astro
@@ -111,5 +111,5 @@ const EXAMPLE_URL =
diff --git a/src/components/DirectoryEntry.astro b/src/components/DirectoryEntry.astro
index 98cbf6d..752fa36 100644
--- a/src/components/DirectoryEntry.astro
+++ b/src/components/DirectoryEntry.astro
@@ -1,6 +1,6 @@
---
-import Icon from "./Icon.astro";
-import type { EntryAction } from "../lib/project-actions";
+import Icon from "@/components/Icon.astro";
+import type { EntryAction } from "@/lib/project-actions";
interface Props {
title: string;
diff --git a/src/components/Footer.astro b/src/components/Footer.astro
index a738faf..8837cf1 100644
--- a/src/components/Footer.astro
+++ b/src/components/Footer.astro
@@ -1,7 +1,7 @@
---
-import Icon from "./Icon.astro";
-import Logo from "./Logo.astro";
-import { SITE, SOCIAL_LINKS } from "../consts";
+import Icon from "@/components/Icon.astro";
+import Logo from "@/components/Logo.astro";
+import { SITE, SOCIAL_LINKS } from "@/consts";
const year = new Date().getFullYear();
---
diff --git a/src/components/Header.astro b/src/components/Header.astro
index 5180738..f779e01 100644
--- a/src/components/Header.astro
+++ b/src/components/Header.astro
@@ -1,9 +1,9 @@
---
-import Icon from "./Icon.astro";
-import Logo from "./Logo.astro";
-import Tabs from "./Tabs.astro";
-import ThemeToggle from "./ThemeToggle.astro";
-import { SOCIAL_LINKS } from "../consts";
+import Icon from "@/components/Icon.astro";
+import Logo from "@/components/Logo.astro";
+import Tabs from "@/components/Tabs.astro";
+import ThemeToggle from "@/components/ThemeToggle.astro";
+import { SOCIAL_LINKS } from "@/consts";
---