diff options
author | Chocobozzz <me@florianbigard.com> | 2018-09-14 11:52:23 +0200 |
---|---|---|
committer | Chocobozzz <me@florianbigard.com> | 2018-09-14 11:52:23 +0200 |
commit | 7348b1fd84dee869b3c36554aea6797f09d4ceed (patch) | |
tree | 46f6800a92f659dd989d0f38c1b682a61fd2315a | |
parent | 2b62cccd75e9025fb66148bcb1feea2a458ee8e4 (diff) | |
download | PeerTube-7348b1fd84dee869b3c36554aea6797f09d4ceed.tar.gz PeerTube-7348b1fd84dee869b3c36554aea6797f09d4ceed.tar.zst PeerTube-7348b1fd84dee869b3c36554aea6797f09d4ceed.zip |
Speed up overviews route
-rw-r--r-- | package.json | 2 | ||||
-rw-r--r-- | server/controllers/api/overviews.ts | 26 | ||||
-rw-r--r-- | server/helpers/utils.ts | 24 | ||||
-rw-r--r-- | server/initializers/constants.ts | 5 | ||||
-rw-r--r-- | server/lib/schedulers/videos-redundancy-scheduler.ts | 2 | ||||
-rw-r--r-- | server/models/video/video.ts | 27 | ||||
-rw-r--r-- | yarn.lock | 38 |
7 files changed, 80 insertions, 44 deletions
diff --git a/package.json b/package.json index 5a8843b0c..1cb5be181 100644 --- a/package.json +++ b/package.json | |||
@@ -111,6 +111,7 @@ | |||
111 | "jsonld-signatures": "https://github.com/Chocobozzz/jsonld-signatures#rsa2017", | 111 | "jsonld-signatures": "https://github.com/Chocobozzz/jsonld-signatures#rsa2017", |
112 | "lodash": "^4.17.10", | 112 | "lodash": "^4.17.10", |
113 | "magnet-uri": "^5.1.4", | 113 | "magnet-uri": "^5.1.4", |
114 | "memoizee": "^0.4.14", | ||
114 | "morgan": "^1.5.3", | 115 | "morgan": "^1.5.3", |
115 | "multer": "^1.1.0", | 116 | "multer": "^1.1.0", |
116 | "nodemailer": "^4.4.2", | 117 | "nodemailer": "^4.4.2", |
@@ -158,6 +159,7 @@ | |||
158 | "@types/lodash": "^4.14.64", | 159 | "@types/lodash": "^4.14.64", |
159 | "@types/magnet-uri": "^5.1.1", | 160 | "@types/magnet-uri": "^5.1.1", |
160 | "@types/maildev": "^0.0.1", | 161 | "@types/maildev": "^0.0.1", |
162 | "@types/memoizee": "^0.4.2", | ||
161 | "@types/mkdirp": "^0.5.1", | 163 | "@types/mkdirp": "^0.5.1", |
162 | "@types/mocha": "^5.0.0", | 164 | "@types/mocha": "^5.0.0", |
163 | "@types/morgan": "^1.7.32", | 165 | "@types/morgan": "^1.7.32", |
diff --git a/server/controllers/api/overviews.ts b/server/controllers/api/overviews.ts index da941c0ac..cc3cc54a7 100644 --- a/server/controllers/api/overviews.ts +++ b/server/controllers/api/overviews.ts | |||
@@ -4,8 +4,9 @@ import { VideoModel } from '../../models/video/video' | |||
4 | import { asyncMiddleware } from '../../middlewares' | 4 | import { asyncMiddleware } from '../../middlewares' |
5 | import { TagModel } from '../../models/video/tag' | 5 | import { TagModel } from '../../models/video/tag' |
6 | import { VideosOverview } from '../../../shared/models/overviews' | 6 | import { VideosOverview } from '../../../shared/models/overviews' |
7 | import { OVERVIEWS, ROUTE_CACHE_LIFETIME } from '../../initializers' | 7 | import { MEMOIZE_TTL, OVERVIEWS, ROUTE_CACHE_LIFETIME } from '../../initializers' |
8 | import { cacheRoute } from '../../middlewares/cache' | 8 | import { cacheRoute } from '../../middlewares/cache' |
9 | import * as memoizee from 'memoizee' | ||
9 | 10 | ||
10 | const overviewsRouter = express.Router() | 11 | const overviewsRouter = express.Router() |
11 | 12 | ||
@@ -23,10 +24,17 @@ export { overviewsRouter } | |||
23 | // This endpoint could be quite long, but we cache it | 24 | // This endpoint could be quite long, but we cache it |
24 | async function getVideosOverview (req: express.Request, res: express.Response) { | 25 | async function getVideosOverview (req: express.Request, res: express.Response) { |
25 | const attributes = await buildSamples() | 26 | const attributes = await buildSamples() |
27 | |||
28 | const [ categories, channels, tags ] = await Promise.all([ | ||
29 | Promise.all(attributes.categories.map(c => getVideosByCategory(c, res))), | ||
30 | Promise.all(attributes.channels.map(c => getVideosByChannel(c, res))), | ||
31 | Promise.all(attributes.tags.map(t => getVideosByTag(t, res))) | ||
32 | ]) | ||
33 | |||
26 | const result: VideosOverview = { | 34 | const result: VideosOverview = { |
27 | categories: await Promise.all(attributes.categories.map(c => getVideosByCategory(c, res))), | 35 | categories, |
28 | channels: await Promise.all(attributes.channels.map(c => getVideosByChannel(c, res))), | 36 | channels, |
29 | tags: await Promise.all(attributes.tags.map(t => getVideosByTag(t, res))) | 37 | tags |
30 | } | 38 | } |
31 | 39 | ||
32 | // Cleanup our object | 40 | // Cleanup our object |
@@ -37,7 +45,7 @@ async function getVideosOverview (req: express.Request, res: express.Response) { | |||
37 | return res.json(result) | 45 | return res.json(result) |
38 | } | 46 | } |
39 | 47 | ||
40 | async function buildSamples () { | 48 | const buildSamples = memoizee(async function () { |
41 | const [ categories, channels, tags ] = await Promise.all([ | 49 | const [ categories, channels, tags ] = await Promise.all([ |
42 | VideoModel.getRandomFieldSamples('category', OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT), | 50 | VideoModel.getRandomFieldSamples('category', OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD, OVERVIEWS.VIDEOS.SAMPLES_COUNT), |
43 | VideoModel.getRandomFieldSamples('channelId', OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD ,OVERVIEWS.VIDEOS.SAMPLES_COUNT), | 51 | VideoModel.getRandomFieldSamples('channelId', OVERVIEWS.VIDEOS.SAMPLE_THRESHOLD ,OVERVIEWS.VIDEOS.SAMPLES_COUNT), |
@@ -45,7 +53,7 @@ async function buildSamples () { | |||
45 | ]) | 53 | ]) |
46 | 54 | ||
47 | return { categories, channels, tags } | 55 | return { categories, channels, tags } |
48 | } | 56 | }, { maxAge: MEMOIZE_TTL.OVERVIEWS_SAMPLE }) |
49 | 57 | ||
50 | async function getVideosByTag (tag: string, res: express.Response) { | 58 | async function getVideosByTag (tag: string, res: express.Response) { |
51 | const videos = await getVideos(res, { tagsOneOf: [ tag ] }) | 59 | const videos = await getVideos(res, { tagsOneOf: [ tag ] }) |
@@ -84,14 +92,16 @@ async function getVideos ( | |||
84 | res: express.Response, | 92 | res: express.Response, |
85 | where: { videoChannelId?: number, tagsOneOf?: string[], categoryOneOf?: number[] } | 93 | where: { videoChannelId?: number, tagsOneOf?: string[], categoryOneOf?: number[] } |
86 | ) { | 94 | ) { |
87 | const { data } = await VideoModel.listForApi(Object.assign({ | 95 | const query = Object.assign({ |
88 | start: 0, | 96 | start: 0, |
89 | count: 10, | 97 | count: 10, |
90 | sort: '-createdAt', | 98 | sort: '-createdAt', |
91 | includeLocalVideos: true, | 99 | includeLocalVideos: true, |
92 | nsfw: buildNSFWFilter(res), | 100 | nsfw: buildNSFWFilter(res), |
93 | withFiles: false | 101 | withFiles: false |
94 | }, where)) | 102 | }, where) |
103 | |||
104 | const { data } = await VideoModel.listForApi(query, false) | ||
95 | 105 | ||
96 | return data.map(d => d.toFormattedJSON()) | 106 | return data.map(d => d.toFormattedJSON()) |
97 | } | 107 | } |
diff --git a/server/helpers/utils.ts b/server/helpers/utils.ts index a1ed8e72d..a42474417 100644 --- a/server/helpers/utils.ts +++ b/server/helpers/utils.ts | |||
@@ -1,12 +1,12 @@ | |||
1 | import { ResultList } from '../../shared' | 1 | import { ResultList } from '../../shared' |
2 | import { CONFIG } from '../initializers' | 2 | import { CONFIG } from '../initializers' |
3 | import { ActorModel } from '../models/activitypub/actor' | ||
4 | import { ApplicationModel } from '../models/application/application' | 3 | import { ApplicationModel } from '../models/application/application' |
5 | import { pseudoRandomBytesPromise, sha256 } from './core-utils' | 4 | import { pseudoRandomBytesPromise, sha256 } from './core-utils' |
6 | import { logger } from './logger' | 5 | import { logger } from './logger' |
7 | import { join } from 'path' | 6 | import { join } from 'path' |
8 | import { Instance as ParseTorrent } from 'parse-torrent' | 7 | import { Instance as ParseTorrent } from 'parse-torrent' |
9 | import { remove } from 'fs-extra' | 8 | import { remove } from 'fs-extra' |
9 | import * as memoizee from 'memoizee' | ||
10 | 10 | ||
11 | function deleteFileAsync (path: string) { | 11 | function deleteFileAsync (path: string) { |
12 | remove(path) | 12 | remove(path) |
@@ -36,24 +36,12 @@ function getFormattedObjects<U, T extends FormattableToJSON> (objects: T[], obje | |||
36 | } as ResultList<U> | 36 | } as ResultList<U> |
37 | } | 37 | } |
38 | 38 | ||
39 | async function getServerActor () { | 39 | const getServerActor = memoizee(async function () { |
40 | if (getServerActor.serverActor === undefined) { | 40 | const application = await ApplicationModel.load() |
41 | const application = await ApplicationModel.load() | 41 | if (!application) throw Error('Could not load Application from database.') |
42 | if (!application) throw Error('Could not load Application from database.') | ||
43 | 42 | ||
44 | getServerActor.serverActor = application.Account.Actor | 43 | return application.Account.Actor |
45 | } | 44 | }) |
46 | |||
47 | if (!getServerActor.serverActor) { | ||
48 | logger.error('Cannot load server actor.') | ||
49 | process.exit(0) | ||
50 | } | ||
51 | |||
52 | return Promise.resolve(getServerActor.serverActor) | ||
53 | } | ||
54 | namespace getServerActor { | ||
55 | export let serverActor: ActorModel | ||
56 | } | ||
57 | 45 | ||
58 | function generateVideoTmpPath (target: string | ParseTorrent) { | 46 | function generateVideoTmpPath (target: string | ParseTorrent) { |
59 | const id = typeof target === 'string' ? target : target.infoHash | 47 | const id = typeof target === 'string' ? target : target.infoHash |
diff --git a/server/initializers/constants.ts b/server/initializers/constants.ts index 5f7bcbd48..9cccb0919 100644 --- a/server/initializers/constants.ts +++ b/server/initializers/constants.ts | |||
@@ -592,6 +592,10 @@ const CACHE = { | |||
592 | } | 592 | } |
593 | } | 593 | } |
594 | 594 | ||
595 | const MEMOIZE_TTL = { | ||
596 | OVERVIEWS_SAMPLE: 1000 * 3600 * 4 // 4 hours | ||
597 | } | ||
598 | |||
595 | const REDUNDANCY = { | 599 | const REDUNDANCY = { |
596 | VIDEOS: { | 600 | VIDEOS: { |
597 | EXPIRES_AFTER_MS: 48 * 3600 * 1000, // 2 days | 601 | EXPIRES_AFTER_MS: 48 * 3600 * 1000, // 2 days |
@@ -708,6 +712,7 @@ export { | |||
708 | VIDEO_ABUSE_STATES, | 712 | VIDEO_ABUSE_STATES, |
709 | JOB_REQUEST_TIMEOUT, | 713 | JOB_REQUEST_TIMEOUT, |
710 | USER_PASSWORD_RESET_LIFETIME, | 714 | USER_PASSWORD_RESET_LIFETIME, |
715 | MEMOIZE_TTL, | ||
711 | USER_EMAIL_VERIFY_LIFETIME, | 716 | USER_EMAIL_VERIFY_LIFETIME, |
712 | IMAGE_MIMETYPE_EXT, | 717 | IMAGE_MIMETYPE_EXT, |
713 | OVERVIEWS, | 718 | OVERVIEWS, |
diff --git a/server/lib/schedulers/videos-redundancy-scheduler.ts b/server/lib/schedulers/videos-redundancy-scheduler.ts index 8b91d750b..7079600a9 100644 --- a/server/lib/schedulers/videos-redundancy-scheduler.ts +++ b/server/lib/schedulers/videos-redundancy-scheduler.ts | |||
@@ -81,7 +81,7 @@ export class VideosRedundancyScheduler extends AbstractScheduler { | |||
81 | } | 81 | } |
82 | 82 | ||
83 | if (cache.strategy === 'recently-added') { | 83 | if (cache.strategy === 'recently-added') { |
84 | const minViews = (cache as RecentlyAddedStrategy).minViews | 84 | const minViews = cache.minViews |
85 | return VideoRedundancyModel.findRecentlyAddedToDuplicate(REDUNDANCY.VIDEOS.RANDOMIZED_FACTOR, minViews) | 85 | return VideoRedundancyModel.findRecentlyAddedToDuplicate(REDUNDANCY.VIDEOS.RANDOMIZED_FACTOR, minViews) |
86 | } | 86 | } |
87 | } | 87 | } |
diff --git a/server/models/video/video.ts b/server/models/video/video.ts index 23d1dedd6..b7d3f184f 100644 --- a/server/models/video/video.ts +++ b/server/models/video/video.ts | |||
@@ -929,7 +929,7 @@ export class VideoModel extends Model<VideoModel> { | |||
929 | videoChannelId?: number, | 929 | videoChannelId?: number, |
930 | actorId?: number | 930 | actorId?: number |
931 | trendingDays?: number | 931 | trendingDays?: number |
932 | }) { | 932 | }, countVideos = true) { |
933 | const query: IFindOptions<VideoModel> = { | 933 | const query: IFindOptions<VideoModel> = { |
934 | offset: options.start, | 934 | offset: options.start, |
935 | limit: options.count, | 935 | limit: options.count, |
@@ -962,7 +962,7 @@ export class VideoModel extends Model<VideoModel> { | |||
962 | trendingDays | 962 | trendingDays |
963 | } | 963 | } |
964 | 964 | ||
965 | return VideoModel.getAvailableForApi(query, queryOptions) | 965 | return VideoModel.getAvailableForApi(query, queryOptions, countVideos) |
966 | } | 966 | } |
967 | 967 | ||
968 | static async searchAndPopulateAccountAndServer (options: { | 968 | static async searchAndPopulateAccountAndServer (options: { |
@@ -1164,7 +1164,14 @@ export class VideoModel extends Model<VideoModel> { | |||
1164 | } | 1164 | } |
1165 | 1165 | ||
1166 | // threshold corresponds to how many video the field should have to be returned | 1166 | // threshold corresponds to how many video the field should have to be returned |
1167 | static getRandomFieldSamples (field: 'category' | 'channelId', threshold: number, count: number) { | 1167 | static async getRandomFieldSamples (field: 'category' | 'channelId', threshold: number, count: number) { |
1168 | const actorId = (await getServerActor()).id | ||
1169 | |||
1170 | const scopeOptions = { | ||
1171 | actorId, | ||
1172 | includeLocalVideos: true | ||
1173 | } | ||
1174 | |||
1168 | const query: IFindOptions<VideoModel> = { | 1175 | const query: IFindOptions<VideoModel> = { |
1169 | attributes: [ field ], | 1176 | attributes: [ field ], |
1170 | limit: count, | 1177 | limit: count, |
@@ -1172,17 +1179,11 @@ export class VideoModel extends Model<VideoModel> { | |||
1172 | having: Sequelize.where(Sequelize.fn('COUNT', Sequelize.col(field)), { | 1179 | having: Sequelize.where(Sequelize.fn('COUNT', Sequelize.col(field)), { |
1173 | [ Sequelize.Op.gte ]: threshold | 1180 | [ Sequelize.Op.gte ]: threshold |
1174 | }) as any, // FIXME: typings | 1181 | }) as any, // FIXME: typings |
1175 | where: { | ||
1176 | [ field ]: { | ||
1177 | [ Sequelize.Op.not ]: null | ||
1178 | }, | ||
1179 | privacy: VideoPrivacy.PUBLIC, | ||
1180 | state: VideoState.PUBLISHED | ||
1181 | }, | ||
1182 | order: [ this.sequelize.random() ] | 1182 | order: [ this.sequelize.random() ] |
1183 | } | 1183 | } |
1184 | 1184 | ||
1185 | return VideoModel.findAll(query) | 1185 | return VideoModel.scope({ method: [ ScopeNames.AVAILABLE_FOR_LIST_IDS, scopeOptions ] }) |
1186 | .findAll(query) | ||
1186 | .then(rows => rows.map(r => r[ field ])) | 1187 | .then(rows => rows.map(r => r[ field ])) |
1187 | } | 1188 | } |
1188 | 1189 | ||
@@ -1210,7 +1211,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1210 | return {} | 1211 | return {} |
1211 | } | 1212 | } |
1212 | 1213 | ||
1213 | private static async getAvailableForApi (query: IFindOptions<VideoModel>, options: AvailableForListIDsOptions) { | 1214 | private static async getAvailableForApi (query: IFindOptions<VideoModel>, options: AvailableForListIDsOptions, countVideos = true) { |
1214 | const idsScope = { | 1215 | const idsScope = { |
1215 | method: [ | 1216 | method: [ |
1216 | ScopeNames.AVAILABLE_FOR_LIST_IDS, options | 1217 | ScopeNames.AVAILABLE_FOR_LIST_IDS, options |
@@ -1227,7 +1228,7 @@ export class VideoModel extends Model<VideoModel> { | |||
1227 | } | 1228 | } |
1228 | 1229 | ||
1229 | const [ count, rowsId ] = await Promise.all([ | 1230 | const [ count, rowsId ] = await Promise.all([ |
1230 | VideoModel.scope(countScope).count(countQuery), | 1231 | countVideos ? VideoModel.scope(countScope).count(countQuery) : Promise.resolve(undefined), |
1231 | VideoModel.scope(idsScope).findAll(query) | 1232 | VideoModel.scope(idsScope).findAll(query) |
1232 | ]) | 1233 | ]) |
1233 | const ids = rowsId.map(r => r.id) | 1234 | const ids = rowsId.map(r => r.id) |
@@ -160,6 +160,10 @@ | |||
160 | dependencies: | 160 | dependencies: |
161 | "@types/node" "*" | 161 | "@types/node" "*" |
162 | 162 | ||
163 | "@types/memoizee@^0.4.2": | ||
164 | version "0.4.2" | ||
165 | resolved "https://registry.yarnpkg.com/@types/memoizee/-/memoizee-0.4.2.tgz#a500158999a8144a9b46cf9a9fb49b15f1853573" | ||
166 | |||
163 | "@types/mime@*": | 167 | "@types/mime@*": |
164 | version "2.0.0" | 168 | version "2.0.0" |
165 | resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.0.tgz#5a7306e367c539b9f6543499de8dd519fac37a8b" | 169 | resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.0.tgz#5a7306e367c539b9f6543499de8dd519fac37a8b" |
@@ -2058,7 +2062,7 @@ error@^7.0.0: | |||
2058 | string-template "~0.2.1" | 2062 | string-template "~0.2.1" |
2059 | xtend "~4.0.0" | 2063 | xtend "~4.0.0" |
2060 | 2064 | ||
2061 | es5-ext@^0.10.14, es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14: | 2065 | es5-ext@^0.10.14, es5-ext@^0.10.35, es5-ext@^0.10.45, es5-ext@^0.10.9, es5-ext@~0.10.14, es5-ext@~0.10.2: |
2062 | version "0.10.46" | 2066 | version "0.10.46" |
2063 | resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.46.tgz#efd99f67c5a7ec789baa3daa7f79870388f7f572" | 2067 | resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.46.tgz#efd99f67c5a7ec789baa3daa7f79870388f7f572" |
2064 | dependencies: | 2068 | dependencies: |
@@ -2110,7 +2114,7 @@ es6-symbol@3.1.1, es6-symbol@^3.1.1, es6-symbol@~3.1.1: | |||
2110 | d "1" | 2114 | d "1" |
2111 | es5-ext "~0.10.14" | 2115 | es5-ext "~0.10.14" |
2112 | 2116 | ||
2113 | es6-weak-map@^2.0.1: | 2117 | es6-weak-map@^2.0.1, es6-weak-map@^2.0.2: |
2114 | version "2.0.2" | 2118 | version "2.0.2" |
2115 | resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.2.tgz#5e3ab32251ffd1538a1f8e5ffa1357772f92d96f" | 2119 | resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.2.tgz#5e3ab32251ffd1538a1f8e5ffa1357772f92d96f" |
2116 | dependencies: | 2120 | dependencies: |
@@ -2223,7 +2227,7 @@ etag@~1.8.1: | |||
2223 | version "1.8.1" | 2227 | version "1.8.1" |
2224 | resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" | 2228 | resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" |
2225 | 2229 | ||
2226 | event-emitter@~0.3.5: | 2230 | event-emitter@^0.3.5, event-emitter@~0.3.5: |
2227 | version "0.3.5" | 2231 | version "0.3.5" |
2228 | resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" | 2232 | resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" |
2229 | dependencies: | 2233 | dependencies: |
@@ -3757,7 +3761,7 @@ is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: | |||
3757 | dependencies: | 3761 | dependencies: |
3758 | isobject "^3.0.1" | 3762 | isobject "^3.0.1" |
3759 | 3763 | ||
3760 | is-promise@^2.1.0: | 3764 | is-promise@^2.1, is-promise@^2.1.0: |
3761 | version "2.1.0" | 3765 | version "2.1.0" |
3762 | resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" | 3766 | resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" |
3763 | 3767 | ||
@@ -4490,6 +4494,12 @@ lru-cache@4.1.x, lru-cache@^4.0.1: | |||
4490 | pseudomap "^1.0.2" | 4494 | pseudomap "^1.0.2" |
4491 | yallist "^2.1.2" | 4495 | yallist "^2.1.2" |
4492 | 4496 | ||
4497 | lru-queue@0.1: | ||
4498 | version "0.1.0" | ||
4499 | resolved "https://registry.yarnpkg.com/lru-queue/-/lru-queue-0.1.0.tgz#2738bd9f0d3cf4f84490c5736c48699ac632cda3" | ||
4500 | dependencies: | ||
4501 | es5-ext "~0.10.2" | ||
4502 | |||
4493 | lru@^3.0.0, lru@^3.1.0: | 4503 | lru@^3.0.0, lru@^3.1.0: |
4494 | version "3.1.0" | 4504 | version "3.1.0" |
4495 | resolved "https://registry.yarnpkg.com/lru/-/lru-3.1.0.tgz#ea7fb8546d83733396a13091d76cfeb4c06837d5" | 4505 | resolved "https://registry.yarnpkg.com/lru/-/lru-3.1.0.tgz#ea7fb8546d83733396a13091d76cfeb4c06837d5" |
@@ -4594,6 +4604,19 @@ mem@^1.1.0: | |||
4594 | dependencies: | 4604 | dependencies: |
4595 | mimic-fn "^1.0.0" | 4605 | mimic-fn "^1.0.0" |
4596 | 4606 | ||
4607 | memoizee@^0.4.14: | ||
4608 | version "0.4.14" | ||
4609 | resolved "https://registry.yarnpkg.com/memoizee/-/memoizee-0.4.14.tgz#07a00f204699f9a95c2d9e77218271c7cd610d57" | ||
4610 | dependencies: | ||
4611 | d "1" | ||
4612 | es5-ext "^0.10.45" | ||
4613 | es6-weak-map "^2.0.2" | ||
4614 | event-emitter "^0.3.5" | ||
4615 | is-promise "^2.1" | ||
4616 | lru-queue "0.1" | ||
4617 | next-tick "1" | ||
4618 | timers-ext "^0.1.5" | ||
4619 | |||
4597 | memory-chunk-store@^1.2.0: | 4620 | memory-chunk-store@^1.2.0: |
4598 | version "1.3.0" | 4621 | version "1.3.0" |
4599 | resolved "https://registry.yarnpkg.com/memory-chunk-store/-/memory-chunk-store-1.3.0.tgz#ae99e7e3b58b52db43d49d94722930d39459d0c4" | 4622 | resolved "https://registry.yarnpkg.com/memory-chunk-store/-/memory-chunk-store-1.3.0.tgz#ae99e7e3b58b52db43d49d94722930d39459d0c4" |
@@ -7201,6 +7224,13 @@ timed-out@^4.0.0: | |||
7201 | version "4.0.1" | 7224 | version "4.0.1" |
7202 | resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" | 7225 | resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" |
7203 | 7226 | ||
7227 | timers-ext@^0.1.5: | ||
7228 | version "0.1.5" | ||
7229 | resolved "https://registry.yarnpkg.com/timers-ext/-/timers-ext-0.1.5.tgz#77147dd4e76b660c2abb8785db96574cbbd12922" | ||
7230 | dependencies: | ||
7231 | es5-ext "~0.10.14" | ||
7232 | next-tick "1" | ||
7233 | |||
7204 | tiny-lr@^1.1.1: | 7234 | tiny-lr@^1.1.1: |
7205 | version "1.1.1" | 7235 | version "1.1.1" |
7206 | resolved "https://registry.yarnpkg.com/tiny-lr/-/tiny-lr-1.1.1.tgz#9fa547412f238fedb068ee295af8b682c98b2aab" | 7236 | resolved "https://registry.yarnpkg.com/tiny-lr/-/tiny-lr-1.1.1.tgz#9fa547412f238fedb068ee295af8b682c98b2aab" |