[{"data":1,"prerenderedAt":1564},["ShallowReactive",2],{"navigation":3,"-guide-middleware":56,"-guide-middleware-surround":1559},[4],{"title":5,"path":6,"stem":7,"children":8,"icon":10},"Getting Started","/guide","1.guide/1.index",[9,11,16,21,26,31,36,41,46,51],{"title":5,"path":6,"stem":7,"icon":10},"ph:book-open-duotone",{"title":12,"path":13,"stem":14,"icon":15},"Using CLI","/guide/cli","1.guide/10.cli","garden:terminal-cli-stroke-12",{"title":17,"path":18,"stem":19,"icon":20},"Fetch Handler","/guide/handler","1.guide/2.handler","i-fluent:target-24-regular",{"title":22,"path":23,"stem":24,"icon":25},"Server Instance","/guide/server","1.guide/3.server","radix-icons:component-instance",{"title":27,"path":28,"stem":29,"icon":30},"Middleware","/guide/middleware","1.guide/4.middleware","clarity:plugin-line",{"title":32,"path":33,"stem":34,"icon":35},"Server Options","/guide/options","1.guide/5.options","ri:settings-3-line",{"title":37,"path":38,"stem":39,"icon":40},"TLS","/guide/tls","1.guide/6.tls","ri:lock-2-line",{"title":42,"path":43,"stem":44,"icon":45},"Bundler Usage","/guide/bundler","1.guide/7.bundler","clarity:bundle-line",{"title":47,"path":48,"stem":49,"icon":50},"Node.js Support","/guide/node","1.guide/8.node","akar-icons:node-fill",{"title":52,"path":53,"stem":54,"icon":55},"AWS Lambda","/guide/aws-lambda","1.guide/9.aws-lambda","clarity:cloud-traffic-line",{"id":57,"title":27,"body":58,"description":1553,"extension":1554,"meta":1555,"navigation":1556,"path":28,"seo":1557,"stem":29,"__hash__":1558},"content/1.guide/4.middleware.md",{"type":59,"value":60,"toc":1543,"icon":30},"minimark",[61,66,451,455,476,486,490,497,591,596,604,682,700,714,718,741,828,834,841,990,1026,1061,1072,1089,1139,1164,1171,1195,1211,1219,1223,1243,1247,1278,1495,1516,1529,1539],[62,63,65],"h2",{"id":64},"example","Example",[67,68,73],"pre",{"className":69,"code":70,"language":71,"meta":72,"style":72},"language-ts shiki shiki-themes github-light github-dark github-dark","import { serve, type ServerMiddleware, type ServerPlugin } from \"srvx\";\n\nconst xPoweredBy: ServerMiddleware = async (req, next) => {\n  const res = await next();\n  res.headers.set(\"X-Powered-By\", \"srvx\");\n  return res;\n};\n\nconst devLogs: ServerPlugin = (server) => {\n  if (process.env.NODE_ENV === \"production\") {\n    return;\n  }\n  console.log(`Logger plugin enabled!`);\n  server.options.middleware.push((req, next) => {\n    console.log(`[request] [${req.method}] ${req.url}`);\n    return next();\n  });\n};\n\nserve({\n  middleware: [xPoweredBy],\n  plugins: [devLogs],\n  fetch(request) {\n    return new Response(`👋 Hello there.`);\n  },\n});\n","ts","",[74,75,76,110,117,161,182,205,214,220,225,251,272,280,286,302,326,362,371,377,382,387,396,402,408,421,439,445],"code",{"__ignoreMap":72},[77,78,81,85,89,92,95,97,100,103,107],"span",{"class":79,"line":80},"line",1,[77,82,84],{"class":83},"so5gQ","import",[77,86,88],{"class":87},"slsVL"," { serve, ",[77,90,91],{"class":83},"type",[77,93,94],{"class":87}," ServerMiddleware, ",[77,96,91],{"class":83},[77,98,99],{"class":87}," ServerPlugin } ",[77,101,102],{"class":83},"from",[77,104,106],{"class":105},"sfrk1"," \"srvx\"",[77,108,109],{"class":87},";\n",[77,111,113],{"class":79,"line":112},2,[77,114,116],{"emptyLinePlaceholder":115},true,"\n",[77,118,120,123,127,130,133,136,139,142,146,149,152,155,158],{"class":79,"line":119},3,[77,121,122],{"class":83},"const",[77,124,126],{"class":125},"shcOC"," xPoweredBy",[77,128,129],{"class":83},":",[77,131,132],{"class":125}," ServerMiddleware",[77,134,135],{"class":83}," =",[77,137,138],{"class":83}," async",[77,140,141],{"class":87}," (",[77,143,145],{"class":144},"sQHwn","req",[77,147,148],{"class":87},", ",[77,150,151],{"class":144},"next",[77,153,154],{"class":87},") ",[77,156,157],{"class":83},"=>",[77,159,160],{"class":87}," {\n",[77,162,164,167,171,173,176,179],{"class":79,"line":163},4,[77,165,166],{"class":83},"  const",[77,168,170],{"class":169},"suiK_"," res",[77,172,135],{"class":83},[77,174,175],{"class":83}," await",[77,177,178],{"class":125}," next",[77,180,181],{"class":87},"();\n",[77,183,185,188,191,194,197,199,202],{"class":79,"line":184},5,[77,186,187],{"class":87},"  res.headers.",[77,189,190],{"class":125},"set",[77,192,193],{"class":87},"(",[77,195,196],{"class":105},"\"X-Powered-By\"",[77,198,148],{"class":87},[77,200,201],{"class":105},"\"srvx\"",[77,203,204],{"class":87},");\n",[77,206,208,211],{"class":79,"line":207},6,[77,209,210],{"class":83},"  return",[77,212,213],{"class":87}," res;\n",[77,215,217],{"class":79,"line":216},7,[77,218,219],{"class":87},"};\n",[77,221,223],{"class":79,"line":222},8,[77,224,116],{"emptyLinePlaceholder":115},[77,226,228,230,233,235,238,240,242,245,247,249],{"class":79,"line":227},9,[77,229,122],{"class":83},[77,231,232],{"class":125}," devLogs",[77,234,129],{"class":83},[77,236,237],{"class":125}," ServerPlugin",[77,239,135],{"class":83},[77,241,141],{"class":87},[77,243,244],{"class":144},"server",[77,246,154],{"class":87},[77,248,157],{"class":83},[77,250,160],{"class":87},[77,252,254,257,260,263,266,269],{"class":79,"line":253},10,[77,255,256],{"class":83},"  if",[77,258,259],{"class":87}," (process.env.",[77,261,262],{"class":169},"NODE_ENV",[77,264,265],{"class":83}," ===",[77,267,268],{"class":105}," \"production\"",[77,270,271],{"class":87},") {\n",[77,273,275,278],{"class":79,"line":274},11,[77,276,277],{"class":83},"    return",[77,279,109],{"class":87},[77,281,283],{"class":79,"line":282},12,[77,284,285],{"class":87},"  }\n",[77,287,289,292,295,297,300],{"class":79,"line":288},13,[77,290,291],{"class":87},"  console.",[77,293,294],{"class":125},"log",[77,296,193],{"class":87},[77,298,299],{"class":105},"`Logger plugin enabled!`",[77,301,204],{"class":87},[77,303,305,308,311,314,316,318,320,322,324],{"class":79,"line":304},14,[77,306,307],{"class":87},"  server.options.middleware.",[77,309,310],{"class":125},"push",[77,312,313],{"class":87},"((",[77,315,145],{"class":144},[77,317,148],{"class":87},[77,319,151],{"class":144},[77,321,154],{"class":87},[77,323,157],{"class":83},[77,325,160],{"class":87},[77,327,329,332,334,336,339,341,344,347,350,352,354,357,360],{"class":79,"line":328},15,[77,330,331],{"class":87},"    console.",[77,333,294],{"class":125},[77,335,193],{"class":87},[77,337,338],{"class":105},"`[request] [${",[77,340,145],{"class":87},[77,342,343],{"class":105},".",[77,345,346],{"class":87},"method",[77,348,349],{"class":105},"}] ${",[77,351,145],{"class":87},[77,353,343],{"class":105},[77,355,356],{"class":87},"url",[77,358,359],{"class":105},"}`",[77,361,204],{"class":87},[77,363,365,367,369],{"class":79,"line":364},16,[77,366,277],{"class":83},[77,368,178],{"class":125},[77,370,181],{"class":87},[77,372,374],{"class":79,"line":373},17,[77,375,376],{"class":87},"  });\n",[77,378,380],{"class":79,"line":379},18,[77,381,219],{"class":87},[77,383,385],{"class":79,"line":384},19,[77,386,116],{"emptyLinePlaceholder":115},[77,388,390,393],{"class":79,"line":389},20,[77,391,392],{"class":125},"serve",[77,394,395],{"class":87},"({\n",[77,397,399],{"class":79,"line":398},21,[77,400,401],{"class":87},"  middleware: [xPoweredBy],\n",[77,403,405],{"class":79,"line":404},22,[77,406,407],{"class":87},"  plugins: [devLogs],\n",[77,409,411,414,416,419],{"class":79,"line":410},23,[77,412,413],{"class":125},"  fetch",[77,415,193],{"class":87},[77,417,418],{"class":144},"request",[77,420,271],{"class":87},[77,422,424,426,429,432,434,437],{"class":79,"line":423},24,[77,425,277],{"class":83},[77,427,428],{"class":83}," new",[77,430,431],{"class":125}," Response",[77,433,193],{"class":87},[77,435,436],{"class":105},"`👋 Hello there.`",[77,438,204],{"class":87},[77,440,442],{"class":79,"line":441},25,[77,443,444],{"class":87},"  },\n",[77,446,448],{"class":79,"line":447},26,[77,449,450],{"class":87},"});\n",[62,452,454],{"id":453},"order-of-execution","Order of execution",[456,457,458,459,462,463,466,467,471,472,475],"p",{},"Middleware run in the order they appear in the ",[74,460,461],{},"middleware"," array, each wrapping the next, with your ",[74,464,465],{},"fetch"," handler at the center. A middleware that returns a response ",[468,469,470],"strong",{},"without"," calling ",[74,473,474],{},"next()"," short-circuits the rest of the chain — nothing after it runs.",[456,477,478,479,482,483,485],{},"Plugins are applied in ",[74,480,481],{},"plugins"," array order, before the server starts listening. A plugin that pushes middleware appends to the end of the array, so ",[74,484,461],{}," entries always run first.",[62,487,489],{"id":488},"built-in-middleware-and-plugins","Built-in middleware and plugins",[456,491,492,493,496],{},"srvx ships several optional extensions as separate subpath imports. All of them are opt-in — importing ",[74,494,495],{},"srvx"," alone pulls in none of them.",[498,499,500,519],"table",{},[501,502,503],"thead",{},[504,505,506,510,513,516],"tr",{},[507,508,509],"th",{},"Import",[507,511,512],{},"Export",[507,514,515],{},"Kind",[507,517,518],{},"Runtimes",[520,521,522,540,557,575],"tbody",{},[504,523,524,530,535,537],{},[525,526,527],"td",{},[74,528,529],{},"srvx/log",[525,531,532],{},[74,533,534],{},"log()",[525,536,27],{},[525,538,539],{},"All",[504,541,542,547,552,554],{},[525,543,544],{},[74,545,546],{},"srvx/static",[525,548,549],{},[74,550,551],{},"serveStatic()",[525,553,27],{},[525,555,556],{},"Node, Deno, Bun",[504,558,559,564,569,572],{},[525,560,561],{},[74,562,563],{},"srvx/mtls",[525,565,566],{},[74,567,568],{},"mtls()",[525,570,571],{},"Plugin",[525,573,574],{},"Node",[504,576,577,582,587,589],{},[525,578,579],{},[74,580,581],{},"srvx/tracing",[525,583,584],{},[74,585,586],{},"tracingPlugin()",[525,588,571],{},[525,590,556],{},[592,593,595],"h3",{"id":594},"request-logging","Request logging",[456,597,598,600,601,603],{},[74,599,534],{}," from ",[74,602,529],{}," prints one colored line per request with the method, URL, status, and duration.",[67,605,608],{"className":69,"code":606,"filename":607,"language":71,"meta":72,"style":72},"import { serve } from \"srvx\";\nimport { log } from \"srvx/log\";\n\nserve({\n  middleware: [log()],\n  fetch: () => new Response(\"👋 Hello there.\"),\n});\n","server.ts",[74,609,610,623,637,641,647,657,678],{"__ignoreMap":72},[77,611,612,614,617,619,621],{"class":79,"line":80},[77,613,84],{"class":83},[77,615,616],{"class":87}," { serve } ",[77,618,102],{"class":83},[77,620,106],{"class":105},[77,622,109],{"class":87},[77,624,625,627,630,632,635],{"class":79,"line":112},[77,626,84],{"class":83},[77,628,629],{"class":87}," { log } ",[77,631,102],{"class":83},[77,633,634],{"class":105}," \"srvx/log\"",[77,636,109],{"class":87},[77,638,639],{"class":79,"line":119},[77,640,116],{"emptyLinePlaceholder":115},[77,642,643,645],{"class":79,"line":163},[77,644,392],{"class":125},[77,646,395],{"class":87},[77,648,649,652,654],{"class":79,"line":184},[77,650,651],{"class":87},"  middleware: [",[77,653,294],{"class":125},[77,655,656],{"class":87},"()],\n",[77,658,659,661,664,666,668,670,672,675],{"class":79,"line":207},[77,660,413],{"class":125},[77,662,663],{"class":87},": () ",[77,665,157],{"class":83},[77,667,428],{"class":83},[77,669,431],{"class":125},[77,671,193],{"class":87},[77,673,674],{"class":105},"\"👋 Hello there.\"",[77,676,677],{"class":87},"),\n",[77,679,680],{"class":79,"line":216},[77,681,450],{"class":87},[67,683,687],{"className":684,"code":685,"language":686,"meta":72,"style":72},"language-sh shiki shiki-themes github-light github-dark github-dark","[10:32:03 AM] GET http://localhost:3000/ [200] (1.42ms)\n","sh",[74,688,689],{"__ignoreMap":72},[77,690,691,694,697],{"class":79,"line":80},[77,692,693],{"class":87},"[10:32:03 AM] GET http://localhost:3000/ [200] (",[77,695,696],{"class":125},"1.42ms",[77,698,699],{"class":87},")\n",[456,701,702,703,705,706,708,709,713],{},"The duration is measured around ",[74,704,474],{},", so place ",[74,707,534],{}," first in the array for it to cover the whole chain. The ",[710,711,712],"a",{"href":13},"CLI"," enables this middleware automatically.",[592,715,717],{"id":716},"static-files","Static files",[456,719,720,600,722,724,725,728,729,732,733,736,737,740],{},[74,721,551],{},[74,723,546],{}," serves files from a directory, with ",[74,726,727],{},"index.html"," resolution, ",[74,730,731],{},".html"," extension fallback (",[74,734,735],{},"/about"," → ",[74,738,739],{},"about.html","), common MIME types, gzip/Brotli compression, and path-traversal protection.",[67,742,744],{"className":69,"code":743,"filename":607,"language":71,"meta":72,"style":72},"import { serve } from \"srvx\";\nimport { serveStatic } from \"srvx/static\";\n\nserve({\n  middleware: [serveStatic({ dir: \"public\" })],\n  fetch: () => new Response(\"Not found\", { status: 404 }),\n});\n",[74,745,746,758,772,776,782,798,824],{"__ignoreMap":72},[77,747,748,750,752,754,756],{"class":79,"line":80},[77,749,84],{"class":83},[77,751,616],{"class":87},[77,753,102],{"class":83},[77,755,106],{"class":105},[77,757,109],{"class":87},[77,759,760,762,765,767,770],{"class":79,"line":112},[77,761,84],{"class":83},[77,763,764],{"class":87}," { serveStatic } ",[77,766,102],{"class":83},[77,768,769],{"class":105}," \"srvx/static\"",[77,771,109],{"class":87},[77,773,774],{"class":79,"line":119},[77,775,116],{"emptyLinePlaceholder":115},[77,777,778,780],{"class":79,"line":163},[77,779,392],{"class":125},[77,781,395],{"class":87},[77,783,784,786,789,792,795],{"class":79,"line":184},[77,785,651],{"class":87},[77,787,788],{"class":125},"serveStatic",[77,790,791],{"class":87},"({ dir: ",[77,793,794],{"class":105},"\"public\"",[77,796,797],{"class":87}," })],\n",[77,799,800,802,804,806,808,810,812,815,818,821],{"class":79,"line":207},[77,801,413],{"class":125},[77,803,663],{"class":87},[77,805,157],{"class":83},[77,807,428],{"class":83},[77,809,431],{"class":125},[77,811,193],{"class":87},[77,813,814],{"class":105},"\"Not found\"",[77,816,817],{"class":87},", { status: ",[77,819,820],{"class":169},"404",[77,822,823],{"class":87}," }),\n",[77,825,826],{"class":79,"line":216},[77,827,450],{"class":87},[456,829,830,831,833],{},"When no file matches the request, it calls ",[74,832,474],{}," — so your handler acts as the fallback for unmatched paths.",[456,835,836],{},[468,837,838,840],{},[74,839,551],{}," options:",[842,843,844,851,863,901,921,932,953,970],"ul",{},[845,846,847,850],"li",{},[74,848,849],{},"dir",": The directory to serve files from (required).",[845,852,853,856,857,860,861,343],{},[74,854,855],{},"methods",": HTTP methods to serve (default ",[74,858,859],{},"[\"GET\", \"HEAD\"]","). Other methods fall through to ",[74,862,474],{},[845,864,865,868,869,871,872,875,876,148,879,882,883,885,886,889,890,893,894,897,898,343],{},[74,866,867],{},"dotfiles",": Dot segments (path segments starting with ",[74,870,343],{},") that may be served (default ",[74,873,874],{},"[\".well-known\"]","). A path containing any other dot segment — ",[74,877,878],{},"/.env",[74,880,881],{},"/.git/config"," — falls through to ",[74,884,474],{},". Pass ",[74,887,888],{},"true"," to serve every dot segment, or ",[74,891,892],{},"false"," (or ",[74,895,896],{},"[]",") to serve none, including ",[74,899,900],{},"/.well-known/",[845,902,903,906,907,909,910,912,913,916,917,920],{},[74,904,905],{},"encodings",": Serve precompressed variants from disk (default ",[74,908,892],{},"). Pass ",[74,911,888],{}," for ",[74,914,915],{},"{ br: \".br\", gzip: \".gz\" }",", or a map setting the extension per encoding (keys tried in order, preferred first). Off by default because most deployments ship no precompressed files, so the lookup is a ",[74,918,919],{},"stat"," that always misses.",[845,922,923,926,927,909,929,931],{},[74,924,925],{},"compress",": Compress a response on the fly when no precompressed variant is served (default ",[74,928,888],{},[74,930,892],{}," to serve only what is already on disk.",[845,933,934,937,938,941,942,945,946,949,950,952],{},[74,935,936],{},"lastModified",": Emit a ",[74,939,940],{},"Last-Modified"," header from the file's modification time, and answer a matching ",[74,943,944],{},"If-Modified-Since"," request with ",[74,947,948],{},"304 Not Modified"," (default ",[74,951,888],{},").",[845,954,955,958,959,962,963,945,966,949,968,952],{},[74,956,957],{},"etag",": Emit a weak ",[74,960,961],{},"ETag"," validator, and answer a matching ",[74,964,965],{},"If-None-Match",[74,967,948],{},[74,969,888],{},[845,971,972,975,976,979,980,148,982,985,986,989],{},[74,973,974],{},"renderHTML",": A function receiving ",[74,977,978],{},"{ request, html, filename }"," for every HTML file (",[74,981,731],{},[74,983,984],{},".htm","), returning the ",[74,987,988],{},"Response"," to send. Use it to inject or template markup before serving.",[456,991,992,993,996,997,1000,1001,1003,1004,1006,1007,1010,1011,1014,1015,1018,1019,1022,1023,343],{},"A request resolves in order: the path itself, then ",[74,994,995],{},"\u003Cpath>.html",", then ",[74,998,999],{},"\u003Cpath>/index.html",". So ",[74,1002,735],{}," serves ",[74,1005,739],{},", while an extension-less file (",[74,1008,1009],{},"LICENSE",", an ACME challenge token) is served at its exact name. A trailing-slash request names a directory, so ",[74,1012,1013],{},"/sub/"," resolves only ",[74,1016,1017],{},"sub/index.html"," — never ",[74,1020,1021],{},"sub.html"," or a file named ",[74,1024,1025],{},"sub",[456,1027,1028,1029,1031,1032,1035,1036,148,1039,1042,1043,1046,1047,1050,1051,1054,1055,1057,1058,1060],{},"By default a compressible response is compressed on the fly as it is sent. Enabling ",[74,1030,905],{}," adds a disk lookup that takes precedence: for ",[74,1033,1034],{},"/app.js"," with ",[74,1037,1038],{},"Accept-Encoding: br",[74,1040,1041],{},"app.js.br"," is served if it exists (with ",[74,1044,1045],{},"Content-Encoding: br","), and only a missing variant falls back to on-the-fly. A variant always wins because it costs no CPU, and a build can afford a better ratio than a per-request encode can justify — so ",[74,1048,1049],{},"encodings: true"," plus a build step is the cheapest way to serve maximum-quality compressed assets. The two switches are independent: ",[74,1052,1053],{},"compress: false"," serves only what is on disk, and ",[74,1056,905],{}," off with ",[74,1059,925],{}," on always compresses on the fly.",[456,1062,1063,1064,1067,1068,1071],{},"Brotli compresses at quality 4 rather than the ",[74,1065,1066],{},"node:zlib"," default of 11, which costs roughly 12x the CPU for a few percent of size. Only files between 1 KiB and 10 MiB are compressed on the fly: below that the encoded body can come out larger than the input, and above it the CPU spent per request outweighs the bandwidth saved — precompress large assets instead. On-the-fly responses are chunked, since the encoded length is not known until the bytes exist, while a variant declares the ",[74,1069,1070],{},"Content-Length"," it has on disk.",[456,1073,1074,1075,1078,1079,1082,1083,1085,1086,1088],{},"Compression applies to compressible types only, so a ",[74,1076,1077],{},".br"," next to an image or font is ignored, and those responses omit ",[74,1080,1081],{},"Vary: Accept-Encoding"," — which compressible ones always set, including uncompressed ones, as a shared cache must key on the header either way. ",[74,1084,974],{}," routes are never compressed and always read the source file: a variant on disk would not match the rendered output, and the ",[74,1087,988],{}," the hook returns is the caller's to encode.",[456,1090,1091,1092,1094,1095,1097,1098,1100,1101,1103,1104,1106,1107,1109,1110,1116,1117,1119,1120,1123,1124,1127,1128,1131,1132,1135,1136,1138],{},"Every file served without ",[74,1093,974],{}," carries an ",[74,1096,961],{}," and a ",[74,1099,940],{}," header, and a conditional request that still matches is answered with an empty ",[74,1102,948],{}," before the body is ever read. ",[74,1105,965],{}," takes precedence over ",[74,1108,944],{},", matching ",[710,1111,1115],{"href":1112,"rel":1113},"https://www.rfc-editor.org/rfc/rfc9110#section-13.2.2",[1114],"nofollow","RFC 9110",". The ",[74,1118,961],{}," is weak (",[74,1121,1122],{},"W/\"…\"","): it is derived from the file's size and modification time rather than its bytes, and folds in the ",[74,1125,1126],{},"Content-Encoding"," so a brotli and a gzip response under one URL get distinct validators. Pass ",[74,1129,1130],{},"etag: false"," or ",[74,1133,1134],{},"lastModified: false"," to drop either header and stop honoring its conditional. ",[74,1137,974],{}," routes carry neither, since the rendered body is the caller's to validate.",[456,1140,1141,1143,1144,1149,1150,1153,1154,1156,1157,1160,1161,952],{},[74,1142,900],{}," is served by default because ",[710,1145,1148],{"href":1146,"rel":1147},"https://www.rfc-editor.org/rfc/rfc8615",[1114],"RFC 8615"," reserves it for public metadata: ACME HTTP-01 challenges and ",[74,1151,1152],{},"security.txt"," live there. Allow-listing is by exact segment name, so ",[74,1155,874],{}," serves neither a sibling sharing its prefix (",[74,1158,1159],{},".well-known-backup",") nor a dot segment nested under it (",[74,1162,1163],{},".well-known/.env",[456,1165,1166,1167,1170],{},"Text responses declare ",[74,1168,1169],{},"charset=utf-8","; without it a browser decodes them with a fallback of its own choosing, mangling any non-ASCII byte the file does not declare inline.",[1172,1173,1174],"note",{},[456,1175,1176,1177,1179,1180,1182,1183,1185,1186,736,1189,882,1192,1194],{},"\nFiles are only served from within ",[74,1178,849],{},", and both rules above are re-checked against the path a symlink actually resolves to. Symlinks are followed, but one resolving outside ",[74,1181,849],{}," — or onto a dot segment ",[74,1184,867],{}," hides, such as ",[74,1187,1188],{},"public.txt",[74,1190,1191],{},".env",[74,1193,474],{}," instead of being served.",[1172,1196,1197],{},[456,1198,1199,1200,1202,1203,1206,1207,1210],{},"\nDespite the runtime-neutral name, ",[74,1201,546],{}," is ",[468,1204,1205],{},"Node-API-only"," — it uses ",[74,1208,1209],{},"node:fs"," internally, so it works only on runtimes with Node.js compatibility (Node, Deno, Bun).",[456,1212,1213,1214,1218],{},"See ",[710,1215,1217],{"href":1216},"/guide/cli#serving-static-files","Serving static files"," for the equivalent CLI flag.",[592,1220,1222],{"id":1221},"mutual-tls","Mutual TLS",[456,1224,1225,600,1230,1232,1233,1239,1240,343],{},[710,1226,1228],{"href":1227},"/guide/tls#mutual-tls-mtls",[74,1229,568],{},[74,1231,563],{}," requests a client certificate during the TLS handshake and exposes it on ",[710,1234,1236],{"href":1235},"/guide/handler#requesttls",[74,1237,1238],{},"request.tls",". It requires the ",[710,1241,1242],{"href":48},"Node.js adapter",[592,1244,1246],{"id":1245},"tracing","Tracing",[456,1248,1249,600,1251,1253,1254,1256,1257,1264,1265,1268,1269,1272,1273,343],{},[74,1250,586],{},[74,1252,581],{}," wraps your ",[74,1255,465],{}," handler and each middleware with ",[710,1258,1261],{"href":1259,"rel":1260},"https://nodejs.org/api/diagnostics_channel.html",[1114],[74,1262,1263],{},"diagnostics_channel"," instrumentation, publishing to the ",[74,1266,1267],{},"srvx.request"," and ",[74,1270,1271],{},"srvx.middleware"," ",[710,1274,1277],{"href":1275,"rel":1276},"https://nodejs.org/api/diagnostics_channel.html#class-tracingchannel",[1114],"tracing channels",[67,1279,1281],{"className":69,"code":1280,"filename":607,"language":71,"meta":72,"style":72},"import { serve } from \"srvx\";\nimport { tracingPlugin } from \"srvx/tracing\";\nimport { tracingChannel } from \"node:diagnostics_channel\";\n\ntracingChannel(\"srvx.request\").subscribe({\n  start: ({ request }) => console.log(`[start] ${request.url}`),\n  asyncEnd: ({ request }) => console.log(`[end] ${request.url}`),\n  error: ({ request, error }) => console.error(`[error] ${request.url}`, error),\n});\n\nserve({\n  plugins: [tracingPlugin()],\n  fetch: () => new Response(\"👋 Hello there.\"),\n});\n",[74,1282,1283,1295,1309,1323,1327,1344,1379,1411,1449,1453,1457,1463,1473,1491],{"__ignoreMap":72},[77,1284,1285,1287,1289,1291,1293],{"class":79,"line":80},[77,1286,84],{"class":83},[77,1288,616],{"class":87},[77,1290,102],{"class":83},[77,1292,106],{"class":105},[77,1294,109],{"class":87},[77,1296,1297,1299,1302,1304,1307],{"class":79,"line":112},[77,1298,84],{"class":83},[77,1300,1301],{"class":87}," { tracingPlugin } ",[77,1303,102],{"class":83},[77,1305,1306],{"class":105}," \"srvx/tracing\"",[77,1308,109],{"class":87},[77,1310,1311,1313,1316,1318,1321],{"class":79,"line":119},[77,1312,84],{"class":83},[77,1314,1315],{"class":87}," { tracingChannel } ",[77,1317,102],{"class":83},[77,1319,1320],{"class":105}," \"node:diagnostics_channel\"",[77,1322,109],{"class":87},[77,1324,1325],{"class":79,"line":163},[77,1326,116],{"emptyLinePlaceholder":115},[77,1328,1329,1332,1334,1337,1339,1342],{"class":79,"line":184},[77,1330,1331],{"class":125},"tracingChannel",[77,1333,193],{"class":87},[77,1335,1336],{"class":105},"\"srvx.request\"",[77,1338,952],{"class":87},[77,1340,1341],{"class":125},"subscribe",[77,1343,395],{"class":87},[77,1345,1346,1349,1352,1354,1357,1359,1362,1364,1366,1369,1371,1373,1375,1377],{"class":79,"line":207},[77,1347,1348],{"class":125},"  start",[77,1350,1351],{"class":87},": ({ ",[77,1353,418],{"class":144},[77,1355,1356],{"class":87}," }) ",[77,1358,157],{"class":83},[77,1360,1361],{"class":87}," console.",[77,1363,294],{"class":125},[77,1365,193],{"class":87},[77,1367,1368],{"class":105},"`[start] ${",[77,1370,418],{"class":87},[77,1372,343],{"class":105},[77,1374,356],{"class":87},[77,1376,359],{"class":105},[77,1378,677],{"class":87},[77,1380,1381,1384,1386,1388,1390,1392,1394,1396,1398,1401,1403,1405,1407,1409],{"class":79,"line":216},[77,1382,1383],{"class":125},"  asyncEnd",[77,1385,1351],{"class":87},[77,1387,418],{"class":144},[77,1389,1356],{"class":87},[77,1391,157],{"class":83},[77,1393,1361],{"class":87},[77,1395,294],{"class":125},[77,1397,193],{"class":87},[77,1399,1400],{"class":105},"`[end] ${",[77,1402,418],{"class":87},[77,1404,343],{"class":105},[77,1406,356],{"class":87},[77,1408,359],{"class":105},[77,1410,677],{"class":87},[77,1412,1413,1416,1418,1420,1422,1425,1427,1429,1431,1433,1435,1438,1440,1442,1444,1446],{"class":79,"line":222},[77,1414,1415],{"class":125},"  error",[77,1417,1351],{"class":87},[77,1419,418],{"class":144},[77,1421,148],{"class":87},[77,1423,1424],{"class":144},"error",[77,1426,1356],{"class":87},[77,1428,157],{"class":83},[77,1430,1361],{"class":87},[77,1432,1424],{"class":125},[77,1434,193],{"class":87},[77,1436,1437],{"class":105},"`[error] ${",[77,1439,418],{"class":87},[77,1441,343],{"class":105},[77,1443,356],{"class":87},[77,1445,359],{"class":105},[77,1447,1448],{"class":87},", error),\n",[77,1450,1451],{"class":79,"line":227},[77,1452,450],{"class":87},[77,1454,1455],{"class":79,"line":253},[77,1456,116],{"emptyLinePlaceholder":115},[77,1458,1459,1461],{"class":79,"line":274},[77,1460,392],{"class":125},[77,1462,395],{"class":87},[77,1464,1465,1468,1471],{"class":79,"line":282},[77,1466,1467],{"class":87},"  plugins: [",[77,1469,1470],{"class":125},"tracingPlugin",[77,1472,656],{"class":87},[77,1474,1475,1477,1479,1481,1483,1485,1487,1489],{"class":79,"line":288},[77,1476,413],{"class":125},[77,1478,663],{"class":87},[77,1480,157],{"class":83},[77,1482,428],{"class":83},[77,1484,431],{"class":125},[77,1486,193],{"class":87},[77,1488,674],{"class":105},[77,1490,677],{"class":87},[77,1492,1493],{"class":79,"line":304},[77,1494,450],{"class":87},[456,1496,1497,1498,1501,1502,1505,1506,1508,1509,1131,1512,1515],{},"Each event carries ",[74,1499,1500],{},"{ server, request }",", plus ",[74,1503,1504],{},"{ middleware: { index, handler } }"," on the ",[74,1507,1271],{}," channel. Pass ",[74,1510,1511],{},"{ fetch: false }",[74,1513,1514],{},"{ middleware: false }"," to instrument only one of the two.",[456,1517,1518,1519,1521,1522,1525,1526,1528],{},"Because plugins run in order, ",[74,1520,586],{}," only wraps middleware registered before it — keep it ",[468,1523,1524],{},"last"," in the ",[74,1527,481],{}," array so it covers middleware added by earlier plugins.",[1530,1531,1532],"important",{},[456,1533,1534,1202,1536,343],{},[74,1535,581],{},[468,1537,1538],{},"experimental",[1540,1541,1542],"style",{},"html pre.shiki code .so5gQ, html code.shiki .so5gQ{--shiki-light:#D73A49;--shiki-default:#F97583;--shiki-dark:#F97583}html pre.shiki code .slsVL, html code.shiki .slsVL{--shiki-light:#24292E;--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8}html pre.shiki code .sfrk1, html code.shiki .sfrk1{--shiki-light:#032F62;--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF}html pre.shiki code .shcOC, html code.shiki .shcOC{--shiki-light:#6F42C1;--shiki-default:#B392F0;--shiki-dark:#B392F0}html pre.shiki code .sQHwn, html code.shiki .sQHwn{--shiki-light:#E36209;--shiki-default:#FFAB70;--shiki-dark:#FFAB70}html pre.shiki code .suiK_, html code.shiki .suiK_{--shiki-light:#005CC5;--shiki-default:#79B8FF;--shiki-dark:#79B8FF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":72,"searchDepth":112,"depth":112,"links":1544},[1545,1546,1547],{"id":64,"depth":112,"text":65},{"id":453,"depth":112,"text":454},{"id":488,"depth":112,"text":489,"children":1548},[1549,1550,1551,1552],{"id":594,"depth":119,"text":595},{"id":716,"depth":119,"text":717},{"id":1221,"depth":119,"text":1222},{"id":1245,"depth":119,"text":1246},"Plugins and middleware allow adding reusable server extensions.","md",{"icon":30},{"icon":30},{"title":27,"description":1553},"J6G9OWVJnV4t_U0bAqQ9Xb-xYJV6jI4D_Xk_v61pFtI",[1560,1562],{"title":22,"path":23,"stem":24,"description":1561,"icon":25,"children":-1},"Control srvx server lifecycle.",{"title":32,"path":33,"stem":34,"description":1563,"icon":35,"children":-1},"Provide additional options to customize listening server.",1784304575693]