'use strict';
-const globals = require('globals');
-const js = require('@eslint/js');
-const node = require('eslint-plugin-n');
-const security = require('eslint-plugin-security');
-const sonarjs = require('eslint-plugin-sonarjs');
-const { FlatCompat } = require('@eslint/eslintrc');
-const compat = new FlatCompat();
+const squeepConfig = require('@squeep/eslint-config');
module.exports = [
- js.configs.recommended,
- ...compat.config(node.configs.recommended),
- security.configs.recommended,
- ...compat.config(sonarjs.configs.recommended),
- {
- files: [ '**/*.js' ],
- plugins: {
- node,
- security,
- sonarjs,
- },
- languageOptions: {
- ecmaVersion: 2023,
- sourceType: 'script',
- },
- rules: {
- 'array-element-newline': [
- 'error',
- 'consistent',
- ],
- 'arrow-parens': [
- 'error',
- 'always',
- ],
- 'arrow-spacing': [
- 'error',
- {
- 'after': true,
- 'before': true,
- },
- ],
- 'block-scoped-var': 'error',
- 'block-spacing': 'error',
- 'brace-style': 'error',
- 'callback-return': 'error',
- 'camelcase': 'error',
- 'class-methods-use-this': 'error',
- 'comma-dangle': [
- 'error',
- 'always-multiline',
- ],
- 'comma-spacing': [
- 'error',
- {
- 'after': true,
- 'before': false,
- },
- ],
- 'comma-style': [
- 'error',
- 'last',
- ],
- 'indent': [
- 'warn',
- 2,
- {
- 'SwitchCase': 1,
- },
- ],
- 'sonarjs/cognitive-complexity': 'warn',
- 'sonarjs/no-duplicate-string': 'warn',
- 'keyword-spacing': 'error',
- 'linebreak-style': [
- 'error',
- 'unix',
- ],
- 'no-unused-vars': [
- 'error', {
- 'varsIgnorePattern': '^_',
- },
- ],
- 'object-curly-spacing': [
- 'error',
- 'always',
- ],
- 'prefer-const': 'error',
- 'quotes': [
- 'error',
- 'single',
- ],
- 'semi': [
- 'error',
- 'always',
- ],
- 'strict': 'error',
- 'vars-on-top': 'error',
- },
- },
- {
- files: ['test/**'],
- languageOptions: {
- globals: {
- ...globals.mocha,
- },
- },
- rules: {
- "n/no-unpublished-require": "off",
- },
- },
+ ...squeepConfig,
];
"license": "ISC",
"dependencies": {
"@squeep/amqp-helper": "git+https://git.squeep.com/squeep-amqp-helper#v1.0.0",
- "@squeep/api-dingus": "^2.1.0",
- "@squeep/authentication-module": "git+https://git.squeep.com/squeep-authentication-module/#v1.4.0",
+ "@squeep/api-dingus": "^2",
+ "@squeep/authentication-module": "git+https://git.squeep.com/squeep-authentication-module/#v1.5.0",
"@squeep/chores": "git+https://git.squeep.com/squeep-chores/#v1.0.1",
- "@squeep/html-template-helper": "git+https://git.squeep.com/squeep-html-template-helper#v1.6.0",
- "@squeep/indieauth-helper": "^1.4.1",
- "@squeep/logger-json-console": "^3.0.2",
- "@squeep/mystery-box": "^2.0.2",
- "@squeep/resource-authentication-module": "git+https://git.squeep.com/squeep-resource-authentication-module#v1.0.1",
- "@squeep/roman": "^1.0.1",
- "@squeep/web-linking": "^1.0.8",
- "better-sqlite3": "^9.4.5",
- "pg-promise": "^11.6.0",
- "uuid": "^9.0.1"
+ "@squeep/html-template-helper": "git+https://git.squeep.com/squeep-html-template-helper#v1.6.1",
+ "@squeep/indieauth-helper": "^1.4",
+ "@squeep/logger-json-console": "^3",
+ "@squeep/mystery-box": "^2",
+ "@squeep/roman": "^1",
+ "@squeep/web-linking": "^1",
+ "better-sqlite3": "^9",
+ "pg-promise": "^11",
+ "uuid": "^9"
},
"devDependencies": {
+ "@squeep/eslint-config": "^1",
"@squeep/test-helper": "git+https://git.squeep.com/squeep-test-helper#v1.0.1",
- "eslint": "^8.57.0",
- "eslint-plugin-n": "^16.6.2",
- "eslint-plugin-promise": "^6.1.1",
- "eslint-plugin-security": "^2.1.1",
- "eslint-plugin-sonarjs": "^0.25.1",
- "html-validate": "^8.18.1",
- "mocha": "^10.4.0",
- "mocha-steps": "^1.3.0",
- "nyc": "^15.1.0",
- "pre-commit": "^1.2.2",
- "sinon": "^17.0.1"
+ "eslint": "^9",
+ "html-validate": "^8",
+ "mocha": "^10",
+ "mocha-steps": "^1",
+ "nyc": "^15",
+ "pre-commit": "^1",
+ "sinon": "^17"
},
"engines": {
- "node": "^14 >=14.18 || >=15.7"
- }
- },
- "node_modules/@aashutoshrathi/word-wrap": {
- "version": "1.2.6",
- "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz",
- "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
+ "node": ">=16.9"
}
},
"node_modules/@acuminous/bitsyntax": {
}
},
"node_modules/@babel/core": {
- "version": "7.24.4",
- "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.4.tgz",
- "integrity": "sha512-MBVlMXP+kkl5394RBLSxxk/iLTeVGuXTV3cIDXavPpMMqnSnt6apKgan/U8O3USWZCWZT/TbgfEpKa4uMgN4Dg==",
+ "version": "7.24.5",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.5.tgz",
+ "integrity": "sha512-tVQRucExLQ02Boi4vdPp49svNGcfL2GhdTCT9aldhXgCJVAI21EtRfBettiuLUwce/7r6bFdgs6JFkcdTiFttA==",
"dev": true,
"dependencies": {
"@ampproject/remapping": "^2.2.0",
"@babel/code-frame": "^7.24.2",
- "@babel/generator": "^7.24.4",
+ "@babel/generator": "^7.24.5",
"@babel/helper-compilation-targets": "^7.23.6",
- "@babel/helper-module-transforms": "^7.23.3",
- "@babel/helpers": "^7.24.4",
- "@babel/parser": "^7.24.4",
+ "@babel/helper-module-transforms": "^7.24.5",
+ "@babel/helpers": "^7.24.5",
+ "@babel/parser": "^7.24.5",
"@babel/template": "^7.24.0",
- "@babel/traverse": "^7.24.1",
- "@babel/types": "^7.24.0",
+ "@babel/traverse": "^7.24.5",
+ "@babel/types": "^7.24.5",
"convert-source-map": "^2.0.0",
"debug": "^4.1.0",
"gensync": "^1.0.0-beta.2",
}
},
"node_modules/@babel/generator": {
- "version": "7.24.4",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.4.tgz",
- "integrity": "sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==",
+ "version": "7.24.5",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.5.tgz",
+ "integrity": "sha512-x32i4hEXvr+iI0NEoEfDKzlemF8AmtOP8CcrRaEcpzysWuoEb1KknpcvMsHKPONoKZiDuItklgWhB18xEhr9PA==",
"dev": true,
"dependencies": {
- "@babel/types": "^7.24.0",
+ "@babel/types": "^7.24.5",
"@jridgewell/gen-mapping": "^0.3.5",
"@jridgewell/trace-mapping": "^0.3.25",
"jsesc": "^2.5.1"
}
},
"node_modules/@babel/helper-module-transforms": {
- "version": "7.23.3",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz",
- "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==",
+ "version": "7.24.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.5.tgz",
+ "integrity": "sha512-9GxeY8c2d2mdQUP1Dye0ks3VDyIMS98kt/llQ2nUId8IsWqTF0l1LkSX0/uP7l7MCDrzXS009Hyhe2gzTiGW8A==",
"dev": true,
"dependencies": {
"@babel/helper-environment-visitor": "^7.22.20",
- "@babel/helper-module-imports": "^7.22.15",
- "@babel/helper-simple-access": "^7.22.5",
- "@babel/helper-split-export-declaration": "^7.22.6",
- "@babel/helper-validator-identifier": "^7.22.20"
+ "@babel/helper-module-imports": "^7.24.3",
+ "@babel/helper-simple-access": "^7.24.5",
+ "@babel/helper-split-export-declaration": "^7.24.5",
+ "@babel/helper-validator-identifier": "^7.24.5"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-simple-access": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz",
- "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==",
+ "version": "7.24.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.5.tgz",
+ "integrity": "sha512-uH3Hmf5q5n7n8mz7arjUlDOCbttY/DW4DYhE6FUsjKJ/oYC1kQQUvwEQWxRwUpX9qQKRXeqLwWxrqilMrf32sQ==",
"dev": true,
"dependencies": {
- "@babel/types": "^7.22.5"
+ "@babel/types": "^7.24.5"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-split-export-declaration": {
- "version": "7.22.6",
- "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
- "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
+ "version": "7.24.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.5.tgz",
+ "integrity": "sha512-5CHncttXohrHk8GWOFCcCl4oRD9fKosWlIRgWm4ql9VYioKm52Mk2xsmoohvm7f3JoiLSM5ZgJuRaf5QZZYd3Q==",
"dev": true,
"dependencies": {
- "@babel/types": "^7.22.5"
+ "@babel/types": "^7.24.5"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-validator-identifier": {
- "version": "7.22.20",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
- "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
+ "version": "7.24.5",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.5.tgz",
+ "integrity": "sha512-3q93SSKX2TWCG30M2G2kwaKeTYgEUp5Snjuj8qm729SObL6nbtUldAi37qbxkD5gg3xnBio+f9nqpSepGZMvxA==",
"dev": true,
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helpers": {
- "version": "7.24.4",
- "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.4.tgz",
- "integrity": "sha512-FewdlZbSiwaVGlgT1DPANDuCHaDMiOo+D/IDYRFYjHOuv66xMSJ7fQwwODwRNAPkADIO/z1EoF/l2BCWlWABDw==",
+ "version": "7.24.5",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.5.tgz",
+ "integrity": "sha512-CiQmBMMpMQHwM5m01YnrM6imUG1ebgYJ+fAIW4FZe6m4qHTPaRHti+R8cggAwkdz4oXhtO4/K9JWlh+8hIfR2Q==",
"dev": true,
"dependencies": {
"@babel/template": "^7.24.0",
- "@babel/traverse": "^7.24.1",
- "@babel/types": "^7.24.0"
+ "@babel/traverse": "^7.24.5",
+ "@babel/types": "^7.24.5"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/highlight": {
- "version": "7.24.2",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz",
- "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==",
+ "version": "7.24.5",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.5.tgz",
+ "integrity": "sha512-8lLmua6AVh/8SLJRRVD6V8p73Hir9w5mJrhE+IPpILG31KKlI9iz5zmBYKcWPS59qSfgP9RaSBQSHHE81WKuEw==",
"dev": true,
"dependencies": {
- "@babel/helper-validator-identifier": "^7.22.20",
+ "@babel/helper-validator-identifier": "^7.24.5",
"chalk": "^2.4.2",
"js-tokens": "^4.0.0",
"picocolors": "^1.0.0"
}
},
"node_modules/@babel/parser": {
- "version": "7.24.4",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.4.tgz",
- "integrity": "sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==",
+ "version": "7.24.5",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.5.tgz",
+ "integrity": "sha512-EOv5IK8arwh3LI47dz1b0tKUb/1uhHAnHJOrjgtQMIpu1uXd9mlFrJg9IUgGUgZ41Ch0K8REPTYpO7B76b4vJg==",
"dev": true,
"bin": {
"parser": "bin/babel-parser.js"
}
},
"node_modules/@babel/traverse": {
- "version": "7.24.1",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz",
- "integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==",
+ "version": "7.24.5",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.5.tgz",
+ "integrity": "sha512-7aaBLeDQ4zYcUFDUD41lJc1fG8+5IU9DaNSJAgal866FGvmD5EbWQgnEC6kO1gGLsX0esNkfnJSndbTXA3r7UA==",
"dev": true,
"dependencies": {
- "@babel/code-frame": "^7.24.1",
- "@babel/generator": "^7.24.1",
+ "@babel/code-frame": "^7.24.2",
+ "@babel/generator": "^7.24.5",
"@babel/helper-environment-visitor": "^7.22.20",
"@babel/helper-function-name": "^7.23.0",
"@babel/helper-hoist-variables": "^7.22.5",
- "@babel/helper-split-export-declaration": "^7.22.6",
- "@babel/parser": "^7.24.1",
- "@babel/types": "^7.24.0",
+ "@babel/helper-split-export-declaration": "^7.24.5",
+ "@babel/parser": "^7.24.5",
+ "@babel/types": "^7.24.5",
"debug": "^4.3.1",
"globals": "^11.1.0"
},
}
},
"node_modules/@babel/types": {
- "version": "7.24.0",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz",
- "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==",
+ "version": "7.24.5",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.5.tgz",
+ "integrity": "sha512-6mQNsaLeXTw0nxYUYu+NSa4Hx4BlF1x1x8/PMFbiR+GBSr+2DkECc69b8hgy2frEodNcvPffeH8YfWd3LI6jhQ==",
"dev": true,
"dependencies": {
- "@babel/helper-string-parser": "^7.23.4",
- "@babel/helper-validator-identifier": "^7.22.20",
+ "@babel/helper-string-parser": "^7.24.1",
+ "@babel/helper-validator-identifier": "^7.24.5",
"to-fast-properties": "^2.0.0"
},
"engines": {
"node": ">=6.9.0"
}
},
+ "node_modules/@es-joy/jsdoccomment": {
+ "version": "0.43.0",
+ "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.43.0.tgz",
+ "integrity": "sha512-Q1CnsQrytI3TlCB1IVWXWeqUIPGVEKGaE7IbVdt13Nq/3i0JESAkQQERrfiQkmlpijl+++qyqPgaS31Bvc1jRQ==",
+ "dev": true,
+ "dependencies": {
+ "@types/eslint": "^8.56.5",
+ "@types/estree": "^1.0.5",
+ "@typescript-eslint/types": "^7.2.0",
+ "comment-parser": "1.4.1",
+ "esquery": "^1.5.0",
+ "jsdoc-type-pratt-parser": "~4.0.0"
+ },
+ "engines": {
+ "node": ">=16"
+ }
+ },
"node_modules/@eslint-community/eslint-utils": {
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz",
"eslint": "^6.0.0 || ^7.0.0 || >=8.0.0"
}
},
+ "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+ "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+ "dev": true,
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
"node_modules/@eslint-community/regexpp": {
"version": "4.10.0",
"resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz",
}
},
"node_modules/@eslint/eslintrc": {
- "version": "2.1.4",
- "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz",
- "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==",
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.0.2.tgz",
+ "integrity": "sha512-wV19ZEGEMAC1eHgrS7UQPqsdEiCIbTKTasEfcXAigzoXICcqZSjBZEHlZwNVvKg6UBCjSlos84XiLqsRJnIcIg==",
"dev": true,
"dependencies": {
"ajv": "^6.12.4",
"debug": "^4.3.2",
- "espree": "^9.6.0",
- "globals": "^13.19.0",
+ "espree": "^10.0.1",
+ "globals": "^14.0.0",
"ignore": "^5.2.0",
"import-fresh": "^3.2.1",
"js-yaml": "^4.1.0",
"strip-json-comments": "^3.1.1"
},
"engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
+ "node_modules/@eslint/eslintrc/node_modules/globals": {
+ "version": "14.0.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz",
+ "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/@eslint/js": {
- "version": "8.57.0",
- "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz",
- "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==",
+ "version": "9.2.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.2.0.tgz",
+ "integrity": "sha512-ESiIudvhoYni+MdsI8oD7skpprZ89qKocwRM2KEvhhBJ9nl5MRh7BXU5GTod7Mdygq+AUl+QzId6iWJKR/wABA==",
"dev": true,
"engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
"node_modules/@html-validate/stylish": {
}
},
"node_modules/@humanwhocodes/config-array": {
- "version": "0.11.14",
- "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
- "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==",
+ "version": "0.13.0",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz",
+ "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==",
"dev": true,
"dependencies": {
- "@humanwhocodes/object-schema": "^2.0.2",
+ "@humanwhocodes/object-schema": "^2.0.3",
"debug": "^4.3.1",
"minimatch": "^3.0.5"
},
"integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
"dev": true
},
+ "node_modules/@humanwhocodes/retry": {
+ "version": "0.2.4",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.2.4.tgz",
+ "integrity": "sha512-Ttl/jHpxfS3st5sxwICYfk4pOH0WrLI1SpW283GgQL7sCWU7EHIOhX4b4fkIxr3tkfzwg8+FNojtzsIEE7Ecgg==",
+ "dev": true,
+ "engines": {
+ "node": ">=18.18"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/nzakas"
+ }
+ },
"node_modules/@isaacs/cliui": {
"version": "8.0.2",
"resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz",
"node-pre-gyp": "bin/node-pre-gyp"
}
},
+ "node_modules/@mapbox/node-pre-gyp/node_modules/detect-libc": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
+ "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
+ "optional": true,
+ "bin": {
+ "detect-libc": "bin/detect-libc.js"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
"node_modules/@nodelib/fs.scandir": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz",
}
},
"node_modules/@sindresorhus/is": {
- "version": "5.6.0",
- "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-5.6.0.tgz",
- "integrity": "sha512-TV7t8GKYaJWsn00tFDqBw8+Uqmr8A0fRU1tvTQhyZzGv0sJCGRQL3JGMI3ucuKo3XIZdUP+Lx7/gh2t3lewy7g==",
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-6.3.0.tgz",
+ "integrity": "sha512-bOSPck7aIJjASXIg1qvXSIjXhVBpIEKdl2Wxg4pVqoTRPL8wWExKBrnGIh6CEnhkFQHfc36k7APhO3uXV4g5xg==",
"engines": {
- "node": ">=14.16"
+ "node": ">=16"
},
"funding": {
"url": "https://github.com/sindresorhus/is?sponsor=1"
"node_modules/@squeep/amqp-helper": {
"version": "1.0.0",
"resolved": "git+https://git.squeep.com/squeep-amqp-helper#174280d3f44ba13dac0b26d42d968189a4f4fa93",
- "license": "ISC",
"dependencies": {
"amqplib": "^0.10.3"
},
}
},
"node_modules/@squeep/api-dingus": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@squeep/api-dingus/-/api-dingus-2.1.0.tgz",
- "integrity": "sha512-SCLPHbSHTz5en5XO8IMyTLr6R+0jIDpL3dSxS3e4XLC3521LzorNywGteMdnZKhwXwahjf4XngxNzmO0kFp6Kw==",
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/@squeep/api-dingus/-/api-dingus-2.1.1.tgz",
+ "integrity": "sha512-iae4nc0mZ2sBR0iHIOu/loqaXSFmsxGdFOVjE0wfzGY4QzvHqLeVgM8VnAczFtCOM8bOqe8RtcvVkN7pDM7TWw==",
"dependencies": {
- "@squeep/log-helper": "^1.0.0",
+ "@squeep/log-helper": "^1",
"mime-db": "^1.52.0",
"uuid": "^9.0.1"
},
"engines": {
- "node": ">=14"
+ "node": ">=14.13.1"
}
},
"node_modules/@squeep/authentication-module": {
- "version": "1.4.0",
- "resolved": "git+https://git.squeep.com/squeep-authentication-module/#9c604adfcde56e35767e3eba70890308ec2d3110",
- "license": "ISC",
+ "version": "1.5.0",
+ "resolved": "git+https://git.squeep.com/squeep-authentication-module/#5ea2ffe571a74618eef073c58c5fef06e1cf06a7",
"dependencies": {
- "@squeep/api-dingus": "^2.1.0",
- "@squeep/html-template-helper": "git+https://git.squeep.com/squeep-html-template-helper#v1.6.0",
- "@squeep/indieauth-helper": "^1.4.1",
- "@squeep/mystery-box": "^2.0.2",
- "@squeep/totp": "^1.1.4"
+ "@squeep/api-dingus": "^2",
+ "@squeep/html-template-helper": "git+https://git.squeep.com/squeep-html-template-helper#v1.6.1",
+ "@squeep/indieauth-helper": "^1",
+ "@squeep/mystery-box": "^2",
+ "@squeep/totp": "^1",
+ "uuid": "^9"
},
"engines": {
- "node": "^18"
+ "node": ">=18"
},
"optionalDependencies": {
"argon2": "^0.40.1",
"node_modules/@squeep/chores": {
"version": "1.0.1",
"resolved": "git+https://git.squeep.com/squeep-chores/#a77e8814cbba0ad751e249850d1f7b144da6446b",
- "license": "ISC",
"dependencies": {
"@squeep/log-helper": "^1.0.0"
}
},
+ "node_modules/@squeep/eslint-config": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/@squeep/eslint-config/-/eslint-config-1.0.0.tgz",
+ "integrity": "sha512-kGuzqWqQekblecm4egJvY/2Wa0wxEDUlFPxwZ4gu8Eglmf9m/2rs2rr85DvtTxt43fvNcZ7IDuspTOv+Ei9BSg==",
+ "dev": true,
+ "dependencies": {
+ "@eslint/js": "^9",
+ "eslint-plugin-jsdoc": "^48",
+ "eslint-plugin-n": "^17",
+ "eslint-plugin-security": "^3",
+ "eslint-plugin-sonarjs": "^1",
+ "globals": "^15"
+ },
+ "engines": {
+ "node": ">=20"
+ },
+ "peerDependencies": {
+ "eslint": ">= 9"
+ }
+ },
"node_modules/@squeep/html-template-helper": {
- "version": "1.6.0",
- "resolved": "git+https://git.squeep.com/squeep-html-template-helper#2d0ba72a2ea35f45c1ab1ac81fce3d0cbe7db419",
- "license": "ISC",
+ "version": "1.6.1",
+ "resolved": "git+https://git.squeep.com/squeep-html-template-helper#93d1b030d6b3c6ea93c36a46f4940181a1acaca0",
"dependencies": {
- "@squeep/lazy-property": "^1.1.2"
+ "@squeep/lazy-property": "^1"
},
"engines": {
- "node": ">=14"
+ "node": ">=14.13.1"
}
},
"node_modules/@squeep/indieauth-helper": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/@squeep/indieauth-helper/-/indieauth-helper-1.4.1.tgz",
- "integrity": "sha512-x/yqrjrbp0vTdvIW8e9CKsr5+YwmDp/x4nK4H5LInt07rk4nthxv7e7qIgy97OFtvFnoNee+N9gyi3TzIIiGoQ==",
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/@squeep/indieauth-helper/-/indieauth-helper-1.4.2.tgz",
+ "integrity": "sha512-PKOr2Mx8e1RwdJ6ab22gWAlbzktDNORIt4xzGZ0iXbvbTdqNLdpAKBHi8Il0vYgZU0HAO3utNqMX5grSfKaDrw==",
"dependencies": {
- "@squeep/log-helper": "^1.0.0",
- "@squeep/web-linking": "^1.0.8",
- "got": "^13.0.0",
- "iconv": "^3.0.1",
- "ip-address": "^9.0.5",
- "microformats-parser": "^2.0.2"
+ "@squeep/log-helper": "^1",
+ "@squeep/web-linking": "^1",
+ "got": "^14",
+ "iconv": "^3",
+ "ip-address": "^9",
+ "microformats-parser": "^2"
},
"engines": {
- "node": "^14 >=14.18 || >=15.7"
+ "node": ">=20"
}
},
"node_modules/@squeep/lazy-property": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@squeep/lazy-property/-/lazy-property-1.1.2.tgz",
- "integrity": "sha512-wRdR4IOqWXoDMArx0HPo5MtM2Wk5wemAULbZ6PabVw1ylSQekkzKfoAUuupxsKuzjcRPjZvbpGDv+i04hBMnQw==",
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/@squeep/lazy-property/-/lazy-property-1.1.3.tgz",
+ "integrity": "sha512-GzQ/bSE6MZ6YeRjLMKK18I0ajvOnhrgacZs6EpLERXPPlQZWkOcmjCcjyqY71lqd5MzsPbSwzsj6Uonpqea6nw==",
"engines": {
"node": ">=14"
}
},
"node_modules/@squeep/log-helper": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/@squeep/log-helper/-/log-helper-1.0.0.tgz",
- "integrity": "sha512-i61ECZLWQI2rhkXj9pDzH1Md5ICghL9zvh5QFVo0BTayuSrdS9SWkJ6gV1qWki/Xz6SuE0y0y145NyHlvOuVaw==",
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/@squeep/log-helper/-/log-helper-1.0.1.tgz",
+ "integrity": "sha512-T+QTxSNoZ9wzyyK1jS8ac9puOikRv14MfkE3uXSBOp70T8eEqCjSwfE+VHtOb0riU4FhYpDsBNSMIskK4UDRZA==",
"engines": {
- "node": ">=14"
+ "node": ">=14.13.1"
}
},
"node_modules/@squeep/logger-json-console": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/@squeep/logger-json-console/-/logger-json-console-3.0.2.tgz",
- "integrity": "sha512-Qz2QMwhyyRB5sZFB/S6eUt7TnmKCPB6oUqa8SW2gGGOLTcvf+0nbFgqqzlFwtUEwF3KwCmMnOt7lwq5PLrm24Q==",
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/@squeep/logger-json-console/-/logger-json-console-3.0.3.tgz",
+ "integrity": "sha512-W8BDrV0fHKABbFXOedJKd8hmIgKOtTCM0lLGmaGsDfV8+OAdEg4kdS0F8GI7PLF9mOzp/z0uRv+CCyv5tS81kA==",
"engines": {
"node": ">=17"
}
},
"node_modules/@squeep/mystery-box": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/@squeep/mystery-box/-/mystery-box-2.0.2.tgz",
- "integrity": "sha512-YoVx9F/ZFOdgPrt5ey3Vg+ttK4nsnfeSjzVDBOCB1L5q2H1V2wZ4DV0/l7mkqPgHHojGeJqncGs/KhB6Lu916g==",
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/@squeep/mystery-box/-/mystery-box-2.0.3.tgz",
+ "integrity": "sha512-OFPVVyYrxZU/8iwJGBRpyh+z9AyEqryWyh8p45LtaHw62hwOb8k2J8An4jFmYU0fiMRR+b3xR94qt0/V+ansyA==",
"engines": {
"node": "^14 >=14.18.0 || >=15.7.0"
}
},
- "node_modules/@squeep/resource-authentication-module": {
- "version": "1.0.1",
- "resolved": "git+https://git.squeep.com/squeep-resource-authentication-module#0dce6b122b90dc9d2fd3b7191cdef4d41e256ae3",
- "license": "ISC",
- "dependencies": {
- "@squeep/api-dingus": "v2.0.0",
- "uuid": "^9.0.0"
- },
- "engines": {
- "node": "^14 >=14.18 || >=15.7"
- }
- },
- "node_modules/@squeep/resource-authentication-module/node_modules/@squeep/api-dingus": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/@squeep/api-dingus/-/api-dingus-2.0.0.tgz",
- "integrity": "sha512-HKz/yB1KNmEcHB92KIvrNvwMph5fSdJBrxKSgERYfyQkLFl2vSwDV+IlFvi68DYmMBP3lWKzQcTXWBMYlW3c0g==",
- "dependencies": {
- "mime-db": "^1.52.0",
- "uuid": "^9.0.0"
- },
- "engines": {
- "node": ">=14"
- }
- },
"node_modules/@squeep/roman": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@squeep/roman/-/roman-1.0.1.tgz",
"version": "1.0.1",
"resolved": "git+https://git.squeep.com/squeep-test-helper#cc0f69b40de9ae3342f1b7a1784d37769e7f1e84",
"dev": true,
- "license": "ISC",
"dependencies": {
"eslint": "^8.53.0",
"eslint-plugin-node": "^11.1.0",
"sinon": "^17.0.1"
}
},
+ "node_modules/@squeep/test-helper/node_modules/@eslint/eslintrc": {
+ "version": "2.1.4",
+ "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz",
+ "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==",
+ "dev": true,
+ "dependencies": {
+ "ajv": "^6.12.4",
+ "debug": "^4.3.2",
+ "espree": "^9.6.0",
+ "globals": "^13.19.0",
+ "ignore": "^5.2.0",
+ "import-fresh": "^3.2.1",
+ "js-yaml": "^4.1.0",
+ "minimatch": "^3.1.2",
+ "strip-json-comments": "^3.1.1"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@squeep/test-helper/node_modules/@eslint/js": {
+ "version": "8.57.0",
+ "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz",
+ "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==",
+ "dev": true,
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ }
+ },
+ "node_modules/@squeep/test-helper/node_modules/@humanwhocodes/config-array": {
+ "version": "0.11.14",
+ "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
+ "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==",
+ "dev": true,
+ "dependencies": {
+ "@humanwhocodes/object-schema": "^2.0.2",
+ "debug": "^4.3.1",
+ "minimatch": "^3.0.5"
+ },
+ "engines": {
+ "node": ">=10.10.0"
+ }
+ },
+ "node_modules/@squeep/test-helper/node_modules/eslint": {
+ "version": "8.57.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz",
+ "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==",
+ "dev": true,
+ "dependencies": {
+ "@eslint-community/eslint-utils": "^4.2.0",
+ "@eslint-community/regexpp": "^4.6.1",
+ "@eslint/eslintrc": "^2.1.4",
+ "@eslint/js": "8.57.0",
+ "@humanwhocodes/config-array": "^0.11.14",
+ "@humanwhocodes/module-importer": "^1.0.1",
+ "@nodelib/fs.walk": "^1.2.8",
+ "@ungap/structured-clone": "^1.2.0",
+ "ajv": "^6.12.4",
+ "chalk": "^4.0.0",
+ "cross-spawn": "^7.0.2",
+ "debug": "^4.3.2",
+ "doctrine": "^3.0.0",
+ "escape-string-regexp": "^4.0.0",
+ "eslint-scope": "^7.2.2",
+ "eslint-visitor-keys": "^3.4.3",
+ "espree": "^9.6.1",
+ "esquery": "^1.4.2",
+ "esutils": "^2.0.2",
+ "fast-deep-equal": "^3.1.3",
+ "file-entry-cache": "^6.0.1",
+ "find-up": "^5.0.0",
+ "glob-parent": "^6.0.2",
+ "globals": "^13.19.0",
+ "graphemer": "^1.4.0",
+ "ignore": "^5.2.0",
+ "imurmurhash": "^0.1.4",
+ "is-glob": "^4.0.0",
+ "is-path-inside": "^3.0.3",
+ "js-yaml": "^4.1.0",
+ "json-stable-stringify-without-jsonify": "^1.0.1",
+ "levn": "^0.4.1",
+ "lodash.merge": "^4.6.2",
+ "minimatch": "^3.1.2",
+ "natural-compare": "^1.4.0",
+ "optionator": "^0.9.3",
+ "strip-ansi": "^6.0.1",
+ "text-table": "^0.2.0"
+ },
+ "bin": {
+ "eslint": "bin/eslint.js"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
"node_modules/@squeep/test-helper/node_modules/eslint-plugin-security": {
"version": "1.7.1",
"resolved": "https://registry.npmjs.org/eslint-plugin-security/-/eslint-plugin-security-1.7.1.tgz",
"eslint": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"
}
},
+ "node_modules/@squeep/test-helper/node_modules/eslint-scope": {
+ "version": "7.2.2",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
+ "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
+ "dev": true,
+ "dependencies": {
+ "esrecurse": "^4.3.0",
+ "estraverse": "^5.2.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@squeep/test-helper/node_modules/eslint-visitor-keys": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
+ "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+ "dev": true,
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@squeep/test-helper/node_modules/espree": {
+ "version": "9.6.1",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
+ "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
+ "dev": true,
+ "dependencies": {
+ "acorn": "^8.9.0",
+ "acorn-jsx": "^5.3.2",
+ "eslint-visitor-keys": "^3.4.1"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://opencollective.com/eslint"
+ }
+ },
+ "node_modules/@squeep/test-helper/node_modules/file-entry-cache": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
+ "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
+ "dev": true,
+ "dependencies": {
+ "flat-cache": "^3.0.4"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ }
+ },
+ "node_modules/@squeep/test-helper/node_modules/flat-cache": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz",
+ "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==",
+ "dev": true,
+ "dependencies": {
+ "flatted": "^3.2.9",
+ "keyv": "^4.5.3",
+ "rimraf": "^3.0.2"
+ },
+ "engines": {
+ "node": "^10.12.0 || >=12.0.0"
+ }
+ },
+ "node_modules/@squeep/test-helper/node_modules/globals": {
+ "version": "13.24.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
+ "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
+ "dev": true,
+ "dependencies": {
+ "type-fest": "^0.20.2"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/@squeep/test-helper/node_modules/type-fest": {
+ "version": "0.20.2",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
+ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/@squeep/totp": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/@squeep/totp/-/totp-1.1.4.tgz",
- "integrity": "sha512-cMoicNB5xIDMdcOtTfkzWZ0eQCepatTsFoWXtQ8Ja4FfvAA3ZWwIMfKV4K7zbx1MjYGF/Ufikxa6CaPS6yd5mw==",
+ "version": "1.1.5",
+ "resolved": "https://registry.npmjs.org/@squeep/totp/-/totp-1.1.5.tgz",
+ "integrity": "sha512-keqggH2NrHs8hqzyov31zIA4XTLUxwXBn+VfUFlCdzZY2omoWbgm4742Ht8j3W48FLtIX1q4Zrm1ncObi9RfMA==",
"dependencies": {
"base32.js": "^0.1.0",
"qrcode-svg": "^1.1.0"
}
},
"node_modules/@squeep/web-linking": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/@squeep/web-linking/-/web-linking-1.0.8.tgz",
- "integrity": "sha512-+0nCl/IXY8RHBWNr5mJMkU+U62in9xYDigIMkMKBp0bWnah/gjXv3NxAa4+LkxCMZU0STt/uBjuVM7SpvuQHSg==",
+ "version": "1.0.9",
+ "resolved": "https://registry.npmjs.org/@squeep/web-linking/-/web-linking-1.0.9.tgz",
+ "integrity": "sha512-NHI2sWiL7PduRBYhM54MqG40xnI867uRyjKDWBCudsel4DmLy3Jh1CIvYORbPt8ScvvL0PV7kCsmowPdufAOkA==",
"engines": {
"node": ">=14.0"
}
"node": ">=14.16"
}
},
+ "node_modules/@types/eslint": {
+ "version": "8.56.10",
+ "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz",
+ "integrity": "sha512-Shavhk87gCtY2fhXDctcfS3e6FdxWkCx1iUZ9eEUbh7rTqlZT0/IzOkCOVt0fCjcFuZ9FPYfuezTBImfHCDBGQ==",
+ "dev": true,
+ "dependencies": {
+ "@types/estree": "*",
+ "@types/json-schema": "*"
+ }
+ },
+ "node_modules/@types/estree": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
+ "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
+ "dev": true
+ },
"node_modules/@types/http-cache-semantics": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/@types/http-cache-semantics/-/http-cache-semantics-4.0.4.tgz",
"integrity": "sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA=="
},
+ "node_modules/@types/json-schema": {
+ "version": "7.0.15",
+ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz",
+ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==",
+ "dev": true
+ },
+ "node_modules/@typescript-eslint/types": {
+ "version": "7.8.0",
+ "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.8.0.tgz",
+ "integrity": "sha512-wf0peJ+ZGlcH+2ZS23aJbOv+ztjeeP8uQ9GgwMJGVLx/Nj9CJt17GWgWWoSmoRVKAX2X+7fzEnAjxdvK2gqCLw==",
+ "dev": true,
+ "engines": {
+ "node": "^18.18.0 || >=20.0.0"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/typescript-eslint"
+ }
+ },
"node_modules/@ungap/structured-clone": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz",
}
},
"node_modules/amqplib": {
- "version": "0.10.3",
- "resolved": "https://registry.npmjs.org/amqplib/-/amqplib-0.10.3.tgz",
- "integrity": "sha512-UHmuSa7n8vVW/a5HGh2nFPqAEr8+cD4dEZ6u9GjP91nHfr1a54RyAKyra7Sb5NH7NBKOUlyQSMXIp0qAixKexw==",
+ "version": "0.10.4",
+ "resolved": "https://registry.npmjs.org/amqplib/-/amqplib-0.10.4.tgz",
+ "integrity": "sha512-DMZ4eCEjAVdX1II2TfIUpJhfKAuoCeDIo/YyETbfAqehHTXxxs7WOOd+N1Xxr4cKhx12y23zk8/os98FxlZHrw==",
"dependencies": {
"@acuminous/bitsyntax": "^0.1.2",
"buffer-more-ints": "~1.0.0",
"integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==",
"dev": true
},
+ "node_modules/are-docs-informative": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz",
+ "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==",
+ "dev": true,
+ "engines": {
+ "node": ">=14"
+ }
+ },
"node_modules/are-we-there-yet": {
"version": "1.1.7",
"resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz",
]
},
"node_modules/better-sqlite3": {
- "version": "9.4.5",
- "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-9.4.5.tgz",
- "integrity": "sha512-uFVyoyZR9BNcjSca+cp3MWCv6upAv+tbMC4SWM51NIMhoQOm4tjIkyxFO/ZsYdGAF61WJBgdzyJcz4OokJi0gQ==",
+ "version": "9.6.0",
+ "resolved": "https://registry.npmjs.org/better-sqlite3/-/better-sqlite3-9.6.0.tgz",
+ "integrity": "sha512-yR5HATnqeYNVnkaUTf4bOP2dJSnyhP4puJN/QPRyx4YkBEEUxib422n2XzPqDEHjQQqazoYoADdAm5vE15+dAQ==",
"hasInstallScript": true,
"dependencies": {
"bindings": "^1.5.0",
"dev": true,
"engines": {
"node": ">=6"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/builtins": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz",
- "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==",
- "dev": true,
- "dependencies": {
- "semver": "^7.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/cacheable-lookup": {
"node": ">=14.16"
}
},
+ "node_modules/cacheable-request/node_modules/get-stream": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
+ "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/caching-transform": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/caching-transform/-/caching-transform-4.0.0.tgz",
}
},
"node_modules/caniuse-lite": {
- "version": "1.0.30001606",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001606.tgz",
- "integrity": "sha512-LPbwnW4vfpJId225pwjZJOgX1m9sGfbw/RKJvw/t0QhYOOaTXHvkjVGFGPpvwEzufrjvTlsULnVTxdy4/6cqkg==",
+ "version": "1.0.30001617",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001617.tgz",
+ "integrity": "sha512-mLyjzNI9I+Pix8zwcrpxEbGlfqOkF9kM3ptzmKNw5tizSyYwMe+nGLTqMK9cO+0E+Bh6TsBxNAaHWEM8xwSsmA==",
"dev": true,
"funding": [
{
}
},
"node_modules/chownr": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
- "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
- "optional": true,
- "engines": {
- "node": ">=10"
- }
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
+ "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="
},
"node_modules/clean-stack": {
"version": "2.2.0",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"devOptional": true
},
+ "node_modules/comment-parser": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz",
+ "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 12.0.0"
+ }
+ },
"node_modules/commondir": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
"optional": true
},
"node_modules/detect-libc": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
- "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
- "optional": true,
- "bin": {
- "detect-libc": "bin/detect-libc.js"
- },
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz",
+ "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==",
"engines": {
- "node": ">=0.10"
+ "node": ">=8"
}
},
"node_modules/diff": {
"dev": true
},
"node_modules/electron-to-chromium": {
- "version": "1.4.729",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.729.tgz",
- "integrity": "sha512-bx7+5Saea/qu14kmPTDHQxkp2UnziG3iajUQu3BxFvCOnpAJdDbMV4rSl+EqFDkkpNNVUFlR1kDfpL59xfy1HA==",
+ "version": "1.4.763",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.763.tgz",
+ "integrity": "sha512-k4J8NrtJ9QrvHLRo8Q18OncqBCB7tIUyqxRcJnlonQ0ioHKYB988GcDFF3ZePmnb8eHEopDs/wPHR/iGAFgoUQ==",
"dev": true
},
"node_modules/emoji-regex": {
"once": "^1.4.0"
}
},
+ "node_modules/enhanced-resolve": {
+ "version": "5.16.1",
+ "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.1.tgz",
+ "integrity": "sha512-4U5pNsuDl0EhuZpq46M5xPslstkviJuhrdobaRDBk2Jy2KO37FDAJl4lb2KlNabxT0m4MTK2UHNrsAcphE8nyw==",
+ "dev": true,
+ "dependencies": {
+ "graceful-fs": "^4.2.4",
+ "tapable": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
"node_modules/entities": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
}
},
"node_modules/eslint": {
- "version": "8.57.0",
- "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz",
- "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==",
+ "version": "9.2.0",
+ "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.2.0.tgz",
+ "integrity": "sha512-0n/I88vZpCOzO+PQpt0lbsqmn9AsnsJAQseIqhZFI8ibQT0U1AkEKRxA3EVMos0BoHSXDQvCXY25TUjB5tr8Og==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.2.0",
"@eslint-community/regexpp": "^4.6.1",
- "@eslint/eslintrc": "^2.1.4",
- "@eslint/js": "8.57.0",
- "@humanwhocodes/config-array": "^0.11.14",
+ "@eslint/eslintrc": "^3.0.2",
+ "@eslint/js": "9.2.0",
+ "@humanwhocodes/config-array": "^0.13.0",
"@humanwhocodes/module-importer": "^1.0.1",
+ "@humanwhocodes/retry": "^0.2.3",
"@nodelib/fs.walk": "^1.2.8",
- "@ungap/structured-clone": "^1.2.0",
"ajv": "^6.12.4",
"chalk": "^4.0.0",
"cross-spawn": "^7.0.2",
"debug": "^4.3.2",
- "doctrine": "^3.0.0",
"escape-string-regexp": "^4.0.0",
- "eslint-scope": "^7.2.2",
- "eslint-visitor-keys": "^3.4.3",
- "espree": "^9.6.1",
+ "eslint-scope": "^8.0.1",
+ "eslint-visitor-keys": "^4.0.0",
+ "espree": "^10.0.1",
"esquery": "^1.4.2",
"esutils": "^2.0.2",
"fast-deep-equal": "^3.1.3",
- "file-entry-cache": "^6.0.1",
+ "file-entry-cache": "^8.0.0",
"find-up": "^5.0.0",
"glob-parent": "^6.0.2",
- "globals": "^13.19.0",
- "graphemer": "^1.4.0",
"ignore": "^5.2.0",
"imurmurhash": "^0.1.4",
"is-glob": "^4.0.0",
"is-path-inside": "^3.0.3",
- "js-yaml": "^4.1.0",
"json-stable-stringify-without-jsonify": "^1.0.1",
"levn": "^0.4.1",
"lodash.merge": "^4.6.2",
"eslint": "bin/eslint.js"
},
"engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
"eslint": ">=8"
}
},
+ "node_modules/eslint-plugin-jsdoc": {
+ "version": "48.2.4",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.2.4.tgz",
+ "integrity": "sha512-3ebvVgCJFy06gpmuS2ynz13uh9iFSzZ1C1dDkgcSAqVVg82zlORKMk2fvjq708pAO6bwfs5YLttknFEbaoDiGw==",
+ "dev": true,
+ "dependencies": {
+ "@es-joy/jsdoccomment": "~0.43.0",
+ "are-docs-informative": "^0.0.2",
+ "comment-parser": "1.4.1",
+ "debug": "^4.3.4",
+ "escape-string-regexp": "^4.0.0",
+ "esquery": "^1.5.0",
+ "is-builtin-module": "^3.2.1",
+ "semver": "^7.6.0",
+ "spdx-expression-parse": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0"
+ }
+ },
"node_modules/eslint-plugin-n": {
- "version": "16.6.2",
- "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-16.6.2.tgz",
- "integrity": "sha512-6TyDmZ1HXoFQXnhCTUjVFULReoBPOAjpuiKELMkeP40yffI/1ZRO+d9ug/VC6fqISo2WkuIBk3cvuRPALaWlOQ==",
+ "version": "17.6.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-17.6.0.tgz",
+ "integrity": "sha512-Y73o88ROwbCtVCCmZjYlYcPYkOG7mIzxxVK1XFRSa2epbKWtAPsmYpAD0pqxg/ZwlcWxMDceQPKHYQi4VIHz7w==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.4.0",
- "builtins": "^5.0.1",
+ "enhanced-resolve": "^5.15.0",
"eslint-plugin-es-x": "^7.5.0",
"get-tsconfig": "^4.7.0",
- "globals": "^13.24.0",
+ "globals": "^15.0.0",
"ignore": "^5.2.4",
- "is-builtin-module": "^3.2.1",
- "is-core-module": "^2.12.1",
- "minimatch": "^3.1.2",
- "resolve": "^1.22.2",
+ "minimatch": "^9.0.0",
"semver": "^7.5.3"
},
"engines": {
- "node": ">=16.0.0"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
- "url": "https://github.com/sponsors/mysticatea"
+ "url": "https://opencollective.com/eslint"
},
"peerDependencies": {
- "eslint": ">=7.0.0"
+ "eslint": ">=8.23.0"
+ }
+ },
+ "node_modules/eslint-plugin-n/node_modules/brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/eslint-plugin-n/node_modules/minimatch": {
+ "version": "9.0.4",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz",
+ "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=16 || 14 >=14.17"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/eslint-plugin-node": {
"semver": "bin/semver.js"
}
},
- "node_modules/eslint-plugin-promise": {
- "version": "6.1.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz",
- "integrity": "sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==",
- "dev": true,
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- },
- "peerDependencies": {
- "eslint": "^7.0.0 || ^8.0.0"
- }
- },
"node_modules/eslint-plugin-security": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-security/-/eslint-plugin-security-2.1.1.tgz",
- "integrity": "sha512-7cspIGj7WTfR3EhaILzAPcfCo5R9FbeWvbgsPYWivSurTBKW88VQxtP3c4aWMG9Hz/GfJlJVdXEJ3c8LqS+u2w==",
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-security/-/eslint-plugin-security-3.0.0.tgz",
+ "integrity": "sha512-2Ij7PkmXIF2cKwoVkEgemwoXbOnxg5UfdhdcpNxZwJxC/10dbsdhHISrTyJ/n8DUkt3yiN6P1ywEgcMGjIwHIw==",
"dev": true,
"dependencies": {
"safe-regex": "^2.1.1"
+ },
+ "engines": {
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
}
},
"node_modules/eslint-plugin-sonarjs": {
- "version": "0.25.1",
- "resolved": "https://registry.npmjs.org/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-0.25.1.tgz",
- "integrity": "sha512-5IOKvj/GMBNqjxBdItfotfRHo7w48496GOu1hxdeXuD0mB1JBlDCViiLHETDTfA8pDAVSBimBEQoetRXYceQEw==",
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-sonarjs/-/eslint-plugin-sonarjs-1.0.3.tgz",
+ "integrity": "sha512-6s41HLPYPyDrp+5+7Db5yFYbod6h9pC7yx+xfcNwHRcLe1EZwbbQT/tdOAkR7ekVUkNGEvN3GmYakIoQUX7dEg==",
"dev": true,
"engines": {
"node": ">=16"
},
"peerDependencies": {
- "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"
+ "eslint": "^8.0.0 || ^9.0.0"
}
},
"node_modules/eslint-scope": {
- "version": "7.2.2",
- "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz",
- "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==",
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.1.tgz",
+ "integrity": "sha512-pL8XjgP4ZOmmwfFE8mEhSxA7ZY4C+LWyqjQ3o4yWkkmD0qcMT9kkW3zWHOczhWcjTSgqycYAgwSlXvZltv65og==",
"dev": true,
"dependencies": {
"esrecurse": "^4.3.0",
"estraverse": "^5.2.0"
},
"engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/eslint-visitor-keys": {
- "version": "3.4.3",
- "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz",
- "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==",
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.0.0.tgz",
+ "integrity": "sha512-OtIRv/2GyiF6o/d8K7MYKKbXrOUBIK6SfkIRM4Z0dY3w+LiQ0vy3F57m0Z71bjbyeiWFiHJ8brqnmE6H6/jEuw==",
"dev": true,
"engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/espree": {
- "version": "9.6.1",
- "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz",
- "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==",
+ "version": "10.0.1",
+ "resolved": "https://registry.npmjs.org/espree/-/espree-10.0.1.tgz",
+ "integrity": "sha512-MWkrWZbJsL2UwnjxTX3gG8FneachS/Mwg7tdGXce011sJd5b0JG54vat5KHnfSBODZ3Wvzd2WnjxyzsRoVv+ww==",
"dev": true,
"dependencies": {
- "acorn": "^8.9.0",
+ "acorn": "^8.11.3",
"acorn-jsx": "^5.3.2",
- "eslint-visitor-keys": "^3.4.1"
+ "eslint-visitor-keys": "^4.0.0"
},
"engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
},
"funding": {
"url": "https://opencollective.com/eslint"
}
},
"node_modules/file-entry-cache": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
- "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==",
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
+ "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==",
"dev": true,
"dependencies": {
- "flat-cache": "^3.0.4"
+ "flat-cache": "^4.0.0"
},
"engines": {
- "node": "^10.12.0 || >=12.0.0"
+ "node": ">=16.0.0"
}
},
"node_modules/file-uri-to-path": {
}
},
"node_modules/flat-cache": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz",
- "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==",
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz",
+ "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==",
"dev": true,
"dependencies": {
"flatted": "^3.2.9",
- "keyv": "^4.5.3",
- "rimraf": "^3.0.2"
+ "keyv": "^4.5.4"
},
"engines": {
- "node": "^10.12.0 || >=12.0.0"
+ "node": ">=16"
}
},
"node_modules/flatted": {
}
},
"node_modules/form-data-encoder": {
- "version": "2.1.4",
- "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-2.1.4.tgz",
- "integrity": "sha512-yDYSgNMraqvnxiEXO4hi88+YZxaHC6QKzb5N84iRCTDeRO7ZALpir/lVmf/uXUhnwUr2O4HU8s/n6x+yNjQkHw==",
+ "version": "4.0.2",
+ "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-4.0.2.tgz",
+ "integrity": "sha512-KQVhvhK8ZkWzxKxOr56CPulAhH3dobtuQ4+hNQ+HekH/Wp5gSOafqRAeTphQUJAIk0GBvHZgJ2ZGRWd5kphMuw==",
"engines": {
- "node": ">= 14.17"
+ "node": ">= 18"
}
},
"node_modules/fromentries": {
}
},
"node_modules/get-stream": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz",
- "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
+ "version": "8.0.1",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz",
+ "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==",
"engines": {
- "node": ">=10"
+ "node": ">=16"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/get-tsconfig": {
- "version": "4.7.3",
- "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.3.tgz",
- "integrity": "sha512-ZvkrzoUA0PQZM6fy6+/Hce561s+faD1rsNwhnO5FelNjyy7EMGJ3Rz1AQ8GYDWjhRs/7dBLOEJvhK8MiEJOAFg==",
+ "version": "4.7.5",
+ "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.5.tgz",
+ "integrity": "sha512-ZCuZCnlqNzjb4QprAzXKdpp/gh6KTxSJuw3IBsPnV/7fV4NxC9ckB+vPTt8w7fJA0TaSD7c55BR47JD6MEDyDw==",
"dev": true,
"dependencies": {
"resolve-pkg-maps": "^1.0.0"
"integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw=="
},
"node_modules/glob": {
- "version": "10.3.12",
- "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz",
- "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==",
+ "version": "10.3.15",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.15.tgz",
+ "integrity": "sha512-0c6RlJt1TICLyvJYIApxb8GsXoai0KUP7AxKKAtsYXdgJR1mGEUa7DgwShbdk1nly0PYoZj01xd4hzbq3fsjpw==",
"dev": true,
"dependencies": {
"foreground-child": "^3.1.0",
"jackspeak": "^2.3.6",
"minimatch": "^9.0.1",
"minipass": "^7.0.4",
- "path-scurry": "^1.10.2"
+ "path-scurry": "^1.11.0"
},
"bin": {
"glob": "dist/esm/bin.mjs"
},
"engines": {
- "node": ">=16 || 14 >=14.17"
+ "node": ">=16 || 14 >=14.18"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/globals": {
- "version": "13.24.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz",
- "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==",
+ "version": "15.2.0",
+ "resolved": "https://registry.npmjs.org/globals/-/globals-15.2.0.tgz",
+ "integrity": "sha512-FQ5YwCHZM3nCmtb5FzEWwdUc9K5d3V/w9mzcz8iGD1gC/aOTHc6PouYu0kkKipNJqHAT7m51sqzQjEjIP+cK0A==",
"dev": true,
- "dependencies": {
- "type-fest": "^0.20.2"
- },
"engines": {
- "node": ">=8"
+ "node": ">=18"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/got": {
- "version": "13.0.0",
- "resolved": "https://registry.npmjs.org/got/-/got-13.0.0.tgz",
- "integrity": "sha512-XfBk1CxOOScDcMr9O1yKkNaQyy865NbYs+F7dr4H0LZMVgCj2Le59k6PqbNHoL5ToeaEQUYh6c6yMfVcc6SJxA==",
+ "version": "14.2.1",
+ "resolved": "https://registry.npmjs.org/got/-/got-14.2.1.tgz",
+ "integrity": "sha512-KOaPMremmsvx6l9BLC04LYE6ZFW4x7e4HkTe3LwBmtuYYQwpeS4XKqzhubTIkaQ1Nr+eXxeori0zuwupXMovBQ==",
"dependencies": {
- "@sindresorhus/is": "^5.2.0",
+ "@sindresorhus/is": "^6.1.0",
"@szmarczak/http-timer": "^5.0.1",
"cacheable-lookup": "^7.0.0",
- "cacheable-request": "^10.2.8",
+ "cacheable-request": "^10.2.14",
"decompress-response": "^6.0.0",
- "form-data-encoder": "^2.1.2",
- "get-stream": "^6.0.1",
- "http2-wrapper": "^2.1.10",
+ "form-data-encoder": "^4.0.2",
+ "get-stream": "^8.0.1",
+ "http2-wrapper": "^2.2.1",
"lowercase-keys": "^3.0.0",
- "p-cancelable": "^3.0.0",
+ "p-cancelable": "^4.0.1",
"responselike": "^3.0.0"
},
"engines": {
- "node": ">=16"
+ "node": ">=20"
},
"funding": {
"url": "https://github.com/sindresorhus/got?sponsor=1"
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/hasha/node_modules/type-fest": {
- "version": "0.8.1",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
- "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/hasown": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
"dev": true
},
"node_modules/html-validate": {
- "version": "8.18.1",
- "resolved": "https://registry.npmjs.org/html-validate/-/html-validate-8.18.1.tgz",
- "integrity": "sha512-6NYRciFBQhVZH29fwDQxofPil0qm7MMSEDzDpZWu2U23Fnmv1WTuompP7fbzHYj6+CIJ4T/Q4hyWRCe0CCrsMg==",
+ "version": "8.18.2",
+ "resolved": "https://registry.npmjs.org/html-validate/-/html-validate-8.18.2.tgz",
+ "integrity": "sha512-X/ahjDnTZe1VjoPz+w7zGe5I5/os8PLQ+c5C9ak6etV0nNK9gPbwbGaP9BQoSQuQx0mszw5khDjP1ffnXx+1OA==",
"dev": true,
"funding": [
{
"url": "https://github.com/sponsors/html-validate"
}
],
+ "workspaces": [
+ "docs",
+ "tests/vitest"
+ ],
"dependencies": {
"@babel/code-frame": "^7.10.0",
"@html-validate/stylish": "^4.1.0",
}
},
"node_modules/html-validate/node_modules/ajv": {
- "version": "8.12.0",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz",
- "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==",
+ "version": "8.13.0",
+ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.13.0.tgz",
+ "integrity": "sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==",
"dev": true,
"dependencies": {
- "fast-deep-equal": "^3.1.1",
+ "fast-deep-equal": "^3.1.3",
"json-schema-traverse": "^1.0.0",
"require-from-string": "^2.0.2",
- "uri-js": "^4.2.2"
+ "uri-js": "^4.4.1"
},
"funding": {
"type": "github",
"resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz",
"integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A=="
},
+ "node_modules/jsdoc-type-pratt-parser": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz",
+ "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
"node_modules/jsesc": {
"version": "2.5.2",
"resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz",
}
},
"node_modules/minipass": {
- "version": "7.0.4",
- "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz",
- "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==",
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.1.tgz",
+ "integrity": "sha512-UZ7eQ+h8ywIRAW1hIEl2AqdwzJucU/Kp59+8kkZeSvafXhZjul247BvIJjEVFVeON6d7lM46XX1HXCduKAS8VA==",
"dev": true,
"engines": {
"node": ">=16 || 14 >=14.17"
}
},
"node_modules/node-abi": {
- "version": "3.57.0",
- "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.57.0.tgz",
- "integrity": "sha512-Dp+A9JWxRaKuHP35H77I4kCKesDy5HUDEmScia2FyncMTOXASMyg251F5PhFoDA5uqBrDDffiLpbqnrZmNXW+g==",
+ "version": "3.62.0",
+ "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.62.0.tgz",
+ "integrity": "sha512-CPMcGa+y33xuL1E0TcNIu4YyaZCxnnvkVaEXrsosR3FxN+fV8xvb7Mzpb7IgKler10qeMkE6+Dp8qJhpzdq35g==",
"dependencies": {
"semver": "^7.3.5"
},
}
},
"node_modules/node-gyp-build": {
- "version": "4.8.0",
- "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.0.tgz",
- "integrity": "sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==",
+ "version": "4.8.1",
+ "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.1.tgz",
+ "integrity": "sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==",
"optional": true,
"bin": {
"node-gyp-build": "bin.js",
}
},
"node_modules/optionator": {
- "version": "0.9.3",
- "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz",
- "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==",
+ "version": "0.9.4",
+ "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz",
+ "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==",
"dev": true,
"dependencies": {
- "@aashutoshrathi/word-wrap": "^1.2.3",
"deep-is": "^0.1.3",
"fast-levenshtein": "^2.0.6",
"levn": "^0.4.1",
"prelude-ls": "^1.2.1",
- "type-check": "^0.4.0"
+ "type-check": "^0.4.0",
+ "word-wrap": "^1.2.5"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/p-cancelable": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-3.0.0.tgz",
- "integrity": "sha512-mlVgR3PGuzlo0MmTdk4cXqXWlwQDLnONTAg6sm62XkMJEiRxN3GL3SffkYvqwonbkJBcrI7Uvv5Zh9yjvn2iUw==",
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-4.0.1.tgz",
+ "integrity": "sha512-wBowNApzd45EIKdO1LaU+LrMBwAcjfPaYtVzV3lmfM3gf8Z4CHZsiIqlM8TZZ8okYvh5A1cP6gTfCRQtwUpaUg==",
"engines": {
- "node": ">=12.20"
+ "node": ">=14.16"
}
},
"node_modules/p-limit": {
"dev": true
},
"node_modules/path-scurry": {
- "version": "1.10.2",
- "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz",
- "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==",
+ "version": "1.11.1",
+ "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz",
+ "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==",
"dev": true,
"dependencies": {
"lru-cache": "^10.2.0",
"minipass": "^5.0.0 || ^6.0.2 || ^7.0.0"
},
"engines": {
- "node": ">=16 || 14 >=14.17"
+ "node": ">=16 || 14 >=14.18"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/path-scurry/node_modules/lru-cache": {
- "version": "10.2.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz",
- "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==",
+ "version": "10.2.2",
+ "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.2.tgz",
+ "integrity": "sha512-9hp3Vp2/hFQUiIwKo8XCeFVnrg8Pk3TYNPIR7tJADKi5YfcF7vEaK7avFHTlSy3kOKYaJQaalfEo6YuXdceBOQ==",
"dev": true,
"engines": {
"node": "14 || >=16.14"
}
},
"node_modules/path-to-regexp": {
- "version": "6.2.1",
- "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz",
- "integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==",
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.2.tgz",
+ "integrity": "sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==",
"dev": true
},
"node_modules/pg": {
"node": ">=10"
}
},
- "node_modules/prebuild-install/node_modules/detect-libc": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz",
- "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==",
- "engines": {
- "node": ">=8"
- }
- },
"node_modules/prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
}
},
"node_modules/semver": {
- "version": "7.6.0",
- "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz",
- "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==",
- "dependencies": {
- "lru-cache": "^6.0.0"
- },
+ "version": "7.6.2",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz",
+ "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==",
"bin": {
"semver": "bin/semver.js"
},
"node": ">=10"
}
},
- "node_modules/semver/node_modules/lru-cache": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
- "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
- "dependencies": {
- "yallist": "^4.0.0"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/semver/node_modules/yallist": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
- "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
- },
"node_modules/serialize-javascript": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz",
}
},
"node_modules/sinon": {
- "version": "17.0.1",
- "resolved": "https://registry.npmjs.org/sinon/-/sinon-17.0.1.tgz",
- "integrity": "sha512-wmwE19Lie0MLT+ZYNpDymasPHUKTaZHUH/pKEubRXIzySv9Atnlw+BUMGCzWgV7b7wO+Hw6f1TEOr0IUnmU8/g==",
+ "version": "17.0.2",
+ "resolved": "https://registry.npmjs.org/sinon/-/sinon-17.0.2.tgz",
+ "integrity": "sha512-uihLiaB9FhzesElPDFZA7hDcNABzsVHwr3YfmM9sBllVwab3l0ltGlRV1XhpNfIacNDLGD1QRZNLs5nU5+hTuA==",
"dev": true,
"dependencies": {
- "@sinonjs/commons": "^3.0.0",
+ "@sinonjs/commons": "^3.0.1",
"@sinonjs/fake-timers": "^11.2.2",
"@sinonjs/samsam": "^8.0.0",
- "diff": "^5.1.0",
- "nise": "^5.1.5",
- "supports-color": "^7.2.0"
+ "diff": "^5.2.0",
+ "nise": "^5.1.9",
+ "supports-color": "^7"
},
"funding": {
"type": "opencollective",
"integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==",
"dev": true
},
+ "node_modules/spdx-exceptions": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz",
+ "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==",
+ "dev": true
+ },
+ "node_modules/spdx-expression-parse": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz",
+ "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==",
+ "dev": true,
+ "dependencies": {
+ "spdx-exceptions": "^2.1.0",
+ "spdx-license-ids": "^3.0.0"
+ }
+ },
+ "node_modules/spdx-license-ids": {
+ "version": "3.0.17",
+ "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz",
+ "integrity": "sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==",
+ "dev": true
+ },
"node_modules/spex": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/spex/-/spex-3.3.0.tgz",
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/tapable": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
+ "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
"node_modules/tar": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz",
"tar-stream": "^2.1.4"
}
},
- "node_modules/tar-fs/node_modules/chownr": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
- "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="
- },
"node_modules/tar-stream": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz",
"safe-buffer": "~5.2.0"
}
},
+ "node_modules/tar/node_modules/chownr": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz",
+ "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==",
+ "optional": true,
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/tar/node_modules/minipass": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz",
}
},
"node_modules/type-fest": {
- "version": "0.20.2",
- "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz",
- "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==",
+ "version": "0.8.1",
+ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz",
+ "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==",
"dev": true,
"engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
+ "node": ">=8"
}
},
"node_modules/typedarray": {
}
},
"node_modules/update-browserslist-db": {
- "version": "1.0.13",
- "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz",
- "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==",
+ "version": "1.0.15",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.15.tgz",
+ "integrity": "sha512-K9HWH62x3/EalU1U6sjSZiylm9C8tgq2mSvshZpqc7QE69RaA2qjhkW2HlNA0tFpEbtyFz7HTqbSdN4MSwUodA==",
"dev": true,
"funding": [
{
}
],
"dependencies": {
- "escalade": "^3.1.1",
+ "escalade": "^3.1.2",
"picocolors": "^1.0.0"
},
"bin": {
"node": ">=8"
}
},
+ "node_modules/word-wrap": {
+ "version": "1.2.5",
+ "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
+ "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/workerpool": {
"version": "6.2.1",
"resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz",
],
"main": "server.js",
"scripts": {
+ "audit": "npm audit",
"coverage": "nyc npm test",
"coverage-check": "nyc check-coverage",
"eslint": "eslint server.js src",
"test": "mocha --recursive"
},
"pre-commit": [
+ "audit",
"eslint",
"coverage",
"coverage-check"
],
"engines": {
- "node": "^14 >=14.18 || >=15.7"
+ "node": ">=16.9"
},
"repository": {
"type": "git",
"license": "ISC",
"dependencies": {
"@squeep/amqp-helper": "git+https://git.squeep.com/squeep-amqp-helper#v1.0.0",
- "@squeep/api-dingus": "^2.1.0",
- "@squeep/authentication-module": "git+https://git.squeep.com/squeep-authentication-module/#v1.4.0",
+ "@squeep/api-dingus": "^2",
+ "@squeep/authentication-module": "git+https://git.squeep.com/squeep-authentication-module/#v1.5.0",
"@squeep/chores": "git+https://git.squeep.com/squeep-chores/#v1.0.1",
- "@squeep/html-template-helper": "git+https://git.squeep.com/squeep-html-template-helper#v1.6.0",
- "@squeep/indieauth-helper": "^1.4.1",
- "@squeep/logger-json-console": "^3.0.2",
- "@squeep/mystery-box": "^2.0.2",
- "@squeep/resource-authentication-module": "git+https://git.squeep.com/squeep-resource-authentication-module#v1.0.1",
- "@squeep/roman": "^1.0.1",
- "@squeep/web-linking": "^1.0.8",
- "better-sqlite3": "^9.4.5",
- "pg-promise": "^11.6.0",
- "uuid": "^9.0.1"
+ "@squeep/html-template-helper": "git+https://git.squeep.com/squeep-html-template-helper#v1.6.1",
+ "@squeep/indieauth-helper": "^1.4",
+ "@squeep/logger-json-console": "^3",
+ "@squeep/mystery-box": "^2",
+ "@squeep/roman": "^1",
+ "@squeep/web-linking": "^1",
+ "better-sqlite3": "^9",
+ "pg-promise": "^11",
+ "uuid": "^9"
},
"devDependencies": {
+ "@squeep/eslint-config": "^1",
"@squeep/test-helper": "git+https://git.squeep.com/squeep-test-helper#v1.0.1",
- "eslint": "^8.57.0",
- "eslint-plugin-n": "^16.6.2",
- "eslint-plugin-promise": "^6.1.1",
- "eslint-plugin-security": "^2.1.1",
- "eslint-plugin-sonarjs": "^0.25.1",
- "html-validate": "^8.18.1",
- "mocha": "^10.4.0",
- "mocha-steps": "^1.3.0",
- "nyc": "^15.1.0",
- "pre-commit": "^1.2.2",
- "sinon": "^17.0.1"
+ "eslint": "^9",
+ "html-validate": "^8",
+ "mocha": "^10",
+ "mocha-steps": "^1",
+ "nyc": "^15",
+ "pre-commit": "^1",
+ "sinon": "^17"
}
}
/**
* Attempt to remove tokens which are expired or otherwise no longer valid.
- * @param {Number} atLeastMsSinceLast
+ * @param {number} atLeastMsSinceLast minimum clean period
*/
async cleanTokens(atLeastMsSinceLast = this.options?.chores?.tokenCleanupMs || 0) {
const _scope = _fileScope('cleanTokens');
/**
* Attempt to remove ephemeral scopes which are no longer referenced by tokens.
- * @param {Number} atLeastMsSinceLast
+ * @param {number} atLeastMsSinceLast minimum clean period
*/
async cleanScopes(atLeastMsSinceLast = this.options?.chores?.scopeCleanupMs || 0) {
const _scope = _fileScope('cleanScopes');
/**
* Limit length of string to keep logs sane
- * @param {String} str
- * @param {Number} len
- * @returns {String}
+ * @param {string} str str
+ * @param {number} len len
+ * @returns {string} str
*/
const logTruncate = (str, len) => {
if (typeof str !== 'string' || str.toString().length <= len) {
/**
* Turn a snake into a camel.
- * @param {String} snakeCase
- * @param {String|RegExp} delimiter
- * @returns {String}
+ * @param {string} snakeCase snake case
+ * @param {string | RegExp} delimiter delimiter
+ * @returns {string} camel case
*/
const camelfy = (snakeCase, delimiter = '_') => {
if (!snakeCase || typeof snakeCase.split !== 'function') {
/**
* Return an array containing x if x is not an array.
- * @param {*} x
+ * @param {*} x x
+ * @returns {any[]} x[]
*/
const ensureArray = (x) => {
if (x === undefined) {
/**
* Recursively freeze an object.
- * @param {Object} o
- * @returns {Object}
+ * @param {object} o obj
+ * @returns {object} frozen obj
*/
const freezeDeep = (o) => {
Object.freeze(o);
};
-/** Oauth2.1 §3.2.3.1
+/**
+ * Oauth2.1 §3.2.3.1
* %x20-21 / %x23-5B / %x5D-7E
- * @param {String} char
+ * ' '-'!' / '#'-'[' / ']'-'~'
+ * not allowed: control characters, '"', '\'
+ * @param {string} char character
+ * @returns {boolean} is valid
*/
const validErrorChar = (char) => {
const value = char.charCodeAt(0);
/**
* Determine if an OAuth error message is valid.
- * @param {String} error
- * @returns {Boolean}
+ * @param {string} error error
+ * @returns {boolean} is valid
*/
const validError = (error) => {
return error && error.split('').filter((c) => !validErrorChar(c)).length === 0 || false;
/**
* OAuth2.1 §3.2.2.1
* scope-token = 1*( %x21 / %x23-5B / %x5D-7E )
- * @param {String} char
+ * @param {string} char char
+ * @returns {boolean} is valid
*/
const validScopeChar = (char) => {
const value = char.charCodeAt(0);
/**
* Determine if a scope has a valid name.
- * @param {String} scope
- * @returns {Boolean}
+ * @param {string} scope scope
+ * @returns {boolean} is valid
*/
const validScope = (scope) => {
return scope && scope.split('').filter((c) => !validScopeChar(c)).length === 0 || false;
/**
*
- * @param {Number} bytes
+ * @param {number} bytes bytes
+ * @returns {string} base64 random string
*/
const newSecret = async (bytes = 64) => {
return (await randomBytesAsync(bytes * 3 / 4)).toString('base64');
/**
* Convert a Date object to epoch seconds.
- * @param {Date=} date
- * @returns {Number}
+ * @param {Date=} date date
+ * @returns {number} epoch
*/
const dateToEpoch = (date) => {
const dateMs = date ? date.getTime() : Date.now();
};
+/**
+ * @typedef {object} ConsoleLike
+ * @property {Function} debug log debug
+ */
+
/**
* Log Mystery Box statistics events.
- * @param {Console} logger
- * @param {String} scope
+ * @param {ConsoleLike} logger logger instance
+ * @param {string} scope scope
+ * @returns {Function} stat logger
*/
const mysteryBoxLogger = (logger, scope) => {
return (s) => {
* At the minimum, this will validate a compatible schema is present and usable.
* Some engines will also perform other initializations or async actions which
* are easier handled outside the constructor.
- */
+ */
async initialize() {
const _scope = _fileScope('initialize');
/**
- * @typedef {Object} SchemaVersionObject
- * @property {Number} major
- * @property {Number} minor
- * @property {Number} patch
+ * @typedef {object} SchemaVersionObject
+ * @property {number} major major
+ * @property {number} minor minor
+ * @property {number} patch patch
*/
/**
* Query the current schema version.
* This is a standalone query function, as it is called before statements are loaded.
- * @returns {Promise<SchemaVersionObject>}
+ * @returns {Promise<SchemaVersionObject>} schema version
*/
async _currentSchema() {
this._notImplemented('_currentSchema', arguments);
/**
* Wrap a function call in a transaction context.
- * @param {*} dbCtx
+ * @param {*} dbCtx db context
* @param {Function} fn fn(txCtx)
*/
async transaction(dbCtx, fn) {
* - infinites
* - null
* - uuid
- * @param {Object} object
- * @param {String[]} properties
- * @param {String[]} types
+ * @param {object} object object
+ * @param {string[]} properties properties
+ * @param {string[]} types types
*/
_ensureTypes(object, properties, types) {
const _scope = _fileScope('_ensureTypes');
/**
- * @typedef {Object} Authentication
- * @property {String} identifier
- * @property {String=} credential
- * @property {Date} created
- * @property {Date=} lastAuthentication
+ * @typedef {object} Authentication
+ * @property {string} identifier identifier
+ * @property {string=} credential credential
+ * @property {Date} created created
+ * @property {Date=} lastAuthentication last authentication
*/
/**
- * @param {Authentication} authentication
+ * @param {Authentication} authentication authentication
*/
_validateAuthentication(authentication) {
[
/**
- * @typedef {Object} Resource
- * @property {String} resourceId - uuid
- * @property {String} secret
- * @property {String} description
- * @property {Date} created
+ * @typedef {object} Resource
+ * @property {string} resourceId uuid
+ * @property {string} secret secret
+ * @property {string} description description
+ * @property {Date} created created at
*/
/**
- * @param {Resource} resource
+ * @param {Resource} resource resource
*/
_validateResource(resource) {
[
/**
- * @typedef {Object} Token
- * @property {String} codeId - uuid
- * @property {String} profile
- * @property {Date} created
- * @property {Date=} expires
- * @property {Date=} refreshExpires
- * @property {Date=} refreshed
- * @property {*=} duration
- * @property {*=} refreshDuration
- * @property {Number|BigInt=} refresh_count
- * @property {Boolean} is_revoked
- * @property {Boolean} is_token
- * @property {String} client_id
- * @property {String[]} scopes
- * @property {Object=} profileData
+ * @typedef {object} Token
+ * @property {string} codeId uuid
+ * @property {string} profile profile
+ * @property {Date} created created at
+ * @property {Date=} expires expires at
+ * @property {Date=} refreshExpires refresh expires at
+ * @property {Date=} refreshed refreshed at
+ * @property {*=} duration duration
+ * @property {*=} refreshDuration refresh duration
+ * @property {number | bigint=} refresh_count refresh count
+ * @property {boolean} is_revoked is revoked
+ * @property {boolean} is_token is token
+ * @property {string} client_id client id
+ * @property {string[]} scopes scopes
+ * @property {object=} profileData profile data
*/
/**
- * @param {Token} token
+ * @param {Token} token token
*/
_validateToken(token) {
[
* Interface methods need implementations. Ensure the db-interaction
* methods on the base class call this, so they may be overridden by
* implementation classes.
- * @param {String} method
- * @param {arguments} args
+ * @param {string} method method
+ * @param {arguments} args args
*/
_notImplemented(method, args) {
this.logger.error(_fileScope(method), 'abstract method called', Array.from(args));
/**
* Get all the almanac entries.
- * @param {*} dbCtx
+ * @param {*} dbCtx db context
*/
async almanacGetAll(dbCtx) {
this._notImplemented('almanacGetAll', arguments);
/**
* Insert or update an almanac entry.
- * @param {*} dbCtx
- * @param {String} event
- * @param {Date=} date
+ * @param {*} dbCtx db context
+ * @param {string} event event
+ * @param {Date=} date date
*/
async almanacUpsert(dbCtx, event, date) {
this._notImplemented('almanacUpsert', arguments);
/**
* Fetch the authentication record for an identifier.
- * @param {*} dbCtx
- * @param {String} identifier
- * @returns {Promise<Authentication>}
+ * @param {*} dbCtx db context
+ * @param {string} identifier identifier
+ * @returns {Promise<Authentication>} authentication
*/
async authenticationGet(dbCtx, identifier) {
this._notImplemented('authenticationGet', arguments);
/**
* Update the authentication record for the identifier that
* correct credentials have been supplied.
- * @param {*} dbCtx
- * @param {String} identifier
+ * @param {*} dbCtx db context
+ * @param {string} identifier identifier
* @returns {Promise<void>}
*/
async authenticationSuccess(dbCtx, identifier) {
/**
* Insert or update the credential for an identifier.
- * @param {*} dbCtx
- * @param {String} identifier
- * @param {String} credential
- * @param {String=} otpKey
+ * @param {*} dbCtx db context
+ * @param {string} identifier identifier
+ * @param {string} credential credential
+ * @param {string=} otpKey otp key
* @returns {Promise<void>}
*/
async authenticationUpsert(dbCtx, identifier, credential, otpKey) {
/**
* Update the otpKey for an identifier.
- * @param {*} dbCtx
- * @param {String} identifier
- * @param {String=} otpKey
+ * @param {*} dbCtx db context
+ * @param {string} identifier identifier
+ * @param {string=} otpKey otp key
* @returns {Promise<void>}
*/
async authenticationUpdateOTPKey(dbCtx, identifier, otpKey) {
/**
* Update the credential for an identifier.
- * @param {*} dbCtx
- * @param {String} identifier
- * @param {String} credential
+ * @param {*} dbCtx db context
+ * @param {string} identifier identifier
+ * @param {string} credential credential
* @returns {Promise<void>}
*/
async authenticationUpdateCredential(dbCtx, identifier, credential) {
/**
* Determine if profile url is known to this service.
- * @param {*} dbCtx
- * @param {String} profile
- * @returns {Promise<Boolean>}
+ * @param {*} dbCtx db context
+ * @param {string} profile profile
+ * @returns {Promise<boolean>} is valid
*/
async profileIsValid(dbCtx, profile) {
this._notImplemented('profileGet', arguments);
/**
* Insert a new relationship between a profile endpoint and
* an authenticated identifier.
- * @param {*} dbCtx
- * @param {String} profile
- * @param {String} identifier
+ * @param {*} dbCtx db context
+ * @param {string} profile profile
+ * @param {string} identifier identifier
* @returns {Promise<void>}
*/
async profileIdentifierInsert(dbCtx, profile, identifier) {
/**
* Adds a scope to be available for a profile to include on any authorization request.
- * @param {*} dbCtx
- * @param {String} profile
- * @param {String} scope
+ * @param {*} dbCtx db context
+ * @param {string} profile profile
+ * @param {string} scope scope
* @returns {Promise<void>}
*/
async profileScopeInsert(dbCtx, profile, scope) {
/**
- * @typedef {Object} ScopeDetails
- * @property {String} description
- * @property {String[]=} profiles
+ * @typedef {object} ScopeDetails
+ * @property {string} description description
+ * @property {string[]=} profiles profiles
+ */
+ /**
+ * @typedef {object} Profile
+ * @property {ScopeDetails} scope scope
*/
/**
- * @typedef {Object.<String, Object>} ProfileScopes
- * @property {Object.<String, Object>} profile
- * @property {Object.<String, ScopeDetails>} profile.scope
+ * @typedef {{[profile: string]: Profile}} ProfileScopes
*/
/**
- * @typedef {Object.<String, Object>} ScopeIndex
- * @property {ScopeDetails} scope
+ * @typedef {{[scope: string]: ScopeDetails}} ScopeIndex
+ * @property {ScopeDetails} scope scope details
*/
/**
- * @typedef {Object} ProfilesScopesReturn
- * @property {ProfileScopes} profileScopes
- * @property {ScopeIndex} scopeIndex
- * @property {String[]} profiles
+ * @typedef {object} ProfilesScopesReturn
+ * @property {ProfileScopes} profileScopes profile scopes
+ * @property {ScopeIndex} scopeIndex scope index
+ * @property {string[]} profiles profiles
*/
/**
* Returns an object containing:
* which each contain a description of the scope and a list of profiles offering it
* - an object with scopes as keys to the same scope objects
* - a list of profiles
- * @param {*} dbCtx
- * @param {String} identifier
- * @returns {Promise<ProfileScopesReturn>}
+ * @param {*} dbCtx db context
+ * @param {string} identifier identifier
+ * @returns {Promise<ProfilesScopesReturn>} profiles scopes
*/
async profilesScopesByIdentifier(dbCtx, identifier) {
this._notImplemented('profilesScopesByIdentifier', arguments);
/**
* @typedef ProfileScopesRow
- * @property profile
- * @property scope
- * @property description
- * @property application
- * @property isPermanent
- * @property isManuallyAdded
+ * @property {string} profile profile
+ * @property {string} scope scope
+ * @property {string} description description
+ * @property {string} application application
+ * @property {boolean} isPermanent avoid cleanup
+ * @property {boolean} isManuallyAdded avoid cleanup
*/
/**
* Convert db row data into associative structures.
* Same behavior is shared by multiple engines.
- * @param {ProfileScopesRow[]} profileScopesRows
- * @returns {ProfileScopesReturn}
+ * @param {ProfileScopesRow[]} profileScopesRows profile scopes row
+ * @returns {ProfilesScopesReturn} profiles scopes
*/
static _profilesScopesBuilder(profileScopesRows) {
const scopeIndex = {};
/**
* Sets list of additional scopes available to profile.
- * @param {*} dbCtx
- * @param {String} profile
- * @param {String[]} scopes
+ * @param {*} dbCtx db context
+ * @param {string} profile profile
+ * @param {string[]} scopes scopes
* @returns {Promise<void>}
*/
async profileScopesSetAll(dbCtx, profile, scopes) {
/**
* Create (or revoke a duplicate) code as a token entry.
- * @param {*} dbCtx
- * @param {Object} data
- * @param {String} data.codeId
- * @param {Date} data.created
- * @param {Boolean} data.isToken
- * @param {String} data.clientId
- * @param {String} data.profile - profile uri
- * @param {String} data.identifier
- * @param {String[]} data.scopes
- * @param {Number|Null} data.lifespanSeconds - null sets expiration to Infinity
- * @param {Number|Null} data.refreshLifespanSeconds - null sets refresh to none
- * @param {String|Null} data.resource
- * @param {Object|Null} data.profileData - profile data from profile uri
- * @returns {Promise<Boolean>} whether redemption was successful
+ * @param {*} dbCtx db context
+ * @param {object} data data
+ * @param {string} data.codeId code id
+ * @param {Date} data.created created at
+ * @param {boolean} data.isToken is token
+ * @param {string} data.clientId client id
+ * @param {string} data.profile profile uri
+ * @param {string} data.identifier identifier
+ * @param {string[]} data.scopes scopesx
+ * @param {number | null} data.lifespanSeconds null sets expiration to Infinity
+ * @param {number | null} data.refreshLifespanSeconds null sets refresh to none
+ * @param {object | null} data.profileData profile data from profile uri
+ * @returns {Promise<boolean>} whether redemption was successful
*/
async redeemCode(dbCtx, { codeId, created, isToken, clientId, profile, identifier, scopes, lifespanSeconds, refreshLifespanSeconds, profileData } = {}) {
this._notImplemented('redeemCode', arguments);
/**
- * @typedef {Object} RefreshedToken
- * @property {Date} expires
- * @property {Date} refreshExpires
- * @property {String[]=} scopes if scopes were reduced
+ * @typedef {object} RefreshedToken
+ * @property {Date} expires expires at
+ * @property {Date} refreshExpires refresh expires at
+ * @property {string[]=} scopes if scopes were reduced
*/
/**
* Redeem a refresh token to renew token codeId.
- * @param {*} dbCtx
- * @param {String} codeId
- * @param {Date} refreshed
- * @param {String[]} removeScopes
- * @returns {Promise<RefreshedToken>}
+ * @param {*} dbCtx db context
+ * @param {string} codeId code id
+ * @param {Date} refreshed refreshed at
+ * @param {string[]} removeScopes remove scopes
+ * @returns {Promise<RefreshedToken>} refreshed token
*/
async refreshCode(dbCtx, codeId, refreshed, removeScopes) {
this._notImplemented('refreshCode', arguments);
/**
* Fetch a resource server record.
- * @param {*} dbCtx
- * @param {String} identifier uuid
- * @returns {Promise<Resource>}
+ * @param {*} dbCtx db context
+ * @param {string} resourceId uuid
+ * @returns {Promise<Resource>} resource
*/
async resourceGet(dbCtx, resourceId) {
this._notImplemented('resourceGet', arguments);
/**
* Create, or update description of, a resourceId.
- * @param {*} dbCtx
- * @param {String=} resourceId uuid
- * @param {String=} secret
- * @param {String=} description
+ * @param {*} dbCtx db context
+ * @param {string=} resourceId uuid
+ * @param {string=} secret secret
+ * @param {string=} description description
* @returns {Promise<void>}
*/
async resourceUpsert(dbCtx, resourceId, secret, description) {
/**
* Register a scope and its description.
- * @param {*} dbCtx
- * @param {String} scope
- * @param {String} application
- * @param {String} description
+ * @param {*} dbCtx db context
+ * @param {string} scope scope
+ * @param {string} application application
+ * @param {string} description description
+ * @param {boolean} manuallyAdded is manually added
* @returns {Promise<void>}
*/
async scopeUpsert(dbCtx, scope, application, description, manuallyAdded = false) {
/**
* Remove a non-permanent scope if it is not currently in use.
- * @param {*} dbCtx
- * @param {String} scope
- * @returns {Promise<Boolean>}
+ * @param {*} dbCtx db context
+ * @param {string} scope scope
+ * @returns {Promise<boolean>} deleted
*/
async scopeDelete(dbCtx, scope) {
this._notImplemented('scopeDelete', arguments);
/**
- * @typedef {Number|BigInt} CleanupResult
+ * @typedef {number | bigint} CleanupResult
*/
/**
- * @typedef {Object} CleanupResult
+ * @alias {object} CleanupResult
*/
/**
* Remove any non-permanent and non-manually-created scopes not currently in use.
- * @param {*} dbCtx
- * @param {Number} atLeastMsSinceLast skip cleanup if already executed this recently
- * @returns {Promise<CleanupResult>}
+ * @param {*} dbCtx db context
+ * @param {number} atLeastMsSinceLast skip cleanup if already executed this recently
+ * @returns {Promise<CleanupResult>} cleanup result
*/
async scopeCleanup(dbCtx, atLeastMsSinceLast) {
this._notImplemented('scopeClean', arguments);
/**
* Forget tokens after they have expired, and redeemed codes after they have expired.
- * @param {*} dbCtx
- * @param {Number} codeLifespanSeconds
- * @param {Number} atLeastMsSinceLast skip cleanup if already executed this recently
- * @returns {Promise<CleanupResult>}
+ * @param {*} dbCtx db context
+ * @param {number} codeLifespanSeconds code lifespan seconds
+ * @param {number} atLeastMsSinceLast skip cleanup if already executed this recently
+ * @returns {Promise<CleanupResult>} cleanup result
*/
async tokenCleanup(dbCtx, codeLifespanSeconds, atLeastMsSinceLast) {
this._notImplemented('tokenCleanup', arguments);
/**
* Look up a redeemed token by code_id.
- * @param {*} dbCtx
- * @param {String} codeId
- * @returns {Promise<Token>}
+ * @param {*} dbCtx db context
+ * @param {string} codeId code id
+ * @returns {Promise<Token>} token
*/
async tokenGetByCodeId(dbCtx, codeId) {
this._notImplemented('tokenGetByCodeId', arguments);
/**
* Sets a redeemed token as revoked.
- * @param {*} dbCtx
- * @param {String} codeId - uuid
+ * @param {*} dbCtx db context
+ * @param {string} codeId - uuid
* @returns {Promise<void>}
*/
async tokenRevokeByCodeId(dbCtx, codeId) {
/**
* Revoke the refreshability of a codeId.
- * @param {*} dbCtx
- * @param {String} codeId - uuid
+ * @param {*} dbCtx db context
+ * @param {string} codeId - uuid
* @returns {Promise<void>}
*/
async tokenRefreshRevokeByCodeId(dbCtx, codeId) {
/**
* Get all tokens assigned to identifier.
- * @param {*} dbCtx
- * @param {String} identifier
- * @returns {Promise<Tokens[]>}
+ * @param {*} dbCtx db context
+ * @param {string} identifier identifier
+ * @returns {Promise<Token[]>} token
*/
async tokensGetByIdentifier(dbCtx, identifier) {
this._notImplemented('tokensGetByIdentifier', arguments);
}
- /** @typedef {Object} RedeemedTicketData
- * @property {String} subject
- * @property {String} resource
- * @property {String=} iss
- * @property {String} ticket
- * @property {String} token
+ /**
+ * @typedef {object} RedeemedTicketData
+ * @property {string} subject subject
+ * @property {string} resource resource
+ * @property {string=} iss issuer
+ * @property {string} ticket ticket
+ * @property {string} token token
*/
/**
* Persist details of a redeemed ticket.
- * @param {*} dbCtx
- * @param {RedeemedTicketData} redeemedData
+ * @param {*} dbCtx db context
+ * @param {RedeemedTicketData} redeemedData redeemed data
* @returns {Promise<void>}
*/
async ticketRedeemed(dbCtx, redeemedData) {
/**
* Update details of a redeemed ticket that it has been published.
- * @param {*} dbCtx
- * @param {RedeemedTicketData} redeemedData
+ * @param {*} dbCtx db context
+ * @param {RedeemedTicketData} redeemedData redeemed data
* @returns {Promise<void>}
*/
async ticketTokenPublished(dbCtx, redeemedData) {
this._notImplemented('ticketTokenPublished', arguments);
}
+
/**
* Retrieve redeemed tokens which have not yet been published to queue.
- * @param {Number} limit
- * @returns {Promise<RedeemedData[]>}
+ * @param {*} dbCtx db context
+ * @param {number} limit limit
+ * @returns {Promise<RedeemedTicketData[]>} redeemed but not published
*/
async ticketTokenGetUnpublished(dbCtx, limit) {
this._notImplemented('ticketTokenGetUnpublished', arguments);
*/
/**
- * @typedef {Object} SchemaVersionObject
- * @property {Number} major
- * @property {Number} minor
- * @property {Number} patch
+ * @typedef {object} SchemaVersionObject
+ * @property {number} major major
+ * @property {number} minor minor
+ * @property {number} patch patch
*/
/**
* Split a dotted version string into parts.
- * @param {String} v
- * @returns {SchemaVersionObject}
+ * @param {string} v version string
+ * @returns {SchemaVersionObject} version object
*/
function schemaVersionStringToObject(v) {
const [ major, minor, patch ] = v.split('.', 3).map((x) => parseInt(x, 10));
/**
* Render a version object numerically.
- * @param {SchemaVersionObject} v
- * @returns {Number}
+ * Assumes no part will be greater than 1000.
+ * @param {SchemaVersionObject} v version object
+ * @returns {number} number
*/
function schemaVersionObjectToNumber(v) {
const vScale = 1000;
/**
* Convert dotted version string into number.
- * @param {String} v
- * @returns {Number}
+ * @param {string} v version string
+ * @returns {number} number
*/
function schemaVersionStringToNumber(v) {
return schemaVersionObjectToNumber(schemaVersionStringToObject(v));
/**
* Version string comparison, for sorting.
- * @param {String} a
- * @param {String} b
- * @returns {Number}
+ * @param {string} a version string
+ * @param {string} b version string
+ * @returns {number} cmp
*/
function schemaVersionStringCmp(a, b) {
return schemaVersionStringToNumber(a) - schemaVersionStringToNumber(b);
/**
* Check if an entry in a directory is a directory containing a migration file.
- * @param {String} schemaDir
- * @param {String} name
- * @returns {Boolean}
+ * @param {string} schemaDir schema dir
+ * @param {string} name name
+ * @param {string} migrationFile migration file
+ * @returns {boolean} is
*/
function isSchemaMigrationDirectory(schemaDir, name, migrationFile = 'apply.sql') {
// eslint-disable-next-line security/detect-non-literal-fs-filename
// eslint-disable-next-line security/detect-non-literal-fs-filename
applyStat = fs.statSync(path.join(schemaDir, name, migrationFile));
return applyStat.isFile();
- } catch (e) {
+ } catch (e) { // eslint-disable-line no-unused-vars
return false;
}
}
/**
* Return an array of schema migration directory names within engineDir,
* sorted in increasing order.
- * @param {String} engineDir
- * @returns {String[]}
+ * @param {string} engineDir path to implementation
+ * @returns {string[]} versions
*/
function allSchemaVersions(engineDir) {
const schemaDir = path.join(engineDir, 'sql', 'schema');
/**
* Return an array of schema migration directory names within engineDir,
* which are within supported range, and are greater than the current
- * @param {String} engineDir
- * @param {SchemaVersionObject} current
- * @param {Object} supported
- * @param {SchemaVersionObject} supported.min
- * @param {SchemaVersionObject} supported.max
- * @returns {String[]}
+ * @param {string} engineDir path to implementation
+ * @param {SchemaVersionObject} current version
+ * @param {object} supported range of supported versions
+ * @param {SchemaVersionObject} supported.min minimum version
+ * @param {SchemaVersionObject} supported.max maximum version
+ * @returns {string[]} applicable versions
*/
function unappliedSchemaVersions(engineDir, current, supported) {
const min = schemaVersionObjectToNumber(supported.min);
isSchemaMigrationDirectory,
allSchemaVersions,
unappliedSchemaVersions,
-};
\ No newline at end of file
+};
/**
* Boolean to 0/1 representation for SQLite params.
- * @param {Boolean} bool
- * @returns {Number}
+ * @param {boolean} bool boolean
+ * @returns {number} number
*/
static _booleanToNumeric(bool) {
// eslint-disable-next-line security/detect-object-injection
let metaExists = tableExists.get();
if (metaExists === undefined) {
const fPath = path.join(__dirname, 'sql', 'schema', 'init.sql');
- // eslint-disable-next-line security/detect-non-literal-fs-filename
+
const fSql = fs.readFileSync(fPath, { encoding: 'utf8' });
this.db.exec(fSql);
metaExists = tableExists.get();
};
};
- // eslint-disable-next-line security/detect-non-literal-fs-filename
+
for (const f of fs.readdirSync(sqlDir)) {
const fPath = path.join(sqlDir, f);
const { name: fName, ext: fExt } = path.parse(f);
/**
* Scrub credential from POST login body data.
- * @param {Object} data
- * @param {Boolean} sanitize
- * @returns {Boolean}
+ * @param {object} data data
+ * @param {boolean} sanitize do sanitize
+ * @returns {boolean} did/would sanitize
*/
function sanitizePostCredential(data, sanitize = true) {
let unclean = false;
/**
* Scrub sensitive data from context.
- * @param {Object} data
- * @param {Boolean} sanitize
- * @returns {Boolean}
+ * @param {object} data data
+ * @param {boolean} sanitize do sanitize
+ * @returns {boolean} did/would sanitize
*/
function sanitizeContext(data, sanitize = true) {
let unclean = false;
* Reduce logged data about scopes from profilesScopes.
* For all referenced scopes, only include profiles list.
* Remove scopes without profile references from scopeIndex.
- * @param {Object} data
- * @param {Boolean} sanitize
+ * @param {object} data data
+ * @param {boolean} sanitize do sanitize
+ * @returns {boolean} did/would sanitize
*/
function reduceScopeVerbosity(data, sanitize = true) {
let unclean = false;
/**
* Return any scope entries on an object, and whether sanitization is needed.
- * @param {Object=} obj
- * @returns {Object}
+ * @param {object=} obj obj
+ * @returns {object} obj
*/
const _scopesFrom = (obj) => {
const scopesEntries = Object.entries(obj?.scopeIndex || {});
/**
- * @typedef {[String, Object]} ScopeEntry
+ * @typedef {[string, object]} ScopeEntry
*/
/**
* Return new list of entries with scrubbed scopeDetails.
- * @param {ScopeEntry[]} entries
- * @returns {ScopeEntry[]}
+ * @param {ScopeEntry[]} entries entries
+ * @returns {ScopeEntry[]} entries
*/
const _scopeEntriesScrubber = (entries) => entries.map(([scopeName, scopeDetails]) => ([scopeName, { profiles: scopeDetails.profiles }]));
/**
* Create a new profilesScopes type object with scrubbed scope details.
- * @param {ScopeEntry[]} scopesEntries
- * @param {ScopeEntry[]} profilesEntries
- * @returns {Object}
+ * @param {ScopeEntry[]} scopesEntries entries
+ * @param {ScopeEntry[]} profilesEntries entries
+ * @returns {object} profilesScopes
*/
const _sanitizeProfilesScopes = (scopesEntries, profilesEntries) => {
const referencedScopesEntries = scopesEntries.filter(([_scopeName, scopeDetails]) => scopeDetails?.profiles?.length); // eslint-disable-line no-unused-vars
+/* eslint-disable sonarjs/no-duplicate-string */
'use strict';
const common = require('./common');
const supportedCodeChallengeMethods = ['S256', 'SHA256'];
+/**
+ * @typedef {import('node:http')} http
+ */
+
class Manager {
constructor(logger, db, options) {
this.options = options;
/**
* Add an error to a session, keeping only the most-severe code, but all descriptions.
* This error is sent along on the redirection back to client endpoint.
- * @param {Object} ctx
- * @param {Object} ctx.session
- * @param {String[]=} ctx.session.errorDescriptions
- * @param {String=} ctx.session.error
- * @param {String} error
- * @param {String} errorDescription
+ * @param {object} ctx context
+ * @param {object} ctx.session session
+ * @param {string[]=} ctx.session.errorDescriptions errors
+ * @param {string=} ctx.session.error error
+ * @param {string} error error
+ * @param {string} errorDescription error
*/
static _setError(ctx, error, errorDescription) {
const errorPrecedence = [ // By increasing severity
* The authorization server MUST include the HTTP Cache-Control response
* header field with a value of no-store in any response
* containing tokens, credentials, or other sensitive information.
- * @param {http.ServerResponse} res
+ * @param {http.ServerResponse} res response
*/
static _sensitiveResponse(res) {
Object.entries({
/**
* Sets params entries as url search parameters.
- * @param {URL} url
- * @param {Object} params
+ * @param {URL} url url
+ * @param {object} params parameters
*/
static _setSearchParams(url, params) {
Object.entries(params).forEach((param) => url.searchParams.set(...param));
/**
* Serve the informational root page.
- * @param {http.ClientRequest} req
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async getRoot(res, ctx) {
const _scope = _fileScope('getRoot');
/**
* Serve the metadata for this service.
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async getMeta(res, ctx) {
const _scope = _fileScope('getMeta');
* Process an authorization request from a client.
* User has authenticated, check if user matches profile,
* present user with consent form.
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async getAuthorization(res, ctx) {
const _scope = _fileScope('getAuthorization');
/**
* Validates, fetches, and parses client_id url, populating clientIdentifier with client h-app data.
- * @param {Object} ctx
+ * @param {object} ctx context
*/
async _clientIdRequired(ctx) {
if (ctx.queryParams['client_id']) {
/**
* Ensure redirect_uri exists and is corroborated by clientIdentifier data.
- * @param {Object} ctx
+ * @param {object} ctx context
*/
static _redirectURIRequired(ctx) {
if (ctx.queryParams['redirect_uri']) {
}
}
}
- } catch (e) {
+ } catch (e) { // eslint-disable-line no-unused-vars
Manager._setError(ctx, 'invalid_request', 'invalid value for parameter \'redirect_uri\'');
}
} else {
/**
* response_type must be valid
- * @param {Object} ctx
+ * @param {object} ctx context
*/
static _responseTypeRequired(ctx) {
ctx.session.responseType = ctx.queryParams['response_type'];
/**
* A state parameter must be present
- * @param {Object} ctx
+ * @param {object} ctx context
*/
static _stateRequired(ctx) {
ctx.session.state = ctx.queryParams['state'];
/**
* A code_challenge_method must be present and valid
- * @param {Object} ctx
+ * @param {object} ctx context
*/
_codeChallengeMethodRequired(ctx) {
ctx.session.codeChallengeMethod = ctx.queryParams['code_challenge_method'];
/**
* A code_challenge must be present
- * @param {Object} ctx
+ * @param {object} ctx context
*/
_codeChallengeRequired(ctx) {
ctx.session.codeChallenge = ctx.queryParams['code_challenge'];
/**
* Scopes may be present, with one known combination limitation
- * @param {Object} ctx
+ * @param {object} ctx context
*/
_scopeOptional(ctx) {
const _scope = _fileScope('_scopeOptional');
/**
* Parses me, if provided
- * @param {Object} ctx
+ * @param {object} ctx context
*/
async _meOptional(ctx) {
const me = ctx.queryParams['me'];
if (me) {
try {
ctx.session.me = await this.communication.validateProfile(me);
- } catch (e) {
+ } catch (e) { // eslint-disable-line no-unused-vars
ctx.session.me = undefined;
}
}
/**
* Ensure authenticated identifier matches profile.
- * @param {Object} ctx
- * @returns {Boolean}
+ * @param {object} ctx context
+ * @returns {boolean} is valid
*/
_profileValidForIdentifier(ctx) {
const _scope = _fileScope('_profileValidForIdentifier');
/**
* Get numeric value from form field data.
- * @param {*} ctx
- * @param {String} field
- * @param {String} customField
- * @returns {Number=}
+ * @param {*} ctx context
+ * @param {string} field field
+ * @param {string} customField custom field
+ * @returns {number=} lifespan
*/
_parseLifespan(ctx, field, customField) {
const _scope = _fileScope('_parseLifespan');
/**
* Validate any accepted scopes, ensure uniqueness, return as array.
- * @param {Object} ctx
- * @returns {String=}
+ * @param {object} ctx context
+ * @returns {string[]} scopes
*/
_parseConsentScopes(ctx) {
const _scope = _fileScope('_ingestConsentScopes');
/**
* Parse and validate selected me is a valid profile option.
- * @param {Object} ctx
- * @returns {URL}
+ * @param {object} ctx context
+ * @returns {URL} url
*/
_parseConsentMe(ctx) {
const _scope = _fileScope('_parseConsentMe');
/**
* Get up-to-date profile data from selected profile endpoint.
- * @param {Object} ctx
- * @returns {Promise<Object>}
+ * @param {object} ctx context
+ * @returns {Promise<object>} profile data
*/
async _fetchConsentProfileData(ctx) {
const _scope = _fileScope('_fetchConsentProfileData');
* expires-seconds - optional custom lifespan
* refresh - optional refresh lifespan
* refresh-seconds - optional custom refresh lifespan
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async postConsent(res, ctx) {
const _scope = _fileScope('postConsent');
/**
* Redeem a code for a profile url, and maybe more profile info.
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async postAuthorization(res, ctx) {
const _scope = _fileScope('postAuthorization');
/**
* Ingest an incoming authorization redemption request, parsing fields
* onto a new session object on the context.
- * @param {*} dbCtx
- * @param {Object} ctx
+ * @param {object} ctx context
+ * @returns {Promise<void>}
*/
async _ingestPostAuthorizationRequest(ctx) {
const _scope = _fileScope('_ingestPostAuthorizationRequest');
/**
* Unpack the session data from provided code overtop of context session ..
- * @param {Object} ctx
+ * @param {object} ctx context
*/
async _restoreSessionFromCode(ctx) {
const _scope = _fileScope('_restoreSessionFromCode');
/**
* Ensure provided client_id matches session clientId.
- * @param {Object} ctx
+ * @param {object} ctx context
*/
_checkSessionMatchingClientId(ctx) {
const _scope = _fileScope('_checkSessionMatchingClientId');
try {
clientId = new URL(clientId);
ctx.session.clientId = new URL(ctx.session.clientId);
- } catch (e) {
+ } catch (e) { // eslint-disable-line no-unused-vars
this.logger.debug(_scope, 'un-parsable client_id url', { ctx });
delete ctx.session.clientId;
Manager._setError(ctx, 'invalid_request', 'malformed client_id');
/**
- * @param {Object} ctx
+ * @param {object} ctx context
*/
_checkSessionMatchingRedirectUri(ctx) {
const _scope = _fileScope('_checkSessionMatchingClientId');
try {
redirectUri = new URL(redirectUri);
ctx.session.redirectUri = new URL(ctx.session.redirectUri);
- } catch (e) {
+ } catch (e) { // eslint-disable-line no-unused-vars
this.logger.debug(_scope, 'un-parsable redirect_uri url', { ctx });
delete ctx.session.redirectUri;
Manager._setError(ctx, 'invalid_request', 'malformed redirect_url');
/**
* Validate grant_type, either persist on session or set error.
- * @param {Object} ctx
- * @param {String[]} validGrantTypes
- * @param {Boolean} treatEmptyAs
+ * @param {object} ctx context
+ * @param {string[]} validGrantTypes grant types
+ * @param {string=} treatEmptyAs grant type
*/
_checkGrantType(ctx, validGrantTypes = ['authorization_code'], treatEmptyAs = 'authorization_code') {
const _scope = _fileScope('_checkGrantType');
/**
- * @param {Object} ctx
+ * @param {object} ctx context
*/
_checkSessionMatchingCodeVerifier(ctx) {
const _scope = _fileScope('_checkSessionMatchingCodeVerifier');
/**
* Attempt to revoke a token.
- * @param {*} dbCtx
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {*} dbCtx db context
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async _revokeToken(dbCtx, res, ctx) {
const _scope = _fileScope('_revokeToken');
/**
* Legacy token validation flow.
- * @param {*} dbCtx
- * @param {http.ClientRequest} req
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {*} dbCtx db context
+ * @param {http.ClientRequest} req request
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async _validateToken(dbCtx, req, res, ctx) {
const _scope = _fileScope('_validateToken');
/**
* Given a list of newly-requested scopes, return a list of scopes
* from previousScopes which are not in requestedScopes.
- * @param {String[]} previousScopes
- * @param {String[]} requestedScopes
- * @returns {String[]}
+ * @param {string[]} previousScopes scopes
+ * @param {string[]} requestedScopes scopes
+ * @returns {string[]} scopes
*/
static _scopeDifference(previousScopes, requestedScopes) {
const scopesToRemove = [];
/**
* Redeem a refresh token for a new token.
- * @param {*} dbCtx
- * @param {http.ClientRequest} req
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {*} dbCtx db context
+ * @param {http.ClientRequest} req request
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async _refreshToken(dbCtx, req, res, ctx) {
const _scope = _fileScope('_refreshToken');
/**
* Generate a new ticket for later redemption.
- * @param {Object} payload
- * @param {} payload.subject deliver ticket to this endpoint
- * @param {} payload.resource url the redeemed ticket is valid for accessing
- * @param {String[]} payload.scopes list of scopes assigned to ticket
- * @param {String} payload.identifier user generating ticket
- * @param {} payload.profile profile of user generating ticket
- * @param {Number} payload.ticketLifespanSeconds ticket redeemable for this long
- * @returns {Promise<String>}
- */
+ * @param {object} payload payload
+ * @param {string} payload.subject deliver ticket to this endpoint
+ * @param {string} payload.resource url the redeemed ticket is valid for accessing
+ * @param {string[]} payload.scopes list of scopes assigned to ticket
+ * @param {string} payload.identifier user generating ticket
+ * @param {string} payload.profile profile of user generating ticket
+ * @param {number} payload.ticketLifespanSeconds ticket redeemable for this long
+ * @returns {Promise<string>} ticket
+ */
async _mintTicket({ subject, resource, scopes, identifier, profile, ticketLifespanSeconds }) {
const _scope = _fileScope('_mintTicket');
this.logger.debug(_scope, 'called', { subject, resource, scopes, identifier, profile, ticketLifespanSeconds });
/**
* @typedef Ticket
- * @property {String} codeId
- * @property {Date} issued
- * @property {Date} expires
- * @property {URL} subject
- * @property {URL} resource
- * @property {String[]} scopes
- * @property {String} identifier
- * @property {URL} profile
+ * @property {string} codeId code id
+ * @property {Date} issued issued at
+ * @property {Date} expires expires at
+ * @property {URL} subject subject
+ * @property {URL} resource resource
+ * @property {string[]} scopes scopes
+ * @property {string} identifier identifier
+ * @property {URL} profile profile
*/
/**
*
- * @param {String} ticket
- * @returns {Promise<Ticket>}
+ * @param {string} ticket ticket
+ * @returns {Promise<Ticket>} ticket object
*/
async _unpackTicket(ticket) {
const ticketObj = await this.mysteryBox.unpack(ticket);
/**
* Redeem a ticket for a token.
- * @param {*} dbCtx
- * @param {http.ClientRequest} req
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {*} dbCtx db context
+ * @param {http.ClientRequest} req request
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
+ * @returns {Promise<void>}
*/
async _ticketAuthToken(dbCtx, req, res, ctx) {
const _scope = _fileScope('_ticketAuthToken');
/**
* Redeem a code for a token.
- * @param {*} dbCtx
- * @param {http.ClientRequest} req
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {*} dbCtx db context
+ * @param {http.ClientRequest} req request
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async _codeToken(dbCtx, req, res, ctx) {
const _scope = _fileScope('_codeToken');
/**
* Issue, refresh, or validate a token.
- * @param {http.ClientRequest} req
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {http.ClientRequest} req request
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async postToken(req, res, ctx) {
const _scope = _fileScope('postToken');
* Ingest token from authorization header, setting ctx.bearer.isValid appropriately.
* ctx.bearer not set if auth method not recognized.
* This is for legacy validation on token endpoint.
- * @param {*} dbCtx
- * @param {http.ClientRequest} req
- * @param {Object} ctx
+ * @param {*} dbCtx db context
+ * @param {http.ClientRequest} req request
+ * @param {object} ctx context
+ * @returns {Promise<void>}
*/
async _checkTokenValidationRequest(dbCtx, req, ctx) {
const _scope = _fileScope('_checkTokenValidationRequest');
};
try {
Object.assign(ctx.bearer, await this.mysteryBox.unpack(authString));
- } catch (e) {
+ } catch (e) { // eslint-disable-line no-unused-vars
this.logger.debug(_scope, 'failed to unpack token', { ctx });
Manager._setError(ctx, 'invalid_request', 'invalid token');
return;
/**
* Accept an unsolicited ticket proffering.
- * @param {http.ClientRequest} req
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {http.ClientRequest} req request
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async postTicket(req, res, ctx) {
const _scope = _fileScope('postTicket');
if (iss) {
try {
new URL(iss);
- } catch (e) {
+ } catch (e) { // eslint-disable-line no-unused-vars
this.logger.debug(_scope, 'unparsable issuer', { ticket, resource, subject, iss, ctx });
// continue, will try resource for metadata
}
}
try {
new URL(resource);
- } catch (e) {
+ } catch (e) { // eslint-disable-line no-unused-vars
this.logger.debug(_scope, 'unparsable resource', { ticket, resource, subject, ctx });
throw new ResponseError(Enum.ErrorResponse.BadRequest);
}
}
+ /**
+ * @typedef {object} AMQPChannel
+ * @property {Function} ack ack
+ */
/**
* Process messages from proffered ticket queue.
* Attempt to redeem ticket and publish to redeemed token queue.
- * @param {AMQPChannel} channel
- * @param {Buffer} message
+ * @param {AMQPChannel} channel channel
+ * @param {Buffer} message message
*/
async queuedTicketProcessor(channel, message) {
const _scope = _fileScope('queuedTicketProcessor');
let resourceUrlObj;
try {
resourceUrlObj = new URL(resource);
- } catch (e) {
+ } catch (e) { // eslint-disable-line no-unused-vars
this.logger.error(_scope, 'unparsable resource, discarding', { payload });
channel.ack(message);
return;
/**
* Validate a token and return data about it.
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async postIntrospection(res, ctx) {
const _scope = _fileScope('postIntrospection');
/**
* Revoke a token or refresh token.
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async postRevocation(res, ctx) {
const _scope = _fileScope('postRevocation');
/**
* Profile information for a token.
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async postUserInfo(res, ctx) {
const _scope = _fileScope('postUserInfo');
/**
* Show admin interface, allowing manipulation of profiles and scopes.
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async getAdmin(res, ctx) {
const _scope = _fileScope('getAdmin');
/**
* Process admin interface events.
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async postAdmin(res, ctx) {
const _scope = _fileScope('postAdmin');
/**
* Show ticket proffer interface.
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async getAdminTicket(res, ctx) {
const _scope = _fileScope('getAdminTicket');
/**
* Handle ticket proffer interface submission.
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async postAdminTicket(res, ctx) {
const _scope = _fileScope('postAdminTicket');
].forEach((param) => {
try {
ctx[param.ctxProp] = new URL(ctx.parsedBody[param.bodyParam]);
- } catch (e) {
+ } catch (e) { // eslint-disable-line no-unused-vars
this.logger.debug(_scope, `invalid ${param.bodyParam}`, { ctx });
ctx.errors.push(param.err);
}
/**
* Report on generally uninteresting backend information.
* Also allow a few event invocations.
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async getAdminMaintenance(res, ctx) {
const _scope = _fileScope('getAdminMaintenance');
/**
*
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async getHealthcheck(res, ctx) {
const _scope = _fileScope('getHealthcheck');
const { Dingus } = require('@squeep/api-dingus');
const common = require('./common');
const Manager = require('./manager');
-const { Authenticator, SessionManager } = require('@squeep/authentication-module');
-const { ResourceAuthenticator } = require('@squeep/resource-authentication-module');
+const { Authenticator, ResourceAuthenticator, SessionManager } = require('@squeep/authentication-module');
const { initContext, navLinks } = require('./template/template-helper');
const Enum = require('./enum');
const { ResponseError } = require('./errors');
const _fileScope = common.fileScope(__filename);
+/**
+ * @typedef {import('node:http')} http
+ */
+
class Service extends Dingus {
constructor(logger, db, options, asyncLocalStorage) {
super(logger, {
/**
* Do a little more on each request.
- * @param {http.IncomingMessage} req
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {http.IncomingMessage} req request
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async preHandler(req, res, ctx) {
const _scope = _fileScope('preHandler');
/**
- * @param {http.IncomingMessage} req
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {http.IncomingMessage} req request
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async handlerGetAdminLogin(req, res, ctx) {
const _scope = _fileScope('handlerGetAdminLogin');
/**
- * @param {http.IncomingMessage} req
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {http.IncomingMessage} req request
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async handlerPostAdminLogin(req, res, ctx) {
const _scope = _fileScope('handlerPostAdminLogin');
/**
- * @param {http.IncomingMessage} req
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {http.IncomingMessage} req request
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async handlerGetAdminSettings(req, res, ctx) {
const _scope = _fileScope('handlerGetAdminSettings');
/**
- * @param {http.IncomingMessage} req
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {http.IncomingMessage} req request
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async handlerPostAdminSettings(req, res, ctx) {
const _scope = _fileScope('handlerPostAdminSettings');
/**
- * @param {http.IncomingMessage} req
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {http.IncomingMessage} req request
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async handlerGetAdminLogout(req, res, ctx) {
const _scope = _fileScope('handlerGetAdminLogout');
/**
- * @param {http.IncomingMessage} req
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {http.IncomingMessage} req request
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async handlerGetAdmin(req, res, ctx) {
const _scope = _fileScope('handlerGetAdmin');
/**
- * @param {http.IncomingMessage} req
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {http.IncomingMessage} req request
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async handlerPostAdmin(req, res, ctx) {
const _scope = _fileScope('handlerPostAdmin');
/**
- * @param {http.IncomingMessage} req
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {http.IncomingMessage} req request
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async handlerGetAdminTicket(req, res, ctx) {
const _scope = _fileScope('handlerGetAdminTicket');
/**
- * @param {http.IncomingMessage} req
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {http.IncomingMessage} req request
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async handlerPostAdminTicket(req, res, ctx) {
const _scope = _fileScope('handlerPostAdminTicket');
/**
- * @param {http.IncomingMessage} req
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {http.IncomingMessage} req request
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async handlerGetMeta(req, res, ctx) {
const _scope = _fileScope('handlerGetMeta');
/**
- * @param {http.IncomingMessage} req
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {http.IncomingMessage} req request
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async handlerGetAuthorization(req, res, ctx) {
const _scope = _fileScope('handlerGetAuthorization');
/**
- * @param {http.IncomingMessage} req
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {http.IncomingMessage} req request
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async handlerPostAuthorization(req, res, ctx) {
const _scope = _fileScope('handlerPostAuthorization');
/**
- * @param {http.IncomingMessage} req
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {http.IncomingMessage} req request
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async handlerPostConsent(req, res, ctx) {
const _scope = _fileScope('handlerPostConsent');
/**
- * @param {http.IncomingMessage} req
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {http.IncomingMessage} req request
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async handlerPostTicket(req, res, ctx) {
const _scope = _fileScope('handlerPostTicket');
/**
- * @param {http.IncomingMessage} req
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {http.IncomingMessage} req request
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async handlerPostToken(req, res, ctx) {
const _scope = _fileScope('handlerPostToken');
/**
- * @param {http.IncomingMessage} req
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {http.IncomingMessage} req request
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async handlerPostRevocation(req, res, ctx) {
const _scope = _fileScope('handlerPostRevocation');
/**
- * @param {http.IncomingMessage} req
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {http.IncomingMessage} req request
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async handlerPostIntrospection(req, res, ctx) {
const _scope = _fileScope('handlerPostIntrospection');
/**
- * @param {http.IncomingMessage} req
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {http.IncomingMessage} req request
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async handlerPostUserInfo(req, res, ctx) {
const _scope = _fileScope('handlerPostUserInfo');
/**
- * @param {http.IncomingMessage} req
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {http.IncomingMessage} req request
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async handlerGetRoot(req, res, ctx) {
const _scope = _fileScope('handlerGetRoot');
/**
* Temporary to see what an unsolicited payload contains.
+ * @param {http.IncomingMessage} req request
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async handlerWhaGwan(req, res, ctx) {
this.setResponseType(this.responseTypes, req, res, ctx);
}
/**
- * @param {http.IncomingMessage} req
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {http.IncomingMessage} req request
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async handlerGetHealthcheck(req, res, ctx) {
const _scope = _fileScope('handlerGetHealthcheck');
/**
- * @param {http.IncomingMessage} req
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {http.IncomingMessage} req request
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async handlerGetAdminMaintenance(req, res, ctx) {
const _scope = _fileScope('handlerGetAdminMaintenance');
* Intercept this and redirect if we have enough information, otherwise default to framework.
* Fixing this will likely have to wait until an e2e test framework is in place.
* The redirect attempt should probably be contained in a Manager method, but here it is for now.
- * @param {http.IncomingMessage} req
- * @param {http.ServerResponse} res
- * @param {Object} ctx
+ * @param {http.IncomingMessage} req request
+ * @param {http.ServerResponse} res response
+ * @param {object} ctx context
*/
async handlerInternalServerError(req, res, ctx) {
const _scope = _fileScope('handlerInternalServerError');
const { sessionNavLinks } = require('@squeep/authentication-module');
+/**
+ *
+ * @param {string} profile profile
+ * @returns {string} li
+ */
function renderProfileLI(profile) {
return `\t<li><a class="uri" id="${profile}">${profile}</a></li>`;
}
+/**
+ *
+ * @param {string} profile profile
+ * @param {string} scope scope
+ * @param {boolean} selected is selected
+ * @returns {string} td
+ */
function renderProfileScopeIndicator(profile, scope, selected) {
const checked = selected ? ' checked' : '';
return `\t\t<td>
\t\t</td>`;
}
+/**
+ *
+ * @param {string} scope scope
+ * @param {object} details details
+ * @param {string[]} profiles profiles
+ * @returns {string} tr
+ */
function renderScopeRow(scope, details, profiles) {
return `\t<tr class="scope">
${(profiles || []).map((profile) => renderProfileScopeIndicator(profile, scope, details.profiles.includes(profile))).join('\n')}
}
+/**
+ *
+ * @param {string} profile profile
+ * @returns {string} th
+ */
function renderProfileHeader(profile) {
return `<th scope="col" class="vertical uri">
\t\t${profile}
}
+/**
+ *
+ * @param {object} scopeIndex scopes
+ * @param {string[]} profiles profiles
+ * @returns {string} table
+ */
function scopeIndexTable(scopeIndex, profiles) {
return `<table>
<thead>
</table>`;
}
+/**
+ *
+ * @param {object} token token
+ * @returns {string} type
+ */
function _tokenType(token) {
if (token.resource) {
return 'ticket-token';
return 'token';
}
+/**
+ *
+ * @param {object} token token
+ * @returns {string} tr
+ */
function renderTokenRow(token) {
const createdTitle = token.refreshed ? 'Refreshed At' : 'Created At';
const createdDate = token.refreshed ? token.refreshed : token.created;
\t\t</tr>`;
}
+/**
+ * @returns {string} tr
+ */
function noTokensRows() {
return [`\t\t<tr>
\t\t\t<td colspan="10" class="centered">(No active or recent tokens.)</td>
\t\t</tr>`];
}
+/**
+ *
+ * @param {object} tokens tokens
+ * @returns {string} table
+ */
function tokenTable(tokens) {
const tokenRows = tokens?.length ? tokens.map((token) => renderTokenRow(token)) : noTokensRows();
const formOpen = tokens?.length ? '<form method="POST">\n' : '';
</table>${formClose}`;
}
+/**
+ *
+ * @param {object} ctx context
+ * @returns {string} section
+ */
function mainContent(ctx) {
const profileList = (ctx.profilesScopes?.profiles || []).map((p) => renderProfileLI(p)).join('\n');
return `<section>
/**
*
- * @param {Object} ctx
- * @param {Object} ctx.profilesScopes.scopeIndex
- * @param {String[]} ctx.profilesScopes.profiles
- * @param {Object[]} ctx.tokens
- * @param {Object} options
- * @param {Object} options.manager
- * @param {String} options.manager.pageTitle
- * @param {String} options.manager.logoUrl
- * @param {String[]} options.manager.footerEntries
- * @returns {String}
+ * @param {object} ctx context
+ * @param {object} ctx.profilesScopes.scopeIndex scopes
+ * @param {string[]} ctx.profilesScopes.profiles profiles
+ * @param {object[]} ctx.tokens tokens
+ * @param {object} options options
+ * @param {object} options.manager manager options
+ * @param {string} options.manager.pageTitle page title
+ * @param {string} options.manager.logoUrl logo url
+ * @param {string[]} options.manager.footerEntries footer entries
+ * @returns {string} page
*/
module.exports = (ctx, options) => {
const pagePathLevel = 1;
const th = require('./template-helper');
const { sessionNavLinks } = require('@squeep/authentication-module');
+/**
+ *
+ * @param {object} entry entry
+ * @returns {string} tr
+ */
function renderAlmanacRow(entry) {
const { event, date } = entry;
return `<tr>
</tr>`;
}
+/**
+ *
+ * @param {object[]} almanac entries
+ * @returns {string} section
+ */
function almanacSection(almanac) {
return `<section>
\t<h2>Almanac</h2>
</section>`;
}
+/**
+ *
+ * @param {string} choreName name
+ * @param {object} choreDetails details
+ * @returns {string} tr
+ */
function renderChoreRow(choreName, choreDetails) {
const { intervalMs, nextSchedule } = choreDetails;
return `<tr>
</tr>`;
}
+/**
+ *
+ * @param {object} chores chores
+ * @returns {string} section
+ */
function choresSection(chores) {
return `<section>
\t<h2>Chores</h2>
/**
*
- * @param {Object} ctx
- * @param {Object[]} ctx.almanac
- * @param {Object} ctx.chores
- * @param {Object} options
- * @param {Object} options.manager
- * @param {String} options.manager.pageTitle
- * @param {String[]} options.manager.footerEntries
- * @param {String} options.adminContactHTML
- * @returns {String}
+ * @param {object} ctx context
+ * @param {object[]} ctx.almanac entries
+ * @param {object} ctx.chores chores
+ * @param {object} options options
+ * @param {object} options.manager manager options
+ * @param {string} options.manager.pageTitle page title
+ * @param {string[]} options.manager.footerEntries footer entires
+ * @returns {string} page
*/
module.exports = (ctx, options) => {
const pagePathLevel = 1;
const { sessionNavLinks } = require('@squeep/authentication-module');
+/**
+ *
+ * @param {string} profile profile
+ * @returns {string} option
+ */
function renderProfileOption(profile) {
return `<option value="${profile}">${profile}</option>`;
}
+/**
+ *
+ * @param {string} scope scope
+ * @returns {string} tr
+ */
function renderScopeCheckboxTR(scope) {
const defaultChecked = ['read'];
const checked = defaultChecked.includes(scope) ? ' checked' : '';
</tr>`;
}
+/**
+ *
+ * @param {object} ctx context
+ * @returns {string} section
+ */
function mainContent(ctx) {
const profileOptions = th.indented(4, (ctx?.profilesScopes?.profiles || []).map((profile) => renderProfileOption(profile)))
.join('\n');
/**
*
- * @param {Object} ctx
- * @param {Object} ctx.profilesScopes.scopeIndex
- * @param {String[]} ctx.profileScopes.profiles
- * @param {Object} options
- * @param {Object} options.manager
- * @param {String} options.manager.pageTitle
- * @param {String} options.manager.logoUrl
- * @param {String[]} options.manager.footerEntries
- * @returns {String}
+ * @param {object} ctx context
+ * @param {object} ctx.profilesScopes.scopeIndex scopes structure
+ * @param {string[]} ctx.profileScopes.profiles profile
+ * @param {object} options options
+ * @param {object} options.manager manager options
+ * @param {string} options.manager.pageTitle page title
+ * @param {string} options.manager.logoUrl logo url
+ * @param {string[]} options.manager.footerEntries footer entries
+ * @returns {string} page
*/
module.exports = (ctx, options) => {
const pagePathLevel = 1;
/**
*
- * @param {Object} ctx
- * @param {Object} ctx.session
- * @param {String=} ctx.session.error
- * @param {String[]=} ctx.session.errorDescriptions
- * @param {Object} options
- * @param {Object} options.manager
- * @param {String} options.manager.pageTitle
- * @param {String} options.manager.footerEntries
- * @returns {String}
+ * @param {object} ctx context
+ * @param {object} ctx.session session
+ * @param {string=} ctx.session.error errors
+ * @param {string[]=} ctx.session.errorDescriptions errors
+ * @param {object} options options
+ * @param {object} options.manager manager options
+ * @param {string} options.manager.pageTitle page title
+ * @param {string} options.manager.footerEntries footer entries
+ * @returns {string} page
*/
module.exports = (ctx, options) => {
const pagePathLevel = 0;
const { sessionNavLinks } = require('@squeep/authentication-module');
/**
- * @param {Object} hApp
- * @param {Object} hApp.properties
- * @param {String[]=} hApp.properties.url
- * @param {String[]=} hApp.properties.summary
- * @param {String[]=} hApp.properties.logo
- * @param {String[]=} hApp.properties.name
- * @returns {String}
+ * @param {object} hApp client identifier h-app
+ * @param {object} hApp.properties properties
+ * @param {string[]=} hApp.properties.url url
+ * @param {string[]=} hApp.properties.summary summary
+ * @param {string[]=} hApp.properties.logo logo
+ * @param {string[]=} hApp.properties.name name
+ * @returns {string} span
*/
function renderClientIdentifierProperties(hApp) {
const properties = hApp.properties || {};
/**
- * @param {Object} clientIdentifier
- * @param {Object[]} clientIdentifier.items
- * @returns {String}
+ * @param {object} clientIdentifier client identifier
+ * @param {object[]} clientIdentifier.items items
+ * @returns {string} spans
*/
function renderClientIdentifier(clientIdentifier) {
const hAppEntries = clientIdentifier?.items || [];
/**
- * @param {String} profile
- * @param {Boolean} selected
- * @returns {String}
+ * @param {string} profile profile
+ * @param {boolean} selected is selected
+ * @returns {string} option
*/
function renderProfileOption(profile, selected) {
return `<option value="${profile}"${selected ? ' selected' : ''}>${profile}</option>`;
/**
- * @param {String[]} availableProfiles
- * @param {String} hintProfile
- * @returns {String}
+ * @param {string[]} availableProfiles profiles
+ * @param {string} hintProfile profile
+ * @returns {string} fieldset
*/
function renderProfileFieldset(availableProfiles, hintProfile) {
if (!availableProfiles || availableProfiles.length <= 1) {
/**
- * @param {ScopeDetails} scope
- * @param {String} scope.scope
- * @param {String} scope.description
- * @param {String[]} scope.profiles
- * @param {Boolean} checked
- * @returns {String}
+ * @typedef {object} ScopeDetails
+ * @property {string} scope scope
+ * @property {string} description description
+ * @property {string[]} profiles profiles
+ */
+
+/**
+ * @param {ScopeDetails} scope scope details
+ * @param {boolean} checked is checked
+ * @returns {string} scope li
*/
function renderScopeCheckboxLI(scope, checked) {
let scopeDescription;
}
+/**
+ *
+ * @param {ScopeDetails[]=} requestedScopes scope details
+ * @returns {string} fieldset
+ */
function renderRequestedScopes(requestedScopes) {
if (!requestedScopes?.length) {
return '';
}
/**
- * @param {ScopeDetails[]} additionalScopes
- * @returns {String}
+ * @param {ScopeDetails[]} additionalScopes scopes
+ * @returns {string} fieldset
*/
function renderAdditionalScopes(additionalScopes) {
const parts = [];
/**
*
+ * @param {string[]} requestedScopes scopes
+ * @returns {string} fieldset
*/
function renderExpiration(requestedScopes) {
const tokenableScopes = requestedScopes.filter((s) => !['profile', 'email'].includes(s));
\t</fieldset>`;
}
+/**
+ *
+ * @param {string} name name
+ * @param {string} value value
+ * @param {string} label label
+ * @param {boolean} checked is checked
+ * @param {number} indent indent
+ * @returns {string} div
+ */
function radioButton(name, value, label, checked = false, indent = 0) {
const id = `${name}-${value}`;
return th.indented(indent, [
]).join('');
}
+/**
+ * @alias {object} ScopeIndex
+ */
+
/**
*
- * @param {Object} ctx
- * @param {Object[]} ctx.notifications
- * @param {Object} ctx.session
- * @param {String[]=} ctx.session.scope
- * @param {URL=} ctx.session.me
- * @param {String[]} ctx.session.profiles
- * @param {ScopeIndex} ctx.session.scopeIndex
- * @param {Object} ctx.session.clientIdentifier
- * @param {Object[]} ctx.session.clientIdentifier.items
- * @param {Object} ctx.session.clientIdentifier.items.properties
- * @param {String[]=} ctx.session.clientIdentifier.items.properties.url
- * @param {String[]=} ctx.session.clientIdentifier.items.properties.summary
- * @param {String[]=} ctx.session.clientIdentifier.items.properties.logo
- * @param {String[]=} ctx.session.clientIdentifier.items.properties.name
- * @param {String} ctx.session.clientId
- * @param {String} ctx.session.persist
- * @param {String} ctx.session.redirectUri
- * @param {Object} options
- * @returns {String}
+ * @param {object} ctx context
+ * @param {object[]} ctx.notifications notifications
+ * @param {object} ctx.session session
+ * @param {string[]=} ctx.session.scope scopes
+ * @param {URL=} ctx.session.me profile
+ * @param {string[]} ctx.session.profiles profiles
+ * @param {ScopeIndex} ctx.session.scopeIndex scopes structure
+ * @param {object} ctx.session.clientIdentifier client identifier
+ * @param {object[]} ctx.session.clientIdentifier.items items
+ * @param {object} ctx.session.clientIdentifier.items.properties properties
+ * @param {string[]=} ctx.session.clientIdentifier.items.properties.url url
+ * @param {string[]=} ctx.session.clientIdentifier.items.properties.summary sumamry
+ * @param {string[]=} ctx.session.clientIdentifier.items.properties.logo logo
+ * @param {string[]=} ctx.session.clientIdentifier.items.properties.name name
+ * @param {string} ctx.session.clientId client id
+ * @param {string} ctx.session.persist persist
+ * @param {string} ctx.session.redirectUri redirect
+ * @param {object} options options
+ * @returns {string} section
*/
function mainContent(ctx, options) { // eslint-disable-line no-unused-vars
const session = ctx.session || {};
return [
`<section class="information">
-\tThe application client ${renderClientIdentifier(session.clientIdentifier)} at <a class="uri" aria-label="client-identifier" id="${session.clientId}">${session.clientId}</a> would like to identify you as <a class="uri" aria-label="profile"${hintedProfile ? ' id="' + hintedProfile + '"' : ''}>${hintedProfile ? hintedProfile : '(unspecified)'}</a>.
+\tThe application client ${renderClientIdentifier(session.clientIdentifier)} at <a class="uri" aria-label="client-identifier" id="${session.clientId}">${session.clientId}</a> would like to identify you as <a class="uri" aria-label="profile"${hintedProfile ? ' id="' + hintedProfile + '"' : ''}>${hintedProfile || '(unspecified)'}</a>.
</section>
<section class="choices">
\t<form action="consent" method="POST" class="form-consent">`,
/**
*
- * @param {Object} ctx
- * @param {Object} ctx.session
- * @param {String[]=} ctx.session.scope
- * @param {URL=} ctx.session.me
- * @param {String[]} ctx.session.profiles
- * @param {ScopeIndex} ctx.session.scopeIndex
- * @param {Object} ctx.session.clientIdentifier
- * @param {String} ctx.session.clientId
- * @param {String} ctx.session.persist
- * @param {String} ctx.session.redirectUri
- * @param {Object} options
- * @param {Object} options.manager
- * @param {String} options.manager.pageTitle
- * @param {String} options.manager.footerEntries
- * @returns {String}
+ * @param {object} ctx context
+ * @param {object} ctx.session session object
+ * @param {string[]=} ctx.session.scope scopes
+ * @param {URL=} ctx.session.me url
+ * @param {string[]} ctx.session.profiles profiles
+ * @param {ScopeIndex} ctx.session.scopeIndex scopes structure
+ * @param {object} ctx.session.clientIdentifier client identifier
+ * @param {string} ctx.session.clientId client id
+ * @param {string} ctx.session.persist persist
+ * @param {string} ctx.session.redirectUri redirect url
+ * @param {object} options options
+ * @param {object} options.manager manager options
+ * @param {string} options.manager.pageTitle page title
+ * @param {string} options.manager.footerEntries footer entries
+ * @returns {string} page
*/
module.exports = (ctx, options) => {
const pagePathLevel = 0;
const th = require('./template-helper');
const { sessionNavLinks } = require('@squeep/authentication-module');
+/**
+ * @returns {string} section
+ */
function aboutSection() {
return `
<section class="about">
</section>`;
}
+/**
+ * @param {string} contactHTML content
+ * @returns {string} section
+ */
function contactSection(contactHTML) {
let section = '';
if (contactHTML) {
/**
*
- * @param {Object} ctx
- * @param {Object} options
- * @param {Object} options.manager
- * @param {String} options.manager.pageTitle
- * @param {String[]} options.manager.footerEntries
- * @param {String} options.adminContactHTML
- * @returns {String}
+ * @param {object} ctx context
+ * @param {object} options options
+ * @param {object} options.manager manager options
+ * @param {string} options.manager.pageTitle page title
+ * @param {string[]} options.manager.footerEntries footer entries
+ * @param {string=} options.adminContactHTML content
+ * @returns {string} page
*/
module.exports = (ctx, options) => {
const pagePathLevel = 0;
/**
* Escape a string to be suitable as a CSS name.
- * @param {String} unsafeName
- * @returns {String}
+ * @param {string} unsafeName unsafe name
+ * @returns {string} escaped name
*/
function escapeCSS(unsafeName) {
return unsafeName.replace(/([^0-9a-zA-Z-])/g, '\\$1');
* return the comparison between the two, for sorting.
* Scopes are sorted such that they are grouped by application, then name.
* Empty applications are sorted ahead of extant applications.
- * @param {Array} a
- * @param {Array} b
- * @returns {Number}
+ * @param {[string, object]} a [scopeName, scopeDetails]
+ * @param {[string, object]} b [scopeName, scopeDetails]
+ * @returns {number} comparison
*/
function scopeCompare([aScope, aDetails], [bScope, bDetails]) {
const { application: aApp } = aDetails;
/**
* Populate common navLinks for page templates.
- * @param {Number} pagePathLevel
- * @param {Object} ctx
- * @param {Object} options
+ * @param {number} pagePathLevel depth from root
+ * @param {object} ctx context
+ * @param {object} options options
*/
function navLinks(pagePathLevel, ctx, options) {
if (!options.navLinks) {
-/* eslint-env mocha */
-/* eslint-disable node/no-unpublished-require */
'use strict';
const assert = require('assert');
-/* eslint-env mocha */
+/* eslint-disable sonarjs/no-duplicate-string */
'use strict';
const assert = require('assert');
-const sinon = require('sinon'); // eslint-disable-line node/no-unpublished-require
+const sinon = require('sinon');
const StubDatabase = require('../../stub-db');
const StubLogger = require('../../stub-logger');
'use strict';
const assert = require('assert');
-const sinon = require('sinon'); // eslint-disable-line node/no-unpublished-require
+const sinon = require('sinon');
const Logger = require('@squeep/logger-json-console');
const DB = require('../../../src/db');
const DBErrors = require('../../../src/db/errors');
-/* eslint-env mocha */
-/* eslint-disable sonarjs/no-identical-functions */
+/* eslint-disable security/detect-object-injection */
'use strict';
/**
*/
const assert = require('assert');
-const { step } = require('mocha-steps'); // eslint-disable-line node/no-unpublished-require
+const { step } = require('mocha-steps');
const StubLogger = require('../../stub-logger');
// const DBErrors = require('../../../src/db/errors');
// const testData = require('../../test-data/db-integration');
-/* eslint-disable sonarjs/no-identical-functions */
-/* eslint-env mocha */
/* eslint-disable sonarjs/no-duplicate-string */
'use strict';
/* This provides implementation coverage, stubbing pg-promise. */
const assert = require('assert');
-const sinon = require('sinon'); // eslint-disable-line node/no-unpublished-require
+const sinon = require('sinon');
const StubLogger = require('../../stub-logger');
const StubDatabase = require('../../stub-db');
const DB = require('../../../src/db/postgres');
assert(db.db.batch.called);
});
it('failure', async function () {
- sinon.stub(db.db, 'tx').rejects(expectedException)
+ sinon.stub(db.db, 'tx').rejects(expectedException);
await assert.rejects(() => db._purgeTables(true), expectedException);
});
}); // _purgeTables
let event, date;
beforeEach(function () {
event = 'test_event';
- date = new Date('Fri Dec 22 03:27 UTC 2023')
+ date = new Date('Fri Dec 22 03:27 UTC 2023');
});
it('success', async function () {
const dbResult = {
duration: 22,
};
sinon.stub(db.db, 'result').resolves(dbResult);
- await db.resourceUpsert(dbCtx, resourceId, secret, description)
+ await db.resourceUpsert(dbCtx, resourceId, secret, description);
});
it('failure', async function () {
const dbResult = {
-/* eslint-env mocha */
'use strict';
const assert = require('assert');
-const sinon = require('sinon'); // eslint-disable-line node/no-unpublished-require
+const sinon = require('sinon');
const fs = require('fs');
const svh = require('../../../src/db/schema-version-helper');
.onCall(i++).returns(notDir) // 'init.sql'
.onCall(i++).returns(isDir).onCall(i++).returns(isMig) // '1.0.1'
.onCall(i++).returns(isDir).onCall(i++).returns(isMig) // '1.0.0'
+ ;
const result = svh.allSchemaVersions('path');
assert.deepStrictEqual(result, expected);
});
.onCall(i++).returns(notDir) // 'init.sql'
.onCall(i++).returns(isDir).onCall(i++).returns(isMig) // '1.0.1'
.onCall(i++).returns(isDir).onCall(i++).returns(isMig) // '1.0.0'
+ ;
const result = svh.unappliedSchemaVersions('path', current, supported);
assert.deepStrictEqual(result, expected);
});
}); // unappliedSchemaVersions
-});
\ No newline at end of file
+});
-/* eslint-disable sonarjs/no-identical-functions */
-/* eslint-env mocha */
/* eslint-disable sonarjs/no-duplicate-string */
'use strict';
/* This provides implementation coverage, stubbing parts of better-sqlite3. */
const assert = require('assert');
-const sinon = require('sinon'); // eslint-disable-line node/no-unpublished-require
+const sinon = require('sinon');
const StubDatabase = require('../../stub-db');
const StubLogger = require('../../stub-logger');
const DB = require('../../../src/db/sqlite');
db._optimize();
assert(db.db.pragma.called);
assert(db.statement._optimize.all.called);
- assert.strictEqual(db.changesSinceLastOptimize, 0n)
+ assert.strictEqual(db.changesSinceLastOptimize, 0n);
});
}); // _optimize
let event, date, dbResult;
beforeEach(function () {
event = 'test_event';
- date = new Date('Fri Dec 22 03:27 UTC 2023')
+ date = new Date('Fri Dec 22 03:27 UTC 2023');
sinon.stub(db.statement.almanacUpsert, 'run');
dbResult = {
changes: 1,
expires: new Date(refreshResponse.expires * 1000),
refreshExpires: new Date(refreshResponse.refreshExpires * 1000),
scopes: ['blah'],
- }
+ };
const response = db.refreshCode(dbCtx, codeId, refreshed, removeScopes);
assert.deepStrictEqual(response, expectedResponse);
});
const expectedResponse = {
expires: new Date(refreshResponse.expires * 1000),
refreshExpires: new Date(refreshResponse.refreshExpires * 1000),
- }
+ };
removeScopes = [];
const response = db.refreshCode(dbCtx, codeId, refreshed, removeScopes);
assert.deepStrictEqual(response, expectedResponse);
expires: new Date(refreshResponse.expires * 1000),
refreshExpires: new Date(refreshResponse.refreshExpires * 1000),
scopes: [],
- }
+ };
const response = db.refreshCode(dbCtx, codeId, refreshed, removeScopes);
assert.deepStrictEqual(response, expectedResponse);
});
sinon.stub(db.statement.scopeInUse, 'get');
dbGetResult = {
inUse: false,
- }
+ };
sinon.stub(db.statement.scopeDelete, 'run');
dbRunResult = {
changes: 1,
let dbResult, codeId;
beforeEach(function () {
codeId = '2f226616-3e79-11ec-ad0f-0025905f714a';
- sinon.stub(db.statement.tokenRevokeByCodeId, 'run')
+ sinon.stub(db.statement.tokenRevokeByCodeId, 'run');
dbResult = {
changes: 1,
lastInsertRowid: undefined,
const dbResultAlmanac = {
...dbResult,
changes: 0,
- }
+ };
db.statement.ticketTokenPublished.run.returns(dbResult);
db.statement.almanacUpsert.run.returns(dbResultAlmanac);
assert.throws(() => db.ticketTokenPublished(dbCtx, redeemedData), DBErrors.UnexpectedResult);
-/* eslint-env mocha */
+/* eslint-disable sonarjs/no-duplicate-string */
'use strict';
const assert = require('assert');
-const sinon = require('sinon'); // eslint-disable-line node/no-unpublished-require
+const sinon = require('sinon');
const Logger = require('../../src/logger');
const Config = require('../../config');
otpConfirmKey: '1234567890123456789012',
otpConfirmBox: 'xxxMysteryxxx',
otpState: 'xxxMysteryxxx',
- }
+ },
});
assert(logger.backend.info.called);
assert(!logger.backend.info.args[0][0].includes('"1234567890123456789012"'));
-/* eslint-env mocha */
-/* eslint-disable capitalized-comments, sonarjs/no-duplicate-string, sonarjs/no-identical-functions */
+/* eslint-disable sonarjs/no-duplicate-string */
'use strict';
const assert = require('assert');
-const sinon = require('sinon'); // eslint-disable-line node/no-unpublished-require
+const sinon = require('sinon');
const Manager = require('../../src/manager');
const Config = require('../../config');
manager.mysteryBox.unpack.resolves({});
req.getHeader.returns('Bearer XXX');
await manager._checkTokenValidationRequest(dbCtx, req, ctx);
- assert(ctx.session.error)
+ assert(ctx.session.error);
});
it('covers no token', async function () {
manager.mysteryBox.unpack.resolves({ c: 'xxx' });
req.getHeader.returns('Bearer XXX');
await manager._checkTokenValidationRequest(dbCtx, req, ctx);
- assert(ctx.session.error)
+ assert(ctx.session.error);
});
it('covers db error', async function () {
manager.mysteryBox.unpack.resolves({ c: 'xxx' });
-/* eslint-env mocha */
-/* eslint-disable capitalized-comments */
-
+/* eslint-disable sonarjs/no-duplicate-string */
'use strict';
const assert = require('assert');
-const sinon = require('sinon'); // eslint-disable-line node/no-unpublished-require
+const sinon = require('sinon');
const { AsyncLocalStorage } = require('node:async_hooks');
const StubDb = require('../stub-db');
});
}); // handlerWhaGwan
-});
\ No newline at end of file
+});
-/* eslint-env mocha */
+/* eslint-disable sonarjs/no-duplicate-string */
'use strict';
const assert = require('assert');
-/* eslint-env mocha */
+/* eslint-disable sonarjs/no-duplicate-string */
'use strict';
const assert = require('assert');
ctx.session = {
error: 'error_name',
errorDescriptions: ['something went wrong', 'another thing went wrong'],
- }
+ };
const result = template(ctx, config);
await lintHtml(result);
assert(result);
-/* eslint-env mocha */
+/* eslint-disable sonarjs/no-duplicate-string */
'use strict';
const assert = require('assert');
-/* eslint-disable security/detect-object-injection */
'use strict';
-const { StubDatabase: Base } = require('@squeep/test-helper'); // eslint-disable-line node/no-unpublished-require
+const { StubDatabase: Base } = require('@squeep/test-helper');
class StubDatabase extends Base {
get _stubFns() {
'use strict';
-const { StubLogger: Base } = require('@squeep/test-helper'); // eslint-disable-line node/no-unpublished-require
+const { StubLogger: Base } = require('@squeep/test-helper');
class StubLogger extends Base {
}
-module.exports = StubLogger;
\ No newline at end of file
+module.exports = StubLogger;