{"id":45447303,"url":"https://github.com/nguyenphuminh/cmdweb","last_synced_at":"2026-02-22T04:04:46.775Z","repository":{"id":244417026,"uuid":"815157782","full_name":"nguyenphuminh/cmdweb","owner":"nguyenphuminh","description":"A web framework for Batch, create a server using Windows Batch files","archived":false,"fork":false,"pushed_at":"2024-12-10T17:45:17.000Z","size":146,"stargazers_count":6,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2024-12-10T19:07:33.831Z","etag":null,"topics":["backend","batch","batch-script","cmd","cmdweb","framework","http","library","networking","runtime","web","web-framework"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nguyenphuminh.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-06-14T13:27:16.000Z","updated_at":"2024-12-10T17:45:22.000Z","dependencies_parsed_at":"2024-06-28T05:22:30.648Z","dependency_job_id":"f8d9625e-ac59-44b1-9837-66123e31de51","html_url":"https://github.com/nguyenphuminh/cmdweb","commit_stats":null,"previous_names":["nguyenphuminh/cmdweb"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/nguyenphuminh/cmdweb","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nguyenphuminh%2Fcmdweb","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nguyenphuminh%2Fcmdweb/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nguyenphuminh%2Fcmdweb/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nguyenphuminh%2Fcmdweb/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nguyenphuminh","download_url":"https://codeload.github.com/nguyenphuminh/cmdweb/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nguyenphuminh%2Fcmdweb/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29704420,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-22T03:17:42.375Z","status":"ssl_error","status_checked_at":"2026-02-22T03:17:31.622Z","response_time":110,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["backend","batch","batch-script","cmd","cmdweb","framework","http","library","networking","runtime","web","web-framework"],"created_at":"2026-02-22T04:04:46.700Z","updated_at":"2026-02-22T04:04:46.769Z","avatar_url":"https://github.com/nguyenphuminh.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"## Introduction\r\n\r\nCmdweb is a framework/runtime that allows backend web development in Batch. While there are much better languages, I sometimes give myself a little challenge to go back and write Batch scripts. A big problem that Batch has is the inability to do server-side work by itself, so I made this as a plugin for Batch to do so.\r\n\r\nDisclaimer: Project is heavily in-dev and there might be vulnerabilities, do not use for anything serious!\r\n\r\n## Getting started\r\n\r\n1. Install Node.js.\r\n2. Git clone this repo.\r\n3. Create a Batch file for your server, a Cmdweb project will look like this:\r\n```bat\r\n:: Get the necessary resources\r\ncall lib/init\r\n\r\n:: Main code goes here\r\n\r\n:: Start the js runtime\r\ncall lib/start \u003cport\u003e \"\u003chostname\u003e\"\r\n```\r\n\r\nIf not specified, port will be 8000 and hostname will be `127.0.0.1`.\r\n\r\n## Routing\r\n\r\nRouting can be done as easily as:\r\n```bat\r\ncall lib/listen \"method\" \"/route\" handler\r\n```\r\n\r\nHere, `\"method\"` is any valid HTTP/1.1 method, `\"/route\"` is self-explanatory, and `handler` is the function (batch file) to call when there is a request coming at this route.\r\n\r\n## Handle requests\r\n\r\nIn a `handler.bat` file, you must follow this template:\r\n```bat\r\n@echo off\r\ncall lib/get_request %~1\r\n\r\n:: Main code goes here\r\n\r\ncall lib/respond %~1\r\n```\r\n\r\n`@echo off` is just there for clean logs, and `%~1` is the ID of the request. Calling `lib/get_request` will get the information of this request, and calling `lib/respond` sends the response to the client.\r\n\r\n### Request body\r\n\r\nYou can get the request body using these variables:\r\n```bat\r\n:: This variable contains the request body\r\necho %req.body%\r\n:: URL (contains query params)\r\necho %req.url%\r\n:: Path (does not contain query params)\r\necho %req.path%\r\n:: Remote address\r\necho %req.address%\r\n:: Headers are stored in a dictionary-like format, example:\r\necho %req.headers[\"content-type\"]%\r\n```\r\n\r\n### Response body\r\n\r\nHere is how to create a response:\r\n```bat\r\n:: Response body\r\nset res.body=Hello, World!\r\n:: Status code, default is 200\r\nset res.statusCode=200\r\n:: Header JSON string\r\nset res.headers={\"content-type\":\"text/html\"}\r\n```\r\n\r\nThough, note that Batch commands are limited to 8197 characters, so minus the variable length you can have around ~8100 characters in a variable. I will soon add streaming to solve this problem.\r\n\r\n### Serving static files\r\n\r\nYou can respond with a static file by providing a path in this variable:\r\n```bat\r\nset res.file=./path/to/file\r\n```\r\n\r\nNote that you must provide the content type yourself in the headers if you need.\r\n\r\n### URL params\r\n\r\nSuppose you have a route like this:\r\n```bat\r\ncall lib/listen \"get\" \"/account/:name\" get_account\r\n```\r\n\r\nIn the handler, you can get the `name` parameter:\r\n```bat\r\necho %req.params.name%\r\n```\r\n\r\n### Query params\r\n\r\nWith an url like `http://bob.com/docs?page=30`, you can access the `page` parameter like so:\r\n```bat\r\necho %req.query.params.page%\r\n```\r\n\r\nCmdweb also comes with arrays support: In the case where you have duplicated keys: `http://bob.com/docs?page=30\u0026page=31\u0026page=32`, page will be parsed as an array, and you can access `page` with variables following this format:\r\n```bat\r\necho %req.query.params.page[0]%\r\necho %req.query.params.page[1]%\r\necho %req.query.params.page[2]%\r\n```\r\n\r\n## Message formats\r\n\r\nCmdweb supports message parsing based on specific formats and convert them into Batch variables to be used in a convenient way. You can provide a fourth optional argument to enable message parsing for that message format, for example:\r\n```bat\r\ncall lib/listen \"post\" \"/account\" add_account \"json\"\r\n```\r\n\r\nCurrently the only supported message formats are JSON and url encoded form data.\r\n\r\n### JSON messages\r\n\r\nJSON messages will be parsed and stored into variables in a dictionary-like manner. For example, if we have a message payload like:\r\n```json\r\n{\r\n    \"name\": \"Bob\",\r\n    \"age\": 19,\r\n    \"profile\": {\r\n        \"isForeign\": false,\r\n        \"isRich\": true\r\n    },\r\n    \"jobs\": [ \"Baker\", \"Coder\", \"Investor\" ]\r\n}\r\n```\r\n\r\nYou can access each property like this:\r\n```bat\r\necho %req.body[\"name\"]%\r\necho %req.body[\"age\"]%\r\necho %req.body[\"profile\"][\"isForeign\"]%\r\necho %req.body[\"profile\"][\"isRich\"]%\r\necho %req.body[\"jobs\"][0]%\r\necho %req.body[\"jobs\"][1]%\r\necho %req.body[\"jobs\"][2]%\r\n```\r\n\r\nThe original JSON string is still available in `req.body`. Like mentioned earlier, `req.body` can only store ~8100 characters, but each of these variables can store ~8100 characters as well. Which means although a variable is limited, you can still have your message size be much larger if you design your message schema such that each property does not exceed 8100 characters.\r\n\r\n### Url encoded form data\r\n\r\nUrl encoded form data will also be parsed and stored into variables in a dictionary-like manner. For example, if we have a message payload like:\r\n```\r\nname=Bob+Ross\u0026age=20\u0026city=New+York\r\n```\r\n\r\nHere is how you can access each field:\r\n```bat\r\necho %req.body[\"name\"]%\r\necho %req.body[\"age\"]%\r\necho %req.body[\"city\"]%\r\n```\r\n\r\nAnd of course arrays are supported. For example, if the message is `name=Bob+Ross\u0026name=Steve+Jobs\u0026name=Dennis+Ritchie`, you can access each field like so:\r\n```bat\r\necho %req.body[\"name\"][0]%\r\necho %req.body[\"name\"][1]%\r\necho %req.body[\"name\"][2]%\r\n```\r\n\r\n### Message size limit\r\n\r\nYou can configure the maximum message size that each route will receive, default is 8100 bytes. Example:\r\n```bat\r\n:: This will limit the message size to 1048576 bytes, aka 1 megabyte\r\ncall lib/listen \"post\" \"/update/account/:name\" update_account \"json\" 1048576\r\n```\r\n\r\n### Character escaping\r\n\r\nBecause characters like `\u0026 \u003e \u003c | ^ % \\n` might cause troubles in our Batch scripts, they are stored into variables in an escaped format:\r\n* `\u0026 \u003e \u003c | ^` are escaped with `^^^`.\r\n* `%` is escaped by duplicating itself.\r\n* `\\n` is replaced with `%NL%` - a built in macro of Cmdweb that can act as a new line.\r\n\r\n## SSL\r\n\r\nYou can load your ssl certificate and host a public https server:\r\n```bat\r\ncall lib/start 443 \"0.0.0.0\" \"./path/to/key\" \"./path/to/cert\" \"./path/to/ca\"\r\n```\r\n\r\n## Server configurations\r\n\r\nCurrently there are not many options to configure so you can call `lib/start` and pass arguments directly like above, but there might be in the future. Therefore, you can also configure and start your server this way:\r\n\r\n```bat\r\nset server.port=443\r\nset server.hostname=0.0.0.0\r\nset server.ssl.keypath=./key.txt\r\nset server.ssl.crtpath=./crt.txt\r\nset server.ssl.capath=./ca.txt\r\n\r\ncall lib/start\r\n```\r\n\r\nNote that the variables above have higher priority than the arguments, so for example `call lib/start 80` will still result in port 443 following the configuration above.\r\n\r\n## Utilities\r\n\r\n### New lines\r\n\r\nCmdweb comes with a macro called `NL` which is an equivalent to a new line. For example:\r\n```bat\r\nset req.body=Hello%NL%World\r\n```\r\n\r\nis equivalent to:\r\n```\r\nHello\r\nWorld\r\n```\r\n\r\n## Examples\r\n\r\nYou can move all files in `./examples` to the current directory, then type `app` in your console to start the server.\r\n\r\n## Todos\r\n\r\nNote: The list is not in order.\r\n* Serve/handle data through streams.\r\n* Add message parsing for more message formats.\r\n* A better way to configure for each route.\r\n* A better way to respond/write to headers.\r\n* Comfortable ways to deal with CORS.\r\n* DB integration.\r\n* Caching.\r\n* Check for code injection possibilities.\r\n\r\n## Copyrights and License\r\n\r\nCopyrights © 2024 Nguyen Phu Minh.\r\n\r\nThis project is licensed under the Apache 2.0 License.\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnguyenphuminh%2Fcmdweb","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnguyenphuminh%2Fcmdweb","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnguyenphuminh%2Fcmdweb/lists"}