├── .gitignore
├── .env
├── README.md
├── public
├── stylesheets
│ └── style.css
└── index.html
├── IoC-container
├── providers
│ ├── databaseProvider.js
│ ├── repositoriesProvider.js
│ ├── cacheProvider.js
│ ├── queryHandlersProvider.js
│ └── httpProvider.js
├── index.js
└── Container.js
├── chain-of-responsibility-software-design-pattern.jpg
├── routes
├── index.js
└── users.js
├── commons
├── redis.js
└── knex.js
├── accessEnv.js
├── repositories
├── UserDataRepository.js
├── GitHubAPIRepository.js
├── StorageQueryHandlersManager.js
├── HttpServiceRepository.js
└── DatabaseTableRepository.js
├── app.js
├── package.json
├── query-handlers
├── FileSystemQueryTaskHandler.js
├── PostgreSQLDatabaseQueryTaskHandler.js
├── RESTServiceQueryTaskHandler.js
├── GraphQLServiceQueryTaskHandler.js
├── StorageQueryTaskHandler.js
└── RedisCacheQueryTaskHandler.js
├── caches
├── CacheWithEncryption.js
├── CacheWithBytePacking.js
└── Cache.js
├── helpers.js
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
--------------------------------------------------------------------------------
/.env:
--------------------------------------------------------------------------------
1 | NODE_ENV=development
2 | AWS_SDK_ACCESS_ID=
3 | AWS_SDK_ACCESS_SECRET=
4 | AWS_SDK_REGION=us-east-1
5 | AWS_SDK_SESSION_TOKEN=i-session
6 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # expressjs-api-gateway-coding-patterns-demo
2 | Created with CodeSandbox
3 |
4 |
5 |
--------------------------------------------------------------------------------
/public/stylesheets/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | padding: 50px;
3 | font: 14px "Lucida Grande", Helvetica, Arial, sans-serif;
4 | }
5 |
6 | a {
7 | color: #00B7FF;
8 | }
9 |
--------------------------------------------------------------------------------
/IoC-container/providers/databaseProvider.js:
--------------------------------------------------------------------------------
1 | const knex = require("../../commons/knex");
2 |
3 | module.exports = function (c) {
4 | c.service("Database", () => knex);
5 | };
6 |
--------------------------------------------------------------------------------
/chain-of-responsibility-software-design-pattern.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/isocroft/expressjs-api-gateway-coding-patterns-demo/HEAD/chain-of-responsibility-software-design-pattern.jpg
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Express
5 |
6 |
7 |
8 |
9 | Express
10 | Welcome to Express
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/routes/index.js:
--------------------------------------------------------------------------------
1 | var express = require('express');
2 | var router = express.Router();
3 |
4 | /* GET home page. */
5 | router.get('/', function(req, res, next) {
6 | res.render('index', { title: 'Express' });
7 | });
8 |
9 | module.exports = router;
10 |
--------------------------------------------------------------------------------
/commons/redis.js:
--------------------------------------------------------------------------------
1 | const accessEnv = require("../accessEnv");
2 | const { createClient } = require("redis");
3 |
4 | module.exports = createClient({
5 | url: `redis://${accessEnv("REDIS_USERNAME", "alice")}:${accessEnv(
6 | "REDIS_PASSWORD",
7 | "inwonderland"
8 | )}@${accessEnv("REDIS_SERVER", "custom.redis.server")}:${accessEnv(
9 | "REDIS_PORT",
10 | 6380
11 | )}`
12 | });
13 |
--------------------------------------------------------------------------------
/accessEnv.js:
--------------------------------------------------------------------------------
1 | const cache = {};
2 |
3 | const accessEnv = (key, defaultValue) => {
4 | if (!(key in process.env)) {
5 | if (defaultValue) {
6 | return defaultValue;
7 | }
8 | throw new Error(`${key} not found in process.env!`);
9 | }
10 |
11 | if (cache[key]) return cache[key];
12 |
13 | cache[key] = process.env[key];
14 |
15 | return process.env[key] || defaultValue;
16 | };
17 |
18 | module.exports = accessEnv;
19 |
--------------------------------------------------------------------------------
/routes/users.js:
--------------------------------------------------------------------------------
1 | const express = require("express");
2 | const router = express.Router();
3 |
4 | const container = require("../IoC-container");
5 |
6 | /* GET users listing. */
7 | router.get("/", function (req, res, next) {
8 | const { status } = req.query;
9 | container.UserModelRepository.fetchAll(["*"], (buidler) => {
10 | buidler.where("status", status);
11 | });
12 | res.send("respond with a resource");
13 | });
14 |
15 | module.exports = router;
16 |
--------------------------------------------------------------------------------
/IoC-container/index.js:
--------------------------------------------------------------------------------
1 | const Container = require("./Container");
2 |
3 | module.exports = (function () {
4 | let container = new Container();
5 |
6 | require("./providers/cacheProvider")(container);
7 | require("./providers/databaseProvider")(container);
8 | require("./providers/httpProvider")(container);
9 | require("./providers/queryHandlersProvider")(container);
10 | require("./providers/repositoriesProvider")(container);
11 |
12 | return container;
13 | })();
14 |
--------------------------------------------------------------------------------
/commons/knex.js:
--------------------------------------------------------------------------------
1 | const accessEnv = require("../accessEnv");
2 |
3 | module.exports = require("knex")({
4 | client: accessEnv("DB_DRIVER", "pg"),
5 | version: accessEnv("DB_DRIVER_VERSION", "5.7"),
6 | connection: {
7 | host: accessEnv("DB_HOST", "127.0.0.1"),
8 | port: accessEnv("DB_PORT", 5432),
9 | user: accessEnv("DB_USER", ""),
10 | password: accessEnv("DB_PASSWORD", ""),
11 | database: accessEnv("DB_NAME", "app")
12 | }
13 | });
14 |
--------------------------------------------------------------------------------
/IoC-container/Container.js:
--------------------------------------------------------------------------------
1 | class Container {
2 | constructor() {
3 | this.services = {};
4 | }
5 |
6 | service(name, cb) {
7 | Object.defineProperty(this, name, {
8 | get: () => {
9 | if (!this.services.hasOwnProperty(name)) {
10 | this.services[name] = cb(this);
11 | }
12 |
13 | return this.services[name];
14 | },
15 | configurable: true,
16 | enumerable: true
17 | });
18 |
19 | return this;
20 | }
21 | }
22 |
23 | module.exports = Container;
24 |
--------------------------------------------------------------------------------
/repositories/UserDataRepository.js:
--------------------------------------------------------------------------------
1 | const DatabaseTableRepository = require("./DatabaseTableRepository");
2 |
3 | /* @HINT: This is the user data repository class. */
4 |
5 | class UserDataRepository extends DatabaseTableRepository {
6 | constructor (queryTaskHandlers, Database) {
7 | super(queryTaskHandlers)
8 | this.Database = Database
9 | }
10 |
11 | get table() {
12 | return "users";
13 | }
14 |
15 | get queryBuilder() {
16 | return this.Database(this.table);
17 | }
18 |
19 | async fetchAllUsers (columnsToFetch = ['*']) {
20 | return await this.fetchAll(columnsToFetch)
21 | }
22 | }
23 |
24 | module.exports = UserDataRepository;
25 |
--------------------------------------------------------------------------------
/IoC-container/providers/repositoriesProvider.js:
--------------------------------------------------------------------------------
1 | const GitHubAPIRepository = require("../../repositories/GitHubAPIRepository");
2 | const UserDataRepository = require("../../repositories/UserDataRepository");
3 |
4 | module.exports = function (c) {
5 | c.service(
6 | "UserModelRepository",
7 | (c) =>
8 | new UserDataRepository([
9 | c.RedisCacheQueryTaskHandler,
10 | c.PostgreSQLDatabaseQueryTaskHandler
11 | ], c.Database)
12 | );
13 | c.service(
14 | "GitHubAPIRepository",
15 | (c) => new GitHubAPIRepository([
16 | c.RESTServiceQueryTaskHandler,
17 | /* @HINT: Redundancy, in case GitHub REST API is down, use the GraphQL API instead */
18 | c.GraphQLServiceQueryTaskHandler
19 | ], c.LRUCache)
20 | );
21 | };
22 |
--------------------------------------------------------------------------------
/IoC-container/providers/cacheProvider.js:
--------------------------------------------------------------------------------
1 | const accessEnv = require("../../accessEnv");
2 | const redis = require("../../commons/redis");
3 |
4 | const QuickLRU = require('quick-lru');
5 |
6 | const Cache = require("../../caches/Cache");
7 | const CacheWithBytePacking = require("../../caches/CacheWithBytePacking");
8 | const CacheWithEncryption = require("../../caches/CacheWithEncryption");
9 |
10 | module.exports = function (c) {
11 | c.service("LRUCache", () => new QuickLRU({ maxSize: 1000, maxAge: 180000 }))
12 | c.service("RedisCache", () => redis);
13 | c.service(
14 | "Cache",
15 | (c) => new Cache(redis, accessEnv("REDIS_KEY_PREFIX", ""))
16 | );
17 | c.service("BytePackedCache", (c) => new CacheWithBytePacking(c.Cache));
18 | c.service(
19 | "EncryptedCache",
20 | (c) => new CacheWithEncryption(c.CacheWithBytePacking)
21 | );
22 | };
23 |
--------------------------------------------------------------------------------
/app.js:
--------------------------------------------------------------------------------
1 | const dotenv = require("dotenv");
2 |
3 | dotenv.config();
4 |
5 | const express = require("express");
6 | const path = require("path");
7 | const cookieParser = require("cookie-parser");
8 | const logger = require("morgan");
9 | const accessEnv = require("./accessEnv");
10 |
11 | const indexRouter = require("./routes/index");
12 | const usersRouter = require("./routes/users");
13 |
14 | const app = express();
15 |
16 | app.use(logger("dev"));
17 | app.use(express.json());
18 | app.use(express.urlencoded({ extended: false }));
19 | app.use(cookieParser());
20 | app.use(express.static(path.join(__dirname, "public")));
21 |
22 | app.use("/", indexRouter);
23 | app.use("/users", usersRouter);
24 |
25 | const PORT = accessEnv("PORT", 3001);
26 |
27 | const listener = app.listen(PORT, "127.0.0.1", () => {
28 | console.info(`API gateway listening on port ${listener.address().port}`);
29 | });
30 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "expressjs-demo-coding-patterns",
3 | "version": "1.0.0",
4 | "description": "A DEMO with Express.js showing implementation of a cache, database and graphql query handlers for a data repository using 3 coding patterns \n\n- chain-of-responsibility pattern\n- decorator pattern\n- repository pattern",
5 | "main": "app.js",
6 | "private": true,
7 | "scripts": {
8 | "start": "nodemon app.js localhost 8080"
9 | },
10 | "dependencies": {
11 | "aws4": "1.12.0",
12 | "aws-sdk": "2.1617.0",
13 | "cookie-parser": "~1.4.4",
14 | "debug": "~2.6.9",
15 | "dotenv": "8.2.0",
16 | "express": "~4.16.1",
17 | "got": "8.3.2",
18 | "gotql": "1.0.0",
19 | "knex": "0.21.1",
20 | "morgan": "~1.9.1",
21 | "pg": "8.10.0",
22 | "quick-lru": "5.1.1",
23 | "redis": "4.6.5"
24 | },
25 | "devDependencies": {
26 | "nodemon": "1.18.4"
27 | },
28 | "keywords": []
29 | }
30 |
--------------------------------------------------------------------------------
/IoC-container/providers/queryHandlersProvider.js:
--------------------------------------------------------------------------------
1 | const PostgreSQLDatabaseQueryTaskHandler = require("../../query-handlers/PostgreSQLDatabaseQueryTaskHandler");
2 | const GraphQLServiceQueryTaskHandler = require("../../query-handlers/GraphQLServiceQueryTaskHandler");
3 | const RESTServiceQueryTaskHandler = require("../../query-handlers/RESTServiceQueryTaskHandler");
4 | const RedisCacheQueryTaskHandler = require("../../query-handlers/RedisCacheQueryTaskHandler");
5 |
6 | module.exports = function (c) {
7 | c.service(
8 | "PostgreSQLDatabaseQueryTaskHandler",
9 | (c) => new PostgreSQLDatabaseQueryTaskHandler(c.Database)
10 | );
11 | c.service(
12 | "RedisCacheQueryTaskHandler",
13 | (c) => new RedisCacheQueryTaskHandler(c.EncryptedCache)
14 | );
15 | c.service(
16 | "GraphQLServiceQueryTaskHandler",
17 | (c) => new GraphQLServiceQueryTaskHandler(c.GraphQLClient)
18 | );
19 | c.service(
20 | "RESTServiceQueryTaskHandler",
21 | (c) => new RESTServiceQueryTaskHandler(c.RestClient)
22 | );
23 | };
24 |
--------------------------------------------------------------------------------
/query-handlers/FileSystemQueryTaskHandler.js:
--------------------------------------------------------------------------------
1 | const StorageQueryTaskHandler = require("./StorageQueryTaskHandler");
2 |
3 | const { isEmpty } = require("../helpers");
4 |
5 | /* @HINT: This is a file system query task handler for any file system and files/folders. */
6 | class FileSystemQueryTaskHandler extends StorageQueryTaskHandler {
7 | constructor(fileClient, contextTransformMap = {}) {
8 | super(
9 | "file system handler execution declined; either stalled connection or refused connection"
10 | );
11 | this.fileClient = fileClient;
12 | this.migrateContextTransformMap = contextTransformMap;
13 | }
14 |
15 | migrateContext (builderOrRequest) {
16 | if (typeof builderOrRequest.url !== "string") {
17 | return {};
18 | }
19 |
20 | return this.migrateContextTransformMap[`${builderOrRequest.method.toLowerCase()}|${builderOrRequest.url}`];
21 | }
22 |
23 | async beginProcessing (fileSystemQuery) {
24 | return isEmpty(fileSystemQuery) ? this.skipHandlerProcessing() : "";
25 | }
26 |
27 | async finalizeProcessing() {
28 | console.log("e don finish file system request ooo");
29 | }
30 |
31 | async finalizeProcessingWithError() {
32 | console.error("e don finish file system request with error ooo");
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/repositories/GitHubAPIRepository.js:
--------------------------------------------------------------------------------
1 | const HttpServiceRepository = require("./HttpServiceRepository");
2 |
3 | /* @HINT: This is the github (third-party) api repository class. */
4 |
5 | class GitHubAPIRepository extends HttpServiceRepository {
6 | constructor (queryTaskHandlers, httpLRUCache = null) {
7 | super(queryTaskHandlers)
8 | this.httpCache = httpLRUCache
9 | }
10 |
11 | get apiVersion () {
12 | return "2022-11-28"
13 | }
14 |
15 | baseURL(pathName = "/") {
16 | return `https://api.github.com${pathName}`;
17 | }
18 |
19 | requestConfig(
20 | pathName = "/",
21 | httpMethod = "GET",
22 | headers = {},
23 | requestParams = {}
24 | ) {
25 | const $config = super.requestConfig(
26 | pathName,
27 | httpMethod,
28 | Object.assign(headers, {
29 | accept: 'application/json',
30 | 'content-type': 'application/json'
31 | }),
32 | requestParams
33 | )
34 |
35 | return Object.assign(
36 | {},
37 | { timeout: this.httpTimeout, cache: this.httpCache },
38 | $config
39 | );
40 | }
41 |
42 | async getAllNotifications (pollingInterval = 60) {
43 | return this.httpGetRequest({
44 | headers: {
45 | 'x-poll-interval': String(pollingInterval),
46 | 'X-GitHub-Api-Version': this.apiVersion
47 | },
48 | pathName: '/notifications'
49 | })
50 | }
51 | }
52 |
53 | module.exports = GitHubAPIRepository;
54 |
--------------------------------------------------------------------------------
/repositories/StorageQueryHandlersManager.js:
--------------------------------------------------------------------------------
1 | const StorageQueryTaskHandler = require("../query-handlers/StorageQueryTaskHandler");
2 |
3 | /* @HINT: This is a storage query manger for all data access an storage needs of a data repository. */
4 | class StorageQueryHandlersManager {
5 | constructor(storageQueryHandlers = []) {
6 | const totalCount = storageQueryHandlers.length;
7 |
8 | if (totalCount === 0) {
9 | throw new Error("Cannot proceed: No storage query task handlers found");
10 | }
11 |
12 | for (let count = 0; count + 1 < totalCount && totalCount > count; count++) {
13 | const previousQueryTaskHandler = storageQueryHandlers[count];
14 | const nextQueryTaskHandler = storageQueryHandlers[count + 1];
15 |
16 | if (previousQueryTaskHandler instanceof StorageQueryTaskHandler) {
17 | previousQueryTaskHandler.setNextHandler(nextQueryTaskHandler);
18 | } else {
19 | continue;
20 | }
21 | }
22 |
23 | const [rootTaskHandler] = storageQueryHandlers;
24 |
25 | this.rootTaskHandler = rootTaskHandler;
26 | }
27 |
28 | async execute(queryObject) {
29 | return this.rootTaskHandler.handle(
30 | queryObject
31 | );
32 | }
33 |
34 | swapRootHandler(newRootTaskHandler) {
35 | if (!(newRootTaskHandler instanceof StorageQueryTaskHandler)) {
36 | throw new Error(
37 | "Cannot proceed: root handler not swapable as object provided isn't a handler"
38 | );
39 | }
40 |
41 | const formerRootTaskHandler = this.rootTaskHandler;
42 |
43 | this.rootTaskHandler = newRootTaskHandler;
44 | this.rootTaskHandler.setNextHandler(formerRootTaskHandler);
45 | }
46 | }
47 |
48 | module.exports = StorageQueryHandlersManager;
49 |
--------------------------------------------------------------------------------
/caches/CacheWithEncryption.js:
--------------------------------------------------------------------------------
1 | const Cache = require("./Cache");
2 | const CacheWithBytePacking = require("./CacheWithBytePacking");
3 | const { encryptData, decryptData } = require("../helpers");
4 |
5 | /* @NOTE: | We can change the behavior of this class by switching its' injected cache */
6 |
7 | /* @NOTE: By switching the injected cache with a class that has the same interface contract, we maintain simplicity */
8 |
9 | /* @NOTE: This class implements the Decorator coding pattern for encrypted cache */
10 |
11 | /* @HINT: This is the cache (with encryption) base/parent class. */
12 |
13 | class CacheWithEncryption {
14 | constructor(redis) {
15 | if (!(redis instanceof CacheWithBytePacking) || !(redis instanceof Cache)) {
16 | throw new Error("Cannot construct encrypted cache instance");
17 | }
18 |
19 | this.$_ = redis;
20 | }
21 |
22 | async get(key) {
23 | const buffer = await this.$_.get(key, {
24 | asBuffer: true,
25 | withEncoding: "base64"
26 | });
27 |
28 | return decryptData(buffer);
29 | }
30 |
31 | async set(key, value) {
32 | await this.$_.set(key, encryptData(value), { asBuffer: true });
33 | }
34 |
35 | async establishConnectionWithRedisServer({ timeoutInMilliSeconds }) {
36 | await this.$_.establishConnectionWithRedisServer({ timeoutInMilliSeconds });
37 | }
38 |
39 | async destroyConnectionWithRedisServer() {
40 | await this.$_.destroyConnectionWithRedisServer();
41 | }
42 |
43 | async hasKey(key) {
44 | return await this.$_.hasKey(key);
45 | }
46 |
47 | async allKeys(keyOrPattern) {
48 | return await this.$_.allKeys(keyOrPattern);
49 | }
50 | }
51 |
52 | module.exports = CacheWithEncryption;
53 |
--------------------------------------------------------------------------------
/caches/CacheWithBytePacking.js:
--------------------------------------------------------------------------------
1 | const Cache = require("./Cache");
2 | const {
3 | convertBinaryStringToBytesArray,
4 | convertBytesArrayToBinaryString,
5 | pack,
6 | unpack
7 | } = require("../helpers");
8 |
9 | /* @CHECK: https://blog.shalvah.me/posts/packing-and-unpacking-bytes */
10 |
11 | /* @NOTE: This base class implements the Decorator coding pattern for byte-packed cache */
12 |
13 | /* @HINT: This is the cache (with byte-packing) base/parent class. */
14 |
15 | class CacheWithBytePacking {
16 | constructor(redis) {
17 | if (!(redis instanceof Cache)) {
18 | throw new Error("Cannot construct byte-packed cache instance");
19 | }
20 |
21 | this._$ = redis;
22 | }
23 |
24 | async get(key, { asBuffer = true, withEncoding = "utf8" }) {
25 | const buffer = await this._$.get(key, {
26 | asBuffer: asBuffer || true,
27 | withEncoding
28 | });
29 |
30 | const bytes = [];
31 |
32 | for (let byte of buffer.values()) {
33 | bytes.push(byte);
34 | }
35 |
36 | return Buffer.from(
37 | unpack(convertBytesArrayToBinaryString(new Uint8Array(bytes))),
38 | withEncoding
39 | );
40 | }
41 |
42 | async set(key, value, { asBuffer = true }) {
43 | if (typeof value !== "string") {
44 | return;
45 | }
46 |
47 | let modifiedValue = convertBinaryStringToBytesArray(value);
48 |
49 | await this._$.set(key, pack(modifiedValue), {
50 | asBuffer: asBuffer || true
51 | });
52 | }
53 |
54 | async establishConnectionWithRedisServer({ timeoutInMilliSeconds }) {
55 | await this._$.establishConnectionWithRedisServer({ timeoutInMilliSeconds });
56 | }
57 |
58 | async destroyConnectionWithRedisServer() {
59 | await this._$.destroyConnectionWithRedisServer();
60 | }
61 |
62 | async hasKey(key) {
63 | return await this._$.hasKey(key);
64 | }
65 |
66 | async allKeys(keyOrPattern) {
67 | return await this._$.allKeys(keyOrPattern);
68 | }
69 | }
70 |
71 | module.exports = CacheWithBytePacking;
72 |
--------------------------------------------------------------------------------
/caches/Cache.js:
--------------------------------------------------------------------------------
1 | const { commandOptions } = require("redis");
2 | const { waitFor } = require("../helpers");
3 |
4 | /* @HINT: This is the reis cache base/parent class. */
5 |
6 | class Cache {
7 | constructor(redis, keyPrefix = "") {
8 | this.keyPrefix = keyPrefix;
9 | this.redis = redis;
10 | }
11 |
12 | async set(key, value, { asBuffer = false }) {
13 | if (typeof value !== "string") {
14 | return;
15 | }
16 | // Buffer.from("", "utf16le");
17 | await this.redis.set(
18 | this.keyPrefix + key,
19 | asBuffer ? Buffer.from(value) : value
20 | );
21 | }
22 |
23 | async get(key, { asBuffer = false, withEncoding = "utf8" }) {
24 | if (asBuffer) {
25 | const buffer = await this.redis.get(
26 | commandOptions({ returnBuffers: asBuffer }),
27 | this.keyPrefix + key
28 | );
29 |
30 | if (!buffer.isEncoding(withEncoding)) {
31 | const characters = buffer.toString(withEncoding);
32 | return Buffer.from(characters, withEncoding);
33 | }
34 |
35 | return buffer;
36 | } else {
37 | return await this.redis.get(this.keyPrefix + key);
38 | }
39 | }
40 |
41 | async allKeys(keyOrPattern) {
42 | const keys = [];
43 | for await (const scannedKey of this.redis.scanIterator({
44 | type: "string",
45 | MATCH: keyOrPattern,
46 | COUNT: 10
47 | })) {
48 | keys.push(scannedKey);
49 | }
50 |
51 | return keys;
52 | }
53 |
54 | async hasKey(key) {
55 | const keys = await this.allKeys(key);
56 | return keys.length > 0;
57 | }
58 |
59 | async establishConnectionWithRedisServer({ timeoutInMilliSeconds }) {
60 | await this.redis.connect();
61 | await waitFor(
62 | () => this.redis.isOpen && this.redis.isReady,
63 | 100,
64 | timeoutInMilliSeconds
65 | ).orThrow(new Error("Couldn't establish connection with redis server"));
66 | }
67 |
68 | async destroyConnectionWithRedisServer() {
69 | await this.redis.disconnect();
70 | }
71 | }
72 |
73 | module.exports = Cache;
74 |
--------------------------------------------------------------------------------
/IoC-container/providers/httpProvider.js:
--------------------------------------------------------------------------------
1 | const accessEnv = require("../../accessEnv");
2 |
3 | const gotQl = require('gotql')
4 | const got = require("got");
5 |
6 | const url = require('url');
7 | const AWS = require('aws-sdk');
8 | const AWS4 = require('aws4');
9 |
10 | const { isEmpty } = require("../../helpers");
11 |
12 | const awsConfig = new AWS.Config({
13 | accessKeyId: accessEnv("AWS_SDK_ACCESS_ID", 'ACC_ID'),
14 | secretAccessKey: accessEnv("AWS_SDK_ACCESS_SECRET", 'ACC_SECRET'),
15 | region: accessEnv("AWS_SDK_REGION", 'us-west-2'),
16 | credentials: new AWS.Credentials({
17 | accessKeyId: accessEnv("AWS_SDK_ACCESS_ID", 'ACC_ID'),
18 | secretAccessKey: accessEnv("AWS_SDK_ACCESS_SECRET", 'ACC_SECRET'),
19 | sessionToken: accessEnv("AWS_SDK_SESSION_TOKEN", 'session')
20 | })
21 | });
22 |
23 | const awsSdkOptions = {
24 | region: awsConfig.region,
25 | headers: {
26 | accept: 'application/json',
27 | 'content-type': 'application/json'
28 | },
29 | method: 'GET',
30 | json: true
31 | };
32 |
33 | /* @NOTE: | We are wrapping and exposing a similar contract to the logic being wrapped for consumption */
34 |
35 | /* @NOTE: This function implements the Adapter coding pattern for data query tasks */
36 |
37 | const awsClient = (uri, options) => {
38 | let requestPayload = {}
39 | /* @HINT: We need to parse the URL before passing it to `got` so `aws4` can sign the request */
40 | if (typeof uri === "string") {
41 | requestPayload = Object.assign(
42 | typeof url['parse'] === "function"
43 | ? url.parse(uri)
44 | : new url.URL(uri),
45 | awsSdkOptions,
46 | options || {}
47 | );
48 | } else {
49 | if (uri instanceof Object) {
50 | requestPayload = uri
51 | }
52 | }
53 |
54 | if (isEmpty(requestPayload)) {
55 | throw new Error("no valid http request object");
56 | }
57 |
58 | AWS4.sign(
59 | requestPayload,
60 | awsConfig.credentials
61 | );
62 |
63 | return got(requestPayload);
64 | };
65 |
66 | module.exports = function (c) {
67 | c.service("AWSHttpClient", () => awsClient);
68 | c.service("RestClient", () => got);
69 | c.service("GraphQLClient", () => gotQl)
70 | };
71 |
--------------------------------------------------------------------------------
/query-handlers/PostgreSQLDatabaseQueryTaskHandler.js:
--------------------------------------------------------------------------------
1 | const StorageQueryTaskHandler = require("./StorageQueryTaskHandler");
2 |
3 | /* @NOTE: | Don't create premature parent classes | Keep it simple! */
4 |
5 | /* @HINT: This is a database query task handler for a PostgreSQL database. */
6 | /* @HINT: There is no need to create a parent class `DatabaseQueryTaskHandler` yet. */
7 | /* @HINT:
8 | If for the meantime PostgreSQL is the database of choice now and there's no
9 | indication that this will change in the forseeable future, then, there no need
10 | to preempt the future by creating a parent base class (`DatabaseQueryTaskHandler`)
11 | and then extending it to create `PostgreSQLDatabaseQueryTaskHandler` derived class
12 | or a `MySQLDatabaseQueryTaskHandler` or `MSSQLDatabaseQueryTaskHandler` derived
13 | classes either
14 | */
15 |
16 | class PostgreSQLDatabaseQueryTaskHandler extends StorageQueryTaskHandler {
17 | constructor(databaseClient) {
18 | super("database handler execution declined");
19 | this.database = databaseClient;
20 | this.databaseConnection = null;
21 | }
22 |
23 | async beginProcessing(builderOrRequest) {
24 | let canProceedWithProcessing = false;
25 |
26 | /* @HINT: Check if variable `builderOrRequest` is a knex query builder instance */
27 | if (builderOrRequest instanceof Object && typeof builderOrRequest.toSQL === "function") {
28 | canProceedWithProcessing = true;
29 | }
30 |
31 | if (!canProceedWithProcessing) {
32 | return this.skipHandlerProcessing();
33 | }
34 |
35 | try {
36 | this.databaseConnection = await this.database.client.acquireConnection();
37 | this.databaseConnection.query('SET timezone="UTC";');
38 | } catch (error) {
39 | return this.skipHandlerProcessing(error);
40 | }
41 |
42 | /* @HINT: Setup a database query timeout via the knex query builder instance */
43 | builderOrRequest.timeout(5500, {
44 | cancel: true
45 | });
46 |
47 | /* @HINT: database query result initialization */
48 | let queryResult = null;
49 |
50 | try {
51 | /* @HINT: Setup database transaction for database query */
52 | await this.database.transaction(async (transaction) => {
53 | /* @CHECK: https://github.com/knex/knex/issues/3018#issuecomment-458781094/ */
54 | queryResult = await builderOrRequest.transacting(transaction);
55 | });
56 | } catch (error) {
57 | return this.skipHandlerProcessing(error);
58 | }
59 |
60 | return queryResult;
61 | }
62 |
63 | async finalizeProcessing() {
64 | await this.database.client.releaseConnection(this.databaseConnection);
65 | }
66 |
67 | async finalizeProcessingWithError() {
68 | console.error("e don finish postgre sql database query with error ooo");
69 | }
70 | }
71 |
72 | module.exports = PostgreSQLDatabaseQueryTaskHandler;
73 |
--------------------------------------------------------------------------------
/repositories/HttpServiceRepository.js:
--------------------------------------------------------------------------------
1 | const StorageQueryHandlersManager = require("./StorageQueryHandlersManager");
2 |
3 | /* @NOTE: | Implicit dependencies can often lead to tight coupling but not always! */
4 |
5 | /* @HINT: This is a http service repository base class. */
6 | class HttpServiceRepository {
7 | constructor(queryHandlers = []) {
8 | /* @NOTE: | Composition can also lead to tight coupling! */
9 | /* @NOTE: Tight coupling here: will allow temporarily */
10 | this.queryManager = new StorageQueryHandlersManager(queryHandlers);
11 | this.timeoutInMilliSeconds = 1500;
12 | }
13 |
14 | set newRootHandler(rootHandler) {
15 | this.queryManager.swapRootHandler(rootHandler);
16 | }
17 |
18 | get httpTimeout () {
19 | return this.timeoutInMilliSeconds
20 | }
21 |
22 | get apiVersion () {
23 | throw new Error("api version not set")
24 | }
25 |
26 | set httpTimeout (newHttpTimeout = 0) {
27 | if (typeof newHttpTimeout === "number"
28 | && !Number.isNaN(newHttpTimeout)) {
29 | this.timeoutInMilliSeconds = newHttpTimeout
30 | }
31 | }
32 |
33 | baseURL(pathName = "/") {
34 | throw new Error(`base URL string with ${pathName} is not available from abstract class`);
35 | }
36 |
37 | requestConfig(
38 | pathName = "/",
39 | httpMethod = "GET",
40 | headers = {},
41 | requestParams = {}
42 | ) {
43 | return {
44 | url: this.baseURL(pathName),
45 | method: httpMethod,
46 | [httpMethod === "GET" || httpMethod === "HEAD" ? "query" : "body"]: requestParams,
47 | headers,
48 | json: headers['content-type'].includes('json'),
49 | form: headers['content-type'].includes('form-data')
50 | };
51 | }
52 |
53 | async httpPostRequest({ headers = {}, pathName = "/", requestParams = {} }) {
54 | const httpRequest = this.requestConfig(
55 | pathName,
56 | "POST",
57 | headers,
58 | requestParams
59 | );
60 |
61 | return this.queryManager.execute(httpRequest);
62 | }
63 |
64 | async httpGetRequest({ headers = {}, pathName = "/", requestParams = {} }) {
65 | const httpRequest = this.requestConfig(
66 | pathName,
67 | "GET",
68 | headers,
69 | requestParams
70 | );
71 |
72 | return this.queryManager.execute(httpRequest);
73 | }
74 |
75 | async httpPutRequest({ headers = {}, pathName = "/", requestParams = {} }) {
76 | const httpRequest = this.requestConfig(
77 | pathName,
78 | "PUT",
79 | headers,
80 | requestParams
81 | );
82 |
83 | return this.queryManager.execute(httpRequest);
84 | }
85 |
86 | async httpDeleteRequest({ headers = {}, pathName = "/", requestParams = {} }) {
87 | const httpRequest = this.requestConfig(
88 | pathName,
89 | "DELETE",
90 | headers,
91 | requestParams
92 | );
93 |
94 | return this.queryManager.execute(httpRequest);
95 | }
96 | }
97 |
98 | module.exports = HttpServiceRepository;
99 |
--------------------------------------------------------------------------------
/query-handlers/RESTServiceQueryTaskHandler.js:
--------------------------------------------------------------------------------
1 | const StorageQueryTaskHandler = require("./StorageQueryTaskHandler");
2 |
3 | /* @HINT: This is a rest service query task handler for a REST API server. */
4 | class RESTServiceQueryTaskHandler extends StorageQueryTaskHandler {
5 | constructor(restClient) {
6 | super(
7 | "rest service handler execution declined; either stalled connection or refused connection"
8 | );
9 | this.httpClient = restClient;
10 | }
11 |
12 | async beginProcessing(builderOrRequest) {
13 | let canProceedWithProcessing = false;
14 | let result = null;
15 |
16 | if (builderOrRequest instanceof Object
17 | && typeof builderOrRequest.url === "string"
18 | && typeof builderOrRequest.method === "string"
19 | && [
20 | "get",
21 | "post",
22 | "patch",
23 | "delete",
24 | "head",
25 | "put"
26 | ].includes(builderOrRequest.method.toLowerCase())) {
27 | canProceedWithProcessing = true;
28 | }
29 |
30 | if (!canProceedWithProcessing) {
31 | return this.skipHandlerProcessing();
32 | }
33 |
34 | try {
35 | result = await this.httpClient(builderOrRequest)
36 | return result;
37 | } catch (error) {
38 | const HttpError = this.httpClient.HTTPError;
39 | const RequestError = this.httpClient.RequestError;
40 | const CancelError = this.httpClient.CancelError;
41 |
42 | if (error instanceof HttpError) {
43 | if (error.statusCode === "400" || error.statusCode === "404" || error.statusCode === "401") {
44 | return this.skipHandlerProcessingWithCustomMessage(
45 | `server "${error.url}" request encountered a service error; reason: ${error.statusMessage}`
46 | );
47 | }
48 | return this.skipHandlerProcessingWithCustomMessage(
49 | `http request to ${error.url} failed; reason: ${error.message}`
50 | );
51 | } else if (error instanceof RequestError) {
52 | if (error.code === 'ETIMEDOUT'
53 | || error.code === 'ECONNREFUSED'
54 | || error.statusCode === "500"
55 | || error.statusCode === "503") {
56 | /* @HINT: This REST API server is down, trigger the next handler to run */
57 | return this.skipHandlerProcessing();
58 | }
59 | return this.skipHandlerProcessingWithCustomMessage(
60 | `http request to ${error.url} failed; reason: ${error.message}`
61 | );
62 | } else if (error instanceof CancelError) {
63 | return this.skipHandlerProcessingWithCustomMessage(
64 | `server "${error.url}" request was cancelled`
65 | );
66 | }
67 | }
68 | }
69 |
70 | async finalizeProcessing(builderOrRequest) {
71 | console.log(`e don finish rest service request ooo; for ${builderOrRequest.url}`);
72 | }
73 |
74 | async finalizeProcessingWithError(builderOrRequest, error) {
75 | console.error(`e don finish rest service request with error: ${error} for ${builderOrRequest.url}`);
76 | }
77 | }
78 |
79 | module.exports = RESTServiceQueryTaskHandler;
80 |
--------------------------------------------------------------------------------
/query-handlers/GraphQLServiceQueryTaskHandler.js:
--------------------------------------------------------------------------------
1 | const StorageQueryTaskHandler = require("./StorageQueryTaskHandler");
2 | const url = require('url');
3 |
4 | const { camelCaseify } = require("../helpers");
5 |
6 | /* @HINT: This is a graphql service query task handler for a GraphQL API server. */
7 | class GraphQLServiceQueryTaskHandler extends StorageQueryTaskHandler {
8 | constructor(graphQlClient, operationNameToFieldsNameMap = { '_': [] }) {
9 | super("graphql service handler execution declined");
10 | this.httpClient = graphQlClient;
11 |
12 | this.pathname = "/graphql"
13 | this.operationNamesMap = operationNameToFieldsNameMap;
14 | }
15 |
16 | set updateGraphQlServicePathname (newPathname = "/") {
17 | this.pathname = newPathname
18 | }
19 |
20 | set updateGraphQlOperationNameToFieldsMap (newOperationNamesMap) {
21 | this.operationNamesMap = newOperationNamesMap
22 | }
23 |
24 | get graphQlServicePathname () {
25 | return this.pathname
26 | }
27 |
28 | get graphQlOperationNameToFieldsMap () {
29 | return this.operationNamesMap
30 | }
31 |
32 | async beginProcessing(builderOrRequest) {
33 | let result = null
34 | let canProceedWithProcessing = false;
35 |
36 | /* @HINT: Check if variable `builderOrRequest` is a knex query builder instance */
37 | if (builderOrRequest instanceof Object
38 | && typeof builderOrRequest.url === "string"
39 | && builderOrRequest.url.endsWith(this.graphQlServicePathname)) {
40 | canProceedWithProcessing = true;
41 | }
42 |
43 | if (!canProceedWithProcessing) {
44 | return this.skipHandlerProcessing();
45 | }
46 |
47 | const url = builderOrRequest.url
48 | const type = builderOrRequest.type
49 | const query = builderOrRequest[type]
50 |
51 | delete builderOrRequest.url
52 | delete builderOrRequest.type
53 | delete builderOrRequest[type]
54 |
55 | try {
56 | result = await this.graphQlClient[type](url, query, builderOrRequest)
57 | return result
58 | } catch (error) {
59 | /* @HINT: re-throw the error using `error.message` */
60 | this.skipHandlerProcessingWithCustomMessage(error.message)
61 | }
62 | }
63 |
64 | migrateContext (builderOrRequest) {
65 | let type = "query"
66 | let operationName = "_"
67 |
68 | if (builderOrRequest['query'] instanceof Object
69 | || builderOrRequest['mutation'] instanceof Object) {
70 | return builderOrRequest;
71 | }
72 |
73 | /* @HINT: transform request object meant for a rest service to a graph ql service payload object */
74 | if (typeof builderOrRequest.url === "string"
75 | && !builderOrRequest.url.endsWith(this.graphQlServicePathname)) {
76 | const { host, pathname } = typeof url['parse'] === "function"
77 | ? url.parse(uri)
78 | : new url.URL(uri);
79 |
80 | operationName = camelCaseify(pathname)
81 | builderOrRequest.url = `${host}${this.graphQlServicePathname}`;
82 | }
83 |
84 | if (typeof builderOrRequest.method === "string"
85 | && builderOrRequest.method !== "POST") {
86 | type = builderOrRequest.method === "GET" || builderOrRequest.method === "GET"
87 | ? "query"
88 | : "mutation"
89 |
90 | delete builderOrRequest.method;
91 | }
92 |
93 | /* @TODO: add `variable` and `args` to `operation` object the JSON-query object for proper GraphQL types */
94 | builderOrRequest[type] = {
95 | operation: {
96 | name: operationName,
97 | fields: this.graphQlOperationToFieldsNameMap[operationName]
98 | }
99 | }
100 |
101 | builderOrRequest.useHttp2 = true
102 | builderOrRequest.type = type
103 |
104 | delete builderOrRequest.body
105 | delete builderOrRequest.query
106 | delete builderOrRequest.form
107 | delete builderOrRequest.timeout
108 |
109 | return builderOrRequest
110 | }
111 |
112 | async finalizeProcessing() {
113 | console.log("e don finish graphql service request ooo");
114 | }
115 |
116 | async finalizeProcessingWithError() {
117 | console.error("e don finish graphql service request with error ooo");
118 | }
119 | }
120 |
121 | module.exports = GraphQLServiceQueryTaskHandler;
122 |
--------------------------------------------------------------------------------
/repositories/DatabaseTableRepository.js:
--------------------------------------------------------------------------------
1 | const StorageQueryHandlersManager = require("./StorageQueryHandlersManager");
2 | const { isEmpty } = require("../helpers");
3 |
4 | /* @NOTE: | Implicit dependencies can often lead to tight coupling but not always! */
5 |
6 | /* @HINT: This is a database table repository base class. */
7 | class DatabaseTableRepository {
8 | constructor(queryHandlers = []) {
9 | /* @NOTE: | Composition can also lead to tight coupling! */
10 | /* @NOTE: Tight coupling (and tight cohesion) here: will allow temporarily */
11 | /* @INFO: `StorageQueryHandlersManager` is a concrete class so we don't extend it, we compose around it */
12 | this.queryManager = new StorageQueryHandlersManager(queryHandlers);
13 | }
14 |
15 | get table() {
16 | throw new Error("table name value is not available from abstract class");
17 | }
18 |
19 | get queryBuidler() {
20 | throw new Error(
21 | "query builder object is not available from abstract class"
22 | );
23 | }
24 |
25 | set newRootHandler(rootHandler) {
26 | this.queryManager.swapRootHandler(rootHandler);
27 | }
28 |
29 | whenConflict(queryBuidler, conflictColumn = undefined) {
30 | /* @CHECK: https://github.com/knex/knex/issues/3018#issuecomment-458781094/ */
31 | return typeof conflictColumn === "string"
32 | ? queryBuidler.onConflict(conflictColumn)
33 | : queryBuidler;
34 | }
35 |
36 | merge(queryBuidler, columnsToMerge = []) {
37 | /* @CHECK: https://github.com/knex/knex/issues/3018#issuecomment-458781094/ */
38 | return Array.isArray(columnsToMerge) && columnsToMerge.length > 0
39 | ? queryBuidler.merge(columnsToMerge)
40 | : queryBuidler.merge();
41 | }
42 |
43 | addWhereClauses(queryBuidler, whereClausesCallback = () => undefined) {
44 | /* @CHECK: https://github.com/knex/knex/issues/3018#issuecomment-458781094/ */
45 | return typeof whereClausesCallback === "function"
46 | ? queryBuidler.where(whereClausesCallback)
47 | : queryBuidler;
48 | }
49 |
50 | async fetchAll(columnsToFetch = ["*"], whereClausesCallback = undefined) {
51 | /* @CHECK: https://github.com/knex/knex/issues/3018#issuecomment-458781094/ */
52 | const queryBuilder = this.queryBuilder;
53 | const { addWhereClauses } = this;
54 |
55 | if (!columnsToFetch || columnsToFetch.length === 0) {
56 | columnsToFetch = ["*"];
57 | }
58 |
59 | return this.queryManager.execute(
60 | addWhereClauses(queryBuilder, whereClausesCallback)
61 | .select(...columnsToFetch)
62 | .clone()
63 | );
64 | }
65 |
66 | async modify(
67 | columnsToFetch = ["*"],
68 | whereClausesCallback = undefined,
69 | rowsToUpdate = {}
70 | ) {
71 | /* @CHECK: https://github.com/knex/knex/issues/3018#issuecomment-458781094/ */
72 | const queryBuilder = this.queryBuilder;
73 | const { addWhereClauses } = this;
74 |
75 | if (isEmpty(rowsToUpdate)) {
76 | throw new Error("Cannot proceed: No rows to update found");
77 | }
78 |
79 | if (!columnsToFetch || columnsToFetch.length === 0) {
80 | columnsToFetch = ["*"];
81 | }
82 |
83 | return this.queryManager.execute(
84 | addWhereClauses(queryBuilder, whereClausesCallback)
85 | .update(rowsToUpdate, columnsToFetch)
86 | .clone()
87 | );
88 | }
89 |
90 | async fetchFirst() {
91 | /* @CHECK: https://github.com/knex/knex/issues/3018#issuecomment-458781094/ */
92 | const queryBuilder = this.queryBuilder;
93 |
94 | return this.queryManager.execute(queryBuilder.first().clone());
95 | }
96 |
97 | async fetchFirstWhere(whereClausesCallback = undefined) {
98 | /* @CHECK: https://github.com/knex/knex/issues/3018#issuecomment-458781094/ */
99 | const queryBuilder = this.queryBuilder;
100 | const { addWhereClauses } = this;
101 |
102 | return this.queryManager.execute(
103 | addWhereClauses(queryBuilder, whereClausesCallback).first().clone()
104 | );
105 | }
106 |
107 | async keepWhenConflict(
108 | rowsToInsert = [],
109 | conflictColumn = "id",
110 | columnsToMerge = []
111 | ) {
112 | /* @CHECK: https://github.com/knex/knex/issues/3018#issuecomment-458781094/ */
113 | const queryBuilder = this.queryBuilder;
114 | const { merge, whenConflict } = this;
115 |
116 | return this.queryManager.execute(
117 | merge(
118 | whenConflict(
119 | queryBuilder.insert(
120 | rowsToInsert.length === 1 ? rowsToInsert[0] : rowsToInsert
121 | ),
122 | conflictColumn
123 | ),
124 | columnsToMerge
125 | ).clone()
126 | );
127 | }
128 | }
129 |
130 | module.exports = DatabaseTableRepository;
131 |
--------------------------------------------------------------------------------
/query-handlers/StorageQueryTaskHandler.js:
--------------------------------------------------------------------------------
1 | /* @NOTE: | We have brought together all the common logic to this base class here! */
2 |
3 | /* @NOTE: This base class implements the Chain-Of-Responsibility coding pattern for data query tasks */
4 |
5 | /* @INFO:
6 | In a language like PHP or Java, this class will be an abstract class with 4 protected and abstract methods:
7 |
8 | - beginProcessing(...);
9 | - finalizeProcessing(...);
10 | - finalizeProcessingWithError(...);
11 | - alternateProcessing(...);
12 |
13 | This abstract class will also have 1 protected and final method:
14 |
15 | - skipHandlerProcessing(...);
16 |
17 | This abstract class will also have 2 public and final methods:
18 |
19 | - handle(...);
20 | - setNextHandler(...);
21 |
22 | This abstract class will have 2 protected methods
23 |
24 | - migrateQueryTask(...);
25 | - skipHandlerProcessingWithCustomMessage(...);
26 | */
27 |
28 | /* @HINT: This is the query task handler base/parent class. */
29 |
30 | class StorageQueryTaskHandler {
31 | constructor(skipHandlerErrorMessage = "") {
32 | /* @INFO 2 private member variables */
33 | this.message = skipHandlerErrorMessage;
34 | this.nextHandler = null;
35 | }
36 |
37 | setNextHandler(handler) {
38 | if (handler instanceof StorageQueryTaskHandler) {
39 | this.nextHandler = handler;
40 | return;
41 | }
42 | throw new Error(
43 | "Cannot set next handler as object provided is not a hanlder"
44 | );
45 | }
46 |
47 | async beginProcessing() {
48 | throw new Error(
49 | "Implementation needed for [protected] [abstract] method {async} `process()`. \r\n\r\n" +
50 | " > This interface is not available from abstract class."
51 | );
52 | }
53 |
54 | skipHandlerProcessing(error) {
55 | if (this.nextHandler === null) {
56 | throw error;
57 | }
58 | throw new Error(this.message);
59 | }
60 |
61 | skipHandlerProcessingWithCustomMessage (message) {
62 | throw new Error(message);
63 | }
64 |
65 | async alternateProcessing () {
66 | throw new Error(
67 | "Implementation needed for [protected] [abstract] method {async} `finalizeProcessing()`. \r\n\r\n" +
68 | " > This interface is not available from abstract class."
69 | );
70 | }
71 |
72 | async finalizeProcessing() {
73 | throw new Error(
74 | "Implementation needed for [protected] [abstract] method {async} `finalizeProcessing()`. \r\n\r\n" +
75 | " > This interface is not available from abstract class."
76 | );
77 | }
78 |
79 | async finalizeProcessingWithError() {
80 | throw new Error(
81 | "Implementation needed for [protected] [abstract] method {async} `finalizeProcessingWithError()`. \r\n\r\n" +
82 | " > This interface is not available from abstract class."
83 | );
84 | }
85 |
86 | migrateQueryTask (builderOrRequest) {
87 | return builderOrRequest;
88 | }
89 |
90 | async handle (builderOrRequest) {
91 | let result = null;
92 | let processingError = null;
93 | let noResult = true;
94 | let hasError = false;
95 |
96 | try {
97 | try {
98 | result = await this.beginProcessing(
99 | this.migrateQueryTask(builderOrRequest)
100 | );
101 | noResult = false;
102 | return result;
103 | } catch (error) {
104 | if (!(error instanceof Error)) {
105 | throw error
106 | }
107 |
108 | if (error.message === this.message
109 | && this.nextHandler !== null) {
110 | result = await this.nextHandler.handle(
111 | builderOrRequest
112 | );
113 | noResult = false;
114 | return result;
115 | } else {
116 | hasError = true;
117 | processingError = error;
118 | throw error;
119 | }
120 | } finally {
121 | if (!hasError) {
122 | await this.finalizeProcessing(this.migrateQueryTask(builderOrRequest), result);
123 | } else {
124 | await this.finalizeProcessingWithError(builderOrRequest, processingError);
125 | if (noResult) {
126 | /* @HINT: If there's no result and we have an error, try to get a result from an alternate process */
127 | if (processingError.message === this.message) {
128 | result = await this.alternateProcessing(
129 | this.migrateQueryTask(builderOrRequest)
130 | );
131 | noResult = false;
132 | return result;
133 | }
134 | }
135 | }
136 | }
137 | } catch ($error) {
138 | throw $error;
139 | }
140 |
141 | return result;
142 | }
143 | }
144 |
145 | module.exports = StorageQueryTaskHandler;
146 |
--------------------------------------------------------------------------------
/query-handlers/RedisCacheQueryTaskHandler.js:
--------------------------------------------------------------------------------
1 | const StorageQueryTaskHandler = require("./StorageQueryTaskHandler");
2 | const { murmurHash } = require("../helpers");
3 | /* @NOTE: | The way the code for this class is written, it's totally closed for modification! */
4 |
5 | /* @NOTE: To change the behaviour of this class, you have to swap it's input */
6 |
7 | /* @HINT: This is a cache query task handler for the Redis cache. */
8 |
9 | class RedisCacheQueryTaskHandler extends StorageQueryTaskHandler {
10 | constructor(cacheContainer) {
11 | super("cache handler execution declined");
12 | cacheContainer.on("error", (error) => {
13 | throw new Error(error);
14 | });
15 | this.cache = cacheContainer;
16 | }
17 |
18 | async canQuery (queryKey) {
19 | return this.cache.hasKey(queryKey);
20 | }
21 |
22 | async beginProcessing (builderOrRequest) {
23 | let canProceedWithProcessing = false;
24 | let isSQLDatabaseQueryTask = false;
25 |
26 | /* @HINT: Check if variable `builderOrRequest` is a knex query builder object */
27 | if (typeof builderOrRequest.toSQL === "function") {
28 | /* @CHECK: https://github.com/knex/knex/issues/3018#issuecomment-458781094/ */
29 | const query = builderOrRequest.toSQL();
30 | canProceedWithProcessing = query.sql.toLowerCase().startsWith("select")
31 | && !query.sql.toLowerCase().includes("join");
32 | isSQLDatabaseQueryTask = true
33 | }
34 | /* @HINT: Check if the variable `builderOrRequest` is a http (graphql) request config object */
35 | else if (typeof builderOrRequest.url === "string"
36 | && !builderOrRequest.url.endsWith("/graphql")) {
37 | const hasHeaders = builderOrRequest.headers instanceof Object;
38 | const headers = builderOrRequest.headers;
39 | const method = builderOrRequest.method.toLowerCase();
40 |
41 | /* @HINT: This redis cache query task handler will not handle graphql query tasks */
42 | canProceedWithProcessing = !(hasHeaders
43 | && headers['content-type'] === "application/graphql")
44 | || !(method === "post"
45 | && typeof builderOrRequest.body === "string"
46 | && headers['content-type'] === "application/json"
47 | && /([\s]*){([\s]*)"([\s]*)query([\s]*)"([\s]*)\:([\s]*)"([\s]*){/m.test(
48 | builderOrRequest.body.toLowerCase()
49 | )
50 | ) || !(method === "get"
51 | && typeof builderOrRequest.query === "string"
52 | && builderOrRequest.query.includes("query={")
53 | );
54 | }
55 |
56 | if (!canProceedWithProcessing) {
57 | return this.skipHandlerProcessing();
58 | }
59 |
60 | try {
61 | await this.cache.establishConnectionWithRedisServer({
62 | timeoutInMilliSeconds: 1200
63 | });
64 | } catch (error) {
65 | return this.skipHandlerProcessing(error);
66 | }
67 |
68 | const queryHash = murmurHash(
69 | isSQLDatabaseQueryTask
70 | ? builderOrRequest.toSQL().sql
71 | : `${builderOrRequest.method.toLowerCase()}-${builderOrRequest.url}`
72 | );
73 | const isCacheHit = await this.canQuery(queryHash);
74 |
75 | if (isCacheHit) {
76 | return await this.cache.get(queryHash);
77 | }
78 |
79 | return this.skipHandlerProcessing();
80 | }
81 |
82 | async finalizeProcessing(builderOrRequest, result) {
83 | let canProceedWithProcessing = false;
84 | let isSQLDatabaseQueryTask = false;
85 |
86 | /* @HINT: Check if variable `builderOrRequest` is a knex query builder object */
87 | if (typeof builderOrRequest.toSQL === "function") {
88 | /* @CHECK: https://github.com/knex/knex/issues/3018#issuecomment-458781094/ */
89 | const query = builderOrRequest.toSQL();
90 | canProceedWithProcessing = query.sql.toLowerCase().startsWith("select")
91 | && !query.sql.toLowerCase().includes("join");
92 | isSQLDatabaseQueryTask = true
93 | }
94 | /* @HINT: Check if the variable `builderOrRequest` is a http (graphql) request config object */
95 | else if (typeof builderOrRequest.url === "string"
96 | && !builderOrRequest.url.endsWith("/graphql")) {
97 | const hasHeaders = builderOrRequest.headers instanceof Object;
98 | const headers = builderOrRequest.headers;
99 | const method = builderOrRequest.method.toLowerCase();
100 |
101 | /* @HINT: This redis cache query task handler will not handle graphql query tasks */
102 | canProceedWithProcessing = !(hasHeaders
103 | && headers['content-type'] === "application/graphql")
104 | || !(method === "post"
105 | && typeof builderOrRequest.body === "string"
106 | && headers['content-type'] === "application/json"
107 | && /([\s]*){([\s]*)"([\s]*)query([\s]*)"([\s]*)\:([\s]*)"([\s]*){/m.test(
108 | builderOrRequest.body.toLowerCase()
109 | )
110 | ) || !(method === "get"
111 | && typeof builderOrRequest.query === "string"
112 | && builderOrRequest.query.includes("query={")
113 | );
114 | }
115 |
116 | if (canProceedWithProcessing) {
117 | const queryHash = murmurHash(
118 | isSQLDatabaseQueryTask
119 | ? builderOrRequest.toSQL().sql
120 | : `${builderOrRequest.method.toLowerCase()}-${builderOrRequest.url}`
121 | );
122 | const isCacheMiss = !(await this.canQuery(queryHash));
123 |
124 | if (isCacheMiss) {
125 | await this.cache.set(queryHash, result);
126 | }
127 | }
128 |
129 | await this.cache.destroyConnectionWithRedisServer();
130 | }
131 | }
132 |
133 | module.exports = RedisCacheQueryTaskHandler;
134 |
--------------------------------------------------------------------------------
/helpers.js:
--------------------------------------------------------------------------------
1 | const crypto = require("crypto");
2 |
3 | /**
4 | *
5 | * @param {Number} durationMilliSeconds
6 | *
7 | * @returns {Promise}
8 | *
9 | * @see https://davidwalsh.name/waitfortime/
10 | */
11 | const sleepFor = (durationMilliSeconds = 10) => {
12 | return new Promise((resolve) => setTimeout(resolve, durationMilliSeconds));
13 | };
14 |
15 | /**
16 | *
17 | * @param {Function} conditionCallback
18 | * @param {Number} pollIntervalMilliSeconds
19 | * @param {Number} timeoutAfterMilliSeconds
20 | *
21 | * @returns {Promise}
22 | *
23 | * @see https://davidwalsh.name/waitfor/
24 | */
25 | const waitFor = async (
26 | conditionCallback,
27 | pollIntervalMilliSeconds = 50,
28 | timeoutAfterMilliSeconds = 3000
29 | ) => {
30 | const startTimeMilliSeconds = Date.now();
31 | const timeoutThresholdMilliseconds =
32 | startTimeMilliSeconds +
33 | (typeof timeoutAfterMilliSeconds === "number"
34 | ? timeoutAfterMilliSeconds
35 | : 0);
36 |
37 | let timedOut = false;
38 | let error = new Error("Condition not met before timeout");
39 |
40 | while (true) {
41 | if (Date.now() >= timeoutThresholdMilliseconds) {
42 | timedOut = true;
43 | break;
44 | }
45 |
46 | const result = conditionCallback();
47 |
48 | if (result) {
49 | return result;
50 | }
51 |
52 | await sleepFor(pollIntervalMilliSeconds);
53 | }
54 |
55 | if (timedOut) {
56 | throw error;
57 | }
58 |
59 | return {
60 | orThrow(newError) {
61 | error = newError;
62 | }
63 | };
64 | };
65 |
66 | /**
67 | *
68 | * @param {Uint8Array} bytes
69 | *
70 | * @return {String}
71 | *
72 | * @see https://stegriff.co.uk/upblog/bit-packing-binary-in-javascript-and-json/
73 | */
74 | const pack = (bytes = []) => {
75 | const characters = [];
76 |
77 | for (let count = 0, bytesLength = bytes.length; count < bytesLength; ) {
78 | characters.push(((bytes[count++] & 0xff) << 8) | (bytes[count++] & 0xff));
79 | }
80 |
81 | String.fromCharCode(...characters);
82 | };
83 |
84 | /**
85 | *
86 | * @param {String} utf16EncodedString
87 | *
88 | * @return {Array}
89 | *
90 | * @see https://stegriff.co.uk/upblog/bit-packing-binary-in-javascript-and-json/
91 | */
92 | const unpack = (utf16EncodedString) => {
93 | const bytes = [];
94 |
95 | for (
96 | let count = 0, binaryStringLength = utf16EncodedString.length;
97 | count < binaryStringLength;
98 | count++
99 | ) {
100 | const character = utf16EncodedString.charCodeAt(count);
101 | bytes.push(character >>> 8, character & 0xff);
102 | }
103 | return bytes;
104 | };
105 |
106 | /**
107 | *
108 | * @param {String} text
109 | * @param {String} delimeter
110 | *
111 | * @returns {String}
112 | */
113 | const camelCaseify = (text) => {
114 | return text.replace(/\W+(.)/g, function(_, chr) {
115 | return chr.toUpperCase();
116 | });
117 | };
118 |
119 | /**
120 | *
121 | * @param {*} objectValue
122 | *
123 | * @returns {Boolean}
124 | */
125 | const isEmpty = (objectValue) => {
126 | if (!objectValue || typeof objectValue !== "object") {
127 | return true;
128 | }
129 |
130 | for (const prop in objectValue) {
131 | if (Object.prototype.hasOwnProperty.call(objectValue, prop)) {
132 | return false;
133 | }
134 | }
135 |
136 | return JSON.stringify(objectValue) === JSON.stringify({});
137 | };
138 |
139 | /**
140 | * @class
141 | * @see https://medium.com/@vincentcorbee/utf-16-to-utf-8-in-javascript-18b4b11b6e1e
142 | */
143 |
144 | class StringReader {
145 | constructor(source) {
146 | this.position = 0;
147 | this.source = source;
148 | }
149 |
150 | isInRange(position) {
151 | if (position > -1 && position < this.source.length) return true;
152 |
153 | return false;
154 | }
155 |
156 | next() {
157 | if (!this.isInRange(this.position)) return null;
158 |
159 | return this.source[this.position++].charCodeAt(0);
160 | }
161 |
162 | previous() {
163 | if (!this.isInRange(this.position)) return null;
164 |
165 | return this.source[this.position--].charCodeAt(0);
166 | }
167 |
168 | peak() {
169 | const oldPosition = this.position;
170 |
171 | const character = this.next();
172 |
173 | this.position = oldPosition;
174 |
175 | return character;
176 | }
177 |
178 | seek(position) {
179 | if (!this.isInRange(position)) {
180 | throw RangeError(`Offset: ${position} is out of range`);
181 | }
182 |
183 | this.position = position;
184 |
185 | return this;
186 | }
187 |
188 | advance() {
189 | const position = this.position + 1;
190 |
191 | if (!this.isInRange(position)) this.position = -1;
192 | else this.position++;
193 |
194 | return this;
195 | }
196 |
197 | getPosition() {
198 | return this.position;
199 | }
200 | }
201 |
202 | /**
203 | * @callback isLeadingSurrogate
204 | * @see https://medium.com/@vincentcorbee/utf-16-to-utf-8-in-javascript-18b4b11b6e1e
205 | */
206 |
207 | const isLeadingSurrogate = (charCode) => {
208 | return charCode >= 0xd800 && charCode <= 0xdbff;
209 | };
210 |
211 | /**
212 | * @callback isTrailingSurrogate
213 | * @see https://medium.com/@vincentcorbee/utf-16-to-utf-8-in-javascript-18b4b11b6e1e
214 | */
215 | const isTrailingSurrogate = (charCode) => {
216 | return charCode >= 0xdc00 && charCode <= 0xdfff;
217 | };
218 |
219 |
220 | /**
221 | * @class StringEncoder
222 | * @see https://medium.com/@vincentcorbee/utf-16-to-utf-8-in-javascript-18b4b11b6e1e
223 | */
224 | class StringEncoder {
225 | static UTF16SurrogatePairToCodePoint(leading, trailing) {
226 | return (leading - 0xd800) * 0x400 + (trailing - 0xdc00) + 0x10000;
227 | }
228 |
229 | static stringToUtf8(source) {
230 | const utf8codes = [];
231 |
232 | const stringReader = new StringReader(source);
233 |
234 | let charCode = null;
235 |
236 | /* eslint-disable-next-line no-cond-assign */
237 | while ((charCode = stringReader.next()) !== null) {
238 | /* Character takes one byte in UTF-8 (US-ASCII range) */
239 | if (charCode >= 0x0000 && charCode <= 0x007f) {
240 | utf8codes.push(charCode);
241 |
242 | /* Character takes two bytes in UTF-8 */
243 | } else if (charCode >= 0x0080 && charCode <= 0x07ff) {
244 | let firstByte = 0xc0 | (charCode >>> 6);
245 | let secondByte = 0x80 | (charCode & 0x3f);
246 |
247 | utf8codes.push(firstByte, secondByte);
248 | } else if (isLeadingSurrogate(charCode)) {
249 | /* High surrogate */
250 | const leading = charCode;
251 |
252 | /* Low surrogate */
253 | const trailing = stringReader.peak();
254 |
255 | if (trailing && isTrailingSurrogate(trailing)) {
256 | /* Surrogate pairs takes four bytes in UTF-8 */
257 | const codePoint = StringEncoder.UTF16SurrogatePairToCodePoint(
258 | leading,
259 | trailing
260 | );
261 |
262 | let firstByte = 0xf0 | (codePoint >>> 18);
263 | let secondByte = 0x80 | ((codePoint >>> 12) & 0x3f);
264 | let thirdByte = 0x80 | ((codePoint >>> 6) & 0x3f);
265 | let fourthByte = 0x80 | (codePoint & 0x3f);
266 |
267 | utf8codes.push(firstByte, secondByte, thirdByte, fourthByte);
268 |
269 | stringReader.advance();
270 | } else {
271 | /* Isolated high surrogate */
272 | }
273 | } else if (isTrailingSurrogate(charCode)) {
274 | /* Low surrogate */
275 | /* Isolated low surrogate */
276 | } else if (charCode >= 0x0800 && charCode <= 0xffff) {
277 | /* Character takes three bytes in UTF-8 */
278 | let firstByte = 0xe0 | (charCode >>> 12);
279 | let secondByte = 0x80 | ((charCode >>> 6) & 0x3f);
280 | let thirdByte = 0x80 | (charCode & 0x3f);
281 |
282 | utf8codes.push(firstByte, secondByte, thirdByte);
283 | }
284 | }
285 |
286 | return new Uint8Array(utf8codes);
287 | }
288 | }
289 |
290 | /**
291 | * @class StringDecoder
292 | * @see https://medium.com/@vincentcorbee/utf-16-to-utf-8-in-javascript-18b4b11b6e1e
293 | */
294 |
295 | class StringDecoder {
296 | static stringFromUTF16CharCode(charCodes) {
297 | return String.fromCharCode(...charCodes);
298 | }
299 |
300 | static UTF8ToString(uint8Array) {
301 | const charCodes = [];
302 |
303 | for (
304 | let index = 0, length = uint8Array.byteLength;
305 | index < length;
306 | index++
307 | ) {
308 | const charCode = uint8Array[index];
309 |
310 | /* Character takes one byte */
311 | if (charCode < 0xc0) charCodes.push(charCode);
312 | /* Character takes two bytes */ else if (charCode < 0xe0)
313 | charCodes.push(((charCode & 0x1f) << 6) | (uint8Array[++index] & 0x3f));
314 | /* Character takes three bytes */ else if (charCode < 0xef)
315 | charCodes.push(
316 | ((charCode & 0xf) << 12) |
317 | ((uint8Array[++index] & 0x3f) << 6) |
318 | (uint8Array[++index] & 0x3f)
319 | );
320 | /* Character takes four bytes */ else {
321 | /* Character consists of high and low surrogate pair */
322 | const codePoint =
323 | (((charCode & 0x7) << 18) |
324 | ((uint8Array[++index] & 0x3f) << 12) |
325 | ((uint8Array[++index] & 0x3f) << 6) |
326 | (uint8Array[++index] & 0x3f)) -
327 | 0x10000;
328 |
329 | charCodes.push(
330 | (codePoint >>> 10) + 0xd800,
331 | (codePoint & 0x3ff) + 0xdc00
332 | );
333 | }
334 | }
335 |
336 | return StringDecoder.stringFromUTF16CharCode(charCodes);
337 | }
338 | }
339 |
340 | /**
341 | *
342 | * @param {Uint8Array} bytesArray
343 | *
344 | * @returns {String}
345 | */
346 | const convertBytesArrayToBinaryString = (bytesArray) => {
347 | const typedArrayUTF8 = bytesArray;
348 | return StringDecoder.UTF8ToString(typedArrayUTF8);
349 | };
350 |
351 | /**
352 | *
353 | * @param {String} rawBinaryString
354 | *
355 | * @returns {Uint8Array}
356 | */
357 | const convertBinaryStringToBytesArray = (rawBinaryString) => {
358 | const javaScriptStringUTF16 = rawBinaryString;
359 | return StringEncoder.stringToUtf8(javaScriptStringUTF16);
360 | };
361 |
362 | const encryptionKey = crypto
363 | .createHash("sha512")
364 | .update("Shcxb573jbci9nbdk")
365 | .digest("hex")
366 | .substring(0, 32);
367 |
368 | const encryptionIV = crypto
369 | .createHash("sha512")
370 | .update("92hFAywb579MNmjh86")
371 | .digest("hex")
372 | .substring(0, 16);
373 |
374 | /**
375 | *
376 | * @param {String} plainData
377 | * @param {String} sourceEncoding
378 | *
379 | * @returns {String}
380 | */
381 | const encryptData = (plainData, sourceEncoding = "utf8") => {
382 | const cipherIV = crypto.createCipheriv(
383 | "aes-256-ocb",
384 | encryptionKey,
385 | encryptionIV
386 | );
387 | return Buffer.from(
388 | cipherIV.update(plainData, sourceEncoding, "hex") + cipherIV.final("hex")
389 | ).toString("base64");
390 | };
391 |
392 | /**
393 | *
394 | * @param {Buffer | String} encryptedData
395 | * @param {String} sourceEncoding
396 | *
397 | * @returns {String}
398 | */
399 | const decryptData = (encryptedData, sourceEncoding = "utf8") => {
400 | const buffer =
401 | encryptedData instanceof Buffer && encryptedData.isEncoding("base64")
402 | ? encryptedData
403 | : Buffer.from(encryptedData, "base64");
404 | const decipherIV = crypto.createDecipheriv(
405 | "aes-256-ocb",
406 | encryptionKey,
407 | encryptionIV
408 | );
409 | return (
410 | decipherIV.update(buffer.toString(sourceEncoding), "hex", sourceEncoding) +
411 | decipherIV.final(sourceEncoding)
412 | );
413 | };
414 |
415 | /*
416 | * The MurmurHash3 algorithm was created by Austin Appleby. This JavaScript port was authored
417 | * by whitequark (based on Java port by Yonik Seeley) and is placed into the public domain.
418 | * The author hereby disclaims copyright to this source code.
419 | *
420 | * This produces exactly the same hash values as the final C++ version of MurmurHash3 and
421 | * is thus suitable for producing the same hash values across platforms.
422 | *
423 | * There are two versions of this hash implementation. First interprets the string as a
424 | * sequence of bytes, ignoring most significant byte of each codepoint. The second one
425 | * interprets the string as a UTF-16 codepoint sequence, and appends each 16-bit codepoint
426 | * to the hash independently. The latter mode was not written to be compatible with
427 | * any other implementation, but it should offer better performance for JavaScript-only
428 | * applications.
429 | *
430 | * See http://github.com/whitequark/murmurhash3-js for future updates to this file.
431 | */
432 |
433 | const MurmurHash3 = {
434 | mul32: function (m, n) {
435 | var nlo = n & 0xffff;
436 | var nhi = n - nlo;
437 | return (((nhi * m) | 0) + ((nlo * m) | 0)) | 0;
438 | },
439 |
440 | hashBytes: function (data, len, seed) {
441 | var c1 = 0xcc9e2d51;
442 | var c2 = 0x1b873593;
443 |
444 | var h1 = seed;
445 | var roundedEnd = len & ~0x3;
446 |
447 | for (var i = 0; i < roundedEnd; i += 4) {
448 | var k1 =
449 | (data.charCodeAt(i) & 0xff) |
450 | ((data.charCodeAt(i + 1) & 0xff) << 8) |
451 | ((data.charCodeAt(i + 2) & 0xff) << 16) |
452 | ((data.charCodeAt(i + 3) & 0xff) << 24);
453 |
454 | k1 = this.mul32(k1, c1);
455 | k1 = ((k1 & 0x1ffff) << 15) | (k1 >>> 17); // ROTL32(k1,15);
456 | k1 = this.mul32(k1, c2);
457 |
458 | h1 ^= k1;
459 | h1 = ((h1 & 0x7ffff) << 13) | (h1 >>> 19); // ROTL32(h1,13);
460 | h1 = (h1 * 5 + 0xe6546b64) | 0;
461 | }
462 |
463 | k1 = 0;
464 |
465 | switch (len % 4) {
466 | case 3:
467 | k1 = (data.charCodeAt(roundedEnd + 2) & 0xff) << 16;
468 | // fallthrough
469 | case 2:
470 | k1 |= (data.charCodeAt(roundedEnd + 1) & 0xff) << 8;
471 | // fallthrough
472 | case 1:
473 | k1 |= data.charCodeAt(roundedEnd) & 0xff;
474 | k1 = this.mul32(k1, c1);
475 | k1 = ((k1 & 0x1ffff) << 15) | (k1 >>> 17); // ROTL32(k1,15);
476 | k1 = this.mul32(k1, c2);
477 | h1 ^= k1;
478 | break;
479 | default:
480 | k1 = 0;
481 | }
482 |
483 | // finalization
484 | h1 ^= len;
485 |
486 | // fmix(h1);
487 | h1 ^= h1 >>> 16;
488 | h1 = this.mul32(h1, 0x85ebca6b);
489 | h1 ^= h1 >>> 13;
490 | h1 = this.mul32(h1, 0xc2b2ae35);
491 | h1 ^= h1 >>> 16;
492 |
493 | return h1;
494 | },
495 |
496 | hashString: function (data, len, seed) {
497 | var c1 = 0xcc9e2d51;
498 | var c2 = 0x1b873593;
499 |
500 | var h1 = seed;
501 | var roundedEnd = len & ~0x1;
502 |
503 | for (var i = 0; i < roundedEnd; i += 2) {
504 | var k1 = data.charCodeAt(i) | (data.charCodeAt(i + 1) << 16);
505 |
506 | k1 = this.mul32(k1, c1);
507 | k1 = ((k1 & 0x1ffff) << 15) | (k1 >>> 17); // ROTL32(k1,15);
508 | k1 = this.mul32(k1, c2);
509 |
510 | h1 ^= k1;
511 | h1 = ((h1 & 0x7ffff) << 13) | (h1 >>> 19); // ROTL32(h1,13);
512 | h1 = (h1 * 5 + 0xe6546b64) | 0;
513 | }
514 |
515 | if (len % 2 === 1) {
516 | k1 = data.charCodeAt(roundedEnd);
517 | k1 = this.mul32(k1, c1);
518 | k1 = ((k1 & 0x1ffff) << 15) | (k1 >>> 17); // ROTL32(k1,15);
519 | k1 = this.mul32(k1, c2);
520 | h1 ^= k1;
521 | }
522 |
523 | // finalization
524 | h1 ^= len << 1;
525 |
526 | // fmix(h1);
527 | h1 ^= h1 >>> 16;
528 | h1 = this.mul32(h1, 0x85ebca6b);
529 | h1 ^= h1 >>> 13;
530 | h1 = this.mul32(h1, 0xc2b2ae35);
531 | h1 ^= h1 >>> 16;
532 |
533 | return h1;
534 | }
535 | };
536 |
537 | /**
538 | *
539 | * @param {String} data
540 | *
541 | * @returns {String}
542 | */
543 | const murmurHash = (data) => {
544 | const hash = MurmurHash3.hashBytes(data, data.length, 150);
545 |
546 | return Number(Math.abs(hash) % 262144263494052048758001).toString(16);
547 | };
548 |
549 | module.exports = {
550 | encryptData,
551 | decryptData,
552 | camelCaseify,
553 | pack,
554 | unpack,
555 | isEmpty,
556 | waitFor,
557 | sleepFor,
558 | murmurHash,
559 | convertBytesArrayToBinaryString,
560 | convertBinaryStringToBytesArray
561 | };
562 |
--------------------------------------------------------------------------------
/yarn.lock:
--------------------------------------------------------------------------------
1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
2 | # yarn lockfile v1
3 |
4 |
5 | abbrev@1:
6 | version "1.1.1"
7 | resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
8 | integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
9 |
10 | accepts@~1.3.5:
11 | version "1.3.7"
12 | resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"
13 | integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==
14 | dependencies:
15 | mime-types "~2.1.24"
16 | negotiator "0.6.2"
17 |
18 | ansi-align@^2.0.0:
19 | version "2.0.0"
20 | resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-2.0.0.tgz#c36aeccba563b89ceb556f3690f0b1d9e3547f7f"
21 | integrity sha1-w2rsy6VjuJzrVW82kPCx2eNUf38=
22 | dependencies:
23 | string-width "^2.0.0"
24 |
25 | ansi-regex@^3.0.0:
26 | version "3.0.0"
27 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
28 | integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
29 |
30 | ansi-styles@^3.2.1:
31 | version "3.2.1"
32 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
33 | integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
34 | dependencies:
35 | color-convert "^1.9.0"
36 |
37 | anymatch@^2.0.0:
38 | version "2.0.0"
39 | resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb"
40 | integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==
41 | dependencies:
42 | micromatch "^3.1.4"
43 | normalize-path "^2.1.1"
44 |
45 | arr-diff@^4.0.0:
46 | version "4.0.0"
47 | resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520"
48 | integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=
49 |
50 | arr-flatten@^1.1.0:
51 | version "1.1.0"
52 | resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1"
53 | integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==
54 |
55 | arr-union@^3.1.0:
56 | version "3.1.0"
57 | resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4"
58 | integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=
59 |
60 | array-flatten@1.1.1:
61 | version "1.1.1"
62 | resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
63 | integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=
64 |
65 | array-unique@^0.3.2:
66 | version "0.3.2"
67 | resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
68 | integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=
69 |
70 | assign-symbols@^1.0.0:
71 | version "1.0.0"
72 | resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367"
73 | integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=
74 |
75 | async-each@^1.0.1:
76 | version "1.0.3"
77 | resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf"
78 | integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==
79 |
80 | atob@^2.1.1:
81 | version "2.1.2"
82 | resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
83 | integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
84 |
85 | balanced-match@^1.0.0:
86 | version "1.0.0"
87 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
88 | integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
89 |
90 | base@^0.11.1:
91 | version "0.11.2"
92 | resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f"
93 | integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==
94 | dependencies:
95 | cache-base "^1.0.1"
96 | class-utils "^0.3.5"
97 | component-emitter "^1.2.1"
98 | define-property "^1.0.0"
99 | isobject "^3.0.1"
100 | mixin-deep "^1.2.0"
101 | pascalcase "^0.1.1"
102 |
103 | basic-auth@~2.0.0:
104 | version "2.0.1"
105 | resolved "https://registry.yarnpkg.com/basic-auth/-/basic-auth-2.0.1.tgz#b998279bf47ce38344b4f3cf916d4679bbf51e3a"
106 | integrity sha512-NF+epuEdnUYVlGuhaxbbq+dvJttwLnGY+YixlXlME5KpQ5W3CnXA5cVTneY3SPbPDRkcjMbifrwmFYcClgOZeg==
107 | dependencies:
108 | safe-buffer "5.1.2"
109 |
110 | binary-extensions@^1.0.0:
111 | version "1.13.1"
112 | resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65"
113 | integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==
114 |
115 | bindings@^1.5.0:
116 | version "1.5.0"
117 | resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df"
118 | integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==
119 | dependencies:
120 | file-uri-to-path "1.0.0"
121 |
122 | body-parser@1.18.3:
123 | version "1.18.3"
124 | resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.18.3.tgz#5b292198ffdd553b3a0f20ded0592b956955c8b4"
125 | integrity sha1-WykhmP/dVTs6DyDe0FkrlWlVyLQ=
126 | dependencies:
127 | bytes "3.0.0"
128 | content-type "~1.0.4"
129 | debug "2.6.9"
130 | depd "~1.1.2"
131 | http-errors "~1.6.3"
132 | iconv-lite "0.4.23"
133 | on-finished "~2.3.0"
134 | qs "6.5.2"
135 | raw-body "2.3.3"
136 | type-is "~1.6.16"
137 |
138 | boxen@^1.2.1:
139 | version "1.3.0"
140 | resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.3.0.tgz#55c6c39a8ba58d9c61ad22cd877532deb665a20b"
141 | integrity sha512-TNPjfTr432qx7yOjQyaXm3dSR0MH9vXp7eT1BFSl/C51g+EFnOR9hTg1IreahGBmDNCehscshe45f+C1TBZbLw==
142 | dependencies:
143 | ansi-align "^2.0.0"
144 | camelcase "^4.0.0"
145 | chalk "^2.0.1"
146 | cli-boxes "^1.0.0"
147 | string-width "^2.0.0"
148 | term-size "^1.2.0"
149 | widest-line "^2.0.0"
150 |
151 | brace-expansion@^1.1.7:
152 | version "1.1.11"
153 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
154 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
155 | dependencies:
156 | balanced-match "^1.0.0"
157 | concat-map "0.0.1"
158 |
159 | braces@^2.3.1, braces@^2.3.2:
160 | version "2.3.2"
161 | resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729"
162 | integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==
163 | dependencies:
164 | arr-flatten "^1.1.0"
165 | array-unique "^0.3.2"
166 | extend-shallow "^2.0.1"
167 | fill-range "^4.0.0"
168 | isobject "^3.0.1"
169 | repeat-element "^1.1.2"
170 | snapdragon "^0.8.1"
171 | snapdragon-node "^2.0.1"
172 | split-string "^3.0.2"
173 | to-regex "^3.0.1"
174 |
175 | bytes@3.0.0:
176 | version "3.0.0"
177 | resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
178 | integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=
179 |
180 | cache-base@^1.0.1:
181 | version "1.0.1"
182 | resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2"
183 | integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==
184 | dependencies:
185 | collection-visit "^1.0.0"
186 | component-emitter "^1.2.1"
187 | get-value "^2.0.6"
188 | has-value "^1.0.0"
189 | isobject "^3.0.1"
190 | set-value "^2.0.0"
191 | to-object-path "^0.3.0"
192 | union-value "^1.0.0"
193 | unset-value "^1.0.0"
194 |
195 | camelcase@^4.0.0:
196 | version "4.1.0"
197 | resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd"
198 | integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0=
199 |
200 | capture-stack-trace@^1.0.0:
201 | version "1.0.1"
202 | resolved "https://registry.yarnpkg.com/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz#a6c0bbe1f38f3aa0b92238ecb6ff42c344d4135d"
203 | integrity sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw==
204 |
205 | chalk@^2.0.1:
206 | version "2.4.2"
207 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
208 | integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
209 | dependencies:
210 | ansi-styles "^3.2.1"
211 | escape-string-regexp "^1.0.5"
212 | supports-color "^5.3.0"
213 |
214 | chokidar@^2.0.2:
215 | version "2.1.8"
216 | resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917"
217 | integrity sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==
218 | dependencies:
219 | anymatch "^2.0.0"
220 | async-each "^1.0.1"
221 | braces "^2.3.2"
222 | glob-parent "^3.1.0"
223 | inherits "^2.0.3"
224 | is-binary-path "^1.0.0"
225 | is-glob "^4.0.0"
226 | normalize-path "^3.0.0"
227 | path-is-absolute "^1.0.0"
228 | readdirp "^2.2.1"
229 | upath "^1.1.1"
230 | optionalDependencies:
231 | fsevents "^1.2.7"
232 |
233 | ci-info@^1.5.0:
234 | version "1.6.0"
235 | resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497"
236 | integrity sha512-vsGdkwSCDpWmP80ncATX7iea5DWQemg1UgCW5J8tqjU3lYw4FBYuj89J0CTVomA7BEfvSZd84GmHko+MxFQU2A==
237 |
238 | class-utils@^0.3.5:
239 | version "0.3.6"
240 | resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
241 | integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==
242 | dependencies:
243 | arr-union "^3.1.0"
244 | define-property "^0.2.5"
245 | isobject "^3.0.0"
246 | static-extend "^0.1.1"
247 |
248 | cli-boxes@^1.0.0:
249 | version "1.0.0"
250 | resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-1.0.0.tgz#4fa917c3e59c94a004cd61f8ee509da651687143"
251 | integrity sha1-T6kXw+WclKAEzWH47lCdplFocUM=
252 |
253 | collection-visit@^1.0.0:
254 | version "1.0.0"
255 | resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0"
256 | integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=
257 | dependencies:
258 | map-visit "^1.0.0"
259 | object-visit "^1.0.0"
260 |
261 | color-convert@^1.9.0:
262 | version "1.9.3"
263 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
264 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
265 | dependencies:
266 | color-name "1.1.3"
267 |
268 | color-name@1.1.3:
269 | version "1.1.3"
270 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
271 | integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
272 |
273 | component-emitter@^1.2.1:
274 | version "1.3.0"
275 | resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0"
276 | integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==
277 |
278 | concat-map@0.0.1:
279 | version "0.0.1"
280 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
281 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
282 |
283 | configstore@^3.0.0:
284 | version "3.1.2"
285 | resolved "https://registry.yarnpkg.com/configstore/-/configstore-3.1.2.tgz#c6f25defaeef26df12dd33414b001fe81a543f8f"
286 | integrity sha512-vtv5HtGjcYUgFrXc6Kx747B83MRRVS5R1VTEQoXvuP+kMI+if6uywV0nDGoiydJRy4yk7h9od5Og0kxx4zUXmw==
287 | dependencies:
288 | dot-prop "^4.1.0"
289 | graceful-fs "^4.1.2"
290 | make-dir "^1.0.0"
291 | unique-string "^1.0.0"
292 | write-file-atomic "^2.0.0"
293 | xdg-basedir "^3.0.0"
294 |
295 | content-disposition@0.5.2:
296 | version "0.5.2"
297 | resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4"
298 | integrity sha1-DPaLud318r55YcOoUXjLhdunjLQ=
299 |
300 | content-type@~1.0.4:
301 | version "1.0.4"
302 | resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
303 | integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
304 |
305 | cookie-parser@~1.4.4:
306 | version "1.4.4"
307 | resolved "https://registry.yarnpkg.com/cookie-parser/-/cookie-parser-1.4.4.tgz#e6363de4ea98c3def9697b93421c09f30cf5d188"
308 | integrity sha512-lo13tqF3JEtFO7FyA49CqbhaFkskRJ0u/UAiINgrIXeRCY41c88/zxtrECl8AKH3B0hj9q10+h3Kt8I7KlW4tw==
309 | dependencies:
310 | cookie "0.3.1"
311 | cookie-signature "1.0.6"
312 |
313 | cookie-signature@1.0.6:
314 | version "1.0.6"
315 | resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
316 | integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw=
317 |
318 | cookie@0.3.1:
319 | version "0.3.1"
320 | resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
321 | integrity sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=
322 |
323 | copy-descriptor@^0.1.0:
324 | version "0.1.1"
325 | resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
326 | integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=
327 |
328 | core-util-is@~1.0.0:
329 | version "1.0.2"
330 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
331 | integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
332 |
333 | create-error-class@^3.0.0:
334 | version "3.0.2"
335 | resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6"
336 | integrity sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=
337 | dependencies:
338 | capture-stack-trace "^1.0.0"
339 |
340 | cross-spawn@^5.0.1:
341 | version "5.1.0"
342 | resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449"
343 | integrity sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=
344 | dependencies:
345 | lru-cache "^4.0.1"
346 | shebang-command "^1.2.0"
347 | which "^1.2.9"
348 |
349 | crypto-random-string@^1.0.0:
350 | version "1.0.0"
351 | resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e"
352 | integrity sha1-ojD2T1aDEOFJgAmUB5DsmVRbyn4=
353 |
354 | debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@~2.6.9:
355 | version "2.6.9"
356 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
357 | integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
358 | dependencies:
359 | ms "2.0.0"
360 |
361 | debug@^3.1.0:
362 | version "3.2.6"
363 | resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
364 | integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
365 | dependencies:
366 | ms "^2.1.1"
367 |
368 | decode-uri-component@^0.2.0:
369 | version "0.2.0"
370 | resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
371 | integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=
372 |
373 | deep-extend@^0.6.0:
374 | version "0.6.0"
375 | resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
376 | integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
377 |
378 | define-property@^0.2.5:
379 | version "0.2.5"
380 | resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116"
381 | integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=
382 | dependencies:
383 | is-descriptor "^0.1.0"
384 |
385 | define-property@^1.0.0:
386 | version "1.0.0"
387 | resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6"
388 | integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY=
389 | dependencies:
390 | is-descriptor "^1.0.0"
391 |
392 | define-property@^2.0.2:
393 | version "2.0.2"
394 | resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d"
395 | integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==
396 | dependencies:
397 | is-descriptor "^1.0.2"
398 | isobject "^3.0.1"
399 |
400 | depd@~1.1.2:
401 | version "1.1.2"
402 | resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
403 | integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=
404 |
405 | destroy@~1.0.4:
406 | version "1.0.4"
407 | resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
408 | integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=
409 |
410 | dot-prop@^4.1.0:
411 | version "4.2.0"
412 | resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57"
413 | integrity sha512-tUMXrxlExSW6U2EXiiKGSBVdYgtV8qlHL+C10TsW4PURY/ic+eaysnSkwB4kA/mBlCyy/IKDJ+Lc3wbWeaXtuQ==
414 | dependencies:
415 | is-obj "^1.0.0"
416 |
417 | dotenv@8.2.0:
418 | version "8.2.0"
419 | resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.2.0.tgz#97e619259ada750eea3e4ea3e26bceea5424b16a"
420 | integrity sha512-8sJ78ElpbDJBHNeBzUbUVLsqKdccaa/BXF1uPTw3GrvQTBgrQrtObr2mUrE38vzYd8cEv+m/JBfDLioYcfXoaw==
421 |
422 | duplexer3@^0.1.4:
423 | version "0.1.4"
424 | resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"
425 | integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=
426 |
427 | ee-first@1.1.1:
428 | version "1.1.1"
429 | resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
430 | integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
431 |
432 | encodeurl@~1.0.2:
433 | version "1.0.2"
434 | resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
435 | integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=
436 |
437 | escape-html@~1.0.3:
438 | version "1.0.3"
439 | resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
440 | integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=
441 |
442 | escape-string-regexp@^1.0.5:
443 | version "1.0.5"
444 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
445 | integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
446 |
447 | etag@~1.8.1:
448 | version "1.8.1"
449 | resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
450 | integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
451 |
452 | execa@^0.7.0:
453 | version "0.7.0"
454 | resolved "https://registry.yarnpkg.com/execa/-/execa-0.7.0.tgz#944becd34cc41ee32a63a9faf27ad5a65fc59777"
455 | integrity sha1-lEvs00zEHuMqY6n68nrVpl/Fl3c=
456 | dependencies:
457 | cross-spawn "^5.0.1"
458 | get-stream "^3.0.0"
459 | is-stream "^1.1.0"
460 | npm-run-path "^2.0.0"
461 | p-finally "^1.0.0"
462 | signal-exit "^3.0.0"
463 | strip-eof "^1.0.0"
464 |
465 | expand-brackets@^2.1.4:
466 | version "2.1.4"
467 | resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622"
468 | integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI=
469 | dependencies:
470 | debug "^2.3.3"
471 | define-property "^0.2.5"
472 | extend-shallow "^2.0.1"
473 | posix-character-classes "^0.1.0"
474 | regex-not "^1.0.0"
475 | snapdragon "^0.8.1"
476 | to-regex "^3.0.1"
477 |
478 | express@~4.16.1:
479 | version "4.16.4"
480 | resolved "https://registry.yarnpkg.com/express/-/express-4.16.4.tgz#fddef61926109e24c515ea97fd2f1bdbf62df12e"
481 | integrity sha512-j12Uuyb4FMrd/qQAm6uCHAkPtO8FDTRJZBDd5D2KOL2eLaz1yUNdUB/NOIyq0iU4q4cFarsUCrnFDPBcnksuOg==
482 | dependencies:
483 | accepts "~1.3.5"
484 | array-flatten "1.1.1"
485 | body-parser "1.18.3"
486 | content-disposition "0.5.2"
487 | content-type "~1.0.4"
488 | cookie "0.3.1"
489 | cookie-signature "1.0.6"
490 | debug "2.6.9"
491 | depd "~1.1.2"
492 | encodeurl "~1.0.2"
493 | escape-html "~1.0.3"
494 | etag "~1.8.1"
495 | finalhandler "1.1.1"
496 | fresh "0.5.2"
497 | merge-descriptors "1.0.1"
498 | methods "~1.1.2"
499 | on-finished "~2.3.0"
500 | parseurl "~1.3.2"
501 | path-to-regexp "0.1.7"
502 | proxy-addr "~2.0.4"
503 | qs "6.5.2"
504 | range-parser "~1.2.0"
505 | safe-buffer "5.1.2"
506 | send "0.16.2"
507 | serve-static "1.13.2"
508 | setprototypeof "1.1.0"
509 | statuses "~1.4.0"
510 | type-is "~1.6.16"
511 | utils-merge "1.0.1"
512 | vary "~1.1.2"
513 |
514 | extend-shallow@^2.0.1:
515 | version "2.0.1"
516 | resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f"
517 | integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=
518 | dependencies:
519 | is-extendable "^0.1.0"
520 |
521 | extend-shallow@^3.0.0, extend-shallow@^3.0.2:
522 | version "3.0.2"
523 | resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8"
524 | integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=
525 | dependencies:
526 | assign-symbols "^1.0.0"
527 | is-extendable "^1.0.1"
528 |
529 | extglob@^2.0.4:
530 | version "2.0.4"
531 | resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543"
532 | integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==
533 | dependencies:
534 | array-unique "^0.3.2"
535 | define-property "^1.0.0"
536 | expand-brackets "^2.1.4"
537 | extend-shallow "^2.0.1"
538 | fragment-cache "^0.2.1"
539 | regex-not "^1.0.0"
540 | snapdragon "^0.8.1"
541 | to-regex "^3.0.1"
542 |
543 | file-uri-to-path@1.0.0:
544 | version "1.0.0"
545 | resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd"
546 | integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==
547 |
548 | fill-range@^4.0.0:
549 | version "4.0.0"
550 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7"
551 | integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=
552 | dependencies:
553 | extend-shallow "^2.0.1"
554 | is-number "^3.0.0"
555 | repeat-string "^1.6.1"
556 | to-regex-range "^2.1.0"
557 |
558 | finalhandler@1.1.1:
559 | version "1.1.1"
560 | resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.1.tgz#eebf4ed840079c83f4249038c9d703008301b105"
561 | integrity sha512-Y1GUDo39ez4aHAw7MysnUD5JzYX+WaIj8I57kO3aEPT1fFRL4sr7mjei97FgnwhAyyzRYmQZaTHb2+9uZ1dPtg==
562 | dependencies:
563 | debug "2.6.9"
564 | encodeurl "~1.0.2"
565 | escape-html "~1.0.3"
566 | on-finished "~2.3.0"
567 | parseurl "~1.3.2"
568 | statuses "~1.4.0"
569 | unpipe "~1.0.0"
570 |
571 | for-in@^1.0.2:
572 | version "1.0.2"
573 | resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
574 | integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=
575 |
576 | forwarded@~0.1.2:
577 | version "0.1.2"
578 | resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84"
579 | integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=
580 |
581 | fragment-cache@^0.2.1:
582 | version "0.2.1"
583 | resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19"
584 | integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=
585 | dependencies:
586 | map-cache "^0.2.2"
587 |
588 | fresh@0.5.2:
589 | version "0.5.2"
590 | resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
591 | integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=
592 |
593 | fsevents@^1.2.7:
594 | version "1.2.11"
595 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.11.tgz#67bf57f4758f02ede88fb2a1712fef4d15358be3"
596 | integrity sha512-+ux3lx6peh0BpvY0JebGyZoiR4D+oYzdPZMKJwkZ+sFkNJzpL7tXc/wehS49gUAxg3tmMHPHZkA8JU2rhhgDHw==
597 | dependencies:
598 | bindings "^1.5.0"
599 | nan "^2.12.1"
600 |
601 | get-stream@^3.0.0:
602 | version "3.0.0"
603 | resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
604 | integrity sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=
605 |
606 | get-value@^2.0.3, get-value@^2.0.6:
607 | version "2.0.6"
608 | resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28"
609 | integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=
610 |
611 | glob-parent@^3.1.0:
612 | version "3.1.0"
613 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae"
614 | integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=
615 | dependencies:
616 | is-glob "^3.1.0"
617 | path-dirname "^1.0.0"
618 |
619 | global-dirs@^0.1.0:
620 | version "0.1.1"
621 | resolved "https://registry.yarnpkg.com/global-dirs/-/global-dirs-0.1.1.tgz#b319c0dd4607f353f3be9cca4c72fc148c49f445"
622 | integrity sha1-sxnA3UYH81PzvpzKTHL8FIxJ9EU=
623 | dependencies:
624 | ini "^1.3.4"
625 |
626 | got@^6.7.1:
627 | version "6.7.1"
628 | resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0"
629 | integrity sha1-JAzQV4WpoY5WHcG0S0HHY+8ejbA=
630 | dependencies:
631 | create-error-class "^3.0.0"
632 | duplexer3 "^0.1.4"
633 | get-stream "^3.0.0"
634 | is-redirect "^1.0.0"
635 | is-retry-allowed "^1.0.0"
636 | is-stream "^1.0.0"
637 | lowercase-keys "^1.0.0"
638 | safe-buffer "^5.0.1"
639 | timed-out "^4.0.0"
640 | unzip-response "^2.0.1"
641 | url-parse-lax "^1.0.0"
642 |
643 | graceful-fs@^4.1.11, graceful-fs@^4.1.2:
644 | version "4.2.3"
645 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423"
646 | integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==
647 |
648 | has-flag@^3.0.0:
649 | version "3.0.0"
650 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
651 | integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
652 |
653 | has-value@^0.3.1:
654 | version "0.3.1"
655 | resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f"
656 | integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=
657 | dependencies:
658 | get-value "^2.0.3"
659 | has-values "^0.1.4"
660 | isobject "^2.0.0"
661 |
662 | has-value@^1.0.0:
663 | version "1.0.0"
664 | resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177"
665 | integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=
666 | dependencies:
667 | get-value "^2.0.6"
668 | has-values "^1.0.0"
669 | isobject "^3.0.0"
670 |
671 | has-values@^0.1.4:
672 | version "0.1.4"
673 | resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771"
674 | integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E=
675 |
676 | has-values@^1.0.0:
677 | version "1.0.0"
678 | resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f"
679 | integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=
680 | dependencies:
681 | is-number "^3.0.0"
682 | kind-of "^4.0.0"
683 |
684 | http-errors@1.6.3, http-errors@~1.6.2, http-errors@~1.6.3:
685 | version "1.6.3"
686 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d"
687 | integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=
688 | dependencies:
689 | depd "~1.1.2"
690 | inherits "2.0.3"
691 | setprototypeof "1.1.0"
692 | statuses ">= 1.4.0 < 2"
693 |
694 | iconv-lite@0.4.23:
695 | version "0.4.23"
696 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63"
697 | integrity sha512-neyTUVFtahjf0mB3dZT77u+8O0QB89jFdnBkd5P1JgYPbPaia3gXXOVL2fq8VyU2gMMD7SaN7QukTB/pmXYvDA==
698 | dependencies:
699 | safer-buffer ">= 2.1.2 < 3"
700 |
701 | ignore-by-default@^1.0.1:
702 | version "1.0.1"
703 | resolved "https://registry.yarnpkg.com/ignore-by-default/-/ignore-by-default-1.0.1.tgz#48ca6d72f6c6a3af00a9ad4ae6876be3889e2b09"
704 | integrity sha1-SMptcvbGo68Aqa1K5odr44ieKwk=
705 |
706 | import-lazy@^2.1.0:
707 | version "2.1.0"
708 | resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43"
709 | integrity sha1-BWmOPUXIjo1+nZLLBYTnfwlvPkM=
710 |
711 | imurmurhash@^0.1.4:
712 | version "0.1.4"
713 | resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
714 | integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
715 |
716 | inherits@2.0.3:
717 | version "2.0.3"
718 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
719 | integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
720 |
721 | inherits@^2.0.3, inherits@~2.0.3:
722 | version "2.0.4"
723 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
724 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
725 |
726 | ini@^1.3.4, ini@~1.3.0:
727 | version "1.3.5"
728 | resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
729 | integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
730 |
731 | ipaddr.js@1.9.0:
732 | version "1.9.0"
733 | resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.0.tgz#37df74e430a0e47550fe54a2defe30d8acd95f65"
734 | integrity sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==
735 |
736 | is-accessor-descriptor@^0.1.6:
737 | version "0.1.6"
738 | resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6"
739 | integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=
740 | dependencies:
741 | kind-of "^3.0.2"
742 |
743 | is-accessor-descriptor@^1.0.0:
744 | version "1.0.0"
745 | resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656"
746 | integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==
747 | dependencies:
748 | kind-of "^6.0.0"
749 |
750 | is-binary-path@^1.0.0:
751 | version "1.0.1"
752 | resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898"
753 | integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=
754 | dependencies:
755 | binary-extensions "^1.0.0"
756 |
757 | is-buffer@^1.1.5:
758 | version "1.1.6"
759 | resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
760 | integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
761 |
762 | is-ci@^1.0.10:
763 | version "1.2.1"
764 | resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.2.1.tgz#e3779c8ee17fccf428488f6e281187f2e632841c"
765 | integrity sha512-s6tfsaQaQi3JNciBH6shVqEDvhGut0SUXr31ag8Pd8BBbVVlcGfWhpPmEOoM6RJ5TFhbypvf5yyRw/VXW1IiWg==
766 | dependencies:
767 | ci-info "^1.5.0"
768 |
769 | is-data-descriptor@^0.1.4:
770 | version "0.1.4"
771 | resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56"
772 | integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=
773 | dependencies:
774 | kind-of "^3.0.2"
775 |
776 | is-data-descriptor@^1.0.0:
777 | version "1.0.0"
778 | resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7"
779 | integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==
780 | dependencies:
781 | kind-of "^6.0.0"
782 |
783 | is-descriptor@^0.1.0:
784 | version "0.1.6"
785 | resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca"
786 | integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==
787 | dependencies:
788 | is-accessor-descriptor "^0.1.6"
789 | is-data-descriptor "^0.1.4"
790 | kind-of "^5.0.0"
791 |
792 | is-descriptor@^1.0.0, is-descriptor@^1.0.2:
793 | version "1.0.2"
794 | resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec"
795 | integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==
796 | dependencies:
797 | is-accessor-descriptor "^1.0.0"
798 | is-data-descriptor "^1.0.0"
799 | kind-of "^6.0.2"
800 |
801 | is-extendable@^0.1.0, is-extendable@^0.1.1:
802 | version "0.1.1"
803 | resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
804 | integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=
805 |
806 | is-extendable@^1.0.1:
807 | version "1.0.1"
808 | resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4"
809 | integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==
810 | dependencies:
811 | is-plain-object "^2.0.4"
812 |
813 | is-extglob@^2.1.0, is-extglob@^2.1.1:
814 | version "2.1.1"
815 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
816 | integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
817 |
818 | is-fullwidth-code-point@^2.0.0:
819 | version "2.0.0"
820 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f"
821 | integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=
822 |
823 | is-glob@^3.1.0:
824 | version "3.1.0"
825 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a"
826 | integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=
827 | dependencies:
828 | is-extglob "^2.1.0"
829 |
830 | is-glob@^4.0.0:
831 | version "4.0.1"
832 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc"
833 | integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==
834 | dependencies:
835 | is-extglob "^2.1.1"
836 |
837 | is-installed-globally@^0.1.0:
838 | version "0.1.0"
839 | resolved "https://registry.yarnpkg.com/is-installed-globally/-/is-installed-globally-0.1.0.tgz#0dfd98f5a9111716dd535dda6492f67bf3d25a80"
840 | integrity sha1-Df2Y9akRFxbdU13aZJL2e/PSWoA=
841 | dependencies:
842 | global-dirs "^0.1.0"
843 | is-path-inside "^1.0.0"
844 |
845 | is-npm@^1.0.0:
846 | version "1.0.0"
847 | resolved "https://registry.yarnpkg.com/is-npm/-/is-npm-1.0.0.tgz#f2fb63a65e4905b406c86072765a1a4dc793b9f4"
848 | integrity sha1-8vtjpl5JBbQGyGBydloaTceTufQ=
849 |
850 | is-number@^3.0.0:
851 | version "3.0.0"
852 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195"
853 | integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=
854 | dependencies:
855 | kind-of "^3.0.2"
856 |
857 | is-obj@^1.0.0:
858 | version "1.0.1"
859 | resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f"
860 | integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8=
861 |
862 | is-path-inside@^1.0.0:
863 | version "1.0.1"
864 | resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.1.tgz#8ef5b7de50437a3fdca6b4e865ef7aa55cb48036"
865 | integrity sha1-jvW33lBDej/cprToZe96pVy0gDY=
866 | dependencies:
867 | path-is-inside "^1.0.1"
868 |
869 | is-plain-object@^2.0.3, is-plain-object@^2.0.4:
870 | version "2.0.4"
871 | resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"
872 | integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==
873 | dependencies:
874 | isobject "^3.0.1"
875 |
876 | is-redirect@^1.0.0:
877 | version "1.0.0"
878 | resolved "https://registry.yarnpkg.com/is-redirect/-/is-redirect-1.0.0.tgz#1d03dded53bd8db0f30c26e4f95d36fc7c87dc24"
879 | integrity sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ=
880 |
881 | is-retry-allowed@^1.0.0:
882 | version "1.2.0"
883 | resolved "https://registry.yarnpkg.com/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz#d778488bd0a4666a3be8a1482b9f2baafedea8b4"
884 | integrity sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==
885 |
886 | is-stream@^1.0.0, is-stream@^1.1.0:
887 | version "1.1.0"
888 | resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
889 | integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
890 |
891 | is-windows@^1.0.2:
892 | version "1.0.2"
893 | resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
894 | integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==
895 |
896 | isarray@1.0.0, isarray@~1.0.0:
897 | version "1.0.0"
898 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
899 | integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
900 |
901 | isexe@^2.0.0:
902 | version "2.0.0"
903 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
904 | integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
905 |
906 | isobject@^2.0.0:
907 | version "2.1.0"
908 | resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89"
909 | integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=
910 | dependencies:
911 | isarray "1.0.0"
912 |
913 | isobject@^3.0.0, isobject@^3.0.1:
914 | version "3.0.1"
915 | resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
916 | integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8=
917 |
918 | kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0:
919 | version "3.2.2"
920 | resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64"
921 | integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=
922 | dependencies:
923 | is-buffer "^1.1.5"
924 |
925 | kind-of@^4.0.0:
926 | version "4.0.0"
927 | resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57"
928 | integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc=
929 | dependencies:
930 | is-buffer "^1.1.5"
931 |
932 | kind-of@^5.0.0:
933 | version "5.1.0"
934 | resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d"
935 | integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==
936 |
937 | kind-of@^6.0.0, kind-of@^6.0.2:
938 | version "6.0.2"
939 | resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051"
940 | integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==
941 |
942 | latest-version@^3.0.0:
943 | version "3.1.0"
944 | resolved "https://registry.yarnpkg.com/latest-version/-/latest-version-3.1.0.tgz#a205383fea322b33b5ae3b18abee0dc2f356ee15"
945 | integrity sha1-ogU4P+oyKzO1rjsYq+4NwvNW7hU=
946 | dependencies:
947 | package-json "^4.0.0"
948 |
949 | lowercase-keys@^1.0.0:
950 | version "1.0.1"
951 | resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f"
952 | integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==
953 |
954 | lru-cache@^4.0.1:
955 | version "4.1.5"
956 | resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
957 | integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==
958 | dependencies:
959 | pseudomap "^1.0.2"
960 | yallist "^2.1.2"
961 |
962 | make-dir@^1.0.0:
963 | version "1.3.0"
964 | resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c"
965 | integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==
966 | dependencies:
967 | pify "^3.0.0"
968 |
969 | map-cache@^0.2.2:
970 | version "0.2.2"
971 | resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf"
972 | integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=
973 |
974 | map-visit@^1.0.0:
975 | version "1.0.0"
976 | resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f"
977 | integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=
978 | dependencies:
979 | object-visit "^1.0.0"
980 |
981 | media-typer@0.3.0:
982 | version "0.3.0"
983 | resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
984 | integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=
985 |
986 | merge-descriptors@1.0.1:
987 | version "1.0.1"
988 | resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
989 | integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=
990 |
991 | methods@~1.1.2:
992 | version "1.1.2"
993 | resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
994 | integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=
995 |
996 | micromatch@^3.1.10, micromatch@^3.1.4:
997 | version "3.1.10"
998 | resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23"
999 | integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==
1000 | dependencies:
1001 | arr-diff "^4.0.0"
1002 | array-unique "^0.3.2"
1003 | braces "^2.3.1"
1004 | define-property "^2.0.2"
1005 | extend-shallow "^3.0.2"
1006 | extglob "^2.0.4"
1007 | fragment-cache "^0.2.1"
1008 | kind-of "^6.0.2"
1009 | nanomatch "^1.2.9"
1010 | object.pick "^1.3.0"
1011 | regex-not "^1.0.0"
1012 | snapdragon "^0.8.1"
1013 | to-regex "^3.0.2"
1014 |
1015 | mime-db@1.42.0:
1016 | version "1.42.0"
1017 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.42.0.tgz#3e252907b4c7adb906597b4b65636272cf9e7bac"
1018 | integrity sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ==
1019 |
1020 | mime-types@~2.1.24:
1021 | version "2.1.25"
1022 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.25.tgz#39772d46621f93e2a80a856c53b86a62156a6437"
1023 | integrity sha512-5KhStqB5xpTAeGqKBAMgwaYMnQik7teQN4IAzC7npDv6kzeU6prfkR67bc87J1kWMPGkoaZSq1npmexMgkmEVg==
1024 | dependencies:
1025 | mime-db "1.42.0"
1026 |
1027 | mime@1.4.1:
1028 | version "1.4.1"
1029 | resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6"
1030 | integrity sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==
1031 |
1032 | minimatch@^3.0.4:
1033 | version "3.0.4"
1034 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
1035 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
1036 | dependencies:
1037 | brace-expansion "^1.1.7"
1038 |
1039 | minimist@^1.2.0:
1040 | version "1.2.0"
1041 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
1042 | integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=
1043 |
1044 | mixin-deep@^1.2.0:
1045 | version "1.3.2"
1046 | resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566"
1047 | integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==
1048 | dependencies:
1049 | for-in "^1.0.2"
1050 | is-extendable "^1.0.1"
1051 |
1052 | morgan@~1.9.1:
1053 | version "1.9.1"
1054 | resolved "https://registry.yarnpkg.com/morgan/-/morgan-1.9.1.tgz#0a8d16734a1d9afbc824b99df87e738e58e2da59"
1055 | integrity sha512-HQStPIV4y3afTiCYVxirakhlCfGkI161c76kKFca7Fk1JusM//Qeo1ej2XaMniiNeaZklMVrh3vTtIzpzwbpmA==
1056 | dependencies:
1057 | basic-auth "~2.0.0"
1058 | debug "2.6.9"
1059 | depd "~1.1.2"
1060 | on-finished "~2.3.0"
1061 | on-headers "~1.0.1"
1062 |
1063 | ms@2.0.0:
1064 | version "2.0.0"
1065 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
1066 |
1067 | ms@^2.1.1:
1068 | version "2.1.2"
1069 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
1070 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
1071 |
1072 | nan@^2.12.1:
1073 | version "2.14.0"
1074 | resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
1075 | integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==
1076 |
1077 | nanomatch@^1.2.9:
1078 | version "1.2.13"
1079 | resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
1080 | integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==
1081 | dependencies:
1082 | arr-diff "^4.0.0"
1083 | array-unique "^0.3.2"
1084 | define-property "^2.0.2"
1085 | extend-shallow "^3.0.2"
1086 | fragment-cache "^0.2.1"
1087 | is-windows "^1.0.2"
1088 | kind-of "^6.0.2"
1089 | object.pick "^1.3.0"
1090 | regex-not "^1.0.0"
1091 | snapdragon "^0.8.1"
1092 | to-regex "^3.0.1"
1093 |
1094 | negotiator@0.6.2:
1095 | version "0.6.2"
1096 | resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
1097 | integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==
1098 |
1099 | nodemon@1.18.4:
1100 | version "1.18.4"
1101 | resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-1.18.4.tgz#873f65fdb53220eb166180cf106b1354ac5d714d"
1102 | integrity sha512-hyK6vl65IPnky/ee+D3IWvVGgJa/m3No2/Xc/3wanS6Ce1MWjCzH6NnhPJ/vZM+6JFym16jtHx51lmCMB9HDtg==
1103 | dependencies:
1104 | chokidar "^2.0.2"
1105 | debug "^3.1.0"
1106 | ignore-by-default "^1.0.1"
1107 | minimatch "^3.0.4"
1108 | pstree.remy "^1.1.0"
1109 | semver "^5.5.0"
1110 | supports-color "^5.2.0"
1111 | touch "^3.1.0"
1112 | undefsafe "^2.0.2"
1113 | update-notifier "^2.3.0"
1114 |
1115 | nopt@~1.0.10:
1116 | version "1.0.10"
1117 | resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee"
1118 | integrity sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=
1119 | dependencies:
1120 | abbrev "1"
1121 |
1122 | normalize-path@^2.1.1:
1123 | version "2.1.1"
1124 | resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9"
1125 | integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=
1126 | dependencies:
1127 | remove-trailing-separator "^1.0.1"
1128 |
1129 | normalize-path@^3.0.0:
1130 | version "3.0.0"
1131 | resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
1132 | integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
1133 |
1134 | npm-run-path@^2.0.0:
1135 | version "2.0.2"
1136 | resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
1137 | integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=
1138 | dependencies:
1139 | path-key "^2.0.0"
1140 |
1141 | object-copy@^0.1.0:
1142 | version "0.1.0"
1143 | resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c"
1144 | integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw=
1145 | dependencies:
1146 | copy-descriptor "^0.1.0"
1147 | define-property "^0.2.5"
1148 | kind-of "^3.0.3"
1149 |
1150 | object-visit@^1.0.0:
1151 | version "1.0.1"
1152 | resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb"
1153 | integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=
1154 | dependencies:
1155 | isobject "^3.0.0"
1156 |
1157 | object.pick@^1.3.0:
1158 | version "1.3.0"
1159 | resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747"
1160 | integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=
1161 | dependencies:
1162 | isobject "^3.0.1"
1163 |
1164 | on-finished@~2.3.0:
1165 | version "2.3.0"
1166 | resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
1167 | integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=
1168 | dependencies:
1169 | ee-first "1.1.1"
1170 |
1171 | on-headers@~1.0.1:
1172 | version "1.0.2"
1173 | resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f"
1174 | integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==
1175 |
1176 | p-finally@^1.0.0:
1177 | version "1.0.0"
1178 | resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
1179 | integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=
1180 |
1181 | package-json@^4.0.0:
1182 | version "4.0.1"
1183 | resolved "https://registry.yarnpkg.com/package-json/-/package-json-4.0.1.tgz#8869a0401253661c4c4ca3da6c2121ed555f5eed"
1184 | integrity sha1-iGmgQBJTZhxMTKPabCEh7VVfXu0=
1185 | dependencies:
1186 | got "^6.7.1"
1187 | registry-auth-token "^3.0.1"
1188 | registry-url "^3.0.3"
1189 | semver "^5.1.0"
1190 |
1191 | parseurl@~1.3.2:
1192 | version "1.3.3"
1193 | resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
1194 | integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
1195 |
1196 | pascalcase@^0.1.1:
1197 | version "0.1.1"
1198 | resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14"
1199 | integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=
1200 |
1201 | path-dirname@^1.0.0:
1202 | version "1.0.2"
1203 | resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0"
1204 | integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=
1205 |
1206 | path-is-absolute@^1.0.0:
1207 | version "1.0.1"
1208 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
1209 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
1210 |
1211 | path-is-inside@^1.0.1:
1212 | version "1.0.2"
1213 | resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53"
1214 | integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=
1215 |
1216 | path-key@^2.0.0:
1217 | version "2.0.1"
1218 | resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
1219 | integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
1220 |
1221 | path-to-regexp@0.1.7:
1222 | version "0.1.7"
1223 | resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
1224 | integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
1225 |
1226 | pify@^3.0.0:
1227 | version "3.0.0"
1228 | resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
1229 | integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=
1230 |
1231 | posix-character-classes@^0.1.0:
1232 | version "0.1.1"
1233 | resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
1234 | integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=
1235 |
1236 | prepend-http@^1.0.1:
1237 | version "1.0.4"
1238 | resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
1239 | integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=
1240 |
1241 | process-nextick-args@~2.0.0:
1242 | version "2.0.1"
1243 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
1244 | integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
1245 |
1246 | proxy-addr@~2.0.4:
1247 | version "2.0.5"
1248 | resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.5.tgz#34cbd64a2d81f4b1fd21e76f9f06c8a45299ee34"
1249 | integrity sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==
1250 | dependencies:
1251 | forwarded "~0.1.2"
1252 | ipaddr.js "1.9.0"
1253 |
1254 | pseudomap@^1.0.2:
1255 | version "1.0.2"
1256 | resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
1257 | integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM=
1258 |
1259 | pstree.remy@^1.1.0:
1260 | version "1.1.7"
1261 | resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.7.tgz#c76963a28047ed61542dc361aa26ee55a7fa15f3"
1262 | integrity sha512-xsMgrUwRpuGskEzBFkH8NmTimbZ5PcPup0LA8JJkHIm2IMUbQcpo3yeLNWVrufEYjh8YwtSVh0xz6UeWc5Oh5A==
1263 |
1264 | qs@6.5.2:
1265 | version "6.5.2"
1266 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
1267 | integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==
1268 |
1269 | range-parser@~1.2.0:
1270 | version "1.2.1"
1271 | resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
1272 | integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
1273 |
1274 | raw-body@2.3.3:
1275 | version "2.3.3"
1276 | resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.3.3.tgz#1b324ece6b5706e153855bc1148c65bb7f6ea0c3"
1277 | integrity sha512-9esiElv1BrZoI3rCDuOuKCBRbuApGGaDPQfjSflGxdy4oyzqghxu6klEkkVIvBje+FF0BX9coEv8KqW6X/7njw==
1278 | dependencies:
1279 | bytes "3.0.0"
1280 | http-errors "1.6.3"
1281 | iconv-lite "0.4.23"
1282 | unpipe "1.0.0"
1283 |
1284 | rc@^1.0.1, rc@^1.1.6:
1285 | version "1.2.8"
1286 | resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
1287 | integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==
1288 | dependencies:
1289 | deep-extend "^0.6.0"
1290 | ini "~1.3.0"
1291 | minimist "^1.2.0"
1292 | strip-json-comments "~2.0.1"
1293 |
1294 | readable-stream@^2.0.2:
1295 | version "2.3.6"
1296 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
1297 | integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==
1298 | dependencies:
1299 | core-util-is "~1.0.0"
1300 | inherits "~2.0.3"
1301 | isarray "~1.0.0"
1302 | process-nextick-args "~2.0.0"
1303 | safe-buffer "~5.1.1"
1304 | string_decoder "~1.1.1"
1305 | util-deprecate "~1.0.1"
1306 |
1307 | readdirp@^2.2.1:
1308 | version "2.2.1"
1309 | resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525"
1310 | integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==
1311 | dependencies:
1312 | graceful-fs "^4.1.11"
1313 | micromatch "^3.1.10"
1314 | readable-stream "^2.0.2"
1315 |
1316 | regex-not@^1.0.0, regex-not@^1.0.2:
1317 | version "1.0.2"
1318 | resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c"
1319 | integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==
1320 | dependencies:
1321 | extend-shallow "^3.0.2"
1322 | safe-regex "^1.1.0"
1323 |
1324 | registry-auth-token@^3.0.1:
1325 | version "3.4.0"
1326 | resolved "https://registry.yarnpkg.com/registry-auth-token/-/registry-auth-token-3.4.0.tgz#d7446815433f5d5ed6431cd5dca21048f66b397e"
1327 | integrity sha512-4LM6Fw8eBQdwMYcES4yTnn2TqIasbXuwDx3um+QRs7S55aMKCBKBxvPXl2RiUjHwuJLTyYfxSpmfSAjQpcuP+A==
1328 | dependencies:
1329 | rc "^1.1.6"
1330 | safe-buffer "^5.0.1"
1331 |
1332 | registry-url@^3.0.3:
1333 | version "3.1.0"
1334 | resolved "https://registry.yarnpkg.com/registry-url/-/registry-url-3.1.0.tgz#3d4ef870f73dde1d77f0cf9a381432444e174942"
1335 | integrity sha1-PU74cPc93h138M+aOBQyRE4XSUI=
1336 | dependencies:
1337 | rc "^1.0.1"
1338 |
1339 | remove-trailing-separator@^1.0.1:
1340 | version "1.1.0"
1341 | resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef"
1342 | integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8=
1343 |
1344 | repeat-element@^1.1.2:
1345 | version "1.1.3"
1346 | resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce"
1347 | integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==
1348 |
1349 | repeat-string@^1.6.1:
1350 | version "1.6.1"
1351 | resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
1352 | integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc=
1353 |
1354 | resolve-url@^0.2.1:
1355 | version "0.2.1"
1356 | resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
1357 | integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
1358 |
1359 | ret@~0.1.10:
1360 | version "0.1.15"
1361 | resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
1362 | integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==
1363 |
1364 | safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
1365 | version "5.1.2"
1366 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
1367 | integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
1368 |
1369 | safe-buffer@^5.0.1:
1370 | version "5.2.0"
1371 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519"
1372 | integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==
1373 |
1374 | safe-regex@^1.1.0:
1375 | version "1.1.0"
1376 | resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e"
1377 | integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4=
1378 | dependencies:
1379 | ret "~0.1.10"
1380 |
1381 | "safer-buffer@>= 2.1.2 < 3":
1382 | version "2.1.2"
1383 | resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
1384 |
1385 | semver-diff@^2.0.0:
1386 | version "2.1.0"
1387 | resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36"
1388 | integrity sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=
1389 | dependencies:
1390 | semver "^5.0.3"
1391 |
1392 | semver@^5.0.3, semver@^5.1.0, semver@^5.5.0:
1393 | version "5.7.1"
1394 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
1395 | integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
1396 |
1397 | send@0.16.2:
1398 | version "0.16.2"
1399 | resolved "https://registry.yarnpkg.com/send/-/send-0.16.2.tgz#6ecca1e0f8c156d141597559848df64730a6bbc1"
1400 | integrity sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==
1401 | dependencies:
1402 | debug "2.6.9"
1403 | depd "~1.1.2"
1404 | destroy "~1.0.4"
1405 | encodeurl "~1.0.2"
1406 | escape-html "~1.0.3"
1407 | etag "~1.8.1"
1408 | fresh "0.5.2"
1409 | http-errors "~1.6.2"
1410 | mime "1.4.1"
1411 | ms "2.0.0"
1412 | on-finished "~2.3.0"
1413 | range-parser "~1.2.0"
1414 | statuses "~1.4.0"
1415 |
1416 | serve-static@1.13.2:
1417 | version "1.13.2"
1418 | resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.13.2.tgz#095e8472fd5b46237db50ce486a43f4b86c6cec1"
1419 | integrity sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==
1420 | dependencies:
1421 | encodeurl "~1.0.2"
1422 | escape-html "~1.0.3"
1423 | parseurl "~1.3.2"
1424 | send "0.16.2"
1425 |
1426 | set-value@^2.0.0, set-value@^2.0.1:
1427 | version "2.0.1"
1428 | resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b"
1429 | integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==
1430 | dependencies:
1431 | extend-shallow "^2.0.1"
1432 | is-extendable "^0.1.1"
1433 | is-plain-object "^2.0.3"
1434 | split-string "^3.0.1"
1435 |
1436 | setprototypeof@1.1.0:
1437 | version "1.1.0"
1438 | resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656"
1439 | integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==
1440 |
1441 | shebang-command@^1.2.0:
1442 | version "1.2.0"
1443 | resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
1444 | integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=
1445 | dependencies:
1446 | shebang-regex "^1.0.0"
1447 |
1448 | shebang-regex@^1.0.0:
1449 | version "1.0.0"
1450 | resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
1451 | integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=
1452 |
1453 | signal-exit@^3.0.0, signal-exit@^3.0.2:
1454 | version "3.0.2"
1455 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
1456 | integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=
1457 |
1458 | snapdragon-node@^2.0.1:
1459 | version "2.1.1"
1460 | resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b"
1461 | integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==
1462 | dependencies:
1463 | define-property "^1.0.0"
1464 | isobject "^3.0.0"
1465 | snapdragon-util "^3.0.1"
1466 |
1467 | snapdragon-util@^3.0.1:
1468 | version "3.0.1"
1469 | resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2"
1470 | integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==
1471 | dependencies:
1472 | kind-of "^3.2.0"
1473 |
1474 | snapdragon@^0.8.1:
1475 | version "0.8.2"
1476 | resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d"
1477 | integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==
1478 | dependencies:
1479 | base "^0.11.1"
1480 | debug "^2.2.0"
1481 | define-property "^0.2.5"
1482 | extend-shallow "^2.0.1"
1483 | map-cache "^0.2.2"
1484 | source-map "^0.5.6"
1485 | source-map-resolve "^0.5.0"
1486 | use "^3.1.0"
1487 |
1488 | source-map-resolve@^0.5.0:
1489 | version "0.5.2"
1490 | resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259"
1491 | integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==
1492 | dependencies:
1493 | atob "^2.1.1"
1494 | decode-uri-component "^0.2.0"
1495 | resolve-url "^0.2.1"
1496 | source-map-url "^0.4.0"
1497 | urix "^0.1.0"
1498 |
1499 | source-map-url@^0.4.0:
1500 | version "0.4.0"
1501 | resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3"
1502 | integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=
1503 |
1504 | source-map@^0.5.6:
1505 | version "0.5.7"
1506 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
1507 | integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
1508 |
1509 | split-string@^3.0.1, split-string@^3.0.2:
1510 | version "3.1.0"
1511 | resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2"
1512 | integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==
1513 | dependencies:
1514 | extend-shallow "^3.0.0"
1515 |
1516 | static-extend@^0.1.1:
1517 | version "0.1.2"
1518 | resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6"
1519 | integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=
1520 | dependencies:
1521 | define-property "^0.2.5"
1522 | object-copy "^0.1.0"
1523 |
1524 | "statuses@>= 1.4.0 < 2":
1525 | version "1.5.0"
1526 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
1527 | integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=
1528 |
1529 | statuses@~1.4.0:
1530 | version "1.4.0"
1531 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087"
1532 | integrity sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==
1533 |
1534 | string-width@^2.0.0, string-width@^2.1.1:
1535 | version "2.1.1"
1536 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
1537 | integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==
1538 | dependencies:
1539 | is-fullwidth-code-point "^2.0.0"
1540 | strip-ansi "^4.0.0"
1541 |
1542 | string_decoder@~1.1.1:
1543 | version "1.1.1"
1544 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
1545 | integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
1546 | dependencies:
1547 | safe-buffer "~5.1.0"
1548 |
1549 | strip-ansi@^4.0.0:
1550 | version "4.0.0"
1551 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f"
1552 | integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8=
1553 | dependencies:
1554 | ansi-regex "^3.0.0"
1555 |
1556 | strip-eof@^1.0.0:
1557 | version "1.0.0"
1558 | resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
1559 | integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=
1560 |
1561 | strip-json-comments@~2.0.1:
1562 | version "2.0.1"
1563 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
1564 | integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
1565 |
1566 | supports-color@^5.2.0, supports-color@^5.3.0:
1567 | version "5.5.0"
1568 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
1569 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
1570 | dependencies:
1571 | has-flag "^3.0.0"
1572 |
1573 | term-size@^1.2.0:
1574 | version "1.2.0"
1575 | resolved "https://registry.yarnpkg.com/term-size/-/term-size-1.2.0.tgz#458b83887f288fc56d6fffbfad262e26638efa69"
1576 | integrity sha1-RYuDiH8oj8Vtb/+/rSYuJmOO+mk=
1577 | dependencies:
1578 | execa "^0.7.0"
1579 |
1580 | timed-out@^4.0.0:
1581 | version "4.0.1"
1582 | resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f"
1583 | integrity sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=
1584 |
1585 | to-object-path@^0.3.0:
1586 | version "0.3.0"
1587 | resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af"
1588 | integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=
1589 | dependencies:
1590 | kind-of "^3.0.2"
1591 |
1592 | to-regex-range@^2.1.0:
1593 | version "2.1.1"
1594 | resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38"
1595 | integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=
1596 | dependencies:
1597 | is-number "^3.0.0"
1598 | repeat-string "^1.6.1"
1599 |
1600 | to-regex@^3.0.1, to-regex@^3.0.2:
1601 | version "3.0.2"
1602 | resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce"
1603 | integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==
1604 | dependencies:
1605 | define-property "^2.0.2"
1606 | extend-shallow "^3.0.2"
1607 | regex-not "^1.0.2"
1608 | safe-regex "^1.1.0"
1609 |
1610 | touch@^3.1.0:
1611 | version "3.1.0"
1612 | resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.0.tgz#fe365f5f75ec9ed4e56825e0bb76d24ab74af83b"
1613 | integrity sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==
1614 | dependencies:
1615 | nopt "~1.0.10"
1616 |
1617 | type-is@~1.6.16:
1618 | version "1.6.18"
1619 | resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
1620 | integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
1621 | dependencies:
1622 | media-typer "0.3.0"
1623 | mime-types "~2.1.24"
1624 |
1625 | undefsafe@^2.0.2:
1626 | version "2.0.2"
1627 | resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-2.0.2.tgz#225f6b9e0337663e0d8e7cfd686fc2836ccace76"
1628 | integrity sha1-Il9rngM3Zj4Njnz9aG/Cg2zKznY=
1629 | dependencies:
1630 | debug "^2.2.0"
1631 |
1632 | union-value@^1.0.0:
1633 | version "1.0.1"
1634 | resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847"
1635 | integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==
1636 | dependencies:
1637 | arr-union "^3.1.0"
1638 | get-value "^2.0.6"
1639 | is-extendable "^0.1.1"
1640 | set-value "^2.0.1"
1641 |
1642 | unique-string@^1.0.0:
1643 | version "1.0.0"
1644 | resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a"
1645 | integrity sha1-nhBXzKhRq7kzmPizOuGHuZyuwRo=
1646 | dependencies:
1647 | crypto-random-string "^1.0.0"
1648 |
1649 | unpipe@1.0.0, unpipe@~1.0.0:
1650 | version "1.0.0"
1651 | resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
1652 | integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=
1653 |
1654 | unset-value@^1.0.0:
1655 | version "1.0.0"
1656 | resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559"
1657 | integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=
1658 | dependencies:
1659 | has-value "^0.3.1"
1660 | isobject "^3.0.0"
1661 |
1662 | unzip-response@^2.0.1:
1663 | version "2.0.1"
1664 | resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97"
1665 | integrity sha1-0vD3N9FrBhXnKmk17QQhRXLVb5c=
1666 |
1667 | upath@^1.1.1:
1668 | version "1.2.0"
1669 | resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894"
1670 | integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==
1671 |
1672 | update-notifier@^2.3.0:
1673 | version "2.5.0"
1674 | resolved "https://registry.yarnpkg.com/update-notifier/-/update-notifier-2.5.0.tgz#d0744593e13f161e406acb1d9408b72cad08aff6"
1675 | integrity sha512-gwMdhgJHGuj/+wHJJs9e6PcCszpxR1b236igrOkUofGhqJuG+amlIKwApH1IW1WWl7ovZxsX49lMBWLxSdm5Dw==
1676 | dependencies:
1677 | boxen "^1.2.1"
1678 | chalk "^2.0.1"
1679 | configstore "^3.0.0"
1680 | import-lazy "^2.1.0"
1681 | is-ci "^1.0.10"
1682 | is-installed-globally "^0.1.0"
1683 | is-npm "^1.0.0"
1684 | latest-version "^3.0.0"
1685 | semver-diff "^2.0.0"
1686 | xdg-basedir "^3.0.0"
1687 |
1688 | urix@^0.1.0:
1689 | version "0.1.0"
1690 | resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
1691 | integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=
1692 |
1693 | url-parse-lax@^1.0.0:
1694 | version "1.0.0"
1695 | resolved "https://registry.yarnpkg.com/url-parse-lax/-/url-parse-lax-1.0.0.tgz#7af8f303645e9bd79a272e7a14ac68bc0609da73"
1696 | integrity sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=
1697 | dependencies:
1698 | prepend-http "^1.0.1"
1699 |
1700 | use@^3.1.0:
1701 | version "3.1.1"
1702 | resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
1703 | integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==
1704 |
1705 | util-deprecate@~1.0.1:
1706 | version "1.0.2"
1707 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
1708 | integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
1709 |
1710 | utils-merge@1.0.1:
1711 | version "1.0.1"
1712 | resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
1713 | integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
1714 |
1715 | vary@~1.1.2:
1716 | version "1.1.2"
1717 | resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
1718 | integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
1719 |
1720 | which@^1.2.9:
1721 | version "1.3.1"
1722 | resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
1723 | integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
1724 | dependencies:
1725 | isexe "^2.0.0"
1726 |
1727 | widest-line@^2.0.0:
1728 | version "2.0.1"
1729 | resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-2.0.1.tgz#7438764730ec7ef4381ce4df82fb98a53142a3fc"
1730 | integrity sha512-Ba5m9/Fa4Xt9eb2ELXt77JxVDV8w7qQrH0zS/TWSJdLyAwQjWoOzpzj5lwVftDz6n/EOu3tNACS84v509qwnJA==
1731 | dependencies:
1732 | string-width "^2.1.1"
1733 |
1734 | write-file-atomic@^2.0.0:
1735 | version "2.4.3"
1736 | resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.3.tgz#1fd2e9ae1df3e75b8d8c367443c692d4ca81f481"
1737 | integrity sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ==
1738 | dependencies:
1739 | graceful-fs "^4.1.11"
1740 | imurmurhash "^0.1.4"
1741 | signal-exit "^3.0.2"
1742 |
1743 | xdg-basedir@^3.0.0:
1744 | version "3.0.0"
1745 | resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4"
1746 | integrity sha1-SWsswQnsqNus/i3HK2A8F8WHCtQ=
1747 |
1748 | yallist@^2.1.2:
1749 | version "2.1.2"
1750 | resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
1751 | integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=
1752 |
--------------------------------------------------------------------------------