{"id":13453844,"url":"https://github.com/sinedied/smoke","last_synced_at":"2025-10-04T19:46:27.024Z","repository":{"id":38022974,"uuid":"158532343","full_name":"sinedied/smoke","owner":"sinedied","description":":dash: Simple yet powerful file-based mock server with recording abilities","archived":false,"fork":false,"pushed_at":"2025-09-10T13:10:21.000Z","size":2553,"stargazers_count":194,"open_issues_count":2,"forks_count":16,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-09-21T04:35:30.434Z","etag":null,"topics":["api","file-based","hacktoberfest","json","mock","nodejs","rest","server","simple","template"],"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/sinedied.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}},"created_at":"2018-11-21T10:40:53.000Z","updated_at":"2025-09-13T18:36:20.000Z","dependencies_parsed_at":"2024-12-14T00:06:28.937Z","dependency_job_id":"a64c7163-8d5d-430b-9c14-e067dde3d27c","html_url":"https://github.com/sinedied/smoke","commit_stats":{"total_commits":158,"total_committers":6,"mean_commits":"26.333333333333332","dds":"0.10759493670886078","last_synced_commit":"e31757fc26c1ff0843e53d4e0bafc01bb778f2ca"},"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"purl":"pkg:github/sinedied/smoke","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sinedied%2Fsmoke","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sinedied%2Fsmoke/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sinedied%2Fsmoke/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sinedied%2Fsmoke/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sinedied","download_url":"https://codeload.github.com/sinedied/smoke/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sinedied%2Fsmoke/sbom","scorecard":{"id":826978,"data":{"date":"2025-08-11","repo":{"name":"github.com/sinedied/smoke","commit":"23c1108b2da91de960d62419a7400395062a9dd0"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4.5,"checks":[{"name":"Maintained","score":10,"reason":"20 commit(s) and 2 issue activity found in the last 90 days -- score normalized to 10","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":0,"reason":"Found 2/25 approved changesets -- score normalized to 0","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":"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":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/ci.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":"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":"Pinned-Dependencies","score":3,"reason":"dependency not pinned by hash detected -- score normalized to 3","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:21: update your workflow using https://app.stepsecurity.io/secureworkflow/sinedied/smoke/ci.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/ci.yml:22: update your workflow using https://app.stepsecurity.io/secureworkflow/sinedied/smoke/ci.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release.yml:12: update your workflow using https://app.stepsecurity.io/secureworkflow/sinedied/smoke/release.yml/main?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release.yml:15: update your workflow using https://app.stepsecurity.io/secureworkflow/sinedied/smoke/release.yml/main?enable=pin","Info:   0 out of   4 GitHub-owned GitHubAction dependencies pinned","Info:   2 out of   2 npmCommand 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":"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":"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":"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":"Packaging","score":10,"reason":"packaging workflow detected","details":["Info: Project packages its releases by way of GitHub Actions.: .github/workflows/release.yml:8"],"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":"Signed-Releases","score":0,"reason":"Project has not signed or included provenance with any releases.","details":["Warn: release artifact 4.1.1 not signed: https://api.github.com/repos/sinedied/smoke/releases/227714021","Warn: release artifact 4.1.0 not signed: https://api.github.com/repos/sinedied/smoke/releases/227697029","Warn: release artifact 4.0.0 not signed: https://api.github.com/repos/sinedied/smoke/releases/192902458","Warn: release artifact 3.1.1 not signed: https://api.github.com/repos/sinedied/smoke/releases/36218156","Warn: release artifact 4.1.1 does not have provenance: https://api.github.com/repos/sinedied/smoke/releases/227714021","Warn: release artifact 4.1.0 does not have provenance: https://api.github.com/repos/sinedied/smoke/releases/227697029","Warn: release artifact 4.0.0 does not have provenance: https://api.github.com/repos/sinedied/smoke/releases/192902458","Warn: release artifact 3.1.1 does not have provenance: https://api.github.com/repos/sinedied/smoke/releases/36218156"],"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":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 8 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"}},{"name":"Vulnerabilities","score":6,"reason":"4 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-fjxv-7rqg-78g4","Warn: Project is vulnerable to: GHSA-fjgf-rc76-4x9p","Warn: Project is vulnerable to: GHSA-76c9-3jph-rj3q"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-23T16:48:14.907Z","repository_id":38022974,"created_at":"2025-08-23T16:48:14.907Z","updated_at":"2025-08-23T16:48:14.907Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":278366608,"owners_count":25975090,"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","status":"online","status_checked_at":"2025-10-04T02:00:05.491Z","response_time":63,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["api","file-based","hacktoberfest","json","mock","nodejs","rest","server","simple","template"],"created_at":"2024-07-31T08:00:48.434Z","updated_at":"2025-10-04T19:46:27.018Z","avatar_url":"https://github.com/sinedied.png","language":"JavaScript","funding_links":[],"categories":["Packages","Repository","包"],"sub_categories":["HTTP"],"readme":"# :dash: smoke\n\n[![NPM version](https://img.shields.io/npm/v/smoke.svg)](https://www.npmjs.com/package/smoke)\n[![Build Status](https://github.com/sinedied/smoke/workflows/build/badge.svg)](https://github.com/sinedied/smoke/actions)\n![Node version](https://img.shields.io/node/v/smoke.svg)\n[![XO code style](https://img.shields.io/badge/code_style-XO-5ed9c7.svg)](https://github.com/sindresorhus/xo)\n[![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)\n\n\u003e Simple yet powerful file-based mock server with recording abilities\n\n![demo](https://user-images.githubusercontent.com/593151/49312821-9f2cc680-f4e5-11e8-900a-117120c38422.gif)\n\nJust drop a bunch of (JSON) files in a folder and you're ready to go!\n\n### Basic mock example\n1. Start the server: `smoke`\n2. Create a file named `get_api#hello.json`:\n    ```json\n    {\n      \"message\": \"hello world!\"\n    }\n    ```\n3. Test the mock: `curl http://localhost:3000/api/hello`\n\n### Features\n\n**Smoke** is a file-based, convention over configuration mock server that can fill your API mocking needs without any\ncomplex setup. Yet, it supports many advanced features and dynamic mocks for almost any situation:\n\n- Generate mocks quickly by recording responses from an existing server\n- Use folders and file names to describe API routes and REST methods\n- Use templates to generate responses based on input queries and route parameters\n- Add / edit / remove mocks without restarting the server\n- Generate mocks with JavaScript for more complex responses\n- Define different mock sets to simulate various scenarii (errors...), with fallback\n- Customize headers and status code if needed, automatically detect content-type if not specified\n- Add custom middlewares to modify requests/responses\n- Mock only specific requests and proxy the rest to an existing server\n- Supports CORS (cross-origin resource-sharing)\n\n## Installation\n\n```bash\nnpm install -g smoke\n```\n\n## Usage\n\nSee [some example mocks](test/mocks) to quickly get a grasp of the syntax and possibilities.\n\nCLI usage is quite straightforward you can just run `smoke` unless you want to add some options:\n```\nUsage: smoke [\u003cmocks_folder\u003e] [options]\n\nBase options:\n  -p, --port \u003cnum\u003e                  Server port           [default: 3000]\n  -h, --host \u003chost\u003e                 Server host           [default: \"localhost\"]\n  -s, --set \u003cname\u003e                  Mocks set to use      [default: none]\n  -n, --not-found \u003cglob\u003e            Mocks for 404 errors  [default: \"404.*\"]\n  -i, --ignore \u003cglob\u003e               Files to ignore       [default: none]\n  -k, --hooks \u003cfile\u003e                Middleware hooks      [default: none]\n  -x, --proxy \u003chost\u003e                Fallback proxy if no mock found\n  -o, --allow-cors [all|\u003chosts\u003e]    Enable CORS requests  [default: none]\n  --https                           Enable secure request serving with HTTPS [default: false]\n  -l, --logs                        Enable server logs\n  -v, --version                     Show version\n  --help                            Show help\n\nMock recording:\n  -r, --record \u003chost\u003e               Proxy \u0026 record requests if no mock found\n  -c, --collection \u003cfile\u003e           Save to single file mock collection\n  -d, --depth \u003cN\u003e                   Folder depth for mocks  [default: 1]\n  -a, --save-headers                Save response headers\n  -q, --save-query                  Save query parameters\n```\n\n### File naming\n\n**General format:** `methods_api#route#@routeParam$queryParam=value.__set.extension`\n\nThe path and file name of the mock is used to determinate:\n\n#### Supported HTTP methods\nOptionally prefix your file by the HTTP method supported followed by an underscore (for example `get_`).\nYou can specify multiple methods at once using a `+` to separate them (for example `post+put_`);\nIf no method is specified, the mock will be used for any HTTP method.\n\n#### Server route and named route parameters\nUse any combination of folders or hash-separated components to specify the server route.\n\nFor example `api/example/get_hello.json` is equivalent to `get_api#example#hello.json` and will respond to\n`GET api/example/hello` requests.\n\nAdditionaly, any route component can be defined as a route parameter by prefixing the name with `@`, for example\n`api#resource#@id.json` will match `GET api/resource/1` and expose `1` as the value for the `id` parameter that can be\nused in dynamic mocks (templates or JavaScript).\n\n#### Query parameters\nYou can further discriminate mocks by adding query parameters to match after defining the route, using a `$` (instead\nof the regular `?`) like you would specify them in a request.\n\nFor example `get_api#hello$who=john.json` will match the request `api/get_hello?who=john.json`.\n\nMultiple query parameters to match can be added with `\u0026`, for example `get_api#hello$who=john\u0026greet=hi.json`.\nAny specified query parameter in the file name must be matched (in any order) by the request, but the opposite is not\nneeded.\n\nNote that special characters must be URL-encoded, for example use `get_api#hello$who=john%20doe.json` to set the\nparameter `who` with the value `john doe`.\n\n\u003e Tip: If you need to URL-encode a string, just run `node -p \"encodeURIComponent('some string')\"` in a terminal.\n\n#### Content type\nThe file extension will determine the content type of the response if it's not already specified in a\n[custom header](#custom-status-and-headers).\n\nFiles with no extension will use the default MIME type `application/octet-stream`.\n\nYou can have multiple mocks with the same API route and different file extensions, the server will then use the best\nmock depending of the [`Accept` header](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Accept) of the\nrequest.\n\n#### Mock set\nYou can optionally specify a mock set before the file extension by using a `__set-name` suffix after the file name.\n\nFor example `get_api#hello__error.json` will only be used if you start the server with the `error` set enabled:\n`smoke --set error`.\n\nIf you do not specify a mock set on your file name, it will be considered as the default mock for the specified route\nand will be used as a fallback if no mock with this set matched.\n\n#### Templates\nIf you add an underscore `_` after the file extension, the mock will be processed as a template before being sent to\nthe client. Templates works only on text-based formats.\n\nFor example `get_hello.html_` or `get_hello.json_` will be treated as templates. \n\nEvery template can use an implicit context object that have these properties defined:\n- `method`: the HTTP method of the request (ex: `'GET'`, `'POST'`)\n- `query`: map with query parameters that were part of the request URL. For example, matched URL\n  `http://server/hello?who=world` will result in the query value: `{ who: 'world' }`.\n- `params`: map containing matched route parameters. For example the mock `resource#@id.json_` with the matched URL\n  `http://server/resource/123` will result in the params value: `{ id: '123' }`.\n- `headers`: map containing request headers\n- `body`: the request body. JSON bodies are automatically parsed.\n- `files`: if the request includes `multipart/form-data`, this will be the array of uploaded files (see\n  [multer documentation](https://github.com/expressjs/multer) for more details)\n\n##### Template syntax\n\n- `{{ }}` interpolates data in place\n\n  For example, create **get_hello.txt_** with this:\n  ```\n  Hello {{query.name}}!\n  ```\n\n  Then `curl \"http://localhost:3000/hello?name=John\"` returns `Hello John!`\n\n- `{{{ }}}` escapes HTML special chars from interpolated string\n\n  For example, create **get_hello.html_** with this:\n  ```html\n  \u003ch1\u003eHello {{{query.name}}}!\u003c/h1\u003e\n  ```\n\n  Then `curl \"http://localhost:3000/hello?name=%3CJack%26Jones%3E\"` returns:\n  ```html\n  \u003ch1\u003eHello \u0026lt;Jack\u0026amp;Jones\u0026gt;!\u003c/h1\u003e\n  ```\n\n- `\u003c{ }\u003e` evaluates JavaScript to generate data\n\n  For example, create **get_hello.html_** with this:\n  ```html\n  Hello to:\n  \u003cul\u003e\n    \u003c{ query.name.forEach(name =\u003e { }\u003e\u003cli\u003e{{name}}\u003c/li\u003e\u003c{ }); }\u003e\n  \u003c/ul\u003e\n  ```\n\n  Then `curl \"http://localhost:3000/hello?name=Jack\u0026name=Jones\"` returns:\n  ```html\n  Hello to:\n  \u003cul\u003e\n    \u003cli\u003eJack\u003c/li\u003e\u003cli\u003eJones\u003c/li\u003e\n  \u003c/ul\u003e\n  ```\n\n### Custom status and headers\n\nBy default all mocks responses are sent with a status code `200` (OK), or `204` (No content) if a mock file is empty.\n\nYou can customize the response status and (optionally) headers with JSON and [JavaScript](#javascript-mocks) files,\nusing this syntax:\n```js\n{\n  \"statusCode\": 400,\n  \"body\": {\n    \"error\": \"Bad request\"\n  },\n  // headers can be omitted, only use if you want to customize them\n  \"headers\": {\n    \"Content-Type\": \"text/plain\"\n  } \n}\n```\n\nYou can also use non-string content type if you encode the content as a base64 string in the `body` property and add\nthe property `\"buffer\": true` to the mock:\n```js\n{\n  \"statusCode\": 200,\n  \"body\": \"U21va2Ugcm9ja3Mh\",\n  \"buffer\": true,\n  \"headers\": {\n    \"Content-Type\": \"application/octet-stream\"\n  } \n}\n```\n\n### Mock formats\n\nAny file format is supported for mocks, and the file extension will be used to determine the response content type.\nFiles with no extension will use the default MIME type `application/octet-stream`.\n\nText formats (for example `.json`, `.html`, `.txt`...) can be processed as [templates](#templates) by adding an\nunderscore to the file extension.\n\nNote that JSON files and templates must use `UTF-8` encoding.\n\n#### JavaScript mocks\n\nIn addition, you can define dynamic mocks using JavaScript by using the `.js` extension, that will be loaded as a regular\nNode.js module.\n\nIn that case, your JS module is expected to export a function that take an input data object with the\n[same properties](#templates) as for templates and must returns the response body or an\n[object](#custom-status-and-headers) containing the status code, headers and body.\n\nExample:\n```js\nexport default (data) =\u003e `{ \"data\": \"Your user agent is: ${data.headers['user-agent']}\" }`;\n```\n\nNote that by default, JS mocks use `application/json` for the response content type. If you want to use another type,\nyou must set the `Content-Type` header yourself, for example:\n```js\nexport default data =\u003e ({\n  statusCode: 200,\n  headers: {\n    'Content-Type': 'text/plain'\n  },\n  body: `Your user agent is: ${data.headers['user-agent']}`\n});\n```\n\n### Fallback proxy\n\nIf you want to override responses of an existing server, you can use the `--proxy \u003chost\u003e` option. This will proxy\nevery request for which a mock does not exist to the specified host.\n\nThis can also be useful for mocking yet-to-be-implemented APIs and keep using real implemented APIs.\n\n### Mock recording\n\nTo quickly create a mock set of an existing server (to allow working offline for example), you can use the\n`--record \u003chost\u003e` option. This will proxy every request for which a mock does not exist to the specified host, and\nrecord the resulting response as a mock file.\n\nYou can change the maximum folder depth for mock files created this way using the `--depth` option.\n\nThe recorded mock set can also be changed using the `--set` option.\n\nInstead of recoring separate mock files, you can also record to a\n[single file mock collection](#single-file-mock-collection) using the `--collection \u003cfile\u003e` option. \n\nNote that by default response headers and request query parameters are not saved. To change this behavior, you can\nuse the `--save-headers` and `--save-query` options.\n\n### Middleware hooks\n\nFor more advanced usages, you can hook on any standard\n[Express middleware](https://expressjs.com/en/guide/writing-middleware.html) to modify the request and/or the response\nreturned by the server.\n\nTo hook on your own middlewares, use the `--hooks` to specify a JavaScript module with exports setup like this:\n```js\nexport const before = []; // middlewares to be executed before the request is processed\nexport const after = [];  // middlewares to be executed after the request has been processed\n```\n\nMiddlewares executed before the request is processed can be used to bypass regular mock response, for example to\nrandomly simulate a server failure with an early error 500 response.\n\nOn the other hand, middlewares executed after the request have been processed can be used to augment or modify the\nresponse, for example by adding header or changing the response status. You can also access and modify the response\nbody by using the special `res.body` property.\n\nRemember that once you have used `.send()`, `.sendStatus` or `.json()` in a middleware the response cannot be altered\nanymore, that's why you should use the `res.body` property instead if you plan to alter the response later on.\n\nSee some [example hooks](test/hooks.js).\n\n## Enabling CORS\n\nSmoke offers support to requests originating from a different origin. However, by default, this would be disabled.\n\nTo enable CORS, pass the hosts that you want to allow to `-o` or `--allow-cors` arguments.\n\n**Accepted Values**\n- `all` - Allow requests from `*`\n- `\u003chosts\u003e` - You could also pass a comma-separated list of hosts that you want to allow requests from something like `'http://localhost:3000,http://example.com'`\n\n### Single file mock collection\n\nYou can regroup multiple mocks in a special single file with the extension `.mocks.js`, using this format:\n```js\nexport default {\n  '\u003cfile_name\u003e': '\u003cfile_content\u003e' // can be a string, an object (custom response) or a function (JavaScript mock)\n};\n```\nSee this [example mock collection](test/mocks/collection.mocks.js) to get an idea of all possibilities.\n\nThe format of file name is the same as for individual mock files, and will be used to match the request using the same\nrules. As for the mock content, the format is also the same as what you would put in single file mock. If a request\nmatches both a mock file and a mock within a collection with the same specificity, the mock file will always be used\nover the collection.\n\nAs the format is the same, you can convert a bunch of files to a single file mock collection and conversely.\nTo convert separate mock files to a collection:\n```sh\nsmoke-conv \u003cglob\u003e \u003coutput_file\u003e  // Will create \u003coutput_file\u003e.mocks.js from all mocks found\n```\n\nTo convert a mock collection to separate files:\n```sh\nsmoke-conv \u003cfile\u003e \u003coutput_folder\u003e  // Will extract separate mocks into \u003coutput_folder\u003e\n```\n\nNote that only text-based file content will be inserted directly, other file content will be converted to a base64\nstring.\n\n:warning: There is a limitation regarding JavaScript mocks: only the exported function will be converted for a given\nmock, meaning that if you have non-exported functions, variables or imports they will be lost during the conversion.\n\n## Migration from v1/v2/v3 to v4\n\nIf you are migrating from a previous version of Smoke, you need to be aware that the default module format has changed: earlier version used CommonJS modules, while v4 uses ES modules by default.\n\nBut don't worry! You don't have to regenerate or updates all your mock files, Smoke will still support the CommonJS format for backward compatibility, though you need to rename all your `*.js` mocks, collections and hooks files to use the `.cjs` extension instead of `.js`.\n\nIf you prefer to migrate your existing mock files to the new ES module format, you can do so by updating the export syntax to use `export default` instead of `module.exports` in mock files and collections, and `export` the `before` and `after` hooks constant separately in hooks fles.\n\n\u003e [!NOTE]\n\u003e If you try to record new mocks into an existing collection in CommonJS format, the result will be saved into a new collection in ES modules format.\n\n## Other mock servers\n\nIf you cannot find what you need here, you might want to check out one of these other Node.js mock servers:\n\n- [JSON Server](https://github.com/typicode/json-server)\n- [mockserver](https://github.com/namshi/mockserver)\n- [node-mock-server](https://github.com/smollweide/node-mock-server)\n- [node-easymock](https://github.com/CyberAgent/node-easymock)\n- [mockserver-node](https://github.com/jamesdbloom/mockserver-node)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsinedied%2Fsmoke","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsinedied%2Fsmoke","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsinedied%2Fsmoke/lists"}