Migrate to localforage to support asyncStorage mode
This commit is contained in:
parent
068bcdbfc6
commit
76f54932bf
@ -19,6 +19,7 @@
|
||||
"@mdi/font": "^3.3.92",
|
||||
"file-saver": "^2.0.0",
|
||||
"gps-to-gpx": "git://github.com/phyks/gps-to-gpx.git#1cb5adf4dd382266d076d7df3cb5aa3a4d7dd27b",
|
||||
"localforage": "^1.7.3",
|
||||
"nosleep.js": "^0.9.0",
|
||||
"ol": "^5.3.0",
|
||||
"roboto-fontface": "^0.10.0",
|
||||
|
@ -82,7 +82,7 @@
|
||||
<script>
|
||||
import runtime from 'serviceworker-webpack-plugin/lib/runtime';
|
||||
|
||||
import { DELAY_BETWEEN_API_BATCH_REQUESTS } from '@/constants';
|
||||
import { APP_NAME, DELAY_BETWEEN_API_BATCH_REQUESTS } from '@/constants';
|
||||
|
||||
import Alert from '@/components/Alert.vue';
|
||||
import ReportIssueModal from '@/components/ReportIssueModal.vue';
|
||||
@ -127,7 +127,7 @@ export default {
|
||||
isSearchModalShown: false,
|
||||
isSendingReports: false,
|
||||
isShareMapViewModalShown: false,
|
||||
title: "Cycl'Assist",
|
||||
title: APP_NAME,
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
|
@ -1,4 +1,5 @@
|
||||
export const VERSION = '0.3';
|
||||
export const APP_NAME = 'Cygnal';
|
||||
export const VERSION = '0.4';
|
||||
|
||||
export const NORMAL_ICON_SCALE = 0.625;
|
||||
export const LARGE_ICON_SCALE = 1.0;
|
||||
|
@ -15,11 +15,13 @@ import router from '@/router';
|
||||
import store from '@/store';
|
||||
import '@/vuetify';
|
||||
|
||||
Vue.config.productionTip = false;
|
||||
|
||||
// Populate the store with settings from the storage
|
||||
store.dispatch('populateInitialStateFromStorage').then(() => {
|
||||
// Ensure locale is correctly set from the store value
|
||||
store.dispatch('setLocale', { locale: store.state.settings.locale });
|
||||
|
||||
Vue.config.productionTip = false;
|
||||
|
||||
new Vue({ // eslint-disable-line no-new
|
||||
el: '#app',
|
||||
router,
|
||||
@ -30,3 +32,4 @@ new Vue({ // eslint-disable-line no-new
|
||||
return h('App');
|
||||
},
|
||||
});
|
||||
});
|
||||
|
119
src/storage/index.js
Normal file
119
src/storage/index.js
Normal file
@ -0,0 +1,119 @@
|
||||
import localforage from 'localforage';
|
||||
|
||||
import { APP_NAME } from '@/constants';
|
||||
|
||||
// Initialize localforage
|
||||
localforage.config({
|
||||
// Prefer IndexedDB
|
||||
driver: [localforage.INDEXEDDB, localforage.WEBSQL, localforage.LOCALSTORAGE],
|
||||
name: APP_NAME,
|
||||
});
|
||||
|
||||
export function loadDataFromStorage(table, keys) {
|
||||
// If a single key is requested, get it
|
||||
if (!Array.isArray(keys)) {
|
||||
return localforage.getItem(`${table}.${keys}`).catch(
|
||||
e => console.error(
|
||||
`Unable to load data from storage using table ${table} and keys ${keys}: ${e}.`,
|
||||
),
|
||||
);
|
||||
}
|
||||
// Else, return an array of values
|
||||
return Promise.all(keys.map(
|
||||
key => localforage.getItem(`${table}.${key}`),
|
||||
)).then((arrayValues) => {
|
||||
const values = {};
|
||||
arrayValues.forEach((value, i) => {
|
||||
values[keys[i]] = value;
|
||||
});
|
||||
return values;
|
||||
});
|
||||
}
|
||||
|
||||
// Handle migrations across storage schemes
|
||||
export function handleMigrations() {
|
||||
return localforage.getItem('settings.version').then((localForageVersion) => {
|
||||
const promises = [];
|
||||
|
||||
// Get (legacy) version from local storage
|
||||
let localStorageVersion = null;
|
||||
try {
|
||||
// Try to load version from local storage if available
|
||||
if (localforage.supports(localforage.LOCALSTORAGE)) {
|
||||
localStorageVersion = (
|
||||
localStorage.getItem('settings.version') // for versions > 0.3
|
||||
|| localStorage.getItem('version') // for versions <= 0.3
|
||||
);
|
||||
if (localStorageVersion) {
|
||||
localStorageVersion = JSON.parse(localStorageVersion);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// Pass, ignore error
|
||||
}
|
||||
|
||||
// Pre-0.4
|
||||
if (!localForageVersion) {
|
||||
// First migration, to 0.1
|
||||
if (!localStorageVersion) {
|
||||
console.log('Migrating local storage to version 0.1...');
|
||||
const preventSuspend = localStorage.getItem('preventSuspend');
|
||||
if (preventSuspend !== null) {
|
||||
localStorage.setItem('hasPreventSuspendPermission', JSON.stringify(preventSuspend));
|
||||
}
|
||||
localStorage.removeItem('preventSuspend');
|
||||
localStorageVersion = '0.1';
|
||||
localStorage.setItem('version', JSON.stringify(localStorageVersion));
|
||||
}
|
||||
|
||||
// Migration to 0.4
|
||||
// Migrate to localforage API and purge localStorage values.
|
||||
if (localStorageVersion < '0.4') {
|
||||
console.log('Migrating local storage to version 0.4...');
|
||||
// Migrate settings
|
||||
[
|
||||
'hasGeolocationPermission',
|
||||
'hasPermanentNotificationPermission',
|
||||
'hasPlaySoundPermission',
|
||||
'hasPreventSuspendPermission',
|
||||
'hasVibratePermission',
|
||||
'locale',
|
||||
'shouldAutorotateMap',
|
||||
'skipOnboarding',
|
||||
'tileServer',
|
||||
'version',
|
||||
].forEach((key) => {
|
||||
let value = localStorage.getItem(key);
|
||||
if (value) {
|
||||
// Put value in localforage
|
||||
try {
|
||||
value = JSON.parse(value);
|
||||
} catch (e) {
|
||||
// Pass, ignore error
|
||||
}
|
||||
promises.push(
|
||||
localforage.setItem(`settings.${key}`, value),
|
||||
);
|
||||
// Remove value from localStorage
|
||||
localStorage.removeItem(key);
|
||||
}
|
||||
});
|
||||
// Migrate unsent reports
|
||||
const unsentReports = localStorage.getItem('unsentReports');
|
||||
if (unsentReports) {
|
||||
// Put value in localforage
|
||||
promises.push(
|
||||
localforage.setItem('unsentReports.items', unsentReports),
|
||||
);
|
||||
// Remove value from localStorage
|
||||
localStorage.removeItem('unsentReports');
|
||||
}
|
||||
promises.push(
|
||||
localforage.setItem('settings.version', '0.4'),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return Promise.all(promises);
|
||||
});
|
||||
}
|
@ -1,7 +1,8 @@
|
||||
import * as api from '@/api';
|
||||
import * as constants from '@/constants';
|
||||
import i18n, { messages, getBrowserLocales } from '@/i18n';
|
||||
import { handleMigrations, loadDataFromStorage } from '@/storage';
|
||||
import { pointToPointDistance } from '@/tools/geometry';
|
||||
import i18n from '@/i18n';
|
||||
|
||||
import {
|
||||
DELETE_REPORT,
|
||||
@ -10,6 +11,7 @@ import {
|
||||
INTRO_WAS_UNSEEN,
|
||||
IS_DONE_LOADING,
|
||||
IS_LOADING,
|
||||
LOAD_UNSENT_REPORTS,
|
||||
PUSH_REPORT,
|
||||
PUSH_UNSENT_REPORT,
|
||||
REMOVE_UNSENT_REPORT,
|
||||
@ -24,6 +26,135 @@ import {
|
||||
STORE_REPORTS,
|
||||
} from './mutations-types';
|
||||
|
||||
export function populateInitialStateFromStorage({ commit }) {
|
||||
return handleMigrations().then(() => {
|
||||
// Load unsent reports from storage
|
||||
const unsentReportsPromise = loadDataFromStorage(
|
||||
'unsentReports', 'items',
|
||||
).then(
|
||||
unsentReports => commit(LOAD_UNSENT_REPORTS, {
|
||||
unsentReports: unsentReports || [],
|
||||
}),
|
||||
);
|
||||
|
||||
// Load settings from storage
|
||||
const settingsPromise = loadDataFromStorage('settings', [
|
||||
'hasGeolocationPermission',
|
||||
'hasPermanentNotificationPermission',
|
||||
'hasPlaySoundPermission',
|
||||
'hasPreventSuspendPermission',
|
||||
'hasVibratePermission',
|
||||
'locale',
|
||||
'shouldAutorotateMap',
|
||||
'skipOnboarding',
|
||||
'tileCachingDuration',
|
||||
'tileServer',
|
||||
], null).then((dbSettings) => {
|
||||
const settings = dbSettings || {};
|
||||
|
||||
if (!(settings.locale in messages)) {
|
||||
settings.locale = null;
|
||||
}
|
||||
if (!settings.locale) {
|
||||
// Get best matching locale from browser
|
||||
const locales = getBrowserLocales();
|
||||
for (let i = 0; i < locales.length; i += 1) {
|
||||
if (messages[locales[i]]) {
|
||||
settings.locale = locales[i];
|
||||
break; // Break at first matching locale
|
||||
}
|
||||
}
|
||||
}
|
||||
if (
|
||||
settings.tileCachingDuration !== null
|
||||
&& !Number.isInteger(settings.tileCachingDuration)
|
||||
) {
|
||||
settings.tileCachingDuration = null;
|
||||
}
|
||||
if (
|
||||
settings.tileServer
|
||||
&& !constants.TILE_SERVERS[settings.tileServer]
|
||||
&& !settings.tileServer.startsWith('custom:')
|
||||
) {
|
||||
settings.tileServer = null;
|
||||
}
|
||||
|
||||
commit(SET_SETTING, {
|
||||
setting: 'locale',
|
||||
value: settings.locale || 'en',
|
||||
});
|
||||
commit(SET_SETTING, {
|
||||
setting: 'hasGeolocationPermission',
|
||||
value: (
|
||||
settings.hasGeolocationPermission !== null
|
||||
? settings.hasGeolocationPermission
|
||||
: true
|
||||
),
|
||||
});
|
||||
commit(SET_SETTING, {
|
||||
setting: 'hasPermanentNotificationPermission',
|
||||
value: (
|
||||
settings.hasPermanentNotificationPermission !== null
|
||||
? settings.hasPermanentNotificationPermission
|
||||
: true
|
||||
),
|
||||
});
|
||||
commit(SET_SETTING, {
|
||||
setting: 'hasPlaySoundPermission',
|
||||
value: (
|
||||
settings.hasPlaySoundPermission !== null
|
||||
? settings.hasPlaySoundPermission
|
||||
: true
|
||||
),
|
||||
});
|
||||
commit(SET_SETTING, {
|
||||
setting: 'hasPreventSuspendPermission',
|
||||
value: (
|
||||
settings.hasPreventSuspendPermission !== null
|
||||
? settings.hasPreventSuspendPermission
|
||||
: true
|
||||
),
|
||||
});
|
||||
commit(SET_SETTING, {
|
||||
setting: 'hasVibratePermission',
|
||||
value: (
|
||||
settings.hasVibratePermission !== null
|
||||
? settings.hasVibratePermission
|
||||
: true
|
||||
),
|
||||
});
|
||||
commit(SET_SETTING, {
|
||||
setting: 'shouldAutorotateMap',
|
||||
value: (
|
||||
settings.shouldAutorotateMap !== null
|
||||
? settings.shouldAutorotateMap
|
||||
: false
|
||||
),
|
||||
});
|
||||
commit(SET_SETTING, {
|
||||
setting: 'skipOnboarding',
|
||||
value: settings.skipOnboarding || false,
|
||||
});
|
||||
commit(SET_SETTING, {
|
||||
setting: 'tileCachingDuration',
|
||||
value: (
|
||||
settings.tileCachingDuration !== null
|
||||
? settings.tileCachingDuration
|
||||
: constants.DEFAULT_TILE_CACHING_DURATION
|
||||
),
|
||||
});
|
||||
commit(SET_SETTING, {
|
||||
setting: 'tileServer',
|
||||
value: settings.tileServer || constants.DEFAULT_TILE_SERVER,
|
||||
});
|
||||
});
|
||||
|
||||
return Promise.all(
|
||||
[settingsPromise, unsentReportsPromise],
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
export function fetchReports({ commit, state }) {
|
||||
commit(IS_LOADING);
|
||||
return api.getActiveReports()
|
||||
|
@ -4,6 +4,7 @@ export const INTRO_WAS_SEEN = 'INTRO_WAS_SEEN';
|
||||
export const INTRO_WAS_UNSEEN = 'INTRO_WAS_UNSEEN';
|
||||
export const IS_DONE_LOADING = 'IS_DONE_LOADING';
|
||||
export const IS_LOADING = 'IS_LOADING';
|
||||
export const LOAD_UNSENT_REPORTS = 'LOAD_UNSENT_REPORTS';
|
||||
export const PUSH_REPORT = 'PUSH_REPORT';
|
||||
export const PUSH_UNSENT_REPORT = 'PUSH_UNSENT_REPORT';
|
||||
export const REMOVE_UNSENT_REPORT = 'REMOVE_UNSENT_REPORT';
|
||||
|
@ -1,99 +1,13 @@
|
||||
import Vue from 'vue';
|
||||
import localforage from 'localforage';
|
||||
|
||||
import { messages, getBrowserLocales } from '@/i18n';
|
||||
import { storageAvailable } from '@/tools';
|
||||
import {
|
||||
DEFAULT_TILE_CACHING_DURATION,
|
||||
DEFAULT_TILE_SERVER,
|
||||
TILE_SERVERS,
|
||||
VERSION,
|
||||
} from '@/constants';
|
||||
import * as types from './mutations-types';
|
||||
|
||||
function loadDataFromStorage(name) {
|
||||
try {
|
||||
const value = localStorage.getItem(name);
|
||||
if (value) {
|
||||
return JSON.parse(value);
|
||||
}
|
||||
return null;
|
||||
} catch (e) {
|
||||
console.error(`Unable to load data from storage using key ${name}: ${e}.`);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
function handleMigrations() {
|
||||
if (!storageAvailable('localStorage')) {
|
||||
return;
|
||||
}
|
||||
const version = loadDataFromStorage('version');
|
||||
|
||||
// Migration from pre-0.1 to 0.1
|
||||
if (version === null) {
|
||||
const preventSuspend = loadDataFromStorage('preventSuspend');
|
||||
if (preventSuspend !== null) {
|
||||
localStorage.setItem('hasPreventSuspendPermission', JSON.stringify(preventSuspend));
|
||||
}
|
||||
localStorage.removeItem('preventSuspend');
|
||||
localStorage.setItem('version', JSON.stringify(VERSION));
|
||||
}
|
||||
}
|
||||
|
||||
// Load unsent reports from storage
|
||||
let unsentReports = null;
|
||||
if (storageAvailable('localStorage')) {
|
||||
unsentReports = loadDataFromStorage('unsentReports');
|
||||
}
|
||||
|
||||
// Load settings from storage
|
||||
let locale = null;
|
||||
let hasGeolocationPermission = null;
|
||||
let hasPermanentNotificationPermission = null;
|
||||
let hasPlaySoundPermission = null;
|
||||
let hasPreventSuspendPermission = null;
|
||||
let hasVibratePermission = null;
|
||||
let shouldAutorotateMap = null;
|
||||
let skipOnboarding = null;
|
||||
let tileCachingDuration = null;
|
||||
let tileServer = null;
|
||||
if (storageAvailable('localStorage')) {
|
||||
handleMigrations();
|
||||
|
||||
hasGeolocationPermission = loadDataFromStorage('hasGeolocationPermission');
|
||||
hasPermanentNotificationPermission = loadDataFromStorage('hasPermanentNotificationPermission');
|
||||
hasPlaySoundPermission = loadDataFromStorage('hasPlaySoundPermission');
|
||||
hasPreventSuspendPermission = loadDataFromStorage('hasPreventSuspendPermission');
|
||||
hasVibratePermission = loadDataFromStorage('hasVibratePermission');
|
||||
shouldAutorotateMap = loadDataFromStorage('shouldAutorotateMap');
|
||||
skipOnboarding = loadDataFromStorage('skipOnboarding');
|
||||
|
||||
tileServer = loadDataFromStorage('tileServer');
|
||||
if (tileServer && !TILE_SERVERS[tileServer] && !tileServer.startsWith('custom:')) {
|
||||
tileServer = null;
|
||||
}
|
||||
|
||||
tileCachingDuration = loadDataFromStorage('tileCachingDuration');
|
||||
if (tileCachingDuration !== null && !Number.isInteger(tileCachingDuration)) {
|
||||
tileCachingDuration = null;
|
||||
}
|
||||
|
||||
locale = loadDataFromStorage('locale');
|
||||
if (!(locale in messages)) {
|
||||
locale = null;
|
||||
}
|
||||
if (!locale) {
|
||||
// Get best matching locale from browser
|
||||
const locales = getBrowserLocales();
|
||||
for (let i = 0; i < locales.length; i += 1) {
|
||||
if (messages[locales[i]]) {
|
||||
locale = locales[i];
|
||||
break; // Break at first matching locale
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle the required migrations
|
||||
export const initialState = {
|
||||
hasGoneThroughIntro: false,
|
||||
hasVibratedOnce: false,
|
||||
@ -114,30 +28,18 @@ export const initialState = {
|
||||
userAsked: null,
|
||||
},
|
||||
reports: [],
|
||||
unsentReports: unsentReports || [],
|
||||
unsentReports: [],
|
||||
settings: {
|
||||
locale: locale || 'en',
|
||||
hasGeolocationPermission: (
|
||||
hasGeolocationPermission !== null ? hasGeolocationPermission : true
|
||||
),
|
||||
hasPermanentNotificationPermission: (
|
||||
hasPermanentNotificationPermission !== null ? hasPermanentNotificationPermission : true
|
||||
),
|
||||
hasPlaySoundPermission: (
|
||||
hasPlaySoundPermission !== null ? hasPlaySoundPermission : true
|
||||
),
|
||||
hasPreventSuspendPermission: (
|
||||
hasPreventSuspendPermission !== null ? hasPreventSuspendPermission : true
|
||||
),
|
||||
hasVibratePermission: (
|
||||
hasVibratePermission !== null ? hasVibratePermission : true
|
||||
),
|
||||
shouldAutorotateMap: shouldAutorotateMap !== null ? shouldAutorotateMap : false,
|
||||
skipOnboarding: skipOnboarding || false,
|
||||
tileCachingDuration: (
|
||||
tileCachingDuration !== null ? tileCachingDuration : DEFAULT_TILE_CACHING_DURATION
|
||||
),
|
||||
tileServer: tileServer || DEFAULT_TILE_SERVER,
|
||||
locale: 'en',
|
||||
hasGeolocationPermission: true,
|
||||
hasPermanentNotificationPermission: true,
|
||||
hasPlaySoundPermission: true,
|
||||
hasPreventSuspendPermission: true,
|
||||
hasVibratePermission: true,
|
||||
shouldAutorotateMap: false,
|
||||
skipOnboarding: false,
|
||||
tileCachingDuration: DEFAULT_TILE_CACHING_DURATION,
|
||||
tileServer: DEFAULT_TILE_SERVER,
|
||||
},
|
||||
};
|
||||
|
||||
@ -163,6 +65,9 @@ export const mutations = {
|
||||
[types.IS_LOADING](state) {
|
||||
state.isLoading = true;
|
||||
},
|
||||
[types.LOAD_UNSENT_REPORTS](state, { unsentReports }) {
|
||||
state.unsentReports = unsentReports;
|
||||
},
|
||||
[types.PUSH_REPORT](state, { report }) {
|
||||
const reportIndex = state.reports.findIndex(item => item.id === report.id);
|
||||
if (reportIndex === -1) {
|
||||
@ -173,15 +78,11 @@ export const mutations = {
|
||||
},
|
||||
[types.PUSH_UNSENT_REPORT](state, { report }) {
|
||||
state.unsentReports.push(report);
|
||||
if (storageAvailable('localStorage')) {
|
||||
localStorage.setItem('unsentReports', JSON.stringify(state.unsentReports));
|
||||
}
|
||||
localforage.setItem('unsentReports.items', state.unsentReports);
|
||||
},
|
||||
[types.REMOVE_UNSENT_REPORT](state, { index }) {
|
||||
state.unsentReports.splice(index, 1);
|
||||
if (storageAvailable('localStorage')) {
|
||||
localStorage.setItem('unsentReports', JSON.stringify(state.unsentReports));
|
||||
}
|
||||
localforage.setItem('unsentReports.items', state.unsentReports);
|
||||
},
|
||||
[types.SET_CURRENT_MAP_CENTER](state, { center }) {
|
||||
Vue.set(state.map, 'center', center);
|
||||
@ -202,9 +103,7 @@ export const mutations = {
|
||||
Vue.set(state.location, 'watcherID', id);
|
||||
},
|
||||
[types.SET_SETTING](state, { setting, value }) {
|
||||
if (storageAvailable('localStorage')) {
|
||||
localStorage.setItem(setting, JSON.stringify(value));
|
||||
}
|
||||
localforage.setItem(`settings.${setting}`, value);
|
||||
state.settings[setting] = value;
|
||||
},
|
||||
[types.SHOW_REPORT_DETAILS](state, { id, userAsked }) {
|
||||
|
@ -71,31 +71,6 @@ export function mockLocation(setPosition) {
|
||||
);
|
||||
}
|
||||
|
||||
export function storageAvailable(type) {
|
||||
let storage;
|
||||
try {
|
||||
storage = window[type];
|
||||
const x = '__storage_test__';
|
||||
storage.setItem(x, x);
|
||||
storage.removeItem(x);
|
||||
return true;
|
||||
} catch (e) {
|
||||
return e instanceof DOMException && (
|
||||
// everything except Firefox
|
||||
e.code === 22
|
||||
// Firefox
|
||||
|| e.code === 1014
|
||||
// test name field too, because code might not be present
|
||||
// everything except Firefox
|
||||
|| e.name === 'QuotaExceededError'
|
||||
// Firefox
|
||||
|| e.name === 'NS_ERROR_DOM_QUOTA_REACHED'
|
||||
)
|
||||
// acknowledge QuotaExceededError only if there's something already stored
|
||||
&& storage.length !== 0;
|
||||
}
|
||||
}
|
||||
|
||||
export function capitalize(string) {
|
||||
return string.charAt(0).toUpperCase() + string.slice(1);
|
||||
}
|
||||
|
@ -34,6 +34,7 @@
|
||||
item-value="duration"
|
||||
:label="$t('settings.tileCachingDuration')"
|
||||
required
|
||||
v-if="tileCachingEnabled"
|
||||
></v-select>
|
||||
|
||||
<v-text-field
|
||||
@ -58,6 +59,8 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import localforage from 'localforage';
|
||||
|
||||
import { TILE_SERVERS } from '@/constants';
|
||||
import { AVAILABLE_LOCALES } from '@/i18n';
|
||||
import { capitalize } from '@/tools';
|
||||
@ -169,6 +172,11 @@ export default {
|
||||
}));
|
||||
i18nItems.sort((a, b) => a.iso > b.iso);
|
||||
|
||||
// Only IndexedDB backend can be used in service workers
|
||||
const tileCachingEnabled = (
|
||||
localforage.driver() === localforage.INDEXEDDB
|
||||
);
|
||||
|
||||
return {
|
||||
i18nItems,
|
||||
orientationModes: [
|
||||
@ -181,6 +189,7 @@ export default {
|
||||
value: true,
|
||||
},
|
||||
],
|
||||
tileCachingEnabled,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
19
yarn.lock
19
yarn.lock
@ -4340,6 +4340,11 @@ imagemin@^5.3.1:
|
||||
pify "^2.3.0"
|
||||
replace-ext "^1.0.0"
|
||||
|
||||
immediate@~3.0.5:
|
||||
version "3.0.6"
|
||||
resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b"
|
||||
integrity sha1-nbHb0Pr43m++D13V5Wu2BigN5ps=
|
||||
|
||||
import-cwd@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/import-cwd/-/import-cwd-2.1.0.tgz#aa6cf36e722761285cb371ec6519f53e2435b0a9"
|
||||
@ -4991,6 +4996,13 @@ levn@^0.3.0, levn@~0.3.0:
|
||||
prelude-ls "~1.1.2"
|
||||
type-check "~0.3.2"
|
||||
|
||||
lie@3.1.1:
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/lie/-/lie-3.1.1.tgz#9a436b2cc7746ca59de7a41fa469b3efb76bd87e"
|
||||
integrity sha1-mkNrLMd0bKWd56QfpGmz77dr2H4=
|
||||
dependencies:
|
||||
immediate "~3.0.5"
|
||||
|
||||
load-bmfont@^1.2.3:
|
||||
version "1.3.0"
|
||||
resolved "https://registry.yarnpkg.com/load-bmfont/-/load-bmfont-1.3.0.tgz#bb7e7c710de6bcafcb13cb3b8c81e0c0131ecbc9"
|
||||
@ -5059,6 +5071,13 @@ loader-utils@^1.2.1:
|
||||
emojis-list "^2.0.0"
|
||||
json5 "^1.0.1"
|
||||
|
||||
localforage@^1.7.3:
|
||||
version "1.7.3"
|
||||
resolved "https://registry.yarnpkg.com/localforage/-/localforage-1.7.3.tgz#0082b3ca9734679e1bd534995bdd3b24cf10f204"
|
||||
integrity sha512-1TulyYfc4udS7ECSBT2vwJksWbkwwTX8BzeUIiq8Y07Riy7bDAAnxDaPU/tWyOVmQAcWJIEIFP9lPfBGqVoPgQ==
|
||||
dependencies:
|
||||
lie "3.1.1"
|
||||
|
||||
locate-path@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e"
|
||||
|
Loading…
Reference in New Issue
Block a user