{"id":16223682,"url":"https://github.com/lykmapipo/sails-hook-validation","last_synced_at":"2026-03-02T08:30:48.193Z","repository":{"id":27217488,"uuid":"30688565","full_name":"lykmapipo/sails-hook-validation","owner":"lykmapipo","description":"Custom validation error messages for sails model with i18n support","archived":false,"fork":false,"pushed_at":"2018-11-13T05:58:07.000Z","size":90,"stargazers_count":103,"open_issues_count":13,"forks_count":29,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-10-25T02:54:11.821Z","etag":null,"topics":["javascript","sails","sails-hook","sails-hook-validation","sails-model","validations"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lykmapipo.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-02-12T06:11:12.000Z","updated_at":"2025-10-03T22:00:12.000Z","dependencies_parsed_at":"2022-08-31T19:22:02.145Z","dependency_job_id":null,"html_url":"https://github.com/lykmapipo/sails-hook-validation","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/lykmapipo/sails-hook-validation","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lykmapipo%2Fsails-hook-validation","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lykmapipo%2Fsails-hook-validation/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lykmapipo%2Fsails-hook-validation/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lykmapipo%2Fsails-hook-validation/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lykmapipo","download_url":"https://codeload.github.com/lykmapipo/sails-hook-validation/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lykmapipo%2Fsails-hook-validation/sbom","scorecard":{"id":607298,"data":{"date":"2025-08-11","repo":{"name":"github.com/lykmapipo/sails-hook-validation","commit":"f0e666c4ba717f6fb3b58b43f2bb92c25d6498ff"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.3,"checks":[{"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":"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":"Code-Review","score":5,"reason":"Found 8/16 approved changesets -- score normalized to 5","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":-1,"reason":"no workflows found","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":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"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":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"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":"License","score":0,"reason":"license file not detected","details":["Warn: project does not have a license file"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"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":"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":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"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 22 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-21T01:53:43.481Z","repository_id":27217488,"created_at":"2025-08-21T01:53:43.482Z","updated_at":"2025-08-21T01:53:43.482Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29995912,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-02T01:47:34.672Z","status":"online","status_checked_at":"2026-03-02T02:00:07.342Z","response_time":60,"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":["javascript","sails","sails-hook","sails-hook-validation","sails-model","validations"],"created_at":"2024-10-10T12:19:44.285Z","updated_at":"2026-03-02T08:30:48.156Z","avatar_url":"https://github.com/lykmapipo.png","language":"JavaScript","readme":"sails-hook-validation\n=====================\n\n[![Build Status](https://travis-ci.org/lykmapipo/sails-hook-validation.svg?branch=master)](https://travis-ci.org/lykmapipo/sails-hook-validation)\n\nCustom validation error messages for sails model with i18n support. Its works with `callback`, `deferred` and `promise` style `model API` provided with sails.\n\n*Note:* \n- *This requires Sails v0.11.0+.  If v0.11.0+ isn't published to NPM yet, you'll need to install it via Github.*\n- *`sails-hook-validation` work by patch model static `validate()`, `create()`, `createEach()`, `findOrCreate()`, `findOrCreateEach()` and `update()`.*\n- *To have custom error messages at model instance level consider using [sails-model-new](https://github.com/lykmapipo/sails-model-new).*\n- *`sails-hook-validation` opt to use `error.Errors` and not to re-create or remove any properties of error object so as to remain with sails legacy options*\n\n## Installation\n```sh\n$ npm install --save sails-hook-validation\n```\n\n## Usage\n\n### Use without i18n\nAdd `validationMessages` static property in your sails model\n```js\n//this is example\nmodule.exports = {\n    attributes: {\n        username: {\n            type: 'string',\n            required: true\n        },\n        email: {\n            type: 'email',\n            required: true,\n            unique: true\n        }\n    },\n    //model validation messages definitions\n    validationMessages: { //hand for i18n \u0026 l10n\n        email: {\n            required: 'Email is required',\n            email: 'Provide valid email address',\n            unique: 'Email address is already taken'\n        },\n        username: {\n            required: 'Username is required'\n        }\n    }\n};\n```\n\n### Use with i18n\nAdd validation messages into `config/locale` files following `modelId.attribute.rule`. If model contains any `validationMessages` definition, they will take precedence over locale defined messages.\n\nExample\n```javascript\n//define your model in api/model/Authentication.js\nmodule.exports = {\n    attributes: {\n        username: {\n            type: 'string',\n            required: true\n        },\n        email: {\n            type: 'email',\n            required: true,\n            unique: true\n        },\n        birthday: {\n            type: 'date',\n            required: true\n        }\n    }\n};\n```\n\nThen define validation messages per locale\n\n```javascript\n//in config/locale/en.json\n{\n    \"authentication.email.required\": \"Email is required\",\n    \"authentication.email.email\": \"Provide valid email address\",\n    \"authentication.email.unique\": \"Email address is already taken\",\n    \"authentication.username.required\": \"Username is required\",\n    \"authentication.username.string\": \"Username is must be a valid string\",\n    \"authentication.birthday.required\": \"Birthday is required\",\n    \"authentication.birthday.date\": \"Birthday is not a valid date\"\n}\n\n//in config/locale/sw.json\n{\n    \"authentication.email.required\": \"Barua pepe yahitajika\",\n    \"authentication.email.email\": \"Toa barua pepe iliyo halali\",\n    \"authentication.email.unique\": \"Barua pepe tayari ishachukuliwa\",\n    \"authentication.username.required\": \"Jina lahitajika\",\n    \"authentication.username.string\": \"Jina lazima liwe ni mchanganyiko wa herufi\",\n    \"authentication.birthday.required\": \"Siku ya kuzaliwa yahitajika\",\n    \"authentication.birthday.date\": \"Siku ya kuzaliwa sio tarehe\"\n}\n```\n\nNow you can call model static \n- `create()`\n- `createEach()`\n- `findOrCreate()`\n- `findOrCreateEach()`\n- `update()` \n- and other static model method that invoke `Model.validate()`. \n\nIf there is any *validations or database errors* `sails-hook-validation` will put your custom errors message in `error.Errors` of the error object returned by those methods in your `callback` or `promise catch`.\n\n### create()\n```js\n//anywhere in your codes if\n//you invoke\n User\n    .create({}, function(error, user) {\n        //you will expect the following\n        //error to exist on error.Errors based on \n        //your custom validation messages\n\n        expect(error.Errors.email).to.exist;\n\n        expect(error.Errors.email[0].message)\n            .to.equal(User.validationMessages.email.email);\n\n        expect(error.Errors.email[1].message)\n            .to.equal(User.validationMessages.email.required);\n\n\n        expect(error.Errors.username).to.exist;\n        expect(error.Errors.username[0].message)\n            .to.equal(User.validationMessages.username.required);\n\n        done();\n    });\n```\n\n### createEach()\n```js\nUser\n    .createEach([{\n        email: faker.internet.email(),\n        username: faker.internet.userName()\n    }, {\n        email: 'otherExistingModelEmail',\n        username: username\n    }])\n    .catch(function(error) {\n        //you will expect the following\n        //error to exist on error.Errors based on \n        //your custom validation messages\n\n        expect(error.Errors.email).to.exist;\n\n        expect(error.Errors.email[0].message)\n            .to.equal(User.validationMessages.email.unique);\n\n        done();\n    });\n```\n\n### findOrCreate()\n```js\nUser\n    .findOrCreate({\n        email: faker.internet.email()\n    }, {\n        email: 'otherExistingModelEmail',\n        username: username\n    })\n    .exec(function(error, user) {\n        //you will expect the following\n        //error to exist on error.Errors based on \n        //your custom validation messages\n\n        expect(error.Errors.email).to.exist;\n\n        expect(error.Errors.email[0].message)\n            .to.equal(User.validationMessages.email.unique);\n\n        done();\n    });\n```\n\n### findOrCreateEach()\n```js\nUser\n    .findOrCreateEach(\n        [{\n            email: faker.internet.email()\n        }], [{\n            email: 'otheExistingModelEmail',\n            username: username\n        }]\n    )\n    .catch(function(error) {\n        //you will expect the following\n        //error to exist on error.Errors based on \n        //your custom validation messages\n\n        expect(error.Errors.email).to.exist;\n\n        expect(error.Errors.email[0].message)\n            .to.equal(User.validationMessages.email.unique);\n\n        done();\n    });\n```\n\n### update()\n```js\nUser\n    .update({\n        email: 'modelEmail'\n    }, {\n        email: 'otherExistingModelEmail'\n    }, function(error, user) {\n        //you will expect the following\n        //error to exist on error.Errors based on \n        //your custom validation messages\n\n        expect(error.Errors.email).to.exist;\n\n        expect(error.Errors.email[0].message)\n            .to.equal(User.validationMessages.email.unique);\n\n        done();\n    });\n```\n\n## Testing\n\n* Clone this repository\n\n* Install all development dependencies\n\n```sh\n$ npm install\n```\n* Then run test\n\n```sh\n$ npm test\n```\n\n## Contribute\n\nFork this repo and push in your ideas. \nDo not forget to add a bit of test(s) of what value you adding.\n\n## Licence\n\nThe MIT License (MIT)\n\nCopyright (c) 2015 lykmapipo \u0026 Contributors\n\nPermission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flykmapipo%2Fsails-hook-validation","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flykmapipo%2Fsails-hook-validation","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flykmapipo%2Fsails-hook-validation/lists"}