Compare commits

...

5 Commits

12 changed files with 251 additions and 188 deletions

View File

@ -6,7 +6,8 @@ import { modal } from '../partials/modal';
export const resultDetails = (searchController, result, emit = () => {}) => {
const { __ } = searchController.i18n;
const modalId = `result_${result.uri}`;
const source = result.sources[0];
const modalId = `result_${source.uri}`;
const hasReviews = typeof result.averageRating !== 'undefined' && typeof result.numberOfReviews !== 'undefined';
@ -27,37 +28,41 @@ export const resultDetails = (searchController, result, emit = () => {}) => {
const tabNames = ['one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen', 'seventeen', 'eighteen', 'nineteen', 'twenty'];
const coversHTMLArray = result.covers.map((cover, index, allCovers) => {
return html`<div>
<img src=${cover.url} alt="${cover.sourceId.replace(':', ' ').toUpperCase()}, Published: ${cover.publishDate}">
${typeof allCovers[index - 1] === 'undefined'
? null
: html`<label class="button" for="cover_${allCovers[index - 1].sourceId}" style="margin-right:8px;">
${'<'}
</label>`
}
${typeof allCovers[index + 1] === 'undefined'
? null
: html`<label class="button" for="cover_${allCovers[index + 1].sourceId}">
${'>'}
</label>`
}
</div>`;
});
const modalContent = html`<article class="flex">
<div class="sixth-700" style="text-align:center;">
<h4>${__('search.covers')}</h4>
${typeof result.covers === 'undefined'
? html`<span style="font-size:3em;"><i class="icon-loading animate-spin"></i></span>`
: html`<div class="tabs ${typeof tabNames[result.covers.length - 1] !== 'undefined' ? tabNames[result.covers.length - 1] : null}">
: html`<div class="tabs ${typeof tabNames[result.covers.length - 1] !== 'undefined' ? tabNames[result.covers.length - 1] : tabNames[19]}">
${result.covers.map((cover, index) => {
return [
html`<input id="cover_${cover.uri}" type="radio" name="${modalId}_covers" ${index === 0 ? 'checked' : null} />`,
// html`<label class="small pseudo button toggle" for="cover_${cover.uri}">•</label>`,
html`<input id="cover_${cover.sourceId}" type="radio" name="${modalId}_covers" ${index === 0 ? 'checked' : null} />`,
// html`<label class="small pseudo button toggle" for="cover_${cover.sourceId}">•</label>`,
];
})}
<div class="row">
${result.covers.map((cover, index, allCovers) => {
return html`<div>
<img src=${cover.url} alt="${cover.uri.replace(':', ' ').toUpperCase()}, Published: ${cover.publishDate}">
${typeof allCovers[index - 1] === 'undefined'
? null
: html`<label class="button" for="cover_${allCovers[index - 1].uri}" style="margin-right:8px;">
${'<'}
</label>`
}
${typeof allCovers[index + 1] === 'undefined'
? null
: html`<label class="button" for="cover_${allCovers[index + 1].uri}">
${'>'}
</label>`
}
</div>`;
})}
</div>
<div class="row" id="covers_${modalId}">${
searchController.openModal === modalId
? coversHTMLArray
: '' /* Leave the covers column empty until opened to prevent loading too many images */
}</div>
</div>`
}
</div>
@ -72,7 +77,7 @@ export const resultDetails = (searchController, result, emit = () => {}) => {
<h4>Top Reviews</h4>
</div>
<div>
<a href="/book/${result.uri}" class="small button">
<a href="/book/${source.uri}" class="small button">
<span style="margin-right:8px;"><i class="icon-chat"></i></span>
<span>${result.numberOfReviews}</span>
<span>${__('search.see_interaction_details')}</span>
@ -92,27 +97,29 @@ export const resultDetails = (searchController, result, emit = () => {}) => {
</p>
${!searchController.showShelves ? null : html`<ul>${searchController.shelves.map(shelf => {
return html`<li>
<button class="pseudo" onclick=${() => searchController.addToShelf({source: 'inventaire', uri: result.uri}, shelf.id)}>
<button class="pseudo" onclick=${() => searchController.addToShelf({ id: result.id, ...source }, shelf.id)}>
${shelf.name}
</button>
</li>`;
})}</ul>`}
<p>
<a class="small button" href=${result.link} target="_blank">
<a class="small button" href=${source.link} target="_blank">
${__('search.see_book_details')}
</a>
</p>
</div>
</article>`;
const onShow = () => {
const coversColumn = document.getElementById(`covers_${modalId}`);
coversColumn.innerHTML = '';
coversHTMLArray.forEach(element => coversColumn.appendChild(element));
};
return modal(modalId, searchController, modalContent, {
styles: "width:90%;",
buttonHTML, // This should be replaced with buttonHTML containing the ratings and number of reviews etc.
headerText: result.name,
onShow: () => {
if (typeof result.covers === 'undefined') {
searchController.getCovers(result.uri).then(() => emit('render'));
}
},
onShow,
});
}

View File

@ -20,8 +20,8 @@
},
"devDependencies": {
"choo-devtools": "^3.0.3",
"concurrently": "^5.1.0",
"faker": "^4.1.0",
"concurrently": "^5.3.0",
"faker": "^5.0.0",
"onchange": "^7.0.2",
"rimraf": "^3.0.1",
"sequelize-erd": "https://github.com/Alamantus/sequelize-erd.git"
@ -31,13 +31,13 @@
"babel-polyfill": "^6.26.0",
"choo": "^7.1.0",
"cross-env": "^7.0.2",
"fastify": "^3.1.1",
"fastify": "^3.2.1",
"fastify-caching": "^6.0.1",
"fastify-compress": "^3.2.2",
"fastify-compress": "^3.3.0",
"fastify-cookie": "^4.0.2",
"fastify-helmet": "^5.0.0",
"fastify-helmet": "^5.0.1",
"fastify-jwt": "^2.1.3",
"fastify-plugin": "^2.1.1",
"fastify-plugin": "^2.3.2",
"fastify-static": "^3.2.0",
"make-promises-safe": "^5.1.0",
"marked": "^1.1.1",
@ -46,7 +46,7 @@
"nodemailer": "^6.4.11",
"parcel-bundler": "^1.12.4",
"parcel-plugin-goodie-bag": "^2.0.0",
"pg": "^8.3.0",
"pg": "^8.3.2",
"pg-hstore": "^2.3.3",
"picnic": "^6.5.2",
"sass": "^1.26.10",

View File

@ -15,6 +15,7 @@ class Inventaire {
static handleQuickEntity(entityObject) {
return {
id: null,
name: (
typeof entityObject.label !== 'undefined'
? entityObject.label
@ -25,22 +26,26 @@ class Inventaire {
? entityObject.description
: null
),
source: 'inventaire',
link: (
typeof entityObject.uri !== 'undefined'
? `${Inventaire.url}/entity/${entityObject.uri}`
: null
),
uri: (
typeof entityObject.uri !== 'undefined'
? entityObject.uri
: null
),
sources: [
{
source: 'inventaire',
uri: (
typeof entityObject.uri !== 'undefined'
? entityObject.uri
: null
),
link: (
typeof entityObject.uri !== 'undefined'
? `${Inventaire.url}/entity/${entityObject.uri}`
: null
),
},
],
covers: (
typeof entityObject.image !== 'undefined'
? entityObject.image.map(imageId => {
return {
uri: imageId.toString(),
sourceId: imageId.toString(),
url: `${Inventaire.url}/img/entities/${imageId}`,
}
})
@ -72,17 +77,21 @@ class Inventaire {
: null
)
),
source: 'inventaire',
link: (
typeof entityObject.uri !== 'undefined'
? `${Inventaire.url}/entity/${entityObject.uri}`
: null
),
uri: (
typeof entityObject.uri !== 'undefined'
? entityObject.uri
: null
),
sources: [
{
source: 'inventaire',
uri: (
typeof entityObject.uri !== 'undefined'
? entityObject.uri
: null
),
link: (
typeof entityObject.uri !== 'undefined'
? `${Inventaire.url}/entity/${entityObject.uri}`
: null
),
},
],
};
}
@ -105,11 +114,11 @@ class Inventaire {
}
});
const bookData = await json;
let bookData = await json;
if (typeof bookData.entities !== 'undefined' && typeof bookData.entities[uri] !== 'undefined') {
const bookData = Inventaire.handleEntity(bookData.entities[uri], this.lang);
bookData['covers'] = await this.getCovers(bookData.uri);
bookData = Inventaire.handleEntity(bookData.entities[uri], this.lang);
bookData['covers'] = await this.getCovers(bookData.sources[0].uri);
return bookData;
}
@ -126,7 +135,7 @@ class Inventaire {
}
// Note: property `wdt:P629` is a given entity (uri)'s list of editions (ISBNs).
const editionsRequest = fetch(`${Inventaire.url}/api/entities?action=reverse-claims&uri=${encodeURIComponent(uri)}&property=wdt:P629`)
const editionsRequest = fetch(`${Inventaire.url}/api/entities?action=reverse-claims&value=${encodeURIComponent(uri)}&property=wdt:P629`)
editionsRequest.catch(exception => {
console.error(exception);
return {
@ -180,7 +189,7 @@ class Inventaire {
}).map(key => {
const entity = responseJSON.entities[key];
return {
uri: entity.uri,
sourceId: entity.uri,
url: typeof entity.claims['invp:P2'] !== 'undefined' ? `${Inventaire.url}/img/entities/${entity.claims['invp:P2'][0]}` : null,
publishDate: typeof entity.claims['wdt:P577'] !== 'undefined' ? entity.claims['wdt:P577'][0] : null,
}

View File

@ -93,27 +93,6 @@ class BooksController {
),
};
}
async createBookReference (bookReferencesModel, source, uri) {
const inventaire = new Inventaire(this.language);
const bookData = await inventaire.getBookData(uri);
return await bookReferencesModel.create({
values: {
name: bookData.name,
description: bookData.description,
sources: {
[source]: uri,
},
covers: bookData.covers.map(cover => {
return {
sourceId: uri,
url: cover.url,
};
}),
locale: this.language,
}
});
}
}
module.exports = BooksController;

View File

@ -7,12 +7,14 @@ class BookReferenceController {
this.lang = language;
}
async createOrUpdateReference(source, sourceId) {
async createOrUpdateReference(source, sourceId, skipSearchBySourceCodes = false) {
const searchController = new SearchController(this.models);
const existingReference = searchController.searchReferencesBySourceCode(source, sourceId);
if (!skipSearchBySourceCodes) {
const existingReferences = await searchController.searchReferencesBySourceCodes(source, [sourceId]);
if (existingReference.id !== null) {
return existingReference;
if (existingReferences.length > 0) {
return existingReferences[0];
}
}
let dataClass;
@ -28,15 +30,15 @@ class BookReferenceController {
}
// Get formatted book data from source
const bookData = dataClass.getBookData(sourceId);
const bookData = await dataClass.getBookData(sourceId);
if (typeof bookData.uri !== 'undefined') {
if (typeof bookData.sources[0].uri !== 'undefined') {
// Check for references by exact name and author from source
const matchingReference = await searchController.searchReferencesForExactMatch(bookData.name, bookData.description);
const matchingReferences = await searchController.searchReferencesForExactMatch(bookData.name, bookData.description);
if (matchingReference.id !== null) {
if (matchingReferences.length > 0) {
// If a match is found, update the sources of reference in the database and return it.
return await this.addSourceToReference(matchingReference, source, sourceId);
return await this.addSourceToReference(matchingReferences[0], source, sourceId);
}
return await this.createReference(bookData, source, sourceId);
@ -57,12 +59,12 @@ class BookReferenceController {
covers: bookData.covers,
locale: this.lang,
});
newReference.totalInteractions = 0;
newReference.numReviews = 0;
newReference.averageRating = null;
newReference.Interactions = [];
newReference.Reviews = [];
newReference.Ratings = [];
// newReference.totalInteractions = 0;
// newReference.numReviews = 0;
// newReference.averageRating = null;
// newReference.Interactions = [];
// newReference.Reviews = [];
// newReference.Ratings = [];
return newReference;
}

View File

@ -43,7 +43,14 @@ function searchInventaire(searchTerm, language) {
message: 'An error occurred when trying read the response from Inventaire as JSON.',
}
});
return json.then(responseJSON => responseJSON.results.map(work => Inventaire.handleEntity(work, language)));
return json.then(responseJSON => {
return responseJSON.results.map(async work => {
const inventaire = new Inventaire(langauge);
const bookData = Inventaire.handleEntity(work, language);
bookData['covers'] = await inventaire.getCovers(bookData.sources[0].uri);
return bookData;
});
});
}
}

View File

@ -3,6 +3,7 @@ const { Op, fn, col } = require('sequelize');
const BooksController = require('../bookData');
const { quickSearchInventaire } = require('./Inventaire');
const Inventaire = require('../bookData/Inventaire');
const defaultSearchOptions = {
searchBy: 'name', // A column name in the BookReference model, mainly 'name' or 'description'
@ -57,6 +58,30 @@ class SearchController {
};
}
static formatReferenceSources(reference) {
const referenceSources = Object.keys(reference.sources);
const reformattedSources = referenceSources.map(source => {
const uri = reference.sources[source];
let link;
switch (source) {
default:
case 'inventaire': {
link = `${Inventaire.url}/entity/${uri}`
break;
}
}
return {
source,
uri,
link,
}
});
reference.sources = reformattedSources;
return reference;
}
async search(searchTerm, options = defaultSearchOptions) {
const searchBy = options.searchBy.replace('title', 'name').replace('author', 'description');
const { source, language } = options;
@ -77,22 +102,23 @@ class SearchController {
// Add any search results that match refs with the same URI and delete from results array
const urisToCheck = searchResults.filter(
result => !bookReferences.some(ref => result.uri === ref.sources[source])
).map(result => result.uri);
result => !bookReferences.some(ref => result.sources[0].uri === ref.sources[source])
).map(result => result.sources[0].uri);
let extraReferences = [];
if (urisToCheck.length > 0) {
// Need to figure this out
extraReferences = await this.searchReferencesBySourceCodes(source, urisToCheck);
}
searchResults = searchResults.filter( // Only show the rest of the search results
result => !extraReferences.some(
ref => result.sources[0].uri === ref.sources[source]
)
);
return [
...bookReferences,
...extraReferences,
...searchResults.filter( // Only show the rest of the search results
result => !extraReferences.some(
ref => result.uri === ref.sources[source]
)
),
...bookReferences.map(match => SearchController.formatReferenceSources(match)),
...extraReferences.map(match => SearchController.formatReferenceSources(match)),
...searchResults,
];
}
@ -142,15 +168,11 @@ class SearchController {
);
}
async searchReferencesBySourceCode(source, sourceId) {
const sourceJSONKey = `"${source}"`; // Enable searching withing JSON column.
return await this.models.BookReference.findOne({
async searchReferencesForExactMatch(name, description) {
return await this.models.BookReference.findAll({
where: {
sources: {
[sourceJSONKey]: { // Where the object key is the source
[Op.eq]: sourceId,
},
},
name,
description,
},
...this.bookReferenceSearchAttributes,
}).then( // Empty results give 1 empty model in an array, so filter those out

View File

@ -1,4 +1,5 @@
const fetch = require('node-fetch');
const BookReferenceController = require('./bookReference');
class ShelfController {
constructor (sequelizeModels, language) { // Language needs to be passed with every request involving books.

View File

@ -15,7 +15,21 @@ const fastify = require('fastify')({
logger: process.env.NODE_ENV !== 'production',
});
fastify.decorate('siteConfig', siteConfig); // Insert siteConfig into global fastify instance
fastify.register(require('fastify-helmet')); // Add security stuff
fastify.register(require('fastify-helmet'), { // Add security stuff
contentSecurityPolicy: { // Modify Content Security Policy headers to allow content from specific domains
directives: {
'default-src': ["'self'"], // Default value
'base-uri': ["'self'"], // Default value
'block-all-mixed-content': [], // Default value
'frame-ancestors': ["'self'"], // Default value
'style-src': ["'self'", "https: 'unsafe-inline'"], // Default value
'upgrade-insecure-requests': [], // Default value
'object-src': ["'none'"], // Default value
'script-src': ["'self'", 'polyfill.io', "https: 'unsafe-inline'"], // Allow loading scripts inline (required for Choo) and from polyfill.io
'img-src': ["'self'", siteConfig.inventaireDomain, 'openlibrary.org', 'covers.openlibrary.org', "data:"], // Allow images from Inventaire, Open Library, and raw `data:` hashes
}
}
});
fastify.register(require('fastify-compress')); // Compress output data for smaller packet delivery
fastify.register(require('fastify-static'), { // Enable delivering static content efficiently
root: path.resolve(__dirname, '../public'), // all static content will be delivered from the public/ folder

View File

@ -1,5 +1,6 @@
const BooksController = require('../controllers/bookData');
const SearchController = require('../controllers/search');
const BookReferenceController = require('../controllers/bookReference');
async function routes(fastify, options) {
fastify.get('/api/books', async (request, reply) => {
@ -39,9 +40,8 @@ async function routes(fastify, options) {
return existingBookReferences[0].id;
}
const books = new BooksController(request.body.source, request.body.uri, request.language);
const newBookReference = await books.createBookReference(request.body.source, request.body.uri);
console.log('created new bookreference', newBookReference);
const bookReference = new BookReferenceController(fastify.models, request.language);
const newBookReference = await bookReference.createOrUpdateReference(request.body.source, request.body.uri, true);
return newBookReference.id;
});
}

View File

@ -188,10 +188,11 @@ async function routes(fastify, options) {
});
}
const shelf = await request.user.getShelf({
const shelf = (await request.user.getShelves({
where: { id: request.body.shelfId },
include: [ fastify.models.ShelfItem ],
});
limit: 1,
}))[0];
if (!ShelfController.userOwnsShelf(request.user, shelf)) {
return reply.code(403).send({

145
yarn.lock
View File

@ -1026,7 +1026,17 @@ acorn@^7.0.0, acorn@^7.1.1:
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.0.tgz#e1ad486e6c54501634c6c397c5c121daa383607c"
integrity sha512-+G7P8jJmCHr+S+cLfQxygbWhXy+8YTVGzAkpEbcLo2mLoL7tij/VG41QSHACSf5QgYRhMZYHuNc6drJaO0Da+w==
ajv@^6.11.0, ajv@^6.12.2, ajv@^6.12.3:
ajv@^6.11.0, ajv@^6.12.2:
version "6.12.4"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.4.tgz#0614facc4522127fa713445c6bfd3ebd376e2234"
integrity sha512-eienB2c9qVQs2KWexhkrdMLVDoIQCz5KSeLxwg9Lzk4DOfBtIK9PQwwufcsn1jjGuf9WZmqPMbGxOzfcuphJCQ==
dependencies:
fast-deep-equal "^3.1.1"
fast-json-stable-stringify "^2.0.0"
json-schema-traverse "^0.4.1"
uri-js "^4.2.2"
ajv@^6.12.3:
version "6.12.3"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.3.tgz#18c5af38a111ddeb4f2697bd78d68abc1cabd706"
integrity sha512-4K0cK3L1hsqk9xIb2z9vs/XU+PGJZ9PNpJRDS9YLzmNdX6jmVPfamLvTJr0aDAusnHyCHO6MjzlkAsgtqp9teA==
@ -1934,10 +1944,10 @@ concat-stream@~1.6.0:
readable-stream "^2.2.2"
typedarray "^0.0.6"
concurrently@^5.1.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-5.2.0.tgz#ead55121d08a0fc817085584c123cedec2e08975"
integrity sha512-XxcDbQ4/43d6CxR7+iV8IZXhur4KbmEJk1CetVMUqCy34z9l0DkszbY+/9wvmSnToTej0SYomc2WSRH+L0zVJw==
concurrently@^5.3.0:
version "5.3.0"
resolved "https://registry.yarnpkg.com/concurrently/-/concurrently-5.3.0.tgz#7500de6410d043c912b2da27de3202cb489b1e7b"
integrity sha512-8MhqOB6PWlBfA2vJ8a0bSFKATOdWlHiQlk11IfmQBPaHVP8oP2gsh2MObE6UR3hqDHqvaIvLTyceNW6obVuFHQ==
dependencies:
chalk "^2.4.2"
date-fns "^2.0.1"
@ -2819,10 +2829,10 @@ extsprintf@^1.2.0:
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=
faker@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/faker/-/faker-4.1.0.tgz#1e45bbbecc6774b3c195fad2835109c6d748cc3f"
integrity sha1-HkW7vsxndLPBlfrSg1EJxtdIzD8=
faker@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/faker/-/faker-5.0.0.tgz#ceaf8120e37994007d6fb0e73479bef0406bfe74"
integrity sha512-wBY77PYhJOqq2cji+l8Gc8HWW7rKlwJvJgV/fbanGlm92/MImBGX51VLQN/DbDvzexmt+EFjQ4SeytCb45AJ1g==
falafel@^2.1.0:
version "2.2.4"
@ -2834,7 +2844,7 @@ falafel@^2.1.0:
isarray "^2.0.1"
object-keys "^1.0.6"
fast-decode-uri-component@^1.0.0:
fast-decode-uri-component@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz#46f8b6c22b30ff7a81357d4f59abfae938202543"
integrity sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==
@ -2901,13 +2911,13 @@ fastify-caching@^6.0.1:
fastify-plugin "^2.0.0"
uid-safe "^2.1.5"
fastify-compress@^3.2.2:
version "3.2.2"
resolved "https://registry.yarnpkg.com/fastify-compress/-/fastify-compress-3.2.2.tgz#5d4cd0b0756f3664d4635f389b26b098fe2ecbd8"
integrity sha512-i4HSMIAcWnHvktlC+HI24luGHaO6mTJTDiuzQU6lTxV2QdEXmNxVMWxekm3JAaNBzS+hBuON3fvyWT58AN3MHw==
fastify-compress@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/fastify-compress/-/fastify-compress-3.3.0.tgz#83c4965048d77e9469128de25f77064b38bad06e"
integrity sha512-g/q7g9JaN14pVe7Op8zwKD/MxyBBXjLkK8Y6UtcwRDwufAlqLO1jZ/srM5JTly5AKnXPnX6ft9Nz/83xYNltrQ==
dependencies:
encoding-negotiator "^2.0.0"
fastify-plugin "^2.0.0"
fastify-plugin "^2.2.0"
into-stream "^5.1.1"
is-deflate "^1.0.0"
is-gzip "^2.0.0"
@ -2930,17 +2940,17 @@ fastify-cookie@^4.0.2:
cookie-signature "^1.1.0"
fastify-plugin "^2.0.0"
fastify-error@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/fastify-error/-/fastify-error-0.1.0.tgz#7ca9d3708a2b1a74aefed0e5dde1b96d0390f718"
integrity sha512-jyCEc3VPEc8/PUwzDQAM2JlXLK2BG6L19mMJzbGij0TfdY1sHF9pCnnAn6Vcoi84TMTBOJynNDQUMUz6cjRmBw==
fastify-error@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/fastify-error/-/fastify-error-0.2.0.tgz#9a1c28d4f42b6259e7a549671c8e5e2d85660634"
integrity sha512-zabxsBatj59ROG0fhP36zNdc5Q1/eYeH9oSF9uvfrurZf8/JKfrJbMcIGrLpLWcf89rS6L91RHWm20A/X85hcA==
fastify-helmet@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/fastify-helmet/-/fastify-helmet-5.0.0.tgz#a8019f009237ca23ccc0aeca72ffc33d8988b781"
integrity sha512-kE5qEflGkSu0RRE3WNdt9XMkU2X6zb85jYLW2TKIL7r0p+JJmqaW24xsD248Bn5hfPxDfKSBqCj6MoaLIqYzTw==
fastify-helmet@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/fastify-helmet/-/fastify-helmet-5.0.1.tgz#1267e1797e4d4022f1be601c4b534849576be624"
integrity sha512-e9SVR5n4oRDqn0NCPMjK8AZvEVUsQTittlQ/Pj3IJ0CMNRciOe6NwXiglVpRICU625EStgOqgmWOoWD2nUJNKQ==
dependencies:
fastify-plugin "^2.0.3"
fastify-plugin "^2.1.1"
helmet "^4.0.0"
fastify-jwt@^2.1.3:
@ -2954,10 +2964,10 @@ fastify-jwt@^2.1.3:
jsonwebtoken "^8.3.0"
steed "^1.1.3"
fastify-plugin@^2.0.0, fastify-plugin@^2.0.3, fastify-plugin@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/fastify-plugin/-/fastify-plugin-2.1.1.tgz#1261e3a07c80a9f5a884f3b471e59a5157753232"
integrity sha512-U0gBig5qOm6zfq7qrEek3eKGBwn2ipUDvQqB+k5YfkA3/RkU0bhfQPcRxPQqEz2SYQP9pQ2ZgLaL4bxxnCxn+w==
fastify-plugin@^2.0.0, fastify-plugin@^2.1.1, fastify-plugin@^2.2.0, fastify-plugin@^2.3.2:
version "2.3.2"
resolved "https://registry.yarnpkg.com/fastify-plugin/-/fastify-plugin-2.3.2.tgz#e8a30cae45e1f6b6e02b467eaee866a3459174f1"
integrity sha512-oii9LhQmbrEXDyTPDad59kZwSLN++ql9UE6+JWZLyPyibGrgYQPVu/sPJ1qhg68+76gk3MCWBjFX/Nhn/1wTxg==
dependencies:
semver "^7.3.2"
@ -2971,16 +2981,22 @@ fastify-static@^3.2.0:
readable-stream "^3.4.0"
send "^0.17.1"
fastify@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.1.1.tgz#0a830f4a929abd7f2b05c08620a609a104300a36"
integrity sha512-A7kBZIFAdpE/8MZ9qHpQV9IVPpfX63uWMaPN4p0fetax10C2p56iV/VEB5hOgtlXzayGn+4tf+tNHcZsfrjlnA==
fastify-warning@^0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/fastify-warning/-/fastify-warning-0.2.0.tgz#e717776026a4493dc9a2befa44db6d17f618008f"
integrity sha512-s1EQguBw/9qtc1p/WTY4eq9WMRIACkj+HTcOIK1in4MV5aFaQC9ZCIt0dJ7pr5bIf4lPpHvAtP2ywpTNgs7hqw==
fastify@^3.2.1:
version "3.2.1"
resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.2.1.tgz#119250e50a3f49e1a8036a4abaebef9823b0db1c"
integrity sha512-2y2qZzS4bqD1cwaX72ot8DjjUFqqxn/SbgKN1xe4vH2HVy7c6u++6IY8HzBRWJv38p3WiBogLWAObxaISxUlJg==
dependencies:
abstract-logging "^2.0.0"
ajv "^6.12.2"
avvio "^7.1.2"
fast-json-stringify "^2.2.1"
fastify-error "^0.1.0"
fastify-error "^0.2.0"
fastify-warning "^0.2.0"
find-my-way "^3.0.0"
flatstr "^1.0.12"
light-my-request "^4.0.0"
@ -3047,11 +3063,11 @@ fill-range@^7.0.1:
to-regex-range "^5.0.1"
find-my-way@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/find-my-way/-/find-my-way-3.0.1.tgz#3df89fd2b145446c09291e1fd0bb67af1177deda"
integrity sha512-tHUHIRGTcfl3phGKLZeD2Xkb+I0QZr4xduSwCJG5Ke11pdJTGuMDtAyAiJzUdWBZJgHA0H42Pb0WF3H321KbRA==
version "3.0.4"
resolved "https://registry.yarnpkg.com/find-my-way/-/find-my-way-3.0.4.tgz#a485973d1a3fdafd989ac9f12fd2d88e83cda268"
integrity sha512-Trl/mNAVvTgCpo9ox6yixkwiZUvecKYUQZoAuMCBACsgGqv+FbWe+jE5sBA5+U8LIWrJk/cw8zPV53GPrjTnsw==
dependencies:
fast-decode-uri-component "^1.0.0"
fast-decode-uri-component "^1.0.1"
safe-regex2 "^2.0.0"
semver-store "^0.3.0"
@ -3375,9 +3391,9 @@ hash.js@^1.0.0, hash.js@^1.0.3:
minimalistic-assert "^1.0.1"
helmet@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/helmet/-/helmet-4.0.0.tgz#34c187894ed001834f997c688f2b2df19846b193"
integrity sha512-HyoRKKHhWhO6+EBfgRLkuZR4/+NXc1nJB7x0bWwW89i9eoPciK0qUqyZNOA/zowpgrW9C4+J5toqMkZrpBOlkg==
version "4.1.0"
resolved "https://registry.yarnpkg.com/helmet/-/helmet-4.1.0.tgz#6f3a34e8f18502d6e52518428b23aa4ddaf84b38"
integrity sha512-KWy75fYN8hOG2Rhl8e5B3WhOzb0by1boQum85TiddIE9iu6gV+TXbUjVC17wfej0o/ZUpqB9kxM0NFCZRMzf+Q==
hex-color-regex@^1.1.0:
version "1.1.0"
@ -4087,9 +4103,9 @@ levn@~0.3.0:
type-check "~0.3.2"
light-my-request@^4.0.0:
version "4.0.1"
resolved "https://registry.yarnpkg.com/light-my-request/-/light-my-request-4.0.1.tgz#7e18f2c3f8535123c329b1ae78a5d6750424a096"
integrity sha512-kGRfzvSS9P/zEsnu34pUisOz2FAPqkHFJfdezW6HRzLLlzjY+1LTRRuh2d82SkW/M/QWNVWnXTZ0HMUydz2fgg==
version "4.0.2"
resolved "https://registry.yarnpkg.com/light-my-request/-/light-my-request-4.0.2.tgz#e80ebbbac512f0f45b9e54cb274b8f121248b924"
integrity sha512-VaiiqR2NtdgYL8zQENPr7FBBVKCGioqa06HYnidj/GC+6jibyZrNCrk6FU8fqe9WWQDqwOtt0UCWLGe0GjyjgA==
dependencies:
ajv "^6.12.2"
cookie "^0.4.0"
@ -4164,11 +4180,16 @@ lodash.uniq@^4.5.0:
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=
lodash@^4.15.0, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.4:
lodash@^4.15.0, lodash@^4.17.19, lodash@^4.17.4:
version "4.17.19"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b"
integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==
lodash@^4.17.15:
version "4.17.20"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52"
integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==
log-symbols@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a"
@ -5303,10 +5324,10 @@ pg-types@^2.1.0:
postgres-date "~1.0.4"
postgres-interval "^1.1.0"
pg@^8.3.0:
version "8.3.0"
resolved "https://registry.yarnpkg.com/pg/-/pg-8.3.0.tgz#941383300d38eef51ecb88a0188cec441ab64d81"
integrity sha512-jQPKWHWxbI09s/Z9aUvoTbvGgoj98AU7FDCcQ7kdejupn/TcNpx56v2gaOTzXkzOajmOEJEdi9eTh9cA2RVAjQ==
pg@^8.3.2:
version "8.3.2"
resolved "https://registry.yarnpkg.com/pg/-/pg-8.3.2.tgz#52766e41302f5b878fe1efa10d4cdd486f6dff50"
integrity sha512-hOoRCTriXS+VWwyXHchRjWb9yv3Koq8irlwwXniqhdgK0AbfWvEnybGS2HIUE+UdCSTuYAM4WGPujFpPg9Vcaw==
dependencies:
buffer-writer "2.0.0"
packet-reader "1.0.0"
@ -5345,21 +5366,21 @@ pify@^3.0.0:
integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=
pino-std-serializers@^2.4.2:
version "2.4.2"
resolved "https://registry.yarnpkg.com/pino-std-serializers/-/pino-std-serializers-2.4.2.tgz#cb5e3e58c358b26f88969d7e619ae54bdfcc1ae1"
integrity sha512-WaL504dO8eGs+vrK+j4BuQQq6GLKeCCcHaMB2ItygzVURcL1CycwNEUHTD/lHFHs/NL5qAz2UKrjYWXKSf4aMQ==
version "2.5.0"
resolved "https://registry.yarnpkg.com/pino-std-serializers/-/pino-std-serializers-2.5.0.tgz#40ead781c65a0ce7ecd9c1c33f409d31fe712315"
integrity sha512-wXqbqSrIhE58TdrxxlfLwU9eDhrzppQDvGhBEr1gYbzzM4KKo3Y63gSjiDXRKLVS2UOXdPNR2v+KnQgNrs+xUg==
pino@^6.2.1:
version "6.5.0"
resolved "https://registry.yarnpkg.com/pino/-/pino-6.5.0.tgz#4d3447c0efa75489936c16071bd3abddbaac7e96"
integrity sha512-qDIFPZ2h2AMrp+JIWKFUtejiTv5F/+glbizrG9VNvegSCSK6sqnRmerNM9R98/x3RxwKkIf5kJ9q4chXdBdvJA==
version "6.5.1"
resolved "https://registry.yarnpkg.com/pino/-/pino-6.5.1.tgz#a245adf960a1f3e88e61a339045d509bccbfb7cc"
integrity sha512-76+RUhQkqjUD4AtQcSfEzh6vlsjXmoWZK5gg+2d70aCLXZTbo4/5js4I9rN1Xk6z1h2/7pnOFX10G4c2T4qNiA==
dependencies:
fast-redact "^2.0.0"
fast-safe-stringify "^2.0.7"
flatstr "^1.0.12"
pino-std-serializers "^2.4.2"
quick-format-unescaped "^4.0.1"
sonic-boom "^1.0.0"
sonic-boom "^1.0.2"
plucker@0.0.0:
version "0.0.0"
@ -5720,9 +5741,9 @@ postgres-bytea@~1.0.0:
integrity sha1-AntTPAqokOJtFy1Hz5zOzFIazTU=
postgres-date@~1.0.4:
version "1.0.5"
resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.5.tgz#710b27de5f27d550f6e80b5d34f7ba189213c2ee"
integrity sha512-pdau6GRPERdAYUQwkBnGKxEfPyhVZXG/JiS44iZWiNdSOWE09N2lUgN6yshuq6fVSon4Pm0VMXd1srUUkLe9iA==
version "1.0.6"
resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.6.tgz#4925e8085b30c2ba1a06ac91b9a3473954a2ce2d"
integrity sha512-o2a4gxeFcox+CgB3Ig/kNHBP23PiEXHCXx7pcIIsvzoNz4qv+lKTyiSkjOXIMNUl12MO/mOYl2K6wR9X5K6Plg==
postgres-interval@^1.1.0:
version "1.2.0"
@ -6549,10 +6570,10 @@ snapdragon@^0.8.1:
source-map-resolve "^0.5.0"
use "^3.1.0"
sonic-boom@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-1.0.2.tgz#8769646fac2ecb58bd0ed60562280aa4211598df"
integrity sha512-sRMmXu7uFDXoniGvtLHuQk5KWovLWoi6WKASn7rw0ro41mPf0fOolkGp4NE6680CbxvNh26zWNyFQYYWXe33EA==
sonic-boom@^1.0.2:
version "1.1.0"
resolved "https://registry.yarnpkg.com/sonic-boom/-/sonic-boom-1.1.0.tgz#538c2de63aaca1b49254a7ed9d16e4931fab6ad3"
integrity sha512-JyOf+Xt7GBN4tAic/DD1Bitw6OMgSHAnswhPeOiLpfRoSjPNjEIi73UF3OxHzhSNn9WavxGuCZzprFCGFSNwog==
dependencies:
atomic-sleep "^1.0.0"
flatstr "^1.0.12"