[{"data":1,"prerenderedAt":2475},["ShallowReactive",2],{"navigation":3,"\u002Fdocs\u002Fpackages\u002Fserve-static":176,"\u002Fdocs\u002Fpackages\u002Fserve-static-surround":2470},[4,21,86,158],{"title":5,"path":6,"stem":7,"children":8,"status":11,"icon":20},"Getting Started","\u002Fdocs\u002Fgetting-started","1.docs\u002F1.getting-started\u002F1.index",[9,12,16],{"title":10,"path":6,"stem":7,"status":11},"Introduction",null,{"title":13,"path":14,"stem":15,"status":11},"Installation","\u002Fdocs\u002Fgetting-started\u002Finstallation","1.docs\u002F1.getting-started\u002F2.installation",{"title":17,"path":18,"stem":19,"status":11},"Quick Start","\u002Fdocs\u002Fgetting-started\u002Fquick-start","1.docs\u002F1.getting-started\u002F3.quick-start",false,{"title":22,"path":23,"stem":24,"children":25,"status":11,"icon":20},"Core Concepts","\u002Fdocs\u002Fcore-concepts","1.docs\u002F2.core-concepts\u002F1.index",[26,28,32,36,46,50,54,58,62,66,70,74,78,82],{"title":27,"path":23,"stem":24,"status":11},"Overview",{"title":29,"path":30,"stem":31,"status":11},"Response","\u002Fdocs\u002Fcore-concepts\u002Fresponse","1.docs\u002F2.core-concepts\u002F10.response",{"title":33,"path":34,"stem":35,"status":11},"Testing","\u002Fdocs\u002Fcore-concepts\u002Ftesting","1.docs\u002F2.core-concepts\u002F12.testing",{"title":37,"path":38,"stem":39,"children":40,"status":11,"icon":20,"defaultOpen":20},"Decorators","\u002Fdocs\u002Fcore-concepts\u002Fdecorators","1.docs\u002F2.core-concepts\u002F13.decorators\u002F1.index",[41,42],{"title":27,"path":38,"stem":39,"status":11},{"title":43,"path":44,"stem":45,"status":11},"Custom","\u002Fdocs\u002Fcore-concepts\u002Fdecorators\u002Fcustom","1.docs\u002F2.core-concepts\u002F13.decorators\u002F2.custom",{"title":47,"path":48,"stem":49,"status":11},"Discovery Service","\u002Fdocs\u002Fcore-concepts\u002Fdiscovery","1.docs\u002F2.core-concepts\u002F14.discovery",{"title":51,"path":52,"stem":53,"status":11},"Application Lifecycle","\u002Fdocs\u002Fcore-concepts\u002Fapp-lifecycle","1.docs\u002F2.core-concepts\u002F15.app-lifecycle",{"title":55,"path":56,"stem":57,"status":11},"Controllers","\u002Fdocs\u002Fcore-concepts\u002Fcontrollers","1.docs\u002F2.core-concepts\u002F2.controllers",{"title":59,"path":60,"stem":61,"status":11},"Routing","\u002Fdocs\u002Fcore-concepts\u002Frouting","1.docs\u002F2.core-concepts\u002F3.routing",{"title":63,"path":64,"stem":65,"status":11},"Providers","\u002Fdocs\u002Fcore-concepts\u002Fproviders","1.docs\u002F2.core-concepts\u002F4.providers",{"title":67,"path":68,"stem":69,"status":11},"Modules","\u002Fdocs\u002Fcore-concepts\u002Fmodules","1.docs\u002F2.core-concepts\u002F5.modules",{"title":71,"path":72,"stem":73,"status":11},"Configuration","\u002Fdocs\u002Fcore-concepts\u002Fconfiguration","1.docs\u002F2.core-concepts\u002F6.configuration",{"title":75,"path":76,"stem":77,"status":11},"Middleware","\u002Fdocs\u002Fcore-concepts\u002Fmiddleware","1.docs\u002F2.core-concepts\u002F7.middleware",{"title":79,"path":80,"stem":81,"status":11},"Guards","\u002Fdocs\u002Fcore-concepts\u002Fguards","1.docs\u002F2.core-concepts\u002F8.guards",{"title":83,"path":84,"stem":85,"status":11},"Exceptions","\u002Fdocs\u002Fcore-concepts\u002Fexceptions","1.docs\u002F2.core-concepts\u002F9.exceptions",{"title":87,"path":88,"stem":89,"children":90,"status":11,"icon":20},"Packages","\u002Fdocs\u002Fpackages","1.docs\u002F3.packages\u002F1.index",[91,92,97,108,112,130,134,138,142,146,150,154],{"title":27,"path":88,"stem":89,"status":11},{"title":93,"path":94,"stem":95,"status":96},"CLI","\u002Fdocs\u002Fpackages\u002Fcli","1.docs\u002F3.packages\u002F10.cli","experimental",{"title":98,"path":99,"stem":100,"children":101,"status":11,"icon":20,"defaultOpen":20},"Events","\u002Fdocs\u002Fpackages\u002Fmessaging","1.docs\u002F3.packages\u002F11.messaging\u002F1.index",[102,104],{"title":27,"path":99,"stem":100,"status":103},"beta",{"title":105,"path":106,"stem":107,"status":96},"Redis","\u002Fdocs\u002Fpackages\u002Fmessaging\u002Fredis","1.docs\u002F3.packages\u002F11.messaging\u002F2.redis",{"title":109,"path":110,"stem":111,"status":103},"Serve Static","\u002Fdocs\u002Fpackages\u002Fserve-static","1.docs\u002F3.packages\u002F12.serve-static",{"title":113,"path":114,"stem":115,"children":116,"status":11,"icon":20,"defaultOpen":20},"Auth","\u002Fdocs\u002Fpackages\u002Fauth","1.docs\u002F3.packages\u002F2.auth\u002F1.index",[117,118,122,126],{"title":27,"path":114,"stem":115,"status":103},{"title":119,"path":120,"stem":121,"status":103},"JWT Provider","\u002Fdocs\u002Fpackages\u002Fauth\u002Fjwt","1.docs\u002F3.packages\u002F2.auth\u002F2.jwt",{"title":123,"path":124,"stem":125,"status":103},"Local Provider","\u002Fdocs\u002Fpackages\u002Fauth\u002Flocal","1.docs\u002F3.packages\u002F2.auth\u002F3.local",{"title":127,"path":128,"stem":129,"status":96},"OAuth2 Provider","\u002Fdocs\u002Fpackages\u002Fauth\u002Foauth2","1.docs\u002F3.packages\u002F2.auth\u002F4.oauth2",{"title":131,"path":132,"stem":133,"status":103},"JWT","\u002Fdocs\u002Fpackages\u002Fjwt","1.docs\u002F3.packages\u002F3.jwt",{"title":135,"path":136,"stem":137,"status":103},"Drizzle","\u002Fdocs\u002Fpackages\u002Fdrizzle","1.docs\u002F3.packages\u002F4.drizzle",{"title":139,"path":140,"stem":141,"status":103},"Papr","\u002Fdocs\u002Fpackages\u002Fpapr","1.docs\u002F3.packages\u002F5.papr",{"title":143,"path":144,"stem":145,"status":103},"Mongoose","\u002Fdocs\u002Fpackages\u002Fmongoose","1.docs\u002F3.packages\u002F6.mongoose",{"title":147,"path":148,"stem":149,"status":103},"Swagger","\u002Fdocs\u002Fpackages\u002Fswagger","1.docs\u002F3.packages\u002F7.swagger",{"title":151,"path":152,"stem":153,"status":103},"Node Server","\u002Fdocs\u002Fpackages\u002Fnode-server","1.docs\u002F3.packages\u002F8.node-server",{"title":155,"path":156,"stem":157,"status":103},"uWS Server","\u002Fdocs\u002Fpackages\u002Fuws-server","1.docs\u002F3.packages\u002F9.uws-server",{"title":159,"path":160,"stem":161,"children":162,"status":11,"icon":20},"Roadmap","\u002Fdocs\u002Froadmap","1.docs\u002F4.roadmap\u002F1.index",[163,164,168,172],{"title":27,"path":160,"stem":161,"status":11},{"title":165,"path":166,"stem":167,"status":11},"Short term (0-3 months)","\u002Fdocs\u002Froadmap\u002Fshort-term","1.docs\u002F4.roadmap\u002F2.short-term",{"title":169,"path":170,"stem":171,"status":11},"Mid term (3-9 months)","\u002Fdocs\u002Froadmap\u002Fmid-term","1.docs\u002F4.roadmap\u002F3.mid-term",{"title":173,"path":174,"stem":175,"status":11},"Long term (9-12+ months)","\u002Fdocs\u002Froadmap\u002Flong-term","1.docs\u002F4.roadmap\u002F4.long-term",{"id":177,"title":109,"body":178,"description":2465,"extension":2466,"meta":2467,"navigation":372,"path":110,"seo":2468,"status":103,"stem":111,"__hash__":2469},"docs\u002F1.docs\u002F3.packages\u002F12.serve-static.md",{"type":179,"value":180,"toc":2438},"minimark",[181,229,233,304,308,311,442,451,459,464,578,761,765,771,948,970,974,978,991,997,1008,1012,1033,1042,1045,1057,1061,1086,1090,1096,1147,1150,1197,1207,1211,1227,1233,1244,1288,1305,1309,1315,1487,1493,1497,1504,1587,1591,1645,1649,1816,1822,1826,1830,1840,1876,1880,1887,1935,1939,1944,1956,1959,1972,2337,2346,2350,2403,2407,2434],[182,183,184,188,189,192,193,196,197,200,201,204,205,208,209,212,213,216,217,220,221,224,225,228],"p",{},[185,186,187],"code",{},"@miiajs\u002Fserve-static"," serves files from disk under a URL prefix. The package speaks full HTTP semantics: weak ",[185,190,191],{},"ETag"," and ",[185,194,195],{},"Last-Modified"," for cache revalidation, ",[185,198,199],{},"Range"," requests for resumable downloads and ",[185,202,203],{},"\u003Cvideo>","\u002F",[185,206,207],{},"\u003Caudio>"," seeking, ",[185,210,211],{},"HEAD"," without body, and a SPA fallback gated by ",[185,214,215],{},"Accept"," and path extension. Default-deny dotfile policy keeps ",[185,218,219],{},".env",", ",[185,222,223],{},".git\u002FHEAD",", and ",[185,226,227],{},".well-known\u002F..."," from leaking.",[230,231,13],"h2",{"id":232},"installation",[234,235,236,261,276,290],"code-group",{},[237,238,244],"pre",{"className":239,"code":240,"filename":241,"language":242,"meta":243,"style":243},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","bun add @miiajs\u002Fserve-static\n","bun","bash","",[185,245,246],{"__ignoreMap":243},[247,248,251,254,258],"span",{"class":249,"line":250},"line",1,[247,252,241],{"class":253},"sBMFI",[247,255,257],{"class":256},"sfazB"," add",[247,259,260],{"class":256}," @miiajs\u002Fserve-static\n",[237,262,265],{"className":239,"code":263,"filename":264,"language":242,"meta":243,"style":243},"npm install @miiajs\u002Fserve-static\n","npm",[185,266,267],{"__ignoreMap":243},[247,268,269,271,274],{"class":249,"line":250},[247,270,264],{"class":253},[247,272,273],{"class":256}," install",[247,275,260],{"class":256},[237,277,280],{"className":239,"code":278,"filename":279,"language":242,"meta":243,"style":243},"pnpm add @miiajs\u002Fserve-static\n","pnpm",[185,281,282],{"__ignoreMap":243},[247,283,284,286,288],{"class":249,"line":250},[247,285,279],{"class":253},[247,287,257],{"class":256},[247,289,260],{"class":256},[237,291,294],{"className":239,"code":292,"filename":293,"language":242,"meta":243,"style":243},"yarn add @miiajs\u002Fserve-static\n","yarn",[185,295,296],{"__ignoreMap":243},[247,297,298,300,302],{"class":249,"line":250},[247,299,293],{"class":253},[247,301,257],{"class":256},[247,303,260],{"class":256},[230,305,307],{"id":306},"setup","Setup",[182,309,310],{},"Mount a directory under a URL prefix:",[237,312,316],{"className":313,"code":314,"language":315,"meta":243,"style":243},"language-typescript shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","import { Miia } from '@miiajs\u002Fcore'\nimport { serveStatic } from '@miiajs\u002Fserve-static'\n\nconst app = new Miia().register(AppModule)\n\nserveStatic(app, '\u002Fstatic', '.\u002Fpublic')\n","typescript",[185,317,318,347,367,374,405,410],{"__ignoreMap":243},[247,319,320,324,328,332,335,338,341,344],{"class":249,"line":250},[247,321,323],{"class":322},"s7zQu","import",[247,325,327],{"class":326},"sMK4o"," {",[247,329,331],{"class":330},"sTEyZ"," Miia",[247,333,334],{"class":326}," }",[247,336,337],{"class":322}," from",[247,339,340],{"class":326}," '",[247,342,343],{"class":256},"@miiajs\u002Fcore",[247,345,346],{"class":326},"'\n",[247,348,350,352,354,357,359,361,363,365],{"class":249,"line":349},2,[247,351,323],{"class":322},[247,353,327],{"class":326},[247,355,356],{"class":330}," serveStatic",[247,358,334],{"class":326},[247,360,337],{"class":322},[247,362,340],{"class":326},[247,364,187],{"class":256},[247,366,346],{"class":326},[247,368,370],{"class":249,"line":369},3,[247,371,373],{"emptyLinePlaceholder":372},true,"\n",[247,375,377,381,384,387,390,393,396,399,402],{"class":249,"line":376},4,[247,378,380],{"class":379},"spNyl","const",[247,382,383],{"class":330}," app ",[247,385,386],{"class":326},"=",[247,388,389],{"class":326}," new",[247,391,331],{"class":392},"s2Zo4",[247,394,395],{"class":330},"()",[247,397,398],{"class":326},".",[247,400,401],{"class":392},"register",[247,403,404],{"class":330},"(AppModule)\n",[247,406,408],{"class":249,"line":407},5,[247,409,373],{"emptyLinePlaceholder":372},[247,411,413,416,419,422,424,427,430,432,434,437,439],{"class":249,"line":412},6,[247,414,415],{"class":392},"serveStatic",[247,417,418],{"class":330},"(app",[247,420,421],{"class":326},",",[247,423,340],{"class":326},[247,425,426],{"class":256},"\u002Fstatic",[247,428,429],{"class":326},"'",[247,431,421],{"class":326},[247,433,340],{"class":326},[247,435,436],{"class":256},".\u002Fpublic",[247,438,429],{"class":326},[247,440,441],{"class":330},")\n",[182,443,444,445,447,448,450],{},"This serves all files from ",[185,446,436],{}," under the ",[185,449,426],{}," URL prefix:",[237,452,457],{"className":453,"code":455,"language":456},[454],"language-text","GET \u002Fstatic\u002Fstyle.css  ->  .\u002Fpublic\u002Fstyle.css\nGET \u002Fstatic\u002Fapp.js     ->  .\u002Fpublic\u002Fapp.js\nGET \u002Fstatic\u002Flogo.png   ->  .\u002Fpublic\u002Flogo.png\n","text",[185,458,455],{"__ignoreMap":243},[460,461,463],"h3",{"id":462},"configuration-options","Configuration options",[237,465,467],{"className":313,"code":466,"language":315,"meta":243,"style":243},"serveStatic(app, '\u002Fassets', '.\u002Fdist', {\n  index: 'index.html',\n  maxAge: 3600,\n  etag: true,\n  dotfiles: false,\n  fallback: 'index.html',\n})\n",[185,468,469,498,517,530,543,555,570],{"__ignoreMap":243},[247,470,471,473,475,477,479,482,484,486,488,491,493,495],{"class":249,"line":250},[247,472,415],{"class":392},[247,474,418],{"class":330},[247,476,421],{"class":326},[247,478,340],{"class":326},[247,480,481],{"class":256},"\u002Fassets",[247,483,429],{"class":326},[247,485,421],{"class":326},[247,487,340],{"class":326},[247,489,490],{"class":256},".\u002Fdist",[247,492,429],{"class":326},[247,494,421],{"class":326},[247,496,497],{"class":326}," {\n",[247,499,500,504,507,509,512,514],{"class":249,"line":349},[247,501,503],{"class":502},"swJcz","  index",[247,505,506],{"class":326},":",[247,508,340],{"class":326},[247,510,511],{"class":256},"index.html",[247,513,429],{"class":326},[247,515,516],{"class":326},",\n",[247,518,519,522,524,528],{"class":249,"line":369},[247,520,521],{"class":502},"  maxAge",[247,523,506],{"class":326},[247,525,527],{"class":526},"sbssI"," 3600",[247,529,516],{"class":326},[247,531,532,535,537,541],{"class":249,"line":376},[247,533,534],{"class":502},"  etag",[247,536,506],{"class":326},[247,538,540],{"class":539},"sfNiH"," true",[247,542,516],{"class":326},[247,544,545,548,550,553],{"class":249,"line":407},[247,546,547],{"class":502},"  dotfiles",[247,549,506],{"class":326},[247,551,552],{"class":539}," false",[247,554,516],{"class":326},[247,556,557,560,562,564,566,568],{"class":249,"line":412},[247,558,559],{"class":502},"  fallback",[247,561,506],{"class":326},[247,563,340],{"class":326},[247,565,511],{"class":256},[247,567,429],{"class":326},[247,569,516],{"class":326},[247,571,573,576],{"class":249,"line":572},7,[247,574,575],{"class":326},"}",[247,577,441],{"class":330},[579,580,581,600],"table",{},[582,583,584],"thead",{},[585,586,587,591,594,597],"tr",{},[588,589,590],"th",{},"Option",[588,592,593],{},"Type",[588,595,596],{},"Default",[588,598,599],{},"Description",[601,602,603,628,651,684,715,739],"tbody",{},[585,604,605,611,616,621],{},[606,607,608],"td",{},[185,609,610],{},"index",[606,612,613],{},[185,614,615],{},"string | false",[606,617,618],{},[185,619,620],{},"'index.html'",[606,622,623,624,627],{},"Index file for directory requests. Set to ",[185,625,626],{},"false"," to disable.",[585,629,630,635,640,645],{},[606,631,632],{},[185,633,634],{},"maxAge",[606,636,637],{},[185,638,639],{},"number",[606,641,642],{},[185,643,644],{},"0",[606,646,647,650],{},[185,648,649],{},"Cache-Control: max-age"," value in seconds. Applied to 200 and 304 responses.",[585,652,653,658,663,668],{},[606,654,655],{},[185,656,657],{},"etag",[606,659,660],{},[185,661,662],{},"boolean",[606,664,665],{},[185,666,667],{},"true",[606,669,670,671,192,673,675,676,679,680,683],{},"Send ",[185,672,191],{},[185,674,195],{}," and honor ",[185,677,678],{},"If-None-Match"," \u002F ",[185,681,682],{},"If-Modified-Since",". Disable to skip conditional GET.",[585,685,686,691,695,699],{},[606,687,688],{},[185,689,690],{},"dotfiles",[606,692,693],{},[185,694,662],{},[606,696,697],{},[185,698,626],{},[606,700,701,702,704,705,707,708,220,710,220,712,714],{},"When ",[185,703,626],{},", any URL with a path segment starting with ",[185,706,398],{}," returns 404 (e.g. ",[185,709,219],{},[185,711,223],{},[185,713,227],{},").",[585,716,717,722,726,730],{},[606,718,719],{},[185,720,721],{},"fallback",[606,723,724],{},[185,725,615],{},[606,727,728],{},[185,729,626],{},[606,731,732,733,736,737,398],{},"Path inside ",[185,734,735],{},"root"," to serve when the requested file is missing and the request looks like a SPA navigation. Typically ",[185,738,620],{},[585,740,741,746,751,754],{},[606,742,743],{},[185,744,745],{},"getMimeType",[606,747,748],{},[185,749,750],{},"(path: string) => string",[606,752,753],{},"built-in map",[606,755,756,757,760],{},"Custom MIME type resolver. Result is automatically suffixed with ",[185,758,759],{},"; charset=utf-8"," for text-like types unless it already specifies a charset.",[230,762,764],{"id":763},"usage","Usage",[182,766,767,768,770],{},"A typical SPA setup - serve built assets, fall back to ",[185,769,511],{}," for client-side routes, cache hashed bundles aggressively:",[237,772,774],{"className":313,"code":773,"language":315,"meta":243,"style":243},"import { Miia } from '@miiajs\u002Fcore'\nimport { serveStatic } from '@miiajs\u002Fserve-static'\n\nconst app = new Miia().register(AppModule)\n\n\u002F\u002F Hashed assets - long-lived cache + SPA fallback for deep links.\nserveStatic(app, '\u002F', '.\u002Fdist', {\n  maxAge: 60 * 60 * 24 * 365,\n  fallback: 'index.html',\n})\n\nawait app.listen(3000)\n",[185,775,776,794,812,816,836,840,846,872,899,914,921,926],{"__ignoreMap":243},[247,777,778,780,782,784,786,788,790,792],{"class":249,"line":250},[247,779,323],{"class":322},[247,781,327],{"class":326},[247,783,331],{"class":330},[247,785,334],{"class":326},[247,787,337],{"class":322},[247,789,340],{"class":326},[247,791,343],{"class":256},[247,793,346],{"class":326},[247,795,796,798,800,802,804,806,808,810],{"class":249,"line":349},[247,797,323],{"class":322},[247,799,327],{"class":326},[247,801,356],{"class":330},[247,803,334],{"class":326},[247,805,337],{"class":322},[247,807,340],{"class":326},[247,809,187],{"class":256},[247,811,346],{"class":326},[247,813,814],{"class":249,"line":369},[247,815,373],{"emptyLinePlaceholder":372},[247,817,818,820,822,824,826,828,830,832,834],{"class":249,"line":376},[247,819,380],{"class":379},[247,821,383],{"class":330},[247,823,386],{"class":326},[247,825,389],{"class":326},[247,827,331],{"class":392},[247,829,395],{"class":330},[247,831,398],{"class":326},[247,833,401],{"class":392},[247,835,404],{"class":330},[247,837,838],{"class":249,"line":407},[247,839,373],{"emptyLinePlaceholder":372},[247,841,842],{"class":249,"line":412},[247,843,845],{"class":844},"sHwdD","\u002F\u002F Hashed assets - long-lived cache + SPA fallback for deep links.\n",[247,847,848,850,852,854,856,858,860,862,864,866,868,870],{"class":249,"line":572},[247,849,415],{"class":392},[247,851,418],{"class":330},[247,853,421],{"class":326},[247,855,340],{"class":326},[247,857,204],{"class":256},[247,859,429],{"class":326},[247,861,421],{"class":326},[247,863,340],{"class":326},[247,865,490],{"class":256},[247,867,429],{"class":326},[247,869,421],{"class":326},[247,871,497],{"class":326},[247,873,875,877,879,882,885,887,889,892,894,897],{"class":249,"line":874},8,[247,876,521],{"class":502},[247,878,506],{"class":326},[247,880,881],{"class":526}," 60",[247,883,884],{"class":326}," *",[247,886,881],{"class":526},[247,888,884],{"class":326},[247,890,891],{"class":526}," 24",[247,893,884],{"class":326},[247,895,896],{"class":526}," 365",[247,898,516],{"class":326},[247,900,902,904,906,908,910,912],{"class":249,"line":901},9,[247,903,559],{"class":502},[247,905,506],{"class":326},[247,907,340],{"class":326},[247,909,511],{"class":256},[247,911,429],{"class":326},[247,913,516],{"class":326},[247,915,917,919],{"class":249,"line":916},10,[247,918,575],{"class":326},[247,920,441],{"class":330},[247,922,924],{"class":249,"line":923},11,[247,925,373],{"emptyLinePlaceholder":372},[247,927,929,932,935,937,940,943,946],{"class":249,"line":928},12,[247,930,931],{"class":322},"await",[247,933,934],{"class":330}," app",[247,936,398],{"class":326},[247,938,939],{"class":392},"listen",[247,941,942],{"class":330},"(",[247,944,945],{"class":526},"3000",[247,947,441],{"class":330},[182,949,950,953,954,957,958,961,962,965,966,969],{},[185,951,952],{},"GET \u002Fabout"," resolves to ",[185,955,956],{},"dist\u002Findex.html","; ",[185,959,960],{},"GET \u002Fassets\u002Fapp-abc123.js"," returns the bundle with a year-long cache; ",[185,963,964],{},"GET \u002Ffavicon.ico"," returns the icon. Refresh on ",[185,967,968],{},"\u002Fabout"," keeps client-side routing intact.",[230,971,973],{"id":972},"http-semantics","HTTP semantics",[460,975,977],{"id":976},"conditional-get-304-not-modified","Conditional GET (304 Not Modified)",[182,979,980,981,983,984,987,988,990],{},"Each response carries a weak ",[185,982,191],{}," of the form ",[185,985,986],{},"W\u002F\"\u003Csize>-\u003Cmtime>\""," and a ",[185,989,195],{}," header. Browsers and CDNs revalidate on subsequent requests:",[237,992,995],{"className":993,"code":994,"language":456},[454],"> GET \u002Fassets\u002Fapp.js\n\u003C 200 OK\n\u003C ETag: W\u002F\"4ad-194a8c4b800\"\n\u003C Last-Modified: Mon, 12 May 2025 10:00:00 GMT\n\n> GET \u002Fassets\u002Fapp.js\n> If-None-Match: W\u002F\"4ad-194a8c4b800\"\n\u003C 304 Not Modified\n",[185,996,994],{"__ignoreMap":243},[182,998,999,1001,1002,1004,1005,398],{},[185,1000,678],{}," takes precedence over ",[185,1003,682],{}," per RFC 7232. Disable both with ",[185,1006,1007],{},"etag: false",[460,1009,1011],{"id":1010},"range-requests-206-partial-content","Range requests (206 Partial Content)",[182,1013,1014,220,1017,1020,1021,1024,1025,1028,1029,1032],{},[185,1015,1016],{},"Range: bytes=0-99",[185,1018,1019],{},"bytes=900-",", and suffix form ",[185,1022,1023],{},"bytes=-50"," are supported. The server replies 206 with ",[185,1026,1027],{},"Content-Range: bytes start-end\u002Ftotal"," and streams only the requested slice. Out-of-range requests return 416 with ",[185,1030,1031],{},"Content-Range: bytes *\u002Ftotal",". Multi-range requests fall back to a full 200.",[182,1034,1035,1038,1039,1041],{},[185,1036,1037],{},"If-Range"," is honored against either the ETag or the ",[185,1040,195],{}," value - if it doesn't match, the full file is served (200) so the client knows to discard its partial cache.",[460,1043,211],{"id":1044},"head",[182,1046,1047,1049,1050,192,1053,1056],{},[185,1048,211],{}," requests reuse the GET pipeline (status code, all headers, including ",[185,1051,1052],{},"Content-Length",[185,1054,1055],{},"Content-Range"," for ranged HEAD) but return no body.",[460,1058,1060],{"id":1059},"charset","Charset",[182,1062,1063,1064,220,1067,220,1070,220,1073,220,1076,1079,1080,1082,1083,1085],{},"Text-like MIME types (",[185,1065,1066],{},"text\u002F*",[185,1068,1069],{},"application\u002Fjavascript",[185,1071,1072],{},"application\u002Fjson",[185,1074,1075],{},"application\u002Fxml",[185,1077,1078],{},"image\u002Fsvg+xml",") are returned with ",[185,1081,759],{}," appended automatically. Binary types (images, fonts, archives) are not modified. If a custom ",[185,1084,745],{}," already specifies a charset, it's left alone.",[230,1087,1089],{"id":1088},"spa-fallback","SPA fallback",[182,1091,1092,1093,1095],{},"Single-page applications need any unmatched URL to resolve to ",[185,1094,511],{}," so client-side routing can take over after a page reload:",[237,1097,1099],{"className":313,"code":1098,"language":315,"meta":243,"style":243},"serveStatic(app, '\u002F', '.\u002Fdist', {\n  fallback: 'index.html',\n})\n",[185,1100,1101,1127,1141],{"__ignoreMap":243},[247,1102,1103,1105,1107,1109,1111,1113,1115,1117,1119,1121,1123,1125],{"class":249,"line":250},[247,1104,415],{"class":392},[247,1106,418],{"class":330},[247,1108,421],{"class":326},[247,1110,340],{"class":326},[247,1112,204],{"class":256},[247,1114,429],{"class":326},[247,1116,421],{"class":326},[247,1118,340],{"class":326},[247,1120,490],{"class":256},[247,1122,429],{"class":326},[247,1124,421],{"class":326},[247,1126,497],{"class":326},[247,1128,1129,1131,1133,1135,1137,1139],{"class":249,"line":349},[247,1130,559],{"class":502},[247,1132,506],{"class":326},[247,1134,340],{"class":326},[247,1136,511],{"class":256},[247,1138,429],{"class":326},[247,1140,516],{"class":326},[247,1142,1143,1145],{"class":249,"line":369},[247,1144,575],{"class":326},[247,1146,441],{"class":330},[182,1148,1149],{},"The fallback only triggers when:",[1151,1152,1153,1163,1183],"ul",{},[1154,1155,1156,1157,1160,1161],"li",{},"the request is ",[185,1158,1159],{},"GET"," or ",[185,1162,211],{},[1154,1164,1165,1167,1168,1160,1171,1174,1175,1178,1179,1182],{},[185,1166,215],{}," includes ",[185,1169,1170],{},"text\u002Fhtml",[185,1172,1173],{},"*\u002F*"," (so ",[185,1176,1177],{},"fetch('\u002Fapi\u002Fusers')"," with ",[185,1180,1181],{},"Accept: application\u002Fjson"," still 404s correctly)",[1154,1184,1185,1186,204,1189,1192,1193,1196],{},"the path has no extension or ends with ",[185,1187,1188],{},".html",[185,1190,1191],{},".htm"," (so a missing ",[185,1194,1195],{},"\u002Fassets\u002Fmissing.png"," 404s instead of returning HTML pretending to be an image)",[182,1198,1199,1200,220,1202,224,1204,398],{},"The fallback path is served fresh each time with its own ",[185,1201,191],{},[185,1203,195],{},[185,1205,1206],{},"Content-Type",[230,1208,1210],{"id":1209},"dotfiles-policy","Dotfiles policy",[182,1212,1213,1214,1216,1217,1219,1220,1223,1224,1226],{},"By default, any URL segment starting with ",[185,1215,398],{}," returns 404, so a stray ",[185,1218,219],{}," next to your ",[185,1221,1222],{},"public\u002F"," directory or a ",[185,1225,223],{}," won't leak:",[237,1228,1231],{"className":1229,"code":1230,"language":456},[454],"GET \u002Fstatic\u002F.env             ->  404\nGET \u002Fstatic\u002F.well-known\u002Fx    ->  404\nGET \u002Fstatic\u002Ffoo\u002F.git\u002FHEAD    ->  404\n",[185,1232,1230],{"__ignoreMap":243},[182,1234,1235,1236,1239,1240,1243],{},"Set ",[185,1237,1238],{},"dotfiles: true"," to allow them (useful for ",[185,1241,1242],{},".well-known\u002Facme-challenge\u002F..."," for ACME\u002FHTTPS):",[237,1245,1247],{"className":313,"code":1246,"language":315,"meta":243,"style":243},"serveStatic(app, '\u002F.well-known', '.\u002Fpublic\u002F.well-known', { dotfiles: true })\n",[185,1248,1249],{"__ignoreMap":243},[247,1250,1251,1253,1255,1257,1259,1262,1264,1266,1268,1271,1273,1275,1277,1280,1282,1284,1286],{"class":249,"line":250},[247,1252,415],{"class":392},[247,1254,418],{"class":330},[247,1256,421],{"class":326},[247,1258,340],{"class":326},[247,1260,1261],{"class":256},"\u002F.well-known",[247,1263,429],{"class":326},[247,1265,421],{"class":326},[247,1267,340],{"class":326},[247,1269,1270],{"class":256},".\u002Fpublic\u002F.well-known",[247,1272,429],{"class":326},[247,1274,421],{"class":326},[247,1276,327],{"class":326},[247,1278,1279],{"class":502}," dotfiles",[247,1281,506],{"class":326},[247,1283,540],{"class":539},[247,1285,334],{"class":326},[247,1287,441],{"class":330},[1289,1290,1291],"caution",{},[182,1292,1293,1294,1297,1298,1301,1302,1304],{},"The dotfile guard is a logical URL check. A symlink at ",[185,1295,1296],{},"public\u002Flegit.txt"," pointing to ",[185,1299,1300],{},"public\u002F.env"," is not blocked - if you allow symlinks under ",[185,1303,1222],{},", audit their targets.",[230,1306,1308],{"id":1307},"custom-mime-types","Custom MIME types",[182,1310,1311,1312,1314],{},"Override or extend MIME type detection with a custom ",[185,1313,745],{}," function:",[237,1316,1318],{"className":313,"code":1317,"language":315,"meta":243,"style":243},"import { serveStatic, getMimeType } from '@miiajs\u002Fserve-static'\n\nserveStatic(app, '\u002Fassets', '.\u002Fpublic', {\n  getMimeType: (path) => {\n    if (path.endsWith('.glb')) return 'model\u002Fgltf-binary'\n    if (path.endsWith('.m3u8')) return 'application\u002Fvnd.apple.mpegurl'\n    return getMimeType(path)\n  }\n})\n",[185,1319,1320,1343,1347,1373,1395,1431,1463,1476,1481],{"__ignoreMap":243},[247,1321,1322,1324,1326,1328,1330,1333,1335,1337,1339,1341],{"class":249,"line":250},[247,1323,323],{"class":322},[247,1325,327],{"class":326},[247,1327,356],{"class":330},[247,1329,421],{"class":326},[247,1331,1332],{"class":330}," getMimeType",[247,1334,334],{"class":326},[247,1336,337],{"class":322},[247,1338,340],{"class":326},[247,1340,187],{"class":256},[247,1342,346],{"class":326},[247,1344,1345],{"class":249,"line":349},[247,1346,373],{"emptyLinePlaceholder":372},[247,1348,1349,1351,1353,1355,1357,1359,1361,1363,1365,1367,1369,1371],{"class":249,"line":369},[247,1350,415],{"class":392},[247,1352,418],{"class":330},[247,1354,421],{"class":326},[247,1356,340],{"class":326},[247,1358,481],{"class":256},[247,1360,429],{"class":326},[247,1362,421],{"class":326},[247,1364,340],{"class":326},[247,1366,436],{"class":256},[247,1368,429],{"class":326},[247,1370,421],{"class":326},[247,1372,497],{"class":326},[247,1374,1375,1378,1380,1383,1387,1390,1393],{"class":249,"line":376},[247,1376,1377],{"class":392},"  getMimeType",[247,1379,506],{"class":326},[247,1381,1382],{"class":326}," (",[247,1384,1386],{"class":1385},"sHdIc","path",[247,1388,1389],{"class":326},")",[247,1391,1392],{"class":379}," =>",[247,1394,497],{"class":326},[247,1396,1397,1400,1402,1404,1406,1409,1411,1413,1416,1418,1421,1424,1426,1429],{"class":249,"line":407},[247,1398,1399],{"class":322},"    if",[247,1401,1382],{"class":502},[247,1403,1386],{"class":330},[247,1405,398],{"class":326},[247,1407,1408],{"class":392},"endsWith",[247,1410,942],{"class":502},[247,1412,429],{"class":326},[247,1414,1415],{"class":256},".glb",[247,1417,429],{"class":326},[247,1419,1420],{"class":502},")) ",[247,1422,1423],{"class":322},"return",[247,1425,340],{"class":326},[247,1427,1428],{"class":256},"model\u002Fgltf-binary",[247,1430,346],{"class":326},[247,1432,1433,1435,1437,1439,1441,1443,1445,1447,1450,1452,1454,1456,1458,1461],{"class":249,"line":412},[247,1434,1399],{"class":322},[247,1436,1382],{"class":502},[247,1438,1386],{"class":330},[247,1440,398],{"class":326},[247,1442,1408],{"class":392},[247,1444,942],{"class":502},[247,1446,429],{"class":326},[247,1448,1449],{"class":256},".m3u8",[247,1451,429],{"class":326},[247,1453,1420],{"class":502},[247,1455,1423],{"class":322},[247,1457,340],{"class":326},[247,1459,1460],{"class":256},"application\u002Fvnd.apple.mpegurl",[247,1462,346],{"class":326},[247,1464,1465,1468,1470,1472,1474],{"class":249,"line":572},[247,1466,1467],{"class":322},"    return",[247,1469,1332],{"class":392},[247,1471,942],{"class":502},[247,1473,1386],{"class":330},[247,1475,441],{"class":502},[247,1477,1478],{"class":249,"line":874},[247,1479,1480],{"class":326},"  }\n",[247,1482,1483,1485],{"class":249,"line":901},[247,1484,575],{"class":326},[247,1486,441],{"class":330},[182,1488,1489,1490,1492],{},"The built-in ",[185,1491,745],{}," is exported for use as a fallback.",[230,1494,1496],{"id":1495},"advanced-raw-handler","Advanced: raw handler",[182,1498,1499,1500,1503],{},"For custom routing, use ",[185,1501,1502],{},"createStaticHandler"," directly:",[237,1505,1507],{"className":313,"code":1506,"language":315,"meta":243,"style":243},"import { createStaticHandler } from '@miiajs\u002Fserve-static'\n\napp.addRoute('GET', '\u002Fcustom\u002F*', createStaticHandler('.\u002Fpublic', { maxAge: 3600 }))\n",[185,1508,1509,1528,1532],{"__ignoreMap":243},[247,1510,1511,1513,1515,1518,1520,1522,1524,1526],{"class":249,"line":250},[247,1512,323],{"class":322},[247,1514,327],{"class":326},[247,1516,1517],{"class":330}," createStaticHandler",[247,1519,334],{"class":326},[247,1521,337],{"class":322},[247,1523,340],{"class":326},[247,1525,187],{"class":256},[247,1527,346],{"class":326},[247,1529,1530],{"class":249,"line":349},[247,1531,373],{"emptyLinePlaceholder":372},[247,1533,1534,1537,1539,1542,1544,1546,1548,1550,1552,1554,1557,1559,1561,1563,1565,1567,1569,1571,1573,1575,1578,1580,1582,1584],{"class":249,"line":369},[247,1535,1536],{"class":330},"app",[247,1538,398],{"class":326},[247,1540,1541],{"class":392},"addRoute",[247,1543,942],{"class":330},[247,1545,429],{"class":326},[247,1547,1159],{"class":256},[247,1549,429],{"class":326},[247,1551,421],{"class":326},[247,1553,340],{"class":326},[247,1555,1556],{"class":256},"\u002Fcustom\u002F*",[247,1558,429],{"class":326},[247,1560,421],{"class":326},[247,1562,1517],{"class":392},[247,1564,942],{"class":330},[247,1566,429],{"class":326},[247,1568,436],{"class":256},[247,1570,429],{"class":326},[247,1572,421],{"class":326},[247,1574,327],{"class":326},[247,1576,1577],{"class":502}," maxAge",[247,1579,506],{"class":326},[247,1581,527],{"class":526},[247,1583,334],{"class":326},[247,1585,1586],{"class":330},"))\n",[230,1588,1590],{"id":1589},"security","Security",[1151,1592,1593,1607,1623,1629],{},[1154,1594,1595,1599,1600,1603,1604,1606],{},[1596,1597,1598],"strong",{},"Lexical traversal protection"," - paths normalized with ",[185,1601,1602],{},".."," segments outside ",[185,1605,735],{}," are rejected before any filesystem call.",[1154,1608,1609,1612,1613,1616,1617,1619,1620,1622],{},[1596,1610,1611],{},"Symlink escape protection"," - ",[185,1614,1615],{},"realpath()"," resolves the target and re-checks it stays under ",[185,1618,735],{},". A symlink inside ",[185,1621,1222],{}," pointing outside is treated as 404.",[1154,1624,1625,1628],{},[1596,1626,1627],{},"Dotfile guard"," - on by default, see above.",[1154,1630,1631,1634,1635,1638,1639,1641,1642,1644],{},[1596,1632,1633],{},"Fallback path validation"," - if you set ",[185,1636,1637],{},"fallback: '.something'"," while ",[185,1640,690],{}," is disabled, ",[185,1643,1502],{}," throws at startup rather than serving a guard-bypassing fallback.",[230,1646,1648],{"id":1647},"supported-mime-types","Supported MIME types",[579,1650,1651,1661],{},[582,1652,1653],{},[585,1654,1655,1658],{},[588,1656,1657],{},"Category",[588,1659,1660],{},"Extensions",[601,1662,1663,1690,1709,1725,1756,1778,1800],{},[585,1664,1665,1668],{},[606,1666,1667],{},"Text",[606,1669,1670,220,1672,220,1675,220,1678,220,1681,220,1684,220,1687],{},[185,1671,1188],{},[185,1673,1674],{},".css",[185,1676,1677],{},".txt",[185,1679,1680],{},".csv",[185,1682,1683],{},".xml",[185,1685,1686],{},".yaml",[185,1688,1689],{},".yml",[585,1691,1692,1695],{},[606,1693,1694],{},"JavaScript",[606,1696,1697,220,1700,220,1703,220,1706],{},[185,1698,1699],{},".js",[185,1701,1702],{},".mjs",[185,1704,1705],{},".cjs",[185,1707,1708],{},".wasm",[585,1710,1711,1714],{},[606,1712,1713],{},"Data",[606,1715,1716,220,1719,220,1722],{},[185,1717,1718],{},".json",[185,1720,1721],{},".map",[185,1723,1724],{},".pdf",[585,1726,1727,1730],{},[606,1728,1729],{},"Images",[606,1731,1732,220,1735,220,1738,220,1741,220,1744,220,1747,220,1750,220,1753],{},[185,1733,1734],{},".svg",[185,1736,1737],{},".png",[185,1739,1740],{},".jpg",[185,1742,1743],{},".jpeg",[185,1745,1746],{},".gif",[185,1748,1749],{},".webp",[185,1751,1752],{},".avif",[185,1754,1755],{},".ico",[585,1757,1758,1761],{},[606,1759,1760],{},"Fonts",[606,1762,1763,220,1766,220,1769,220,1772,220,1775],{},[185,1764,1765],{},".woff",[185,1767,1768],{},".woff2",[185,1770,1771],{},".ttf",[185,1773,1774],{},".otf",[185,1776,1777],{},".eot",[585,1779,1780,1783],{},[606,1781,1782],{},"Audio\u002FVideo",[606,1784,1785,220,1788,220,1791,220,1794,220,1797],{},[185,1786,1787],{},".mp3",[185,1789,1790],{},".ogg",[185,1792,1793],{},".wav",[185,1795,1796],{},".mp4",[185,1798,1799],{},".webm",[585,1801,1802,1805],{},[606,1803,1804],{},"Archives",[606,1806,1807,220,1810,220,1813],{},[185,1808,1809],{},".zip",[185,1811,1812],{},".gz",[185,1814,1815],{},".tar",[182,1817,1818,1819,398],{},"Unknown extensions default to ",[185,1820,1821],{},"application\u002Foctet-stream",[230,1823,1825],{"id":1824},"api-reference","API Reference",[460,1827,1829],{"id":1828},"servestaticapp-prefix-root-options","serveStatic(app, prefix, root, options?)",[182,1831,1832,1833,1836,1837,1839],{},"Registers a wildcard ",[185,1834,1835],{},"GET ${prefix}\u002F*"," route on ",[185,1838,1536],{},". Convenience wrapper for the common case.",[237,1841,1843],{"className":313,"code":1842,"language":315,"meta":243,"style":243},"serveStatic(app: Miia, prefix: string, root: string, options?: ServeStaticOptions): void\n",[185,1844,1845],{"__ignoreMap":243},[247,1846,1847,1849,1852,1854,1857,1859,1862,1864,1867,1870,1873],{"class":249,"line":250},[247,1848,415],{"class":392},[247,1850,1851],{"class":330},"(app: Miia",[247,1853,421],{"class":326},[247,1855,1856],{"class":330}," prefix: string",[247,1858,421],{"class":326},[247,1860,1861],{"class":330}," root: string",[247,1863,421],{"class":326},[247,1865,1866],{"class":330}," options",[247,1868,1869],{"class":326},"?:",[247,1871,1872],{"class":330}," ServeStaticOptions): ",[247,1874,1875],{"class":326},"void\n",[460,1877,1879],{"id":1878},"createstatichandlerroot-options","createStaticHandler(root, options?)",[182,1881,1882,1883,1886],{},"Returns a ",[185,1884,1885],{},"RequestContext","-handler. Use when you need to mount the handler under a custom route, behind guards, or composed with middleware.",[237,1888,1890],{"className":313,"code":1889,"language":315,"meta":243,"style":243},"createStaticHandler(root: string, options?: ServeStaticOptions): (ctx: RequestContext) => Promise\u003CResponse>\n",[185,1891,1892],{"__ignoreMap":243},[247,1893,1894,1896,1899,1901,1903,1905,1908,1910,1912,1915,1917,1920,1922,1924,1927,1930,1932],{"class":249,"line":250},[247,1895,1502],{"class":392},[247,1897,1898],{"class":330},"(root: string",[247,1900,421],{"class":326},[247,1902,1866],{"class":330},[247,1904,1869],{"class":326},[247,1906,1907],{"class":330}," ServeStaticOptions)",[247,1909,506],{"class":326},[247,1911,1382],{"class":326},[247,1913,1914],{"class":1385},"ctx",[247,1916,506],{"class":326},[247,1918,1919],{"class":253}," RequestContext",[247,1921,1389],{"class":326},[247,1923,1392],{"class":379},[247,1925,1926],{"class":253}," Promise",[247,1928,1929],{"class":326},"\u003C",[247,1931,29],{"class":330},[247,1933,1934],{"class":326},">\n",[460,1936,1938],{"id":1937},"getmimetypepath","getMimeType(path)",[182,1940,1941,1942,398],{},"Built-in MIME resolver. Exported for use as a fallback inside a custom ",[185,1943,745],{},[237,1945,1947],{"className":313,"code":1946,"language":315,"meta":243,"style":243},"getMimeType(path: string): string\n",[185,1948,1949],{"__ignoreMap":243},[247,1950,1951,1953],{"class":249,"line":250},[247,1952,745],{"class":392},[247,1954,1955],{"class":330},"(path: string): string\n",[230,1957,33],{"id":1958},"testing",[182,1960,1961,1962,1965,1966,1968,1969,506],{},"Use a ",[185,1963,1964],{},"Miia"," instance directly - mount ",[185,1967,415],{}," against a temp directory, then drive it with ",[185,1970,1971],{},"app.fetch()",[237,1973,1975],{"className":313,"code":1974,"language":315,"meta":243,"style":243},"import { mkdtempSync, writeFileSync } from 'node:fs'\nimport { tmpdir } from 'node:os'\nimport { join } from 'node:path'\nimport { Miia } from '@miiajs\u002Fcore'\nimport { serveStatic } from '@miiajs\u002Fserve-static'\n\nconst root = mkdtempSync(join(tmpdir(), 'static-'))\nwriteFileSync(join(root, 'hello.txt'), 'hello world')\n\nconst app = new Miia({ logger: false })\nserveStatic(app, '\u002Fstatic', root)\nawait app.init()\n\nconst res = await app.fetch(new Request('http:\u002F\u002Flocalhost\u002Fstatic\u002Fhello.txt'))\nexpect(res.status).toBe(200)\nexpect(await res.text()).toBe('hello world')\n\nawait app.destroy()\n",[185,1976,1977,2002,2022,2042,2060,2078,2082,2116,2150,2154,2182,2201,2215,2220,2259,2285,2318,2323],{"__ignoreMap":243},[247,1978,1979,1981,1983,1986,1988,1991,1993,1995,1997,2000],{"class":249,"line":250},[247,1980,323],{"class":322},[247,1982,327],{"class":326},[247,1984,1985],{"class":330}," mkdtempSync",[247,1987,421],{"class":326},[247,1989,1990],{"class":330}," writeFileSync",[247,1992,334],{"class":326},[247,1994,337],{"class":322},[247,1996,340],{"class":326},[247,1998,1999],{"class":256},"node:fs",[247,2001,346],{"class":326},[247,2003,2004,2006,2008,2011,2013,2015,2017,2020],{"class":249,"line":349},[247,2005,323],{"class":322},[247,2007,327],{"class":326},[247,2009,2010],{"class":330}," tmpdir",[247,2012,334],{"class":326},[247,2014,337],{"class":322},[247,2016,340],{"class":326},[247,2018,2019],{"class":256},"node:os",[247,2021,346],{"class":326},[247,2023,2024,2026,2028,2031,2033,2035,2037,2040],{"class":249,"line":369},[247,2025,323],{"class":322},[247,2027,327],{"class":326},[247,2029,2030],{"class":330}," join",[247,2032,334],{"class":326},[247,2034,337],{"class":322},[247,2036,340],{"class":326},[247,2038,2039],{"class":256},"node:path",[247,2041,346],{"class":326},[247,2043,2044,2046,2048,2050,2052,2054,2056,2058],{"class":249,"line":376},[247,2045,323],{"class":322},[247,2047,327],{"class":326},[247,2049,331],{"class":330},[247,2051,334],{"class":326},[247,2053,337],{"class":322},[247,2055,340],{"class":326},[247,2057,343],{"class":256},[247,2059,346],{"class":326},[247,2061,2062,2064,2066,2068,2070,2072,2074,2076],{"class":249,"line":407},[247,2063,323],{"class":322},[247,2065,327],{"class":326},[247,2067,356],{"class":330},[247,2069,334],{"class":326},[247,2071,337],{"class":322},[247,2073,340],{"class":326},[247,2075,187],{"class":256},[247,2077,346],{"class":326},[247,2079,2080],{"class":249,"line":412},[247,2081,373],{"emptyLinePlaceholder":372},[247,2083,2084,2086,2089,2091,2093,2095,2098,2100,2103,2105,2107,2109,2112,2114],{"class":249,"line":572},[247,2085,380],{"class":379},[247,2087,2088],{"class":330}," root ",[247,2090,386],{"class":326},[247,2092,1985],{"class":392},[247,2094,942],{"class":330},[247,2096,2097],{"class":392},"join",[247,2099,942],{"class":330},[247,2101,2102],{"class":392},"tmpdir",[247,2104,395],{"class":330},[247,2106,421],{"class":326},[247,2108,340],{"class":326},[247,2110,2111],{"class":256},"static-",[247,2113,429],{"class":326},[247,2115,1586],{"class":330},[247,2117,2118,2121,2123,2125,2128,2130,2132,2135,2137,2139,2141,2143,2146,2148],{"class":249,"line":874},[247,2119,2120],{"class":392},"writeFileSync",[247,2122,942],{"class":330},[247,2124,2097],{"class":392},[247,2126,2127],{"class":330},"(root",[247,2129,421],{"class":326},[247,2131,340],{"class":326},[247,2133,2134],{"class":256},"hello.txt",[247,2136,429],{"class":326},[247,2138,1389],{"class":330},[247,2140,421],{"class":326},[247,2142,340],{"class":326},[247,2144,2145],{"class":256},"hello world",[247,2147,429],{"class":326},[247,2149,441],{"class":330},[247,2151,2152],{"class":249,"line":901},[247,2153,373],{"emptyLinePlaceholder":372},[247,2155,2156,2158,2160,2162,2164,2166,2168,2171,2174,2176,2178,2180],{"class":249,"line":916},[247,2157,380],{"class":379},[247,2159,383],{"class":330},[247,2161,386],{"class":326},[247,2163,389],{"class":326},[247,2165,331],{"class":392},[247,2167,942],{"class":330},[247,2169,2170],{"class":326},"{",[247,2172,2173],{"class":502}," logger",[247,2175,506],{"class":326},[247,2177,552],{"class":539},[247,2179,334],{"class":326},[247,2181,441],{"class":330},[247,2183,2184,2186,2188,2190,2192,2194,2196,2198],{"class":249,"line":923},[247,2185,415],{"class":392},[247,2187,418],{"class":330},[247,2189,421],{"class":326},[247,2191,340],{"class":326},[247,2193,426],{"class":256},[247,2195,429],{"class":326},[247,2197,421],{"class":326},[247,2199,2200],{"class":330}," root)\n",[247,2202,2203,2205,2207,2209,2212],{"class":249,"line":928},[247,2204,931],{"class":322},[247,2206,934],{"class":330},[247,2208,398],{"class":326},[247,2210,2211],{"class":392},"init",[247,2213,2214],{"class":330},"()\n",[247,2216,2218],{"class":249,"line":2217},13,[247,2219,373],{"emptyLinePlaceholder":372},[247,2221,2223,2225,2228,2230,2233,2235,2237,2240,2242,2245,2248,2250,2252,2255,2257],{"class":249,"line":2222},14,[247,2224,380],{"class":379},[247,2226,2227],{"class":330}," res ",[247,2229,386],{"class":326},[247,2231,2232],{"class":322}," await",[247,2234,934],{"class":330},[247,2236,398],{"class":326},[247,2238,2239],{"class":392},"fetch",[247,2241,942],{"class":330},[247,2243,2244],{"class":326},"new",[247,2246,2247],{"class":392}," Request",[247,2249,942],{"class":330},[247,2251,429],{"class":326},[247,2253,2254],{"class":256},"http:\u002F\u002Flocalhost\u002Fstatic\u002Fhello.txt",[247,2256,429],{"class":326},[247,2258,1586],{"class":330},[247,2260,2262,2265,2268,2270,2273,2275,2278,2280,2283],{"class":249,"line":2261},15,[247,2263,2264],{"class":392},"expect",[247,2266,2267],{"class":330},"(res",[247,2269,398],{"class":326},[247,2271,2272],{"class":330},"status)",[247,2274,398],{"class":326},[247,2276,2277],{"class":392},"toBe",[247,2279,942],{"class":330},[247,2281,2282],{"class":526},"200",[247,2284,441],{"class":330},[247,2286,2288,2290,2292,2294,2297,2299,2301,2304,2306,2308,2310,2312,2314,2316],{"class":249,"line":2287},16,[247,2289,2264],{"class":392},[247,2291,942],{"class":330},[247,2293,931],{"class":322},[247,2295,2296],{"class":330}," res",[247,2298,398],{"class":326},[247,2300,456],{"class":392},[247,2302,2303],{"class":330},"())",[247,2305,398],{"class":326},[247,2307,2277],{"class":392},[247,2309,942],{"class":330},[247,2311,429],{"class":326},[247,2313,2145],{"class":256},[247,2315,429],{"class":326},[247,2317,441],{"class":330},[247,2319,2321],{"class":249,"line":2320},17,[247,2322,373],{"emptyLinePlaceholder":372},[247,2324,2326,2328,2330,2332,2335],{"class":249,"line":2325},18,[247,2327,931],{"class":322},[247,2329,934],{"class":330},[247,2331,398],{"class":326},[247,2333,2334],{"class":392},"destroy",[247,2336,2214],{"class":330},[182,2338,2339,2340,2342,2343,2345],{},"The same pattern works for asserting ",[185,2341,191],{}," round-trips, ",[185,2344,199],{}," slicing, dotfile blocks, and SPA fallback - just toggle the relevant option and inspect headers on the response.",[230,2347,2349],{"id":2348},"exports","Exports",[237,2351,2353],{"className":313,"code":2352,"language":315,"meta":243,"style":243},"import {\n  serveStatic,\n  createStaticHandler,\n  getMimeType,\n  type ServeStaticOptions,\n} from '@miiajs\u002Fserve-static'\n",[185,2354,2355,2361,2368,2375,2381,2391],{"__ignoreMap":243},[247,2356,2357,2359],{"class":249,"line":250},[247,2358,323],{"class":322},[247,2360,497],{"class":326},[247,2362,2363,2366],{"class":249,"line":349},[247,2364,2365],{"class":330},"  serveStatic",[247,2367,516],{"class":326},[247,2369,2370,2373],{"class":249,"line":369},[247,2371,2372],{"class":330},"  createStaticHandler",[247,2374,516],{"class":326},[247,2376,2377,2379],{"class":249,"line":376},[247,2378,1377],{"class":330},[247,2380,516],{"class":326},[247,2382,2383,2386,2389],{"class":249,"line":407},[247,2384,2385],{"class":322},"  type",[247,2387,2388],{"class":330}," ServeStaticOptions",[247,2390,516],{"class":326},[247,2392,2393,2395,2397,2399,2401],{"class":249,"line":412},[247,2394,575],{"class":326},[247,2396,337],{"class":322},[247,2398,340],{"class":326},[247,2400,187],{"class":256},[247,2402,346],{"class":326},[230,2404,2406],{"id":2405},"see-also","See also",[1151,2408,2409,2418,2426],{},[1154,2410,2411,2414,2415,2417],{},[2412,2413,75],"a",{"href":76}," - mounting ",[185,2416,415],{}," behind guards or custom middleware.",[1154,2419,2420,2425],{},[2412,2421,2422],{"href":152},[185,2423,2424],{},"@miiajs\u002Fnode-server"," - the Node.js HTTP adapter that hosts the static handler.",[1154,2427,2428,2433],{},[2412,2429,2430],{"href":156},[185,2431,2432],{},"@miiajs\u002Fuws-server"," - the uWebSockets.js adapter for higher throughput.",[2435,2436,2437],"style",{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}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);}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}",{"title":243,"searchDepth":349,"depth":349,"links":2439},[2440,2441,2444,2445,2451,2452,2453,2454,2455,2456,2457,2462,2463,2464],{"id":232,"depth":349,"text":13},{"id":306,"depth":349,"text":307,"children":2442},[2443],{"id":462,"depth":369,"text":463},{"id":763,"depth":349,"text":764},{"id":972,"depth":349,"text":973,"children":2446},[2447,2448,2449,2450],{"id":976,"depth":369,"text":977},{"id":1010,"depth":369,"text":1011},{"id":1044,"depth":369,"text":211},{"id":1059,"depth":369,"text":1060},{"id":1088,"depth":349,"text":1089},{"id":1209,"depth":349,"text":1210},{"id":1307,"depth":349,"text":1308},{"id":1495,"depth":349,"text":1496},{"id":1589,"depth":349,"text":1590},{"id":1647,"depth":349,"text":1648},{"id":1824,"depth":349,"text":1825,"children":2458},[2459,2460,2461],{"id":1828,"depth":369,"text":1829},{"id":1878,"depth":369,"text":1879},{"id":1937,"depth":369,"text":1938},{"id":1958,"depth":349,"text":33},{"id":2348,"depth":349,"text":2349},{"id":2405,"depth":349,"text":2406},"Static file server with Range, conditional GET, charset, dotfile guard, and SPA fallback.","md",{},{"title":109,"description":2465},"2nCAfeR4NwflNkzSGxqW4_ZBsyNyS864uL_iP6l7v1Q",[2471,2473],{"title":105,"path":106,"stem":107,"description":2472,"children":-1},"Redis Streams transport for @miiajs\u002Fmessaging - consumer groups, ZSET-backed retry, auto-DLQ.",{"title":27,"path":114,"stem":115,"description":2474,"children":-1},"Lightweight auth primitives - AuthProvider interface, AuthGuard factory, HTTP token extractors, timing-safe utilities.",1778575273805]