{"id":47998927,"url":"https://github.com/j9t/htaccess-punk","last_synced_at":"2026-04-04T12:10:41.418Z","repository":{"id":344893243,"uuid":"1183570148","full_name":"j9t/htaccess-punk","owner":"j9t","description":"Redirect checker for .htaccess files","archived":false,"fork":false,"pushed_at":"2026-03-23T06:15:32.000Z","size":116,"stargazers_count":0,"open_issues_count":2,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-30T03:46:13.620Z","etag":null,"topics":["apache","check","checker","htaccess","http","links","quality","redirects"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","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/j9t.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE.txt","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},"funding":{"github":"j9t"}},"created_at":"2026-03-16T18:34:56.000Z","updated_at":"2026-03-23T06:15:36.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/j9t/htaccess-punk","commit_stats":null,"previous_names":["j9t/htaccess-punk"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/j9t/htaccess-punk","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/j9t%2Fhtaccess-punk","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/j9t%2Fhtaccess-punk/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/j9t%2Fhtaccess-punk/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/j9t%2Fhtaccess-punk/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/j9t","download_url":"https://codeload.github.com/j9t/htaccess-punk/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/j9t%2Fhtaccess-punk/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31398899,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-04T10:20:44.708Z","status":"ssl_error","status_checked_at":"2026-04-04T10:20:06.846Z","response_time":60,"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":["apache","check","checker","htaccess","http","links","quality","redirects"],"created_at":"2026-04-04T12:10:40.914Z","updated_at":"2026-04-04T12:10:41.408Z","avatar_url":"https://github.com/j9t.png","language":"JavaScript","readme":"# .htaccess Punk\n\n[![npm version](https://img.shields.io/npm/v/htaccess-punk.svg)](https://www.npmjs.com/package/htaccess-punk) [![Build status](https://github.com/j9t/htaccess-punk/workflows/Tests/badge.svg)](https://github.com/j9t/htaccess-punk/actions) [![Socket](https://badge.socket.dev/npm/package/htaccess-punk)](https://socket.dev/npm/package/htaccess-punk)\n\n.htaccess Punk checks the redirect targets defined in `.htaccess` files. It follows redirect chains to verify where they ultimately resolve and what HTTP status they return, thus helping to fight redirect rot.\n\n## Usage\n\n### CLI Use\n\n```shell\nnpx htaccess-punk [options] [directory]\n```\n\n`directory` defaults to the current working directory. .htaccess Punk scans it recursively.\n\n| Option | Short | Description |\n|---|---|---|\n| `--errors` | `-e` | Show only error results (HTTP 4xx+ and connection failures); summary still reflects all checked URLs |\n| `--help` | `-h` | Show usage information |\n\n### Programmatic Use\n\n```javascript\nimport { check } from 'htaccess-punk';\n\nconst { files, urls, urlToFiles, results } = await check('/path/to/dir');\n```\n\n`urlToFiles` is a `Map\u003cstring, string[]\u003e` of each target URL to the `.htaccess` files that reference it. `results` is an array of objects:\n\n```javascript\n{\n  url,      // original target URL\n  status,   // final HTTP status code\n  finalUrl, // final URL after following redirects (null if no redirects)\n  chain,    // array of `{ url, status }` for each hop\n  error,    // error message if the request failed (`status` and `finalUrl` absent)\n}\n```\n\n`check()` also accepts an options object:\n\n```javascript\nawait check(dir, {\n  concurrency: 5,               // parallel requests (default: 5)\n  onReady({ files, urls }) {},  // called after files are found and targets extracted\n  onResult(result) {},          // called for each result as it comes in\n});\n```\n\n## How It Works\n\n.htaccess Punk:\n\n1. **finds** all `.htaccess` files in the given directory, recursively (skipping `node_modules` and `.git`)\n2. **parses** `Redirect`, `RedirectPermanent`, `RedirectTemp`, `RedirectMatch`, and `RewriteRule` directives to extract absolute target URLs\n3. **skips** targets that contain regex backreferences (`$1`, `%1`, etc.)—these depend on the matched request path and can’t be checked without it\n4. **deduplicates** targets across all files\n5. **checks** each unique URL with a HEAD request (falling back to GET if the server returns 403 or 405), following redirect chains up to 10 hops, and reports the final HTTP status\n\nThe `check()` function returns raw result data. The CLI (`bin/htaccess-punk.js`) collects those results and prints them grouped by `.htaccess` file, with the final status color-coded: green for 2xx, yellow for 3xx (further redirect from the final hop, e.g. a loop or exceeded redirect limit), red for 4xx/5xx. When a target redirected before settling, the final URL is shown below it.","funding_links":["https://github.com/sponsors/j9t"],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fj9t%2Fhtaccess-punk","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fj9t%2Fhtaccess-punk","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fj9t%2Fhtaccess-punk/lists"}