mirror of
https://github.com/absmach/supermq.git
synced 2026-06-23 06:20:18 +00:00
+1
-1
@@ -41,7 +41,7 @@ pnpm preview
|
||||
|
||||
- `src/pages/index.astro`: product landing page
|
||||
- `src/components/home/*.astro`: landing page components (Astro-only, no React)
|
||||
- `src/content/docs/docs/*`: docs content shown under `/docs/*`
|
||||
- `src/content/docs/*`: docs content shown under `/docs/*`
|
||||
- `src/styles/global.css`: Tailwind entry and shared brand/component styles
|
||||
- `src/styles/starlight.css`: docs-theme overrides for Starlight
|
||||
- `astro.config.mjs`: Astro, Tailwind, Starlight, and sitemap config
|
||||
|
||||
Generated
+1275
-5
File diff suppressed because it is too large
Load Diff
@@ -12,12 +12,16 @@
|
||||
"dependencies": {
|
||||
"@astrojs/mdx": "^4.3.13",
|
||||
"@astrojs/react": "^4.4.2",
|
||||
"@orama/orama": "^3.1.18",
|
||||
"@astrojs/sitemap": "^3.0.0",
|
||||
"@orama/orama": "^3.1.18",
|
||||
"@tailwindcss/vite": "^4.1.18",
|
||||
"@tisoap/react-flow-smart-edge": "^4.0.1",
|
||||
"@xyflow/react": "^12.10.0",
|
||||
"astro": "^5.5.0",
|
||||
"fumadocs-core": "^16.5.0",
|
||||
"fumadocs-ui": "^16.5.0",
|
||||
"lucide-react": "^0.563.0",
|
||||
"mermaid": "^11.12.2",
|
||||
"react": "^19.2.0",
|
||||
"react-dom": "^19.2.0",
|
||||
"tailwindcss": "^4.1.18"
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { DocsLayout } from 'fumadocs-ui/layouts/docs';
|
||||
import { DocsPage, type DocsPageProps } from 'fumadocs-ui/layouts/docs/page';
|
||||
import { DocsBody, DocsDescription, DocsPage, type DocsPageProps, DocsTitle } from 'fumadocs-ui/layouts/docs/page';
|
||||
import type { Root } from 'fumadocs-core/page-tree';
|
||||
import type { ReactNode } from 'react';
|
||||
import { FrameworkProvider } from 'fumadocs-core/framework';
|
||||
@@ -13,12 +13,16 @@ export function Docs({
|
||||
pathname,
|
||||
params,
|
||||
page,
|
||||
title,
|
||||
description,
|
||||
}: {
|
||||
tree: Root;
|
||||
children: ReactNode;
|
||||
pathname: string;
|
||||
params: Record<string, string | string[]>;
|
||||
page?: DocsPageProps;
|
||||
title: string;
|
||||
description?: string;
|
||||
}) {
|
||||
return (
|
||||
<FrameworkProvider
|
||||
@@ -38,7 +42,7 @@ export function Docs({
|
||||
tree={tree}
|
||||
nav={{
|
||||
title: (
|
||||
<span style={{ fontWeight: 800, lineHeight: 1.1, fontSize: '1.9rem' }}>
|
||||
<span style={{ fontWeight: 800, lineHeight: 1.1, fontSize: '1.5rem' }}>
|
||||
<span style={{ color: 'var(--flux-blue)' }}>Flux</span>
|
||||
<span style={{ color: 'var(--flux-orange)' }}>MQ</span>
|
||||
</span>
|
||||
@@ -60,7 +64,11 @@ export function Docs({
|
||||
},
|
||||
]}
|
||||
>
|
||||
<DocsPage {...page}>{children}</DocsPage>
|
||||
<DocsPage {...page}>
|
||||
<DocsTitle>{title}</DocsTitle>
|
||||
{description ? <DocsDescription>{description}</DocsDescription> : null}
|
||||
<DocsBody>{children}</DocsBody>
|
||||
</DocsPage>
|
||||
</DocsLayout>
|
||||
</RootProvider>
|
||||
</FrameworkProvider>
|
||||
|
||||
@@ -1,48 +1,65 @@
|
||||
<section id="architecture" class="border-b-2 border-theme bg-theme-alt py-20">
|
||||
<div class="mx-auto w-[min(100%-2.5rem,1200px)]">
|
||||
<h2 class="mb-12 text-4xl font-bold md:text-5xl">
|
||||
<span class="border-l-4 border-[var(--flux-orange)] pl-4">ARCHITECTURE</span>
|
||||
---
|
||||
import { MermaidDiagram } from "./MermaidDiagram";
|
||||
|
||||
const architectureDiagram = `
|
||||
graph TD
|
||||
A[Setup and configuration] --> B[MQTT/WS/HTTP/CoAP<br/>Servers]
|
||||
A --> C[AMQP 1.0<br/>Server]
|
||||
A --> D[AMQP 0.9.1<br/>Server]
|
||||
B --> E[MQTT v3.1.1/v5 Broker]
|
||||
C --> F[AMQP Broker<br/> 1.0]
|
||||
D --> G[AMQP Broker<br/>0.9.1]
|
||||
E --> H[Queue Manager<br/>Bindings + Delivery]
|
||||
F --> H
|
||||
G --> H
|
||||
H --> I[Log Storage<br/>+ Topic Index]
|
||||
|
||||
style A fill:#2F69B3,stroke:#000000,stroke-width:2px,color:#ffffff
|
||||
style H fill:#F9A32A,stroke:#000000,stroke-width:2px,color:#000000
|
||||
style I fill:#2F69B3,stroke:#000000,stroke-width:2px,color:#ffffff
|
||||
`;
|
||||
---
|
||||
|
||||
<section id="architecture" class="py-20 border-b-2 border-theme bg-theme-alt">
|
||||
<div class="container mx-auto px-6">
|
||||
<h2 class="text-4xl md:text-5xl font-bold mb-12">
|
||||
<span class="border-l-4 border-(--flux-orange) pl-4">ARCHITECTURE</span>
|
||||
</h2>
|
||||
|
||||
<div class="mx-auto max-w-4xl">
|
||||
<div class="brutalist-border bg-theme overflow-x-auto p-6">
|
||||
<svg viewBox="0 0 880 370" class="min-w-[760px]" role="img" aria-label="FluxMQ architecture diagram">
|
||||
<g font-family="JetBrains Mono, ui-monospace, monospace" font-size="13" font-weight="700">
|
||||
<rect x="335" y="20" width="210" height="48" rx="8" fill="#2f69b3" stroke="#1f1f1f" stroke-width="2"></rect>
|
||||
<text x="440" y="49" text-anchor="middle" fill="#fff">Setup and configuration</text>
|
||||
|
||||
<rect x="70" y="110" width="220" height="52" rx="8" fill="#fafafa" stroke="#1f1f1f" stroke-width="2"></rect>
|
||||
<rect x="330" y="110" width="220" height="52" rx="8" fill="#fafafa" stroke="#1f1f1f" stroke-width="2"></rect>
|
||||
<rect x="590" y="110" width="220" height="52" rx="8" fill="#fafafa" stroke="#1f1f1f" stroke-width="2"></rect>
|
||||
<text x="180" y="142" text-anchor="middle" fill="#101010">TCP/WS/HTTP/CoAP Servers</text>
|
||||
<text x="440" y="142" text-anchor="middle" fill="#101010">AMQP 1.0 Server</text>
|
||||
<text x="700" y="142" text-anchor="middle" fill="#101010">AMQP 0.9.1 Server</text>
|
||||
|
||||
<rect x="70" y="200" width="220" height="52" rx="8" fill="#fafafa" stroke="#1f1f1f" stroke-width="2"></rect>
|
||||
<rect x="330" y="200" width="220" height="52" rx="8" fill="#fafafa" stroke="#1f1f1f" stroke-width="2"></rect>
|
||||
<rect x="590" y="200" width="220" height="52" rx="8" fill="#fafafa" stroke="#1f1f1f" stroke-width="2"></rect>
|
||||
<text x="180" y="232" text-anchor="middle" fill="#101010">MQTT Broker</text>
|
||||
<text x="440" y="232" text-anchor="middle" fill="#101010">AMQP Broker 1.0</text>
|
||||
<text x="700" y="232" text-anchor="middle" fill="#101010">AMQP Broker 0.9.1</text>
|
||||
|
||||
<rect x="315" y="290" width="250" height="52" rx="8" fill="#f9a32a" stroke="#1f1f1f" stroke-width="2"></rect>
|
||||
<text x="440" y="322" text-anchor="middle" fill="#101010">Queue Manager (Bindings + Delivery)</text>
|
||||
|
||||
<path d="M440 70 L440 104" stroke="#2f69b3" stroke-width="2"></path>
|
||||
<path d="M180 162 L180 194M440 162 L440 194M700 162 L700 194" stroke="#2f69b3" stroke-width="2"></path>
|
||||
<path d="M180 252 L180 280 L315 280M440 252 L440 290M700 252 L700 280 L565 280" stroke="#2f69b3" stroke-width="2"></path>
|
||||
</g>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="max-w-4xl mx-auto">
|
||||
<MermaidDiagram chart={architectureDiagram} client:load />
|
||||
</div>
|
||||
|
||||
<div class="brutalist-border bg-theme mx-auto mt-12 max-w-3xl p-6">
|
||||
<h3 class="mono mb-4 text-lg font-bold">KEY COMPONENTS</h3>
|
||||
<ul class="space-y-3 text-base text-theme-muted">
|
||||
<li class="flex items-start"><span class="mr-2 font-bold text-[var(--flux-blue)]">▸</span><span><strong>Transport Layer:</strong> Multi-protocol servers (MQTT, AMQP 1.0, AMQP 0.9.1, CoAP, HTTP, WebSocket)</span></li>
|
||||
<li class="flex items-start"><span class="mr-2 font-bold text-[var(--flux-blue)]">▸</span><span><strong>Protocol Brokers:</strong> FSM-based protocol handlers with zero-copy parsing</span></li>
|
||||
<li class="flex items-start"><span class="mr-2 font-bold text-[var(--flux-blue)]">▸</span><span><strong>Queue Manager:</strong> Durable queue bindings with FIFO, priority, and topic-based delivery</span></li>
|
||||
<li class="flex items-start"><span class="mr-2 font-bold text-[var(--flux-blue)]">▸</span><span><strong>Storage:</strong> Persistence for messages and topic indexing</span></li>
|
||||
<div class="mt-12 max-w-3xl mx-auto brutalist-border bg-theme p-6">
|
||||
<h3 class="font-bold mono text-lg mb-4">KEY COMPONENTS</h3>
|
||||
<ul class="space-y-3 text-theme-muted text-base">
|
||||
<li class="flex items-start">
|
||||
<span class="text-(--flux-blue) mr-2 font-bold">▸</span>
|
||||
<span>
|
||||
<strong>Transport Layer:</strong> Multi-protocol servers (MQTT, AMQP 1.0,
|
||||
AMQP 0.9.1, CoAP, HTTP, WebSocket)
|
||||
</span>
|
||||
</li>
|
||||
<li class="flex items-start">
|
||||
<span class="text-(--flux-blue) mr-2 font-bold">▸</span>
|
||||
<span>
|
||||
<strong>Protocol Brokers:</strong> FSM-based protocol handlers with zero-copy
|
||||
parsing
|
||||
</span>
|
||||
</li>
|
||||
<li class="flex items-start">
|
||||
<span class="text-(--flux-blue) mr-2 font-bold">▸</span>
|
||||
<span>
|
||||
<strong>Queue Manager:</strong> Durable queue bindings with FIFO, priority,
|
||||
and topic-based delivery
|
||||
</span>
|
||||
</li>
|
||||
<li class="flex items-start">
|
||||
<span class="text-(--flux-blue) mr-2 font-bold">▸</span>
|
||||
<span>
|
||||
<strong>Storage:</strong> For message persistence and topic indexing
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -6,14 +6,40 @@ interface Props {
|
||||
const { code } = Astro.props;
|
||||
---
|
||||
|
||||
<div class="code-panel">
|
||||
<div class="relative terminal mb-4 p-6 group" data-code-panel>
|
||||
<button
|
||||
class="absolute top-2 right-2 border-2 border-[#3c3c3c] bg-[#191b1d] px-2 py-1 text-xs font-semibold text-white transition hover:border-[var(--flux-orange)] hover:bg-[var(--flux-orange)] hover:text-black"
|
||||
class="absolute top-4 right-4 p-2 hover:bg-(--flux-orange) hover:text-white transition-colors brutalist-border opacity-70 group-hover:opacity-100"
|
||||
type="button"
|
||||
data-copy-btn
|
||||
aria-label="Copy command"
|
||||
>
|
||||
Copy
|
||||
<svg
|
||||
class="size-4"
|
||||
data-copy-icon
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
|
||||
<path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
|
||||
</svg>
|
||||
<svg
|
||||
class="hidden size-4"
|
||||
data-check-icon
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path d="M20 6 9 17l-5-5"></path>
|
||||
</svg>
|
||||
</button>
|
||||
<pre><code>{code}</code></pre>
|
||||
<pre class="overflow-x-auto"><code class="text-sm md:text-base">{code}</code></pre>
|
||||
</div>
|
||||
|
||||
@@ -1,58 +1,43 @@
|
||||
<section id="features" class="border-b-2 border-[var(--flux-border)] py-20">
|
||||
<div class="mx-auto w-[min(100%-2.5rem,1200px)]">
|
||||
---
|
||||
import { Code2, Database, Network, Server, Shield, Zap } from 'lucide-react';
|
||||
---
|
||||
|
||||
<section id="features" class="border-b-2 border-(--flux-border) py-20">
|
||||
<div class="container mx-auto px-6">
|
||||
<h2 class="mb-12 text-4xl font-bold md:text-5xl">
|
||||
<span class="border-l-4 border-[var(--flux-orange)] pl-4">FEATURES</span>
|
||||
<span class="border-l-4 border-(--flux-orange) pl-4">FEATURES</span>
|
||||
</h2>
|
||||
|
||||
<div class="grid gap-6 md:grid-cols-2 lg:grid-cols-3">
|
||||
<article class="brutalist-card accent-line p-6 pl-8">
|
||||
<div class="mb-4 inline-flex size-8 items-center justify-center rounded-sm border-2 border-[var(--flux-blue)] text-[var(--flux-blue)]">
|
||||
<svg class="size-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M4 8h16M4 16h16M8 4v16M16 4v16"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<Network className="mb-4 text-(--flux-blue)" size={32} strokeWidth={2} />
|
||||
<h3 class="mono mb-3 text-xl font-bold">Multi-Protocol Support</h3>
|
||||
<p class="text-base leading-relaxed text-theme-muted">
|
||||
Full MQTT 3.1.1 and 5.0 over TCP and WebSocket, plus HTTP-MQTT and CoAP bridges. All protocols share the
|
||||
same broker core and messages flow seamlessly across transports.
|
||||
same broker core - messages flow seamlessly across transports.
|
||||
</p>
|
||||
</article>
|
||||
|
||||
<article class="brutalist-card accent-line p-6 pl-8">
|
||||
<div class="mb-4 inline-flex size-8 items-center justify-center rounded-sm border-2 border-[var(--flux-orange)] text-[var(--flux-orange)]">
|
||||
<svg class="size-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<ellipse cx="12" cy="6" rx="7" ry="3"></ellipse>
|
||||
<path d="M5 6v6c0 1.7 3.1 3 7 3s7-1.3 7-3V6"></path>
|
||||
<path d="M5 12v6c0 1.7 3.1 3 7 3s7-1.3 7-3v-6"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<Database className="mb-4 text-(--flux-orange)" size={32} strokeWidth={2} />
|
||||
<h3 class="mono mb-3 text-xl font-bold">Durable Queues</h3>
|
||||
<p class="text-base leading-relaxed text-theme-muted">
|
||||
Persistent message queues with consumer groups, ack/nack/reject semantics, dead-letter queues, and retention
|
||||
policies. Raft-based replication with automatic failover.
|
||||
Persistent message queues with consumer groups, ack/nack/reject semantics, dead-letter queues, and Kafka-style
|
||||
retention. Raft-based replication with automatic failover.
|
||||
</p>
|
||||
</article>
|
||||
|
||||
<article class="brutalist-card accent-line p-6 pl-8">
|
||||
<div class="mb-4 inline-flex size-8 items-center justify-center rounded-sm border-2 border-[var(--flux-blue)] text-[var(--flux-blue)]">
|
||||
<svg class="size-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<rect x="3" y="4" width="18" height="6"></rect>
|
||||
<rect x="3" y="14" width="18" height="6"></rect>
|
||||
</svg>
|
||||
</div>
|
||||
<Server className="mb-4 text-(--flux-blue)" size={32} strokeWidth={2} />
|
||||
<h3 class="mono mb-3 text-xl font-bold">Clustering & High Availability</h3>
|
||||
<p class="text-base leading-relaxed text-theme-muted">
|
||||
Embedded etcd for coordination, gRPC-based inter-broker communication with mTLS, automatic session
|
||||
ownership, and graceful shutdown with session transfer.
|
||||
Embedded etcd for coordination, gRPC-based inter-broker communication with mTLS, automatic session ownership,
|
||||
and graceful shutdown with session transfer. No external dependencies.
|
||||
</p>
|
||||
</article>
|
||||
|
||||
<article class="brutalist-card accent-line p-6 pl-8">
|
||||
<div class="mb-4 inline-flex size-8 items-center justify-center rounded-sm border-2 border-[var(--flux-orange)] text-[var(--flux-orange)]">
|
||||
<svg class="size-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M13 2L4 14h7l-1 8 10-13h-7l0-7z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<Zap className="mb-4 text-(--flux-orange)" size={32} strokeWidth={2} />
|
||||
<h3 class="mono mb-3 text-xl font-bold">Performance Optimized</h3>
|
||||
<p class="text-base leading-relaxed text-theme-muted">
|
||||
Zero-copy packet parsing, object pooling, efficient trie-based topic matching, and direct instrumentation.
|
||||
@@ -61,28 +46,20 @@
|
||||
</article>
|
||||
|
||||
<article class="brutalist-card accent-line p-6 pl-8">
|
||||
<div class="mb-4 inline-flex size-8 items-center justify-center rounded-sm border-2 border-[var(--flux-blue)] text-[var(--flux-blue)]">
|
||||
<svg class="size-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M12 3l7 3v6c0 5-3.5 7.5-7 9-3.5-1.5-7-4-7-9V6l7-3z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<Shield className="mb-4 text-(--flux-blue)" size={32} strokeWidth={2} />
|
||||
<h3 class="mono mb-3 text-xl font-bold">Security</h3>
|
||||
<p class="text-base leading-relaxed text-theme-muted">
|
||||
TLS/mTLS for client connections, mTLS for inter-broker gRPC, DTLS options for CoAP, WebSocket origin
|
||||
validation, and per-IP/per-client rate limiting.
|
||||
TLS/mTLS for client connections, mTLS for inter-broker gRPC, DTLS/mDTLS for CoAP, WebSocket origin validation,
|
||||
and per-IP/per-client rate limiting.
|
||||
</p>
|
||||
</article>
|
||||
|
||||
<article class="brutalist-card accent-line p-6 pl-8">
|
||||
<div class="mb-4 inline-flex size-8 items-center justify-center rounded-sm border-2 border-[var(--flux-orange)] text-[var(--flux-orange)]">
|
||||
<svg class="size-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M16 18l6-6-6-6M8 6l-6 6 6 6"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<Code2 className="mb-4 text-(--flux-orange)" size={32} strokeWidth={2} />
|
||||
<h3 class="mono mb-3 text-xl font-bold">Open-Source & Extensible</h3>
|
||||
<p class="text-base leading-relaxed text-theme-muted">
|
||||
Licensed under Apache 2.0 with a clean layered architecture. Pluggable storage backends, protocol-agnostic
|
||||
domain logic, and easy extensibility.
|
||||
Licensed under Apache 2.0 with a clean layered architecture (Transport → Protocol → Domain). Pluggable
|
||||
storage backends, protocol-agnostic domain logic, and easy extensibility.
|
||||
</p>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
@@ -1,42 +1,44 @@
|
||||
<footer class="bg-[var(--flux-bg-alt)] py-14">
|
||||
<div class="mx-auto grid w-[min(100%-2.5rem,1200px)] gap-6 md:grid-cols-2 xl:grid-cols-4">
|
||||
<section>
|
||||
<h3 class="mb-3 text-lg font-bold uppercase">About</h3>
|
||||
<p class="text-[var(--flux-muted)]">
|
||||
FluxMQ is developed by Abstract Machines, an IoT infrastructure and security company located in Paris.
|
||||
</p>
|
||||
</section>
|
||||
<footer class="bg-theme-alt py-12">
|
||||
<div class="container mx-auto px-6">
|
||||
<div class="grid gap-8 md:grid-cols-4">
|
||||
<section>
|
||||
<h3 class="mb-4 text-lg font-bold">ABOUT</h3>
|
||||
<p class="text-sm leading-relaxed">
|
||||
FluxMQ is developed by Abstract Machines, an IoT infrastructure and security company located in Paris.
|
||||
</p>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3 class="mb-3 text-lg font-bold uppercase">Products</h3>
|
||||
<ul class="space-y-2 text-[var(--flux-muted)]">
|
||||
<li><a class="hover:text-[var(--flux-orange)]" href="https://magistrala.absmach.eu" target="_blank" rel="noopener noreferrer">Magistrala</a></li>
|
||||
<li><a class="hover:text-[var(--flux-orange)]" href="https://absmach.eu/supermq/" target="_blank" rel="noopener noreferrer">SuperMQ</a></li>
|
||||
<li><a class="hover:text-[var(--flux-orange)]" href="https://absmach.eu/propeller/" target="_blank" rel="noopener noreferrer">Propeller</a></li>
|
||||
</ul>
|
||||
</section>
|
||||
<section>
|
||||
<h3 class="mb-4 text-lg font-bold">PRODUCTS</h3>
|
||||
<ul class="space-y-2 text-sm">
|
||||
<li><a class="hover:text-[var(--flux-orange)]" href="https://magistrala.absmach.eu" target="_blank" rel="noopener noreferrer">Magistrala</a></li>
|
||||
<li><a class="hover:text-[var(--flux-orange)]" href="https://absmach.eu/supermq/" target="_blank" rel="noopener noreferrer">SuperMQ</a></li>
|
||||
<li><a class="hover:text-[var(--flux-orange)]" href="https://absmach.eu/propeller/" target="_blank" rel="noopener noreferrer">Propeller</a></li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3 class="mb-3 text-lg font-bold uppercase">Resources</h3>
|
||||
<ul class="space-y-2 text-[var(--flux-muted)]">
|
||||
<li><a class="hover:text-[var(--flux-orange)]" href="/docs/">Documentation</a></li>
|
||||
<li><a class="hover:text-[var(--flux-orange)]" href="https://github.com/absmach/fluxmq" target="_blank" rel="noopener noreferrer">GitHub</a></li>
|
||||
<li><a class="hover:text-[var(--flux-orange)]" href="https://absmach.eu/blog/" target="_blank" rel="noopener noreferrer">Blog</a></li>
|
||||
</ul>
|
||||
</section>
|
||||
<section>
|
||||
<h3 class="mb-4 text-lg font-bold">RESOURCES</h3>
|
||||
<ul class="space-y-2 text-sm">
|
||||
<li><a class="hover:text-[var(--flux-orange)]" href="/docs">Documentation</a></li>
|
||||
<li><a class="hover:text-[var(--flux-orange)]" href="https://github.com/absmach/fluxmq" target="_blank" rel="noopener noreferrer">GitHub</a></li>
|
||||
<li><a class="hover:text-[var(--flux-orange)]" href="https://absmach.eu/blog/" target="_blank" rel="noopener noreferrer">Blog</a></li>
|
||||
</ul>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h3 class="mb-3 text-lg font-bold uppercase">Contact</h3>
|
||||
<ul class="space-y-2 text-[var(--flux-muted)]">
|
||||
<li><a class="hover:text-[var(--flux-orange)]" href="mailto:info@absmach.eu">info@absmach.eu</a></li>
|
||||
<li><a class="hover:text-[var(--flux-orange)]" href="https://github.com/absmach" target="_blank" rel="noopener noreferrer">GitHub</a></li>
|
||||
<li><a class="hover:text-[var(--flux-orange)]" href="https://twitter.com/absmach" target="_blank" rel="noopener noreferrer">Twitter</a></li>
|
||||
<li><a class="hover:text-[var(--flux-orange)]" href="https://www.linkedin.com/company/abstract-machines" target="_blank" rel="noopener noreferrer">LinkedIn</a></li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
<section>
|
||||
<h3 class="mb-4 text-lg font-bold">CONTACT</h3>
|
||||
<ul class="space-y-2 text-sm">
|
||||
<li><a class="hover:text-[var(--flux-orange)]" href="mailto:info@absmach.eu">info@absmach.eu</a></li>
|
||||
<li><a class="hover:text-[var(--flux-orange)]" href="https://github.com/absmach" target="_blank" rel="noopener noreferrer">GitHub</a></li>
|
||||
<li><a class="hover:text-[var(--flux-orange)]" href="https://twitter.com/absmach" target="_blank" rel="noopener noreferrer">Twitter</a></li>
|
||||
<li><a class="hover:text-[var(--flux-orange)]" href="https://www.linkedin.com/company/abstract-machines" target="_blank" rel="noopener noreferrer">LinkedIn</a></li>
|
||||
</ul>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<div class="mx-auto mt-8 w-[min(100%-2.5rem,1200px)] border-t-2 border-[var(--flux-border)] pt-4 text-center text-sm text-[var(--flux-muted)]">
|
||||
© 2026 Abstract Machines. Licensed under Apache 2.0.
|
||||
<div class="border-theme mt-8 border-t pt-8 text-center text-sm opacity-70">
|
||||
<p>© 2026 Abstract Machines. Licensed under Apache 2.0.</p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
@@ -0,0 +1,276 @@
|
||||
"use client";
|
||||
|
||||
import { useMemo } from "react";
|
||||
import {
|
||||
Background,
|
||||
ConnectionMode,
|
||||
Handle,
|
||||
MarkerType,
|
||||
Position,
|
||||
ReactFlow,
|
||||
type Edge,
|
||||
type Node,
|
||||
} from "@xyflow/react";
|
||||
import { SmartBezierEdge } from "@tisoap/react-flow-smart-edge";
|
||||
import "@xyflow/react/dist/style.css";
|
||||
|
||||
const blue = "#2F69B3";
|
||||
const orange = "#F9A32A";
|
||||
const green = "#28b828";
|
||||
|
||||
const nodeTypes = {
|
||||
broker: BrokerNode,
|
||||
};
|
||||
|
||||
const edgeTypes = {
|
||||
smart: SmartBezierEdge,
|
||||
};
|
||||
|
||||
export default function HeroFlow() {
|
||||
const nodes: Node[] = useMemo(
|
||||
() => [
|
||||
{
|
||||
id: "mqtt",
|
||||
position: { x: 0, y: 50 },
|
||||
data: { label: "MQTT" },
|
||||
sourcePosition: Position.Right,
|
||||
type: "input",
|
||||
style: protocolStyle,
|
||||
},
|
||||
{
|
||||
id: "http",
|
||||
position: { x: 0, y: 250 },
|
||||
data: { label: "HTTP" },
|
||||
sourcePosition: Position.Right,
|
||||
type: "input",
|
||||
style: protocolStyle,
|
||||
},
|
||||
{
|
||||
id: "ws",
|
||||
position: { x: 0, y: 450 },
|
||||
data: { label: "WebSocket" },
|
||||
sourcePosition: Position.Right,
|
||||
type: "input",
|
||||
style: protocolStyle,
|
||||
},
|
||||
{
|
||||
id: "amqp",
|
||||
position: { x: 0, y: 650 },
|
||||
data: { label: "AMQP" },
|
||||
sourcePosition: Position.Right,
|
||||
type: "input",
|
||||
style: protocolStyle,
|
||||
},
|
||||
{
|
||||
id: "broker-a",
|
||||
position: { x: 300, y: 50 },
|
||||
data: { label: "FluxMQ Node A" },
|
||||
style: brokerStyle,
|
||||
type: "broker",
|
||||
},
|
||||
{
|
||||
id: "broker-b",
|
||||
position: { x: 300, y: 350 },
|
||||
data: { label: "FluxMQ Node B" },
|
||||
style: brokerStyle,
|
||||
type: "broker",
|
||||
},
|
||||
{
|
||||
id: "broker-c",
|
||||
position: { x: 300, y: 600 },
|
||||
data: { label: "FluxMQ Node C" },
|
||||
style: brokerStyle,
|
||||
type: "broker",
|
||||
},
|
||||
{
|
||||
id: "analytics",
|
||||
position: { x: 600, y: 150 },
|
||||
data: { label: "Analytics" },
|
||||
targetPosition: Position.Left,
|
||||
type: "output",
|
||||
style: consumerStyle,
|
||||
},
|
||||
{
|
||||
id: "apps",
|
||||
position: { x: 600, y: 350 },
|
||||
data: { label: "Applications" },
|
||||
targetPosition: Position.Left,
|
||||
type: "output",
|
||||
style: consumerStyle,
|
||||
},
|
||||
{
|
||||
id: "services",
|
||||
position: { x: 600, y: 550 },
|
||||
data: { label: "Services" },
|
||||
targetPosition: Position.Left,
|
||||
type: "output",
|
||||
style: consumerStyle,
|
||||
},
|
||||
],
|
||||
[],
|
||||
);
|
||||
|
||||
const edges: Edge[] = useMemo(
|
||||
() => [
|
||||
edge("mqtt", "broker-a"),
|
||||
edge("mqtt", "broker-b"),
|
||||
edge("mqtt", "broker-c"),
|
||||
edge("http", "broker-b"),
|
||||
edge("http", "broker-c"),
|
||||
edge("ws", "broker-a"),
|
||||
edge("ws", "broker-b"),
|
||||
edge("ws", "broker-c"),
|
||||
edge("amqp", "broker-c"),
|
||||
clusterEdge("broker-a", "broker-b", "bottom", "top"),
|
||||
clusterEdge("broker-b", "broker-c", "bottom", "top"),
|
||||
clusterEdge("broker-c", "broker-a", "bottom", "left"),
|
||||
clusterEdge("broker-c", "broker-b", "bottom", "left"),
|
||||
clusterEdge("broker-b", "broker-a", "right", "top"),
|
||||
consumerEdge("broker-a", "analytics"),
|
||||
consumerEdge("broker-b", "analytics"),
|
||||
consumerEdge("broker-a", "apps"),
|
||||
consumerEdge("broker-b", "apps"),
|
||||
consumerEdge("broker-c", "apps"),
|
||||
consumerEdge("broker-b", "services"),
|
||||
consumerEdge("broker-c", "services"),
|
||||
],
|
||||
[],
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
cursor: "default",
|
||||
pointerEvents: "none",
|
||||
}}
|
||||
>
|
||||
<ReactFlow
|
||||
nodes={nodes}
|
||||
edges={edges}
|
||||
nodeTypes={nodeTypes}
|
||||
edgeTypes={edgeTypes}
|
||||
fitView
|
||||
panOnDrag={false}
|
||||
zoomOnScroll={false}
|
||||
zoomOnPinch={false}
|
||||
nodesDraggable={false}
|
||||
nodesConnectable={false}
|
||||
elementsSelectable={false}
|
||||
preventScrolling={true}
|
||||
connectionMode={ConnectionMode.Loose}
|
||||
proOptions={{ hideAttribution: true }}
|
||||
>
|
||||
<Background gap={32} size={1} color="rgba(47,105,179,0.08)" />
|
||||
</ReactFlow>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const edge = (
|
||||
source: string,
|
||||
target: string,
|
||||
sourceHandle?: string,
|
||||
targetHandle?: string,
|
||||
): Edge => ({
|
||||
id: `${source}-${target}`,
|
||||
source,
|
||||
target,
|
||||
sourceHandle,
|
||||
targetHandle,
|
||||
animated: true,
|
||||
style: {
|
||||
stroke: blue,
|
||||
strokeWidth: 1.5,
|
||||
},
|
||||
markerEnd: {
|
||||
type: MarkerType.ArrowClosed,
|
||||
color: blue,
|
||||
},
|
||||
});
|
||||
|
||||
const consumerEdge = (source: string, target: string): Edge => ({
|
||||
id: `${source}-${target}`,
|
||||
source,
|
||||
target,
|
||||
animated: true,
|
||||
style: {
|
||||
stroke: green,
|
||||
strokeWidth: 1.5,
|
||||
},
|
||||
markerEnd: {
|
||||
type: MarkerType.ArrowClosed,
|
||||
color: blue,
|
||||
},
|
||||
});
|
||||
|
||||
const clusterEdge = (
|
||||
source: string,
|
||||
target: string,
|
||||
sourceHandle?: string,
|
||||
targetHandle?: string,
|
||||
): Edge => ({
|
||||
id: `${source}-${target}`,
|
||||
source,
|
||||
target,
|
||||
sourceHandle,
|
||||
targetHandle,
|
||||
animated: true,
|
||||
type: "smoothstep",
|
||||
style: {
|
||||
stroke: orange,
|
||||
strokeWidth: 2,
|
||||
strokeDasharray: "6 6",
|
||||
},
|
||||
});
|
||||
|
||||
const protocolStyle = {
|
||||
borderRadius: 8,
|
||||
padding: "16px 20px",
|
||||
fontSize: 16,
|
||||
fontWeight: 600,
|
||||
border: `1px solid ${blue}`,
|
||||
color: blue,
|
||||
background: "rgba(47,105,179,0.05)",
|
||||
minWidth: 120,
|
||||
textAlign: "center" as const,
|
||||
};
|
||||
|
||||
const consumerStyle = {
|
||||
...protocolStyle,
|
||||
color: green,
|
||||
border: `1px solid ${green}`,
|
||||
background: "rgba(40, 184, 40, 0.08)",
|
||||
};
|
||||
|
||||
const brokerStyle = {
|
||||
borderRadius: 12,
|
||||
padding: "20px 24px",
|
||||
fontSize: 18,
|
||||
fontWeight: 700,
|
||||
border: `1px solid ${orange}`,
|
||||
color: orange,
|
||||
background: "rgba(249,163,42,0.08)",
|
||||
boxShadow: "0 0 18px rgba(249,163,42,0.35)",
|
||||
minWidth: 160,
|
||||
textAlign: "center" as const,
|
||||
};
|
||||
|
||||
function BrokerNode() {
|
||||
return (
|
||||
<div className="flex w-full flex-col gap-2">
|
||||
<div className="w-full rounded-md border p-1 text-center">
|
||||
<span className="text-(--flux-blue)">Flux</span>
|
||||
<span className="text-(--flux-orange)">MQ</span>
|
||||
</div>
|
||||
<div className="w-full rounded-md border p-1 text-center">
|
||||
Durable Queue
|
||||
</div>
|
||||
<Handle type="target" position={Position.Left} id="left" />
|
||||
<Handle type="target" position={Position.Top} id="top" />
|
||||
<Handle type="source" position={Position.Right} id="right" />
|
||||
<Handle type="source" position={Position.Bottom} id="bottom" />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,30 +1,49 @@
|
||||
---
|
||||
import HeroNetwork from './HeroNetwork.astro';
|
||||
import HeroFlow from "./HeroFlow";
|
||||
---
|
||||
|
||||
<section class="relative h-[90vh] border-b-2 border-[var(--flux-border)] py-20 md:py-20">
|
||||
<div class="mx-auto w-[min(100%-2.5rem,1200px)]">
|
||||
<section
|
||||
class="relative border-b-2 border-(--flux-border) py-20 md:py-20 min-h-[90vh]"
|
||||
>
|
||||
<div class="container mx-auto px-6">
|
||||
<div class="grid items-center gap-12 md:grid-cols-2">
|
||||
<div class="max-w-2xl">
|
||||
<div class="mb-14">
|
||||
<h1 class="animate-fade-in mb-4 text-6xl font-bold md:text-8xl" style="line-height:1.1">
|
||||
<span class="text-[var(--flux-blue)]">Flux</span><span class="text-[var(--flux-orange)]">MQ</span>
|
||||
<h1
|
||||
class="animate-fade-in mb-4 text-6xl font-bold md:text-8xl"
|
||||
style="line-height:1.1"
|
||||
>
|
||||
<span class="text-(--flux-blue)">Flux</span><span
|
||||
class="text-(--flux-orange)">MQ</span
|
||||
>
|
||||
</h1>
|
||||
<div class="mono animate-slide-up mb-6 border-l-4 border-[var(--flux-orange)] pl-4 text-base text-theme-muted md:text-xl">
|
||||
<div>open-source | high-throughput | low-latency | scalable</div>
|
||||
<div>persistent storage | replication | MQTT v3/v5 | AMQP</div>
|
||||
<div>security | extensibility</div>
|
||||
<div
|
||||
class="mono animate-slide-up mb-6 flex flex-wrap gap-x-2 border-l-4 border-(--flux-orange) pl-4 text-base text-theme-muted md:text-xl"
|
||||
>
|
||||
<span class="whitespace-nowrap">open-source |</span>
|
||||
<span class="whitespace-nowrap">high-throughput |</span>
|
||||
<span class="whitespace-nowrap">low-latency |</span>
|
||||
<span class="whitespace-nowrap">scalable |</span>
|
||||
<span class="whitespace-nowrap">persistent storage |</span>
|
||||
<span class="whitespace-nowrap">replication |</span>
|
||||
<span class="whitespace-nowrap">MQTT v3/v5 |</span>
|
||||
<span class="whitespace-nowrap">AMQP |</span>
|
||||
<span class="whitespace-nowrap">security |</span>
|
||||
<span class="whitespace-nowrap">extensibility</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p class="animate-fade-in mb-14 max-w-3xl text-xl leading-relaxed md:text-2xl">
|
||||
A high-performance, open source, multi-protocol message broker written in Go for scalable IoT and
|
||||
event-driven architectures. Single binary. No external dependencies.
|
||||
<p
|
||||
class="animate-fade-in mb-14 max-w-3xl text-xl! leading-relaxed md:text-2xl!"
|
||||
>
|
||||
A high-performance, open source, multi-protocol message broker written
|
||||
in Go for scalable IoT and event-driven architectures. Single binary.
|
||||
No external dependencies.
|
||||
</p>
|
||||
|
||||
<div class="animate-slide-up flex flex-wrap gap-4">
|
||||
<a
|
||||
class="brutalist-border inline-block px-6 py-3 font-bold transition-colors hover:bg-[var(--flux-blue)] hover:text-white"
|
||||
class="brutalist-border inline-block px-6 py-3 font-bold transition-colors hover:bg-(--flux-blue) hover:text-white"
|
||||
href="https://github.com/absmach/fluxmq"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
@@ -32,8 +51,8 @@ import HeroNetwork from './HeroNetwork.astro';
|
||||
VIEW ON GITHUB →
|
||||
</a>
|
||||
<a
|
||||
class="brutalist-border inline-block px-6 py-3 font-bold transition-colors hover:bg-[var(--flux-orange)] hover:text-white"
|
||||
href="/docs/"
|
||||
class="brutalist-border inline-block px-6 py-3 font-bold transition-colors hover:bg-(--flux-orange) hover:text-white"
|
||||
href="/docs"
|
||||
>
|
||||
READ DOCUMENTATION
|
||||
</a>
|
||||
@@ -41,7 +60,7 @@ import HeroNetwork from './HeroNetwork.astro';
|
||||
</div>
|
||||
|
||||
<div class="hidden h-[80vh] items-center justify-center md:flex">
|
||||
<HeroNetwork />
|
||||
<HeroFlow client:load />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import mermaid from "mermaid";
|
||||
|
||||
interface MermaidDiagramProps {
|
||||
chart: string;
|
||||
}
|
||||
|
||||
const isDarkTheme = () => {
|
||||
const root = document.documentElement;
|
||||
return root.classList.contains("dark") || root.dataset.theme === "dark";
|
||||
};
|
||||
|
||||
export function MermaidDiagram({ chart }: MermaidDiagramProps) {
|
||||
const ref = useRef<HTMLDivElement>(null);
|
||||
const [dark, setDark] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setDark(isDarkTheme());
|
||||
|
||||
const observer = new MutationObserver(() => {
|
||||
setDark(isDarkTheme());
|
||||
});
|
||||
|
||||
observer.observe(document.documentElement, {
|
||||
attributes: true,
|
||||
attributeFilter: ["class", "data-theme"],
|
||||
});
|
||||
|
||||
return () => observer.disconnect();
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
mermaid.initialize({
|
||||
startOnLoad: true,
|
||||
theme: "base",
|
||||
themeVariables: {
|
||||
primaryColor: "#2F69B3",
|
||||
primaryTextColor: "#ffffff",
|
||||
primaryBorderColor: dark ? "#444444" : "#333333",
|
||||
lineColor: dark ? "#cccccc" : "#666666",
|
||||
secondaryColor: "#F9A32A",
|
||||
tertiaryColor: dark ? "#1a1a1a" : "#ffffff",
|
||||
background: dark ? "#1a1a1a" : "#f9f9f9",
|
||||
mainBkg: "#1a1a1a",
|
||||
textColor: dark ? "#ffffff" : "#1a1a1a",
|
||||
fontSize: "14px",
|
||||
fontFamily: "'JetBrains Mono', 'Courier New', monospace",
|
||||
},
|
||||
});
|
||||
|
||||
const current = ref.current;
|
||||
if (!current) return;
|
||||
|
||||
const id = `mermaid-${Math.random().toString(36).slice(2, 11)}`;
|
||||
let cancelled = false;
|
||||
|
||||
mermaid.render(id, chart).then(({ svg }) => {
|
||||
if (!cancelled && current) current.innerHTML = svg;
|
||||
});
|
||||
|
||||
return () => {
|
||||
cancelled = true;
|
||||
};
|
||||
}, [chart, dark]);
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={ref}
|
||||
className="my-8 flex items-center justify-center overflow-x-auto brutalist-border bg-theme p-8"
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -1,37 +1,67 @@
|
||||
<section class="border-b-2 border-[var(--flux-border)] bg-[var(--flux-bg-alt)] py-20">
|
||||
<div class="mx-auto w-[min(100%-2.5rem,1200px)]">
|
||||
<div class="mx-auto max-w-[700px] text-center">
|
||||
<h2 class="mb-2 text-3xl font-bold uppercase md:text-4xl">Subscribe to Newsletter</h2>
|
||||
<p class="text-[var(--flux-muted)]">Stay updated with the latest FluxMQ news, updates, and announcements.</p>
|
||||
<section
|
||||
class="border-b-2 border-[var(--flux-border)] bg-[var(--flux-bg-alt)] py-20"
|
||||
>
|
||||
<div class="container mx-auto px-6">
|
||||
<div class="mx-auto max-w-2xl">
|
||||
<h2 class="mb-6 text-center text-3xl font-bold md:text-4xl">
|
||||
SUBSCRIBE TO NEWSLETTER
|
||||
</h2>
|
||||
<p class="mb-8 text-center text-theme-muted">
|
||||
Stay updated with the latest FluxMQ news, updates and announcements.
|
||||
</p>
|
||||
|
||||
<form
|
||||
action="https://absmach.us11.list-manage.com/subscribe/post?u=70b43c7181d005024187bfb31&id=0a319b6b63&f_id=00d816e1f0"
|
||||
action="https://absmach.us11.list-manage.com/subscribe/post?u=70b43c7181d005024187bfb31&id=0a319b6b63&f_id=00d816e1f0"
|
||||
method="post"
|
||||
id="mc-embedded-subscribe-form"
|
||||
name="mc-embedded-subscribe-form"
|
||||
target="_blank"
|
||||
class="mt-6 flex flex-col border-2 border-[var(--flux-border)] bg-white sm:flex-row"
|
||||
class="mx-auto max-w-md"
|
||||
>
|
||||
<input
|
||||
type="email"
|
||||
name="EMAIL"
|
||||
placeholder="Enter your email"
|
||||
required
|
||||
class="w-full flex-1 px-4 py-3 text-sm outline-none placeholder:text-[#6b6b6b] sm:text-base"
|
||||
/>
|
||||
<button
|
||||
type="submit"
|
||||
class="bg-[var(--flux-orange)] px-4 py-3 text-sm font-bold uppercase tracking-wide text-black transition hover:bg-[var(--flux-blue)] hover:text-white sm:text-base"
|
||||
>
|
||||
Subscribe
|
||||
</button>
|
||||
<div class="flex gap-0">
|
||||
<input
|
||||
type="email"
|
||||
name="EMAIL"
|
||||
placeholder="Enter your email"
|
||||
required
|
||||
class="brutalist-border flex-1 border-r-0 px-4 py-3 focus:border-[var(--flux-orange)] focus:outline-none"
|
||||
/>
|
||||
<button
|
||||
type="submit"
|
||||
class="brutalist-border bg-[var(--flux-orange)] px-6 py-3 font-bold text-white transition-colors hover:bg-[var(--flux-blue)]"
|
||||
>
|
||||
SUBSCRIBE
|
||||
</button>
|
||||
</div>
|
||||
<input type="hidden" name="tags" value="8115284" />
|
||||
<div style="position:absolute;left:-5000px;" aria-hidden="true">
|
||||
<input
|
||||
type="text"
|
||||
name="b_70b43c7181d005024187bfb31_0a319b6b63"
|
||||
tabindex="-1"
|
||||
value=""
|
||||
/>
|
||||
</div>
|
||||
<p class="mt-4 text-center text-xs text-theme-muted">
|
||||
By subscribing, you agree to our
|
||||
<a
|
||||
class="underline"
|
||||
href="https://absmach.eu/privacy/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Privacy Policy</a
|
||||
> and
|
||||
<a
|
||||
class="underline"
|
||||
href="https://absmach.eu/terms/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Terms of Service</a
|
||||
>. You can unsubscribe at any time.
|
||||
</p>
|
||||
</form>
|
||||
|
||||
<p class="mt-4 text-sm text-[var(--flux-muted)]">
|
||||
By subscribing, you agree to our
|
||||
<a class="underline" href="https://absmach.eu/privacy/" target="_blank" rel="noopener noreferrer">Privacy Policy</a>
|
||||
and
|
||||
<a class="underline" href="https://absmach.eu/terms/" target="_blank" rel="noopener noreferrer">Terms of Service</a>.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<section id="performance" class="border-b-2 border-theme bg-theme-alt py-20">
|
||||
<div class="mx-auto w-[min(100%-2.5rem,1200px)]">
|
||||
<div class="container mx-auto px-6">
|
||||
<h2 class="mb-12 text-4xl font-bold md:text-5xl">
|
||||
<span class="border-l-4 border-[var(--flux-orange)] pl-4">PERFORMANCE</span>
|
||||
</h2>
|
||||
|
||||
<div class="max-w-4xl">
|
||||
<div class="mx-auto max-w-4xl">
|
||||
<table class="metrics-table mono w-full text-sm md:text-base">
|
||||
<thead>
|
||||
<tr>
|
||||
@@ -12,7 +12,7 @@
|
||||
<th>VALUE</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tbody class="bg-white">
|
||||
<tr>
|
||||
<td>Concurrent Connections</td>
|
||||
<td class="font-bold">500K+ per node</td>
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
---
|
||||
import CodePanel from './CodePanel.astro';
|
||||
import { BookOpen } from 'lucide-react';
|
||||
|
||||
const dockerSnippet = `git clone https://github.com/absmach/fluxmq.git
|
||||
cd fluxmq
|
||||
@@ -18,44 +19,48 @@ make build
|
||||
---
|
||||
|
||||
<section id="quick-start" class="border-b-2 border-[var(--flux-border)] py-20">
|
||||
<div class="mx-auto w-[min(100%-2.5rem,1200px)]">
|
||||
<h2 class="mb-8 text-[clamp(2rem,4vw,3rem)] leading-tight font-bold uppercase tracking-[0.03em]">
|
||||
<span class="border-l-[5px] border-[var(--flux-orange)] pl-3">Quick Start</span>
|
||||
<div class="container mx-auto px-6">
|
||||
<h2 class="mb-12 text-4xl font-bold md:text-5xl">
|
||||
<span class="border-l-4 border-[var(--flux-orange)] pl-4">QUICK START</span>
|
||||
</h2>
|
||||
|
||||
<div class="space-y-8">
|
||||
<div class="mx-auto max-w-4xl space-y-8">
|
||||
<div>
|
||||
<h3 class="mono mb-3 text-xl font-bold">1. Run with Docker</h3>
|
||||
<h3 class="mono mb-4 text-xl font-bold">1. RUN WITH DOCKER</h3>
|
||||
<CodePanel code={dockerSnippet} />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 class="mono mb-3 text-xl font-bold">2. Test with MQTT</h3>
|
||||
<h3 class="mono mb-4 text-xl font-bold">2. TEST WITH MQTT</h3>
|
||||
<CodePanel code={mqttSnippet} />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3 class="mono mb-3 text-xl font-bold">3. Or Build Locally</h3>
|
||||
<h3 class="mono mb-4 text-xl font-bold">3. OR BUILD LOCALLY</h3>
|
||||
<CodePanel code={localSnippet} />
|
||||
</div>
|
||||
|
||||
<div class="cluster-box">
|
||||
<p class="mono text-sm md:text-base"><strong>Defaults:</strong> MQTT TCP :1883, AMQP 0.9.1 :5682, Data /tmp/fluxmq/data</p>
|
||||
<p class="mono mt-3"><strong>Next Steps:</strong></p>
|
||||
<ul class="mt-2 list-none space-y-2 p-0">
|
||||
<div class="brutalist-border bg-theme mt-12 p-8">
|
||||
<p class="mb-4 text-lg font-bold">Defaults (MQTT TCP: :1883, AMQP 0.9.1: :5682, Data: /tmp/fluxmq/data)</p>
|
||||
<p class="mb-4 text-lg font-bold">Next Steps:</p>
|
||||
<ul class="space-y-3">
|
||||
<li>
|
||||
<a
|
||||
class="font-bold text-[var(--flux-blue)] hover:text-[var(--flux-orange)]"
|
||||
class="flex items-center gap-2 text-lg font-bold text-[var(--flux-blue)] hover:underline"
|
||||
href="https://github.com/absmach/fluxmq/tree/main/examples"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Explore code examples on GitHub
|
||||
<svg class="size-5" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
|
||||
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12" />
|
||||
</svg>
|
||||
<span>Explore code examples on GitHub</span>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="font-bold text-[var(--flux-blue)] hover:text-[var(--flux-orange)]" href="/docs/">
|
||||
Read the full documentation
|
||||
<a class="flex items-center gap-2 text-lg font-bold text-[var(--flux-orange)] hover:underline" href="/docs">
|
||||
<BookOpen size={20} />
|
||||
<span>Read the full documentation</span>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -67,16 +72,24 @@ make build
|
||||
const copyButtons = document.querySelectorAll('[data-copy-btn]');
|
||||
for (const button of copyButtons) {
|
||||
button.addEventListener('click', async () => {
|
||||
const panel = button.closest('.code-panel');
|
||||
const panel = button.closest('[data-code-panel]');
|
||||
const code = panel?.querySelector('code')?.textContent ?? '';
|
||||
|
||||
if (!code) return;
|
||||
|
||||
await navigator.clipboard.writeText(code);
|
||||
const original = button.textContent;
|
||||
button.textContent = 'Copied';
|
||||
const copyIcon = button.querySelector('[data-copy-icon]');
|
||||
const checkIcon = button.querySelector('[data-check-icon]');
|
||||
if (copyIcon && checkIcon) {
|
||||
copyIcon.classList.add('hidden');
|
||||
checkIcon.classList.remove('hidden');
|
||||
}
|
||||
|
||||
window.setTimeout(() => {
|
||||
button.textContent = original;
|
||||
if (copyIcon && checkIcon) {
|
||||
checkIcon.classList.add('hidden');
|
||||
copyIcon.classList.remove('hidden');
|
||||
}
|
||||
}, 1600);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,51 +1,42 @@
|
||||
---
|
||||
import { Activity, Cpu, Gauge } from 'lucide-react';
|
||||
---
|
||||
|
||||
<section id="use-cases" class="border-b-2 border-[var(--flux-border)] py-20">
|
||||
<div class="mx-auto w-[min(100%-2.5rem,1200px)]">
|
||||
<div class="container mx-auto px-6">
|
||||
<h2 class="mb-12 text-4xl font-bold md:text-5xl">
|
||||
<span class="border-l-4 border-[var(--flux-orange)] pl-4">USE CASES</span>
|
||||
</h2>
|
||||
|
||||
<div class="grid gap-6 md:grid-cols-3">
|
||||
<article class="brutalist-card p-6">
|
||||
<div class="mb-4 inline-flex size-9 items-center justify-center rounded-sm border-2 border-[var(--flux-orange)] text-[var(--flux-orange)]">
|
||||
<svg class="size-6" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M4 12h4l2-6 4 12 2-6h4"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<Activity className="mb-4 text-(--flux-orange)" size={36} strokeWidth={2} />
|
||||
<div class="mb-4 border-b-2 border-[var(--flux-border)] pb-4">
|
||||
<h3 class="mono text-2xl font-bold">Event-Driven Systems</h3>
|
||||
</div>
|
||||
<ul class="space-y-3 text-base text-theme-muted">
|
||||
<li class="flex items-start"><span class="mr-2 font-bold text-[var(--flux-orange)]">■</span><span>Decouple microservices with event streams</span></li>
|
||||
<li class="flex items-start"><span class="mr-2 font-bold text-[var(--flux-orange)]">■</span><span>Reliable command and event pipelines (CQRS)</span></li>
|
||||
<li class="flex items-start"><span class="mr-2 font-bold text-[var(--flux-orange)]">■</span><span>Background jobs and asynchronous workflows</span></li>
|
||||
<li class="flex items-start"><span class="mr-2 font-bold text-[var(--flux-orange)]">■</span><span>Reliable command & event pipelines (CQRS)</span></li>
|
||||
<li class="flex items-start"><span class="mr-2 font-bold text-[var(--flux-orange)]">■</span><span>Background jobs & asynchronous workflows</span></li>
|
||||
<li class="flex items-start"><span class="mr-2 font-bold text-[var(--flux-orange)]">■</span><span>Real-time data processing pipelines</span></li>
|
||||
</ul>
|
||||
</article>
|
||||
|
||||
<article class="brutalist-card p-6">
|
||||
<div class="mb-4 inline-flex size-9 items-center justify-center rounded-sm border-2 border-[var(--flux-blue)] text-[var(--flux-blue)]">
|
||||
<svg class="size-6" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<rect x="4" y="4" width="16" height="16" rx="2"></rect>
|
||||
<path d="M9 9h6v6H9z"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<Cpu className="mb-4 text-(--flux-blue)" size={36} strokeWidth={2} />
|
||||
<div class="mb-4 border-b-2 border-[var(--flux-border)] pb-4">
|
||||
<h3 class="mono text-2xl font-bold">IoT & Real-Time</h3>
|
||||
</div>
|
||||
<ul class="space-y-3 text-base text-theme-muted">
|
||||
<li class="flex items-start"><span class="mr-2 font-bold text-[var(--flux-orange)]">■</span><span>IoT device telemetry ingestion (MQTT)</span></li>
|
||||
<li class="flex items-start"><span class="mr-2 font-bold text-[var(--flux-orange)]">■</span><span>Edge deployments with intermittent connectivity</span></li>
|
||||
<li class="flex items-start"><span class="mr-2 font-bold text-[var(--flux-orange)]">■</span><span>Live dashboards and browser updates (WebSocket)</span></li>
|
||||
<li class="flex items-start"><span class="mr-2 font-bold text-[var(--flux-orange)]">■</span><span>Live dashboards & browser updates (WebSocket)</span></li>
|
||||
<li class="flex items-start"><span class="mr-2 font-bold text-[var(--flux-orange)]">■</span><span>Constrained device messaging via protocol bridges</span></li>
|
||||
</ul>
|
||||
</article>
|
||||
|
||||
<article class="brutalist-card p-6">
|
||||
<div class="mb-4 inline-flex size-9 items-center justify-center rounded-sm border-2 border-[var(--flux-orange)] text-[var(--flux-orange)]">
|
||||
<svg class="size-6" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
|
||||
<path d="M4 18h16M6 18V9M12 18V5M18 18v-7"></path>
|
||||
</svg>
|
||||
</div>
|
||||
<Gauge className="mb-4 text-(--flux-orange)" size={36} strokeWidth={2} />
|
||||
<div class="mb-4 border-b-2 border-[var(--flux-border)] pb-4">
|
||||
<h3 class="mono text-2xl font-bold">High-Throughput Pipelines</h3>
|
||||
</div>
|
||||
@@ -53,7 +44,7 @@
|
||||
<li class="flex items-start"><span class="mr-2 font-bold text-[var(--flux-orange)]">■</span><span>Stream millions of events per second</span></li>
|
||||
<li class="flex items-start"><span class="mr-2 font-bold text-[var(--flux-orange)]">■</span><span>Buffer traffic bursts with durable queues</span></li>
|
||||
<li class="flex items-start"><span class="mr-2 font-bold text-[var(--flux-orange)]">■</span><span>Decouple ingestion from downstream processing</span></li>
|
||||
<li class="flex items-start"><span class="mr-2 font-bold text-[var(--flux-orange)]">■</span><span>Power analytics and observability data streams</span></li>
|
||||
<li class="flex items-start"><span class="mr-2 font-bold text-[var(--flux-orange)]">■</span><span>Power analytics & observability data streams</span></li>
|
||||
</ul>
|
||||
</article>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
---
|
||||
import '../styles/global.css';
|
||||
import { ClientRouter } from 'astro:transitions';
|
||||
---
|
||||
|
||||
@@ -18,7 +19,12 @@ import { ClientRouter } from 'astro:transitions';
|
||||
})();
|
||||
</script>
|
||||
</head>
|
||||
<body class="flex min-h-screen flex-col" transition:persist transition:animate="none" transition:name="page-layout">
|
||||
<body
|
||||
class="bg-theme text-[var(--flux-text)] flex min-h-screen flex-col"
|
||||
transition:persist
|
||||
transition:animate="none"
|
||||
transition:name="page-layout"
|
||||
>
|
||||
<slot />
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -2,7 +2,7 @@ import { glob } from 'astro/loaders';
|
||||
import { defineCollection, z } from 'astro:content';
|
||||
|
||||
const docs = defineCollection({
|
||||
loader: glob({ pattern: '**/*.{md,mdx}', base: './src/content/docs/docs' }),
|
||||
loader: glob({ pattern: '**/*.{md,mdx}', base: './src/content/docs' }),
|
||||
schema: z.object({
|
||||
title: z.string(),
|
||||
description: z.string().optional(),
|
||||
@@ -11,7 +11,7 @@ const docs = defineCollection({
|
||||
});
|
||||
|
||||
const meta = defineCollection({
|
||||
loader: glob({ pattern: '**/*.{json,yaml}', base: './src/content/docs/docs' }),
|
||||
loader: glob({ pattern: '**/*.{json,yaml}', base: './src/content/docs' }),
|
||||
schema: z.object({
|
||||
title: z.string().optional(),
|
||||
description: z.string().optional(),
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
---
|
||||
title: FluxMQ Architecture
|
||||
description: Comprehensive system design overview covering layered architecture, protocol adapters, domain logic, and multi-protocol support
|
||||
---
|
||||
|
||||
# FluxMQ Architecture
|
||||
|
||||
**Last Updated:** 2026-02-05
|
||||
|
||||
## Overview
|
||||
|
||||
FluxMQ is a multi-protocol message broker built around a shared queue manager. MQTT transports (TCP, WebSocket, HTTP bridge, CoAP) share one MQTT broker instance, while AMQP 1.0 and AMQP 0.9.1 use dedicated brokers. Durable queues are protocol-agnostic and provide cross-protocol routing and fan-out.
|
||||
|
||||
## High-Level View
|
||||
|
||||
```
|
||||
┌──────────────────────────────────────────────────────────────┐
|
||||
│ Server Wiring │
|
||||
│ • Starts protocol servers (MQTT TCP/WS/HTTP/CoAP, AMQP) │
|
||||
│ • Creates shared Queue Manager │
|
||||
│ • Wires storage, cluster, metrics, shutdown │
|
||||
└──────────┬──────────────────┬──────────────────┬─────────────┘
|
||||
│ │ │
|
||||
▼ ▼ ▼
|
||||
┌────────────────┐ ┌─────────────┐ ┌─────────────┐
|
||||
│ MQTT Transports│ │ AMQP 1.0 │ │ AMQP 0.9.1 │
|
||||
│ (TCP/WS/HTTP/ │ │ Broker │ │ Broker │
|
||||
│ CoAP) │ └──────┬──────┘ └──────┬──────┘
|
||||
└───────┬────────┘ │ │
|
||||
▼ ▼ ▼
|
||||
┌────────────┐ ┌────────────┐ ┌────────────┐
|
||||
│ MQTT Broker│ │ AMQP Broker│ │ AMQP Broker│
|
||||
└──────┬─────┘ └──────┬─────┘ └──────┬─────┘
|
||||
└──────────────────┬──────────────────┘
|
||||
│ queue-capable traffic
|
||||
▼
|
||||
┌────────────────┐
|
||||
│ Queue Manager │
|
||||
│ (durable logs) │
|
||||
└──────┬─────────┘
|
||||
▼
|
||||
┌────────────────┐
|
||||
│ Log Storage │
|
||||
└────────────────┘
|
||||
```
|
||||
|
||||
## Key Components (Code Map)
|
||||
|
||||
- **MQTT Broker**: `mqtt/broker/`
|
||||
- Session lifecycle, topic routing, retained messages, wills
|
||||
- Shared subscriptions (MQTT 5.0)
|
||||
- Queue integration for `$queue/` topics and ack topics
|
||||
|
||||
- **AMQP Brokers**:
|
||||
- AMQP 1.0: `amqp1/broker/`
|
||||
- AMQP 0.9.1: `amqp/broker/`
|
||||
- Both integrate with the shared queue manager
|
||||
|
||||
- **Transports and Bridges**: `server/`
|
||||
- `server/tcp`, `server/websocket` for MQTT
|
||||
- `server/http` HTTP publish bridge
|
||||
- `server/coap` CoAP publish bridge
|
||||
- `server/amqp`, `server/amqp1` for AMQP listeners
|
||||
|
||||
- **Queue Manager**: `queue/` and `logstorage/`
|
||||
- Append-only logs with consumer groups
|
||||
- Queue and stream modes
|
||||
- Ack/Nack/Reject support and retention policies
|
||||
|
||||
- **Storage**: `storage/` (BadgerDB and memory backends)
|
||||
- Sessions, subscriptions, retained messages, offline queues
|
||||
|
||||
- **Clustering**: `cluster/`
|
||||
- Embedded etcd metadata, gRPC transport for routing
|
||||
- Session ownership, retained/will coordination
|
||||
|
||||
- **Observability**: `server/otel/`
|
||||
- OpenTelemetry metrics and tracing setup
|
||||
|
||||
- **Webhook Notifier**: `broker/webhook/`
|
||||
- Asynchronous event delivery with retries and circuit breaker
|
||||
|
||||
- **Queue API (Connect/gRPC)**: `server/api/`, `server/queue/`
|
||||
- Programmatic queue operations over HTTP/2 (h2c or TLS)
|
||||
|
||||
## Related Docs
|
||||
|
||||
- `docs/broker.md`
|
||||
- `docs/queue.md`
|
||||
- `docs/configuration.md`
|
||||
- `docs/clustering.md`
|
||||
- `docs/webhooks.md`
|
||||
@@ -1,74 +0,0 @@
|
||||
---
|
||||
title: FluxMQ Architecture
|
||||
description: Comprehensive system design overview covering layered architecture, protocol adapters, domain logic, and multi-protocol support
|
||||
---
|
||||
|
||||
# FluxMQ Architecture
|
||||
|
||||
**Last Updated:** 2026-02-05
|
||||
|
||||
## Overview
|
||||
|
||||
FluxMQ is a multi-protocol message broker built around a shared queue manager. MQTT transports (TCP, WebSocket, HTTP bridge, CoAP) share one MQTT broker instance, while AMQP 1.0 and AMQP 0.9.1 use dedicated brokers. Durable queues are protocol-agnostic and provide cross-protocol routing and fan-out.
|
||||
|
||||
## High-Level View
|
||||
|
||||
1. **Server wiring**
|
||||
Initializes protocol servers (MQTT TCP/WS/HTTP/CoAP and AMQP), creates the shared queue manager, and wires storage, clustering, metrics, and graceful shutdown.
|
||||
2. **Protocol entry points**
|
||||
MQTT transports feed the MQTT broker, while AMQP 1.0 and AMQP 0.9.1 each feed their own protocol broker.
|
||||
3. **Broker layer**
|
||||
MQTT, AMQP 1.0, and AMQP 0.9.1 brokers process protocol semantics independently.
|
||||
4. **Queue layer**
|
||||
Queue-capable traffic from all brokers converges into the shared **Queue Manager** (durable logs, fan-out, consumer groups).
|
||||
5. **Persistence layer**
|
||||
Queue logs and related durable data are written through the storage backend.
|
||||
|
||||
`Server Wiring -> Protocol Servers -> Protocol Brokers -> Queue Manager -> Log Storage`
|
||||
|
||||
## Key Components (Code Map)
|
||||
|
||||
- **MQTT Broker**: `mqtt/broker/`
|
||||
- Session lifecycle, topic routing, retained messages, wills
|
||||
- Shared subscriptions (MQTT 5.0)
|
||||
- Queue integration for `$queue/` topics and ack topics
|
||||
|
||||
- **AMQP Brokers**:
|
||||
- AMQP 1.0: `amqp1/broker/`
|
||||
- AMQP 0.9.1: `amqp/broker/`
|
||||
- Both integrate with the shared queue manager
|
||||
|
||||
- **Transports and Bridges**: `server/`
|
||||
- `server/tcp`, `server/websocket` for MQTT
|
||||
- `server/http` HTTP publish bridge
|
||||
- `server/coap` CoAP publish bridge
|
||||
- `server/amqp`, `server/amqp1` for AMQP listeners
|
||||
|
||||
- **Queue Manager**: `queue/` and `logstorage/`
|
||||
- Append-only logs with consumer groups
|
||||
- Queue and stream modes
|
||||
- Ack/Nack/Reject support and retention policies
|
||||
|
||||
- **Storage**: `storage/` (BadgerDB and memory backends)
|
||||
- Sessions, subscriptions, retained messages, offline queues
|
||||
|
||||
- **Clustering**: `cluster/`
|
||||
- Embedded etcd metadata, gRPC transport for routing
|
||||
- Session ownership, retained/will coordination
|
||||
|
||||
- **Observability**: `server/otel/`
|
||||
- OpenTelemetry metrics and tracing setup
|
||||
|
||||
- **Webhook Notifier**: `broker/webhook/`
|
||||
- Asynchronous event delivery with retries and circuit breaker
|
||||
|
||||
- **Queue API (Connect/gRPC)**: `server/api/`, `server/queue/`
|
||||
- Programmatic queue operations over HTTP/2 (h2c or TLS)
|
||||
|
||||
## Related Docs
|
||||
|
||||
- `docs/broker.md`
|
||||
- `docs/queue.md`
|
||||
- `docs/configuration.md`
|
||||
- `docs/clustering.md`
|
||||
- `docs/webhooks.md`
|
||||
@@ -1,20 +0,0 @@
|
||||
{
|
||||
"root": true,
|
||||
"pages": [
|
||||
"---Overview---",
|
||||
"index",
|
||||
"roadmap",
|
||||
"---Core Concepts---",
|
||||
"architecture",
|
||||
"broker",
|
||||
"queue",
|
||||
"clustering",
|
||||
"---Operations---",
|
||||
"configuration",
|
||||
"scaling",
|
||||
"webhooks",
|
||||
"---Reference---",
|
||||
"client",
|
||||
"competition"
|
||||
]
|
||||
}
|
||||
@@ -81,12 +81,38 @@ FluxMQ uses a clean layered architecture:
|
||||
|
||||
## Documentation
|
||||
|
||||
- [Architecture](/docs/architecture): System design and component overview
|
||||
- [Configuration](/docs/configuration): Complete configuration reference
|
||||
- [Clustering](/docs/clustering): Distributed broker setup
|
||||
- [Client Libraries](/docs/client): Go MQTT and AMQP clients
|
||||
- [Durable Queues](/docs/queue): Queue system with consumer groups
|
||||
- [Webhooks](/docs/webhooks): Event notification system
|
||||
<Cards>
|
||||
<Card
|
||||
title="Architecture"
|
||||
href="/docs/architecture"
|
||||
description="System design and component overview"
|
||||
/>
|
||||
<Card
|
||||
title="Configuration"
|
||||
href="/docs/configuration"
|
||||
description="Complete configuration reference"
|
||||
/>
|
||||
<Card
|
||||
title="Clustering"
|
||||
href="/docs/clustering"
|
||||
description="Distributed broker setup"
|
||||
/>
|
||||
<Card
|
||||
title="Client Libraries"
|
||||
href="/docs/client"
|
||||
description="Go MQTT and AMQP clients"
|
||||
/>
|
||||
<Card
|
||||
title="Durable Queues"
|
||||
href="/docs/queue"
|
||||
description="Queue system with consumer groups"
|
||||
/>
|
||||
<Card
|
||||
title="Webhooks"
|
||||
href="/docs/webhooks"
|
||||
description="Event notification system"
|
||||
/>
|
||||
</Cards>
|
||||
|
||||
## Performance
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
---
|
||||
import '../styles/global.css';
|
||||
import '../styles/fumadocs-search.css';
|
||||
import HomeSearchBridge from '@/components/HomeSearchBridge';
|
||||
import "../styles/global.css";
|
||||
import "../styles/fumadocs-search.css";
|
||||
import HomeSearchBridge from "@/components/HomeSearchBridge";
|
||||
|
||||
interface Props {
|
||||
title?: string;
|
||||
@@ -9,9 +9,8 @@ interface Props {
|
||||
}
|
||||
|
||||
const {
|
||||
title = 'FluxMQ - High-Performance Multi-Protocol Message Broker',
|
||||
description =
|
||||
'FluxMQ is a high-performance, multi-protocol message broker written in Go. Supports MQTT, WebSocket, HTTP and CoAP with durable queues and clustering.',
|
||||
title = "FluxMQ - High-Performance Multi-Protocol Message Broker",
|
||||
description = "FluxMQ is a high-performance, multi-protocol message broker written in Go. Supports MQTT, WebSocket, HTTP and CoAP with durable queues and clustering.",
|
||||
} = Astro.props;
|
||||
---
|
||||
|
||||
@@ -34,195 +33,353 @@ const {
|
||||
<link rel="canonical" href="https://absmach.eu/fluxmq/" />
|
||||
<script is:inline>
|
||||
(() => {
|
||||
const THEME_KEY = 'theme';
|
||||
const THEME_KEY = "theme";
|
||||
const stored = localStorage.getItem(THEME_KEY);
|
||||
const mode = stored === 'light' || stored === 'dark' || stored === 'system' ? stored : 'system';
|
||||
const preferred = window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
|
||||
const resolved = mode === 'system' ? preferred : mode;
|
||||
const mode =
|
||||
stored === "light" || stored === "dark" || stored === "system"
|
||||
? stored
|
||||
: "system";
|
||||
const preferred = window.matchMedia("(prefers-color-scheme: light)")
|
||||
.matches
|
||||
? "light"
|
||||
: "dark";
|
||||
const resolved = mode === "system" ? preferred : mode;
|
||||
document.documentElement.dataset.theme = resolved;
|
||||
document.documentElement.classList.toggle('dark', resolved === 'dark');
|
||||
document.documentElement.classList.toggle("dark", resolved === "dark");
|
||||
})();
|
||||
</script>
|
||||
</head>
|
||||
<body class="flex min-h-screen flex-col bg-theme text-[var(--flux-text)]">
|
||||
<HomeSearchBridge client:only="react" />
|
||||
|
||||
<header class="site-header z-50">
|
||||
<nav class="mx-auto flex min-h-[64px] w-[min(100%-2.5rem,1360px)] items-center gap-4" aria-label="Main navigation">
|
||||
<a class="animate-fade-in text-2xl font-bold md:text-[2.45rem]" style="line-height:1.1" href="/" aria-label="FluxMQ home">
|
||||
<span class="text-[var(--flux-blue)]">Flux</span><span class="text-[var(--flux-orange)]">MQ</span>
|
||||
</a>
|
||||
|
||||
<button
|
||||
class="inline-flex rounded-md border border-[var(--flux-pill-border)] bg-[var(--flux-pill-bg)] px-3 py-2 text-sm font-semibold text-[var(--flux-text)] md:hidden"
|
||||
type="button"
|
||||
aria-expanded="false"
|
||||
aria-controls="site-menu"
|
||||
data-menu-toggle
|
||||
>
|
||||
Menu
|
||||
</button>
|
||||
|
||||
<ul
|
||||
id="site-menu"
|
||||
class="absolute left-0 right-0 top-[63px] hidden flex-col items-start gap-4 border-b border-[var(--flux-header-border)] bg-[var(--flux-header-bg)] px-5 py-4 text-[0.95rem] font-normal md:static md:top-0 md:flex md:min-w-0 md:flex-1 md:flex-row md:items-center md:gap-7 md:border-0 md:bg-transparent md:p-0 md:pl-8"
|
||||
data-menu
|
||||
>
|
||||
<li><a class="nav-link" href="/#features">Features</a></li>
|
||||
<li><a class="nav-link" href="/#performance">Performance</a></li>
|
||||
<li><a class="nav-link" href="/#use-cases">Use Cases</a></li>
|
||||
<li><a class="nav-link" href="/#architecture">Architecture</a></li>
|
||||
<li><a class="nav-link" href="/#quick-start">Quick Start</a></li>
|
||||
<li><a class="nav-link" href="/docs/">Documentation</a></li>
|
||||
<li class="md:hidden"><a class="nav-link" href="https://github.com/absmach/fluxmq" target="_blank" rel="noopener noreferrer">GitHub</a></li>
|
||||
</ul>
|
||||
|
||||
<div class="ml-auto hidden items-center gap-2 md:flex">
|
||||
<button type="button" class="nav-search-pill" aria-label="Search docs" data-search-trigger>
|
||||
<span class="inline-flex items-center gap-2">
|
||||
<svg class="size-4" viewBox="0 0 20 20" fill="none" aria-hidden="true">
|
||||
<circle cx="9" cy="9" r="5.5" stroke="currentColor" stroke-width="1.6"></circle>
|
||||
<path d="M13 13L17 17" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"></path>
|
||||
</svg>
|
||||
<span>Search</span>
|
||||
</span>
|
||||
<span class="inline-flex items-center gap-1">
|
||||
<kbd class="kbd-chip" data-shortcut-mod>Ctrl</kbd>
|
||||
<kbd class="kbd-chip">K</kbd>
|
||||
</span>
|
||||
</button>
|
||||
|
||||
<button type="button" class="theme-toggle-pill" aria-label="Toggle theme" data-theme-toggle>
|
||||
<span class="theme-dot" data-theme-sun aria-hidden="true">
|
||||
<svg class="size-3.5" viewBox="0 0 20 20" fill="none">
|
||||
<circle cx="10" cy="10" r="3.2" stroke="currentColor" stroke-width="1.6"></circle>
|
||||
<path d="M10 2v2.2M10 15.8V18M2 10h2.2M15.8 10H18M4.6 4.6l1.5 1.5M13.9 13.9l1.5 1.5M15.4 4.6l-1.5 1.5M6.1 13.9l-1.5 1.5" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"></path>
|
||||
</svg>
|
||||
</span>
|
||||
<span class="theme-dot" data-theme-moon aria-hidden="true">
|
||||
<svg class="size-3.5" viewBox="0 0 20 20" fill="none">
|
||||
<path d="M13.8 13.9A6.2 6.2 0 0 1 6 6.2a6.7 6.7 0 1 0 7.8 7.7Z" stroke="currentColor" stroke-width="1.6" stroke-linejoin="round"></path>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
<body class="flex flex-col min-h-screen text-[var(--flux-text)]">
|
||||
<main class="flex flex-1 flex-col [--fd-layout-width:1400px]">
|
||||
<HomeSearchBridge client:only="react" />
|
||||
|
||||
<header id="nd-nav" class="sticky h-14 top-0 z-40" aria-label="Main">
|
||||
<div class="backdrop-blur-lg border-b transition-colors *:mx-auto *:max-w-(--fd-layout-width) bg-fd-background/80">
|
||||
<div style="position:relative">
|
||||
<nav class="flex h-14 w-full items-center px-4" aria-label="Main navigation">
|
||||
<a
|
||||
class="nav-icon-link"
|
||||
href="https://github.com/absmach/fluxmq"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
aria-label="FluxMQ GitHub repository"
|
||||
class="animate-fade-in text-2xl font-bold"
|
||||
style="line-height:1.1"
|
||||
href="/"
|
||||
aria-label="FluxMQ home"
|
||||
>
|
||||
<svg class="size-5" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
|
||||
<path d="M12 .5C5.65.5.5 5.66.5 12.03c0 5.1 3.3 9.43 7.88 10.96.58.11.79-.25.79-.57 0-.28-.01-1.04-.02-2.04-3.2.7-3.88-1.55-3.88-1.55-.53-1.35-1.28-1.7-1.28-1.7-1.05-.72.08-.71.08-.71 1.15.08 1.76 1.2 1.76 1.2 1.03 1.76 2.7 1.25 3.37.96.1-.75.4-1.25.72-1.54-2.56-.29-5.26-1.29-5.26-5.74 0-1.27.46-2.3 1.2-3.11-.12-.29-.52-1.46.12-3.04 0 0 .98-.32 3.2 1.19a11.1 11.1 0 0 1 5.82 0c2.22-1.51 3.2-1.19 3.2-1.19.64 1.58.24 2.75.12 3.04.75.81 1.2 1.84 1.2 3.11 0 4.46-2.7 5.44-5.28 5.73.42.36.78 1.06.78 2.14 0 1.54-.01 2.78-.01 3.16 0 .31.21.68.8.56A11.54 11.54 0 0 0 23.5 12.03C23.5 5.66 18.35.5 12 .5Z" />
|
||||
</svg>
|
||||
<span class="text-[var(--flux-blue)]">Flux</span><span
|
||||
class="text-[var(--flux-orange)]">MQ</span
|
||||
>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="ml-auto flex items-center gap-2 md:hidden">
|
||||
<button type="button" class="theme-toggle-pill" aria-label="Toggle theme" data-theme-toggle>
|
||||
<span class="theme-dot" data-theme-sun aria-hidden="true">
|
||||
<svg class="size-3.5" viewBox="0 0 20 20" fill="none">
|
||||
<circle cx="10" cy="10" r="3.2" stroke="currentColor" stroke-width="1.6"></circle>
|
||||
<path d="M10 2v2.2M10 15.8V18M2 10h2.2M15.8 10H18M4.6 4.6l1.5 1.5M13.9 13.9l1.5 1.5M15.4 4.6l-1.5 1.5M6.1 13.9l-1.5 1.5" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"></path>
|
||||
</svg>
|
||||
</span>
|
||||
<span class="theme-dot" data-theme-moon aria-hidden="true">
|
||||
<svg class="size-3.5" viewBox="0 0 20 20" fill="none">
|
||||
<path d="M13.8 13.9A6.2 6.2 0 0 1 6 6.2a6.7 6.7 0 1 0 7.8 7.7Z" stroke="currentColor" stroke-width="1.6" stroke-linejoin="round"></path>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
<a
|
||||
class="nav-icon-link"
|
||||
href="https://github.com/absmach/fluxmq"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
aria-label="FluxMQ GitHub repository"
|
||||
>
|
||||
<svg class="size-5" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
|
||||
<path d="M12 .5C5.65.5.5 5.66.5 12.03c0 5.1 3.3 9.43 7.88 10.96.58.11.79-.25.79-.57 0-.28-.01-1.04-.02-2.04-3.2.7-3.88-1.55-3.88-1.55-.53-1.35-1.28-1.7-1.28-1.7-1.05-.72.08-.71.08-.71 1.15.08 1.76 1.2 1.76 1.2 1.03 1.76 2.7 1.25 3.37.96.1-.75.4-1.25.72-1.54-2.56-.29-5.26-1.29-5.26-5.74 0-1.27.46-2.3 1.2-3.11-.12-.29-.52-1.46.12-3.04 0 0 .98-.32 3.2 1.19a11.1 11.1 0 0 1 5.82 0c2.22-1.51 3.2-1.19 3.2-1.19.64 1.58.24 2.75.12 3.04.75.81 1.2 1.84 1.2 3.11 0 4.46-2.7 5.44-5.28 5.73.42.36.78 1.06.78 2.14 0 1.54-.01 2.78-.01 3.16 0 .31.21.68.8.56A11.54 11.54 0 0 0 23.5 12.03C23.5 5.66 18.35.5 12 .5Z" />
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</nav>
|
||||
</header>
|
||||
<button
|
||||
class="inline-flex rounded-md border border-[var(--flux-pill-border)] bg-[var(--flux-pill-bg)] px-3 py-2 text-sm font-semibold text-[var(--flux-text)] sm:hidden"
|
||||
type="button"
|
||||
aria-expanded="false"
|
||||
aria-controls="site-menu"
|
||||
data-menu-toggle
|
||||
>
|
||||
Menu
|
||||
</button>
|
||||
|
||||
<ul class="flex flex-row items-center gap-2 px-6 max-sm:hidden">
|
||||
<li class="list-none text-sm">
|
||||
<a class="[&_svg]:size-4 inline-flex items-center gap-1 p-2 text-fd-muted-foreground transition-colors hover:text-fd-accent-foreground data-[active=true]:text-fd-primary" data-active="false" data-radix-collection-item="" href="/#features">Features</a>
|
||||
</li>
|
||||
<li class="list-none text-sm">
|
||||
<a class="[&_svg]:size-4 inline-flex items-center gap-1 p-2 text-fd-muted-foreground transition-colors hover:text-fd-accent-foreground data-[active=true]:text-fd-primary" data-active="false" data-radix-collection-item="" href="/#performance">Performance</a>
|
||||
</li>
|
||||
<li class="list-none text-sm">
|
||||
<a class="[&_svg]:size-4 inline-flex items-center gap-1 p-2 text-fd-muted-foreground transition-colors hover:text-fd-accent-foreground data-[active=true]:text-fd-primary" data-active="false" data-radix-collection-item="" href="/#use-cases">Use Cases</a>
|
||||
</li>
|
||||
<li class="list-none text-sm">
|
||||
<a class="[&_svg]:size-4 inline-flex items-center gap-1 p-2 text-fd-muted-foreground transition-colors hover:text-fd-accent-foreground data-[active=true]:text-fd-primary" data-active="false" data-radix-collection-item="" href="/#architecture">Architecture</a>
|
||||
</li>
|
||||
<li class="list-none text-sm">
|
||||
<a class="[&_svg]:size-4 inline-flex items-center gap-1 p-2 text-fd-muted-foreground transition-colors hover:text-fd-accent-foreground data-[active=true]:text-fd-primary" data-active="false" data-radix-collection-item="" href="/#quick-start">Quick Start</a>
|
||||
</li>
|
||||
<li class="list-none text-sm">
|
||||
<a class="[&_svg]:size-4 inline-flex items-center gap-1 p-2 text-fd-muted-foreground transition-colors hover:text-fd-accent-foreground data-[active=true]:text-fd-primary" data-active="false" data-radix-collection-item="" href="/docs">Documentation</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<ul
|
||||
id="site-menu"
|
||||
class="absolute left-0 right-0 top-[55px] hidden flex-col items-start gap-4 border-b border-[var(--flux-header-border)] bg-[var(--flux-header-bg)] px-5 py-4 text-[0.95rem] font-normal sm:hidden"
|
||||
data-menu
|
||||
>
|
||||
<li><a class="nav-link" href="/#features">Features</a></li>
|
||||
<li><a class="nav-link" href="/#performance">Performance</a></li>
|
||||
<li><a class="nav-link" href="/#use-cases">Use Cases</a></li>
|
||||
<li><a class="nav-link" href="/#architecture">Architecture</a></li>
|
||||
<li><a class="nav-link" href="/#quick-start">Quick Start</a></li>
|
||||
<li><a class="nav-link" href="/docs">Documentation</a></li>
|
||||
<li>
|
||||
<a
|
||||
class="nav-link"
|
||||
href="https://github.com/absmach/fluxmq"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer">GitHub</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<div class="flex flex-row items-center justify-end gap-1.5 flex-1 max-lg:hidden">
|
||||
<button
|
||||
type="button"
|
||||
data-search-full=""
|
||||
data-search-trigger
|
||||
class="inline-flex items-center gap-2 border bg-fd-secondary/50 p-1.5 text-sm text-fd-muted-foreground transition-colors hover:bg-fd-accent hover:text-fd-accent-foreground w-full rounded-full ps-2.5 max-w-[240px]"
|
||||
aria-label="Search docs"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="lucide lucide-search size-4"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path d="m21 21-4.34-4.34"></path>
|
||||
<circle cx="11" cy="11" r="8"></circle>
|
||||
</svg>
|
||||
Search
|
||||
<div class="ms-auto inline-flex gap-0.5">
|
||||
<kbd
|
||||
class="rounded-md border bg-fd-background px-1.5"
|
||||
data-shortcut-mod>Ctrl</kbd
|
||||
>
|
||||
<kbd class="rounded-md border bg-fd-background px-1.5">K</kbd>
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<button
|
||||
class="inline-flex items-center rounded-full border p-1"
|
||||
aria-label="Toggle Theme"
|
||||
data-theme-toggle
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="lucide lucide-sun size-6.5 rounded-full p-1.5 text-fd-muted-foreground"
|
||||
aria-hidden="true"
|
||||
data-theme-sun
|
||||
>
|
||||
<circle cx="12" cy="12" r="4"></circle>
|
||||
<path d="M12 2v2"></path>
|
||||
<path d="M12 20v2"></path>
|
||||
<path d="m4.93 4.93 1.41 1.41"></path>
|
||||
<path d="m17.66 17.66 1.41 1.41"></path>
|
||||
<path d="M2 12h2"></path>
|
||||
<path d="M20 12h2"></path>
|
||||
<path d="m6.34 17.66-1.41 1.41"></path>
|
||||
<path d="m19.07 4.93-1.41 1.41"></path>
|
||||
</svg>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="lucide lucide-moon size-6.5 rounded-full p-1.5 text-fd-muted-foreground"
|
||||
aria-hidden="true"
|
||||
data-theme-moon
|
||||
>
|
||||
<path
|
||||
d="M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401"
|
||||
></path>
|
||||
</svg>
|
||||
</button>
|
||||
|
||||
<ul class="flex flex-row gap-2 items-center empty:hidden">
|
||||
<li class="list-none -mx-1 first:ms-0 last:me-0">
|
||||
<a
|
||||
href="https://github.com/absmach/fluxmq"
|
||||
rel="noreferrer noopener"
|
||||
target="_blank"
|
||||
aria-label="github"
|
||||
class="inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors duration-100 disabled:pointer-events-none disabled:opacity-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-fd-ring hover:bg-fd-accent hover:text-fd-accent-foreground p-1.5 [&_svg]:size-5"
|
||||
>
|
||||
<svg role="img" viewBox="0 0 24 24" fill="currentColor">
|
||||
<path
|
||||
d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"
|
||||
></path>
|
||||
</svg>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="ml-auto flex items-center gap-2 md:hidden">
|
||||
<button
|
||||
type="button"
|
||||
class="theme-toggle-pill"
|
||||
aria-label="Toggle theme"
|
||||
data-theme-toggle
|
||||
>
|
||||
<span class="theme-dot" data-theme-sun aria-hidden="true">
|
||||
<svg
|
||||
class="size-full"
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<circle cx="12" cy="12" r="4"></circle>
|
||||
<path d="M12 2v2"></path>
|
||||
<path d="M12 20v2"></path>
|
||||
<path d="m4.93 4.93 1.41 1.41"></path>
|
||||
<path d="m17.66 17.66 1.41 1.41"></path>
|
||||
<path d="M2 12h2"></path>
|
||||
<path d="M20 12h2"></path>
|
||||
<path d="m6.34 17.66-1.41 1.41"></path>
|
||||
<path d="m19.07 4.93-1.41 1.41"></path>
|
||||
</svg>
|
||||
</span>
|
||||
<span class="theme-dot" data-theme-moon aria-hidden="true">
|
||||
<svg
|
||||
class="size-full"
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
>
|
||||
<path
|
||||
d="M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401"
|
||||
></path>
|
||||
</svg>
|
||||
</span>
|
||||
</button>
|
||||
<a
|
||||
class="nav-icon-link"
|
||||
href="https://github.com/absmach/fluxmq"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
aria-label="FluxMQ GitHub repository"
|
||||
>
|
||||
<svg
|
||||
class="size-5"
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
d="M12 .5C5.65.5.5 5.66.5 12.03c0 5.1 3.3 9.43 7.88 10.96.58.11.79-.25.79-.57 0-.28-.01-1.04-.02-2.04-3.2.7-3.88-1.55-3.88-1.55-.53-1.35-1.28-1.7-1.28-1.7-1.05-.72.08-.71.08-.71 1.15.08 1.76 1.2 1.76 1.2 1.03 1.76 2.7 1.25 3.37.96.1-.75.4-1.25.72-1.54-2.56-.29-5.26-1.29-5.26-5.74 0-1.27.46-2.3 1.2-3.11-.12-.29-.52-1.46.12-3.04 0 0 .98-.32 3.2 1.19a11.1 11.1 0 0 1 5.82 0c2.22-1.51 3.2-1.19 3.2-1.19.64 1.58.24 2.75.12 3.04.75.81 1.2 1.84 1.2 3.11 0 4.46-2.7 5.44-5.28 5.73.42.36.78 1.06.78 2.14 0 1.54-.01 2.78-.01 3.16 0 .31.21.68.8.56A11.54 11.54 0 0 0 23.5 12.03C23.5 5.66 18.35.5 12 .5Z"
|
||||
></path>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
<div class="flex w-full justify-center"></div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<slot />
|
||||
</main>
|
||||
|
||||
<script is:inline>
|
||||
const THEME_KEY = 'theme';
|
||||
const THEME_KEY = "theme";
|
||||
|
||||
const setTheme = (mode) => {
|
||||
const preferred = window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark';
|
||||
const resolved = mode === 'system' ? preferred : mode;
|
||||
const preferred = window.matchMedia("(prefers-color-scheme: light)")
|
||||
.matches
|
||||
? "light"
|
||||
: "dark";
|
||||
const resolved = mode === "system" ? preferred : mode;
|
||||
document.documentElement.dataset.theme = resolved;
|
||||
document.documentElement.classList.toggle('dark', resolved === 'dark');
|
||||
document.documentElement.classList.toggle("dark", resolved === "dark");
|
||||
localStorage.setItem(THEME_KEY, mode);
|
||||
updateThemeIcons(resolved);
|
||||
};
|
||||
|
||||
const updateThemeIcons = (resolved) => {
|
||||
document.querySelectorAll('[data-theme-sun]').forEach((sun) => {
|
||||
sun.classList.toggle('theme-dot-active', resolved === 'light');
|
||||
document.querySelectorAll("[data-theme-sun]").forEach((sun) => {
|
||||
sun.classList.toggle("theme-dot-active", resolved === "light");
|
||||
});
|
||||
document.querySelectorAll('[data-theme-moon]').forEach((moon) => {
|
||||
moon.classList.toggle('theme-dot-active', resolved === 'dark');
|
||||
document.querySelectorAll("[data-theme-moon]").forEach((moon) => {
|
||||
moon.classList.toggle("theme-dot-active", resolved === "dark");
|
||||
});
|
||||
};
|
||||
|
||||
document.querySelectorAll('[data-theme-toggle]').forEach((toggleTheme) => {
|
||||
const current = document.documentElement.dataset.theme === 'dark' ? 'dark' : 'light';
|
||||
updateThemeIcons(current);
|
||||
document
|
||||
.querySelectorAll("[data-theme-toggle]")
|
||||
.forEach((toggleTheme) => {
|
||||
const current =
|
||||
document.documentElement.dataset.theme === "dark"
|
||||
? "dark"
|
||||
: "light";
|
||||
updateThemeIcons(current);
|
||||
|
||||
toggleTheme.addEventListener('click', () => {
|
||||
const active = document.documentElement.dataset.theme === 'dark' ? 'dark' : 'light';
|
||||
const next = active === 'dark' ? 'light' : 'dark';
|
||||
setTheme(next);
|
||||
toggleTheme.addEventListener("click", () => {
|
||||
const active =
|
||||
document.documentElement.dataset.theme === "dark"
|
||||
? "dark"
|
||||
: "light";
|
||||
const next = active === "dark" ? "light" : "dark";
|
||||
setTheme(next);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const openSearch = () => {
|
||||
if (typeof window.__fluxmqOpenSearch === 'function') {
|
||||
if (typeof window.__fluxmqOpenSearch === "function") {
|
||||
window.__fluxmqOpenSearch();
|
||||
return;
|
||||
}
|
||||
|
||||
window.dispatchEvent(new CustomEvent('fluxmq:open-search'));
|
||||
window.dispatchEvent(new CustomEvent("fluxmq:open-search"));
|
||||
};
|
||||
|
||||
const searchTrigger = document.querySelector('[data-search-trigger]');
|
||||
const searchTrigger = document.querySelector("[data-search-trigger]");
|
||||
if (searchTrigger) {
|
||||
searchTrigger.addEventListener('click', openSearch);
|
||||
searchTrigger.addEventListener("click", openSearch);
|
||||
}
|
||||
|
||||
const shortcutMod = document.querySelector('[data-shortcut-mod]');
|
||||
const shortcutMod = document.querySelector("[data-shortcut-mod]");
|
||||
if (shortcutMod && /(Mac|iPhone|iPad|iPod)/i.test(navigator.userAgent)) {
|
||||
shortcutMod.textContent = '⌘';
|
||||
shortcutMod.textContent = "⌘";
|
||||
}
|
||||
|
||||
window.addEventListener('keydown', (event) => {
|
||||
if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === 'k') {
|
||||
window.addEventListener("keydown", (event) => {
|
||||
if (
|
||||
(event.ctrlKey || event.metaKey) &&
|
||||
event.key.toLowerCase() === "k"
|
||||
) {
|
||||
event.preventDefault();
|
||||
openSearch();
|
||||
}
|
||||
});
|
||||
|
||||
window.matchMedia('(prefers-color-scheme: light)').addEventListener('change', () => {
|
||||
const stored = localStorage.getItem(THEME_KEY);
|
||||
if (!stored || stored === 'system') setTheme('system');
|
||||
});
|
||||
window
|
||||
.matchMedia("(prefers-color-scheme: light)")
|
||||
.addEventListener("change", () => {
|
||||
const stored = localStorage.getItem(THEME_KEY);
|
||||
if (!stored || stored === "system") setTheme("system");
|
||||
});
|
||||
|
||||
const toggle = document.querySelector('[data-menu-toggle]');
|
||||
const menu = document.querySelector('[data-menu]');
|
||||
const toggle = document.querySelector("[data-menu-toggle]");
|
||||
const menu = document.querySelector("[data-menu]");
|
||||
if (toggle && menu) {
|
||||
toggle.addEventListener('click', () => {
|
||||
const expanded = toggle.getAttribute('aria-expanded') === 'true';
|
||||
toggle.setAttribute('aria-expanded', String(!expanded));
|
||||
menu.classList.toggle('hidden', expanded);
|
||||
menu.classList.toggle('flex', !expanded);
|
||||
toggle.addEventListener("click", () => {
|
||||
const expanded = toggle.getAttribute("aria-expanded") === "true";
|
||||
toggle.setAttribute("aria-expanded", String(!expanded));
|
||||
menu.classList.toggle("hidden", expanded);
|
||||
menu.classList.toggle("flex", !expanded);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -9,7 +9,7 @@ export const source = loader({
|
||||
baseUrl: '/docs',
|
||||
});
|
||||
|
||||
const docs = import.meta.glob('/src/content/docs/docs/**/*.{md,mdx}');
|
||||
const docs = import.meta.glob('/src/content/docs/**/*.{md,mdx}');
|
||||
|
||||
export async function getFullExport(entry: CollectionEntry<'docs'>) {
|
||||
return (await docs['/' + entry.filePath!]()) as {
|
||||
@@ -28,7 +28,7 @@ async function createSource() {
|
||||
};
|
||||
|
||||
for (const page of await getCollection('docs')) {
|
||||
const virtualPath = path.relative('src/content/docs/docs', page.filePath!);
|
||||
const virtualPath = path.relative('src/content/docs', page.filePath!);
|
||||
|
||||
out.files.push({
|
||||
type: 'page',
|
||||
@@ -41,7 +41,7 @@ async function createSource() {
|
||||
}
|
||||
|
||||
for (const meta of await getCollection('meta')) {
|
||||
const virtualPath = path.relative('src/content/docs/docs', meta.filePath!);
|
||||
const virtualPath = path.relative('src/content/docs', meta.filePath!);
|
||||
|
||||
out.files.push({
|
||||
type: 'meta',
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
import { render, type CollectionEntry } from 'astro:content';
|
||||
import { Docs } from '@/components/docs';
|
||||
import defaultMdxComponents from 'fumadocs-ui/mdx';
|
||||
import '@/styles/docs.css';
|
||||
import { source } from '@/lib/source';
|
||||
import Layout from '@/components/layout.astro';
|
||||
import type { TOCItemType } from 'fumadocs-core/toc';
|
||||
@@ -12,10 +11,22 @@ interface Props {
|
||||
}
|
||||
|
||||
export async function getStaticPaths() {
|
||||
return source.getPages().map((page) => ({
|
||||
const pages = source.getPages();
|
||||
const paths = pages.map((page) => ({
|
||||
params: { slug: page.slugs.length > 0 ? page.slugs.join('/') : undefined },
|
||||
props: { page: page.data._raw },
|
||||
}));
|
||||
|
||||
// Alias the root docs page to `/docs/index` to avoid edge-case 404s in some dev/preview setups.
|
||||
const rootPage = pages.find((page) => page.slugs.length === 0);
|
||||
if (rootPage) {
|
||||
paths.push({
|
||||
params: { slug: 'index' },
|
||||
props: { page: rootPage.data._raw },
|
||||
});
|
||||
}
|
||||
|
||||
return paths;
|
||||
}
|
||||
|
||||
const { page } = Astro.props;
|
||||
@@ -37,12 +48,10 @@ const toc: TOCItemType[] = headings.map((heading) => ({
|
||||
pathname={Astro.url.pathname}
|
||||
params={Astro.params as Record<string, string | string[]>}
|
||||
page={{ toc }}
|
||||
title={page.data.title}
|
||||
description={page.data.description}
|
||||
client:load
|
||||
>
|
||||
<h1 class="text-3xl font-semibold">{page.data.title}</h1>
|
||||
<p class="mb-8 text-lg text-fd-muted-foreground">{page.data.description}</p>
|
||||
<div class="prose flex-1">
|
||||
<Content components={{ ...defaultMdxComponents }} />
|
||||
</div>
|
||||
<Content components={{ ...defaultMdxComponents }} />
|
||||
</Docs>
|
||||
</Layout>
|
||||
|
||||
@@ -11,12 +11,14 @@ import UseCasesSection from '../components/home/UseCasesSection.astro';
|
||||
---
|
||||
|
||||
<BaseLayout>
|
||||
<HeroSection />
|
||||
<FeaturesSection />
|
||||
<PerformanceSection />
|
||||
<UseCasesSection />
|
||||
<ArchitectureSection />
|
||||
<QuickStartSection />
|
||||
<NewsletterSection />
|
||||
<FooterSection />
|
||||
<main class="min-h-screen bg-theme">
|
||||
<HeroSection />
|
||||
<FeaturesSection />
|
||||
<PerformanceSection />
|
||||
<UseCasesSection />
|
||||
<ArchitectureSection />
|
||||
<QuickStartSection />
|
||||
<NewsletterSection />
|
||||
<FooterSection />
|
||||
</main>
|
||||
</BaseLayout>
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
@import 'tailwindcss';
|
||||
@import 'fumadocs-ui/css/neutral.css';
|
||||
@import 'fumadocs-ui/css/preset.css';
|
||||
|
||||
:root {
|
||||
--flux-blue: hsl(213.64deg 58.41% 44.31%);
|
||||
@@ -47,6 +49,10 @@ body {
|
||||
background: var(--flux-bg);
|
||||
}
|
||||
|
||||
html {
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
|
||||
p {
|
||||
font-size: 1.0625rem;
|
||||
line-height: 1.7;
|
||||
@@ -152,56 +158,36 @@ p {
|
||||
}
|
||||
|
||||
.nav-link {
|
||||
@apply inline-flex text-[1.03rem] font-medium transition-colors;
|
||||
color: color-mix(in srgb, var(--flux-text) 65%, transparent);
|
||||
@apply inline-flex items-center gap-1 p-2 text-sm font-normal transition-colors;
|
||||
color: var(--color-fd-muted-foreground);
|
||||
}
|
||||
|
||||
.nav-link:hover {
|
||||
color: var(--flux-text);
|
||||
color: var(--color-fd-accent-foreground);
|
||||
}
|
||||
|
||||
.nav-search-pill {
|
||||
@apply inline-flex min-w-[252px] items-center justify-between rounded-full border px-4 py-2 text-[1.05rem] leading-none transition;
|
||||
border-color: var(--flux-pill-border);
|
||||
background: var(--flux-pill-bg);
|
||||
color: var(--flux-pill-text);
|
||||
}
|
||||
|
||||
.nav-search-pill:hover {
|
||||
border-color: color-mix(in srgb, var(--flux-blue) 35%, var(--flux-pill-border));
|
||||
color: color-mix(in srgb, var(--flux-text) 75%, transparent);
|
||||
@apply inline-flex w-full max-w-[240px] items-center gap-2 rounded-full border bg-fd-secondary/50 p-1.5 ps-2.5 text-sm text-fd-muted-foreground transition-colors hover:bg-fd-accent hover:text-fd-accent-foreground;
|
||||
}
|
||||
|
||||
.kbd-chip {
|
||||
@apply inline-flex items-center justify-center rounded-md border px-1.5 py-[0.14rem] text-[0.72rem] font-semibold;
|
||||
border-color: var(--flux-pill-border);
|
||||
background: var(--flux-bg);
|
||||
color: var(--flux-pill-text);
|
||||
@apply rounded-md border bg-fd-background px-1.5;
|
||||
}
|
||||
|
||||
.theme-toggle-pill {
|
||||
@apply inline-flex items-center gap-0.5 rounded-full border p-[0.2rem];
|
||||
border-color: var(--flux-pill-border);
|
||||
background: var(--flux-pill-bg);
|
||||
}
|
||||
|
||||
.theme-toggle-pill:hover {
|
||||
border-color: color-mix(in srgb, var(--flux-orange) 45%, var(--flux-pill-border));
|
||||
@apply inline-flex items-center rounded-full border p-1;
|
||||
}
|
||||
|
||||
.theme-dot {
|
||||
@apply inline-flex size-6 items-center justify-center rounded-full transition-colors;
|
||||
color: var(--flux-pill-text);
|
||||
@apply size-6.5 rounded-full p-1.5 text-fd-muted-foreground;
|
||||
}
|
||||
|
||||
.theme-dot-active {
|
||||
background: var(--flux-bg);
|
||||
color: var(--flux-icon);
|
||||
box-shadow: 0 0 0 1px var(--flux-pill-border);
|
||||
@apply bg-fd-accent text-fd-accent-foreground;
|
||||
}
|
||||
|
||||
.nav-icon-link {
|
||||
@apply inline-flex items-center justify-center rounded-full p-1 transition-colors;
|
||||
@apply inline-flex size-8 items-center justify-center rounded-full p-1 transition-colors;
|
||||
color: var(--flux-icon);
|
||||
}
|
||||
|
||||
@@ -336,6 +322,16 @@ p {
|
||||
}
|
||||
|
||||
:focus-visible {
|
||||
outline: 2px solid var(--flux-focus-ring);
|
||||
outline: 2px solid var(--flux-orange);
|
||||
outline-offset: 2px;
|
||||
}
|
||||
|
||||
#nd-sidebar [data-active='true'] {
|
||||
color: var(--flux-orange) !important;
|
||||
background-color: rgb(249 163 42 / 10%) !important;
|
||||
border-left: 3px solid var(--flux-orange) !important;
|
||||
}
|
||||
|
||||
#nd-sidebar a:hover {
|
||||
color: var(--flux-blue) !important;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user