Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions website/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -141,5 +141,8 @@ vite.config.ts.timestamp-*
# Astro
.astro

# Cloudflare Wrangler
.wrangler

# Mac OS
.DS_Store
3 changes: 3 additions & 0 deletions website/astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import mdx from "@astrojs/mdx";
import react from "@astrojs/react";
import rehypeExternalLinks from "./src/utils/rehype-external-links.ts";
import playformCompress from "@playform/compress";
import markdownForAgents from "astro-markdown-for-agents";
import { markdownForAgentsOptions } from "./markdown-for-agents.config.mjs";

const SITE_BASE_URL = process.env.SITE_BASE_URL || "https://www.quantus.com";
const DEFAULT_LOCALE = "en-US";
Expand Down Expand Up @@ -99,5 +101,6 @@ export default defineConfig({
mdx(),
react(),
playformCompress(),
markdownForAgents(markdownForAgentsOptions),
],
});
7 changes: 7 additions & 0 deletions website/bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

68 changes: 68 additions & 0 deletions website/functions/_middleware.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import {
applyMarkdownHeaders,
ensureVaryAccept,
markdownAssetPath,
prefersMarkdown,
} from "astro-markdown-for-agents/runtime";
import {
MARKDOWN_NEGOTIATION_BYPASS_HEADER,
isNegotiablePath,
resolvedMarkdownOptions,
} from "../markdown-for-agents.config.mjs";

/**
* Serve pre-built markdown from dist/_markdown-cache when clients negotiate
* Accept: text/markdown. HTML remains the default for browsers.
*/
export async function onRequest(context) {
const { request, env } = context;
const method = request.method.toUpperCase();

if (method !== "GET" && method !== "HEAD") {
return context.next();
}

if (request.headers.get(MARKDOWN_NEGOTIATION_BYPASS_HEADER) === "1") {
return context.next();
}

const accept = request.headers.get("Accept") ?? "";
if (!prefersMarkdown(accept, resolvedMarkdownOptions.preferPlainText)) {
return context.next();
}

const pathname = new URL(request.url).pathname;
if (!isNegotiablePath(pathname, resolvedMarkdownOptions)) {
return context.next();
}

const mdPath = markdownAssetPath(
pathname,
resolvedMarkdownOptions.markdownDir,
);
const mdRequest = new Request(new URL(mdPath, request.url), {
method,
headers: {
[MARKDOWN_NEGOTIATION_BYPASS_HEADER]: "1",
},
});

const mdResponse = env.ASSETS
? await env.ASSETS.fetch(mdRequest)
: await fetch(mdRequest);

if (!mdResponse.ok) {
return context.next();
}

const markdown = await mdResponse.text();
const headers = new Headers(mdResponse.headers);
applyMarkdownHeaders(headers, markdown, resolvedMarkdownOptions);
ensureVaryAccept(headers);

if (method === "HEAD") {
return new Response(null, { status: mdResponse.status, headers });
}

return new Response(markdown, { status: mdResponse.status, headers });
}
93 changes: 93 additions & 0 deletions website/markdown-for-agents.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
/** @type {import('astro-markdown-for-agents').MarkdownForAgentsOptions} */
export const markdownForAgentsOptions = {
excludePrefixes: ["/api/", "/_astro/", "/.well-known/", "/_markdown-cache/"],
contentSignals: {
aiTrain: true,
search: true,
aiInput: true,
},
};

/** Resolved options for edge middleware (runtime-safe, no Node imports). */
export const resolvedMarkdownOptions = {
include: [],
exclude: [],
excludePrefixes: markdownForAgentsOptions.excludePrefixes ?? [],
excludeExtensions: [
".css",
".js",
".mjs",
".map",
".json",
".xml",
".txt",
".ico",
".png",
".jpg",
".jpeg",
".webp",
".svg",
".gif",
".pdf",
".zip",
".woff",
".woff2",
],
markdownDir: markdownForAgentsOptions.markdownDir ?? "_markdown-cache",
contentSignalHeader: "ai-train=yes, search=yes, ai-input=yes",
maxExtractedChars: Infinity,
preferPlainText: markdownForAgentsOptions.preferPlainText ?? true,
};

export const MARKDOWN_NEGOTIATION_BYPASS_HEADER =
"x-markdown-negotiation-bypass";

function extensionOf(value) {
const dotIndex = value.lastIndexOf(".");
if (dotIndex === -1) {
return "";
}
return value.slice(dotIndex).toLowerCase();
}

function matches(pathname, matcher) {
if (typeof matcher === "function") {
return matcher(pathname);
}
if (matcher instanceof RegExp) {
return matcher.test(pathname);
}
if (!matcher.includes("*")) {
return pathname === matcher;
}
const regex = new RegExp(
`^${matcher.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*")}$`,
);
return regex.test(pathname);
}

function matchesAny(pathname, matchers) {
return matchers.some((matcher) => matches(pathname, matcher));
}

/** Edge-safe mirror of astro-markdown-for-agents route matching. */
export function isNegotiablePath(pathname, options) {
if (!pathname) {
return false;
}
if (matchesAny(pathname, options.exclude)) {
return false;
}
if (options.include.length > 0 && !matchesAny(pathname, options.include)) {
return false;
}
if (options.excludePrefixes.some((prefix) => pathname.startsWith(prefix))) {
return false;
}
const lastSegment = pathname.split("/").pop() ?? "";
const ext = extensionOf(lastSegment);
if (ext && options.excludeExtensions.includes(ext)) {
return false;
}
return !lastSegment.includes(".") || ext === "";
}
1 change: 1 addition & 0 deletions website/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
"@radix-ui/react-slot": "^1.2.3",
"@tanstack/react-table": "^8.21.3",
"astro": "6.0.7",
"astro-markdown-for-agents": "^0.1.1",
"astro-seo": "^0.8.4",
"chart.js": "^4.5.1",
"chartjs-plugin-datalabels": "^2.2.0",
Expand Down
67 changes: 67 additions & 0 deletions website/public/.well-known/api-catalog
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
{
"linkset": [
{
"anchor": "https://api.quantus.com/api",
"service-desc": [
{
"href": "https://www.quantus.com/.well-known/openapi/website-api.json",
"type": "application/json"
}
],
"service-doc": [
{
"href": "https://docs.quantus.com/",
"type": "text/html"
}
],
"status": [
{
"href": "https://api.quantus.com/",
"type": "text/plain"
}
]
},
{
"anchor": "https://quests.quantus.com/api",
"service-desc": [
{
"href": "https://www.quantus.com/.well-known/openapi/quests-api.json",
"type": "application/json"
}
],
"service-doc": [
{
"href": "https://docs.quantus.com/",
"type": "text/html"
}
],
"status": [
{
"href": "https://quests.quantus.com/health",
"type": "application/json"
}
]
},
{
"anchor": "https://sub2.quantus.com/v1/graphql",
"service-desc": [
{
"href": "https://www.quantus.com/.well-known/openapi/indexer-api.json",
"type": "application/json"
}
],
"service-doc": [
{
"href": "https://docs.quantus.com/",
"type": "text/html"
}
],
"status": [
{
"href": "https://sub2.quantus.com/health",
"type": "application/json"
}
]
}
]
}
58 changes: 58 additions & 0 deletions website/public/.well-known/openapi/indexer-api.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{
"openapi": "3.1.0",
"info": {
"title": "Quantus Indexer GraphQL API",
"version": "1.0.0",
"description": "GraphQL indexer for Quantus chain statistics and on-chain data."
},
"servers": [{ "url": "https://sub2.quantus.com" }],
"paths": {
"/health": {
"get": {
"summary": "Service health",
"operationId": "getHealth",
"responses": {
"200": {
"description": "Indexer is healthy",
"content": {
"application/json": {
"schema": {
"type": "object",
"additionalProperties": true
}
}
}
}
}
}
},
"/v1/graphql": {
"post": {
"summary": "GraphQL query endpoint",
"operationId": "graphqlQuery",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"type": "object",
"required": ["query"],
"properties": {
"query": { "type": "string" },
"variables": {
"type": "object",
"additionalProperties": true
},
"operationName": { "type": "string" }
}
}
}
}
},
"responses": {
"200": { "description": "GraphQL response" }
}
}
}
}
}
Loading
Loading