{"id":13896555,"url":"https://github.com/creationix/weblit","last_synced_at":"2025-08-16T15:17:11.698Z","repository":{"id":28482956,"uuid":"31999048","full_name":"creationix/weblit","owner":"creationix","description":"A web framework for luvit 2.0 and lit","archived":false,"fork":false,"pushed_at":"2022-10-16T07:17:58.000Z","size":71,"stargazers_count":112,"open_issues_count":11,"forks_count":24,"subscribers_count":15,"default_branch":"master","last_synced_at":"2025-03-24T04:14:16.393Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Lua","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/creationix.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-03-11T04:54:39.000Z","updated_at":"2025-01-19T14:40:53.000Z","dependencies_parsed_at":"2023-01-14T08:54:12.044Z","dependency_job_id":null,"html_url":"https://github.com/creationix/weblit","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/creationix%2Fweblit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/creationix%2Fweblit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/creationix%2Fweblit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/creationix%2Fweblit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/creationix","download_url":"https://codeload.github.com/creationix/weblit/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248145472,"owners_count":21055136,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-06T18:03:00.185Z","updated_at":"2025-04-10T02:43:52.610Z","avatar_url":"https://github.com/creationix.png","language":"Lua","funding_links":[],"categories":["Lua"],"sub_categories":[],"readme":"# weblit\n\nA web framework for luvit 2.0 and lit\n\nWeblit is a collection of lit packages that together form a nice web framework.\n\n## weblit-app\n\nThis is the core of the framework.  It's export value is the app itself.  The\nconfig functions can be chained off this config for super terse syntax.\n\n```lua\nrequire('weblit-app')\n\n  .bind({\n    host = \"0.0.0.0\",\n    port = 8080\n  })\n\n  .use(require('weblit-logger'))\n  .use(require('weblit-auto-headers'))\n  .use(require('weblit-etag-cache'))\n\n  .route({\n    method = \"GET\",\n    path = \"/do/:user/:action\",\n    domain = \"*.myapp.io\"\n  }, function (req, res, go)\n    -- Handle route\n  end)\n\n  .start()\n\n```\n\n### bind(options)\n\nUse this to configure your server.  You can bind to multiple addresses and\nports. For example, the same server can listen on port `8080` using normal HTTP\nwhile also listening on port `8443` using HTTPS.\n\n```lua\n-- Listen on port 8080 internally using plain HTTP.\n.bind({\n  host = \"127.0.0.1\",\n  port = 8080\n})\n\n-- Also listen on port 8443 externally using encrypted HTTPS.\n.bind({\n  host = \"0.0.0.0\",\n  port = 8443,\n  tls = {\n    cert = module:load(\"cert.pem\"),\n    key = module:load(\"key.pem\"),\n  }\n})\n```\n\nThe `host` option defaults to `\"127.0.0.1\"`.  The default port depends on if\nyou're running as root and if the connection is TLS encrypted.\n\n|      | Root | User\n|------|-----:|------:\n|HTTP  | 80   | 8080\n|HTTPS | 442  | 8443\n\n\n### use(middleware)\n\nThis adds a raw middleware to the chain.  It's signature is:\n\n```lua\n.use(function (req, res, go)\n  -- Log the request table\n  p(\"request\", req)\n  -- Hand off to the next layer.\n  return go()\nend)\n```\n\nThe `req` table will contain information about the HTTP request.  This includes\nseveral fields:\n\n - `socket` - The raw libuv `uv_tty_t` socket.\n - `method` - The HTTP request method verb like `GET` or `POST`.\n - `path` - The raw HTTP request path (including query string).\n - `headers` - A list of headers.  Each header is a table with two entries for\n   key and value.  For convenience, there are special `__index` and\n   `__newindex` metamethods that let you treat this like a case insensitive\n   key/value store.\n - `version` - The HTTP version (Usually either `1.0` or `1.1`).\n - `keepAlive` - A flag telling you if this should be a keepalive connection.\n - `body` - The request body as a string.  In the future, this may also be a stream.\n\nThe `res` table also has some conventions used to form the response a piece at a\ntime.  Initially it contains:\n\n - `code` - The response status code. Initially contains `404`.\n - `headers` - Another special headers table like in `req`.\n - `body` - The response body to send. Initially contains `\"Not Found\\n\"`.\n\nThe `go` function is to be called if you wish to not handle a request.  This\nallows other middleware layers to get a chance to respond to the request.  Use a\ntail call if there is nothing more to do.\n\nOtherwise do further processing after `go` returns.  At this point, all inner\nlayers have finished and a response is ready in `res`.\n\n### route(options, middleware)\n\nRoute is like use, but allows you to pre-filter the requests before the middleware\nis called.\n\n```lua\n.route({\n  method = \"PUT\",\n  path = \"/upload/:username\"\n}, function (req, res, go)\n  local url = saveFile(req.params.username, req.body)\n  res.code = 201\n  res.headers.Location = url\nend)\n```\n\nThe route options accept several parameters:\n\n - `method` - This is a simple filter on a specific HTTP method verb.\n - `path` - This is either an exact match or can contain patterns.  Segments\n   looking like `:name` will match single path segments while `:name:` will\n   match multiple segments.  The matches will go into `req.params`.  Also any\n   query string will be stripped off, parsed out, and stored in `req.query`.\n - `host` - Will filter against the `Host` header.  This can be an exact match\n   or a glob match like `*.mydomain.org`.\n - `filter` - Filter is a custom lua function that accepts `req` and returns\n   `true` or `false`.\n\nIf the request matches all the requirements, then the middleware is called the\nsame as with `use`.\n\n### start\n\nBind to the port(s), listen on the socket(s) and start accepting connections.\n\n## weblit-logger\n\nThis is a simple middleware that logs the request method, url and user agent.\nIt also includes the response status code.\n\nMake sure to use it at the top of your middleware chain so that it's able to see\nthe final response code sent to the client.\n\n```lua\n.use(require('weblit-logger'))\n```\n\n## weblit-auto-headers\n\nThis implements lots of conventions and useful defaults that help your app\nimplement a proper HTTP server.\n\nYou should always use this near the top of the list.  The only middleware that\ngoes before this is the logger.\n\n\n```lua\n.use(require('weblit-auto-headers'))\n```\n\n## weblit-etag-cache\n\nThis caches responses in memory keyed by etag.  If there is no etag, but there\nis a response body, it will use the body to generate an etag.\n\nPut this in your list after auto-headers, but before custom server logic.\n\n```lua\n.use(require('weblit-etag-cache'))\n```\n\n## weblit-static\n\nThis middleware serves static files to the user.  Use this to serve your client-\nside web assets.\n\nUsage is pretty simplistic for now.\n\n```lua\nlocal static = require('weblit-static')\napp.use(static(\"path/to/static/assets\"))\n```\n\nIf you want to only match a sub-path, use the router.\n\n```lua\napp.route({\n  path = \"/blog/:path:\"\n}, static(pathJoin(module.dir, \"articles\")))\n```\n\nThe `path` param will be used if it exists and the full path will be used\notherwise.\n\n## weblit-websocket\n\nThis implements a websocket upgrade handler.  You can choose the subprotocol and\nother routing information.\n\n```lua\napp.websocket({\n  path = \"/v2/socket\", -- Prefix for matching\n  protocol = \"virgo/2.0\", -- Restrict to a websocket sub-protocol\n}, function (req, read, write)\n  -- Log the request headers\n  p(req)\n  -- Log and echo all messages\n  for message in read do\n    write(message)\n  end\n  -- End the stream\n  write()\nend)\n```\n\n\n## weblit\n\nThis is the metapackage that simply includes the other modules.\n\nIt exposes the other modules as a single exports table.\n\n```lua\nreturn {\n  app = require('weblit-app'),\n  autoHeaders = require('weblit-auto-headers'),\n  etagCache = require('weblit-etag-cache'),\n  logger = require('weblit-logger'),\n  static = require('weblit-static'),\n  websocket = require('weblit-websocket'),\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcreationix%2Fweblit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcreationix%2Fweblit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcreationix%2Fweblit/lists"}