Repository navigation
Added
@tetsujs/static, a new package:staticFiles()serves the files of a directory fromfallbackor a route, a built site, a single-page app or assets, inside the pipeline, so the application's hooks apply to them. A path is checked before the disk is touched, a directory is redirected to its trailing slash, a file hasETagandLast-Modifiedwith304, and Bun answersRange.notFoundsends a page of the site to a browser,spathe app's shell, andprecompressedthe.bror.gzcopy beside a file. The route stays out of the OpenAPI document unless it saysdocs: { hidden: false }(#74).@tetsujs/core: a status of a response map can name the media type of a body that is not JSON —{ 200: { contentType: "text/csv", body } }— for a status the handler answers with aResponseit builds: a file, a CSV export,sse(). Returning a value for it, or nothing, is a compile error, since a value would leave as JSON and nothing as an empty body; a type the compiler knows only as astringcounts as not JSON, and where it does not see the key at all, it is a500when responses are validated.route()refuses a content type that is not a bare type or range, such as one with a charset.@tetsujs/openapi: such a status is documented under its own media type, with itsbodyas the schema, instead ofapplication/json. So is a responsedocumented()gives a hook, with acontentTypeof its own;documented()refuses one that is not a bare type or range.@tetsujs/openapi:documented()annotates a handler as it does a hook, so a package's handler describes every route that mounts it. Its responses are the route's own, andhidden: truekeeps the route out of the document unless the route saysdocs: { hidden: false }.@tetsujs/openapi:assertDescribedtakes a body under a range of media types, such asimage/*or*/*, and compares types without regard to case. It parses a body as JSON only underapplication/jsonor a+jsontype, and takes an empty body under any other.
Fixed
@tetsujs/core: a route with aqueryschema answers a request without a usableHost, such as an HTTP/1.0 health check, instead of failing it with a500. Bun leavesreq.urlrelative then, and the query is read against a placeholder origin. AHostsuch as[makesreq.urlno URL at all, and such a request has no query.@tetsujs/request-log: for the same requests,arrivalLog()no longer turns the request into a500, andaccessLog()writes its record instead of reporting a failure. The path is read from a relativereq.urltoo, and areq.urlthat is no URL is written as it came, up to its query.@tetsujs/core: a response map keyed by anything but a status, a range such as4XXordefault, or with an entry that is neither a schema,nullnor an object of parts, is refused where the route is declared. It passed: a key such as600matched no response and was documented as one, an entry such as a bare string made every validated response of its status a500, anundefinedentry went unchecked, andopenapi()threw aTypeErroron either of the last two.defaultand the ranges, OpenAPI's own keys, are taken as before: they are documented, and declare no status a response may leave with.@tetsujs/openapi: a response a hook documents below400without aschemahas no body in the document — a redirect, or the refusal of asecured()hook that sends to a sign-in page. It was described as the error envelope.@tetsujs/openapi: the responses hooks document are no longer merged by status and description. Two guards that answer403 Forbiddenwith codes of their own, such asNOT_OWNERandPLAN_LIMIT, are both documented, where the second was dropped; a description that a coded response already gives is said once; and two definitions of one code with differentfieldsgive a warning, where one was dropped without a word.@tetsujs/openapi:defaultand a range such as4XXin a response map are described as what they are,Any other responseandClient error, not asHTTP NaN.
Full Changelog: v0.6.2...v0.6.3