diff --git a/.env.development.sample b/.env.development.sample index 255b88e1..41e7d515 100644 --- a/.env.development.sample +++ b/.env.development.sample @@ -1 +1,3 @@ -NEXT_PUBLIC_GRAPHQL_URI="http://localhost:3001" \ No newline at end of file +NEXT_PUBLIC_GRAPHQL_URI="http://localhost:3001" +MONGO_URI="mongodb://localhost:27017/vns" +APOLLO_SERVER_CORS_WHITELIST="http://localhost:3000" \ No newline at end of file diff --git a/README.md b/README.md index 73857c6e..28841770 100644 --- a/README.md +++ b/README.md @@ -32,13 +32,14 @@ You can start editing the page by modifying `pages/index.js`. The page auto-upda ...To be completed. -## Other Next frameworks, and Next+Apollo boilerplates +## Other cool Next stuff - [Official Apollo example from Next](https://github.com/zeit/next.js/tree/canary/examples/with-apollo) - [Next Right Now](https://github.com/UnlyEd/next-right-now) (a complete Next Starter, relying on Prisma cloud solutions for the backend) - [Blitz](https://blitzjs.com/) (fullstack Next without GraphQL) - [Next react Graphql Apollo Bootstrap](https://github.com/Sebastp/Next-react-graphql-apollo_Boostrap) -- [Next advanced starter](https://github.com/borisowsky/next-advanced-starter) +- [Next advanced starter](https://github.com/borisowsky/next-advanced-starter), +- [Next - Mongo](https://github.com/hoangvvo/nextjs-mongodb-app) (no Express, no GraphQL, just Next and Mongo) # About Next diff --git a/cypress/integration/vns/mongo.spec.ts b/cypress/integration/vns/mongo.spec.ts new file mode 100644 index 00000000..dcd16773 --- /dev/null +++ b/cypress/integration/vns/mongo.spec.ts @@ -0,0 +1,6 @@ +describe("connect to mongo", () => { + it("get the best restaurants in town", () => { + cy.visit("/vns/debug/mongo"); + cy.get("li").should("have.length", 5); + }); +}); diff --git a/docs/features.md b/docs/features.md index a03a5c7a..6b73d256 100644 --- a/docs/features.md +++ b/docs/features.md @@ -40,6 +40,22 @@ GraphQL Playground is available on `api/graphql`. All API routes of Next are loc Open `api/debug/graphql-voyager` and explore your API visually. +## MongoDB + +### Lambda safe connection + +Relevant docs: + +[Official tutorial without mongoose](https://developer.mongodb.com/how-to/nextjs-building-modern-applications) + +[Best practice for Mongo in AWS Lambda](https://docs.atlas.mongodb.com/best-practices-connecting-to-aws-lambda/) + +### Mongoose for schema modelling + +### Conversion between GraphQL ID and Mongoose ID types + +https://github.com/apollographql/apollo-server/issues/1633 + ## Code architecture and build ### Code in `src` diff --git a/package.json b/package.json index 88972074..39d4619c 100644 --- a/package.json +++ b/package.json @@ -66,6 +66,7 @@ "i18next-http-backend": "^1.0.15", "isomorphic-unfetch": "3.0.0", "lodash": "^4.17.15", + "mongoose": "^5.9.19", "next": "9.4.0", "next-i18next": "5.0.0-beta.2", "next-with-apollo": "5.0.1", @@ -89,6 +90,7 @@ "@testing-library/react": "^10.2.0", "@testing-library/react-hooks": "^3.3.0", "@types/jest": "^25.2.3", + "@types/mongoose": "^5.7.27", "@types/node": "^13.7.6", "@types/react": "^16.9.23", "@types/react-dom": "^16.9.5", diff --git a/src/lib/api/cors.ts b/src/api/cors.ts similarity index 78% rename from src/lib/api/cors.ts rename to src/api/cors.ts index f068cba7..b058500a 100644 --- a/src/lib/api/cors.ts +++ b/src/api/cors.ts @@ -1,4 +1,6 @@ import { parseEnvVariableArray } from "~/lib/utils"; +import debug from "debug"; +const debugCors = debug("vns:cors"); const corsWhitelist = parseEnvVariableArray( process.env.APOLLO_SERVER_CORS_WHITELIST @@ -9,6 +11,7 @@ const corsWhitelist = parseEnvVariableArray( */ const corsOptions = { origin: function (origin, callback) { + debugCors("Origin is", origin, "Allowed origins are ", corsWhitelist); if (!origin) { // same origin callback(null, true); diff --git a/src/api/middlewares/mongoConnection.ts b/src/api/middlewares/mongoConnection.ts new file mode 100644 index 00000000..ac278dc5 --- /dev/null +++ b/src/api/middlewares/mongoConnection.ts @@ -0,0 +1,68 @@ +/** + * This middleware relies on Express + * + * @see https://developer.mongodb.com/how-to/nextjs-building-modern-applications + * @see https://docs.atlas.mongodb.com/best-practices-connecting-to-aws-lambda/ + * @see https://github.com/vercel/next.js/discussions/12229 + */ + +import { Request, Response } from "express"; +import mongoose from "mongoose"; +// Import mongoose models here +import "~/api/mongoose/models"; + +/* +async function closeDbConnection() { + try { + await mongoose.connection.close(); + } catch (err) { + // Catch locally error + } +} +*/ + +import debug from "debug"; +const debugMongo = debug("vns:mongo"); + +// trigger the initial connection on app startup +export const connectToDb = async () => { + if (![1, 2].includes(mongoose.connection.readyState)) { + debugMongo("Call mongoose connect"); + return await mongoose.connect(process.env.MONGO_URI, { + useNewUrlParser: true, + }); + } + debugMongo("Ran connectToDb, already connected or connecting to Mongo"); +}; + +const mongoConnectionMiddleware = () => { + // init the first database connection on server startup + connectToDb(); + // mongoose.set("useFindAndModify", false); + + // then return a middleware that checks the connection on every call + return async (req: Request, res: Response, next) => { + try { + // To debug the number of connections in Mongo client: db.serverStatus().connections + await connectToDb(); + + // Do not forget to close connection on finish and close events + // NOTE: actually we don't need this. Db connection close should happen on lambda destruction instead. + // res.on("finish", closeDbConnection); + // res.on("close", closeDbConnection); + next(); + } catch (err) { + res.status(500); + res.send("Could not connect to db"); + } + }; +}; + +export default mongoConnectionMiddleware; + +// We need to add a converter between Mongoose ID and Apollo Server +// @see https://github.com/apollographql/apollo-server/issues/1633 +const ObjectId = require("mongoose").Types.ObjectId; +ObjectId.prototype.valueOf = function () { + return this.toString(); +}; diff --git a/src/api/mongoose/models.ts b/src/api/mongoose/models.ts new file mode 100644 index 00000000..2378b75e --- /dev/null +++ b/src/api/mongoose/models.ts @@ -0,0 +1,2 @@ +// Add your models here +import "mongoose"; diff --git a/src/pages/api/graphql.ts b/src/pages/api/graphql.ts index 7409147d..b40828bd 100644 --- a/src/pages/api/graphql.ts +++ b/src/pages/api/graphql.ts @@ -1,8 +1,10 @@ import express from "express"; import cors from "cors"; -import corsOptions from "~/lib/api/cors"; +import mongoose from "mongoose"; +import corsOptions from "~/api/cors"; import { ApolloServer, gql } from "apollo-server-express"; import { makeExecutableSchema } from "graphql-tools"; +import mongoConnection from "~/api/middlewares/mongoConnection"; /** * Sample, naive, Apollo server. You can move this code in `src/server` @@ -14,16 +16,32 @@ import { makeExecutableSchema } from "graphql-tools"; const typeDefs = gql` type Query { users: [User!]! + restaurants: [Restaurant] } type User { name: String } + type Restaurant { + _id: ID! + name: String + } `; const resolvers = { Query: { users() { return [{ name: "Rick" }, { name: "Morty" }]; }, + // Demo with mongoose + // Expected the database to be setup with the demo "restaurant" API from mongoose + async restaurants() { + const db = mongoose.connection; + const restaurants = await db + .collection("restaurants") + .find(null, null) + .limit(5) + .toArray(); + return restaurants; + }, }, }; const schema = makeExecutableSchema({ typeDefs, resolvers }); @@ -47,8 +65,11 @@ const app = express(); app.set("trust proxy", true); const gqlPath = "/api/graphql"; +// setup cors app.use(gqlPath, cors(corsOptions)); -// You could init the db connection here too +// init the db +app.use(gqlPath, mongoConnection()); + server.applyMiddleware({ app, path: "/api/graphql" }); export default app; diff --git a/src/pages/vns/debug/mongo.tsx b/src/pages/vns/debug/mongo.tsx new file mode 100644 index 00000000..cbcd9e0b --- /dev/null +++ b/src/pages/vns/debug/mongo.tsx @@ -0,0 +1,38 @@ +import { useQuery } from "@apollo/react-hooks"; +import gql from "graphql-tag"; +import { withApollo } from "@vulcan/next-apollo"; +const MongoDebugPage = () => { + const { data, loading, error } = useQuery( + gql` + query restaurants { + restaurants { + _id + name + } + } + ` + ); + if (loading) return <>Thinking about restaurants...; // NOTE: in TypeScript with React we can't return just a string + if (error) + return ( +
+ I could not remember any restaurant, sorry... Error: {error.message} +
+ ); + + const { restaurants } = data; + + return ( +
+

First 5 restaurants that comes to my mind:

+ +
+ ); +}; +export default withApollo(MongoDebugPage, { + graphqlUri: "http://localhost:3000/api/graphql", +}); diff --git a/yarn.lock b/yarn.lock index 319ac3df..a25bfe1d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2994,6 +2994,13 @@ resolved "https://registry.yarnpkg.com/@types/braces/-/braces-3.0.0.tgz#7da1c0d44ff1c7eb660a36ec078ea61ba7eb42cb" integrity sha512-TbH79tcyi9FHwbyboOKeRachRq63mSuWYXOflsNO9ZyE5ClQ/JaozNKl+aWUq87qPNsXasXxi2AbgfwIJ+8GQw== +"@types/bson@*": + version "4.0.2" + resolved "https://registry.yarnpkg.com/@types/bson/-/bson-4.0.2.tgz#7accb85942fc39bbdb7515d4de437c04f698115f" + integrity sha512-+uWmsejEHfmSjyyM/LkrP0orfE2m5Mx9Xel4tXNeqi1ldK5XMQcDsFkBmLDtuyKUbxj2jGDo0H240fbCRJZo7Q== + dependencies: + "@types/node" "*" + "@types/color-name@^1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" @@ -3221,6 +3228,22 @@ resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== +"@types/mongodb@*": + version "3.5.23" + resolved "https://registry.yarnpkg.com/@types/mongodb/-/mongodb-3.5.23.tgz#e360ca025348bcc11328ce9a22099734401a2330" + integrity sha512-v4Ay/0av+oDUsj3P6TT6UIGDlLKnpnokO5e3TFR53FSOngc7QX+BBZ0KgnIk4Vtna6ODoL6Jcy/uQobvmCnn8g== + dependencies: + "@types/bson" "*" + "@types/node" "*" + +"@types/mongoose@^5.7.27": + version "5.7.27" + resolved "https://registry.yarnpkg.com/@types/mongoose/-/mongoose-5.7.27.tgz#8cb259fa463c466aba305937a31967727ad804d1" + integrity sha512-6+QFJg4jUM91dJYsJk32FuREOJ7ghgzxj4c+BV3+aK7a9fFGbghQRteB14P94fGXhJN63b2mBqf7luBHvCRFtg== + dependencies: + "@types/mongodb" "*" + "@types/node" "*" + "@types/node-fetch@2.5.7", "@types/node-fetch@^2.5.4": version "2.5.7" resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.7.tgz#20a2afffa882ab04d44ca786449a276f9f6bbf3c" @@ -4930,6 +4953,19 @@ bindings@^1.5.0: dependencies: file-uri-to-path "1.0.0" +bl@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/bl/-/bl-2.2.0.tgz#e1a574cdf528e4053019bb800b041c0ac88da493" + integrity sha512-wbgvOpqopSr7uq6fJrLH8EsvYMJf9gzfo2jCsL2eTy75qXPukA4pCgHamOQkZtY5vmfVtjB+P3LNlMHW5CEZXA== + dependencies: + readable-stream "^2.3.5" + safe-buffer "^5.1.1" + +bluebird@3.5.1: + version "3.5.1" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" + integrity sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA== + bluebird@3.5.3: version "3.5.3" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.3.tgz#7d01c6f9616c9a51ab0f8c549a79dfe6ec33efa7" @@ -5251,6 +5287,11 @@ bser@2.1.1: dependencies: node-int64 "^0.4.0" +bson@^1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/bson/-/bson-1.1.4.tgz#f76870d799f15b854dffb7ee32f0a874797f7e89" + integrity sha512-S/yKGU1syOMzO86+dGpg2qGoDL0zvzcb262G+gqEy6TgP6rt6z6qxSFX/8X6vLC91P7G7C3nLs0+bvDzmvBA3Q== + buffer-crc32@~0.2.3: version "0.2.13" resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" @@ -6567,6 +6608,13 @@ debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.0, debug@^2.6.9: dependencies: ms "2.0.0" +debug@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" + integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== + dependencies: + ms "2.0.0" + debug@4.1.1, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" @@ -6684,6 +6732,11 @@ delegates@^1.0.0: resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= +denque@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/denque/-/denque-1.4.1.tgz#6744ff7641c148c3f8a69c307e51235c1f4a37cf" + integrity sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ== + depd@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" @@ -10308,6 +10361,11 @@ jsx-ast-utils@^2.2.3: array-includes "^3.1.1" object.assign "^4.1.0" +kareem@2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/kareem/-/kareem-2.3.1.tgz#def12d9c941017fabfb00f873af95e9c99e1be87" + integrity sha512-l3hLhffs9zqoDe8zjmb/mAN4B8VT3L56EUvKNqLFVs9YlFA+zx7ke1DO8STAdDyYNkeSo1nKmjuvQeI12So8Xw== + kind-of@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-2.0.1.tgz#018ec7a4ce7e3a86cb9141be519d24c8faa981b5" @@ -10794,6 +10852,11 @@ memory-fs@^0.5.0: errno "^0.1.3" readable-stream "^2.0.1" +memory-pager@^1.0.2: + version "1.5.0" + resolved "https://registry.yarnpkg.com/memory-pager/-/memory-pager-1.5.0.tgz#d8751655d22d384682741c972f2c3d6dfa3e66b5" + integrity sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg== + merge-deep@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/merge-deep/-/merge-deep-3.0.2.tgz#f39fa100a4f1bd34ff29f7d2bf4508fbb8d83ad2" @@ -11057,6 +11120,41 @@ moment@2.24.0: resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b" integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg== +mongodb@3.5.9: + version "3.5.9" + resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-3.5.9.tgz#799b72be8110b7e71a882bb7ce0d84d05429f772" + integrity sha512-vXHBY1CsGYcEPoVWhwgxIBeWqP3dSu9RuRDsoLRPTITrcrgm1f0Ubu1xqF9ozMwv53agmEiZm0YGo+7WL3Nbug== + dependencies: + bl "^2.2.0" + bson "^1.1.4" + denque "^1.4.1" + require_optional "^1.0.1" + safe-buffer "^5.1.2" + optionalDependencies: + saslprep "^1.0.0" + +mongoose-legacy-pluralize@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz#3ba9f91fa507b5186d399fb40854bff18fb563e4" + integrity sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ== + +mongoose@^5.9.19: + version "5.9.19" + resolved "https://registry.yarnpkg.com/mongoose/-/mongoose-5.9.19.tgz#fadedce84e3f49b7ea335b73d2a60d2df97d69e1" + integrity sha512-wJ5FR2ykvyd17MRHA6sku/N1CMaC/kf4CnN357htD48RpzJhW60YDkxPSPLbkLg8Woa+i7jYi0glhzC0EcBcRQ== + dependencies: + bson "^1.1.4" + kareem "2.3.1" + mongodb "3.5.9" + mongoose-legacy-pluralize "1.0.2" + mpath "0.7.0" + mquery "3.2.2" + ms "2.1.2" + regexp-clone "1.0.0" + safe-buffer "5.1.2" + sift "7.0.1" + sliced "1.0.1" + move-concurrently@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" @@ -11069,6 +11167,22 @@ move-concurrently@^1.0.1: rimraf "^2.5.4" run-queue "^1.0.3" +mpath@0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/mpath/-/mpath-0.7.0.tgz#20e8102e276b71709d6e07e9f8d4d0f641afbfb8" + integrity sha512-Aiq04hILxhz1L+f7sjGyn7IxYzWm1zLNNXcfhDtx04kZ2Gk7uvFdgZ8ts1cWa/6d0TQmag2yR8zSGZUmp0tFNg== + +mquery@3.2.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/mquery/-/mquery-3.2.2.tgz#e1383a3951852ce23e37f619a9b350f1fb3664e7" + integrity sha512-XB52992COp0KP230I3qloVUbkLUxJIu328HBP2t2EsxSFtf4W1HPSOBWOXf1bqxK4Xbb66lfMJ+Bpfd9/yZE1Q== + dependencies: + bluebird "3.5.1" + debug "3.1.0" + regexp-clone "^1.0.0" + safe-buffer "5.1.2" + sliced "1.0.1" + ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -11079,7 +11193,7 @@ ms@2.1.1: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== -ms@^2.1.1: +ms@2.1.2, ms@^2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== @@ -13063,7 +13177,7 @@ read-pkg@^5.2.0: parse-json "^5.0.0" type-fest "^0.6.0" -"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6: +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6: version "2.3.7" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== @@ -13202,6 +13316,11 @@ regex-parser@2.2.10: resolved "https://registry.yarnpkg.com/regex-parser/-/regex-parser-2.2.10.tgz#9e66a8f73d89a107616e63b39d4deddfee912b37" integrity sha512-8t6074A68gHfU8Neftl0Le6KTDwfGAj7IyjPIMSfikI2wJUTHDMaIq42bUsfVnj8mhx0R+45rdUXHGpN164avA== +regexp-clone@1.0.0, regexp-clone@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/regexp-clone/-/regexp-clone-1.0.0.tgz#222db967623277056260b992626354a04ce9bf63" + integrity sha512-TuAasHQNamyyJ2hb97IuBEif4qBHGjPHBS64sZwytpLEqtBQ1gPJTnOaQ6qmpET16cK14kkjbazl6+p0RRv0yw== + regexp.prototype.flags@^1.2.0, regexp.prototype.flags@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.3.0.tgz#7aba89b3c13a64509dabcf3ca8d9fbb9bdf5cb75" @@ -13394,6 +13513,14 @@ require-main-filename@^2.0.0: resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== +require_optional@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/require_optional/-/require_optional-1.0.1.tgz#4cf35a4247f64ca3df8c2ef208cc494b1ca8fc2e" + integrity sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g== + dependencies: + resolve-from "^2.0.0" + semver "^5.1.0" + resize-observer-polyfill@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464" @@ -13406,6 +13533,11 @@ resolve-cwd@^3.0.0: dependencies: resolve-from "^5.0.0" +resolve-from@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57" + integrity sha1-lICrIOlP+h2egKgEx+oUdhGWa1c= + resolve-from@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" @@ -13621,6 +13753,13 @@ sane@^4.0.3: minimist "^1.1.1" walker "~1.0.5" +saslprep@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/saslprep/-/saslprep-1.0.3.tgz#4c02f946b56cf54297e347ba1093e7acac4cf226" + integrity sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag== + dependencies: + sparse-bitfield "^3.0.3" + sass-loader@8.0.2: version "8.0.2" resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-8.0.2.tgz#debecd8c3ce243c76454f2e8290482150380090d" @@ -13683,7 +13822,7 @@ select@^1.1.2: resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d" integrity sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0= -"semver@2 || 3 || 4 || 5", semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: +"semver@2 || 3 || 4 || 5", semver@^5.1.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: version "5.7.1" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== @@ -13876,6 +14015,11 @@ side-channel@^1.0.2: es-abstract "^1.17.0-next.1" object-inspect "^1.7.0" +sift@7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/sift/-/sift-7.0.1.tgz#47d62c50b159d316f1372f8b53f9c10cd21a4b08" + integrity sha512-oqD7PMJ+uO6jV9EQCl0LrRw1OwsiPsiFQR5AR30heR+4Dl7jBBbDLnNvWiak20tzZlSE1H7RB30SX/1j/YYT7g== + signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" @@ -13942,6 +14086,11 @@ slice-ansi@^2.1.0: astral-regex "^1.0.0" is-fullwidth-code-point "^2.0.0" +sliced@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/sliced/-/sliced-1.0.1.tgz#0b3a662b5d04c3177b1926bea82b03f837a2ef41" + integrity sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E= + snapdragon-node@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" @@ -14035,6 +14184,13 @@ space-separated-tokens@^1.0.0: resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz#85f32c3d10d9682007e917414ddc5c26d1aa6899" integrity sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA== +sparse-bitfield@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz#ff4ae6e68656056ba4b3e792ab3334d38273ca11" + integrity sha1-/0rm5oZWBWuks+eSqzM004JzyhE= + dependencies: + memory-pager "^1.0.2" + spawn-wrap@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/spawn-wrap/-/spawn-wrap-2.0.0.tgz#103685b8b8f9b79771318827aa78650a610d457e"