diff --git a/README.md b/README.md index b17a7f5d4e..14a57b14d1 100644 --- a/README.md +++ b/README.md @@ -20,10 +20,6 @@ - - - - diff --git a/examples/getstarted/package.json b/examples/getstarted/package.json index 2dc3651319..86911e9391 100644 --- a/examples/getstarted/package.json +++ b/examples/getstarted/package.json @@ -16,7 +16,7 @@ "lodash": "4.17.19", "mysql": "^2.17.1", "pg": "8.5.1", - "sqlite3": "^5.0.0", + "sqlite3": "^5.0.1", "strapi": "3.4.6", "strapi-admin": "3.4.6", "strapi-connector-bookshelf": "3.4.6", diff --git a/packages/strapi-admin/admin/src/translations/de.json b/packages/strapi-admin/admin/src/translations/de.json index f3efa62c14..b8ab0a1073 100644 --- a/packages/strapi-admin/admin/src/translations/de.json +++ b/packages/strapi-admin/admin/src/translations/de.json @@ -65,12 +65,20 @@ "Roles.ListPage.notification.delete-not-allowed": "Eine Rolle, die mit einem Benutzer verknüpft ist, kann nicht gelöscht werden", "Roles.RoleRow.user-count.plural": "{number} Benutzer", "Roles.RoleRow.user-count.singular": "{number} Benutzer", + "Settings.application.description": "Projektdetails ansehen", + "Settings.application.edition-title": "Aktuelle Planversion", + "Settings.application.link-pricing": "Alle Preisgestaltungen anzeigen", + "Settings.application.link-upgrade": "Dein Projekt upgraden", + "Settings.application.node-version": "NODE VERSION", + "Settings.application.strapi-version": "STRAPI VERSION", + "Settings.application.title": "Anwendung", "Roles.components.List.empty.withSearch": "Es gibt keine Rolle die der Suche ({search}) entspricht...", "Settings.PageTitle": "Einstellungen - {name}", "Settings.error": "Fehler", "Settings.global": "Globale Einstellungen", "Settings.permissions": "Administrationsoberfläche", "Settings.permissions.category": "Berechtigungseinstellungen für die {category}", + "Settings.permissions.category.plugins": "Berechtigungseinstellungen für das {category} Plugin", "Settings.permissions.conditions.anytime": "Jederzeit", "Settings.permissions.conditions.apply": "Anwenden", "Settings.permissions.conditions.can": "Kann", @@ -333,5 +341,7 @@ "notification.permission.not-allowed-read": "Keine Berechtigung dieses Dokument einzusehen", "notification.success.delete": "Eintrag wurde gelöscht", "notification.success.saved": "Gespeichert", + "notification.version.update.link": "Erfahre mehr", + "notification.version.update.message": "Eine neue Strapi Version ist verfügbar", "request.error.model.unknown": "Dieses Schema existiert nicht" -} +} \ No newline at end of file diff --git a/packages/strapi-admin/package.json b/packages/strapi-admin/package.json index 34a1fc4bd6..bb408ac8b9 100644 --- a/packages/strapi-admin/package.json +++ b/packages/strapi-admin/package.json @@ -19,11 +19,11 @@ "@babel/plugin-proposal-class-properties": "^7.12.1", "@babel/plugin-syntax-dynamic-import": "^7.2.0", "@babel/plugin-transform-modules-commonjs": "^7.12.1", - "@babel/plugin-transform-runtime": "^7.9.0", + "@babel/plugin-transform-runtime": "^7.12.15", "@babel/polyfill": "^7.12.1", "@babel/preset-env": "^7.9.5", "@babel/preset-react": "^7.9.4", - "@babel/runtime": "^7.9.2", + "@babel/runtime": "^7.12.13", "@buffetjs/core": "3.3.4", "@buffetjs/custom": "3.3.4", "@buffetjs/hooks": "3.3.4", diff --git a/packages/strapi-connector-bookshelf/lib/knex.js b/packages/strapi-connector-bookshelf/lib/knex.js index b1bcfa3bef..e8dd0dc04e 100644 --- a/packages/strapi-connector-bookshelf/lib/knex.js +++ b/packages/strapi-connector-bookshelf/lib/knex.js @@ -102,6 +102,7 @@ module.exports = strapi => { ...connection.options, debug: _.get(connection.options, 'debug', false), pool: { + ..._.get(connection.options, 'pool', {}), min: _.get(connection.options, 'pool.min', 0), }, }, diff --git a/packages/strapi-connector-bookshelf/lib/queries.js b/packages/strapi-connector-bookshelf/lib/queries.js index 6c3d46091d..e93fa29ce3 100644 --- a/packages/strapi-connector-bookshelf/lib/queries.js +++ b/packages/strapi-connector-bookshelf/lib/queries.js @@ -700,12 +700,14 @@ const buildSearchQuery = ({ model, params }) => qb => { const searchColumns = Object.keys(model._attributes) .filter(attribute => !associations.includes(attribute)) - .filter(attribute => stringTypes.includes(model._attributes[attribute].type)); + .filter(attribute => stringTypes.includes(model._attributes[attribute].type)) + .filter(attribute => model._attributes[attribute].searchable !== false); if (!_.isNaN(_.toNumber(query))) { const numberColumns = Object.keys(model._attributes) .filter(attribute => !associations.includes(attribute)) - .filter(attribute => numberTypes.includes(model._attributes[attribute].type)); + .filter(attribute => numberTypes.includes(model._attributes[attribute].type)) + .filter(attribute => model._attributes[attribute].searchable !== false); searchColumns.push(...numberColumns); } diff --git a/packages/strapi-connector-mongoose/lib/buildQuery.js b/packages/strapi-connector-mongoose/lib/buildQuery.js index 7037621b0b..379206b4b5 100644 --- a/packages/strapi-connector-mongoose/lib/buildQuery.js +++ b/packages/strapi-connector-mongoose/lib/buildQuery.js @@ -36,6 +36,9 @@ const buildSearchOr = (model, query) => { } const searchOr = Object.keys(model.attributes).reduce((acc, curr) => { + if (model.attributes[curr].searchable === false) { + return acc; + } switch (model.attributes[curr].type) { case 'biginteger': case 'integer': diff --git a/packages/strapi-connector-mongoose/lib/mount-models.js b/packages/strapi-connector-mongoose/lib/mount-models.js index 0fd55a6ef6..0b7aa7dae5 100644 --- a/packages/strapi-connector-mongoose/lib/mount-models.js +++ b/packages/strapi-connector-mongoose/lib/mount-models.js @@ -311,7 +311,9 @@ module.exports = async ({ models, target }, ctx) => { const createOnFetchPopulateFn = ({ morphAssociations, componentAttributes, definition }) => { return function() { const populatedPaths = this.getPopulatedPaths(); - const { publicationState } = this.getOptions(); + const { publicationState, _depth = 0 } = this.getOptions(); + + if (_depth > 2) return; const getMatchQuery = assoc => { const assocModel = strapi.db.getModelByAssoc(assoc); @@ -334,7 +336,10 @@ const createOnFetchPopulateFn = ({ morphAssociations, componentAttributes, defin this.populate({ path: alias, match: matchQuery, options: { publicationState } }); } else if (populatedPaths.includes(alias)) { _.set(this._mongooseOptions.populate, [alias, 'path'], `${alias}.ref`); - _.set(this._mongooseOptions.populate, [alias, 'options'], { publicationState }); + _.set(this._mongooseOptions.populate, [alias, 'options'], { + publicationState, + _depth: _depth + 1, + }); if (matchQuery !== undefined) { _.set(this._mongooseOptions.populate, [alias, 'match'], matchQuery); @@ -350,13 +355,13 @@ const createOnFetchPopulateFn = ({ morphAssociations, componentAttributes, defin this.populate({ path: ast.alias, match: getMatchQuery(ast), - options: { publicationState }, + options: { publicationState, _depth: _depth + 1 }, }); }); } componentAttributes.forEach(key => { - this.populate({ path: `${key}.ref`, options: { publicationState } }); + this.populate({ path: `${key}.ref`, options: { publicationState, _depth: _depth + 1 } }); }); }; }; diff --git a/packages/strapi-generate-new/package.json b/packages/strapi-generate-new/package.json index 8814338a3c..74392c2c94 100644 --- a/packages/strapi-generate-new/package.json +++ b/packages/strapi-generate-new/package.json @@ -13,7 +13,7 @@ "lib": "./lib" }, "dependencies": { - "@sentry/node": "^6.0.3", + "@sentry/node": "6.1.0", "chalk": "^2.4.2", "execa": "^1.0.0", "fs-extra": "^9.0.1", diff --git a/packages/strapi-plugin-content-manager/package.json b/packages/strapi-plugin-content-manager/package.json index 2bb2133dfc..74acb36284 100644 --- a/packages/strapi-plugin-content-manager/package.json +++ b/packages/strapi-plugin-content-manager/package.json @@ -28,7 +28,7 @@ "markdown-it-deflist": "^2.0.3", "markdown-it-emoji": "^2.0.0", "markdown-it-footnote": "^3.0.2", - "markdown-it-ins": "^3.0.0", + "markdown-it-ins": "^3.0.1", "markdown-it-mark": "^3.0.1", "markdown-it-sub": "^1.0.0", "markdown-it-sup": "^1.0.0", diff --git a/packages/strapi-plugin-content-type-builder/admin/src/components/BooleanBox/CT.js b/packages/strapi-plugin-content-type-builder/admin/src/components/BooleanBox/CT.js new file mode 100644 index 0000000000..ea2cc34d3d --- /dev/null +++ b/packages/strapi-plugin-content-type-builder/admin/src/components/BooleanBox/CT.js @@ -0,0 +1,21 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import CTSelected from './icons/CTSelected'; +import CTUnselected from './icons/CTUnselected'; + +const CT = ({ selected }) => + selected ? ( + + ) : ( + + ); + +CT.defaultProps = { + selected: false, +}; + +CT.propTypes = { + selected: PropTypes.bool, +}; + +export default CT; diff --git a/packages/strapi-plugin-content-type-builder/admin/src/components/BooleanBox/ST.js b/packages/strapi-plugin-content-type-builder/admin/src/components/BooleanBox/ST.js new file mode 100644 index 0000000000..e3078eee4a --- /dev/null +++ b/packages/strapi-plugin-content-type-builder/admin/src/components/BooleanBox/ST.js @@ -0,0 +1,21 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import STSelected from './icons/STSelected'; +import STUnselected from './icons/STUnselected'; + +const ST = ({ selected }) => + selected ? ( + + ) : ( + + ); + +ST.defaultProps = { + selected: false, +}; + +ST.propTypes = { + selected: PropTypes.bool, +}; + +export default ST; diff --git a/packages/strapi-plugin-content-type-builder/admin/src/components/BooleanBox/icons/CTSelected.js b/packages/strapi-plugin-content-type-builder/admin/src/components/BooleanBox/icons/CTSelected.js new file mode 100644 index 0000000000..7eeb59b91b --- /dev/null +++ b/packages/strapi-plugin-content-type-builder/admin/src/components/BooleanBox/icons/CTSelected.js @@ -0,0 +1,136 @@ +/* eslint-disable */ +import React from 'react'; + +const CTSelected = props => ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +); + +export default CTSelected; diff --git a/packages/strapi-plugin-content-type-builder/admin/src/components/BooleanBox/icons/CTUnselected.js b/packages/strapi-plugin-content-type-builder/admin/src/components/BooleanBox/icons/CTUnselected.js new file mode 100644 index 0000000000..03c58bf8f0 --- /dev/null +++ b/packages/strapi-plugin-content-type-builder/admin/src/components/BooleanBox/icons/CTUnselected.js @@ -0,0 +1,136 @@ +/* eslint-disable */ +import React from 'react'; + +const CTUnSelected = props => ( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +); + +export default CTUnSelected; diff --git a/packages/strapi-plugin-content-type-builder/admin/src/components/BooleanBox/icons/STSelected.js b/packages/strapi-plugin-content-type-builder/admin/src/components/BooleanBox/icons/STSelected.js new file mode 100644 index 0000000000..1ba2080d85 --- /dev/null +++ b/packages/strapi-plugin-content-type-builder/admin/src/components/BooleanBox/icons/STSelected.js @@ -0,0 +1,80 @@ +/* eslint-disable */ +import React from 'react'; + +const STSelected = props => ( + + + + + + + + + + + + + + + + + + + + + + + + + + + +); + +export default STSelected; diff --git a/packages/strapi-plugin-content-type-builder/admin/src/components/BooleanBox/icons/STUnselected.js b/packages/strapi-plugin-content-type-builder/admin/src/components/BooleanBox/icons/STUnselected.js new file mode 100644 index 0000000000..5433e92195 --- /dev/null +++ b/packages/strapi-plugin-content-type-builder/admin/src/components/BooleanBox/icons/STUnselected.js @@ -0,0 +1,76 @@ +/* eslint-disable */ +import React from 'react'; + +const STUnselected = props => ( + + + + + + + + + + + + + + + + + + + + + + + + + + + +); + +export default STUnselected; diff --git a/packages/strapi-plugin-content-type-builder/admin/src/components/BooleanBox/index.js b/packages/strapi-plugin-content-type-builder/admin/src/components/BooleanBox/index.js index d29e9e9029..da00027402 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/components/BooleanBox/index.js +++ b/packages/strapi-plugin-content-type-builder/admin/src/components/BooleanBox/index.js @@ -1,11 +1,29 @@ import React from 'react'; import PropTypes from 'prop-types'; import { useGlobalContext } from 'strapi-helper-plugin'; +import { Flex } from '@buffetjs/core'; +import styled from 'styled-components'; +import CTIcon from './CT'; +import STIcon from './ST'; import CustomLabel from './Label'; import Enumeration from './Enumeration'; import EnumerationWrapper from './EnumerationWrapper'; import Wrapper from './Wrapper'; +/** + * TODO: Those should not exist, remove with design system + */ +const CTHackSpan = styled.span` + margin-left: -1rem; + margin-right: 1rem; + margin-top: -1.3rem; +`; +const STHackSpan = styled.span` + margin-left: -1rem; + margin-right: 1rem; + margin-top: -0.5rem; +`; + const BooleanBox = ({ label, name, onChange, onChangeCallback, options, value }) => { const { formatMessage } = useGlobalContext(); @@ -31,17 +49,37 @@ const BooleanBox = ({ label, name, onChange, onChangeCallback, options, value }) value={option.value} /> ))} - {options.map(option => ( - - - {formatMessage({ id: option.headerId })} - {formatMessage({ id: option.descriptionId })} - - ))} + {options.map(option => { + const isST = option.value === 'singleType'; + const isCT = option.value === 'collectionType'; + + return ( + + + {isST && ( + + + + )} + {isCT && ( + + + + )} + + + + {formatMessage({ id: option.headerId })} + {formatMessage({ id: option.descriptionId })} + + + + ); + })} ); diff --git a/packages/strapi-plugin-content-type-builder/admin/src/components/BooleanBox/tests/BooleanBox.test.js b/packages/strapi-plugin-content-type-builder/admin/src/components/BooleanBox/tests/BooleanBox.test.js new file mode 100644 index 0000000000..3d541b5472 --- /dev/null +++ b/packages/strapi-plugin-content-type-builder/admin/src/components/BooleanBox/tests/BooleanBox.test.js @@ -0,0 +1,112 @@ +import React from 'react'; +import { render, screen } from '@testing-library/react'; +import { ThemeProvider } from 'styled-components'; +import defaultThemes from '../../../../../../strapi-admin/admin/src/themes'; +import BooleanBox from '..'; + +jest.mock('strapi-helper-plugin', () => ({ + useGlobalContext: () => ({ formatMessage: ({ id }) => id }), +})); + +describe('BooleanBox', () => { + it('has single type selected by default and verifies the other states', () => { + const options = [ + { + headerId: 'menu.section.models.name.singular', + descriptionId: 'form.button.collection-type.description', + value: 'collectionType', + }, + { + headerId: 'menu.section.single-types.name.singular', + descriptionId: 'form.button.single-type.description', + value: 'singleType', + }, + ]; + + render( + + null} + onChangeCallback={() => null} + options={options} + value="singleType" + /> + + ); + + expect(screen.getByTestId('st-selected')).toBeVisible(); + expect(screen.getByTestId('ct-unselected')).toBeVisible(); + + expect(screen.queryByTestId('ct-selected')).toBeFalsy(); + expect(screen.queryByTestId('st-unselected')).toBeFalsy(); + }); + + it('has collection type selected by default and verifies the other states', () => { + const options = [ + { + headerId: 'menu.section.models.name.singular', + descriptionId: 'form.button.collection-type.description', + value: 'collectionType', + }, + { + headerId: 'menu.section.single-types.name.singular', + descriptionId: 'form.button.single-type.description', + value: 'singleType', + }, + ]; + + render( + + null} + onChangeCallback={() => null} + options={options} + value="collectionType" + /> + + ); + + expect(screen.getByTestId('ct-selected')).toBeVisible(); + expect(screen.getByTestId('st-unselected')).toBeVisible(); + + expect(screen.queryByTestId('st-selected')).toBeFalsy(); + expect(screen.queryByTestId('ct-unselected')).toBeFalsy(); + }); + + it('does not show the ST and CT icons for other types', () => { + const options = [ + { + headerId: 'menu.section.models.name.singular', + descriptionId: 'form.button.collection-type.description', + value: 'text', + }, + { + headerId: 'menu.section.single-types.name.singular', + descriptionId: 'form.button.single-type.description', + value: 'string', + }, + ]; + + render( + + null} + onChangeCallback={() => null} + options={options} + value="collectionType" + /> + + ); + + expect(screen.queryByTestId('ct-selected')).toBeFalsy(); + expect(screen.queryByTestId('st-unselected')).toBeFalsy(); + expect(screen.queryByTestId('st-selected')).toBeFalsy(); + expect(screen.queryByTestId('ct-unselected')).toBeFalsy(); + }); +}); diff --git a/packages/strapi-plugin-content-type-builder/admin/src/translations/de.json b/packages/strapi-plugin-content-type-builder/admin/src/translations/de.json index 0889f65e09..6511aadaa5 100644 --- a/packages/strapi-plugin-content-type-builder/admin/src/translations/de.json +++ b/packages/strapi-plugin-content-type-builder/admin/src/translations/de.json @@ -16,6 +16,7 @@ "attribute.json.description": "Daten im JSON-Format", "attribute.media": "Medien", "attribute.media.description": "Dateien wie Bilder, Videos, etc", + "attribute.null": " ", "attribute.number": "Zahl", "attribute.number.description": "Zahlen (ganzzahlig, Gleitkommazahl, dezimal)", "attribute.password": "Passwort", @@ -65,6 +66,9 @@ "form.attribute.component.option.single.description": "Nützlich um Felder wie volle Addresse, Hauptinformationen, etc. zu grupppieren", "form.attribute.item.customColumnName": "Eigener Spaltenname", "form.attribute.item.customColumnName.description": "Dies ist nützlich, um Spalten in der Datenbank für Antworten der API umzubenennen", + "form.attribute.item.date.type.date": "Datum", + "form.attribute.item.date.type.datetime": "Datum und Uhrzeit", + "form.attribute.item.date.type.time": "Uhrzeit", "form.attribute.item.defineRelation.fieldName": "Feldname", "form.attribute.item.enumeration.graphql": "Namensüberschreibung für GraphQL", "form.attribute.item.enumeration.graphql.description": "Ermöglicht, den standardmäßig generierten Namen für GraphQL zu überschreiben", @@ -180,4 +184,4 @@ "relation.oneWay": "hat ein(-e/-en)", "table.attributes.title.plural": "{number} Felder", "table.attributes.title.singular": "{number} Feld" -} +} \ No newline at end of file diff --git a/packages/strapi-plugin-documentation/admin/src/translations/de.json b/packages/strapi-plugin-documentation/admin/src/translations/de.json index 6d7d8441bd..9aea5ac5f0 100755 --- a/packages/strapi-plugin-documentation/admin/src/translations/de.json +++ b/packages/strapi-plugin-documentation/admin/src/translations/de.json @@ -5,6 +5,9 @@ "containers.HomePage.Block.title": "Versionen", "containers.HomePage.Button.open": "Dokumentation öffnen", "containers.HomePage.Button.update": "Aktualisieren", + "containers.HomePage.copied": "Token in der Zwischenablage kopiert", + "containers.HomePage.form.jwtToken": "Jwt Token abrufen", + "containers.HomePage.form.jwtToken.description": "Kopieren Sie diesen Token und nutzen Sie es unter Swagger, um Anfragen zu stellen", "containers.HomePage.PluginHeader.description": "Einstellungen des Dokumentation-Plugins ändern", "containers.HomePage.PluginHeader.title": "Dokumentation - Einstellungen", "containers.HomePage.PopUpWarning.confirm": "Ich verstehe", @@ -16,9 +19,12 @@ "containers.HomePage.form.showGeneratedFiles": "Generierte Dateien anzeigen", "containers.HomePage.form.showGeneratedFiles.inputDescription": "Nützlich, wenn Sie die generierte Dokumentation überschreiben möchten. \nDas Plugin wird nach Modell und Plugin geteilte Dateien erzeugen. \nDurch die Aktivierung dieser Option wird es einfacher sein, Ihre Dokumentation anzupassen.", "error.deleteDoc.versionMissing": "Die Version, die Sie zu löschen versuchen, existiert nicht.", + "error.noVersion": "Eine Version wird benötigt", "error.regenerateDoc": "Ein Fehler ist während dem Neu-Erstellen der Dokumentation aufgetreten.", "error.regenerateDoc.versionMissing": "Die Version, die Sie zu generieren versuchen, existiert nicht", "notification.update.success": "Einstellungen wurden erfolgreich aktualisiert", + "notification.delete.success": "Dokument wurde erfolgreich gelöscht", + "notification.generate.success": "Dokument wurde erfolgreich generiert", "plugin.name": "Dokumentation" -} +} \ No newline at end of file diff --git a/packages/strapi-plugin-documentation/package.json b/packages/strapi-plugin-documentation/package.json index 4a8667da70..e72e76725b 100644 --- a/packages/strapi-plugin-documentation/package.json +++ b/packages/strapi-plugin-documentation/package.json @@ -36,7 +36,7 @@ "redux-immutable": "^4.0.0", "reselect": "^4.0.0", "strapi-helper-plugin": "3.4.6", - "swagger-ui-dist": "3.41.1" + "swagger-ui-dist": "3.43.0" }, "author": { "name": "soupette", diff --git a/packages/strapi-plugin-documentation/services/Documentation.js b/packages/strapi-plugin-documentation/services/Documentation.js index 5ad4b323cf..df12cb4a18 100755 --- a/packages/strapi-plugin-documentation/services/Documentation.js +++ b/packages/strapi-plugin-documentation/services/Documentation.js @@ -348,7 +348,7 @@ module.exports = { } if (isField) { - acc.properties[curr] = { type: this.getType(attribute.type) }; + acc.properties[curr] = { type: this.getType(attribute.type), enum: attribute.enum }; } else { const newGetter = getter.slice(); newGetter.splice(newGetter.length - 1, 1, 'associations'); @@ -359,6 +359,7 @@ module.exports = { switch (relationNature) { case 'manyToMany': case 'oneToMany': + case 'manyWay': case 'manyToManyMorph': acc.properties[curr] = { type: 'array', @@ -573,6 +574,7 @@ module.exports = { switch (relationNature) { case 'manyToMany': case 'oneToMany': + case 'manyWay': case 'manyToManyMorph': acc.properties[current] = { type: 'array', diff --git a/packages/strapi-plugin-sentry/.editorconfig b/packages/strapi-plugin-sentry/.editorconfig new file mode 100644 index 0000000000..d4eed8406b --- /dev/null +++ b/packages/strapi-plugin-sentry/.editorconfig @@ -0,0 +1,7 @@ +root = true + +[*] +end_of_line = lf +insert_final_newline = false +indent_style = space +indent_size = 2 diff --git a/packages/strapi-plugin-sentry/.gitattributes b/packages/strapi-plugin-sentry/.gitattributes new file mode 100644 index 0000000000..065a11c71d --- /dev/null +++ b/packages/strapi-plugin-sentry/.gitattributes @@ -0,0 +1,103 @@ +# From https://github.com/Danimoth/gitattributes/blob/master/Web.gitattributes + +# Handle line endings automatically for files detected as text +# and leave all files detected as binary untouched. +* text=auto + +# +# The above will handle all files NOT found below +# + +# +## These files are text and should be normalized (Convert crlf => lf) +# + +# source code +*.php text +*.css text +*.sass text +*.scss text +*.less text +*.styl text +*.js text eol=lf +*.coffee text +*.json text +*.htm text +*.html text +*.xml text +*.svg text +*.txt text +*.ini text +*.inc text +*.pl text +*.rb text +*.py text +*.scm text +*.sql text +*.sh text +*.bat text + +# templates +*.ejs text +*.hbt text +*.jade text +*.haml text +*.hbs text +*.dot text +*.tmpl text +*.phtml text + +# git config +.gitattributes text +.gitignore text +.gitconfig text + +# code analysis config +.jshintrc text +.jscsrc text +.jshintignore text +.csslintrc text + +# misc config +*.yaml text +*.yml text +.editorconfig text + +# build config +*.npmignore text +*.bowerrc text + +# Heroku +Procfile text +.slugignore text + +# Documentation +*.md text +LICENSE text +AUTHORS text + + +# +## These files are binary and should be left untouched +# + +# (binary is a macro for -text -diff) +*.png binary +*.jpg binary +*.jpeg binary +*.gif binary +*.ico binary +*.mov binary +*.mp4 binary +*.mp3 binary +*.flv binary +*.fla binary +*.swf binary +*.gz binary +*.zip binary +*.7z binary +*.ttf binary +*.eot binary +*.woff binary +*.pyc binary +*.pdf binary diff --git a/packages/strapi-plugin-sentry/.gitignore b/packages/strapi-plugin-sentry/.gitignore new file mode 100644 index 0000000000..afe256bf30 --- /dev/null +++ b/packages/strapi-plugin-sentry/.gitignore @@ -0,0 +1,10 @@ +# Don't check auto-generated stuff into git +coverage +node_modules +stats.json +package-lock.json + +# Cruft +.DS_Store +npm-debug.log +.idea diff --git a/packages/strapi-plugin-sentry/.npmignore b/packages/strapi-plugin-sentry/.npmignore new file mode 100644 index 0000000000..afe256bf30 --- /dev/null +++ b/packages/strapi-plugin-sentry/.npmignore @@ -0,0 +1,10 @@ +# Don't check auto-generated stuff into git +coverage +node_modules +stats.json +package-lock.json + +# Cruft +.DS_Store +npm-debug.log +.idea diff --git a/packages/strapi-plugin-sentry/LICENSE b/packages/strapi-plugin-sentry/LICENSE new file mode 100644 index 0000000000..db018546b5 --- /dev/null +++ b/packages/strapi-plugin-sentry/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2015-present Strapi Solutions SAS + +Portions of the Strapi software are licensed as follows: + +* All software that resides under an "ee/" directory (the “EE Software”), if that directory exists, is licensed under the license defined in "ee/LICENSE". + +* All software outside of the above-mentioned directories or restrictions above is available under the "MIT Expat" license as set forth below. + +MIT Expat License + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/packages/strapi-plugin-sentry/README.md b/packages/strapi-plugin-sentry/README.md new file mode 100644 index 0000000000..368cef37bd --- /dev/null +++ b/packages/strapi-plugin-sentry/README.md @@ -0,0 +1,116 @@ +# Strapi plugin Sentry + +The official plugin to track Strapi errors with Sentry. + +## Features + +- Initialize a Sentry instance when your Strapi app starts +- Send errors encountered in your application's end API to Sentry +- Attach useful metadata to Sentry events, to help you with debugging +- Expose a global Sentry service + +## Configuration + +| property | type (default) | description | +| -------------- | ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `dsn` | string (`null`) | Your Sentry data source name ([see Sentry docs](https://docs.sentry.io/product/sentry-basics/dsn-explainer/)). | +| `sendMetadata` | boolean (`true`) | Whether the plugin should attach additional information (like OS, browser, etc.) to the events sent to Sentry. | +| `init` | object (`{}`) | A config object that is passed directly to Sentry during the `Sentry.init()`. See all available options [on Sentry's docs](https://docs.sentry.io/platforms/node/configuration/options/) | + +**Example** + +`./config/plugins.js` + +```js +module.exports = ({ env }) => ({ + // ... + sentry: { + dsn: env('SENTRY_DSN'), + sendMetadata: true, + }, + // ... +}); +``` + +## Global Sentry service + +You can access a Sentry service throughout your app. + +```js +const sentryService = strapi.plugins.sentry.services.sentry; +``` + +This service exposes the following methods: + +### `sendError(error, configureScope)` + +Use it to manually send errors to Sentry. The `configureScope` is optional, it allows you to customize the error event. Read more about Sentry's scope system [on their docs](https://docs.sentry.io/platforms/node/enriching-events/scopes/#configuring-the-scope). + +**Example** + +```js +try { + // Your code here +} catch (error) { + // Either send a simple error + strapi.plugins.sentry.services.sentry.sendError(error); + + // Or send an error with a customized Sentry scope + strapi.plugins.sentry.services.sentry.sendError(error, (scope, sentryInstance) => { + // Customize the scope here + scope.setTag('my_custom_tag', 'Tag value'); + }); + throw error; +} +``` + +### `getInstance()` + +Use it if you need direct access to the Sentry instance, which should already already be initialized. It's useful if `sendError` doesn't suit your needs. + +**Example** + +```js +const sentryInstance = strapi.plugins.sentry.services.sentry.getInstance(); +``` + +## Disabling + +### Disabling only the middleware + +By default, this plugin uses a middleware that logs all your unhandled API errors to Sentry. You can disable this feature by turning off the `sentry` middleware in your app's config. + +**Example** + +`./config/middleware.js` + +```js +module.exports = { + //... + settings: { + sentry: { + enabled: false, + }, + }, +}; +``` + +Only the middleware will be disabled. You will still have access to the Sentry service. + +### Disabling the plugin entirely + +You can also completely disable this plugin (both the middleware and the service). If you omit the `dsn` property of your plugin's settings, or if you give it a null value, the Sentry plugin will be ignored. You can use the `env` utility to disable it depending on the environment. + +**Example** + +`./config/plugins.js` + +```js +module.exports = ({ env }) => ({ + // ... + sentry: { + dsn: env('NODE_ENV') === 'development' ? null : env('SENTRY_DSN'), + }, + // ... +}); +``` diff --git a/packages/strapi-plugin-sentry/admin/src/assets/images/logo.svg b/packages/strapi-plugin-sentry/admin/src/assets/images/logo.svg new file mode 100644 index 0000000000..9d9d1c787f --- /dev/null +++ b/packages/strapi-plugin-sentry/admin/src/assets/images/logo.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/strapi-plugin-sentry/admin/src/index.js b/packages/strapi-plugin-sentry/admin/src/index.js new file mode 100644 index 0000000000..a22453af33 --- /dev/null +++ b/packages/strapi-plugin-sentry/admin/src/index.js @@ -0,0 +1,29 @@ +import pluginPkg from '../../package.json'; +import pluginId from './pluginId'; +import pluginLogo from './assets/images/logo.svg'; +import trads from './translations'; + +export default strapi => { + const pluginDescription = pluginPkg.strapi.description || pluginPkg.description; + + const plugin = { + blockerComponent: null, + blockerComponentProps: {}, + description: pluginDescription, + icon: pluginPkg.strapi.icon, + id: pluginId, + isReady: true, + initializer: () => null, + injectedComponents: [], + isRequired: pluginPkg.strapi.required || false, + layout: null, + lifecycles: () => {}, + mainComponent: null, + name: pluginPkg.strapi.name, + pluginLogo, + preventComponentRendering: false, + trads, + }; + + return strapi.registerPlugin(plugin); +}; diff --git a/packages/strapi-plugin-sentry/admin/src/pluginId.js b/packages/strapi-plugin-sentry/admin/src/pluginId.js new file mode 100644 index 0000000000..f5ad7de626 --- /dev/null +++ b/packages/strapi-plugin-sentry/admin/src/pluginId.js @@ -0,0 +1,5 @@ +import pluginPkg from '../../package.json'; + +const pluginId = pluginPkg.name.replace(/^strapi-plugin-/i, ''); + +export default pluginId; diff --git a/packages/strapi-plugin-sentry/admin/src/translations/ar.json b/packages/strapi-plugin-sentry/admin/src/translations/ar.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/packages/strapi-plugin-sentry/admin/src/translations/ar.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/packages/strapi-plugin-sentry/admin/src/translations/cs.json b/packages/strapi-plugin-sentry/admin/src/translations/cs.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/packages/strapi-plugin-sentry/admin/src/translations/cs.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/packages/strapi-plugin-sentry/admin/src/translations/de.json b/packages/strapi-plugin-sentry/admin/src/translations/de.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/packages/strapi-plugin-sentry/admin/src/translations/de.json @@ -0,0 +1 @@ +{} diff --git a/packages/strapi-plugin-sentry/admin/src/translations/en.json b/packages/strapi-plugin-sentry/admin/src/translations/en.json new file mode 100644 index 0000000000..1fc4b05602 --- /dev/null +++ b/packages/strapi-plugin-sentry/admin/src/translations/en.json @@ -0,0 +1,4 @@ +{ + "plugin.description.short": "Send Strapi error events to Sentry.", + "plugin.description.long": "Send Strapi error events to Sentry." +} \ No newline at end of file diff --git a/packages/strapi-plugin-sentry/admin/src/translations/es.json b/packages/strapi-plugin-sentry/admin/src/translations/es.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/packages/strapi-plugin-sentry/admin/src/translations/es.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/packages/strapi-plugin-sentry/admin/src/translations/fr.json b/packages/strapi-plugin-sentry/admin/src/translations/fr.json new file mode 100644 index 0000000000..ea4cc69ee2 --- /dev/null +++ b/packages/strapi-plugin-sentry/admin/src/translations/fr.json @@ -0,0 +1,4 @@ +{ + "plugin.description.short": "Envoie vos erreurs Strapi à Sentry.", + "plugin.description.long": "Envoie vos erreurs Strapi à Sentry." +} \ No newline at end of file diff --git a/packages/strapi-plugin-sentry/admin/src/translations/id.json b/packages/strapi-plugin-sentry/admin/src/translations/id.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/packages/strapi-plugin-sentry/admin/src/translations/id.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/packages/strapi-plugin-sentry/admin/src/translations/index.js b/packages/strapi-plugin-sentry/admin/src/translations/index.js new file mode 100644 index 0000000000..d990d5ae93 --- /dev/null +++ b/packages/strapi-plugin-sentry/admin/src/translations/index.js @@ -0,0 +1,49 @@ +import ar from './ar.json'; +import cs from './cs.json'; +import de from './de.json'; +import en from './en.json'; +import es from './es.json'; +import fr from './fr.json'; +import id from './id.json'; +import it from './it.json'; +import ko from './ko.json'; +import ms from './ms.json'; +import nl from './nl.json'; +import pl from './pl.json'; +import ptBR from './pt-BR.json'; +import pt from './pt.json'; +import ru from './ru.json'; +import th from './th.json'; +import tr from './tr.json'; +import uk from './uk.json'; +import vi from './vi.json'; +import zhHans from './zh-Hans.json'; +import zh from './zh.json'; +import sk from './sk.json'; + +const trads = { + ar, + cs, + de, + en, + es, + fr, + id, + it, + ko, + ms, + nl, + pl, + 'pt-BR': ptBR, + pt, + ru, + th, + tr, + uk, + vi, + 'zh-Hans': zhHans, + zh, + sk, +}; + +export default trads; diff --git a/packages/strapi-plugin-sentry/admin/src/translations/it.json b/packages/strapi-plugin-sentry/admin/src/translations/it.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/packages/strapi-plugin-sentry/admin/src/translations/it.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/packages/strapi-plugin-sentry/admin/src/translations/ko.json b/packages/strapi-plugin-sentry/admin/src/translations/ko.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/packages/strapi-plugin-sentry/admin/src/translations/ko.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/packages/strapi-plugin-sentry/admin/src/translations/ms.json b/packages/strapi-plugin-sentry/admin/src/translations/ms.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/packages/strapi-plugin-sentry/admin/src/translations/ms.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/packages/strapi-plugin-sentry/admin/src/translations/nl.json b/packages/strapi-plugin-sentry/admin/src/translations/nl.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/packages/strapi-plugin-sentry/admin/src/translations/nl.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/packages/strapi-plugin-sentry/admin/src/translations/pl.json b/packages/strapi-plugin-sentry/admin/src/translations/pl.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/packages/strapi-plugin-sentry/admin/src/translations/pl.json @@ -0,0 +1 @@ +{} diff --git a/packages/strapi-plugin-sentry/admin/src/translations/pt-BR.json b/packages/strapi-plugin-sentry/admin/src/translations/pt-BR.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/packages/strapi-plugin-sentry/admin/src/translations/pt-BR.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/packages/strapi-plugin-sentry/admin/src/translations/pt.json b/packages/strapi-plugin-sentry/admin/src/translations/pt.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/packages/strapi-plugin-sentry/admin/src/translations/pt.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/packages/strapi-plugin-sentry/admin/src/translations/ru.json b/packages/strapi-plugin-sentry/admin/src/translations/ru.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/packages/strapi-plugin-sentry/admin/src/translations/ru.json @@ -0,0 +1 @@ +{} diff --git a/packages/strapi-plugin-sentry/admin/src/translations/sk.json b/packages/strapi-plugin-sentry/admin/src/translations/sk.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/packages/strapi-plugin-sentry/admin/src/translations/sk.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/packages/strapi-plugin-sentry/admin/src/translations/th.json b/packages/strapi-plugin-sentry/admin/src/translations/th.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/packages/strapi-plugin-sentry/admin/src/translations/th.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/packages/strapi-plugin-sentry/admin/src/translations/tr.json b/packages/strapi-plugin-sentry/admin/src/translations/tr.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/packages/strapi-plugin-sentry/admin/src/translations/tr.json @@ -0,0 +1 @@ +{} diff --git a/packages/strapi-plugin-sentry/admin/src/translations/uk.json b/packages/strapi-plugin-sentry/admin/src/translations/uk.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/packages/strapi-plugin-sentry/admin/src/translations/uk.json @@ -0,0 +1 @@ +{} diff --git a/packages/strapi-plugin-sentry/admin/src/translations/vi.json b/packages/strapi-plugin-sentry/admin/src/translations/vi.json new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/packages/strapi-plugin-sentry/admin/src/translations/vi.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/packages/strapi-plugin-sentry/admin/src/translations/zh-Hans.json b/packages/strapi-plugin-sentry/admin/src/translations/zh-Hans.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/packages/strapi-plugin-sentry/admin/src/translations/zh-Hans.json @@ -0,0 +1 @@ +{} diff --git a/packages/strapi-plugin-sentry/admin/src/translations/zh.json b/packages/strapi-plugin-sentry/admin/src/translations/zh.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/packages/strapi-plugin-sentry/admin/src/translations/zh.json @@ -0,0 +1 @@ +{} diff --git a/packages/strapi-plugin-sentry/config/functions/bootstrap.js b/packages/strapi-plugin-sentry/config/functions/bootstrap.js new file mode 100644 index 0000000000..fe50250c6c --- /dev/null +++ b/packages/strapi-plugin-sentry/config/functions/bootstrap.js @@ -0,0 +1,7 @@ +'use strict'; + +module.exports = async () => { + // Initialize the Sentry service exposed by this plugin + const { sentry } = strapi.plugins.sentry.services; + sentry.init(); +}; diff --git a/packages/strapi-plugin-sentry/config/routes.json b/packages/strapi-plugin-sentry/config/routes.json new file mode 100644 index 0000000000..9ade02d5d3 --- /dev/null +++ b/packages/strapi-plugin-sentry/config/routes.json @@ -0,0 +1,3 @@ +{ + "routes": [] +} diff --git a/packages/strapi-plugin-sentry/config/settings.json b/packages/strapi-plugin-sentry/config/settings.json new file mode 100644 index 0000000000..c19e847bd7 --- /dev/null +++ b/packages/strapi-plugin-sentry/config/settings.json @@ -0,0 +1,5 @@ +{ + "dsn": null, + "sendMetadata": true, + "init": {} +} \ No newline at end of file diff --git a/packages/strapi-plugin-sentry/controllers/sentry.js b/packages/strapi-plugin-sentry/controllers/sentry.js new file mode 100644 index 0000000000..3a6a590586 --- /dev/null +++ b/packages/strapi-plugin-sentry/controllers/sentry.js @@ -0,0 +1,9 @@ +'use strict'; + +/** + * sentry.js controller + * + * @description: A set of functions called "actions" of the `sentry` plugin. + */ + +module.exports = {}; diff --git a/packages/strapi-plugin-sentry/middlewares/sentry/defaults.json b/packages/strapi-plugin-sentry/middlewares/sentry/defaults.json new file mode 100644 index 0000000000..d3394f4839 --- /dev/null +++ b/packages/strapi-plugin-sentry/middlewares/sentry/defaults.json @@ -0,0 +1,5 @@ +{ + "sentry": { + "enabled": true + } +} diff --git a/packages/strapi-plugin-sentry/middlewares/sentry/index.js b/packages/strapi-plugin-sentry/middlewares/sentry/index.js new file mode 100644 index 0000000000..6d52b17151 --- /dev/null +++ b/packages/strapi-plugin-sentry/middlewares/sentry/index.js @@ -0,0 +1,33 @@ +'use strict'; + +module.exports = strapi => ({ + beforeInitialize() { + strapi.config.middleware.load.after.unshift('sentry'); + }, + initialize() { + const { sentry } = strapi.plugins.sentry.services; + sentry.init(); + + strapi.app.use(async (ctx, next) => { + try { + await next(); + } catch (error) { + sentry.sendError(error, (scope, sentryInstance) => { + scope.addEventProcessor(event => { + // Parse Koa context to add error metadata + return sentryInstance.Handlers.parseRequest(event, ctx.request, { + // Don't parse the transaction name, we'll do it manually + transaction: false, + }); + }); + // Manually add transaction name + scope.setTag('transaction', `${ctx.method} ${ctx.request.url}`); + // Manually add Strapi version + scope.setTag('strapi_version', strapi.config.info.strapi); + scope.setTag('method', ctx.method); + }); + throw error; + } + }); + }, +}); diff --git a/packages/strapi-plugin-sentry/package.json b/packages/strapi-plugin-sentry/package.json new file mode 100644 index 0000000000..fa6534d2a2 --- /dev/null +++ b/packages/strapi-plugin-sentry/package.json @@ -0,0 +1,30 @@ +{ + "name": "strapi-plugin-sentry", + "version": "3.4.6", + "description": "Send Strapi error events to Sentry", + "strapi": { + "name": "Sentry", + "icon": "plug", + "description": "sentry.plugin.description" + }, + "dependencies": { + "@sentry/node": "6.1.0" + }, + "author": { + "name": "A Strapi developer", + "email": "", + "url": "" + }, + "maintainers": [ + { + "name": "A Strapi developer", + "email": "", + "url": "" + } + ], + "engines": { + "node": ">=10.16.0 <=14.x.x", + "npm": ">=6.0.0" + }, + "license": "SEE LICENSE IN LICENSE" +} diff --git a/packages/strapi-plugin-sentry/services/__tests__/sentry.test.js b/packages/strapi-plugin-sentry/services/__tests__/sentry.test.js new file mode 100644 index 0000000000..84ffd14979 --- /dev/null +++ b/packages/strapi-plugin-sentry/services/__tests__/sentry.test.js @@ -0,0 +1,106 @@ +'use strict'; + +const INVALID_DSN = 'an_invalid_dsn'; +const VALID_DSN = 'a_valid_dsn'; +const captureException = jest.fn(); + +jest.mock('@sentry/node', () => { + return { + init(options = {}) { + if (options.dsn !== VALID_DSN) { + throw Error(); + } + }, + captureException, + withScope(configureScope) { + configureScope(); + }, + }; +}); + +let sentryService = require('../sentry'); +const defaultConfig = require('../../config/settings.json'); + +describe('strapi-plugin-sentry service', () => { + beforeEach(() => { + // Reset Strapi state + global.strapi = { + config: {}, + plugins: { + sentry: { + config: defaultConfig, + }, + }, + log: { + warn: jest.fn(), + info: jest.fn(), + }, + }; + sentryService = require('../sentry'); + }); + + afterEach(() => { + // Reset the plugin resource state + jest.resetModules(); + }); + + it('disables Sentry when no DSN is provided', () => { + sentryService.init(); + expect(strapi.log.info).toHaveBeenCalledWith(expect.stringMatching(/disabled/i)); + + const instance = sentryService.getInstance(); + expect(instance).toBeNull(); + }); + + it('disables Sentry when an invalid DSN is provided', () => { + global.strapi.plugins.sentry.config = { + dsn: INVALID_DSN, + }; + sentryService.init(); + expect(strapi.log.warn).toHaveBeenCalledWith(expect.stringMatching(/could not set up sentry/i)); + + const instance = sentryService.getInstance(); + expect(instance).toBeNull(); + }); + + it("doesn't send events before init", () => { + sentryService.sendError(Error()); + expect(strapi.log.warn).toHaveBeenCalledWith(expect.stringMatching(/cannot send event/i)); + }); + + it('initializes and sends errors', () => { + global.strapi.plugins.sentry.config = { + dsn: VALID_DSN, + }; + sentryService.init(); + + // Saves the instance correctly + const instance = sentryService.getInstance(); + expect(instance).not.toBeNull(); + + // Doesn't allow re-init + sentryService.init(); + + // Send error + const error = Error('an error'); + const configureScope = jest.fn(); + sentryService.sendError(error, configureScope); + expect(configureScope).toHaveBeenCalled(); + expect(captureException).toHaveBeenCalled(); + }); + + it('does not not send metadata when the option is disabled', () => { + // Init with metadata option disabled + global.strapi.plugins.sentry.config = { + dsn: VALID_DSN, + sendMetadata: false, + }; + sentryService.init(); + + // Send error + const error = Error('an error'); + const configureScope = jest.fn(); + sentryService.sendError(error, configureScope); + expect(configureScope).not.toHaveBeenCalled(); + }); +}); diff --git a/packages/strapi-plugin-sentry/services/sentry.js b/packages/strapi-plugin-sentry/services/sentry.js new file mode 100644 index 0000000000..bb5f962530 --- /dev/null +++ b/packages/strapi-plugin-sentry/services/sentry.js @@ -0,0 +1,87 @@ +'use strict'; + +const Sentry = require('@sentry/node'); +const defaultSettings = require('../config/settings.json'); + +const createSentryService = () => { + let isReady = false; + let instance = null; + let settings = {}; + + return { + /** + * Initialize Sentry service + */ + init() { + // Make sure there isn't a Sentry instance already running + if (instance != null) { + return this; + } + + // Retrieve user settings and merge them with the default ones + settings = { + ...defaultSettings, + ...strapi.plugins.sentry.config, + }; + + try { + // Don't init Sentry if no DSN was provided + if (settings.dsn) { + Sentry.init({ + dsn: settings.dsn, + environment: strapi.config.environment, + ...settings.init, + }); + // Store the successfully initialized Sentry instance + instance = Sentry; + isReady = true; + } else { + strapi.log.info('strapi-plugin-sentry is disabled because no Sentry DSN was provided'); + } + } catch (error) { + strapi.log.warn('Could not set up Sentry, make sure you entered a valid DSN'); + } + + return this; + }, + + /** + * Expose Sentry instance through a getter + * @returns {Sentry} + */ + getInstance() { + return instance; + }, + + /** + * Callback to [configure an instance of Sentry's scope]{@link https://docs.sentry.io/platforms/node/enriching-events/scopes/#configuring-the-scope} + * @callback configureScope + * @param {Sentry.scope} scope + * @param {Sentry=} instance An initialized Sentry instance + */ + + /** + * Higher level method to send exception events to Sentry + * @param {Error} error An error object + * @param {configureScope=} configureScope + */ + sendError(error, configureScope) { + // Make sure Sentry is ready + if (!isReady) { + strapi.log.warn("Sentry wasn't properly initialized, cannot send event"); + return; + } + + instance.withScope(scope => { + // Configure the Sentry scope using the provided callback + if (configureScope && settings.sendMetadata) { + configureScope(scope, instance); + } + // Actually send the Error to Sentry + instance.captureException(error); + }); + }, + }; +}; + +module.exports = createSentryService(); diff --git a/packages/strapi-plugin-upload/middlewares/upload/index.js b/packages/strapi-plugin-upload/middlewares/upload/index.js index ea8a06ac63..d37aa91910 100644 --- a/packages/strapi-plugin-upload/middlewares/upload/index.js +++ b/packages/strapi-plugin-upload/middlewares/upload/index.js @@ -3,6 +3,7 @@ const { resolve } = require('path'); const range = require('koa-range'); const koaStatic = require('koa-static'); +const _ = require('lodash'); module.exports = strapi => ({ initialize() { @@ -23,6 +24,12 @@ module.exports = strapi => ({ strapi.app.onerror(err); }); - strapi.router.get('/uploads/(.*)', range, koaStatic(staticDir, { defer: true })); + const localServerConfig = + _.get(strapi, 'plugins.upload.config.providerOptions.localServer') || {}; + strapi.router.get( + '/uploads/(.*)', + range, + koaStatic(staticDir, { defer: true, ...localServerConfig }) + ); }, }); diff --git a/packages/strapi-provider-email-nodemailer/package.json b/packages/strapi-provider-email-nodemailer/package.json index ef7bd2918e..c40fc26996 100644 --- a/packages/strapi-provider-email-nodemailer/package.json +++ b/packages/strapi-provider-email-nodemailer/package.json @@ -15,7 +15,7 @@ }, "dependencies": { "lodash": "4.17.20", - "nodemailer": "6.4.17" + "nodemailer": "6.4.18" }, "repository": { "type": "git", diff --git a/packages/strapi/bin/strapi.js b/packages/strapi/bin/strapi.js index cd477201f6..410929ef29 100755 --- a/packages/strapi/bin/strapi.js +++ b/packages/strapi/bin/strapi.js @@ -113,6 +113,7 @@ program .alias('dev') .option('--no-build', 'Disable build') .option('--watch-admin', 'Enable watch', false) + .option('--polling', 'Watching file changes in network directories', false) .option('--browser ', 'Open the browser', true) .description('Start your Strapi application in development mode') .action(getLocalScript('develop')); diff --git a/packages/strapi/lib/commands/develop.js b/packages/strapi/lib/commands/develop.js index 860380da9e..833f89347f 100644 --- a/packages/strapi/lib/commands/develop.js +++ b/packages/strapi/lib/commands/develop.js @@ -14,7 +14,7 @@ const strapi = require('../index'); * `$ strapi develop` * */ -module.exports = async function({ build, watchAdmin, browser }) { +module.exports = async function({ build, watchAdmin, polling, browser }) { const dir = process.cwd(); const config = loadConfiguration(dir); @@ -77,6 +77,7 @@ module.exports = async function({ build, watchAdmin, browser }) { dir, strapiInstance, watchIgnoreFiles: adminWatchIgnoreFiles, + polling, }); process.on('message', message => { @@ -106,7 +107,7 @@ module.exports = async function({ build, watchAdmin, browser }) { * @param {Strapi} options.strapi - Strapi instance * @param {array} options.watchIgnoreFiles - Array of custom file paths that should not be watched */ -function watchFileChanges({ dir, strapiInstance, watchIgnoreFiles }) { +function watchFileChanges({ dir, strapiInstance, watchIgnoreFiles, polling }) { const restart = () => { if (strapiInstance.reload.isWatching && !strapiInstance.reload.isReloading) { strapiInstance.reload.isReloading = true; @@ -116,6 +117,7 @@ function watchFileChanges({ dir, strapiInstance, watchIgnoreFiles }) { const watcher = chokidar.watch(dir, { ignoreInitial: true, + usePolling: polling, ignored: [ /(^|[/\\])\../, // dot files /tmp/, diff --git a/yarn.lock b/yarn.lock index 9d0d91e585..1164f2b340 100644 --- a/yarn.lock +++ b/yarn.lock @@ -215,19 +215,12 @@ dependencies: "@babel/types" "^7.12.1" -"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.10.4": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.10.4.tgz#4c5c54be04bd31670a7382797d75b9fa2e5b5620" - integrity sha512-nEQJHqYavI217oD9+s5MUBzk6x1IlvoS9WTPfgG43CbMEeStE0v+r+TucWdx8KFGowPGvyOkDT9+7DHedIDnVw== +"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.10.4", "@babel/helper-module-imports@^7.12.1", "@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.7.0": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.12.13.tgz#ec67e4404f41750463e455cc3203f6a32e93fcb0" + integrity sha512-NGmfvRp9Rqxy0uHSSVP+SRIW1q31a7Ji10cLBcqSDUngGentY4FRiHOFZFE1CLU5eiL0oE8reH7Tg1y99TDM/g== dependencies: - "@babel/types" "^7.10.4" - -"@babel/helper-module-imports@^7.12.1", "@babel/helper-module-imports@^7.7.0": - version "7.12.5" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.12.5.tgz#1bfc0229f794988f76ed0a4d4e90860850b54dfb" - integrity sha512-SR713Ogqg6++uexFRORf/+nPXMmWIn80TALu0uaFb+iQIUoR7bOC7zBWyzBs5b3tBBJXuyD0cRu1F15GyzjOWA== - dependencies: - "@babel/types" "^7.12.5" + "@babel/types" "^7.12.13" "@babel/helper-module-transforms@^7.10.4", "@babel/helper-module-transforms@^7.10.5", "@babel/helper-module-transforms@^7.12.1": version "7.12.1" @@ -251,10 +244,10 @@ dependencies: "@babel/types" "^7.10.4" -"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": - version "7.10.4" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.4.tgz#2f75a831269d4f677de49986dff59927533cf375" - integrity sha512-O4KCvQA6lLiMU9l2eawBPMf1xPP8xPfB3iEQw150hOVTqj/rfXz0ThTb4HEzqQfs2Bmo5Ay8BzxfzVtBrr9dVg== +"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.12.13.tgz#174254d0f2424d8aefb4dd48057511247b0a9eeb" + integrity sha512-C+10MXCXJLiR6IeG9+Wiejt9jmtFpxUc3MQqCmPY8hfCjyUGl9kT+B2okzEZrtykiwrc4dbCPdDoz0A/HQbDaA== "@babel/helper-regex@^7.10.4": version "7.10.5" @@ -318,6 +311,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.10.4.tgz#a78c7a7251e01f616512d31b10adcf52ada5e0d2" integrity sha512-3U9y+43hz7ZM+rzG24Qe2mufW5KhvFg/NhnNph+i9mgCtdTCtMJuI1TMkrIUiK7Ix4PYlRF9I5dhqaLYA/ADXw== +"@babel/helper-validator-identifier@^7.12.11": + version "7.12.11" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz#c9a1f021917dcb5ccf0d4e453e399022981fc9ed" + integrity sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw== + "@babel/helper-wrap-function@^7.10.4": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.10.4.tgz#8a6f701eab0ff39f765b5a1cfef409990e624b87" @@ -825,14 +823,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.10.4" -"@babel/plugin-transform-runtime@^7.9.0": - version "7.11.5" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.11.5.tgz#f108bc8e0cf33c37da031c097d1df470b3a293fc" - integrity sha512-9aIoee+EhjySZ6vY5hnLjigHzunBlscx9ANKutkeWTJTx6m5Rbq6Ic01tLvO54lSusR+BxV7u4UDdCmXv5aagg== +"@babel/plugin-transform-runtime@^7.12.15": + version "7.12.15" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.12.15.tgz#4337b2507288007c2b197059301aa0af8d90c085" + integrity sha512-OwptMSRnRWJo+tJ9v9wgAf72ydXWfYSXWhnQjZing8nGZSDFqU1MBleKM3+DriKkcbv7RagA8gVeB0A1PNlNow== dependencies: - "@babel/helper-module-imports" "^7.10.4" - "@babel/helper-plugin-utils" "^7.10.4" - resolve "^1.8.1" + "@babel/helper-module-imports" "^7.12.13" + "@babel/helper-plugin-utils" "^7.12.13" semver "^5.5.1" "@babel/plugin-transform-shorthand-properties@^7.10.4": @@ -1002,10 +999,10 @@ core-js-pure "^3.0.0" regenerator-runtime "^0.13.4" -"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.5", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5", "@babel/runtime@^7.2.0", "@babel/runtime@^7.4.0", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": - version "7.12.5" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.5.tgz#410e7e487441e1b360c29be715d870d9b985882e" - integrity sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg== +"@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.2", "@babel/runtime@^7.10.5", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.2.0", "@babel/runtime@^7.4.0", "@babel/runtime@^7.4.4", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.2", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.12.13.tgz#0a21452352b02542db0ffb928ac2d3ca7cb6d66d" + integrity sha512-8+3UMPBrjFa/6TtKi/7sehPKqfAm4g6K+YQjyyFOLUTxzOngcRZTlAVY8sc2CORJYqdHQY8gRPHmn+qo15rCBw== dependencies: regenerator-runtime "^0.13.4" @@ -1042,6 +1039,15 @@ lodash "^4.17.19" to-fast-properties "^2.0.0" +"@babel/types@^7.12.13": + version "7.12.13" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.12.13.tgz#8be1aa8f2c876da11a9cf650c0ecf656913ad611" + integrity sha512-oKrdZTld2im1z8bDwTOQvUbxKwE+854zc16qWZQlcTqMN00pWxHQ4ZeOq0yDMnisOpRykH2/5Qqcrk/OlbAjiQ== + dependencies: + "@babel/helper-validator-identifier" "^7.12.11" + lodash "^4.17.19" + to-fast-properties "^2.0.0" + "@bcoe/v8-coverage@^0.2.3": version "0.2.3" resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" @@ -2702,72 +2708,72 @@ "@sendgrid/client" "^6.4.0" "@sendgrid/helpers" "^6.4.0" -"@sentry/core@6.0.3": - version "6.0.3" - resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.0.3.tgz#620cb32365a11eac75497bed281bd52b9f0bb359" - integrity sha512-UykB/4/98y2DkNvwTiL2ofFPuK3KDHc7rIRNsdj6dg6D+Cf7FRexgmWUUkZrpC/y+QBj0TPqkcFDcZAuQDa3Ag== +"@sentry/core@6.1.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.1.0.tgz#7dd4584dcaf2188a78b94b766068342e6ee65229" + integrity sha512-57mXkp3NoyxRycXrL+Ec6bYS6UYJZp9tYX0lUp5Ry2M0FxDZ3Q4drkjr8MIQOhBaQXP2ukSX4QTVLGMPm60zMw== dependencies: - "@sentry/hub" "6.0.3" - "@sentry/minimal" "6.0.3" - "@sentry/types" "6.0.3" - "@sentry/utils" "6.0.3" + "@sentry/hub" "6.1.0" + "@sentry/minimal" "6.1.0" + "@sentry/types" "6.1.0" + "@sentry/utils" "6.1.0" tslib "^1.9.3" -"@sentry/hub@6.0.3": - version "6.0.3" - resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.0.3.tgz#097f7b1e775a4c6c20c9bec60d7507d5ad2e8db0" - integrity sha512-BfV32tE09rjTWM9W0kk8gzxUC2k1h57Z5dNWJ35na79+LguNNtCcI6fHlFQ3PkJca6ITYof9FI8iQHUfsHFZnw== +"@sentry/hub@6.1.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.1.0.tgz#fb22734c91c9d68564737996bf28b7e032e3d8ee" + integrity sha512-JnBSCgNg3VHiMojUl5tCHU8iWPVuE+qqENIzG9A722oJms1kKWBvWl+yQzhWBNdgk5qeAY3F5UzKWJZkbJ6xow== dependencies: - "@sentry/types" "6.0.3" - "@sentry/utils" "6.0.3" + "@sentry/types" "6.1.0" + "@sentry/utils" "6.1.0" tslib "^1.9.3" -"@sentry/minimal@6.0.3": - version "6.0.3" - resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.0.3.tgz#6eaaf78c479c49720df3e712d41518e7f4f0ffdf" - integrity sha512-YsW+nw0SMyyb7UQdjZeKlZjxbGsJFpXNLh9iIp6fHKnoLTTv17YPm2ej9sOikDsQuVotaPg/xn/Qt5wySGHIxw== +"@sentry/minimal@6.1.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.1.0.tgz#b3abf76d93b95477a3c1029db810818bdc56845f" + integrity sha512-g6sfNKenL7wnsr/tibp8nFiMv/XRH0s0Pt4p151npmNI+SmjuUz3GGYEXk8ChCyaKldYKilkNOFdVXJxUf5gZw== dependencies: - "@sentry/hub" "6.0.3" - "@sentry/types" "6.0.3" + "@sentry/hub" "6.1.0" + "@sentry/types" "6.1.0" tslib "^1.9.3" -"@sentry/node@^6.0.3": - version "6.0.3" - resolved "https://registry.yarnpkg.com/@sentry/node/-/node-6.0.3.tgz#f41e707db710fd7c48e3bffdf05c8edeec95cbe9" - integrity sha512-yvj/e91NPiTtkjUvQSdTqAlRkEw0f/jIC70abobtWH0ExUJOuLHOPWMCpAYST8Adv2QV7eGEhywseRrY1dxSsw== +"@sentry/node@6.1.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@sentry/node/-/node-6.1.0.tgz#9e20443fdfd15e508da5c0b674ef32960e8a6380" + integrity sha512-yOxYHoPxg8Br19QOsJbonP2uYirv1FFxdNkdeykfO2QBorRUkcirjET5qjRfz73jF1YYtUZBuxwR+f9ZOPqGTg== dependencies: - "@sentry/core" "6.0.3" - "@sentry/hub" "6.0.3" - "@sentry/tracing" "6.0.3" - "@sentry/types" "6.0.3" - "@sentry/utils" "6.0.3" + "@sentry/core" "6.1.0" + "@sentry/hub" "6.1.0" + "@sentry/tracing" "6.1.0" + "@sentry/types" "6.1.0" + "@sentry/utils" "6.1.0" cookie "^0.4.1" https-proxy-agent "^5.0.0" lru_map "^0.3.3" tslib "^1.9.3" -"@sentry/tracing@6.0.3": - version "6.0.3" - resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.0.3.tgz#103f4942ddd546321e22ba20c011adf52b25b3f2" - integrity sha512-H7dnsvPz9cD1nuCNQM4MxcHxt2JdT9F8dQ/4+gp+eB9iBLy6staMrmKRLYuAcMU/M3MCDG4ISIip7KbTt74OLg== +"@sentry/tracing@6.1.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.1.0.tgz#cefabd0e4794fefb6a0a17478a8f09b2f1f3d889" + integrity sha512-s6a4Ra3hHn4awiNz4fOEK6TCV2w2iLcxdppijcYEB7S/1rJpmqZgHWDicqufbOmVMOLmyKLEQ7w+pZq3TR3WgQ== dependencies: - "@sentry/hub" "6.0.3" - "@sentry/minimal" "6.0.3" - "@sentry/types" "6.0.3" - "@sentry/utils" "6.0.3" + "@sentry/hub" "6.1.0" + "@sentry/minimal" "6.1.0" + "@sentry/types" "6.1.0" + "@sentry/utils" "6.1.0" tslib "^1.9.3" -"@sentry/types@6.0.3": - version "6.0.3" - resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.0.3.tgz#a1ef6d6b2ac2a9201e3e4a894db6ecf7ceb5b27c" - integrity sha512-266aBQbk9AGedhG2dzXshWbn23LYLElXqlI74DLku48UrU2v7TGKdyik/8/nfOfquCoRSp0GFGYHbItwU124XQ== +"@sentry/types@6.1.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.1.0.tgz#5f9379229423ca1325acf6709e95687180f67132" + integrity sha512-kIaN52Fw5K+2mKRaHE2YluJ+F/qMGSUzZXIFDNdC6OUMXQ4TM8gZTrITXs8CLDm7cK8iCqFCtzKOjKK6KyOKAg== -"@sentry/utils@6.0.3": - version "6.0.3" - resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.0.3.tgz#114d9faa47f76416c3e140711465e76d2129dba8" - integrity sha512-lvuBFvZHYs1zYwI8dkC8Z8ryb0aYnwPFUl1rbZiMwJpYI2Dgl1jpqqZWv9luux2rSRYOMid74uGedV708rvEgA== +"@sentry/utils@6.1.0": + version "6.1.0" + resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.1.0.tgz#52e3d7050983e685d3a48f9d2efa1e6eb4ae3e6d" + integrity sha512-6JAplzUOS6bEwfX0PDRZBbYRvn9EN22kZfcL0qGHtM9L0QQ5ybjbbVwOpbXgRkiZx++dQbzLFtelxnDhsbFG+Q== dependencies: - "@sentry/types" "6.0.3" + "@sentry/types" "6.1.0" tslib "^1.9.3" "@sindresorhus/is@^0.14.0": @@ -12780,10 +12786,10 @@ markdown-it-footnote@^3.0.2: resolved "https://registry.yarnpkg.com/markdown-it-footnote/-/markdown-it-footnote-3.0.2.tgz#1575ee7a093648d4e096aa33386b058d92ac8bc1" integrity sha512-JVW6fCmZWjvMdDQSbOT3nnOQtd9iAXmw7hTSh26+v42BnvXeVyGMDBm5b/EZocMed2MbCAHiTX632vY0FyGB8A== -markdown-it-ins@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/markdown-it-ins/-/markdown-it-ins-3.0.0.tgz#b1b56824c78dc66e52b0fc97531b317cd78d79d2" - integrity sha512-+vyAdBuMGwmT2yMlAFJSx2VR/0QZ1onQ/Mkkmr4l9tDFOh5sVoAgRbkgbuSsk+sxJ9vaMH/IQ323ydfvQrPO/Q== +markdown-it-ins@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/markdown-it-ins/-/markdown-it-ins-3.0.1.tgz#c09356b917cf1dbf73add0b275d67ab8c73d4b4d" + integrity sha512-32SSfZqSzqyAmmQ4SHvhxbFqSzPDqsZgMHDwxqPzp+v+t8RsmqsBZRG+RfRQskJko9PfKC2/oxyOs4Yg/CfiRw== markdown-it-mark@^3.0.1: version "3.0.1" @@ -13536,12 +13542,7 @@ node-abi@^2.7.0: dependencies: semver "^5.4.1" -node-addon-api@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.0.tgz#f9afb8d777a91525244b01775ea0ddbe1125483b" - integrity sha512-ASCL5U13as7HhOExbT6OlWJJUV/lLzL2voOSP1UVehpRD8FbSrSDjfScK/KwAvVTI5AS6r4VwbOMlIqtvRidnA== - -node-addon-api@^3.1.0: +node-addon-api@^3.0.0, node-addon-api@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.1.0.tgz#98b21931557466c6729e51cb77cd39c965f42239" integrity sha512-flmrDNB06LIl5lywUz7YlNGZH/5p0M7W28k8hzd9Lshtdh1wshD2Y+U4h9LD6KObOy1f+fEVdgprPrEymjM5uw== @@ -13713,10 +13714,10 @@ nodemailer-shared@1.1.0: dependencies: nodemailer-fetch "1.6.0" -nodemailer@6.4.17: - version "6.4.17" - resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.4.17.tgz#8de98618028953b80680775770f937243a7d7877" - integrity sha512-89ps+SBGpo0D4Bi5ZrxcrCiRFaMmkCt+gItMXQGzEtZVR3uAD3QAQIDoxTWnx3ky0Dwwy/dhFrQ+6NNGXpw/qQ== +nodemailer@6.4.18: + version "6.4.18" + resolved "https://registry.yarnpkg.com/nodemailer/-/nodemailer-6.4.18.tgz#2788c85792844fc17befda019031609017f4b9a1" + integrity sha512-ht9cXxQ+lTC+t00vkSIpKHIyM4aXIsQ1tcbQCn5IOnxYHi81W2XOaU66EQBFFpbtzLEBTC94gmkbD4mGZQzVpA== noop-logger@^0.1.1: version "0.1.1" @@ -16877,7 +16878,7 @@ resolve@1.1.x: resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= -resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.10.1, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.16.1, resolve@^1.17.0, resolve@^1.18.1, resolve@^1.3.2, resolve@^1.8.1: +resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.10.1, resolve@^1.12.0, resolve@^1.13.1, resolve@^1.16.1, resolve@^1.17.0, resolve@^1.18.1, resolve@^1.3.2: version "1.18.1" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.18.1.tgz#018fcb2c5b207d2a6424aee361c5a266da8f4130" integrity sha512-lDfCPaMKfOJXjy0dPayzPdF1phampNWr3qFCjAu+rw/qbQmr5jWH5xN2hwh9QKfw9E5v4hwV7A+jrCmL8yjjqA== @@ -18217,12 +18218,12 @@ sprintf-js@~1.0.2: resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= -sqlite3@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/sqlite3/-/sqlite3-5.0.0.tgz#1bfef2151c6bc48a3ab1a6c126088bb8dd233566" - integrity sha512-rjvqHFUaSGnzxDy2AHCwhHy6Zp6MNJzCPGYju4kD8yi6bze4d1/zMTg6C7JI49b7/EM7jKMTvyfN/4ylBKdwfw== +sqlite3@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/sqlite3/-/sqlite3-5.0.1.tgz#d5b58c8d1568bbaf13062eb9465982f36324f78a" + integrity sha512-kh2lTIcYNfmVcvhVJihsYuPj9U0xzBbh6bmqILO2hkryWSC9RRhzYmkIDtJkJ+d8Kg4wZRJ0T1reyHUEspICfg== dependencies: - node-addon-api "2.0.0" + node-addon-api "^3.0.0" node-pre-gyp "^0.11.0" optionalDependencies: node-gyp "3.x" @@ -18882,10 +18883,10 @@ svgo@^1.0.0: unquote "~1.1.1" util.promisify "~1.0.0" -swagger-ui-dist@3.41.1: - version "3.41.1" - resolved "https://registry.yarnpkg.com/swagger-ui-dist/-/swagger-ui-dist-3.41.1.tgz#1cb803fab9aef9bd45e1848068908887a23bf27f" - integrity sha512-Wg3RqMBp8dSYEwyvXOWuOTwh3fTxYxmtAvLjEbUwRlPXKEHcde3BG/v2zjswrDVcumUpPQ6Cp5RG3LMz6M0YIw== +swagger-ui-dist@3.43.0: + version "3.43.0" + resolved "https://registry.yarnpkg.com/swagger-ui-dist/-/swagger-ui-dist-3.43.0.tgz#b064a2cec1d27776f9a124bc70423cfa0bbc0d3f" + integrity sha512-PtE+g23bNbYv8qqAVoPBqNQth8hU5Sl5ZsQ7gHXlO5jlCt31dVTiKI9ArHIT1b23ZzUYTnKsFgPYYFoiWyNCAw== switchback@^2.0.1: version "2.0.5"
{formatMessage({ id: option.descriptionId })}