{"id":13527361,"url":"https://github.com/node-modules/compressing","last_synced_at":"2026-01-28T15:00:52.039Z","repository":{"id":14375477,"uuid":"76440540","full_name":"node-modules/compressing","owner":"node-modules","description":"Everything you need for compressing and uncompressing","archived":false,"fork":false,"pushed_at":"2025-12-20T15:57:45.000Z","size":920,"stargazers_count":455,"open_issues_count":50,"forks_count":35,"subscribers_count":15,"default_branch":"master","last_synced_at":"2026-01-25T02:23:42.393Z","etag":null,"topics":["compressed-files","filestream","gzip","stream","tar","tgz"],"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/node-modules.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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":"2016-12-14T08:37:34.000Z","updated_at":"2026-01-13T17:48:05.000Z","dependencies_parsed_at":"2024-04-23T03:27:00.633Z","dependency_job_id":"9fb3db52-918a-453d-9aee-e8b2b1863e13","html_url":"https://github.com/node-modules/compressing","commit_stats":{"total_commits":51,"total_committers":14,"mean_commits":3.642857142857143,"dds":0.6862745098039216,"last_synced_commit":"674915cb61467bed01c9fb29c81af5a9aa6920e2"},"previous_names":[],"tags_count":27,"template":false,"template_full_name":null,"purl":"pkg:github/node-modules/compressing","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/node-modules%2Fcompressing","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/node-modules%2Fcompressing/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/node-modules%2Fcompressing/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/node-modules%2Fcompressing/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/node-modules","download_url":"https://codeload.github.com/node-modules/compressing/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/node-modules%2Fcompressing/sbom","scorecard":{"id":692002,"data":{"date":"2025-08-11","repo":{"name":"github.com/node-modules/compressing","commit":"b2d231b3096450962bd5673a436011c2d9828d56"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4.8,"checks":[{"name":"Maintained","score":7,"reason":"8 commit(s) and 1 issue activity found in the last 90 days -- score normalized to 7","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":3,"reason":"Found 11/30 approved changesets -- score normalized to 3","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/nodejs.yml:1","Warn: no topLevel permission defined: .github/workflows/release.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Pinned-Dependencies","score":0,"reason":"dependency not pinned by hash detected -- score normalized to 0","details":["Warn: third-party GitHubAction not pinned by hash: .github/workflows/nodejs.yml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/node-modules/compressing/nodejs.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/release.yml:10: update your workflow using https://app.stepsecurity.io/secureworkflow/node-modules/compressing/release.yml/master?enable=pin","Info:   0 out of   2 third-party GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 1 commits out of 19 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-22T02:30:49.448Z","repository_id":14375477,"created_at":"2025-08-22T02:30:49.448Z","updated_at":"2025-08-22T02:30:49.448Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28846081,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-28T13:02:32.985Z","status":"ssl_error","status_checked_at":"2026-01-28T13:02:04.945Z","response_time":57,"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":["compressed-files","filestream","gzip","stream","tar","tgz"],"created_at":"2024-08-01T06:01:46.406Z","updated_at":"2026-01-28T15:00:52.027Z","avatar_url":"https://github.com/node-modules.png","language":"JavaScript","readme":"# compressing\n\n[![NPM version][npm-image]][npm-url]\n[![Test coverage][codecov-image]][codecov-url]\n[![npm download][download-image]][download-url]\n[![Node.js Version](https://img.shields.io/node/v/compressing.svg?style=flat)](https://nodejs.org/en/download/)\n[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://makeapullrequest.com)\n![CodeRabbit Pull Request Reviews](https://img.shields.io/coderabbit/prs/github/node-modules/compressing)\n\n[npm-image]: https://img.shields.io/npm/v/compressing.svg?style=flat-square\n[npm-url]: https://npmjs.org/package/compressing\n[codecov-image]: https://codecov.io/gh/node-modules/compressing/branch/master/graph/badge.svg\n[codecov-url]: https://codecov.io/gh/node-modules/compressing\n[download-image]: https://img.shields.io/npm/dm/compressing.svg?style=flat-square\n[download-url]: https://npmjs.org/package/compressing\n\nThe missing compressing and uncompressing lib for node.\n\nCurrently supported:\n\n- tar\n- gzip\n- tgz\n- zip\n\n## Install\n\n```bash\nnpm install compressing\n```\n\n## Usage\n\n### Compress a single file\n\nUse gzip as an example, tar, tgz and zip is same as gzip.\n\n__promise style__\n\n```js\nconst compressing = require('compressing');\n\n// compress a file\ncompressing.gzip.compressFile('file/path/to/compress', 'path/to/destination.gz')\n.then(compressDone)\n.catch(handleError);\n\n// compress a file buffer\ncompressing.gzip.compressFile(buffer, 'path/to/destination.gz')\n.then(compressDone)\n.catch(handleError);\n\n// compress a stream\ncompressing.gzip.compressFile(stream, 'path/to/destination.gz')\n.then(compressDone)\n.catch(handleError);\n```\n\n__stream style__\n\n```js\nconst compressing = require('compressing');\n\nnew compressing.gzip.FileStream({ source: 'file/path/to/compress' })\n  .on('error', handleError)\n  .pipe(fs.createWriteStream('path/to/destination.gz'))\n  .on('error', handleError);\n\n// It's a transform stream, so you can pipe to it\nfs.createReadStream('file/path/to/compress')\n  .on('error', handleError)\n  .pipe(new compressing.gzip.FileStream())\n  .on('error', handleError)\n  .pipe(fs.createWriteStream('path/to/destination.gz'))\n  .on('error', handleError);\n\n// You should take care of stream errors in caution, use pump to handle error in one place\nconst { pipeline: pump } = require('stream');\nconst sourceStream = fs.createReadStream('file/path/to/compress');\nconst gzipStream = new compressing.gzip.FileStream();\nconst destStream = fs.createWriteStream('path/to/destination.gz');\npump(sourceStream, gzipStream, destStream, handleError);\n```\n\n### Compress a dir\n\nUse tar as an example, tgz and zip is same as gzip.\n\n__Gzip only support compressing a single file. if you want to compress a dir with gzip, then you may need tgz instead.__\n\n__promise style__\n\n```js\nconst compressing = require('compressing');\ncompressing.tar.compressDir('dir/path/to/compress', 'path/to/destination.tar')\n.then(compressDone)\n.catch(handleError);\n```\n\n__stream style__\n\n```js\nconst compressing = require('compressing');\n\nconst tarStream = new compressing.tar.Stream();\ntarStream.addEntry('dir/path/to/compress');\n\ntarStream\n  .on('error', handleError)\n  .pipe(fs.createWriteStream('path/to/destination.tar'))\n  .on('error', handleError);\n\n// You should take care of stream errors in caution, use pump to handle error in one place\nconst tarStream = new compressing.tar.Stream();\ntarStream.addEntry('dir/path/to/compress');\nconst destStream = fs.createWriteStream('path/to/destination.tar');\npump(tarStream, destStream, handleError);\n```\n\nStream is very powerful, you can compress multiple entries in it;\n\n```js\nconst tarStream = new compressing.tar.Stream();\n// dir\ntarStream.addEntry('dir/path/to/compress');\n\n// file\ntarStream.addEntry('file/path/to/compress');\n\n// buffer\ntarStream.addEntry(buffer);\n\n// stream\ntarStream.addEntry(stream);\n\nconst destStream = fs.createWriteStream('path/to/destination.tar');\npipe(tarStream, destStream, handleError);\n```\n\n### Uncompress a file\n\n__promise style__\n\n```js\nconst compressing = require('compressing');\n\n// uncompress a file\ncompressing.tgz.uncompress('file/path/to/uncompress.tgz', 'path/to/destination/dir')\n.then(uncompressDone)\n.catch(handleError);\n\n// uncompress a file buffer\ncompressing.tgz.uncompress(buffer, 'path/to/destination/dir')\n.then(uncompressDone)\n.catch(handleError);\n\n// uncompress a stream\ncompressing.tgz.uncompress(stream, 'path/to/destination/dir')\n.then(uncompressDone)\n.catch(handleError);\n```\n\n__Note: tar, tgz and zip have the same uncompressing API as above: destination should be a path of a directory, while that of gzip is slightly different: destination must be a file or filestream.__\n\nAnd working with urllib is super easy. Let's download a tgz file and uncompress to a directory:\n\n```js\nconst urllib = require('urllib');\nconst targetDir = require('os').tmpdir();\nconst compressing = require('compressing');\n\nurllib.request('http://registry.npmjs.org/compressing/-/compressing-2.0.0.tgz', {\n  streaming: true,\n  followRedirect: true,\n})\n.then(result =\u003e compressing.tgz.uncompress(result.res, targetDir))\n.then(() =\u003e console.log('uncompress done'))\n.catch(console.error);\n```\n\n__stream style__\n\n```js\nconst compressing = require('compressing');\nconst mkdirp = require('mkdirp');\n\nfunction onEntry(header, stream, next) =\u003e {\n  stream.on('end', next);\n\n  // header.type =\u003e file | directory\n  // header.name =\u003e path name\n\n  if (header.type === 'file') {\n    stream.pipe(fs.createWriteStream(path.join(destDir, header.name)));\n  } else { // directory\n    fs.mkdir(path.join(destDir, header.name), { recursive: true }, err =\u003e {\n      if (err) return handleError(err);\n      stream.resume();\n    });\n  }\n}\n\nnew compressing.tgz.UncompressStream({ source: 'file/path/to/uncompress.tgz' })\n  .on('error', handleError)\n  .on('finish', handleFinish) // uncompressing is done\n  .on('entry', onEntry);\n\n// It's a writable stream, so you can pipe to it\nfs.createReadStream('file/path/to/uncompress')\n  .on('error', handleError)\n  .pipe(new compressing.tgz.UncompressStream())\n  .on('error', handleError)\n  .on('finish', handleFinish) // uncompressing is done\n  .on('entry', onEntry);\n```\n\n**Note: tar, tgz and zip have the same uncompressing streaming API as above: it's a writable stream, and entries will be emitted while uncompressing one after one another, while that of gzip is slightly different: gzip.UncompressStream is a transform stream, so no `entry` event will be emitted and you can just pipe to another stream**\n\nThis constrants is brought by Gzip algorithm itself, it only support compressing one file and uncompress one file.\n\n```js\nnew compressing.gzip.UncompressStream({ source: 'file/path/to/uncompress.gz' })\n  .on('error', handleError)\n  .pipe(fs.createWriteStream('path/to/dest/file'))\n  .on('error', handleError);\n```\n\n## API\n\n### compressFile\n\nUse this API to compress a single file. This is a convenient method, which wraps FileStream API below, but you can handle error in one place.\n\n- gzip.compressFile(source, dest, opts)\n- tar.compressFile(source, dest, opts)\n- tgz.compressFile(source, dest, opts)\n- zip.compressFile(source, dest, opts)\n\nParams\n\n- source {String|Buffer|Stream} - source to be compressed, could be a file path, buffer, or a readable stream\n- dest {String|Stream} - compressing destination, could be a file path(eg. `/path/to/xx.tgz`), or a writable stream.\n- opts {Object} - usually you don't need it\n\nReturns a promise object.\n\n### compressDir\n\nUse this API to compress a dir. This is a convenient method, which wraps Stream API below, but you can handle error in one place.\n\n__Note: gzip do not have a compressDir method, you may need tgz instead.__\n\n- tar.compressDir(source, dest, opts)\n- tgz.compressDir(source, dest, opts)\n- zip.compressDir(source, dest, opts)\n\nParams\n\n- source {String|Buffer|Stream} - source to be compressed\n- dest {String|Stream} - compressing destination, could be a file path(eg. `/path/to/xx.tgz`), or a writable stream.\n- opts {Object} - usually you don't need it\n\n### uncompress\n\nUse this API to uncompress a file. This is a convenient method, which wraps UncompressStream API below, but you can handle error in one place. RECOMMANDED.\n\n- tar.uncompress(source, dest, opts)\n- tgz.uncompress(source, dest, opts)\n- zip.uncompress(source, dest, opts)\n- gzip.uncompress(source, dest, opts)\n\nParams\n\n- source {String|Buffer|Stream} - source to be uncompressed\n- dest {String|Stream} - uncompressing destination. When uncompressing tar, tgz and zip, it should be a directory path (eg. `/path/to/xx`). __When uncompressing gzip, it should be a file path or a writable stream.__\n- opts {Object} - usually you don't need it\n  - opts.zipFileNameEncoding {String} - Only work on zip format, default is 'utf8'.\n    Major non-UTF8 encodings by languages:\n\n    - Korean: cp949, euc-kr\n    - Japanese: sjis (shift_jis), cp932, euc-jp\n    - Chinese: gbk, gb18030, gb2312, cp936, hkscs, big5, cp950\n  - opts.strip {Number} - Strip leading path segments when extracting (tar/tgz/zip). Default is 0.\n\n### FileStream\n\nThe transform stream to compress a single file.\n\n__Note: If you are not very familiar with streams, just use compressFile() API, error can be handled in one place.__\n\n- new gzip.FileStream(opts)\n- new tar.FileStream(opts)\n- new tgz.FileStream(opts)\n- new zip.FileStream(opts)\n\nCommon params:\n\n- opts.source {String|Buffer|Stream} - source to be compressed, could be a file path, buffer, or a readable stream.\n\nGzip params:\n\n- opts.zlib - {Object} gzip.FileStream uses zlib to compress, pass this param to control the behavior of zlib.\n\nTar params:\n\n- opts.relativePath {String} - Adds a file from source into the compressed result file as opts.relativePath. Uncompression programs would extract the file from the compressed file as relativePath. If opts.source is a file path, opts.relativePath is optional, otherwise it's required.\n- opts.size {Number} - Tar compression requires the size of file in advance. When opts.source is a stream, the size of it cannot be calculated unless load all content of the stream into memory(the default behavior, but loading all data into memory could be a very bad idea). Pass opts.size to avoid loading all data into memory, or a warning will be shown.\n- opts.suppressSizeWarning {Boolean} - Pass true to suppress the size warning mentioned.\n\nTgz params:\n\ntgz.FileStream is a combination of tar.FileStream and gzip.FileStream, so the params are the combination of params of tar and gzip.\n\nZip params:\n\n- opts.relativePath {String} - Adds a file from source into the compressed result file as opts.relativePath. Uncompression programs would extract the file from the compressed file as relativePath. If opts.source is a file path, opts.relativePath is optional, otherwise it's required.\n- opts.yazl {Object} - zip.FileStream compression uses [yazl](https://github.com/thejoshwolfe/yazl), pass this param to control the behavior of yazl.\n\n### Stream\n\nThe readable stream to compress anything as you need.\n\n__Note: If you are not very familiar with streams, just use compressFile() and compressDir() API, error can be handled in one place.__\n\n__Gzip only support compressing a single file. So gzip.Stream is not available.__\n\n__Constructor__\n\n- new tar.Stream()\n- new tgz.Stream()\n- new zip.Stream()\n\nNo options in all constructors.\n\n__Instance methods__\n\n- addEntry(entry, opts)\n\nParams\n\n- entry {String|Buffer|Stream} - entry to compress, cound be a file path, a dir path, a buffer, or a stream.\n- opts.relativePath {String} - uncompression programs would extract the file from the compressed file as opts.relativePath. If entry is a file path or a dir path, opts.relativePath is optional, otherwise it's required.\n- opts.ignoreBase {Boolean} - when entry is a dir path, and opts.ignoreBase is set to true, the compression will contain files relative to the path passed, and not with the path included.\n\n### UncompressStream\n\nThe writable stream to uncompress anything as you need.\n\n__Note: If you are not very familiar with streams, just use `uncompress()` API, error can be handled in one place.__\n\n__Gzip only support compressing and uncompressing one single file. So gzip.UncompressStream is a transform stream which is different from others.__\n\n__Constructor__\n\n- new gzip.UncompressStream(opts)\n- new tar.UncompressStream(opts)\n- new tgz.UncompressStream(opts)\n- new zip.UncompressStream(opts)\n\nCommon params:\n\n- opts.source {String|Buffer|Stream} - source to be uncompressed, could be a file path, buffer, or a readable stream.\n- opts.strip {Number} - Strip leading path segments when extracting (tar/tgz/zip). Default is 0.\n\n__CAUTION for zip.UncompressStream__\n\nDue to the design of the .zip file format, it's impossible to interpret a .zip file without loading all data into memory.\n\nAlthough the API is streaming style(try to keep it handy), it still loads all data into memory.\n\n\u003chttps://github.com/thejoshwolfe/yauzl#no-streaming-unzip-api\u003e\n\n## Contributors\n\n[![Contributors](https://contrib.rocks/image?repo=node-modules/compressing)](https://github.com/node-modules/compressing/graphs/contributors)\n\nMade with [contributors-img](https://contrib.rocks).\n","funding_links":[],"categories":["Repository","压缩解压缩","JavaScript","Uncategorized"],"sub_categories":["File Compression / Decompression","redux 扩展","macros","Uncategorized"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnode-modules%2Fcompressing","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnode-modules%2Fcompressing","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnode-modules%2Fcompressing/lists"}