test: add IndexedDB tests (#1075)
* test: add IndexedDB tests Adds unit tests using fake-indexeddb. * remove wtfnode dep
This commit is contained in:
parent
93a3e85994
commit
5cde48c2c5
|
@ -103,6 +103,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"assert": "^1.4.1",
|
"assert": "^1.4.1",
|
||||||
"eslint-plugin-html": "^5.0.3",
|
"eslint-plugin-html": "^5.0.3",
|
||||||
|
"fake-indexeddb": "^2.0.5",
|
||||||
"mocha": "^6.0.2",
|
"mocha": "^6.0.2",
|
||||||
"now": "^14.0.1",
|
"now": "^14.0.1",
|
||||||
"standard": "^12.0.1",
|
"standard": "^12.0.1",
|
||||||
|
|
|
@ -42,6 +42,12 @@ function getOrCreateInstanceCache (cache, instanceName) {
|
||||||
export function clearCache (cache, instanceName) {
|
export function clearCache (cache, instanceName) {
|
||||||
delete cache.caches[instanceName]
|
delete cache.caches[instanceName]
|
||||||
}
|
}
|
||||||
|
export function clearAllCaches (instanceName) {
|
||||||
|
let allCaches = [statusesCache, accountsCache, relationshipsCache, metaCache, notificationsCache]
|
||||||
|
for (let cache of allCaches) {
|
||||||
|
clearCache(cache, instanceName)
|
||||||
|
}
|
||||||
|
}
|
||||||
export function setInCache (cache, instanceName, key, value) {
|
export function setInCache (cache, instanceName, key, value) {
|
||||||
let instanceCache = getOrCreateInstanceCache(cache, instanceName)
|
let instanceCache = getOrCreateInstanceCache(cache, instanceName)
|
||||||
return instanceCache.set(key, value)
|
return instanceCache.set(key, value)
|
||||||
|
|
|
@ -15,9 +15,10 @@ import { mark, stop } from '../_utils/marks'
|
||||||
import { deleteAll } from './utils'
|
import { deleteAll } from './utils'
|
||||||
import { createPinnedStatusKeyRange, createThreadKeyRange } from './keys'
|
import { createPinnedStatusKeyRange, createThreadKeyRange } from './keys'
|
||||||
import { getKnownInstances } from './knownInstances'
|
import { getKnownInstances } from './knownInstances'
|
||||||
|
import noop from 'lodash-es/noop'
|
||||||
|
|
||||||
const BATCH_SIZE = 20
|
const BATCH_SIZE = 20
|
||||||
const TIME_AGO = 5 * 24 * 60 * 60 * 1000 // five days ago
|
export const TIME_AGO = 5 * 24 * 60 * 60 * 1000 // five days ago
|
||||||
const DELAY = 5 * 60 * 1000 // five minutes
|
const DELAY = 5 * 60 * 1000 // five minutes
|
||||||
|
|
||||||
function batchedGetAll (callGetAll, callback) {
|
function batchedGetAll (callGetAll, callback) {
|
||||||
|
@ -97,7 +98,7 @@ function cleanupRelationships (relationshipsStore, cutoff) {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
async function cleanup (instanceName) {
|
export async function cleanup (instanceName) {
|
||||||
console.log('cleanup', instanceName)
|
console.log('cleanup', instanceName)
|
||||||
mark(`cleanup:${instanceName}`)
|
mark(`cleanup:${instanceName}`)
|
||||||
let db = await getDatabase(instanceName)
|
let db = await getDatabase(instanceName)
|
||||||
|
@ -146,4 +147,5 @@ async function scheduledCleanup () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const scheduleCleanup = debounce(scheduledCleanup, DELAY)
|
// we have unit tests that test indexedDB; we don't want this thing to run forever
|
||||||
|
export const scheduleCleanup = process.browser ? debounce(scheduledCleanup, DELAY) : noop
|
||||||
|
|
|
@ -17,4 +17,7 @@ export const USERNAME_LOWERCASE = '__pinafore_acct_lc'
|
||||||
export const DB_VERSION_INITIAL = 9
|
export const DB_VERSION_INITIAL = 9
|
||||||
export const DB_VERSION_SEARCH_ACCOUNTS = 10
|
export const DB_VERSION_SEARCH_ACCOUNTS = 10
|
||||||
export const DB_VERSION_SNOWFLAKE_IDS = 11
|
export const DB_VERSION_SNOWFLAKE_IDS = 11
|
||||||
export const DB_VERSION_CURRENT = 11
|
|
||||||
|
// Using an object for these so that unit tests can change them
|
||||||
|
export const DB_VERSION_CURRENT = { version: 11 }
|
||||||
|
export const CURRENT_TIME = { now: () => Date.now() }
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
import { DB_VERSION_CURRENT } from './constants'
|
import { DB_VERSION_CURRENT } from './constants'
|
||||||
import { addKnownInstance, deleteKnownInstance } from './knownInstances'
|
import { addKnownInstance, deleteKnownInstance } from './knownInstances'
|
||||||
import { migrations } from './migrations'
|
import { migrations } from './migrations'
|
||||||
|
import { clearAllCaches } from './cache'
|
||||||
|
|
||||||
const openReqs = {}
|
const openReqs = {}
|
||||||
const databaseCache = {}
|
const databaseCache = {}
|
||||||
|
|
||||||
function createDatabase (instanceName) {
|
function createDatabase (instanceName) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
let req = indexedDB.open(instanceName, DB_VERSION_CURRENT)
|
let req = indexedDB.open(instanceName, DB_VERSION_CURRENT.version)
|
||||||
openReqs[instanceName] = req
|
openReqs[instanceName] = req
|
||||||
req.onerror = reject
|
req.onerror = reject
|
||||||
req.onblocked = () => {
|
req.onblocked = () => {
|
||||||
|
@ -73,4 +74,17 @@ export function deleteDatabase (instanceName) {
|
||||||
req.onerror = () => reject(req.error)
|
req.onerror = () => reject(req.error)
|
||||||
req.onblocked = () => console.error(`database ${instanceName} blocked`)
|
req.onblocked = () => console.error(`database ${instanceName} blocked`)
|
||||||
}).then(() => deleteKnownInstance(instanceName))
|
}).then(() => deleteKnownInstance(instanceName))
|
||||||
|
.then(() => clearAllCaches(instanceName))
|
||||||
|
}
|
||||||
|
|
||||||
|
// this should probably only be used in unit tests
|
||||||
|
export function closeDatabase (instanceName) {
|
||||||
|
// close any open requests
|
||||||
|
let openReq = openReqs[instanceName]
|
||||||
|
if (openReq && openReq.result) {
|
||||||
|
openReq.result.close()
|
||||||
|
}
|
||||||
|
delete openReqs[instanceName]
|
||||||
|
delete databaseCache[instanceName]
|
||||||
|
clearAllCaches(instanceName)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import { dbPromise, getDatabase } from './databaseLifecycle'
|
import { dbPromise, getDatabase } from './databaseLifecycle'
|
||||||
import { getInCache, hasInCache, setInCache } from './cache'
|
import { getInCache, hasInCache, setInCache } from './cache'
|
||||||
import { ACCOUNT_ID, REBLOG_ID, STATUS_ID, TIMESTAMP, USERNAME_LOWERCASE } from './constants'
|
import {
|
||||||
|
ACCOUNT_ID, REBLOG_ID, STATUS_ID, TIMESTAMP, USERNAME_LOWERCASE, CURRENT_TIME
|
||||||
|
} from './constants'
|
||||||
|
|
||||||
export async function getGenericEntityWithId (store, cache, instanceName, id) {
|
export async function getGenericEntityWithId (store, cache, instanceName, id) {
|
||||||
if (hasInCache(cache, instanceName, id)) {
|
if (hasInCache(cache, instanceName, id)) {
|
||||||
|
@ -50,6 +52,6 @@ export function cloneForStorage (obj) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
res[TIMESTAMP] = Date.now()
|
res[TIMESTAMP] = CURRENT_TIME.now()
|
||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
import indexedDB from 'fake-indexeddb'
|
||||||
|
import IDBKeyRange from 'fake-indexeddb/build/FDBKeyRange'
|
||||||
|
|
||||||
|
global.indexedDB = indexedDB
|
||||||
|
global.IDBKeyRange = IDBKeyRange
|
|
@ -0,0 +1,192 @@
|
||||||
|
/* global it describe beforeEach afterEach */
|
||||||
|
|
||||||
|
import '../indexedDBShims'
|
||||||
|
import assert from 'assert'
|
||||||
|
import { closeDatabase, deleteDatabase, getDatabase } from '../../src/routes/_database/databaseLifecycle'
|
||||||
|
import * as dbApi from '../../src/routes/_database/databaseApis'
|
||||||
|
import times from 'lodash-es/times'
|
||||||
|
import cloneDeep from 'lodash-es/cloneDeep'
|
||||||
|
import {
|
||||||
|
TIMESTAMP, ACCOUNT_ID, STATUS_ID, REBLOG_ID, USERNAME_LOWERCASE,
|
||||||
|
CURRENT_TIME, DB_VERSION_CURRENT, DB_VERSION_SEARCH_ACCOUNTS, DB_VERSION_SNOWFLAKE_IDS
|
||||||
|
} from '../../src/routes/_database/constants'
|
||||||
|
import { cleanup, TIME_AGO } from '../../src/routes/_database/cleanup'
|
||||||
|
|
||||||
|
const INSTANCE_NAME = 'localhost:3000'
|
||||||
|
|
||||||
|
const INSTANCE_INFO = {
|
||||||
|
'uri': 'localhost:3000',
|
||||||
|
'title': 'lolcathost',
|
||||||
|
'description': 'blah',
|
||||||
|
'foo': {
|
||||||
|
'bar': true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const createStatus = i => ({
|
||||||
|
id: i.toString(),
|
||||||
|
created_at: new Date().toISOString(),
|
||||||
|
content: `Status #4{id}`,
|
||||||
|
account: {
|
||||||
|
id: '1'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const stripDBFields = item => {
|
||||||
|
let res = cloneDeep(item)
|
||||||
|
delete res[TIMESTAMP]
|
||||||
|
delete res[ACCOUNT_ID]
|
||||||
|
delete res[STATUS_ID]
|
||||||
|
delete res[REBLOG_ID]
|
||||||
|
delete res[USERNAME_LOWERCASE]
|
||||||
|
if (res.account) {
|
||||||
|
delete res.account[TIMESTAMP]
|
||||||
|
}
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('test-database.js', function () {
|
||||||
|
this.timeout(60000)
|
||||||
|
|
||||||
|
describe('db-basic', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
await getDatabase(INSTANCE_NAME)
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
await deleteDatabase(INSTANCE_NAME)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('basic indexeddb test', async () => {
|
||||||
|
let info = await dbApi.getInstanceInfo(INSTANCE_NAME)
|
||||||
|
assert(!info)
|
||||||
|
await dbApi.setInstanceInfo(INSTANCE_NAME, INSTANCE_INFO)
|
||||||
|
info = await dbApi.getInstanceInfo(INSTANCE_NAME)
|
||||||
|
assert.deepStrictEqual(info, INSTANCE_INFO)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('basic indexeddb test 2', async () => {
|
||||||
|
// sanity check to make sure that we have a clean DB between each test
|
||||||
|
let info = await dbApi.getInstanceInfo(INSTANCE_NAME)
|
||||||
|
assert(!info)
|
||||||
|
await dbApi.setInstanceInfo(INSTANCE_NAME, INSTANCE_INFO)
|
||||||
|
info = await dbApi.getInstanceInfo(INSTANCE_NAME)
|
||||||
|
assert.deepStrictEqual(info, INSTANCE_INFO)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('stores and sorts some statuses', async () => {
|
||||||
|
let allStatuses = times(40, createStatus)
|
||||||
|
await dbApi.insertTimelineItems(INSTANCE_NAME, 'local', allStatuses)
|
||||||
|
let statuses = await dbApi.getTimeline(INSTANCE_NAME, 'local', null, 20)
|
||||||
|
let expected = allStatuses.slice().reverse().slice(0, 20)
|
||||||
|
assert.deepStrictEqual(statuses.map(stripDBFields), expected)
|
||||||
|
|
||||||
|
statuses = await dbApi.getTimeline(INSTANCE_NAME, 'local', statuses[statuses.length - 1].id, 20)
|
||||||
|
expected = allStatuses.slice().reverse().slice(20, 40)
|
||||||
|
assert.deepStrictEqual(statuses.map(stripDBFields), expected)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('cleans up old statuses', async () => {
|
||||||
|
// Pretend we are inserting a status from a long time ago. Note that we
|
||||||
|
// set a timestamp based on the *current* date when the status is inserted,
|
||||||
|
// not the date that the status was composed.
|
||||||
|
|
||||||
|
let longAgo = Date.now() - (TIME_AGO * 2)
|
||||||
|
|
||||||
|
let oldStatus = {
|
||||||
|
id: '1',
|
||||||
|
created_at: new Date(longAgo).toISOString(),
|
||||||
|
content: 'This is old',
|
||||||
|
account: {
|
||||||
|
id: '1'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let previousNow = CURRENT_TIME.now
|
||||||
|
CURRENT_TIME.now = () => longAgo
|
||||||
|
|
||||||
|
await dbApi.insertTimelineItems(INSTANCE_NAME, 'local', [oldStatus])
|
||||||
|
|
||||||
|
CURRENT_TIME.now = previousNow
|
||||||
|
|
||||||
|
let newStatus = {
|
||||||
|
id: '2',
|
||||||
|
created_at: new Date().toISOString(),
|
||||||
|
content: 'This is new',
|
||||||
|
account: {
|
||||||
|
id: '2'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await dbApi.insertTimelineItems(INSTANCE_NAME, 'local', [newStatus])
|
||||||
|
let statuses = await dbApi.getTimeline(INSTANCE_NAME, 'local', null, 20)
|
||||||
|
assert.deepStrictEqual(statuses.map(stripDBFields), [newStatus, oldStatus])
|
||||||
|
|
||||||
|
let status1 = await dbApi.getStatus(INSTANCE_NAME, '1')
|
||||||
|
let status2 = await dbApi.getStatus(INSTANCE_NAME, '2')
|
||||||
|
|
||||||
|
assert.deepStrictEqual(stripDBFields(status1), oldStatus)
|
||||||
|
assert.deepStrictEqual(stripDBFields(status2), newStatus)
|
||||||
|
|
||||||
|
await cleanup(INSTANCE_NAME)
|
||||||
|
|
||||||
|
statuses = await dbApi.getTimeline(INSTANCE_NAME, 'local', null, 20)
|
||||||
|
assert.deepStrictEqual(statuses.map(stripDBFields), [newStatus])
|
||||||
|
|
||||||
|
status1 = await dbApi.getStatus(INSTANCE_NAME, '1')
|
||||||
|
status2 = await dbApi.getStatus(INSTANCE_NAME, '2')
|
||||||
|
|
||||||
|
assert(!!status1)
|
||||||
|
assert.deepStrictEqual(stripDBFields(status2), newStatus)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('db-migrations', () => {
|
||||||
|
let oldCurrentVersion
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
oldCurrentVersion = DB_VERSION_CURRENT.version
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
DB_VERSION_CURRENT.version = oldCurrentVersion
|
||||||
|
await deleteDatabase(INSTANCE_NAME)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('migrates from v10 to v11', async () => {
|
||||||
|
// open the db using the old version
|
||||||
|
DB_VERSION_CURRENT.version = DB_VERSION_SEARCH_ACCOUNTS
|
||||||
|
await getDatabase(INSTANCE_NAME)
|
||||||
|
|
||||||
|
// insert some statuses
|
||||||
|
let allStatuses = times(40, createStatus)
|
||||||
|
await dbApi.insertTimelineItems(INSTANCE_NAME, 'local', allStatuses)
|
||||||
|
|
||||||
|
let statuses = await dbApi.getTimeline(INSTANCE_NAME, 'local', null, 40)
|
||||||
|
let expected = allStatuses.slice().reverse()
|
||||||
|
assert.deepStrictEqual(statuses.map(stripDBFields), expected)
|
||||||
|
|
||||||
|
// close the database
|
||||||
|
closeDatabase(INSTANCE_NAME)
|
||||||
|
|
||||||
|
// do a version upgrade
|
||||||
|
DB_VERSION_CURRENT.version = DB_VERSION_SNOWFLAKE_IDS
|
||||||
|
await getDatabase(INSTANCE_NAME)
|
||||||
|
|
||||||
|
// check that the old statuses are correct
|
||||||
|
statuses = await dbApi.getTimeline(INSTANCE_NAME, 'local', null, 40)
|
||||||
|
expected = allStatuses.slice().reverse()
|
||||||
|
assert.deepStrictEqual(statuses.map(stripDBFields), expected)
|
||||||
|
|
||||||
|
// insert some more statuses for good measure
|
||||||
|
let moreStatuses = times(20, i => 40 + i).map(createStatus)
|
||||||
|
|
||||||
|
await dbApi.insertTimelineItems(INSTANCE_NAME, 'local', moreStatuses)
|
||||||
|
|
||||||
|
statuses = await dbApi.getTimeline(INSTANCE_NAME, 'local', null, 60)
|
||||||
|
expected = moreStatuses.slice().reverse().concat(allStatuses.reverse())
|
||||||
|
|
||||||
|
assert.deepStrictEqual(statuses.map(stripDBFields), expected)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
81
yarn.lock
81
yarn.lock
|
@ -1237,6 +1237,11 @@ balanced-match@^1.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
|
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
|
||||||
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
|
integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
|
||||||
|
|
||||||
|
base64-arraybuffer-es6@0.4.2:
|
||||||
|
version "0.4.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/base64-arraybuffer-es6/-/base64-arraybuffer-es6-0.4.2.tgz#b567d364065843113589b6c1436bd9492701c7fe"
|
||||||
|
integrity sha512-HaJx92u12By863ZXVHZs4Bp1nkKaLpbs3Ec9SI1OKzq60Hz+Ks6z7UvdD8pIx61Ck3e8F9MH/IPEu5T0xKSbkQ==
|
||||||
|
|
||||||
base64-js@^1.0.2, base64-js@^1.1.2:
|
base64-js@^1.0.2, base64-js@^1.1.2:
|
||||||
version "1.3.0"
|
version "1.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3"
|
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3"
|
||||||
|
@ -2001,6 +2006,11 @@ core-js@^2.4.0, core-js@^2.5.0:
|
||||||
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.3.tgz#4b70938bdffdaf64931e66e2db158f0892289c49"
|
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.3.tgz#4b70938bdffdaf64931e66e2db158f0892289c49"
|
||||||
integrity sha512-l00tmFFZOBHtYhN4Cz7k32VM7vTn3rE2ANjQDxdEN6zmXZ/xq1jQuutnmHvMG1ZJ7xd72+TA5YpUK8wz3rWsfQ==
|
integrity sha512-l00tmFFZOBHtYhN4Cz7k32VM7vTn3rE2ANjQDxdEN6zmXZ/xq1jQuutnmHvMG1ZJ7xd72+TA5YpUK8wz3rWsfQ==
|
||||||
|
|
||||||
|
core-js@^2.4.1, core-js@^2.5.3:
|
||||||
|
version "2.6.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.5.tgz#44bc8d249e7fb2ff5d00e0341a7ffb94fbf67895"
|
||||||
|
integrity sha512-klh/kDpwX8hryYL14M9w/xei6vrv6sE8gTHDG7/T/+SEovB/G4ejwcfE/CBzO6Edsu+OETZMZ3wcX/EjUkrl5A==
|
||||||
|
|
||||||
core-util-is@1.0.2, core-util-is@~1.0.0:
|
core-util-is@1.0.2, core-util-is@~1.0.0:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
|
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
|
||||||
|
@ -2447,6 +2457,13 @@ domelementtype@~1.1.1:
|
||||||
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.1.3.tgz#bd28773e2642881aec51544924299c5cd822185b"
|
resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.1.3.tgz#bd28773e2642881aec51544924299c5cd822185b"
|
||||||
integrity sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=
|
integrity sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs=
|
||||||
|
|
||||||
|
domexception@^1.0.1:
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/domexception/-/domexception-1.0.1.tgz#937442644ca6a31261ef36e3ec677fe805582c90"
|
||||||
|
integrity sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==
|
||||||
|
dependencies:
|
||||||
|
webidl-conversions "^4.0.2"
|
||||||
|
|
||||||
domhandler@^2.3.0:
|
domhandler@^2.3.0:
|
||||||
version "2.4.2"
|
version "2.4.2"
|
||||||
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803"
|
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803"
|
||||||
|
@ -3023,6 +3040,15 @@ extsprintf@^1.2.0:
|
||||||
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
|
resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
|
||||||
integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=
|
integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=
|
||||||
|
|
||||||
|
fake-indexeddb@^2.0.5:
|
||||||
|
version "2.0.5"
|
||||||
|
resolved "https://registry.yarnpkg.com/fake-indexeddb/-/fake-indexeddb-2.0.5.tgz#829685232f79bcb9d182b8dd33934e9e5657ed18"
|
||||||
|
integrity sha512-C68kh3Ec3L6JZaTpRm6+TjY5AOs4bwtEOXazzb6733UL0F0jLR7j939e+TdlUmJdxumFQmXIzFhyLu5ZifQc5w==
|
||||||
|
dependencies:
|
||||||
|
core-js "^2.4.1"
|
||||||
|
realistic-structured-clone "^2.0.1"
|
||||||
|
setimmediate "^1.0.5"
|
||||||
|
|
||||||
fast-deep-equal@^2.0.1:
|
fast-deep-equal@^2.0.1:
|
||||||
version "2.0.1"
|
version "2.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
|
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
|
||||||
|
@ -4542,6 +4568,11 @@ lodash.mergewith@^4.6.0:
|
||||||
resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz#639057e726c3afbdb3e7d42741caa8d6e4335927"
|
resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz#639057e726c3afbdb3e7d42741caa8d6e4335927"
|
||||||
integrity sha512-eWw5r+PYICtEBgrBE5hhlT6aAa75f411bgDz/ZL2KZqYV03USvucsxcHUIlGTDTECs1eunpI7HOV7U+WLDvNdQ==
|
integrity sha512-eWw5r+PYICtEBgrBE5hhlT6aAa75f411bgDz/ZL2KZqYV03USvucsxcHUIlGTDTECs1eunpI7HOV7U+WLDvNdQ==
|
||||||
|
|
||||||
|
lodash.sortby@^4.7.0:
|
||||||
|
version "4.7.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
|
||||||
|
integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=
|
||||||
|
|
||||||
lodash@4.17.11, "lodash@4.6.1 || ^4.16.1", lodash@^4.0.0, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.3.0, lodash@~4.17.10:
|
lodash@4.17.11, "lodash@4.6.1 || ^4.16.1", lodash@^4.0.0, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.10, lodash@^4.17.11, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.3.0, lodash@~4.17.10:
|
||||||
version "4.17.11"
|
version "4.17.11"
|
||||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
|
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
|
||||||
|
@ -6126,6 +6157,16 @@ readdirp@^2.0.0, readdirp@^2.2.1:
|
||||||
micromatch "^3.1.10"
|
micromatch "^3.1.10"
|
||||||
readable-stream "^2.0.2"
|
readable-stream "^2.0.2"
|
||||||
|
|
||||||
|
realistic-structured-clone@^2.0.1:
|
||||||
|
version "2.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/realistic-structured-clone/-/realistic-structured-clone-2.0.2.tgz#2f8ec225b1f9af20efc79ac96a09043704414959"
|
||||||
|
integrity sha512-5IEvyfuMJ4tjQOuKKTFNvd+H9GSbE87IcendSBannE28PTrbolgaVg5DdEApRKhtze794iXqVUFKV60GLCNKEg==
|
||||||
|
dependencies:
|
||||||
|
core-js "^2.5.3"
|
||||||
|
domexception "^1.0.1"
|
||||||
|
typeson "^5.8.2"
|
||||||
|
typeson-registry "^1.0.0-alpha.20"
|
||||||
|
|
||||||
redent@^1.0.0:
|
redent@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde"
|
resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde"
|
||||||
|
@ -6575,7 +6616,7 @@ set-value@^2.0.0:
|
||||||
is-plain-object "^2.0.3"
|
is-plain-object "^2.0.3"
|
||||||
split-string "^3.0.1"
|
split-string "^3.0.1"
|
||||||
|
|
||||||
setimmediate@^1.0.4:
|
setimmediate@^1.0.4, setimmediate@^1.0.5:
|
||||||
version "1.0.5"
|
version "1.0.5"
|
||||||
resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
|
resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
|
||||||
integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=
|
integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=
|
||||||
|
@ -7455,6 +7496,13 @@ tough-cookie@~2.4.3:
|
||||||
psl "^1.1.24"
|
psl "^1.1.24"
|
||||||
punycode "^1.4.1"
|
punycode "^1.4.1"
|
||||||
|
|
||||||
|
tr46@^1.0.1:
|
||||||
|
version "1.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09"
|
||||||
|
integrity sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=
|
||||||
|
dependencies:
|
||||||
|
punycode "^2.1.0"
|
||||||
|
|
||||||
tree-kill@^1.1.0:
|
tree-kill@^1.1.0:
|
||||||
version "1.2.1"
|
version "1.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.1.tgz#5398f374e2f292b9dcc7b2e71e30a5c3bb6c743a"
|
resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.1.tgz#5398f374e2f292b9dcc7b2e71e30a5c3bb6c743a"
|
||||||
|
@ -7551,6 +7599,21 @@ typescript@^3.3.3:
|
||||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.3.3333.tgz#171b2c5af66c59e9431199117a3bcadc66fdcfd6"
|
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.3.3333.tgz#171b2c5af66c59e9431199117a3bcadc66fdcfd6"
|
||||||
integrity sha512-JjSKsAfuHBE/fB2oZ8NxtRTk5iGcg6hkYXMnZ3Wc+b2RSqejEqTaem11mHASMnFilHrax3sLK0GDzcJrekZYLw==
|
integrity sha512-JjSKsAfuHBE/fB2oZ8NxtRTk5iGcg6hkYXMnZ3Wc+b2RSqejEqTaem11mHASMnFilHrax3sLK0GDzcJrekZYLw==
|
||||||
|
|
||||||
|
typeson-registry@^1.0.0-alpha.20:
|
||||||
|
version "1.0.0-alpha.26"
|
||||||
|
resolved "https://registry.yarnpkg.com/typeson-registry/-/typeson-registry-1.0.0-alpha.26.tgz#d1f337584196c5d5d112ad981e0dbbd2ced30c30"
|
||||||
|
integrity sha512-R0wwXIYSiJMh+1XfvyUsCnEGVERoJcNrMl9e/ka30dJ+gQyh4/0NU9WHaqUm8oHtZzZYCz+A5fDRCiXYIq7H1Q==
|
||||||
|
dependencies:
|
||||||
|
base64-arraybuffer-es6 "0.4.2"
|
||||||
|
typeson "5.11.0"
|
||||||
|
uuid "3.3.2"
|
||||||
|
whatwg-url "7.0.0"
|
||||||
|
|
||||||
|
typeson@5.11.0, typeson@^5.8.2:
|
||||||
|
version "5.11.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/typeson/-/typeson-5.11.0.tgz#a8273f00050be9eeef974aaa04a0c95a394f821a"
|
||||||
|
integrity sha512-S5KtLzcU4dr4BXh8VuJDYugsRGsDQYlumCbrmwuAX1a1GNpbVYK4p9wluCIfTVPFvVyV6wRfExXX6Q1+YDItEQ==
|
||||||
|
|
||||||
uglify-js@3.4.x:
|
uglify-js@3.4.x:
|
||||||
version "3.4.9"
|
version "3.4.9"
|
||||||
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.9.tgz#af02f180c1207d76432e473ed24a28f4a782bae3"
|
resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.9.tgz#af02f180c1207d76432e473ed24a28f4a782bae3"
|
||||||
|
@ -7701,7 +7764,7 @@ utils-merge@1.0.1:
|
||||||
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
|
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
|
||||||
integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
|
integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
|
||||||
|
|
||||||
uuid@^3.3.2:
|
uuid@3.3.2, uuid@^3.3.2:
|
||||||
version "3.3.2"
|
version "3.3.2"
|
||||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
|
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
|
||||||
integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==
|
integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==
|
||||||
|
@ -7749,6 +7812,11 @@ webauth@^1.1.0:
|
||||||
resolved "https://registry.yarnpkg.com/webauth/-/webauth-1.1.0.tgz#64704f6b8026986605bc3ca629952e6e26fdd100"
|
resolved "https://registry.yarnpkg.com/webauth/-/webauth-1.1.0.tgz#64704f6b8026986605bc3ca629952e6e26fdd100"
|
||||||
integrity sha1-ZHBPa4AmmGYFvDymKZUubib90QA=
|
integrity sha1-ZHBPa4AmmGYFvDymKZUubib90QA=
|
||||||
|
|
||||||
|
webidl-conversions@^4.0.2:
|
||||||
|
version "4.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"
|
||||||
|
integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==
|
||||||
|
|
||||||
webpack-bundle-analyzer@^3.0.4:
|
webpack-bundle-analyzer@^3.0.4:
|
||||||
version "3.0.4"
|
version "3.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-3.0.4.tgz#095638487a664162f19e3b2fb7e621b7002af4b8"
|
resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-3.0.4.tgz#095638487a664162f19e3b2fb7e621b7002af4b8"
|
||||||
|
@ -7805,6 +7873,15 @@ webpack@^4.29.6:
|
||||||
watchpack "^1.5.0"
|
watchpack "^1.5.0"
|
||||||
webpack-sources "^1.3.0"
|
webpack-sources "^1.3.0"
|
||||||
|
|
||||||
|
whatwg-url@7.0.0:
|
||||||
|
version "7.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.0.0.tgz#fde926fa54a599f3adf82dff25a9f7be02dc6edd"
|
||||||
|
integrity sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==
|
||||||
|
dependencies:
|
||||||
|
lodash.sortby "^4.7.0"
|
||||||
|
tr46 "^1.0.1"
|
||||||
|
webidl-conversions "^4.0.2"
|
||||||
|
|
||||||
which-module@^1.0.0:
|
which-module@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f"
|
resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f"
|
||||||
|
|
Loading…
Reference in New Issue