diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index aae5ab0..aaf3312 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,12 +1,8 @@ name: CI on: - push: - branches-ignore: - - 'dependabot/**' #avoid duplicates: run the PR, not the push - tags-ignore: - - 'v*' #avoid rerun existing commit on release pull_request: + types: [opened, synchronize, reopened] env: CI: true diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index f79da52..7a266d6 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -1,13 +1,8 @@ name: publish on: - push: - branches: - - main - paths: - - package.json - release: - types: [published] + release: + types: [published] env: CI: true diff --git a/.prettierrc.yml b/.prettierrc.yml deleted file mode 100644 index 9b110b8..0000000 --- a/.prettierrc.yml +++ /dev/null @@ -1,3 +0,0 @@ -trailingComma: 'all' -semi: false -singleQuote: true diff --git a/.release b/.release index 7307651..d106d83 160000 --- a/.release +++ b/.release @@ -1 +1 @@ -Subproject commit 73076513e83c2057a32515831b638771c15b1d83 +Subproject commit d106d83e69d5d8c99e4d6be4ba98ddde550d082b diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d5d1f7..d7a2efc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/). ### Unreleased +### [0.8.3] - 2026-03-13 + +- ns: NSD -> nsd +- user: user is now an array +- prettier: move config into package.json +- zone: last publish can be all zeroes +- zone_rec: expanded valid RR types & all the fields that go with them +- ESM: dual export with wrapper +- deps: bump all to latest + ### [0.8.2] - 2025-04-08 - feat(zone_record): added GET, POST, and DELETE formats @@ -77,13 +87,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/). [0.5.0]: https://github.com/NicTool/validate/releases/tag/0.5.0 [0.6.0]: https://github.com/NicTool/validate/releases/tag/0.6.0 [0.6.1]: https://github.com/NicTool/validate/releases/tag/0.6.1 -[0.6.3]: https://github.com/NicTool/validate/releases/tag/0.6.3 +[0.6.3]: https://github.com/NicTool/validate/releases/tag/v0.6.3 [0.7.0]: https://github.com/NicTool/validate/releases/tag/0.7.0 -[0.7.1]: https://github.com/NicTool/validate/releases/tag/0.7.1 +[0.7.1]: https://github.com/NicTool/validate/releases/tag/v0.7.1 [0.7.2]: https://github.com/NicTool/validate/releases/tag/0.7.2 [0.7.3]: https://github.com/NicTool/validate/releases/tag/0.7.3 -[0.7.4]: https://github.com/NicTool/validate/releases/tag/0.7.4 -[0.8.0]: https://github.com/NicTool/validate/releases/tag/0.8.0 +[0.7.4]: https://github.com/NicTool/validate/releases/tag/v0.7.4 +[0.8.0]: https://github.com/NicTool/validate/releases/tag/v0.8.0 [0.8.1]: https://github.com/NicTool/validate/releases/tag/v0.8.1 [0.8.2]: https://github.com/NicTool/validate/releases/tag/v0.8.2 -[1.0.0]: https://github.com/NicTool/validate/releases/tag/1.0.0 +[0.8.3]: https://github.com/NicTool/validate/releases/tag/v0.8.3 diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index bf1f31d..f3b0392 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -1,8 +1,8 @@ # Contributors -This handcrafted artisinal software is brought to you by: +This handcrafted artisanal software is brought to you by: -|
msimerson (21) | +|
msimerson (22) | | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | this file is generated by [.release](https://github.com/msimerson/.release). diff --git a/eslint.config.mjs b/eslint.config.mjs index 2c521da..8350eec 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -1,22 +1,13 @@ import globals from 'globals' -import path from 'node:path' -import { fileURLToPath } from 'node:url' import js from '@eslint/js' -import { FlatCompat } from '@eslint/eslintrc' - -const __filename = fileURLToPath(import.meta.url) -const __dirname = path.dirname(__filename) -const compat = new FlatCompat({ - baseDirectory: __dirname, - recommendedConfig: js.configs.recommended, - allConfig: js.configs.all, -}) +import prettier from 'eslint-config-prettier' export default [ { - ignores: ['**/package-lock.json'], + ignores: ['**/package-lock.json', 'node_modules/**', '.release/**'], }, - ...compat.extends('eslint:recommended', 'prettier'), + js.configs.recommended, + prettier, { languageOptions: { globals: { diff --git a/index.js b/index.js index b260fd6..c3bb025 100644 --- a/index.js +++ b/index.js @@ -1,11 +1,3 @@ -for (const l of [ - 'group', - 'nameserver', - 'permission', - 'session', - 'user', - 'zone', - 'zone_record', -]) { +for (const l of ['group', 'nameserver', 'permission', 'session', 'user', 'zone', 'zone_record']) { module.exports[l] = require(`./lib/${l}`) } diff --git a/index.mjs b/index.mjs new file mode 100644 index 0000000..c5278f4 --- /dev/null +++ b/index.mjs @@ -0,0 +1,14 @@ +import { createRequire } from 'node:module' + +const require = createRequire(import.meta.url) +const validate = require('./index.js') + +export default validate + +export const group = validate.group +export const nameserver = validate.nameserver +export const permission = validate.permission +export const session = validate.session +export const user = validate.user +export const zone = validate.zone +export const zone_record = validate.zone_record diff --git a/lib/group.test.js b/lib/group.test.js index 5bd1d2f..778cebd 100644 --- a/lib/group.test.js +++ b/lib/group.test.js @@ -28,10 +28,7 @@ describe('group', function () { const { error, value } = schema.validate(testCase) - assert.strictEqual( - error.message, - '"name" length must be at least 3 characters long', - ) + assert.strictEqual(error.message, '"name" length must be at least 3 characters long') assert.deepEqual(value, testCase) }) diff --git a/lib/nameserver.js b/lib/nameserver.js index 784c2f0..078d9f1 100644 --- a/lib/nameserver.js +++ b/lib/nameserver.js @@ -10,15 +10,7 @@ exports.name = Joi.string() .domain({ allowFullyQualified: true, tlds: false }) .pattern(/\.$/) -exports.type = Joi.string().valid( - 'bind', - 'djbdns', - 'knot', - 'NSD', - 'maradns', - 'powerdns', - 'dynect', -) +exports.type = Joi.string().valid('bind', 'djbdns', 'knot', 'nsd', 'maradns', 'powerdns', 'dynect') exports.remote_login = Joi.string().empty('').max(127) diff --git a/lib/nameserver.test.js b/lib/nameserver.test.js index 6e14129..19478a9 100644 --- a/lib/nameserver.test.js +++ b/lib/nameserver.test.js @@ -35,10 +35,7 @@ describe('nameserver', function () { }) } - const errMsgs = [ - '"name" must be a valid hostname', - '"name" must contain a valid domain name', - ] + const errMsgs = ['"name" must be a valid hostname', '"name" must contain a valid domain name'] const invalid_names = [ '-bad_ns', @@ -77,15 +74,7 @@ describe('nameserver', function () { assert.deepEqual(value, testCase) }) - for (const n of [ - 'bind', - 'djbdns', - 'knot', - 'NSD', - 'maradns', - 'powerdns', - 'dynect', - ]) { + for (const n of ['bind', 'djbdns', 'knot', 'nsd', 'maradns', 'powerdns', 'dynect']) { it(`accepts valid: ${n}`, () => { const testCase = JSON.parse(JSON.stringify(testNS)) testCase.export.type = n @@ -97,16 +86,7 @@ describe('nameserver', function () { }) } - for (const n of [ - 'cryptic', - 'fuzzy', - 'yitizg', - 'bin', - 'djbs', - 'DJB', - 'BIND', - 'NT', - ]) { + for (const n of ['cryptic', 'fuzzy', 'yitizg', 'bin', 'djbs', 'DJB', 'BIND', 'NT']) { it(`rejects invalid: ${n}`, () => { const testCase = JSON.parse(JSON.stringify(testNS)) testCase.export.type = n @@ -115,7 +95,7 @@ describe('nameserver', function () { assert.strictEqual( error.message, - '"export.type" must be one of [bind, djbdns, knot, NSD, maradns, powerdns, dynect]', + '"export.type" must be one of [bind, djbdns, knot, nsd, maradns, powerdns, dynect]', ) assert.deepEqual(value, testCase) }) diff --git a/lib/test/nameserver.json b/lib/test/nameserver.json index f37c502..d030553 100644 --- a/lib/test/nameserver.json +++ b/lib/test/nameserver.json @@ -8,7 +8,7 @@ "logdir": "/foo", "datadir": "/bar", "export": { - "type": "NSD", + "type": "nsd", "interval": 0, "serials": true, "status": "last run:03-05 15:25
last cp :09-20 12:59" diff --git a/lib/user.js b/lib/user.js index 051585e..5c4ce18 100644 --- a/lib/user.js +++ b/lib/user.js @@ -7,10 +7,7 @@ const group = require('./group') exports.id = Joi.number().integer().min(1).max(4294967295) -exports.username = Joi.string() - .min(3) - .max(50) - .pattern(new RegExp('^[a-zA-Z0-9 _.@-]+$', '')) +exports.username = Joi.string().min(3).max(50).pattern(new RegExp('^[a-zA-Z0-9 _.@-]+$', '')) exports.password = JoiPassword.string() .min(8) @@ -41,7 +38,7 @@ exports.GET_req = Joi.object({ }) exports.GET_res = Joi.object({ - user: exports.v3, + user: Joi.array().items(exports.v3), group: Joi.object({ id: group.id, name: group.name, diff --git a/lib/user.test.js b/lib/user.test.js index 693f602..39ce23a 100644 --- a/lib/user.test.js +++ b/lib/user.test.js @@ -38,16 +38,11 @@ describe('user', function () { }) it('rejects too long', () => { - const username = - 'abcdefghijklmopqrstuvwxyzabcdefghijklmopqrstuvwxyzabcdefghijklmopqrstuvwxyz' + const username = 'abcdefghijklmopqrstuvwxyzabcdefghijklmopqrstuvwxyzabcdefghijklmopqrstuvwxyz' const { error, value } = schema.username.validate(username) - assert.ok( - /length must be less than or equal to 50 characters long/.test( - error.message, - ), - ) + assert.ok(/length must be less than or equal to 50 characters long/.test(error.message)) assert.deepEqual(value, username) }) diff --git a/lib/zone.js b/lib/zone.js index 8795a03..c1bd6ee 100644 --- a/lib/zone.js +++ b/lib/zone.js @@ -4,18 +4,14 @@ const shared = require('./shared') exports.id = shared.uint32 -exports.zone = Joi.string() - .min(3) - .max(255) - .domain({ allowFullyQualified: true, tlds: false }) - .required() +exports.zone = Joi.string().min(3).max(255).domain({ allowFullyQualified: true, tlds: false }) exports.v3 = Joi.object({ id: exports.id, gid: shared.uint32.required(), - zone: exports.zone, + zone: exports.zone.required(), description: Joi.string().empty(''), @@ -37,7 +33,7 @@ exports.v3 = Joi.object({ last_modified: Joi.date(), - last_publish: Joi.date().allow('', null), + last_publish: Joi.date().allow('0000-00-00 00:00:00', '', null), deleted: Joi.boolean(), }) diff --git a/lib/zone.test.js b/lib/zone.test.js index e15828d..6307cd2 100644 --- a/lib/zone.test.js +++ b/lib/zone.test.js @@ -37,10 +37,7 @@ describe('zone', function () { const { error, value } = schema.validate(testCase) // if (error) console.error(error.message) - assert.strictEqual( - error.message, - '"zone" must contain a valid domain name', - ) + assert.strictEqual(error?.message, '"zone" must contain a valid domain name') assert.deepEqual(value, testCase) }) } diff --git a/lib/zone_record.js b/lib/zone_record.js index c65553f..905d1d6 100644 --- a/lib/zone_record.js +++ b/lib/zone_record.js @@ -20,14 +20,94 @@ exports.v3 = Joi.object({ ttl: shared.ttl.required(), type: Joi.string() - .valid('A', 'AAAA', 'PTR', 'MX', 'NS', 'CNAME', 'SRV') + .valid( + 'A', + 'AAAA', + 'CAA', + 'CERT', + 'CNAME', + 'DNAME', + 'DNSKEY', + 'DS', + 'HINFO', + 'HTTPS', + 'IPSECKEY', + 'KEY', + 'LOC', + 'MX', + 'NAPTR', + 'NS', + 'NSEC', + 'NSEC3', + 'NSEC3PARAM', + 'NXT', + 'OPENPGPKEY', + 'PTR', + 'RRSIG', + 'SIG', + 'SMIMEA', + 'SOA', + 'SPF', + 'SRV', + 'SSHFP', + 'SVCB', + 'TLSA', + 'TSIG', + 'TXT', + 'URI', + 'WKS', + ) .required(), - address: Joi.string() - .ip({ version: ['ipv4'], cidr: 'forbidden' }) - .min(7) - .max(15) - .required(), + address: Joi.string().min(2).max(39), + + cname: Joi.string(), + + data: Joi.string(), + + description: Joi.string().empty(''), + + dname: Joi.string(), + + exchange: Joi.string(), + + fingerprint: Joi.string(), + + flags: [Joi.number(), Joi.string().empty('')], + + gateway: Joi.string().empty(''), + + 'gateway type': Joi.string().empty(''), + + location: Joi.string().empty(''), + + order: shared.uint16, + + other: Joi.string().empty(''), + + port: shared.uint16, + + precedence: shared.uint8, + + preference: shared.uint16, + + priority: shared.uint16, + + publickey: Joi.string().empty(''), + + regexp: Joi.string().empty(''), + + replacement: Joi.string().empty(''), + + service: [Joi.number(), Joi.string().empty('')], + + tag: Joi.string(), + + target: Joi.string(), + + weight: shared.uint16, + + value: Joi.string(), deleted: Joi.boolean(), }) diff --git a/lib/zone_record.test.js b/lib/zone_record.test.js index 3a7a8c9..8b2081e 100644 --- a/lib/zone_record.test.js +++ b/lib/zone_record.test.js @@ -73,10 +73,7 @@ describe('zone_record', function () { const testCase = JSON.parse(JSON.stringify(testZR)) testCase.owner = owner const { error } = schema.validate(testCase) - assert.deepEqual( - error.message, - '"owner" must contain a valid domain name', - ) + assert.deepEqual(error.message, '"owner" must contain a valid domain name') }) } }) @@ -104,10 +101,7 @@ describe('zone_record', function () { const testCase = JSON.parse(JSON.stringify(testZR)) testCase.type = type const { error } = schema.validate(testCase) - assert.deepEqual( - error.message, - '"type" must be one of [A, AAAA, PTR, MX, NS, CNAME, SRV]', - ) + assert.ok(/must be one of/.test(error.message)) }) } }) diff --git a/package.json b/package.json index c6e75e4..234913a 100644 --- a/package.json +++ b/package.json @@ -1,24 +1,35 @@ { "name": "@nictool/validate", - "version": "0.8.2", + "version": "0.8.3", "description": "NicTool Object Validation", "files": [ "lib", "index.js", + "index.mjs", "CHANGELOG.md" ], "main": "index.js", + "exports": { + ".": { + "import": "./index.mjs", + "require": "./index.js", + "default": "./index.js" + }, + "./package.json": "./package.json", + "./lib/*": "./lib/*" + }, "directories": { "test": "test" }, "scripts": { "format:check": "npm run prettier; npm run lint", "format": "npm run prettier -- --write && npm run lint --fix", - "lint": "npx eslint **/*.js", - "lint:fix": "npm run lint --fix", + "lint": "npx eslint .", + "lint:fix": "npx eslint --fix .", "prettier": "npx prettier --ignore-path .gitignore --check .", "prettier:fix": "npx prettier --ignore-path .gitignore --write .", "test": "node --test", + "test:only": "node --test --test-only", "versions": "npx dependency-version-checker check", "versions:fix": "npx dependency-version-checker update", "watch": "node --test --watch" @@ -40,14 +51,19 @@ }, "homepage": "https://github.com/NicTool/validate#readme", "devDependencies": { - "@eslint/eslintrc": "^3.3.1", - "eslint": "^9.24.0", - "@eslint/js": "^10.0.0", - "eslint-config-prettier": "^10.1.1", - "globals": "^16.0.0" + "eslint": "^10.0.3", + "@eslint/js": "^10.0.1", + "eslint-config-prettier": "^10.1.8", + "globals": "^17.4.0" }, "dependencies": { - "joi": "^17.13.3", - "joi-password": "^4.2.0" + "joi": "^18.0.2", + "joi-password": "^4.3.0" + }, + "prettier": { + "semi": false, + "singleQuote": true, + "trailingComma": "all", + "printWidth": 100 } -} +} \ No newline at end of file