Browse Source

fix: no flatMap in old browsers + refactor

+ flatten `store` into separate vars and reuse more consts for keys to avoid typos
+ match const names to their contents e.g. INJECT_MORE -> MORE, INJECT_AUTO -> AUTO
tophf 2 years ago
parent
commit
b4f25c96e7

+ 98 - 103
src/background/utils/db.js

@@ -13,26 +13,23 @@ import { addOwnCommands, addPublicCommands, commands } from './message';
 import patchDB from './patch-db';
 import { setOption } from './options';
 import storage, {
-  S_CACHE, S_CODE, S_REQUIRE, S_VALUE,
+  S_CACHE, S_CODE, S_REQUIRE, S_SCRIPT, S_VALUE,
   S_CACHE_PRE, S_CODE_PRE, S_MOD_PRE, S_REQUIRE_PRE, S_SCRIPT_PRE, S_VALUE_PRE,
 } from './storage';
 
-export const store = {
-  /** @type {VMScript[]} */
-  scripts: [],
-  /** @type {Object<string,VMScript[]>} */
-  scriptMap: {},
-  /** @type {VMScript[]} */
-  removedScripts: [],
-  /** @type {{ [url:string]: number }} */
-  sizes: {},
-  /** Same order as in SIZE_TITLES and getSizes */
-  sizesPrefixRe: RegExp(`^(${S_CODE_PRE}|${S_SCRIPT_PRE}|${S_VALUE_PRE}|${S_REQUIRE_PRE}|${S_CACHE_PRE}${S_MOD_PRE})`),
-  storeInfo: {
-    id: 0,
-    position: 0,
-  },
-};
+let maxScriptId = 0;
+let maxScriptPosition = 0;
+/** @type {{ [url:string]: number }} */
+export let scriptSizes = {};
+/** @type {Object<string,VMScript[]>} */
+export const scriptMap = {};
+/** @type {VMScript[]} */
+const aliveScripts = [];
+/** @type {VMScript[]} */
+const removedScripts = [];
+/** Same order as in SIZE_TITLES and getSizes */
+export const sizesPrefixRe = RegExp(
+  `^(${S_CODE_PRE}|${S_SCRIPT_PRE}|${S_VALUE_PRE}|${S_REQUIRE_PRE}|${S_CACHE_PRE}${S_MOD_PRE})`);
 
 addPublicCommands({
   GetScriptVer(opts) {
@@ -53,15 +50,15 @@ addOwnCommands({
   async ExportZip({ values }) {
     const scripts = getScripts();
     const ids = scripts.map(getPropsId);
-    const codeMap = await storage.code.getMulti(ids);
+    const codeMap = await storage[S_CODE].getMulti(ids);
     return {
       items: scripts.map(script => ({ script, code: codeMap[script.props.id] })),
-      values: values ? await storage.value.getMulti(ids) : undefined,
+      values: values ? await storage[S_VALUE].getMulti(ids) : undefined,
     };
   },
   /** @return {Promise<string>} */
   GetScriptCode(id) {
-    return storage.code[Array.isArray(id) ? 'getMulti' : 'getOne'](id);
+    return storage[S_CODE][Array.isArray(id) ? 'getMulti' : 'getOne'](id);
   },
   /** @return {Promise<void>} */
   async MarkRemoved({ id, removed }) {
@@ -74,17 +71,17 @@ addOwnCommands({
       config: { removed: removed ? 1 : 0 },
       props: { lastModified: Date.now() },
     });
-    const list = store[removed ? 'scripts' : 'removedScripts'];
+    const list = removed ? aliveScripts : removedScripts;
     const i = list.findIndex(script => script.props.id === id);
     const [script] = list.splice(i, 1);
-    store[removed ? 'removedScripts' : 'scripts'].push(script);
+    (removed ? removedScripts : aliveScripts).push(script);
   },
   /** @return {Promise<number>} */
   Move({ id, offset }) {
     const script = getScriptById(id);
-    const index = store.scripts.indexOf(script);
-    store.scripts.splice(index, 1);
-    store.scripts.splice(index + offset, 0, script);
+    const index = aliveScripts.indexOf(script);
+    aliveScripts.splice(index, 1);
+    aliveScripts.splice(index + offset, 0, script);
     return normalizePosition();
   },
   ParseMeta: parseMetaWithErrors,
@@ -107,10 +104,9 @@ preInitialize.push(async () => {
   if (!lastVersion) await patchDB();
   if (version !== lastVersion) storage.base.set({ version });
   const data = await storage.base.getMulti();
-  const { scripts, removedScripts, storeInfo, scriptMap } = store;
   const uriMap = {};
   data::forEachEntry(([key, script]) => {
-    const id = +storage.script.toId(key);
+    const id = +storage[S_SCRIPT].toId(key);
     if (id && script) {
       const uri = getNameURI(script);
       // Only check ID/namespace conflicts for scripts not removed
@@ -136,9 +132,9 @@ preInitialize.push(async () => {
         ...getDefaultCustom(),
         ...script.custom,
       };
-      storeInfo.id = Math.max(storeInfo.id, id);
-      storeInfo.position = Math.max(storeInfo.position, getInt(script.props.position));
-      (script.config.removed ? removedScripts : scripts).push(script);
+      maxScriptId = Math.max(maxScriptId, id);
+      maxScriptPosition = Math.max(maxScriptPosition, getInt(script.props.position));
+      (script.config.removed ? removedScripts : aliveScripts).push(script);
       // listing all known resource urls in order to remove unused mod keys
       const {
         meta = script.meta = {},
@@ -151,12 +147,14 @@ preInitialize.push(async () => {
   // Switch defaultInjectInto from `page` to `auto` when upgrading VM2.12.7 or older
   if (version !== lastVersion
   && IS_FIREFOX
-  && data.options?.defaultInjectInto === INJECT_PAGE
+  && data.options?.defaultInjectInto === PAGE
   && compareVersion(lastVersion, '2.12.7') <= 0) {
-    setOption('defaultInjectInto', INJECT_AUTO);
+    setOption('defaultInjectInto', AUTO);
   }
   if (process.env.DEBUG) {
-    console.log('store:', store); // eslint-disable-line no-console
+    console.info('store:', {
+      aliveScripts, removedScripts, maxScriptId, maxScriptPosition, scriptMap, scriptSizes,
+    });
   }
   sortScripts();
   vacuum(data);
@@ -179,7 +177,7 @@ function updateLastModified() {
 
 /** @return {Promise<boolean>} */
 export async function normalizePosition() {
-  const updates = store.scripts.reduce((res, script, index) => {
+  const updates = aliveScripts.reduce((res, script, index) => {
     const { props } = script;
     const position = index + 1;
     if (props.position !== position) {
@@ -188,9 +186,9 @@ export async function normalizePosition() {
     }
     return res;
   }, null);
-  store.storeInfo.position = store.scripts.length;
+  maxScriptPosition = aliveScripts.length;
   if (updates) {
-    await storage.script.set(updates);
+    await storage[S_SCRIPT].set(updates);
     updateLastModified();
   }
   return !!updates;
@@ -198,7 +196,7 @@ export async function normalizePosition() {
 
 /** @return {Promise<number>} */
 export async function sortScripts() {
-  store.scripts.sort((a, b) => getInt(a.props.position) - getInt(b.props.position));
+  aliveScripts.sort((a, b) => getInt(a.props.position) - getInt(b.props.position));
   const changed = await normalizePosition();
   sendCmd('ScriptsUpdated', null);
   return changed;
@@ -206,11 +204,11 @@ export async function sortScripts() {
 
 /** @return {?VMScript} */
 export function getScriptById(id) {
-  return store.scriptMap[id];
+  return scriptMap[id];
 }
 
 export function getScriptsByIdsOrAll(ids) {
-  return ids?.map(getScriptById) ?? [...store.scripts, ...store.removedScripts];
+  return ids?.map(getScriptById) ?? [...aliveScripts, ...removedScripts];
 }
 
 /** @return {?VMScript} */
@@ -220,32 +218,32 @@ export function getScript({ id, uri, meta, removed }) {
     script = getScriptById(id);
   } else {
     if (!uri) uri = getNameURI({ meta, id: '@@should-have-name' });
-    script = store[removed ? 'removedScripts' : 'scripts'].find(({ props }) => uri === props.uri);
+    script = (removed ? removedScripts : aliveScripts).find(({ props }) => uri === props.uri);
   }
   return script;
 }
 
 /** @return {VMScript[]} */
 export function getScripts() {
-  return [...store.scripts];
+  return [...aliveScripts];
 }
 
-export const ENV_CACHE_KEYS = 'cacheKeys';
-export const ENV_REQ_KEYS = 'reqKeys';
-export const ENV_SCRIPTS = 'scripts';
-export const ENV_VALUE_IDS = 'valueIds';
+export const CACHE_KEYS = 'cacheKeys';
+export const REQ_KEYS = 'reqKeys';
+export const VALUE_IDS = 'valueIds';
+export const PROMISE = 'promise';
 const makeEnv = () => ({
   depsMap: {},
-  runAt: {},
-  [ENV_SCRIPTS]: [],
+  [RUN_AT]: {},
+  [SCRIPTS]: [],
 });
 const GMCLIP_RE = /^GM[_.]setClipboard$/;
 const GMVALUES_RE = /^GM[_.](listValues|([gs]et|delete)Value)$/;
 const STORAGE_ROUTES = {
-  [S_CACHE]: ENV_CACHE_KEYS,
-  [S_CODE]: 'ids',
-  [S_REQUIRE]: ENV_REQ_KEYS,
-  [S_VALUE]: ENV_VALUE_IDS,
+  [S_CACHE]: CACHE_KEYS,
+  [S_CODE]: IDS,
+  [S_REQUIRE]: REQ_KEYS,
+  [S_VALUE]: VALUE_IDS,
 };
 const STORAGE_ROUTES_ENTRIES = Object.entries(STORAGE_ROUTES);
 const notifiedBadScripts = new Set();
@@ -261,7 +259,7 @@ export function getScriptsByURL(url, isTop, errors) {
   testerBatch(errors || true);
   const allScripts = testBlacklist(url)
     ? []
-    : store.scripts.filter(script => (
+    : aliveScripts.filter(script => (
       (isTop || !(script.custom.noframes ?? script.meta.noframes))
       && testScript(url, script)
     ));
@@ -286,10 +284,10 @@ export function getScriptsByURL(url, isTop, errors) {
     const runAt = getScriptRunAt(script);
     const env = runAt === 'start' || runAt === 'body' ? envStart : envDelayed;
     const { depsMap } = env;
-    env.ids.push(id);
-    env.runAt[id] = runAt;
+    env[IDS].push(id);
+    env[RUN_AT][id] = runAt;
     if (meta.grant.some(GMVALUES_RE.test, GMVALUES_RE)) {
-      env[ENV_VALUE_IDS].push(id);
+      env[VALUE_IDS].push(id);
     }
     if (!clipboardChecked && meta.grant.some(GMCLIP_RE.test, GMCLIP_RE)) {
       clipboardChecked = envStart.clipFF = true;
@@ -314,19 +312,19 @@ export function getScriptsByURL(url, isTop, errors) {
         }
       }
     }
-    env[ENV_SCRIPTS].push(script);
+    env[SCRIPTS].push(script);
   });
   if (!errors) {
-    envDelayed.promise = readEnvironmentData(envDelayed);
+    envDelayed[PROMISE] = readEnvironmentData(envDelayed);
     return envDelayed;
   }
-  if (envStart.ids.length) {
-    envStart.promise = readEnvironmentData(envStart);
+  if (envStart[IDS].length) {
+    envStart[PROMISE] = readEnvironmentData(envStart);
   }
-  if (envDelayed.ids.length) {
-    envDelayed.promise = makePause().then(readEnvironmentData.bind(null, envDelayed));
+  if (envDelayed[IDS].length) {
+    envDelayed[PROMISE] = makePause().then(readEnvironmentData.bind(null, envDelayed));
   }
-  return Object.assign(envStart, { allIds, [INJECT_MORE]: envDelayed });
+  return Object.assign(envStart, { allIds, [MORE]: envDelayed });
 }
 
 async function readEnvironmentData(env) {
@@ -339,7 +337,7 @@ async function readEnvironmentData(env) {
   const data = await storage.base.getMulti(keys);
   const badScripts = new Set();
   for (const [area, listName] of STORAGE_ROUTES_ENTRIES) {
-    env[area] = {}; // presence of the area object is used to check that `env.promise` is resolved
+    env[area] = {}; // presence of the area object is used to check that `env[PROMISE]` is resolved
     for (const id of env[listName]) {
       let val = data[storage[area].toKey(id)];
       if (!val && area === S_VALUE) val = {};
@@ -416,7 +414,7 @@ async function getIconCache(scripts) {
   // Getting a data uri for own icon to load it instantly in Chrome when there are many images
   const ownPath = `${ICON_PREFIX}38.png`;
   const [res, ownUri] = await Promise.all([
-    storage.cache.getMulti(urls, makeDataUri),
+    storage[S_CACHE].getMulti(urls, makeDataUri),
     commands.GetImageData(ownPath).catch(noop),
   ]);
   if (ownUri) res[ownPath] = ownUri;
@@ -435,49 +433,46 @@ export function getSizes(ids) {
     props: { id },
   }, i) => [
     // Same order as SIZE_TITLES and sizesPrefixRe
-    store.sizes[S_CODE_PRE + id] || 0,
+    scriptSizes[S_CODE_PRE + id] || 0,
     deepSize(scripts[i]),
-    store.sizes[S_VALUE_PRE + id] || 0,
+    scriptSizes[S_VALUE_PRE + id] || 0,
     meta.require.reduce(getSizeForRequires, { len: 0, pathMap }).len,
     Object.values(meta.resources).reduce(getSizeForResources, { len: 0, pathMap }).len,
   ]);
 }
 
 function getSizeForRequires(accum, url) {
-  accum.len += (store.sizes[S_REQUIRE_PRE + (accum.pathMap[url] || url)] || 0) + url.length;
+  accum.len += (scriptSizes[S_REQUIRE_PRE + (accum.pathMap[url] || url)] || 0) + url.length;
   return accum;
 }
 
 function getSizeForResources(accum, url) {
-  accum.len += (store.sizes[S_CACHE_PRE + (accum.pathMap[url] || url)] || 0) + url.length;
+  accum.len += (scriptSizes[S_CACHE_PRE + (accum.pathMap[url] || url)] || 0) + url.length;
   return accum;
 }
 
 export async function removeScripts(ids) {
   // Only those marked as removed can be removed permanently
-  const toKeep = [];
-  const toRemove = [];
-  store.removedScripts.forEach(script => {
-    const { id } = script.props;
-    (ids.includes(id) ? toRemove : toKeep).push(script);
-  });
-  if (!toRemove.length) return;
-  ids = toRemove.map(script => script.props.id);
-  ids.forEach(id => {
-    delete store.scriptMap[id];
-  });
-  store.removedScripts = toKeep;
-  await storage.base.remove(ids.flatMap(id => [
-    storage.code.toKey(id),
-    storage.script.toKey(id),
-    storage.value.toKey(id),
-  ]));
-  return sendCmd('RemoveScripts', ids);
+  const newLen = 1 + removedScripts.reduce((iAlive, script, i) => {
+    const id = getPropsId(script);
+    if (ids.includes(id)) delete scriptMap[id];
+    else if (++iAlive < i) removedScripts[iAlive] = script;
+    return iAlive;
+  }, -1);
+  if (removedScripts.length !== newLen) {
+    removedScripts.length = newLen; // live scripts were moved to the beginning
+    await storage.base.remove([
+      ...ids.map(storage[S_CODE].toKey),
+      ...ids.map(storage[S_SCRIPT].toKey),
+      ...ids.map(storage[S_VALUE].toKey),
+    ]);
+    return sendCmd('RemoveScripts', ids);
+  }
 }
 
 export function checkRemove({ force } = {}) {
   const now = Date.now();
-  const ids = store.removedScripts.filter(script => {
+  const ids = removedScripts.filter(script => {
     const { lastModified } = script.props;
     return script.config.removed && (force || now - getInt(lastModified) > TIMEOUT_WEEK);
   }).map(script => script.props.id);
@@ -508,47 +503,47 @@ async function saveScript(script, code) {
   const props = script.props || {};
   let oldScript;
   if (!props.id) {
-    store.storeInfo.id += 1;
-    props.id = store.storeInfo.id;
+    maxScriptId += 1;
+    props.id = maxScriptId;
   } else {
-    oldScript = store.scriptMap[props.id];
+    oldScript = scriptMap[props.id];
   }
   props.uri = getNameURI(script);
   props.uuid = props.uuid || crypto.randomUUID?.() || getUUID();
   // Do not allow script with same name and namespace
-  if (store.scripts.some(({ props: { id, uri } = {} }) => props.id !== id && props.uri === uri)) {
+  if (aliveScripts.some(({ props: { id, uri } = {} }) => props.id !== id && props.uri === uri)) {
     throw i18n('msgNamespaceConflict');
   }
   if (oldScript) {
     script.config = { ...oldScript.config, ...config };
     script.props = { ...oldScript.props, ...props };
-    const index = store.scripts.indexOf(oldScript);
-    store.scripts[index] = script;
+    const index = aliveScripts.indexOf(oldScript);
+    aliveScripts[index] = script;
   } else {
     if (!props.position) {
-      store.storeInfo.position += 1;
-      props.position = store.storeInfo.position;
-    } else if (store.storeInfo.position < props.position) {
-      store.storeInfo.position = props.position;
+      maxScriptPosition += 1;
+      props.position = maxScriptPosition;
+    } else if (maxScriptPosition < props.position) {
+      maxScriptPosition = props.position;
     }
     script.config = config;
     script.props = props;
-    store.scripts.push(script);
+    aliveScripts.push(script);
   }
   return storage.base.set({
-    [storage.script.toKey(props.id)]: script,
-    [storage.code.toKey(props.id)]: code,
+    [storage[S_SCRIPT].toKey(props.id)]: script,
+    [storage[S_CODE].toKey(props.id)]: code,
   });
 }
 
 /** @return {Promise<void>} */
 export async function updateScriptInfo(id, data) {
-  const script = store.scriptMap[id];
+  const script = scriptMap[id];
   if (!script) throw null;
   script.props = { ...script.props, ...data.props };
   script.config = { ...script.config, ...data.config };
   script.custom = { ...script.custom, ...data.custom };
-  await storage.script.setOne(id, script);
+  await storage[S_SCRIPT].setOne(id, script);
   return sendCmd('UpdateScript', { where: { id }, update: script });
 }
 
@@ -743,7 +738,7 @@ export async function vacuum(data) {
       status[key] = -1;
     }
   });
-  store.sizes = sizes;
+  scriptSizes = sizes;
   getScriptsByIdsOrAll().forEach((script) => {
     const { meta, props } = script;
     const { icon } = meta;

+ 12 - 12
src/background/utils/patch-db.js

@@ -1,5 +1,5 @@
 import { parseMeta } from './script';
-import storage from './storage';
+import storage, { S_CACHE, S_CODE, S_REQUIRE, S_SCRIPT, S_VALUE } from './storage';
 
 export default () => new Promise((resolve, reject) => {
   console.info('Upgrade database...');
@@ -21,7 +21,7 @@ export default () => new Promise((resolve, reject) => {
     };
   }
   function transform(db) {
-    const tx = db.transaction(['scripts', 'require', 'cache', 'values']);
+    const tx = db.transaction([SCRIPTS, S_REQUIRE, S_CACHE, VALUES]);
     const updates = {};
     let processing = 3;
     const done = () => {
@@ -33,31 +33,31 @@ export default () => new Promise((resolve, reject) => {
       req.onsuccess = () => callback(req.result);
       req.onerror = reject;
     };
-    getAll('scripts', (allScripts) => {
+    getAll(SCRIPTS, (allScripts) => {
       const uriMap = {};
       allScripts.forEach((script) => {
         const { code, id, uri } = script;
-        updates[storage.script.toKey(id)] = transformScript(script);
-        updates[storage.code.toKey(id)] = code;
+        updates[storage[S_SCRIPT].toKey(id)] = transformScript(script);
+        updates[storage[S_CODE].toKey(id)] = code;
         uriMap[uri] = id;
       });
-      getAll('values', (allValues) => {
-        allValues.forEach(({ uri, values }) => {
+      getAll(VALUES, (allValues) => {
+        allValues.forEach(({ uri, [VALUES]: values }) => {
           const id = uriMap[uri];
-          if (id) updates[storage.value.toKey(id)] = values;
+          if (id) updates[storage[S_VALUE].toKey(id)] = values;
         });
         done();
       });
     });
-    getAll('cache', (allCache) => {
+    getAll(S_CACHE, (allCache) => {
       allCache.forEach(({ uri, data }) => {
-        updates[storage.cache.toKey(uri)] = data;
+        updates[storage[S_CACHE].toKey(uri)] = data;
       });
       done();
     });
-    getAll('require', (allRequire) => {
+    getAll(S_REQUIRE, (allRequire) => {
       allRequire.forEach(({ uri, code }) => {
-        updates[storage.require.toKey(uri)] = code;
+        updates[storage[S_REQUIRE].toKey(uri)] = code;
       });
       done();
     });

+ 1 - 1
src/background/utils/popup-tracker.js

@@ -9,7 +9,7 @@ export const popupTabs = {}; // { tabId: 1 }
 addPublicCommands({
   async SetPopup(data, src) {
     if (popupTabs[src.tab.id]) return;
-    Object.assign(data, await getData({ ids: Object.keys(data.ids) }));
+    Object.assign(data, await getData({ [IDS]: Object.keys(data[IDS]) }));
     cache.put('SetPopup', Object.assign({ [src.frameId]: [data, src] }, cache.get('SetPopup')));
   },
 });

+ 50 - 50
src/background/utils/preinject.js

@@ -3,7 +3,7 @@ import { BLACKLIST, HOMEPAGE_URL, META_STR, METABLOCK_RE, NEWLINE_END_RE } from
 import initCache from '@/common/cache';
 import { forEachEntry, forEachKey, forEachValue, mapEntry, objectSet } from '@/common/object';
 import ua from '@/common/ua';
-import { getScriptsByURL, ENV_CACHE_KEYS, ENV_REQ_KEYS, ENV_SCRIPTS, ENV_VALUE_IDS } from './db';
+import { getScriptsByURL, CACHE_KEYS, PROMISE, REQ_KEYS, VALUE_IDS } from './db';
 import { postInitialize } from './init';
 import { addPublicCommands } from './message';
 import { getOption, hookOptions } from './options';
@@ -28,16 +28,16 @@ const API_CONFIG = {
 const __CODE = Symbol('code'); // will be stripped when messaging
 const INJECT = 'inject';
 /** These bags are reused in cache to reduce memory usage,
- * ENV_CACHE_KEYS is for removeStaleCacheEntry */
-const BAG_NOOP = { [INJECT]: {}, [ENV_CACHE_KEYS]: [] };
-const BAG_NOOP_EXPOSE = { ...BAG_NOOP, [INJECT]: { expose: true, [kSessionId]: sessionId } };
+ * CACHE_KEYS is for removeStaleCacheEntry */
+const BAG_NOOP = { [INJECT]: {}, [CACHE_KEYS]: [] };
+const BAG_NOOP_EXPOSE = { ...BAG_NOOP, [INJECT]: { [EXPOSE]: true, [kSessionId]: sessionId } };
 const CSAPI_REG = 'csReg';
 const contentScriptsAPI = browser.contentScripts;
 const cache = initCache({
   lifetime: 5 * 60e3,
   onDispose(val) {
     val[CSAPI_REG]?.then(reg => reg.unregister());
-    cache.del(val[INJECT_MORE]);
+    cache.del(val[MORE]);
   },
 });
 // KEY_XXX for hooked options
@@ -46,7 +46,7 @@ const META_KEYS_TO_ENSURE = [
   'description',
   'name',
   'namespace',
-  'runAt',
+  [RUN_AT],
   'version',
 ];
 const META_KEYS_TO_ENSURE_FROM = [
@@ -57,16 +57,16 @@ const pluralizeMetaKey = (s, consonant) => s + (consonant ? 'es' : 's');
 const pluralizeMeta = key => key.replace(META_KEYS_TO_PLURALIZE_RE, pluralizeMetaKey);
 const UNWRAP = 'unwrap';
 const KNOWN_INJECT_INTO = {
-  [INJECT_AUTO]: 1,
-  [INJECT_CONTENT]: 1,
-  [INJECT_PAGE]: 1,
+  [AUTO]: 1,
+  [CONTENT]: 1,
+  [PAGE]: 1,
 };
 const propsToClear = {
-  [S_CACHE_PRE]: ENV_CACHE_KEYS,
+  [S_CACHE_PRE]: CACHE_KEYS,
   [S_CODE_PRE]: true,
-  [S_REQUIRE_PRE]: ENV_REQ_KEYS,
+  [S_REQUIRE_PRE]: REQ_KEYS,
   [S_SCRIPT_PRE]: true,
-  [S_VALUE_PRE]: ENV_VALUE_IDS,
+  [S_VALUE_PRE]: VALUE_IDS,
 };
 const expose = {};
 const resolveDataCodeStr = `(${(global, data) => {
@@ -77,13 +77,13 @@ const getKey = (url, isTop) => (
   isTop ? url : `-${url}`
 );
 const normalizeRealm = val => (
-  KNOWN_INJECT_INTO[val] ? val : injectInto || INJECT_AUTO
+  KNOWN_INJECT_INTO[val] ? val : injectInto || AUTO
 );
 const normalizeScriptRealm = (custom, meta) => (
   normalizeRealm(custom[INJECT_INTO] || meta[INJECT_INTO])
 );
 const isContentRealm = (val, force) => (
-  val === INJECT_CONTENT || val === INJECT_AUTO && force
+  val === CONTENT || val === AUTO && force
 );
 const OPT_HANDLERS = {
   [BLACKLIST]: cache.destroy,
@@ -94,7 +94,7 @@ const OPT_HANDLERS = {
   /** WARNING! toggleXhrInject should precede togglePreinject as it sets xhrInject variable */
   xhrInject: toggleXhrInject,
   isApplied: togglePreinject,
-  expose(value) {
+  [EXPOSE](value) {
     value::forEachEntry(([site, isExposed]) => {
       expose[decodeURIComponent(site)] = isExposed;
     });
@@ -104,7 +104,7 @@ if (contentScriptsAPI) OPT_HANDLERS.ffInject = toggleFastFirefoxInject;
 
 addPublicCommands({
   /** @return {Promise<VMInjection>} */
-  async GetInjected({ url, [INJECT_CONTENT_FORCE]: forceContent, done }, src) {
+  async GetInjected({ url, [FORCE_CONTENT]: forceContent, done }, src) {
     const { frameId, tab } = src;
     const tabId = tab.id;
     const isTop = !frameId;
@@ -112,12 +112,12 @@ addPublicCommands({
     clearFrameData(tabId, frameId);
     const bagKey = getKey(url, isTop);
     const bagP = cache.get(bagKey) || prepare(bagKey, url, isTop);
-    const bag = bagP[INJECT] ? bagP : await bagP.promise;
+    const bag = bagP[INJECT] ? bagP : await bagP[PROMISE];
     /** @type {VMInjection} */
     const inject = bag[INJECT];
-    const scripts = inject[ENV_SCRIPTS];
+    const scripts = inject[SCRIPTS];
     if (scripts) {
-      triageRealms(scripts, bag[INJECT_CONTENT_FORCE] || forceContent, tabId, frameId, bag);
+      triageRealms(scripts, bag[FORCE_CONTENT] || forceContent, tabId, frameId, bag);
       addValueOpener(scripts, tabId, frameId);
     }
     if (popupTabs[tabId]) {
@@ -126,9 +126,9 @@ addPublicCommands({
     return !done && inject;
   },
   async InjectionFeedback({
-    [INJECT_CONTENT_FORCE]: forceContent,
-    [INJECT_CONTENT]: items,
-    [INJECT_MORE]: moreKey,
+    [FORCE_CONTENT]: forceContent,
+    [CONTENT]: items,
+    [MORE]: moreKey,
     url,
   }, src) {
     const { frameId, tab } = src;
@@ -139,12 +139,12 @@ addPublicCommands({
     let more = cache.get(moreKey)
       || cache.put(moreKey, getScriptsByURL(url, !frameId));
     const envCache = more[S_CACHE]
-      || cache.put(moreKey, more = await more.promise)[S_CACHE];
+      || cache.put(moreKey, more = await more[PROMISE])[S_CACHE];
     const scripts = prepareScripts(more);
     triageRealms(scripts, forceContent, tabId, frameId);
     addValueOpener(scripts, tabId, frameId);
     return {
-      [ENV_SCRIPTS]: scripts,
+      [SCRIPTS]: scripts,
       [S_CACHE]: envCache,
     };
   },
@@ -166,7 +166,7 @@ onStorageChanged(({ keys }) => {
 
 /** @this {string[][]} changed storage keys, already split as [prefix,id] */
 function removeStaleCacheEntry(val, key) {
-  if (!val[ENV_CACHE_KEYS]) return;
+  if (!val[CACHE_KEYS]) return;
   for (const [prefix, id] of this) {
     const prop = propsToClear[prefix];
     if (prop === true) {
@@ -248,7 +248,7 @@ function onHeadersReceived(info) {
   const key = getKey(info.url, !info.frameId);
   const bag = xhrInject && cache.get(key);
   // Proceeding only if prepareScripts has replaced promise in cache with the actual data
-  return bag?.[INJECT]?.[ENV_SCRIPTS] && prepareXhrBlob(info, bag);
+  return bag?.[INJECT]?.[SCRIPTS] && prepareXhrBlob(info, bag);
 }
 
 /**
@@ -257,9 +257,9 @@ function onHeadersReceived(info) {
  */
 function prepareXhrBlob({ url, [kResponseHeaders]: responseHeaders, tabId, frameId }, bag) {
   if (IS_FIREFOX && url.startsWith('https:') && detectStrictCsp(responseHeaders)) {
-    bag[INJECT_CONTENT_FORCE] = true;
+    bag[FORCE_CONTENT] = true;
   }
-  triageRealms(bag[INJECT][ENV_SCRIPTS], bag[INJECT_CONTENT_FORCE], tabId, frameId, bag);
+  triageRealms(bag[INJECT][SCRIPTS], bag[FORCE_CONTENT], tabId, frameId, bag);
   const blobUrl = URL.createObjectURL(new Blob([
     JSON.stringify(bag[INJECT]),
   ]));
@@ -271,7 +271,7 @@ function prepareXhrBlob({ url, [kResponseHeaders]: responseHeaders, tabId, frame
   return { [kResponseHeaders]: responseHeaders };
 }
 
-async function prepare(cacheKey, url, isTop) {
+function prepare(cacheKey, url, isTop) {
   const shouldExpose = isTop && url.startsWith('https://') && expose[url.split('/', 3)[2]];
   const bagNoOp = shouldExpose ? BAG_NOOP_EXPOSE : BAG_NOOP;
   if (!isApplied) {
@@ -281,40 +281,40 @@ async function prepare(cacheKey, url, isTop) {
   // TODO: teach `getScriptEnv` to skip prepared scripts in cache
   const env = getScriptsByURL(url, isTop, errors);
   if (env) {
-    env.promise = prepareBag(cacheKey, url, isTop,
-      env, shouldExpose ? { expose: true } : {}, errors);
+    env[PROMISE] = prepareBag(cacheKey, url, isTop,
+      env, shouldExpose ? { [EXPOSE]: true } : {}, errors);
   }
   return cache.put(cacheKey, env || bagNoOp);
 }
 
 async function prepareBag(cacheKey, url, isTop, env, inject, errors) {
-  await env.promise;
+  await env[PROMISE];
   cache.batch(true);
   const bag = { [INJECT]: inject };
-  const { allIds, [INJECT_MORE]: envDelayed } = env;
-  const moreKey = envDelayed.promise && getUniqId('more');
+  const { allIds, [MORE]: envDelayed } = env;
+  const moreKey = envDelayed[PROMISE] && getUniqId('more');
   Object.assign(inject, {
     [S_CACHE]: env[S_CACHE],
-    [ENV_SCRIPTS]: prepareScripts(env),
+    [SCRIPTS]: prepareScripts(env),
     [INJECT_INTO]: injectInto,
-    [INJECT_MORE]: moreKey,
+    [MORE]: moreKey,
     [kSessionId]: sessionId,
+    [IDS]: allIds,
     clipFF: env.clipFF,
-    ids: allIds,
     info: { ua },
     errors: errors.filter(err => allIds[err.split('#').pop()]).join('\n'),
   });
   propsToClear::forEachValue(val => {
     if (val !== true) bag[val] = env[val];
   });
-  bag[INJECT_MORE] = envDelayed;
+  bag[MORE] = envDelayed;
   if (ffInject && contentScriptsAPI && !xhrInject && isTop) {
-    inject[INJECT_PAGE] = env[INJECT_PAGE] || triagePageRealm(envDelayed);
+    inject[PAGE] = env[PAGE] || triagePageRealm(envDelayed);
     bag[CSAPI_REG] = registerScriptDataFF(inject, url);
   }
   if (moreKey) {
     cache.put(moreKey, envDelayed);
-    envDelayed[INJECT_MORE] = cacheKey;
+    envDelayed[MORE] = cacheKey;
   }
   cache.put(cacheKey, bag); // synchronous onHeadersReceived needs plain object not a Promise
   cache.batch(false);
@@ -322,7 +322,7 @@ async function prepareBag(cacheKey, url, isTop, env, inject, errors) {
 }
 
 function prepareScripts(env) {
-  const scripts = env[ENV_SCRIPTS];
+  const scripts = env[SCRIPTS];
   for (let i = 0, script, key, id; i < scripts.length; i++) {
     script = scripts[i];
     id = script.id;
@@ -332,10 +332,10 @@ function prepareScripts(env) {
       script = cache.get(key) || cache.put(key, prepareScript(script, env));
       scripts[i] = script;
     }
-    if (script[INJECT_INTO] !== INJECT_CONTENT) {
-      env[INJECT_PAGE] = true; // for registerScriptDataFF
+    if (script[INJECT_INTO] !== CONTENT) {
+      env[PAGE] = true; // for registerScriptDataFF
     }
-    script[INJECT_VAL] = env[S_VALUE][id] || null;
+    script[VALUES] = env[S_VALUE][id] || null;
   }
   return scripts;
 }
@@ -348,7 +348,7 @@ function prepareScripts(env) {
 function prepareScript(script, env) {
   const { custom, meta, props } = script;
   const { id } = props;
-  const { require, runAt } = env;
+  const { require, [RUN_AT]: runAt } = env;
   const code = env[S_CODE][id];
   const dataKey = getUniqId();
   const winKey = getUniqId();
@@ -415,7 +415,6 @@ function prepareScript(script, env) {
     key,
     meta: metaCopy,
     pathMap,
-    runAt: runAt[id],
     [__CODE]: injectedCode,
     [INJECT_INTO]: normalizeScriptRealm(custom, meta),
     [META_STR]: [
@@ -424,6 +423,7 @@ function prepareScript(script, env) {
       tmp = (metaStrMatch.index + metaStrMatch[1].length),
       tmp + metaStrMatch[2].length,
     ],
+    [RUN_AT]: runAt[id],
   };
 }
 
@@ -448,7 +448,7 @@ function triageRealms(scripts, forceContent, tabId, frameId, bag) {
     scr.code = code;
   }
   if (bag) {
-    bag[INJECT][INJECT_PAGE] = wantsPage || triagePageRealm(bag[INJECT_MORE]);
+    bag[INJECT][PAGE] = wantsPage || triagePageRealm(bag[MORE]);
   }
   if (toContent[0]) {
     // Processing known feedback without waiting for InjectionFeedback message.
@@ -458,7 +458,7 @@ function triageRealms(scripts, forceContent, tabId, frameId, bag) {
 }
 
 function triagePageRealm(env, forceContent) {
-  return env?.[ENV_SCRIPTS].some(isPageRealmScript, forceContent || null);
+  return env?.[SCRIPTS].some(isPageRealmScript, forceContent || null);
 }
 
 function injectContentRealm(toContent, tabId, frameId) {
@@ -467,7 +467,7 @@ function injectContentRealm(toContent, tabId, frameId) {
     if (!scr || scr.key.data !== dataKey) continue;
     browser.tabs.executeScript(tabId, {
       code: scr[__CODE].join(''),
-      runAt: `document_${scr.runAt}`.replace('body', 'start'),
+      runAt: `document_${scr[RUN_AT]}`.replace('body', 'start'),
       frameId,
     }).then(scr.meta[UNWRAP] && (() => sendTabCmd(tabId, 'Run', id, { frameId })));
   }
@@ -476,7 +476,7 @@ function injectContentRealm(toContent, tabId, frameId) {
 // TODO: rework the whole thing to register scripts individually with real `matches`
 // (this will also allow proper handling of @noframes)
 function registerScriptDataFF(inject, url) {
-  for (const scr of inject[ENV_SCRIPTS]) {
+  for (const scr of inject[SCRIPTS]) {
     scr.code = scr[__CODE];
   }
   return contentScriptsAPI.register({

+ 7 - 8
src/background/utils/storage-cache.js

@@ -2,8 +2,8 @@ import { debounce, ensureArray, initHooks, isEmpty } from '@/common';
 import initCache from '@/common/cache';
 import { INFERRED, WATCH_STORAGE } from '@/common/consts';
 import { deepCopy, deepCopyDiff, deepSize, forEachEntry } from '@/common/object';
-import { store } from './db';
-import storage, { S_SCRIPT_PRE } from './storage';
+import { scriptMap, scriptSizes, sizesPrefixRe } from './db';
+import storage, { S_SCRIPT, S_SCRIPT_PRE, S_VALUE } from './storage';
 import { clearValueOpener } from './values';
 
 /** Throttling browser API for `storage.value`, processing requests sequentially,
@@ -22,7 +22,6 @@ const TTL_MAIN = 3600e3;
 const TTL_TINY = 24 * 3600e3;
 const cache = initCache({ lifetime: TTL_MAIN });
 const dbKeys = initCache({ lifetime: TTL_TINY }); // 1: exists, 0: known to be absent
-const { scriptMap } = store;
 const { api } = storage;
 const GET = 'get';
 const SET = 'set';
@@ -74,7 +73,7 @@ storage.api = {
       if (copy !== undefined) {
         cache.put(key, copy);
         dbKeys.put(key, 1);
-        if (storage.value.toId(key)) {
+        if (storage[S_VALUE].toId(key)) {
           unflushed = true;
           valuesToFlush[key] = copy;
         } else {
@@ -102,7 +101,7 @@ storage.api = {
       if (ok) {
         cache.del(key);
         dbKeys.put(key, 0);
-        if (storage.value.toId(key)) {
+        if (storage[S_VALUE].toId(key)) {
           valuesToFlush[key] = null;
           unflushed = true;
           ok = false;
@@ -169,7 +168,7 @@ function batch(state) {
 }
 
 function updateScriptMap(key, val) {
-  const id = +storage.script.toId(key);
+  const id = +storage[S_SCRIPT].toId(key);
   if (id) {
     if (val) scriptMap[id] = val;
     else delete scriptMap[id];
@@ -178,9 +177,9 @@ function updateScriptMap(key, val) {
 }
 
 async function updateScriptSizeContributor(key, val) {
-  const area = store.sizesPrefixRe.exec(key);
+  const area = sizesPrefixRe.exec(key);
   if (area && area[0] !== S_SCRIPT_PRE) {
-    store.sizes[key] = deepSize(val);
+    scriptSizes[key] = deepSize(val);
   }
 }
 

+ 1 - 1
src/background/utils/values.js

@@ -76,7 +76,7 @@ export function clearValueOpener(tabId, frameId) {
  */
 export function addValueOpener(injectedScripts, tabId, frameId) {
   injectedScripts.forEach(script => {
-    const { id, [INJECT_VAL]: values } = script;
+    const { id, [VALUES]: values } = script;
     if (values) objectSet(openers, [id, tabId, frameId], values);
     else delete openers[id];
   });

+ 1 - 1
src/common/index.js

@@ -194,7 +194,7 @@ export function getScriptName(script) {
 
 /** @returns {VMInjection.RunAt} without "document-" */
 export function getScriptRunAt(script) {
-  return `${script.custom.runAt || script.meta.runAt || ''}`.match(RUN_AT_RE)?.[1] || 'end';
+  return `${script.custom[RUN_AT] || script.meta[RUN_AT] || ''}`.match(RUN_AT_RE)?.[1] || 'end';
 }
 
 /** URL that shows the name of the script and opens in devtools sources or in our editor */

+ 2 - 2
src/common/options-defaults.js

@@ -11,7 +11,7 @@ export default {
   badgeColorBlocked: '#888888',
   exportValues: true,
   exportNameTemplate: '[violentmonkey]_YYYY-MM-DD_HH.mm.ss',
-  expose: { // use percent-encoding for '.'
+  [EXPOSE]: { // use percent-encoding for '.'
     'greasyfork%2Eorg': true,
     'sleazyfork%2Eorg': false,
   },
@@ -29,7 +29,7 @@ export default {
   notifyUpdatesGlobal: false, // `true` ignores script.config.notifyUpdates
   version: null,
   /** @type {VMScriptInjectInto} */
-  defaultInjectInto: INJECT_AUTO,
+  defaultInjectInto: AUTO,
   ffInject: true,
   xhrInject: false,
   filters: {

+ 10 - 7
src/common/safe-globals-shared.js

@@ -13,15 +13,18 @@ const global = (function _() {
  * The document's value can change only in about:blank but we don't inject there. */
 const { document, window } = global;
 export const VIOLENTMONKEY = 'Violentmonkey';
-export const INJECT_AUTO = 'auto';
-export const INJECT_PAGE = 'page';
-export const INJECT_CONTENT = 'content';
-export const INJECT_CONTENT_FORCE = 'forceContent';
-export const INJECT_INTO = 'injectInto';
-export const INJECT_MORE = 'more';
-export const INJECT_VAL = 'val';
+export const AUTO = 'auto';
+export const CONTENT = 'content';
+export const EXPOSE = 'expose';
+export const FORCE_CONTENT = 'forceContent';
+export const IDS = 'ids';
 export const ID_BAD_REALM = -1;
 export const ID_INJECTING = 2;
+export const INJECT_INTO = 'injectInto';
+export const MORE = 'more';
+export const PAGE = 'page';
+export const RUN_AT = 'runAt';
+export const VALUES = 'values';
 export const kResponse = 'response';
 export const kResponseHeaders = 'responseHeaders';
 export const kResponseText = 'responseText';

+ 2 - 1
src/common/safe-globals.js

@@ -21,7 +21,8 @@ export const { apply: safeApply } = Reflect;
 export const hasOwnProperty = safeApply.call.bind(({}).hasOwnProperty);
 export const safeCall = Object.call.bind(Object.call);
 export const IS_FIREFOX = !chrome.app;
-export const ROUTE_SCRIPTS = `#scripts`;
+export const SCRIPTS = 'scripts';
+export const ROUTE_SCRIPTS = '#' + SCRIPTS;
 export const extensionRoot = chrome.runtime.getURL('/');
 export const extensionOrigin = extensionRoot.slice(0, -1);
 export const extensionManifest = chrome.runtime.getManifest();

+ 5 - 5
src/injected/content/bridge.js

@@ -28,7 +28,7 @@ export const addBackgroundHandlers = addHandlersImpl.bind({}, bgHandlers);
 const bridge = {
   __proto__: null,
   /** @type {VMBridgeContentIds} */
-  ids: createNullObj(),
+  [IDS]: createNullObj(),
   cache: createNullObj(),
   pathMaps: createNullObj(),
   // realm is provided when called directly via invokeHost
@@ -42,7 +42,7 @@ const bridge = {
     try {
       res = handle === true
         ? sendCmd(cmd, data)
-        : node::handle(data, realm || INJECT_PAGE);
+        : node::handle(data, realm || PAGE);
       if (isPromise(res)) {
         res = await res;
       }
@@ -70,8 +70,8 @@ browser.runtime.onMessage.addListener(async ({ cmd, data }, src) => {
 /**
  * @callback MessageFromGuestHandler
  * @param {Object} [data]
- * @param {INJECT_CONTENT | INJECT_PAGE} realm -
- *   INJECT_CONTENT when the message is from the content script context,
- *   INJECT_PAGE otherwise. Make sure to specify the same realm when messaging
+ * @param {CONTENT | PAGE} realm -
+ *   CONTENT when the message is from the content script context,
+ *   PAGE otherwise. Make sure to specify the same realm when messaging
  *   the results back otherwise it won't reach the target script.
  */

+ 1 - 1
src/injected/content/cmd-run.js

@@ -14,7 +14,7 @@ onScripts.push(() => {
 
 export function Run(id, realm) {
   safePush(runningIds, id);
-  bridge.ids[id] = realm || INJECT_PAGE;
+  bridge[IDS][id] = realm || PAGE;
   if (!pending) pending = sendSetBadge(2);
 }
 

+ 1 - 1
src/injected/content/gm-api-content.js

@@ -63,6 +63,6 @@ export async function sendSetPopup(isDelayed) {
       await setPopupThrottle;
       setPopupThrottle = null;
     }
-    sendCmd('SetPopup', safePickInto({ menus }, bridge, ['ids', INJECT_INTO]));
+    sendCmd('SetPopup', safePickInto({ menus }, bridge, [IDS, INJECT_INTO]));
   }
 }

+ 8 - 8
src/injected/content/index.js

@@ -9,9 +9,9 @@ import { sendCmd } from './util';
 import { isEmpty } from '../util';
 import { Run } from './cmd-run';
 
-const { ids } = bridge;
+const { [IDS]: ids } = bridge;
 
-// Make sure to call obj::method() in code that may run after INJECT_CONTENT userscripts
+// Make sure to call obj::method() in code that may run after CONTENT userscripts
 async function init() {
   const isXml = document instanceof XMLDocument;
   const xhrData = getXhrInjection();
@@ -20,7 +20,7 @@ async function init() {
      * in Chrome sender.url is ok, but location.href is wrong for text selection URLs #:~:text= */
     url: IS_FIREFOX && location.href,
     // XML document's appearance breaks when script elements are added
-    [INJECT_CONTENT_FORCE]: isXml,
+    [FORCE_CONTENT]: isXml,
     done: !!(xhrData || global.vmData),
   }, {
     retry: true,
@@ -32,9 +32,9 @@ async function init() {
       ? await getDataFF(dataPromise)
       : await dataPromise
   );
-  assign(ids, data.ids);
+  assign(ids, data[IDS]);
   bridge[INJECT_INTO] = data[INJECT_INTO];
-  if (data.expose && !isXml && injectPageSandbox(data)) {
+  if (data[EXPOSE] && !isXml && injectPageSandbox(data)) {
     addHandlers({ GetScriptVer: true });
     bridge.post('Expose');
   }
@@ -51,15 +51,15 @@ async function init() {
 
 addBackgroundHandlers({
   Command: data => bridge.post('Command', data, ids[data.id]),
-  Run: id => Run(id, INJECT_CONTENT),
+  Run: id => Run(id, CONTENT),
   UpdatedValues(data) {
     const dataPage = createNullObj();
     const dataContent = createNullObj();
     objectKeys(data)::forEach((id) => {
-      (ids[id] === INJECT_CONTENT ? dataContent : dataPage)[id] = data[id];
+      (ids[id] === CONTENT ? dataContent : dataPage)[id] = data[id];
     });
     if (!isEmpty(dataPage)) bridge.post('UpdatedValues', dataPage);
-    if (!isEmpty(dataContent)) bridge.post('UpdatedValues', dataContent, INJECT_CONTENT);
+    if (!isEmpty(dataContent)) bridge.post('UpdatedValues', dataContent, CONTENT);
   },
 });
 

+ 18 - 18
src/injected/content/inject.js

@@ -3,7 +3,7 @@ import { elemByTag, makeElem, nextTask, onElement, sendCmd } from './util';
 import { bindEvents, fireBridgeEvent, META_STR } from '../util';
 import { Run } from './cmd-run';
 
-const bridgeIds = bridge.ids;
+const bridgeIds = bridge[IDS];
 let tardyQueue;
 let bridgeInfo;
 let contLists;
@@ -116,7 +116,7 @@ export function injectPageSandbox({ [kSessionId]: sessionId }) {
  * @param {boolean} isXml
  */
 export async function injectScripts(data, isXml) {
-  const { errors, info, [INJECT_MORE]: more } = data;
+  const { errors, info, [MORE]: more } = data;
   const CACHE = 'cache';
   if (errors) {
     logging.warn(errors);
@@ -125,22 +125,22 @@ export async function injectScripts(data, isXml) {
     IS_FIREFOX = parseFloat(info.ua.browserVersion); // eslint-disable-line no-global-assign
   }
   bridgeInfo = createNullObj();
-  bridgeInfo[INJECT_PAGE] = info;
-  bridgeInfo[INJECT_CONTENT] = info;
+  bridgeInfo[PAGE] = info;
+  bridgeInfo[CONTENT] = info;
   assign(bridge[CACHE], data[CACHE]);
-  if (isXml || data[INJECT_CONTENT_FORCE]) {
+  if (isXml || data[FORCE_CONTENT]) {
     pageInjectable = false;
-  } else if (data[INJECT_PAGE] && pageInjectable == null) {
+  } else if (data[PAGE] && pageInjectable == null) {
     injectPageSandbox(data);
   }
   const toContent = data.scripts
-    .filter(scr => triageScript(scr) === INJECT_CONTENT)
+    .filter(scr => triageScript(scr) === CONTENT)
     .map(scr => [scr.id, scr.key.data]);
   const moreData = (more || toContent.length)
     && sendCmd('InjectionFeedback', {
-      [INJECT_CONTENT_FORCE]: !pageInjectable,
-      [INJECT_CONTENT]: toContent,
-      [INJECT_MORE]: more,
+      [FORCE_CONTENT]: !pageInjectable,
+      [CONTENT]: toContent,
+      [MORE]: more,
       url: IS_FIREFOX && location.href,
     });
   const getReadyState = describeProperty(Document[PROTO], 'readyState').get;
@@ -179,14 +179,14 @@ export async function injectScripts(data, isXml) {
 
 function triageScript(script) {
   let realm = script[INJECT_INTO];
-  realm = (realm === INJECT_AUTO && !pageInjectable) || realm === INJECT_CONTENT
-    ? INJECT_CONTENT
-    : pageInjectable && INJECT_PAGE;
+  realm = (realm === AUTO && !pageInjectable) || realm === CONTENT
+    ? CONTENT
+    : pageInjectable && PAGE;
   if (realm) {
-    const lists = realm === INJECT_CONTENT
+    const lists = realm === CONTENT
       ? contLists || (contLists = createNullObj())
       : pageLists || (pageLists = createNullObj());
-    const { gmi, [META_STR]: metaStr, pathMap, runAt } = script;
+    const { gmi, [META_STR]: metaStr, pathMap, [RUN_AT]: runAt } = script;
     const list = lists[runAt] || (lists[runAt] = []);
     safePush(list, script);
     setOwnProp(gmi, 'scriptMetaStr', metaStr[0]
@@ -266,7 +266,7 @@ function inject(item, iframeCb) {
 function injectAll(runAt) {
   let res;
   for (let inPage = 1; inPage >= 0; inPage--) {
-    const realm = inPage ? INJECT_PAGE : INJECT_CONTENT;
+    const realm = inPage ? PAGE : CONTENT;
     const lists = inPage ? pageLists : contLists;
     const items = lists?.[runAt];
     if (items) {
@@ -300,7 +300,7 @@ function setupContentInvoker() {
   const invokeContent = VMInitInjection(IS_FIREFOX)(bridge.onHandle);
   const postViaBridge = bridge.post;
   bridge.post = (cmd, params, realm, node) => {
-    const fn = realm === INJECT_CONTENT
+    const fn = realm === CONTENT
       ? invokeContent
       : postViaBridge;
     fn(cmd, params, undefined, node);
@@ -323,7 +323,7 @@ function tardyQueueCheck(scripts) {
 function tellBridgeToWriteVault(vaultId, wnd) {
   const { post } = bridge;
   if (post) { // may be absent if this page doesn't have scripts
-    post('WriteVault', vaultId, INJECT_PAGE, wnd);
+    post('WriteVault', vaultId, PAGE, wnd);
     return true;
   }
 }

+ 2 - 2
src/injected/util/index.js

@@ -24,7 +24,7 @@ export const bindEvents = (srcId, destId, bridge) => {
   window::on(srcId, e => {
     e::stopImmediatePropagation();
     if (process.env.DEBUG) {
-      console.info(`[bridge.${bridge.ids ? 'host' : 'guest.web'}] received`,
+      console.info(`[bridge.${bridge[IDS] ? 'host' : 'guest.web'}] received`,
         incomingNodeEvent ? e::getRelatedTarget() : e::getDetail());
     }
     if (!incomingNodeEvent) {
@@ -42,7 +42,7 @@ export const bindEvents = (srcId, destId, bridge) => {
   }, true);
   /** In Content bridge `pageNode` is `realm` which is wired in setupContentInvoker */
   bridge.post = (cmd, data, pageNode, contNode) => {
-    const node = bridge.ids ? contNode : pageNode;
+    const node = bridge[IDS] ? contNode : pageNode;
     // Constructing the event now so we don't send anything if it throws on invalid `node`
     const evtNode = node && new SafeMouseEvent(destId, { __proto__: null, relatedTarget: node });
     fireBridgeEvent(destId, { cmd, data, node: !!evtNode });

+ 2 - 2
src/injected/web/gm-values.js

@@ -14,7 +14,7 @@ const dataDecoders = {
 addHandlers({
   UpdatedValues(updates) {
     objectKeys(updates)::forEach(id => {
-      const oldData = store.values[id];
+      const oldData = store[VALUES][id];
       if (oldData) {
         const update = updates[id];
         const keyHooks = changeHooks[id];
@@ -26,7 +26,7 @@ addHandlers({
 });
 
 export function loadValues(id) {
-  return store.values[id];
+  return store[VALUES][id];
 }
 
 /**

+ 5 - 5
src/injected/web/index.js

@@ -18,7 +18,7 @@ export default function initialize(invokeHost) {
       bindEvents(e[0], e[1], bridge);
     }, { __proto__: null, once: true, capture: true });
     window::fire(new SafeCustomEvent(PAGE_MODE_HANDSHAKE));
-    bridge.mode = INJECT_PAGE;
+    bridge.mode = PAGE;
     addHandlers({
       /** @this {Node} contentWindow */
       WriteVault(id) {
@@ -26,9 +26,9 @@ export default function initialize(invokeHost) {
       },
     });
   } else {
-    bridge.mode = INJECT_CONTENT;
+    bridge.mode = CONTENT;
     bridge.post = (cmd, data, node) => {
-      invokeHost({ cmd, data, node }, INJECT_CONTENT);
+      invokeHost({ cmd, data, node }, CONTENT);
     };
     global.chrome = undefined;
     global.browser = undefined;
@@ -71,7 +71,7 @@ addHandlers({
     for (const script of items) {
       const { key } = script;
       toRun[key.data] = script;
-      store.values[script.id] = nullObjFrom(script[INJECT_VAL]);
+      store[VALUES][script.id] = nullObjFrom(script[VALUES]);
       if (!PAGE_MODE_HANDSHAKE) {
         const winKey = key.win;
         const data = window[winKey];
@@ -87,7 +87,7 @@ addHandlers({
       }
     }
     if (!PAGE_MODE_HANDSHAKE) toRunNow::forEach(onCodeSet);
-    else if (IS_FIREFOX) bridge.post('InjectList', items[0].runAt);
+    else if (IS_FIREFOX) bridge.post('InjectList', items[0][RUN_AT]);
   },
   Expose() {
     external[VIOLENTMONKEY] = {

+ 1 - 1
src/injected/web/store.js

@@ -1,4 +1,4 @@
 export default {
   commands: createNullObj(),
-  values: createNullObj(),
+  [VALUES]: createNullObj(),
 };

+ 2 - 2
src/options/views/edit/index.vue

@@ -92,7 +92,7 @@ import VmHelp from './help';
 
 const CUSTOM_PROPS = {
   name: '',
-  runAt: '',
+  [RUN_AT]: '',
   homepageURL: '',
   updateURL: '',
   downloadURL: '',
@@ -255,7 +255,7 @@ export default {
         ...CUSTOM_PROPS,
         ...objectPick(custom, Object.keys(CUSTOM_PROPS)),
         ...objectPick(custom, CUSTOM_LISTS, fromList),
-        runAt: custom.runAt || '',
+        [RUN_AT]: custom[RUN_AT] || '',
         noframes: noframes == null ? '' : +noframes, // it was boolean in old VM
       },
     };

+ 4 - 4
src/options/views/tab-settings/index.vue

@@ -178,9 +178,9 @@ const items = {
   },
   defaultInjectInto: {
     enum: {
-      [INJECT_AUTO]: '',
-      [INJECT_PAGE]: '',
-      [INJECT_CONTENT]: '',
+      [AUTO]: '',
+      [PAGE]: '',
+      [CONTENT]: '',
     },
   },
   showAdvanced: {
@@ -276,7 +276,7 @@ export default {
       this.revokers.push(hookSetting(name, val => { settings[name] = normalize(val, name); }));
       this.$watch(() => settings[name], getItemUpdater(name, normalize));
     });
-    this.expose = Object.keys(options.get('expose')).map(k => [k, decodeURIComponent(k)]);
+    this.expose = Object.keys(options.get(EXPOSE)).map(k => [k, decodeURIComponent(k)]);
     // Preload zip.js when user visits settings tab
     loadZip();
   },

+ 4 - 4
src/popup/index.js

@@ -28,7 +28,7 @@ Object.assign(handlers, {
     const idMapAllFrames = store.idMap;
     const idMapMain = idMapAllFrames[0] || (idMapAllFrames[0] = {});
     const idMapOld = idMapAllFrames[frameId] || (idMapAllFrames[frameId] = {});
-    const idMap = data.ids::mapEntry(null, (id, val) => val !== idMapOld[id] && id);
+    const idMap = data[IDS]::mapEntry(null, (id, val) => val !== idMapOld[id] && id);
     const ids = Object.keys(idMap).map(Number);
     if (ids.length) {
       Object.assign(idMapOld, idMap);
@@ -51,12 +51,12 @@ Object.assign(handlers, {
             if (i >= 0) frameScripts.splice(i, 1);
           }
         }
-        script.runs = state === INJECT_CONTENT || state === INJECT_PAGE;
+        script.runs = state === CONTENT || state === PAGE;
         script.pageUrl = url; // each frame has its own URL
         script.failed = badRealm || state === ID_INJECTING;
         script.syntax = state === ID_INJECTING;
         if (badRealm && !store.injectionFailure) {
-          store.injectionFailure = { fixable: data[INJECT_INTO] === INJECT_PAGE };
+          store.injectionFailure = { fixable: data[INJECT_INTO] === PAGE };
         }
       });
     }
@@ -76,7 +76,7 @@ if (!CSS.supports?.('list-style-type', 'disclosure-open')) {
 
 Promise.all([
   sendCmdDirectly('GetTabDomain'),
-  browser.tabs.executeScript({ code: '1', runAt: 'document_start' }).catch(() => []),
+  browser.tabs.executeScript({ code: '1', [RUN_AT]: 'document_start' }).catch(() => []),
 ])
 .then(async ([
   { tab, domain },

+ 1 - 1
src/popup/views/app.vue

@@ -419,7 +419,7 @@ export default {
     },
     async onInjectionFailureFix() {
       // TODO: promisify options.set, resolve on storage write, await it instead of makePause
-      options.set('defaultInjectInto', INJECT_AUTO);
+      options.set('defaultInjectInto', AUTO);
       await makePause(100);
       await browser.tabs.reload();
       window.close();