{"id":16427590,"url":"https://github.com/cferdinandi/bouncer","last_synced_at":"2025-04-04T13:09:26.669Z","repository":{"id":33374350,"uuid":"156880558","full_name":"cferdinandi/bouncer","owner":"cferdinandi","description":"A lightweight form validation script that augments native HTML5 form validation elements and attributes.","archived":false,"fork":false,"pushed_at":"2023-03-03T19:50:04.000Z","size":553,"stargazers_count":309,"open_issues_count":51,"forks_count":44,"subscribers_count":11,"default_branch":"master","last_synced_at":"2024-10-12T08:13:27.336Z","etag":null,"topics":["form-validation","javascript","javascript-plugin","vanilla-js"],"latest_commit_sha":null,"homepage":null,"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/cferdinandi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE.md","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-09T15:25:31.000Z","updated_at":"2024-09-22T08:24:40.000Z","dependencies_parsed_at":"2024-06-18T15:25:24.755Z","dependency_job_id":"4e46cba6-3dec-4da4-ae7e-551b9d6a5c69","html_url":"https://github.com/cferdinandi/bouncer","commit_stats":null,"previous_names":[],"tags_count":24,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cferdinandi%2Fbouncer","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cferdinandi%2Fbouncer/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cferdinandi%2Fbouncer/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/cferdinandi%2Fbouncer/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/cferdinandi","download_url":"https://codeload.github.com/cferdinandi/bouncer/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247182334,"owners_count":20897379,"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","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":["form-validation","javascript","javascript-plugin","vanilla-js"],"created_at":"2024-10-11T08:13:26.097Z","updated_at":"2025-04-04T13:09:26.653Z","avatar_url":"https://github.com/cferdinandi.png","language":"JavaScript","funding_links":[],"categories":["UI Components"],"sub_categories":["Form Validation"],"readme":"# Bouncer.js [![Build Status](https://travis-ci.org/cferdinandi/bouncer.svg)](https://travis-ci.org/cferdinandi/bouncer)\nA lightweight form validation script that augments native HTML5 form validation elements and attributes.\n\n**[View the Demo on CodePen \u0026rarr;](https://codepen.io/cferdinandi/pen/ywMdKp)**\n\n[Getting Started](#getting-started) | [Form Validation Attributes](#form-validation-attributes) | [Error Styling](#error-styling) | [Error Types](#error-types) | [Custom Validations](#custom-validation-types) | [Error Location](#error-message-location) | [API](#api) | [Browser Compatibility](#browser-compatibility) | [License](#license) |\n\n**Features:**\n\n- Fields validate on blur (as the user moves out of them), which data shows is the best time for cognitive load.\n- The entire form is validated on submit.\n- Fields with errors are revalidated as the user types. Errors are removed the instant the field is valid.\n- Supports custom validation patterns and error messages.\n\n\n\u003chr\u003e\n\n### Want to learn how to write your own vanilla JS plugins? Check out my [Vanilla JS Pocket Guides](https://vanillajsguides.com/) or join the [Vanilla JS Academy](https://vanillajsacademy.com) and level-up as a web developer. 🚀\n\n\u003chr\u003e\n\n\n## Getting Started\n\nCompiled and production-ready code can be found in the `dist` directory. The `src` directory contains development code.\n\n### 1. Include Bouncer on your site.\n\nThere are two versions of Bouncer: the standalone version, and one that comes preloaded with polyfills for `closest()`, `matches()`, `classList`, and `CustomEvent()`, which are only supported in newer browsers.\n\nIf you're including your own polyfills or don't want to enable this feature for older browsers, use the standalone version. Otherwise, use the version with polyfills.\n\n**Direct Download**\n\nYou can [download the files directly from GitHub](https://github.com/cferdinandi/bouncer/archive/master.zip).\n\n```html\n\u003cscript src=\"path/to/bouncer.polyfills.min.js\"\u003e\u003c/script\u003e\n```\n\n**CDN**\n\nYou can also use the [jsDelivr CDN](https://cdn.jsdelivr.net/gh/cferdinandi/bouncer/dist/). I recommend linking to a specific version number or version range to prevent major updates from breaking your site. Smooth Scroll uses semantic versioning.\n\n```html\n\u003c!-- Always get the latest version --\u003e\n\u003c!-- Not recommended for production sites! --\u003e\n\u003cscript src=\"https://cdn.jsdelivr.net/gh/cferdinandi/bouncer/dist/bouncer.polyfills.min.js\"\u003e\u003c/script\u003e\n\n\u003c!-- Get minor updates and patch fixes within a major version --\u003e\n\u003cscript src=\"https://cdn.jsdelivr.net/gh/cferdinandi/bouncer@1/dist/bouncer.polyfills.min.js\"\u003e\u003c/script\u003e\n\n\u003c!-- Get patch fixes within a minor version --\u003e\n\u003cscript src=\"https://cdn.jsdelivr.net/gh/cferdinandi/bouncer@1.0/dist/bouncer.polyfills.min.js\"\u003e\u003c/script\u003e\n\n\u003c!-- Get a specific version --\u003e\n\u003cscript src=\"https://cdn.jsdelivr.net/gh/cferdinandi/bouncer@1.0.0/dist/bouncer.polyfills.min.js\"\u003e\u003c/script\u003e\n```\n\n**NPM**\n\nYou can also use NPM (or your favorite package manager).\n\n```bash\nnpm install formbouncerjs\n```\n\n### 2. Add browser-native form validation attributes to your markup.\n\nNo special markup needed\u0026mdash;just browser-native validation attributes (like `required`) and input types (like `email` or `number`).\n\n```html\n\u003cform\u003e\n\t\u003clabel for=\"email\"\u003eYour email address\u003c/label\u003e\n\t\u003cinput type=\"email\" name=\"email\" id=\"email\"\u003e\n\t\u003cbutton\u003eSubmit\u003c/button\u003e\n\u003c/form\u003e\n```\n\n### 3. Initialize Bouncer.\n\nIn the footer of your page, after the content, initialize Bouncer by passing in a selector for the forms that should be validated.\n\nIf the form has errors, submission will get blocked until they're corrected. Otherwise, it will submit as normal.\n\nAnd that's it, you're done. Nice work!\n\n```html\n\u003cscript\u003e\n\tvar validate = new Bouncer('form');\n\u003c/script\u003e\n```\n\n\n\n## Form Validation Attributes\n\nModern browsers provide built-in form validation.\n\nBouncer hooks into those native attributes, suppressing the native validation and running its own. If Bouncer fails to load or run, the browser-native validation will run in its place.\n\n### Required fields\n\nAdd the `required` attribute to any field that must be filled out or selected.\n\n```html\n\u003cinput type=\"text\" name=\"first-name\" required\u003e\n```\n\n### Special Input Types\n\nYou can use special `type` attribute values to indicate specific types of data that should be captured.\n\n```html\n\u003c!-- Must be a valid email address --\u003e\n\u003cinput type=\"email\" name=\"email\"\u003e\n\n\u003c!-- Must be a valid URL --\u003e\n\u003cinput type=\"url\" name=\"website\"\u003e\n\n\u003c!-- Must be a number --\u003e\n\u003cinput type=\"number\" name=\"age\"\u003e\n\n\u003c!-- Must be a date in YYYY-MM-DD format (many browsers include a native date picker for this) --\u003e\n\u003cinput type=\"date\" name=\"dob\"\u003e\n\n\u003c!-- Must be a time in 24-hour format (many browsers include a native date picker for this) --\u003e\n\u003cinput type=\"time\" name=\"time\"\u003e\n\n\u003c!-- Must be a month/year in YYYY-MM format (many browsers include a native date picker for this) --\u003e\n\u003cinput type=\"month\" name=\"birthday\"\u003e\n\n\u003c!-- Must be a color in #rrggbb format (many browsers include a native color picker for this) --\u003e\n\u003cinput type=\"color\" name=\"color\"\u003e\n```\n\n### Min and Max Values\n\nFor numbers that should not go below or exceed a certain value, you can use the `min` and `max` attributes, respectively.\n\n```html\n\u003c!-- Cannot exceed 72 --\u003e\n\u003cinput type=\"number\" max=\"72\" name=\"answer\"\u003e\n\n\u003c!-- Cannot be below 37 --\u003e\n\u003cinput type=\"number\" min=\"37\" name=\"answer\"\u003e\n\n\u003c!-- They can also be combined --\u003e\n\u003cinput type=\"number\" min=\"37\" max=\"72\" name=\"answer\"\u003e\n```\n\n### Min and Max Length\n\nFor inputs that should not be shorter or longer than a certain number of characters, you can use the `minlength` and `maxlength` attributes, respectively.\n\n```html\n\u003c!-- Cannot be shorter than 12 characters --\u003e\n\u003cinput type=\"password\" minlength=\"12\" name=\"password\"\u003e\n\n\u003c!-- Cannot be longer than 24 characters --\u003e\n\u003cinput type=\"text\" maxlength=\"24\" name=\"first-name\"\u003e\n\n\u003c!-- They can also be combined --\u003e\n\u003cinput type=\"text\" minlength=\"7\" maxlength=\"24\" name=\"favorite-pixar-character\"\u003e\n```\n\n### Custom Validation Patterns\n\nYou can use your own validation pattern for a field with the `pattern` attribute. This uses regular expressions.\n\n```html\n\u003c!-- Phone number be in 555-555-5555 format --\u003e\n\u003cinput type=\"text\" name=\"tel\" pattern=\"\\d{3}[\\-]\\d{3}[\\-]\\d{4}\"\u003e\n```\n\n### Custom Pattern Mismatch Error Messages\n\nShow custom errors for pattern mismatches by adding the `[data-bouncer-message]` attribute to the field.\n\n```html\n\u003c!-- Phone number be in 555-555-5555 format --\u003e\n\u003cinput type=\"text\" name=\"tel\" pattern=\"\\d{3}[\\-]\\d{3}[\\-]\\d{4}\" data-bouncer-message=\"Please use the following format: 555-555-5555\"\u003e\n```\n\n\n\n## Error Styling\n\nBouncer does not come pre-packaged with any styles for fields with errors or error messages. Use the `.error` class to style fields, and the `.error-message` class to style error messages.\n\nNeed a starting point? Here's some really lightweight CSS you can use.\n\n```css\n/**\n * Form Validation Errors\n */\n.error {\n\tborder-color: red;\n}\n\n.error-message {\n\tcolor: red;\n\tfont-style: italic;\n\tmargin-bottom: 1em;\n}\n```\n\n\n\n## Error Types\n\nBouncer captures four different types of field errors:\n\n- **`missingValue`** errors occur when a `required` field has no value (or for checkboxes and radio buttons, nothing is selected).\n- **`patternMismatch`** errors occur when a value doesn't match the expected pattern for a particular input type, or a pattern provided by the `pattern` attribute.\n- **`outOfRange`** errors occur when a number is above or below the `min` or `max` values.\n- **`wrongLength`** errors occur when the input is longer or shorter than the `minlength` and `maxlength` values.\n\nThe patterns and messages associated with these types of errors can be customized.\n\n\n\n## Custom Validation Types\n\nYou can add custom validation types to Bouncer beyond the four standard validations.\n\nYou can see this feature in action with the *Confirm Password* field on [the demo page](http://cferdinandi.github.io/bouncer/), and view examples of custom validations in the Cookbook (*coming soon*).\n\n### Adding custom validations\n\nPass in a `customValidations` object as an option when instantiating a new Bouncer instance. Each property in the object is a new validation type. Each value should be a function that accepts two arguments: the field being validated and the settings for the current instantiation.\n\nThe function should *check if the field has an error*. Return `true` if there's an error, and `false` when there's not.\n\n```js\nvar validate = new Bouncer('form', {\n\tcustomValidations: {\n\t\tisHello: function (field) {\n\n\t\t\t// Return false because there is NO error\n\t\t\tif (field.value === 'hello') return false;\n\n\t\t\t// Return true when there is\n\t\t\treturn true;\n\n\t\t}\n\t}\n});\n```\n\n### Creating custom validation error messages\n\nAdd an error message for the custom validation by including the `messages` object in your options.\n\nThe key should be the same as your custom validation. It's value can be a string, or a function that returns a string. Message functions can accept two arguments: the field being validated and the settings for the current instantiation.\n\n```js\nvar validate = new Bouncer('form', {\n\tcustomValidations: {\n\t\tisHello: function (field) {\n\n\t\t\t// Return false because there is NO error\n\t\t\tif (field.value === 'hello') return false;\n\n\t\t\t// Return true when there is\n\t\t\treturn true;\n\n\t\t}\n\t},\n\tmessages: {\n\t\t// As a string\n\t\tisHello: 'This field should have a value of \"hello\"',\n\n\t\t// As a function\n\t\tisHello: function () {\n\t\t\treturn 'This field should have a value of \"hello\"';\n\t\t}\n\t}\n});\n```\n\n## Error Message Location\n\nBy default, bouncer will render error messages after the invalid field (or the label for it, if the field is a `radio` or `checkbox`).\n\nYou can optionally render error messages *before* the field by setting the `messageAfterField` option to `false`.\n\n```js\nvar validate = new Bouncer('form', {\n\tmessageAfterField: false\n});\n```\n\nYou can also assign a custom location for an error message by including the `[data-bouncer-target]` attribute on a field. Use a selector for where the message should go as its value.\n\n```html\n\u003clabel for=\"email\"\u003eYour Email Address\u003c/label\u003e\n\u003cinput type=\"email\" name=\"email\" id=\"email\" data-bouncer-target=\"#email-error\"\u003e\n\u003cp\u003e\u003cstrong\u003eWhy do we need this?\u003c/strong\u003e We'll use your email address to send you account information.\u003c/p\u003e\n\u003cdiv id=\"email-error\"\u003e\u003c/div\u003e\n```\n\n\n\n## API\n\nBouncer includes smart defaults and works right out of the box.\n\nBut if you want to customize things, it also has a robust API that provides multiple ways for you to adjust the default options and settings.\n\n### Options and Settings\n\nYou can customize validation patterns, error messages, and more by passing and options object into Bouncer during instantiation.\n\n```js\nvar validate = new Bouncer('form', {\n\n\t// Classes \u0026 IDs\n\tfieldClass: 'error', // Applied to fields with errors\n\terrorClass: 'error-message', // Applied to the error message for invalid fields\n\tfieldPrefix: 'bouncer-field_', // If a field doesn't have a name or ID, one is generated with this prefix\n\terrorPrefix: 'bouncer-error_', // Prefix used for error message IDs\n\n\t// Patterns\n\t// Validation patterns for specific input types\n\tpatterns: {\n\t\temail: /^([^\\x00-\\x20\\x22\\x28\\x29\\x2c\\x2e\\x3a-\\x3c\\x3e\\x40\\x5b-\\x5d\\x7f-\\xff]+|\\x22([^\\x0d\\x22\\x5c\\x80-\\xff]|\\x5c[\\x00-\\x7f])*\\x22)(\\x2e([^\\x00-\\x20\\x22\\x28\\x29\\x2c\\x2e\\x3a-\\x3c\\x3e\\x40\\x5b-\\x5d\\x7f-\\xff]+|\\x22([^\\x0d\\x22\\x5c\\x80-\\xff]|\\x5c[\\x00-\\x7f])*\\x22))*\\x40([^\\x00-\\x20\\x22\\x28\\x29\\x2c\\x2e\\x3a-\\x3c\\x3e\\x40\\x5b-\\x5d\\x7f-\\xff]+|\\x5b([^\\x0d\\x5b-\\x5d\\x80-\\xff]|\\x5c[\\x00-\\x7f])*\\x5d)(\\x2e([^\\x00-\\x20\\x22\\x28\\x29\\x2c\\x2e\\x3a-\\x3c\\x3e\\x40\\x5b-\\x5d\\x7f-\\xff]+|\\x5b([^\\x0d\\x5b-\\x5d\\x80-\\xff]|\\x5c[\\x00-\\x7f])*\\x5d))*(\\.\\w{2,})+$/,\n\t\turl: /^(?:(?:https?|HTTPS?|ftp|FTP):\\/\\/)(?:\\S+(?::\\S*)?@)?(?:(?!(?:10|127)(?:\\.\\d{1,3}){3})(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-zA-Z\\u00a1-\\uffff0-9]-*)*[a-zA-Z\\u00a1-\\uffff0-9]+)(?:\\.(?:[a-zA-Z\\u00a1-\\uffff0-9]-*)*[a-zA-Z\\u00a1-\\uffff0-9]+)*(?:\\.(?:[a-zA-Z\\u00a1-\\uffff]{2,}))\\.?)(?::\\d{2,5})?(?:[/?#]\\S*)?$/,\n\t\tnumber: /[-+]?[0-9]*[.,]?[0-9]+/,\n\t\tcolor: /^#?([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$/,\n\t\tdate: /(?:19|20)[0-9]{2}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-9])|(?:(?!02)(?:0[1-9]|1[0-2])-(?:30))|(?:(?:0[13578]|1[02])-31))/,\n\t\ttime: /(0[0-9]|1[0-9]|2[0-3])(:[0-5][0-9])/,\n\t\tmonth: /(?:19|20)[0-9]{2}-(?:(?:0[1-9]|1[0-2]))/\n\t},\n\n\t// Message Settings\n\tmessageAfterField: true, // If true, displays error message below field. If false, displays it above.\n\tmessageCustom: 'data-bouncer-message', // The data attribute to use for customer error messages\n\tmessageTarget: 'data-bouncer-target', // The data attribute to pass in a custom selector for the field error location\n\n\t// Error messages by error type\n\tmessages: {\n\t\tmissingValue: {\n\t\t\tcheckbox: 'This field is required.',\n\t\t\tradio: 'Please select a value.',\n\t\t\tselect: 'Please select a value.',\n\t\t\t'select-multiple': 'Please select at least one value.',\n\t\t\tdefault: 'Please fill out this field.'\n\t\t},\n\t\tpatternMismatch: {\n\t\t\temail: 'Please enter a valid email address.',\n\t\t\turl: 'Please enter a URL.',\n\t\t\tnumber: 'Please enter a number',\n\t\t\tcolor: 'Please match the following format: #rrggbb',\n\t\t\tdate: 'Please use the YYYY-MM-DD format',\n\t\t\ttime: 'Please use the 24-hour time format. Ex. 23:00',\n\t\t\tmonth: 'Please use the YYYY-MM format',\n\t\t\tdefault: 'Please match the requested format.'\n\t\t},\n\t\toutOfRange: {\n\t\t\tover: 'Please select a value that is no more than {max}.',\n\t\t\tunder: 'Please select a value that is no less than {min}.'\n\t\t},\n\t\twrongLength: {\n\t\t\tover: 'Please shorten this text to no more than {maxLength} characters. You are currently using {length} characters.',\n\t\t\tunder: 'Please lengthen this text to {minLength} characters or more. You are currently using {length} characters.'\n\t\t}\n\t},\n\n\t// Form Submission\n\tdisableSubmit: false, // If true, native form submission is suppressed even when form validates\n\n\t// Custom Events\n\temitEvents: true // If true, emits custom events\n\n});\n```\n\n### Custom Events\n\nBouncer emits five custom events:\n\n- `bouncerShowError` is emitted on a field when an error is displayed for it.\n- `bouncerRemoveError` is emitted on a field when an error is removed from it.\n- `bouncerFormValid` is emitted on a form is successfully validated.\n- `bouncerFormInvalid` is emitted on a form that fails validation.\n- `bouncerInitialized` is emitted when bouncer initializes.\n- `bouncerDestroy` is emitted when bouncer is destroyed.\n\nYou can listen for these events with `addEventListener`. All five events bubble up the DOM. The `event.target` is the field or form (or document, when initializing and destroying).\n\n```js\n// Detect show error events\ndocument.addEventListener('bouncerShowError', function (event) {\n\n\t// The field with the error\n\tvar field = event.target;\n\n}, false);\n\n// Detect a successful form validation\ndocument.addEventListener('bouncerFormValid', function (event) {\n\n\t// The successfully validated form\n\tvar form = event.target;\n\n\t// If `disableSubmit` is true, you might use this to submit the form with Ajax\n\n}, false);\n```\n\nThe `event.detail` object holds event-specific information:\n\n- On the `bouncerShowError` event, it has the specific errors for the field.\n- On the `bouncerInitialized` and `bouncerDestroyed` events , it contains the `settings` for the instantiation.\n- On the `bouncerFormInvalid` event, it includes all of the fields with errors under `event.detail`.\n\n```js\n// Detect show error events\ndocument.addEventListener('bouncerShowError', function (event) {\n\n\t// The field with the error\n\tvar field = event.target;\n\n\t// The error details\n\tvar errors = event.details.errors;\n\n}, false);\n```\n\n### Using Bouncer methods in your own scripts\n\nBouncer exposes a few public methods that you can use in your own scripts.\n\n#### `validate()`\n\nValidate a field. Pass in the field as an argument. Returns an object with validity data.\n\n```js\n// Get a field\nvar field = document.querySelector('#email');\n\n// Validate the field\nvar bouncer = new Bouncer();\nvar isValid = bouncer.validate(field);\n\n// Returns an object\nisValid = {\n\n\t// If true, field is valid\n\tvalid: false,\n\n\t// The specific errors\n\terrors: {\n\t\tmissingValue: true,\n\t\tpatternMismatch: true,\n\t\toutOfRange: true,\n\t\twrongLength: true\n\t}\n\n};\n\n// You can also pass in custom options\nbouncer.validate(field, {\n\t// ...\n});\n```\n\n#### `validateAll()`\n\nValidate all fields in a form or fieldset. Pass in the section as an argument. Returns an array of fields with errors.\n\n```js\n// Get a fieldset\nvar fieldset = document.querySelector('#fieldset');\n\n// Validate the field\nvar bouncer = new Bouncer();\nvar areValid = bouncer.validateAll(fieldset);\n```\n\n#### `destroy()`\n\nDestroys an instantiated Bouncer instance. Removes any errors from the form and turns validation back over to the browser-native APIs.\n\n```js\n// An bouncer instance\nvar bouncer = new Bouncer('form');\n\n// Destroy it\nbouncer.destroy();\n```\n\n\n\n## Browser Compatibility\n\nBouncer works in all modern browsers, and IE 9 and above.\n\nBouncer is built with modern JavaScript APIs, and uses progressive enhancement. If the JavaScript file fails to load, browser-native form validation runs instead\n\n### Polyfills\n\nSupport back to IE9 requires polyfills for `closest()`, `matches()`, `classList`, and `CustomEvent()`. Without them, support starts with Edge.\n\nUse the included polyfills version of Bouncer, or include your own.\n\n\n\n## License\n\nThe code is available under the [MIT License](LICENSE.md).","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcferdinandi%2Fbouncer","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcferdinandi%2Fbouncer","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcferdinandi%2Fbouncer/lists"}