{"id":36882545,"url":"https://github.com/est/req4cmt","last_synced_at":"2026-01-12T15:26:07.716Z","repository":{"id":66497900,"uuid":"565119969","full_name":"est/req4cmt","owner":"est","description":"simple plugin to save webpage/blog comments to a static JSON over git http","archived":false,"fork":false,"pushed_at":"2025-09-30T14:49:34.000Z","size":56,"stargazers_count":12,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-09-30T16:29:43.710Z","etag":null,"topics":["blog","cloudflare-workers","comment-system","single-file","static-site"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/est.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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-11-12T12:03:17.000Z","updated_at":"2025-09-30T14:49:38.000Z","dependencies_parsed_at":"2025-09-07T11:17:28.846Z","dependency_job_id":"b407ed35-d65a-4062-b150-2b6226fd010c","html_url":"https://github.com/est/req4cmt","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/est/req4cmt","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/est%2Freq4cmt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/est%2Freq4cmt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/est%2Freq4cmt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/est%2Freq4cmt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/est","download_url":"https://codeload.github.com/est/req4cmt/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/est%2Freq4cmt/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28340697,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-12T12:22:26.515Z","status":"ssl_error","status_checked_at":"2026-01-12T12:22:10.856Z","response_time":98,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: 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":["blog","cloudflare-workers","comment-system","single-file","static-site"],"created_at":"2026-01-12T15:26:07.246Z","updated_at":"2026-01-12T15:26:07.710Z","avatar_url":"https://github.com/est.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# req4cmt\n\nA comment plugin for your blog or website, just like disqus without ads.\n\nIt requires **NO** cookie, no signups, no login, no bullshit. Just type your comment in a `textarea` and submit.\n\nTo render the `textarea`, a few kilobyes static uncompressed `req4cmt.js` is loaded.\n\nThen the .js do a `fetch` and render the comment list\n\nRuns on [Cloudflare worker](https://developers.cloudflare.com/workers/) for free. Every data is self-contained in a git repo\n\ninspired by [staticman](https://github.com/eduardoboucas/staticman) and its successor [comment-worker](https://github.com/zanechua/comment-worker/issues/4), transfer HTTP POST content, append to a JSON file, commit to a git. May even allowing additional `blob` for picture attachments in the future.\n\nInstead of using Github proprietary API, `req4cmt` use [isomorphic-git](https://isomorphic-git.org/) to speak the git-http protocol, enabling read/write to *any* git remote.\n\n评论插件。通过cf worker把内容写入到git-http远端，不依赖github api\n\n## Demo\n\nVisit my blog: \u003chttps://blog.est.im/2025/stdout-07\u003e\n\n## Setup\n\n1. fork the repo and deploy to Cloudflare Worker. Assign a domain or use the default like `req4cmt.myaccount.workers.dev`\n2. Create another empty repo for data storage, like `github.com/gh_user/my_comments`\n3. in your Worker settings, create a new environment secret\n4. the secret name is `REPO`, value is the git http url like `https://req4cmt:PAT@github.com/gh_user/my_comments.git`\n5. the `PAT` in the above url is a fine-grained [Personal Access Token](https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) with just one `repo` scope to `gh_user/my_comments` with `content` read/write permission. You can create a token under your github [personal settings - Developer Settings](https://github.com/settings/personal-access-tokens).\n6. if you are using Gitlab or others, similar private tokens can be found\n7. embed a snippet to your HTML page. `\u003cscript defer src=\"https://req4cmt.myaccount.workers.dev/req4cmt.js\"\u003e\u003c/script\u003e`\n8. A new `\u003cdiv\u003e` with a `\u003cform\u003e` and a `\u003cdl\u003e` will appear for your HTML page just below the `\u003cscript\u003e` tag\n\nThe UI is too ugly? Modify the `\u003cdiv id=\"req4cmt_thread\"\u003e` inside `dist/req4cmt.js` yourself.\n\n## Plans\n\n- [ ] git committer\n- [ ] attachments\n- [ ] Github [pull requests](https://github.com/apps/req4cmt) for moderation\n- [ ] add cache and reduce API calls\n- [ ] rich content formatting like `pre` or markdown\n- [ ] `at` someone for notification?\n- [ ] also as a [Github App](https://github.com/apps/req4cmt)\n- [X] limit length\n- [X] 20250912 git-http fetch file for private repos, replace github download.\n\n## failures and non-goals\n\n### 1. partial fetch (2025-09-13)\n\nTo accelerate `git clone`, in theory we only need to fetch the latest commit and the individual .jsonl file.\n\nI failed attemped to implement this. isomorphic-git does not handle single file checkout well. When `.commit()` Other files gets deleted. WTF?\n\nAlso the `git.clone()` at minimal depth=1 would still load every .jsonl from a shallow commit.\n\nScaling might be an issue in the future.\n\n###  2. no `append` to git commits\n\nHow to append new lines to a large .jsonl file, without downloading the previous file content?\n\ngit use `sha1` for hashing (mostly). `sha1` can be \"streamed\" by serializing its internal state, in Python you can pickle a `hashlib.sha1` instance.\n\nSadly, the git blob is hashed as `\"blob \" + \u003cdecimal size\u003e + \"\\0\" + \u003cfile content\u003e`\n\nevery new line is appended, the `\u003cdecimal size\u003e` changes, makes the header different. To make a new git commit, download the entire file, re-hash is a must .\n\nLearned from ChatGPT today (2025-09-30). Saved me lot of time.\n\n### 3. why not use SQLite/D1 or some proper database?\n\nThe same reason why choosing static site over Wordpress, which uses a database\n\nI dislike managing DBs. Think of all those mess with backups, migrations, imports, exports, difference between mysql/pg/sqlite/etc. Tons of operating cost just for the sake of few blog comments\n\n### 4. wasted CPU and memory, git is too heavy for comments\n\nFor a blog comment plugin, most of IOs are read. The worker will load single .jsonl from raw.githubusercontent.com if you are using github.\n\nIn case of writes, req4cmt worker will clone the repo (as minimal as possible), append the new line, and commit it back to the remote.\n\nLet's be realistic, your blog won't have millions of comments. The clone should be fast.\n\nAnd optimistically, There won't be too many visitor writing comments at the same time. So a basic git optimistic lock should be good enough\n\n### 5. comments are risky, moderation is hard!\n\nIt's a git of .jsonl files, one comment for one line per commit, just `git clone`, `sed` them and `git push`\n\nTo erase the history entirely, use `git cherry-pick` and `git push -f`\n\nNot a shell user? I don't think you'd run a static generated site anyway.\n\nFuture work:   \n -  allow req4cmt to commit to a different branch\n - use \"Pull Request\" to review them before merge.\n\n### 6. How to fight spam?\n\nLook at the source. You can insert you clever if-else there.\n\nor `git filter-branch` the commits just in case.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fest%2Freq4cmt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fest%2Freq4cmt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fest%2Freq4cmt/lists"}