@assetsart/nylon-mesh 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/.github/workflows/release.yml +98 -0
  2. package/Cargo.lock +2965 -0
  3. package/Cargo.toml +33 -0
  4. package/README.md +104 -0
  5. package/bin/nylon-mesh.js +213 -0
  6. package/bun.lock +360 -0
  7. package/docs/content/docs/caching.mdx +85 -0
  8. package/docs/content/docs/configuration.mdx +115 -0
  9. package/docs/content/docs/index.mdx +58 -0
  10. package/docs/content/docs/load-balancing.mdx +69 -0
  11. package/docs/content/docs/meta.json +9 -0
  12. package/docs/next.config.mjs +11 -0
  13. package/docs/package-lock.json +6099 -0
  14. package/docs/package.json +32 -0
  15. package/docs/postcss.config.mjs +7 -0
  16. package/docs/source.config.ts +23 -0
  17. package/docs/src/app/(home)/layout.tsx +6 -0
  18. package/docs/src/app/(home)/page.tsx +125 -0
  19. package/docs/src/app/api/search/route.ts +9 -0
  20. package/docs/src/app/docs/[[...slug]]/page.tsx +46 -0
  21. package/docs/src/app/docs/layout.tsx +11 -0
  22. package/docs/src/app/global.css +7 -0
  23. package/docs/src/app/layout.tsx +31 -0
  24. package/docs/src/app/llms-full.txt/route.ts +10 -0
  25. package/docs/src/app/llms.txt/route.ts +13 -0
  26. package/docs/src/app/og/docs/[...slug]/route.tsx +27 -0
  27. package/docs/src/components/ai/page-actions.tsx +240 -0
  28. package/docs/src/components/architecture-diagram.tsx +88 -0
  29. package/docs/src/components/benchmark.tsx +129 -0
  30. package/docs/src/components/configuration.tsx +107 -0
  31. package/docs/src/components/copy-button.tsx +29 -0
  32. package/docs/src/components/footer.tsx +37 -0
  33. package/docs/src/components/framework-logos.tsx +35 -0
  34. package/docs/src/lib/cn.ts +1 -0
  35. package/docs/src/lib/layout.shared.tsx +23 -0
  36. package/docs/src/lib/source.ts +27 -0
  37. package/docs/src/mdx-components.tsx +9 -0
  38. package/docs/tsconfig.json +46 -0
  39. package/nylon-mesh.yaml +41 -0
  40. package/package.json +23 -0
  41. package/scripts/publish.mjs +18 -0
  42. package/scripts/release.mjs +52 -0
  43. package/src/config.rs +91 -0
  44. package/src/main.rs +214 -0
  45. package/src/proxy/cache.rs +304 -0
  46. package/src/proxy/handlers.rs +76 -0
  47. package/src/proxy/load_balancer.rs +23 -0
  48. package/src/proxy/mod.rs +232 -0
  49. package/src/tls_accept.rs +119 -0
@@ -0,0 +1,88 @@
1
+ 'use client';
2
+
3
+ import { Globe, Server } from 'lucide-react';
4
+
5
+ export function ArchitectureDiagram() {
6
+ return (
7
+ <div className="text-center">
8
+ <h2 className="text-4xl font-extrabold mb-4 bg-linear-to-br from-fd-foreground to-emerald-500 bg-clip-text text-transparent tracking-tight">
9
+ How It Works
10
+ </h2>
11
+ <p className="text-lg text-fd-muted-foreground max-w-xl mx-auto mb-14 leading-relaxed">
12
+ Nylon Mesh intercepts every HTTP request, checks its 2-tier cache, and only hits your backend when absolutely necessary.
13
+ </p>
14
+
15
+ <div className="flex items-center justify-center flex-col md:flex-row flex-wrap md:flex-nowrap gap-2 md:gap-0 max-w-full mx-auto px-4">
16
+ {/* Client */}
17
+ <div className="flex flex-col items-center justify-center bg-fd-card/50 border border-fd-border rounded-2xl px-6 py-6 min-w-[140px] shrink-0 backdrop-blur-sm transition-all duration-300 hover:-translate-y-1 hover:shadow-xl hover:border-blue-500/30 group">
18
+ <div className="p-3 bg-blue-500/10 rounded-xl mb-3 group-hover:bg-blue-500/20 transition-colors">
19
+ <Globe className="w-8 h-8 text-blue-400" />
20
+ </div>
21
+ <div className="font-bold text-lg text-fd-foreground mb-0.5">Client</div>
22
+ <div className="text-xs text-fd-muted-foreground font-medium">Browser / CDN</div>
23
+ </div>
24
+
25
+ {/* Arrow 1 */}
26
+ <div className="hidden md:flex flex-col items-center gap-1.5 px-3 shrink">
27
+ <div className="flex items-center gap-0 w-full justify-center">
28
+ <div className="w-12 h-0.5 bg-linear-to-r from-emerald-500/30 to-emerald-500" />
29
+ <svg viewBox="0 0 12 12" width="12" height="12"><path d="M0 0 L12 6 L0 12 Z" fill="#10b981" /></svg>
30
+ </div>
31
+ <span className="text-[0.65rem] text-emerald-500/80 font-bold uppercase tracking-wider whitespace-nowrap">Request</span>
32
+ </div>
33
+
34
+ {/* Mobile Arrow 1 */}
35
+ <div className="md:hidden flex items-center justify-center my-2">
36
+ <svg viewBox="0 0 12 12" width="12" height="12" className="rotate-90"><path d="M0 0 L12 6 L0 12 Z" fill="#10b981" /></svg>
37
+ </div>
38
+
39
+ {/* Nylon Mesh */}
40
+ <div className="flex flex-col items-center border border-emerald-500/30 bg-linear-to-br from-emerald-500/5 to-transparent rounded-3xl px-8 py-6 min-w-[240px] shrink-0 shadow-xl shadow-emerald-500/10 transition-all duration-300 hover:-translate-y-1 hover:shadow-emerald-500/20 hover:border-emerald-500/50 relative overflow-hidden group">
41
+ <div className="absolute inset-0 bg-linear-to-b from-emerald-500/5 to-transparent opacity-0 group-hover:opacity-100 transition-opacity" />
42
+
43
+ <div className="relative z-10 w-full flex flex-col items-center">
44
+ <div className="font-black text-xl text-transparent bg-clip-text bg-linear-to-r from-emerald-400 to-cyan-500 mb-0.5">Nylon Mesh</div>
45
+ <div className="text-xs text-fd-muted-foreground font-semibold uppercase tracking-wider mb-5">Pingora Core</div>
46
+
47
+ <div className="w-full flex flex-col gap-2">
48
+ <div className="flex items-center gap-3 bg-fd-card/80 border border-fd-border rounded-xl px-4 py-2.5 text-sm transition-colors group-hover:border-emerald-500/30 shadow-sm min-w-44">
49
+ <span className="bg-emerald-500/20 text-emerald-400 font-black text-[0.65rem] px-1.5 py-0.5 rounded tracking-wide">T1</span>
50
+ <span className="text-fd-foreground font-bold">RAM Cache</span>
51
+ <span className="ml-auto text-emerald-500 font-mono font-bold">~0.01ms</span>
52
+ </div>
53
+ <div className="text-[0.65rem] text-fd-muted-foreground text-center font-bold tracking-widest uppercase py-0.5">↓ miss</div>
54
+ <div className="flex items-center gap-3 bg-fd-card/80 border border-fd-border rounded-xl px-4 py-2.5 text-sm transition-colors group-hover:border-blue-500/30 shadow-sm min-w-44 whitespace-nowrap">
55
+ <span className="bg-blue-500/20 text-blue-400 font-black text-[0.65rem] px-1.5 py-0.5 rounded tracking-wide">T2</span>
56
+ <span className="text-fd-foreground font-bold text-xs">Redis/Dragonfly</span>
57
+ <span className="ml-auto pl-2 text-blue-400 font-mono font-bold">~0.5ms</span>
58
+ </div>
59
+ </div>
60
+ </div>
61
+ </div>
62
+
63
+ {/* Arrow 2 */}
64
+ <div className="hidden md:flex flex-col items-center gap-1.5 px-3 shrink">
65
+ <div className="flex items-center gap-0 opacity-60 group-hover:opacity-100 transition-opacity w-full justify-center">
66
+ <div className="w-12 h-0.5 bg-[repeating-linear-gradient(90deg,#6e7681_0px,#6e7681_4px,transparent_4px,transparent_8px)]" />
67
+ <svg viewBox="0 0 12 12" width="12" height="12"><path d="M0 0 L12 6 L0 12 Z" fill="#6e7681" /></svg>
68
+ </div>
69
+ <span className="text-[0.65rem] text-fd-muted-foreground font-semibold uppercase tracking-wider whitespace-nowrap">Cache Miss</span>
70
+ </div>
71
+
72
+ {/* Mobile Arrow 2 */}
73
+ <div className="md:hidden flex items-center justify-center my-2 opacity-60">
74
+ <svg viewBox="0 0 12 12" width="12" height="12" className="rotate-90"><path d="M0 0 L12 6 L0 12 Z" fill="#6e7681" /></svg>
75
+ </div>
76
+
77
+ {/* Backend */}
78
+ <div className="flex flex-col items-center justify-center bg-fd-card/50 border border-fd-border rounded-2xl px-6 py-6 min-w-[140px] shrink-0 backdrop-blur-sm transition-all duration-300 hover:-translate-y-1 hover:shadow-xl hover:border-purple-500/30 group">
79
+ <div className="p-3 bg-purple-500/10 rounded-xl mb-3 group-hover:bg-purple-500/20 transition-colors">
80
+ <Server className="w-8 h-8 text-purple-400" />
81
+ </div>
82
+ <div className="font-bold text-lg text-fd-foreground mb-0.5">Backend</div>
83
+ <div className="text-xs text-fd-muted-foreground font-medium">Next.js / Nuxt</div>
84
+ </div>
85
+ </div>
86
+ </div>
87
+ );
88
+ }
@@ -0,0 +1,129 @@
1
+ 'use client';
2
+
3
+ import { useEffect, useRef, useState } from 'react';
4
+
5
+ export function Benchmark() {
6
+ const [vanillaReqSec, setVanillaReqSec] = useState(0);
7
+ const [vanillaLatency, setVanillaLatency] = useState('0.00');
8
+ const [vanillaTransfer, setVanillaTransfer] = useState(0);
9
+ const [meshReqSec, setMeshReqSec] = useState(0);
10
+ const [meshLatency, setMeshLatency] = useState('0.00');
11
+ const [meshTransfer, setMeshTransfer] = useState(0);
12
+ const [multiplier, setMultiplier] = useState('0.0');
13
+ const animationId = useRef<number | null>(null);
14
+
15
+ useEffect(() => {
16
+ const vTargetReq = 5181, vTargetLat = 23.20, vTargetTrans = 15;
17
+ const mTargetReq = 100321, mTargetLat = 1.19, mTargetTrans = 292;
18
+ const targetMultiplier = mTargetReq / vTargetReq;
19
+ const duration = 2000;
20
+ let startTime: number | null = null;
21
+
22
+ const animate = (timestamp: number) => {
23
+ if (!startTime) startTime = timestamp;
24
+ const elapsed = timestamp - Math.max(startTime, 0);
25
+
26
+ if (elapsed < duration) {
27
+ const p = 1 - Math.pow(1 - elapsed / duration, 4);
28
+ setVanillaReqSec(Math.floor(p * vTargetReq));
29
+ setVanillaLatency((p * vTargetLat).toFixed(2));
30
+ setVanillaTransfer(Math.floor(p * vTargetTrans));
31
+ setMeshReqSec(Math.floor(p * mTargetReq));
32
+ setMeshLatency((p * mTargetLat).toFixed(2));
33
+ setMeshTransfer(Math.floor(p * mTargetTrans));
34
+ setMultiplier((p * targetMultiplier).toFixed(1));
35
+ } else {
36
+ const t = timestamp / 1000;
37
+ const vr = Math.floor(vTargetReq + Math.sin(t * 2) * 150 + Math.cos(t * 3.5) * 80);
38
+ setVanillaReqSec(vr);
39
+ setVanillaLatency(Math.max(10, vTargetLat + Math.sin(t * 3) * 0.8 + Math.cos(t * 1.8) * 0.5).toFixed(2));
40
+ setVanillaTransfer(Math.floor(vTargetTrans + Math.sin(t * 2.5) * 1 + Math.cos(t * 4) * 0.5));
41
+ const mr = Math.floor(mTargetReq + Math.sin(t * 2) * 800 + Math.cos(t * 3.5) * 500);
42
+ setMeshReqSec(mr);
43
+ setMeshLatency(Math.max(0.8, mTargetLat + Math.sin(t * 3) * 0.08 + Math.cos(t * 1.8) * 0.05).toFixed(2));
44
+ setMeshTransfer(Math.floor(mTargetTrans + Math.sin(t * 2.5) * 6 + Math.cos(t * 4) * 4));
45
+ setMultiplier((mr / Math.max(vr, 1)).toFixed(1));
46
+ }
47
+ animationId.current = requestAnimationFrame(animate);
48
+ };
49
+
50
+ animationId.current = requestAnimationFrame(animate);
51
+ return () => { if (animationId.current) cancelAnimationFrame(animationId.current); };
52
+ }, []);
53
+
54
+ return (
55
+ <div className="relative text-center py-8 px-6 pb-16 overflow-hidden">
56
+ <h2 className="text-4xl font-extrabold mb-4 bg-linear-to-br from-fd-foreground to-emerald-500 bg-clip-text text-transparent tracking-tight animate-[slideUp_0.6s_ease-out]">
57
+ Blazing Fast on Edge
58
+ </h2>
59
+ <p className="text-lg text-fd-muted-foreground mb-10 leading-relaxed animate-[slideUp_0.6s_ease-out_0.1s_both]">
60
+ Tested with <code className="bg-emerald-500/10 text-emerald-500 px-1.5 py-0.5 rounded font-semibold text-sm">oha</code> — 120 concurrent connections on <strong>Apple M1 Pro</strong> serving a default <code className="bg-emerald-500/10 text-emerald-500 px-1.5 py-0.5 rounded font-semibold text-sm">Next.js 16</code> app.
61
+ </p>
62
+
63
+ {/* Multiplier */}
64
+ <div className="flex items-baseline justify-center gap-1.5 mb-10 animate-[slideUp_0.6s_ease-out_0.2s_both]">
65
+ <span className="text-7xl font-black bg-linear-to-br from-emerald-500 via-green-500 to-cyan-400 bg-clip-text text-transparent leading-none tracking-tighter drop-shadow-[0_0_20px_rgba(16,185,129,0.3)]">
66
+ {multiplier}Ɨ
67
+ </span>
68
+ <span className="text-xl font-semibold text-fd-muted-foreground">faster</span>
69
+ </div>
70
+
71
+ {/* Cards */}
72
+ <div className="flex flex-col lg:flex-row items-stretch justify-center gap-6 lg:gap-8 mb-12 relative animate-[slideUp_0.6s_ease-out_0.3s_both] w-full max-w-5xl mx-auto">
73
+ {/* Mesh Card */}
74
+ <div className="flex-1 w-full rounded-2xl p-8 relative overflow-hidden bg-linear-to-br from-fd-card to-emerald-500/5 border border-emerald-500/25 shadow-lg shadow-emerald-500/10 transition-all duration-300 hover:-translate-y-1 hover:shadow-xl hover:shadow-emerald-500/20">
75
+ <div className="flex items-center justify-between mb-8">
76
+ <h3 className="text-xl font-bold text-fd-foreground m-0">With Nylon Mesh</h3>
77
+ <span className="text-xs font-bold tracking-wide px-2.5 py-1 rounded-full bg-emerald-500/15 text-emerald-500 border border-emerald-500/25">⚔ Cached</span>
78
+ </div>
79
+ <div className="grid grid-cols-2 gap-y-8 gap-x-4">
80
+ <div className="flex flex-col items-start col-span-2">
81
+ <span className="text-5xl font-bold bg-linear-to-r from-emerald-500 to-green-500 bg-clip-text text-transparent drop-shadow-[0_0_12px_rgba(16,185,129,0.3)] tabular-nums">{meshReqSec.toLocaleString()}</span>
82
+ <span className="text-xs uppercase tracking-wider font-semibold text-fd-muted-foreground mt-2">Requests / Second</span>
83
+ </div>
84
+ <div className="flex flex-col items-start">
85
+ <span className="text-2xl font-bold text-emerald-500 tabular-nums">{meshLatency}<small className="text-sm font-semibold text-emerald-500/50 ml-0.5">ms</small></span>
86
+ <span className="text-xs uppercase tracking-wider font-semibold text-fd-muted-foreground mt-1.5">Avg Latency</span>
87
+ </div>
88
+ <div className="flex flex-col items-start">
89
+ <span className="text-2xl font-bold text-emerald-500 tabular-nums">{meshTransfer}<small className="text-sm font-semibold text-emerald-500/50 ml-0.5">MB/s</small></span>
90
+ <span className="text-xs uppercase tracking-wider font-semibold text-fd-muted-foreground mt-1.5">Throughput</span>
91
+ </div>
92
+ </div>
93
+ </div>
94
+
95
+ {/* VS Badge (Desktop) */}
96
+ <div className="hidden lg:flex absolute left-1/2 top-[calc(50%+1rem)] -translate-x-1/2 -translate-y-1/2 items-center justify-center z-2">
97
+ <div className="w-12 h-12 rounded-full bg-fd-card border border-fd-border flex items-center justify-center font-extrabold italic text-fd-muted-foreground text-sm shadow-xl">VS</div>
98
+ </div>
99
+
100
+ {/* VS Badge (Mobile) */}
101
+ <div className="flex lg:hidden items-center justify-center my-2 z-2">
102
+ <div className="w-10 h-10 rounded-full bg-fd-card border border-fd-border flex items-center justify-center font-extrabold italic text-fd-muted-foreground text-sm shadow-lg">VS</div>
103
+ </div>
104
+
105
+ {/* Vanilla Card */}
106
+ <div className="flex-1 w-full rounded-2xl p-8 bg-fd-card/60 border border-fd-border opacity-85 transition-all duration-300 hover:-translate-y-1 hover:opacity-100">
107
+ <div className="flex items-center justify-between mb-8">
108
+ <h3 className="text-xl font-bold text-fd-foreground m-0">Vanilla Next.js</h3>
109
+ <span className="text-xs font-bold tracking-wide px-2.5 py-1 rounded-full bg-fd-muted-foreground/10 text-fd-muted-foreground border border-fd-muted-foreground/20">No Cache</span>
110
+ </div>
111
+ <div className="grid grid-cols-2 gap-y-8 gap-x-4">
112
+ <div className="flex flex-col items-start col-span-2">
113
+ <span className="text-5xl font-bold text-fd-muted-foreground tabular-nums">{vanillaReqSec.toLocaleString()}</span>
114
+ <span className="text-xs uppercase tracking-wider font-semibold text-fd-muted-foreground mt-2">Requests / Second</span>
115
+ </div>
116
+ <div className="flex flex-col items-start">
117
+ <span className="text-2xl font-bold text-fd-muted-foreground tabular-nums">{vanillaLatency}<small className="text-sm font-semibold text-fd-muted-foreground/70 ml-0.5">ms</small></span>
118
+ <span className="text-xs uppercase tracking-wider font-semibold text-fd-muted-foreground mt-1.5">Avg Latency</span>
119
+ </div>
120
+ <div className="flex flex-col items-start">
121
+ <span className="text-2xl font-bold text-fd-muted-foreground tabular-nums">{vanillaTransfer}<small className="text-sm font-semibold text-fd-muted-foreground/70 ml-0.5">MB/s</small></span>
122
+ <span className="text-xs uppercase tracking-wider font-semibold text-fd-muted-foreground mt-1.5">Throughput</span>
123
+ </div>
124
+ </div>
125
+ </div>
126
+ </div>
127
+ </div>
128
+ );
129
+ }
@@ -0,0 +1,107 @@
1
+ 'use client';
2
+
3
+ import { CopyButton } from '@/components/copy-button';
4
+
5
+ export function Configuration() {
6
+ const yamlContent = `listen: "0.0.0.0:3000"
7
+
8
+ upstreams:
9
+ - "127.0.0.1:3001"
10
+
11
+ # DragonflyDB is highly recommended over Redis for Tier 2
12
+ # redis_url: "redis://localhost:6379"
13
+
14
+ cache:
15
+ tier1_capacity: 10000
16
+ tier1_ttl_seconds: 3
17
+ tier2_ttl_seconds: 60
18
+ status: [200, 404]
19
+ content_types:
20
+ - "text/html"
21
+
22
+ bypass:
23
+ paths:
24
+ - "/_next/"
25
+ - "/api/"
26
+ extensions:
27
+ - ".ico"
28
+ - ".png"`;
29
+
30
+ return (
31
+ <div className="text-center max-w-4xl mx-auto px-4 mt-16 mb-0">
32
+ <h2 className="text-4xl font-extrabold mb-4 bg-linear-to-br from-fd-foreground to-emerald-500 bg-clip-text text-transparent tracking-tight">
33
+ Drop-in Configuration
34
+ </h2>
35
+ <p className="text-lg text-fd-muted-foreground max-w-xl mx-auto mb-10 leading-relaxed">
36
+ Everything is controlled through a single, declarative <code className="text-emerald-500 bg-emerald-500/10 px-1.5 py-0.5 rounded font-mono text-sm">yaml</code> file. No complex setups or hidden logic.
37
+ </p>
38
+
39
+ <div className="relative text-left">
40
+ {/* Glow behind terminal */}
41
+ <div className="absolute -inset-1 bg-linear-to-r from-emerald-500 to-cyan-500 rounded-3xl blur-xl opacity-20" />
42
+
43
+ {/* Terminal Window */}
44
+ <div className="relative rounded-2xl border border-white/10 bg-[#0d1117] shadow-2xl overflow-hidden ring-1 ring-white/5">
45
+ {/* Mac window controls */}
46
+ <div className="flex items-center justify-between px-4 py-3 border-b border-white/5 bg-[#161b22]">
47
+ <div className="flex gap-2 w-16">
48
+ <div className="w-3 h-3 rounded-full bg-red-500/80 border border-black/10"></div>
49
+ <div className="w-3 h-3 rounded-full bg-yellow-500/80 border border-black/10"></div>
50
+ <div className="w-3 h-3 rounded-full bg-green-500/80 border border-black/10"></div>
51
+ </div>
52
+ <div className="text-xs font-mono text-gray-400 font-medium">nylon-mesh.yaml</div>
53
+ <div className="w-16 flex justify-end">
54
+ <CopyButton text={yamlContent} />
55
+ </div>
56
+ </div>
57
+
58
+ {/* Code Body */}
59
+ <div className="p-6 md:p-8 overflow-x-auto">
60
+ <pre className="text-sm md:text-base font-mono leading-loose">
61
+ <code>
62
+ <span className="text-pink-400">listen</span><span className="text-gray-300">: </span><span className="text-green-400">"0.0.0.0:3000"</span>
63
+ {`\n\n`}
64
+ <span className="text-pink-400">upstreams</span><span className="text-gray-300">:</span>
65
+ {`\n`}
66
+ {` - `}<span className="text-green-400">"127.0.0.1:3001"</span>
67
+ {`\n\n`}
68
+ <span className="text-gray-500"># DragonflyDB is highly recommended over Redis for Tier 2</span>
69
+ {`\n`}
70
+ <span className="text-gray-500"># redis_url: "redis://localhost:6379"</span>
71
+ {`\n\n`}
72
+ <span className="text-pink-400">cache</span><span className="text-gray-300">:</span>
73
+ {`\n`}
74
+ {` `}<span className="text-blue-400">tier1_capacity</span><span className="text-gray-300">: </span><span className="text-yellow-400">10000</span>
75
+ {`\n`}
76
+ {` `}<span className="text-blue-400">tier1_ttl_seconds</span><span className="text-gray-300">: </span><span className="text-yellow-400">3</span>
77
+ {`\n`}
78
+ {` `}<span className="text-blue-400">tier2_ttl_seconds</span><span className="text-gray-300">: </span><span className="text-yellow-400">60</span>
79
+ {`\n`}
80
+ {` `}<span className="text-blue-400">status</span><span className="text-gray-300">: [</span><span className="text-yellow-400">200</span><span className="text-gray-300">, </span><span className="text-yellow-400">404</span><span className="text-gray-300">]</span>
81
+ {`\n`}
82
+ {` `}<span className="text-blue-400">content_types</span><span className="text-gray-300">:</span>
83
+ {`\n`}
84
+ {` - `}<span className="text-green-400">"text/html"</span>
85
+ {`\n\n`}
86
+ <span className="text-pink-400">bypass</span><span className="text-gray-300">:</span>
87
+ {`\n`}
88
+ {` `}<span className="text-blue-400">paths</span><span className="text-gray-300">:</span>
89
+ {`\n`}
90
+ {` - `}<span className="text-green-400">"/_next/"</span>
91
+ {`\n`}
92
+ {` - `}<span className="text-green-400">"/api/"</span>
93
+ {`\n`}
94
+ {` `}<span className="text-blue-400">extensions</span><span className="text-gray-300">:</span>
95
+ {`\n`}
96
+ {` - `}<span className="text-green-400">".ico"</span>
97
+ {`\n`}
98
+ {` - `}<span className="text-green-400">".png"</span>
99
+ {`\n`}
100
+ </code>
101
+ </pre>
102
+ </div>
103
+ </div>
104
+ </div>
105
+ </div>
106
+ );
107
+ }
@@ -0,0 +1,29 @@
1
+ "use client";
2
+
3
+ import { useState } from 'react';
4
+ import { Copy, Check } from 'lucide-react';
5
+
6
+ export function CopyButton({ text }: { text: string }) {
7
+ const [copied, setCopied] = useState(false);
8
+
9
+ const handleCopy = async () => {
10
+ try {
11
+ await navigator.clipboard.writeText(text);
12
+ setCopied(true);
13
+ setTimeout(() => setCopied(false), 2000);
14
+ } catch (err) {
15
+ console.error('Failed to copy text: ', err);
16
+ }
17
+ };
18
+
19
+ return (
20
+ <button
21
+ onClick={handleCopy}
22
+ className="text-fd-muted-foreground hover:text-fd-foreground transition-colors group-hover:text-emerald-500 cursor-pointer"
23
+ aria-label="Copy to clipboard"
24
+ title="Copy to clipboard"
25
+ >
26
+ {copied ? <Check className="w-4 h-4 text-emerald-500" /> : <Copy className="w-4 h-4" />}
27
+ </button>
28
+ );
29
+ }
@@ -0,0 +1,37 @@
1
+ import Link from 'next/link';
2
+
3
+ export function Footer() {
4
+ return (
5
+ <footer className="border-t border-fd-border/50 bg-fd-background py-12 lg:py-16 mt-auto">
6
+ <div className="max-w-6xl mx-auto px-4 flex flex-col md:flex-row items-center md:items-start justify-between gap-12">
7
+ <div className="flex flex-col items-center md:items-start max-w-sm">
8
+ <div className="font-bold text-2xl tracking-tight mb-3 bg-linear-to-r from-emerald-400 to-cyan-500 bg-clip-text text-transparent">Nylon Mesh</div>
9
+ <p className="text-sm text-fd-muted-foreground text-center md:text-left mb-6 leading-relaxed">
10
+ A high-performance edge proxy built on Cloudflare Pingora. Cache everything, scale instantly.
11
+ </p>
12
+ <div className="text-xs text-fd-muted-foreground/60 font-medium">
13
+ Ā© {new Date().getFullYear()} Nylon Mesh.
14
+ </div>
15
+ </div>
16
+
17
+ <div className="flex gap-16 sm:gap-24 text-sm text-center md:text-left">
18
+ <div className="flex flex-col gap-4">
19
+ <h3 className="font-semibold text-fd-foreground">Resources</h3>
20
+ <div className="flex flex-col gap-3">
21
+ <Link href="/docs" className="text-fd-muted-foreground hover:text-emerald-400 transition-colors">Documentation</Link>
22
+ <Link href="/docs/guide/deployment" className="text-fd-muted-foreground hover:text-emerald-400 transition-colors">Deployment</Link>
23
+ <Link href="https://github.com/AssetsArt/nylon-mesh" target="_blank" rel="noopener noreferrer" className="text-fd-muted-foreground hover:text-emerald-400 transition-colors">GitHub</Link>
24
+ </div>
25
+ </div>
26
+
27
+ <div className="flex flex-col gap-4">
28
+ <h3 className="font-semibold text-fd-foreground">Community</h3>
29
+ <div className="flex flex-col gap-3">
30
+ <a href="https://github.com/AssetsArt/nylon-mesh/issues" target="_blank" rel="noopener noreferrer" className="text-fd-muted-foreground hover:text-emerald-400 transition-colors">Issues</a>
31
+ </div>
32
+ </div>
33
+ </div>
34
+ </div>
35
+ </footer>
36
+ );
37
+ }
@@ -0,0 +1,35 @@
1
+ 'use client';
2
+
3
+ const frameworks = [
4
+ { name: 'Next.js', svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128"><circle cx="64" cy="64" r="64"/><path fill="url(#a)" d="M106.317 112.014 49.167 38.4H38.4v51.179h8.614v-40.24l52.54 67.884a64.216 64.216 0 0 0 6.763-5.209z"/><path fill="url(#b)" d="M81.778 38.4h8.533v51.2h-8.533z"/><defs><linearGradient id="a" x1="109" x2="144.5" y1="116.5" y2="160.5" gradientTransform="scale(.71111)" gradientUnits="userSpaceOnUse"><stop stop-color="#fff"/><stop offset="1" stop-color="#fff" stop-opacity="0"/></linearGradient><linearGradient id="b" x1="121" x2="120.799" y1="54" y2="106.875" gradientTransform="scale(.71111)" gradientUnits="userSpaceOnUse"><stop stop-color="#fff"/><stop offset="1" stop-color="#fff" stop-opacity="0"/></linearGradient></defs></svg>` },
5
+ { name: 'Nuxt', svg: `<svg viewBox="0 0 128 128" xmlns="http://www.w3.org/2000/svg"><path d="M39.267 108.97l-.284-.567c-.567-1.135-.567-2.27-.283-3.689H8.059L53.454 24.14l19.009 34.33 6.241-4.54L59.695 19.6c-.283-.567-2.553-3.971-6.241-3.971-1.703 0-4.256.567-6.242 4.255L1.25 101.31c-.284.852-2.27 4.54-.568 7.66 1.135 1.703 2.838 3.405 6.81 3.405h38.585c-3.972 0-5.958-1.702-6.81-3.404z" fill="#00c58e"/><path d="M126.65 101.59L89.767 35.201c-.567-.567-2.553-4.256-6.242-4.256-1.702 0-4.255.851-6.241 4.256l-4.823 7.944v15.321l11.065-19.009 36.599 65.254h-13.902a6.525 6.525 0 01-.568 3.972l-.284.284c-1.702 3.12-5.958 3.404-6.525 3.404h21.562c.851 0 4.823-.283 6.809-3.404.851-1.419 1.419-3.972-.567-7.377z" fill="#108775"/><path d="M106.51 108.97v-.284l.284-.567c.283-1.135.567-2.27.283-3.405l-1.134-3.404-28.938-50.501-4.256-7.66h-.284l-4.256 7.66-28.938 50.5-1.134 3.405a6.81 6.81 0 00.567 4.256c1.135 1.702 2.837 3.405 6.809 3.405h53.906c.851 0 5.107-.284 7.093-3.405zM72.464 58.469l26.386 46.245H46.079z" fill="#2f495e"/></svg>` },
6
+ { name: 'React', svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128"><g fill="#61DAFB"><circle cx="64" cy="64" r="11.4"/><path d="M107.3 45.2c-2.2-.8-4.5-1.6-6.9-2.3.6-2.4 1.1-4.8 1.5-7.1 2.1-13.2-.2-22.5-6.6-26.1-1.9-1.1-4-1.6-6.4-1.6-7 0-15.9 5.2-24.9 13.9-9-8.7-17.9-13.9-24.9-13.9-2.4 0-4.5.5-6.4 1.6-6.4 3.7-8.7 13-6.6 26.1.4 2.3.9 4.7 1.5 7.1-2.4.7-4.7 1.4-6.9 2.3C8.2 50 1.4 56.6 1.4 64s6.9 14 19.3 18.8c2.2.8 4.5 1.6 6.9 2.3-.6 2.4-1.1 4.8-1.5 7.1-2.1 13.2.2 22.5 6.6 26.1 1.9 1.1 4 1.6 6.4 1.6 7.1 0 16-5.2 24.9-13.9 9 8.7 17.9 13.9 24.9 13.9 2.4 0 4.5-.5 6.4-1.6 6.4-3.7 8.7-13 6.6-26.1-.4-2.3-.9-4.7-1.5-7.1 2.4-.7 4.7-1.4 6.9-2.3 12.5-4.8 19.3-11.4 19.3-18.8s-6.8-14-19.3-18.8zM92.5 14.7c4.1 2.4 5.5 9.8 3.8 20.3-.3 2.1-.8 4.3-1.4 6.6-5.2-1.2-10.7-2-16.5-2.5-3.4-4.8-6.9-9.1-10.4-13 7.4-7.3 14.9-12.3 21-12.3 1.3 0 2.5.3 3.5.9zM81.3 74c-1.8 3.2-3.9 6.4-6.1 9.6-3.7.3-7.4.4-11.2.4-3.9 0-7.6-.1-11.2-.4-2.2-3.2-4.2-6.4-6-9.6-1.9-3.3-3.7-6.7-5.3-10 1.6-3.3 3.4-6.7 5.3-10 1.8-3.2 3.9-6.4 6.1-9.6 3.7-.3 7.4-.4 11.2-.4 3.9 0 7.6.1 11.2.4 2.2 3.2 4.2 6.4 6 9.6 1.9 3.3 3.7 6.7 5.3 10-1.7 3.3-3.4 6.6-5.3 10zm8.3-3.3c1.5 3.5 2.7 6.9 3.8 10.3-3.4.8-7 1.4-10.8 1.9 1.2-1.9 2.5-3.9 3.6-6 1.2-2.1 2.3-4.2 3.4-6.2zM64 97.8c-2.4-2.6-4.7-5.4-6.9-8.3 2.3.1 4.6.2 6.9.2 2.3 0 4.6-.1 6.9-.2-2.2 2.9-4.5 5.7-6.9 8.3zm-18.6-15c-3.8-.5-7.4-1.1-10.8-1.9 1.1-3.3 2.3-6.8 3.8-10.3 1.1 2 2.2 4.1 3.4 6.1 1.2 2.2 2.4 4.1 3.6 6.1zm-7-25.5c-1.5-3.5-2.7-6.9-3.8-10.3 3.4-.8 7-1.4 10.8-1.9-1.2 1.9-2.5 3.9-3.6 6-1.2 2.1-2.3 4.2-3.4 6.2zM64 30.2c2.4 2.6 4.7 5.4 6.9 8.3-2.3-.1-4.6-.2-6.9-.2-2.3 0-4.6.1-6.9.2 2.2-2.9 4.5-5.7 6.9-8.3zm22.2 21l-3.6-6c3.8.5 7.4 1.1 10.8 1.9-1.1 3.3-2.3 6.8-3.8 10.3-1.1-2.1-2.2-4.2-3.4-6.2zM31.7 35c-1.7-10.5-.3-17.9 3.8-20.3 1-.6 2.2-.9 3.5-.9 6 0 13.5 4.9 21 12.3-3.5 3.8-7 8.2-10.4 13-5.8.5-11.3 1.4-16.5 2.5-.6-2.3-1-4.5-1.4-6.6zM7 64c0-4.7 5.7-9.7 15.7-13.4 2-.8 4.2-1.5 6.4-2.1 1.6 5 3.6 10.3 6 15.6-2.4 5.3-4.5 10.5-6 15.5C15.3 75.6 7 69.6 7 64zm28.5 49.3c-4.1-2.4-5.5-9.8-3.8-20.3.3-2.1.8-4.3 1.4-6.6 5.2 1.2 10.7 2 16.5 2.5 3.4 4.8 6.9 9.1 10.4 13-7.4 7.3-14.9 12.3-21 12.3-1.3 0-2.5-.3-3.5-.9zM96.3 93c1.7 10.5.3 17.9-3.8 20.3-1 .6-2.2.9-3.5.9-6 0-13.5-4.9-21-12.3 3.5-3.8 7-8.2 10.4-13 5.8-.5 11.3-1.4 16.5-2.5.6 2.3 1 4.5 1.4 6.6zm9-15.6c-2 .8-4.2 1.5-6.4 2.1-1.6-5-3.6-10.3-6-15.6 2.4-5.3 4.5-10.5 6-15.5 13.8 4 22.1 10 22.1 15.6 0 4.7-5.8 9.7-15.7 13.4z"/></g></svg>` },
7
+ { name: 'Angular', svg: `<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" viewBox="0 0 128 128"><linearGradient id="ng-a" x1="14.704" x2="110.985" y1="46.27" y2="92.024" gradientTransform="matrix(1 0 0 -1 0 130)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#e40035"/><stop offset=".24" stop-color="#f60a48"/><stop offset=".352" stop-color="#f20755"/><stop offset=".494" stop-color="#dc087d"/><stop offset=".745" stop-color="#9717e7"/><stop offset="1" stop-color="#6c00f5"/></linearGradient><path fill="url(#ng-a)" d="m124.5 21.3-4.4 68.6L78.3 0l46.2 21.3zm-29 88.7L64 128l-31.5-18 6.4-15.5h50.3l6.3 15.5zM64 34.1l16.5 40.2h-33L64 34.1zM7.9 89.9 3.5 21.3 49.7 0 7.9 89.9z"/><linearGradient id="ng-b" x1="28.733" x2="91.742" y1="117.071" y2="45.195" gradientTransform="matrix(1 0 0 -1 0 130)" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#ff31d9"/><stop offset="1" stop-color="#ff5be1" stop-opacity="0"/></linearGradient><path fill="url(#ng-b)" d="m124.5 21.3-4.4 68.6L78.3 0l46.2 21.3zm-29 88.7L64 128l-31.5-18 6.4-15.5h50.3l6.3 15.5zM64 34.1l16.5 40.2h-33L64 34.1zM7.9 89.9 3.5 21.3 49.7 0 7.9 89.9z"/></svg>` },
8
+ { name: 'Vue', svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 128 128"><path d="M0 8.934l49.854.158 14.167 24.47 14.432-24.47L128 8.935l-63.834 110.14zm126.98.637l-24.36.02-38.476 66.053L25.691 9.592.942 9.572l63.211 107.89zm-25.149-.008l-22.745.168-15.053 24.647L49.216 9.73l-22.794-.168 37.731 64.476zm-75.834-.17l23.002.009m-23.002-.01l23.002.01" fill="none"/><path d="M25.997 9.393l23.002.009L64.035 34.36 79.018 9.404 102 9.398 64.15 75.053z" fill="#35495e"/><path d="M.91 9.569l25.067-.172 38.15 65.659L101.98 9.401l25.11.026-62.966 108.06z" fill="#41b883"/></svg>` },
9
+ ];
10
+
11
+ export function FrameworkLogos() {
12
+ return (
13
+ <div className="text-center">
14
+ <p className="text-sm font-black uppercase tracking-[0.2em] text-fd-muted-foreground mb-10 select-none">
15
+ Works with your favorite framework
16
+ </p>
17
+ <div className="flex items-center justify-center gap-10 flex-wrap">
18
+ {frameworks.map((fw) => (
19
+ <div
20
+ key={fw.name}
21
+ className="flex flex-col items-center gap-2.5 cursor-default transition-all duration-300 hover:-translate-y-1 group"
22
+ >
23
+ <div
24
+ className="w-11 h-11 transition-all duration-300 group-hover:drop-shadow-[0_0_12px_rgba(16,185,129,0.4)] [&>svg]:w-full [&>svg]:h-full"
25
+ dangerouslySetInnerHTML={{ __html: fw.svg }}
26
+ />
27
+ <span className="text-xs font-semibold text-fd-muted-foreground transition-colors duration-300 group-hover:text-fd-foreground">
28
+ {fw.name}
29
+ </span>
30
+ </div>
31
+ ))}
32
+ </div>
33
+ </div>
34
+ );
35
+ }
@@ -0,0 +1 @@
1
+ export { twMerge as cn } from 'tailwind-merge';
@@ -0,0 +1,23 @@
1
+ import type { BaseLayoutProps } from 'fumadocs-ui/layouts/shared';
2
+
3
+ export const gitConfig = {
4
+ user: 'AssetsArt',
5
+ repo: 'nylon-mesh',
6
+ branch: 'main',
7
+ };
8
+
9
+ export function baseOptions(): BaseLayoutProps {
10
+ return {
11
+ nav: {
12
+ title: 'Nylon Mesh',
13
+ },
14
+ links: [
15
+ {
16
+ text: 'Docs',
17
+ url: '/docs',
18
+ active: 'nested-url',
19
+ },
20
+ ],
21
+ githubUrl: `https://github.com/${gitConfig.user}/${gitConfig.repo}`,
22
+ };
23
+ }
@@ -0,0 +1,27 @@
1
+ import { docs } from 'fumadocs-mdx:collections/server';
2
+ import { type InferPageType, loader } from 'fumadocs-core/source';
3
+ import { lucideIconsPlugin } from 'fumadocs-core/source/lucide-icons';
4
+
5
+ // See https://fumadocs.dev/docs/headless/source-api for more info
6
+ export const source = loader({
7
+ baseUrl: '/docs',
8
+ source: docs.toFumadocsSource(),
9
+ plugins: [lucideIconsPlugin()],
10
+ });
11
+
12
+ export function getPageImage(page: InferPageType<typeof source>) {
13
+ const segments = [...page.slugs, 'image.png'];
14
+
15
+ return {
16
+ segments,
17
+ url: `/og/docs/${segments.join('/')}`,
18
+ };
19
+ }
20
+
21
+ export async function getLLMText(page: InferPageType<typeof source>) {
22
+ const processed = await page.data.getText('processed');
23
+
24
+ return `# ${page.data.title}
25
+
26
+ ${processed}`;
27
+ }
@@ -0,0 +1,9 @@
1
+ import defaultMdxComponents from 'fumadocs-ui/mdx';
2
+ import type { MDXComponents } from 'mdx/types';
3
+
4
+ export function getMDXComponents(components?: MDXComponents): MDXComponents {
5
+ return {
6
+ ...defaultMdxComponents,
7
+ ...components,
8
+ };
9
+ }
@@ -0,0 +1,46 @@
1
+ {
2
+ "compilerOptions": {
3
+ "baseUrl": ".",
4
+ "target": "ESNext",
5
+ "lib": [
6
+ "dom",
7
+ "dom.iterable",
8
+ "esnext"
9
+ ],
10
+ "allowJs": true,
11
+ "skipLibCheck": true,
12
+ "strict": true,
13
+ "forceConsistentCasingInFileNames": true,
14
+ "noEmit": true,
15
+ "esModuleInterop": true,
16
+ "module": "esnext",
17
+ "moduleResolution": "bundler",
18
+ "resolveJsonModule": true,
19
+ "isolatedModules": true,
20
+ "jsx": "react-jsx",
21
+ "incremental": true,
22
+ "paths": {
23
+ "@/*": [
24
+ "./src/*"
25
+ ],
26
+ "fumadocs-mdx:collections/*": [
27
+ ".source/*"
28
+ ]
29
+ },
30
+ "plugins": [
31
+ {
32
+ "name": "next"
33
+ }
34
+ ]
35
+ },
36
+ "include": [
37
+ "next-env.d.ts",
38
+ "**/*.ts",
39
+ "**/*.tsx",
40
+ ".next/types/**/*.ts",
41
+ ".next/dev/types/**/*.ts"
42
+ ],
43
+ "exclude": [
44
+ "node_modules"
45
+ ]
46
+ }
@@ -0,0 +1,41 @@
1
+ # threads: 10
2
+ # liveness_path: "/_health/live"
3
+ # readiness_path: "/_health/ready"
4
+ # grace_period_seconds: 0
5
+ # graceful_shutdown_timeout_seconds: 0
6
+ listen: "0.0.0.0:3000"
7
+ # tls:
8
+ # listen: "0.0.0.0:443"
9
+ # certs:
10
+ # - host: "default"
11
+ # cert_path: "cert.pem"
12
+ # key_path: "key.pem"
13
+ upstreams:
14
+ - "127.0.0.1:3001"
15
+ # - address: "127.0.0.1:3002"
16
+ # weight: 5
17
+ load_balancer_algo: "round_robin"
18
+ redis_url: "redis://localhost:6379"
19
+ cache:
20
+ tier1_capacity: 10000
21
+ tier1_ttl_seconds: 3
22
+ tier2_ttl_seconds: 60
23
+ status: [200, 404]
24
+ content_types:
25
+ - "text/html"
26
+ bypass:
27
+ paths:
28
+ - "/_next/"
29
+ - "/api/"
30
+ extensions:
31
+ - ".ico"
32
+ - ".png"
33
+ # cache_control:
34
+ # - value: "public, max-age=31536000, immutable"
35
+ # paths:
36
+ # - "/_next/static/"
37
+ # extensions:
38
+ # - ".ico"
39
+ # - ".png"
40
+ # - ".jpg"
41
+
package/package.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "@assetsart/nylon-mesh",
3
+ "version": "1.0.1",
4
+ "description": "Nylon Mesh - Cache Everything. Scale Instantly.",
5
+ "main": "index.js",
6
+ "bin": {
7
+ "nylon-mesh": "bin/nylon-mesh.js"
8
+ },
9
+ "scripts": {
10
+ "build": "cargo build --release",
11
+ "docs:dev": "cd docs && bun run dev",
12
+ "docs:build": "cd docs && bun run build",
13
+ "release": "bun run scripts/release.mjs",
14
+ "publish:npm": "bun run scripts/publish.mjs"
15
+ },
16
+ "keywords": [
17
+ "proxy",
18
+ "nylon",
19
+ "pingora"
20
+ ],
21
+ "author": "",
22
+ "license": "MIT"
23
+ }
@@ -0,0 +1,18 @@
1
+ import { execSync } from 'child_process';
2
+ import { readFileSync } from 'fs';
3
+ import { join } from 'path';
4
+
5
+ try {
6
+ const pkgPath = join(process.cwd(), 'package.json');
7
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
8
+
9
+ console.log(`šŸš€ Publishing ${pkg.name} v${pkg.version} to npm...`);
10
+
11
+ // Run npm publish with public access for scoped packages
12
+ execSync('npm publish --access public', { stdio: 'inherit' });
13
+
14
+ console.log(`\nāœ… Successfully published v${pkg.version} to npm!`);
15
+ } catch (err) {
16
+ console.error('\nāŒ Failed to publish to npm:', err.message);
17
+ process.exit(1);
18
+ }