aboutsummaryrefslogtreecommitdiff
path: root/common
diff options
context:
space:
mode:
Diffstat (limited to 'common')
-rw-r--r--common/ajax.js70
-rw-r--r--common/broadcast.js6
-rw-r--r--common/connection_types.js53
-rw-r--r--common/indexeddb.js2
-rw-r--r--common/lock.js94
-rw-r--r--common/message_server.js2
-rw-r--r--common/misc.js56
-rw-r--r--common/observables.js61
-rw-r--r--common/once.js74
-rw-r--r--common/sanitize_JSON.js431
-rw-r--r--common/settings_query.js66
-rw-r--r--common/storage_client.js208
-rw-r--r--common/storage_light.js162
-rw-r--r--common/storage_raw.js82
-rw-r--r--common/stored_types.js80
15 files changed, 4 insertions, 1443 deletions
diff --git a/common/ajax.js b/common/ajax.js
deleted file mode 100644
index 462e511..0000000
--- a/common/ajax.js
+++ /dev/null
@@ -1,70 +0,0 @@
-/**
- * This file is part of Haketilo.
- *
- * Function: Wrapping XMLHttpRequest into a Promise.
- *
- * Copyright (C) 2021 Wojtek Kosior
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * As additional permission under GNU GPL version 3 section 7, you
- * may distribute forms of that code without the copy of the GNU
- * GPL normally required by section 4, provided you include this
- * license notice and, in case of non-source distribution, a URL
- * through which recipients can access the Corresponding Source.
- * If you modify file(s) with this exception, you may extend this
- * exception to your version of the file(s), but you are not
- * obligated to do so. If you do not wish to do so, delete this
- * exception statement from your version.
- *
- * As a special exception to the GPL, any HTML file which merely
- * makes function calls to this code, and for that purpose
- * includes it by reference shall be deemed a separate work for
- * copyright law purposes. If you modify this code, you may extend
- * this exception to your version of the code, but you are not
- * obligated to do so. If you do not wish to do so, delete this
- * exception statement from your version.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * I, Wojtek Kosior, thereby promise not to sue for violation of this file's
- * license. Although I request that you do not make use of this code in a
- * proprietary program, I am not going to enforce this in court.
- */
-
-function ajax_callback()
-{
- if (this.readyState == 4)
- this.resolve_callback(this);
-}
-
-function initiate_ajax_request(resolve, reject, method, url)
-{
- const xhttp = new XMLHttpRequest();
- xhttp.resolve_callback = resolve;
- xhttp.onreadystatechange = ajax_callback;
- xhttp.open(method, url, true);
- try {
- xhttp.send();
- } catch(e) {
- console.log(e);
- setTimeout(reject, 0);
- }
-}
-
-function make_ajax_request(method, url)
-{
- return new Promise((resolve, reject) =>
- initiate_ajax_request(resolve, reject, method, url));
-}
-
-#EXPORT make_ajax_request
diff --git a/common/broadcast.js b/common/broadcast.js
index ce4ac08..4dcac2b 100644
--- a/common/broadcast.js
+++ b/common/broadcast.js
@@ -41,14 +41,12 @@
* proprietary program, I am not going to enforce this in court.
*/
-#IMPORT common/connection_types.js AS CONNECTION_TYPE
-
#FROM common/message_server.js IMPORT connect_to_background
function sender_connection()
{
return {
- port: connect_to_background(CONNECTION_TYPE.BROADCAST_SEND)
+ port: connect_to_background("broadcast_send")
};
}
#EXPORT sender_connection
@@ -94,7 +92,7 @@ function flush(sender_conn)
function listener_connection(cb)
{
const conn = {
- port: connect_to_background(CONNECTION_TYPE.BROADCAST_LISTEN)
+ port: connect_to_background("broadcast_listen")
};
conn.port.onMessage.addListener(cb);
diff --git a/common/connection_types.js b/common/connection_types.js
deleted file mode 100644
index 6ed2e4a..0000000
--- a/common/connection_types.js
+++ /dev/null
@@ -1,53 +0,0 @@
-/**
- * This file is part of Haketilo.
- *
- * Function: Define an "enum" of message connection types.
- *
- * Copyright (C) 2021 Wojtek Kosior
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * As additional permission under GNU GPL version 3 section 7, you
- * may distribute forms of that code without the copy of the GNU
- * GPL normally required by section 4, provided you include this
- * license notice and, in case of non-source distribution, a URL
- * through which recipients can access the Corresponding Source.
- * If you modify file(s) with this exception, you may extend this
- * exception to your version of the file(s), but you are not
- * obligated to do so. If you do not wish to do so, delete this
- * exception statement from your version.
- *
- * As a special exception to the GPL, any HTML file which merely
- * makes function calls to this code, and for that purpose
- * includes it by reference shall be deemed a separate work for
- * copyright law purposes. If you modify this code, you may extend
- * this exception to your version of the code, but you are not
- * obligated to do so. If you do not wish to do so, delete this
- * exception statement from your version.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * I, Wojtek Kosior, thereby promise not to sue for violation of this file's
- * license. Although I request that you do not make use of this code in a
- * proprietary program, I am not going to enforce this in court.
- */
-
-/*
- * Those need to be strings so they can be used as 'name' parameter
- * to browser.runtime.connect()
- */
-
-#EXPORT "0" AS REMOTE_STORAGE
-#EXPORT "1" AS PAGE_ACTIONS
-#EXPORT "2" AS ACTIVITY_INFO
-#EXPORT "3" AS BROADCAST_SEND
-#EXPORT "4" AS BROADCAST_LISTEN
diff --git a/common/indexeddb.js b/common/indexeddb.js
index 1b8e574..271dfce 100644
--- a/common/indexeddb.js
+++ b/common/indexeddb.js
@@ -48,7 +48,7 @@ let initial_data = (
#IF UNIT_TEST
{}
#ELSE
-#INCLUDE_VERBATIM default_settings.json
+#INCLUDE default_settings.json
#ENDIF
);
diff --git a/common/lock.js b/common/lock.js
deleted file mode 100644
index f577481..0000000
--- a/common/lock.js
+++ /dev/null
@@ -1,94 +0,0 @@
-/**
- * This file is part of Haketilo.
- *
- * Function: Implement a lock (aka binary semaphore aka mutex).
- *
- * Copyright (C) 2021 Wojtek Kosior
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * As additional permission under GNU GPL version 3 section 7, you
- * may distribute forms of that code without the copy of the GNU
- * GPL normally required by section 4, provided you include this
- * license notice and, in case of non-source distribution, a URL
- * through which recipients can access the Corresponding Source.
- * If you modify file(s) with this exception, you may extend this
- * exception to your version of the file(s), but you are not
- * obligated to do so. If you do not wish to do so, delete this
- * exception statement from your version.
- *
- * As a special exception to the GPL, any HTML file which merely
- * makes function calls to this code, and for that purpose
- * includes it by reference shall be deemed a separate work for
- * copyright law purposes. If you modify this code, you may extend
- * this exception to your version of the code, but you are not
- * obligated to do so. If you do not wish to do so, delete this
- * exception statement from your version.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * I, Wojtek Kosior, thereby promise not to sue for violation of this file's
- * license. Although I request that you do not make use of this code in a
- * proprietary program, I am not going to enforce this in court.
- */
-
-/*
- * Javascript runs single-threaded, with an event loop. Because of that,
- * explicit synchronization is often not needed. An exception is when we use
- * an API function that must wait. Ajax is an example. Callback passed to ajax
- * call doesn't get called immediately, but after some time. In the meantime
- * some other piece of code might get to execute and modify some variables.
- * Access to WebExtension local storage is another situation where this problem
- * can occur.
- *
- * This is a solution. A lock object, that can be used to delay execution of
- * some code until other code finishes its critical work. Locking is wrapped
- * in a promise.
- */
-
-#EXPORT () => ({free: true, queue: []}) AS make_lock
-
-function _lock(lock, cb) {
- if (lock.free) {
- lock.free = false;
- setTimeout(cb);
- } else {
- lock.queue.push(cb);
- }
-}
-
-#EXPORT lock => new Promise(resolve => _lock(lock, resolve)) AS lock
-
-function try_lock(lock)
-{
- if (lock.free) {
- lock.free = false;
- return true;
- }
-
- return false;
-}
-#EXPORT try_lock
-
-function unlock(lock) {
- if (lock.free)
- throw new Exception("Attempting to release a free lock");
-
- if (lock.queue.length === 0) {
- lock.free = true;
- } else {
- let cb = lock.queue[0];
- lock.queue.splice(0, 1);
- setTimeout(cb);
- }
-}
-#EXPORT unlock
diff --git a/common/message_server.js b/common/message_server.js
index 80cefd5..a67b6ee 100644
--- a/common/message_server.js
+++ b/common/message_server.js
@@ -97,7 +97,7 @@ function connect_to_background(magic)
return browser.runtime.connect({name: magic});
if (!(magic in listeners))
- throw `no listener for '${magic}'`
+ throw `no listener for '${magic}'`;
const ports = [new Port(magic), new Port(magic)];
ports[0].other = ports[1];
diff --git a/common/misc.js b/common/misc.js
index f8e0812..c06052a 100644
--- a/common/misc.js
+++ b/common/misc.js
@@ -42,9 +42,6 @@
* proprietary program, I am not going to enforce this in court.
*/
-#FROM common/browser.js IMPORT browser
-#FROM common/stored_types.js IMPORT TYPE_NAME, TYPE_PREFIX
-
/* uint8_to_hex is a separate function used in cryptographic functions. */
const uint8_to_hex =
array => [...array].map(b => ("0" + b.toString(16)).slice(-2)).join("");
@@ -83,15 +80,6 @@ const csp_header_regex =
*/
#EXPORT (prefix, name) => `${name} (${TYPE_NAME[prefix]})` AS nice_name
-/* Open settings tab with given item's editing already on. */
-function open_in_settings(prefix, name)
-{
- name = encodeURIComponent(name);
- const url = browser.runtime.getURL("html/options.html#" + prefix + name);
- window.open(url, "_blank");
-}
-#EXPORT open_in_settings
-
/*
* Check if url corresponds to a browser's special page (or a directory index in
* case of `file://' protocol).
@@ -102,47 +90,3 @@ const priv_reg = /^moz-extension:\/\/|^about:|^file:\/\/[^?#]*\/([?#]|$)/;
const priv_reg = /^chrome(-extension)?:\/\/|^about:|^file:\/\/[^?#]*\/([?#]|$)/;
#ENDIF
#EXPORT url => priv_reg.test(url) AS is_privileged_url
-
-/* Parse a CSP header */
-function parse_csp(csp) {
- let directive, directive_array;
- let directives = {};
- for (directive of csp.split(';')) {
- directive = directive.trim();
- if (directive === '')
- continue;
-
- directive_array = directive.split(/\s+/);
- directive = directive_array.shift();
- /* The "true" case should never occur; nevertheless... */
- directives[directive] = directive in directives ?
- directives[directive].concat(directive_array) :
- directive_array;
- }
- return directives;
-}
-
-/* Regexes and objects to use as/in schemas for parse_json_with_schema(). */
-const nonempty_string_matcher = /.+/;
-
-const matchers = {
- sha256: /^[0-9a-f]{64}$/,
- nonempty_string: nonempty_string_matcher,
- component: [
- new RegExp(`^[${TYPE_PREFIX.SCRIPT}${TYPE_PREFIX.BAG}]$`),
- nonempty_string_matcher
- ]
-};
-#EXPORT matchers
-
-/*
- * Facilitates checking if there aren't any keys in object. This does *NOT*
- * account for pathological cases like redefined properties of Object prototype.
- */
-function is_object_empty(object)
-{
- for (const key in object)
- return false;
- return true;
-}
-#EXPORT is_object_empty
diff --git a/common/observables.js b/common/observables.js
deleted file mode 100644
index e73b9f7..0000000
--- a/common/observables.js
+++ /dev/null
@@ -1,61 +0,0 @@
-/**
- * This file is part of Haketilo.
- *
- * Function: Facilitate listening to (internal, self-generated) events.
- *
- * Copyright (C) 2021 Wojtek Kosior
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * As additional permission under GNU GPL version 3 section 7, you
- * may distribute forms of that code without the copy of the GNU
- * GPL normally required by section 4, provided you include this
- * license notice and, in case of non-source distribution, a URL
- * through which recipients can access the Corresponding Source.
- * If you modify file(s) with this exception, you may extend this
- * exception to your version of the file(s), but you are not
- * obligated to do so. If you do not wish to do so, delete this
- * exception statement from your version.
- *
- * As a special exception to the GPL, any HTML file which merely
- * makes function calls to this code, and for that purpose
- * includes it by reference shall be deemed a separate work for
- * copyright law purposes. If you modify this code, you may extend
- * this exception to your version of the code, but you are not
- * obligated to do so. If you do not wish to do so, delete this
- * exception statement from your version.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * I, Wojtek Kosior, thereby promise not to sue for violation of this file's
- * license. Although I request that you do not make use of this code in a
- * proprietary program, I am not going to enforce this in court.
- */
-
-#EXPORT (value=undefined) => ({value, listeners: new Set()}) AS make
-#EXPORT (observable, cb) => observable.listeners.add(cb) AS subscribe
-#EXPORT (observable, cb) => observable.listeners.delete(cb) AS unsubscribe
-
-const silent_set = (observable, value) => observable.value = value;
-#EXPORT silent_set
-
-const broadcast = (observable, ...values) =>
- observable.listeners.forEach(cb => cb(...values));
-#EXPORT broadcast
-
-function set(observable, value)
-{
- const old_value = observable.value;
- silent_set(observable, value);
- broadcast(observable, value, old_value);
-}
-#EXPORT set
diff --git a/common/once.js b/common/once.js
deleted file mode 100644
index 01216bd..0000000
--- a/common/once.js
+++ /dev/null
@@ -1,74 +0,0 @@
-/**
- * This file is part of Haketilo.
- *
- * Function: Wrap APIs that depend on some asynchronous initialization into
- * promises.
- *
- * Copyright (C) 2021 Wojtek Kosior
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * As additional permission under GNU GPL version 3 section 7, you
- * may distribute forms of that code without the copy of the GNU
- * GPL normally required by section 4, provided you include this
- * license notice and, in case of non-source distribution, a URL
- * through which recipients can access the Corresponding Source.
- * If you modify file(s) with this exception, you may extend this
- * exception to your version of the file(s), but you are not
- * obligated to do so. If you do not wish to do so, delete this
- * exception statement from your version.
- *
- * As a special exception to the GPL, any HTML file which merely
- * makes function calls to this code, and for that purpose
- * includes it by reference shall be deemed a separate work for
- * copyright law purposes. If you modify this code, you may extend
- * this exception to your version of the code, but you are not
- * obligated to do so. If you do not wish to do so, delete this
- * exception statement from your version.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * I, Wojtek Kosior, thereby promise not to sue for violation of this file's
- * license. Although I request that you do not make use of this code in a
- * proprietary program, I am not going to enforce this in court.
- */
-
-/*
- * This module provides an easy way to wrap an async function into a promise
- * so that it only gets executed once.
- */
-
-async function assign_result(state, result_producer)
-{
- state.result = await result_producer();
- state.ready = true;
- for (let cb of state.waiting)
- setTimeout(cb, 0, state.result);
- state.waiting = undefined;
-}
-
-async function get_result(state)
-{
- if (state.ready)
- return state.result;
-
- return new Promise((resolve, reject) => state.waiting.push(resolve));
-}
-
-function make_once(result_producer)
-{
- let state = {waiting : [], ready : false, result : undefined};
- assign_result(state, result_producer);
- return () => get_result(state);
-}
-
-#EXPORT make_once
diff --git a/common/sanitize_JSON.js b/common/sanitize_JSON.js
deleted file mode 100644
index e03e396..0000000
--- a/common/sanitize_JSON.js
+++ /dev/null
@@ -1,431 +0,0 @@
-/**
- * This file is part of Haketilo.
- *
- * Function: Powerful, full-blown format enforcer for externally-obtained JSON.
- *
- * Copyright (C) 2021 Wojtek Kosior
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * As additional permission under GNU GPL version 3 section 7, you
- * may distribute forms of that code without the copy of the GNU
- * GPL normally required by section 4, provided you include this
- * license notice and, in case of non-source distribution, a URL
- * through which recipients can access the Corresponding Source.
- * If you modify file(s) with this exception, you may extend this
- * exception to your version of the file(s), but you are not
- * obligated to do so. If you do not wish to do so, delete this
- * exception statement from your version.
- *
- * As a special exception to the GPL, any HTML file which merely
- * makes function calls to this code, and for that purpose
- * includes it by reference shall be deemed a separate work for
- * copyright law purposes. If you modify this code, you may extend
- * this exception to your version of the code, but you are not
- * obligated to do so. If you do not wish to do so, delete this
- * exception statement from your version.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * I, Wojtek Kosior, thereby promise not to sue for violation of this file's
- * license. Although I request that you do not make use of this code in a
- * proprietary program, I am not going to enforce this in court.
- */
-
-var error_path;
-var invalid_schema;
-
-function parse_json_with_schema(schema, json_string)
-{
- error_path = [];
- invalid_schema = false;
-
- try {
- return sanitize_unknown(schema, JSON.parse(json_string));
- } catch (e) {
- throw `Invalid JSON${invalid_schema ? " schema" : ""}: ${e}.`;
- } finally {
- /* Allow garbage collection. */
- error_path = undefined;
- }
-}
-
-function error_message(cause)
-{
- return `object${error_path.join("")} ${cause}`;
-}
-
-function sanitize_unknown(schema, item)
-{
- let error_msg = undefined;
- let schema_options = [];
- let has_default = false;
- let _default = undefined;
-
- if (!Array.isArray(schema) || schema[1] === "matchentry" ||
- schema.length < 2 || !["ordefault", "or"].includes(schema[1]))
- return sanitize_unknown_no_alternatives(schema, item);
-
- if ((schema.length & 1) !== 1) {
- invalid_schema = true;
- throw error_message("was not understood");
- }
-
- for (let i = 0; i < schema.length; i++) {
- if ((i & 1) !== 1) {
- schema_options.push(schema[i]);
- continue;
- }
-
- if (schema[i] === "or")
- continue;
- if (schema[i] === "ordefault" && schema.length === i + 2) {
- has_default = true;
- _default = schema[i + 1];
- break;
- }
-
- invalid_schema = true;
- throw error_message("was not understood");
- }
-
- for (const schema_option of schema_options) {
- try {
- return sanitize_unknown_no_alternatives(schema_option, item);
- } catch (e) {
- if (invalid_schema)
- throw e;
-
- if (has_default)
- continue;
-
- if (error_msg === undefined)
- error_msg = e;
- else
- error_msg = `${error_msg}, or ${e}`;
- }
- }
-
- if (has_default)
- return _default;
-
- throw error_msg;
-}
-
-function sanitize_unknown_no_alternatives(schema, item)
-{
- for (const [schema_check, item_check, sanitizer, type_name] of checks) {
- if (schema_check(schema)) {
- if (item_check(item))
- return sanitizer(schema, item);
- throw error_message(`should be ${type_name} but is not`);
- }
- }
-
- invalid_schema = true;
- throw error_message("was not understood");
-}
-
-function key_error_path_segment(key)
-{
- return /^[a-zA-Z_][a-zA-Z_0-9]*$/.exec(key) ?
- `.${key}` : `[${JSON.stringify(key)}]`;
-}
-
-/*
- * Generic object - one that can contain arbitrary keys (in addition to ones
- * specified explicitly in the schema).
- */
-function sanitize_genobj(schema, object)
-{
- let max_matched_entries = Infinity;
- let min_matched_entries = 0;
- let matched_entries = 0;
- const entry_schemas = [];
- schema = [...schema];
-
- if (schema[2] === "minentries") {
- if (schema.length < 4) {
- invalid_schema = true;
- throw error_message("was not understood");
- }
-
- min_matched_entries = schema[3];
- schema.splice(2, 2);
- }
-
- if (min_matched_entries < 0) {
- invalid_schema = true;
- throw error_message('specifies invalid "minentries" (should be a non-negative number)');
- }
-
- if (schema[2] === "maxentries") {
- if (schema.length < 4) {
- invalid_schema = true;
- throw error_message("was not understood");
- }
-
- max_matched_entries = schema[3];
- schema.splice(2, 2);
- }
-
- if (max_matched_entries < 0) {
- invalid_schema = true;
- throw error_message('specifies invalid "maxentries" (should be a non-negative number)');
- }
-
- while (schema.length > 2) {
- let regex = /.+/;
-
- if (schema.length > 3) {
- regex = schema[2];
- schema.splice(2, 1);
- }
-
- if (typeof regex === "string")
- regex = new RegExp(regex);
-
- entry_schemas.push([regex, schema[2]]);
- schema.splice(2, 1);
- }
-
- const result = sanitize_object(schema[0], object);
-
- for (const [key, entry] of Object.entries(object)) {
- if (result.hasOwnProperty(key))
- continue;
-
- matched_entries += 1;
- if (matched_entries > max_matched_entries)
- throw error_message(`has more than ${max_matched_entries} matched entr${max_matched_entries === 1 ? "y" : "ies"}`);
-
- error_path.push(key_error_path_segment(key));
-
- let match = false;
- for (const [key_regex, entry_schema] of entry_schemas) {
- if (!key_regex.exec(key))
- continue;
-
- match = true;
-
- sanitize_object_entry(result, key, entry_schema, object);
- break;
- }
-
- if (!match) {
- const regex_list = entry_schemas.map(i => i[0]).join(", ");
- throw error_message(`does not match any of key regexes: [${regex_list}]`);
- }
-
- error_path.pop();
- }
-
- if (matched_entries < min_matched_entries)
- throw error_message(`has less than ${min_matched_entries} matched entr${min_matched_entries === 1 ? "y" : "ies"}`);
-
- return result;
-}
-
-function sanitize_array(schema, array)
-{
- let min_length = 0;
- let max_length = Infinity;
- let repeat_length = 1;
- let i = 0;
- const result = [];
-
- schema = [...schema];
- if (schema[schema.length - 2] === "maxlen") {
- max_length = schema[schema.length - 1];
- schema.splice(schema.length - 2);
- }
-
- if (schema[schema.length - 2] === "minlen") {
- min_length = schema[schema.length - 1];
- schema.splice(schema.length - 2);
- }
-
- if (["repeat", "repeatfull"].includes(schema[schema.length - 2]))
- repeat_length = schema.pop();
- if (repeat_length < 1) {
- invalid_schema = true;
- throw error_message('specifies invalid "${schema[schema.length - 2]}" (should be number greater than 1)');
- }
- if (["repeat", "repeatfull"].includes(schema[schema.length - 1])) {
- var repeat_directive = schema.pop();
- var repeat = schema.splice(schema.length - repeat_length);
- } else if (schema.length !== array.length) {
- throw error_message(`does not have exactly ${schema.length} items`);
- }
-
- if (repeat_directive === "repeatfull" &&
- (array.length - schema.length) % repeat_length !== 0)
- throw error_message(`does not contain a full number of item group repetitions`);
-
- if (array.length < min_length)
- throw error_message(`has less than ${min_length} element${min_length === 1 ? "" : "s"}`);
-
- if (array.length > max_length)
- throw error_message(`has more than ${max_length} element${max_length === 1 ? "" : "s"}`);
-
- for (const item of array) {
- if (i >= schema.length) {
- i = 0;
- schema = repeat;
- }
-
- error_path.push(`[${i}]`);
- const sanitized = sanitize_unknown(schema[i], item);
- if (sanitized !== discard)
- result.push(sanitized);
- error_path.pop();
-
- i++;
- }
-
- return result;
-}
-
-function sanitize_regex(schema, string)
-{
- if (schema.test(string))
- return string;
-
- throw error_message(`does not match regex ${schema}`);
-}
-
-const string_spec_regex = /^string(:(.*))?$/;
-
-function sanitize_string(schema, string)
-{
- const regex = string_spec_regex.exec(schema)[2];
-
- if (regex === undefined)
- return string;
-
- return sanitize_regex(new RegExp(regex), string);
-}
-
-function sanitize_object(schema, object)
-{
- const result = {};
-
- for (let [key, entry_schema] of Object.entries(schema)) {
- error_path.push(key_error_path_segment(key));
- sanitize_object_entry(result, key, entry_schema, object);
- error_path.pop();
- }
-
- return result;
-}
-
-function sanitize_object_entry(result, key, entry_schema, object)
-{
- let optional = false;
- let has_default = false;
- let _default = undefined;
-
- if (Array.isArray(entry_schema) && entry_schema.length > 1) {
- if (entry_schema[0] === "optional") {
- optional = true;
- entry_schema = [...entry_schema].splice(1);
-
- const idx_def = entry_schema.length - (entry_schema.length & 1) - 1;
- if (entry_schema[idx_def] === "default") {
- has_default = true;
- _default = entry_schema[idx_def + 1];
- entry_schema.splice(idx_def);
- } else if ((entry_schema.length & 1) !== 1) {
- invalid_schema = true;
- throw error_message("was not understood");
- }
-
- if (entry_schema.length < 2)
- entry_schema = entry_schema[0];
- }
- }
-
- let unsanitized_value = object[key];
- if (unsanitized_value === undefined) {
- if (!optional)
- throw error_message("is missing");
-
- if (has_default)
- result[key] = _default;
-
- return;
- }
-
- const sanitized = sanitize_unknown(entry_schema, unsanitized_value);
- if (sanitized !== discard)
- result[key] = sanitized;
-}
-
-function take_literal(schema, item)
-{
- return item;
-}
-
-/*
- * This function is used like a symbol. Other parts of code do sth like
- * `item === discard` to check if item was returned by this function.
- */
-function discard(schema, item)
-{
- return discard;
-}
-
-/*
- * The following are some helper functions to categorize various
- * schema item specifiers (used in the array below).
- */
-
-function is_genobj_spec(item)
-{
- return Array.isArray(item) && item[1] === "matchentry";
-}
-
-function is_regex(item)
-{
- return typeof item === "object" && typeof item.test === "function";
-}
-
-function is_string_spec(item)
-{
- return typeof item === "string" && string_spec_regex.test(item);
-}
-
-function is_object(item)
-{
- return typeof item === "object";
-}
-
-function eq(what)
-{
- return i => i === what;
-}
-
-/* Array and null checks must go before object check. */
-const checks = [
- [is_genobj_spec, is_object, sanitize_genobj, "an object"],
- [Array.isArray, Array.isArray, sanitize_array, "an array"],
- [eq(null), i => i === null, take_literal, "null"],
- [is_regex, i => typeof i === "string", sanitize_regex, "a string"],
- [is_string_spec, i => typeof i === "string", sanitize_string, "a string"],
- [is_object, is_object, sanitize_object, "an object"],
- [eq("number"), i => typeof i === "number", take_literal, "a number"],
- [eq("boolean"), i => typeof i === "boolean", take_literal, "a boolean"],
- [eq("anything"), i => true, take_literal, "dummy"],
- [eq("discard"), i => true, discard, "dummy"]
-];
-
-#EXPORT parse_json_with_schema
diff --git a/common/settings_query.js b/common/settings_query.js
deleted file mode 100644
index b8c3a25..0000000
--- a/common/settings_query.js
+++ /dev/null
@@ -1,66 +0,0 @@
-/**
- * This file is part of Haketilo.
- *
- * Function: Querying page settings.
- *
- * Copyright (C) 2021 Wojtek Kosior
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * As additional permission under GNU GPL version 3 section 7, you
- * may distribute forms of that code without the copy of the GNU
- * GPL normally required by section 4, provided you include this
- * license notice and, in case of non-source distribution, a URL
- * through which recipients can access the Corresponding Source.
- * If you modify file(s) with this exception, you may extend this
- * exception to your version of the file(s), but you are not
- * obligated to do so. If you do not wish to do so, delete this
- * exception statement from your version.
- *
- * As a special exception to the GPL, any HTML file which merely
- * makes function calls to this code, and for that purpose
- * includes it by reference shall be deemed a separate work for
- * copyright law purposes. If you modify this code, you may extend
- * this exception to your version of the code, but you are not
- * obligated to do so. If you do not wish to do so, delete this
- * exception statement from your version.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * I, Wojtek Kosior, thereby promise not to sue for violation of this file's
- * license. Although I request that you do not make use of this code in a
- * proprietary program, I am not going to enforce this in court.
- */
-
-
-#FROM common/stored_types.js IMPORT TYPE_PREFIX
-#FROM common/patterns.js IMPORT each_url_pattern
-
-function query(storage, url, multiple)
-{
- const matched = [];
- const cb = p => check_pattern(storage, p, multiple, matched);
- for (const pattern of each_url_pattern(url)) {
- const result = [pattern, storage.get(TYPE_PREFIX.PAGE, pattern)];
- if (result[1] === undefined)
- continue;
-
- if (!multiple)
- return result;
- matched.push(result);
- }
-
- return multiple ? matched : [undefined, undefined];
-}
-
-#EXPORT (storage, url) => query(storage, url, false) AS query_best
-#EXPORT (storage, url) => query(storage, url, true) AS query_all
diff --git a/common/storage_client.js b/common/storage_client.js
deleted file mode 100644
index fe8d6e6..0000000
--- a/common/storage_client.js
+++ /dev/null
@@ -1,208 +0,0 @@
-/**
- * This file is part of Haketilo.
- *
- * Function: Storage through messages (client side).
- *
- * Copyright (C) 2021 Wojtek Kosior
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * As additional permission under GNU GPL version 3 section 7, you
- * may distribute forms of that code without the copy of the GNU
- * GPL normally required by section 4, provided you include this
- * license notice and, in case of non-source distribution, a URL
- * through which recipients can access the Corresponding Source.
- * If you modify file(s) with this exception, you may extend this
- * exception to your version of the file(s), but you are not
- * obligated to do so. If you do not wish to do so, delete this
- * exception statement from your version.
- *
- * As a special exception to the GPL, any HTML file which merely
- * makes function calls to this code, and for that purpose
- * includes it by reference shall be deemed a separate work for
- * copyright law purposes. If you modify this code, you may extend
- * this exception to your version of the code, but you are not
- * obligated to do so. If you do not wish to do so, delete this
- * exception statement from your version.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * I, Wojtek Kosior, thereby promise not to sue for violation of this file's
- * license. Although I request that you do not make use of this code in a
- * proprietary program, I am not going to enforce this in court.
- */
-
-#IMPORT common/connection_types.js AS CONNECTION_TYPE
-
-#FROM common/browser.js IMPORT browser
-#FROM common/stored_types.js IMPORT list_prefixes
-#FROM common/once.js IMPORT make_once
-
-var call_id = 0;
-var port;
-var calls_waiting = new Map();
-
-function set_call_callback(resolve, reject, func, args)
-{
- port.postMessage([call_id, func, args]);
- calls_waiting.set(call_id++, [resolve, reject]);
-}
-
-async function remote_call(func, args)
-{
- return new Promise((resolve, reject) =>
- set_call_callback(resolve, reject, func, args));
-}
-
-function handle_message(message)
-{
- let callbacks = calls_waiting.get(message.call_id);
- if (callbacks === undefined) {
- handle_change(message);
- return;
- }
-
- let [resolve, reject] = callbacks;
- calls_waiting.delete(message.call_id);
- if (message.error !== undefined)
- setTimeout(reject, 0, message.error);
- else
- setTimeout(resolve, 0, message.result);
-}
-
-const list_by_prefix = {};
-
-for (const prefix of list_prefixes)
- list_by_prefix[prefix] = {prefix, listeners : new Set()};
-
-var resolve_init;
-
-function handle_first_message(message)
-{
- for (let prefix of Object.keys(message))
- list_by_prefix[prefix].map = new Map(message[prefix]);
-
- port.onMessage.removeListener(handle_first_message);
- port.onMessage.addListener(handle_message);
-
- resolve_init();
-}
-
-function handle_change(change)
-{
- let list = list_by_prefix[change.prefix];
-
- if (change.new_val === undefined)
- list.map.delete(change.item);
- else
- list.map.set(change.item, change.new_val);
-
- for (let listener_callback of list.listeners)
- listener_callback(change);
-}
-
-var exports = {};
-
-function start_connection(resolve)
-{
- resolve_init = resolve;
- port = browser.runtime.connect({name : CONNECTION_TYPE.REMOTE_STORAGE});
- port.onMessage.addListener(handle_first_message);
-}
-
-async function init() {
- await new Promise((resolve, reject) => start_connection(resolve));
- return exports;
-}
-
-for (let call_name of ["set", "remove", "replace", "clear"])
- exports [call_name] = (...args) => remote_call(call_name, args);
-
-// TODO: Much of the code below is copy-pasted from /background/storage.mjs.
-// This should later be refactored into a separate module
-// to avoid duplication.
-
-/*
- * Facilitate listening to changes
- */
-
-exports.add_change_listener = function (cb, prefixes=list_prefixes)
-{
- if (typeof(prefixes) === "string")
- prefixes = [prefixes];
-
- for (let prefix of prefixes)
- list_by_prefix[prefix].listeners.add(cb);
-}
-
-exports.remove_change_listener = function (cb, prefixes=list_prefixes)
-{
- if (typeof(prefixes) === "string")
- prefixes = [prefixes];
-
- for (let prefix of prefixes)
- list_by_prefix[prefix].listeners.delete(cb);
-}
-
-/* Prepare some hepler functions to get elements of a list */
-
-function list_items_it(list, with_values=false)
-{
- return with_values ? list.map.entries() : list.map.keys();
-}
-
-function list_entries_it(list)
-{
- return list_items_it(list, true);
-}
-
-function list_items(list, with_values=false)
-{
- let array = [];
-
- for (let item of list_items_it(list, with_values))
- array.push(item);
-
- return array;
-}
-
-function list_entries(list)
-{
- return list_items(list, true);
-}
-
-exports.get = function (prefix, item)
-{
- return list_by_prefix[prefix].map.get(item);
-}
-
-exports.get_all_names = function (prefix)
-{
- return list_items(list_by_prefix[prefix]);
-}
-
-exports.get_all_names_it = function (prefix)
-{
- return list_items_it(list_by_prefix[prefix]);
-}
-
-exports.get_all = function (prefix)
-{
- return list_entries(list_by_prefix[prefix]);
-}
-
-exports.get_all_it = function (prefix)
-{
- return list_entries_it(list_by_prefix[prefix]);
-}
-
-#EXPORT make_once(init) AS get_remote_storage
diff --git a/common/storage_light.js b/common/storage_light.js
deleted file mode 100644
index 35dfae2..0000000
--- a/common/storage_light.js
+++ /dev/null
@@ -1,162 +0,0 @@
-/**
- * This file is part of Haketilo.
- *
- * Function: Storage manager, lighter than the previous one.
- *
- * Copyright (C) 2021 Wojtek Kosior
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * As additional permission under GNU GPL version 3 section 7, you
- * may distribute forms of that code without the copy of the GNU
- * GPL normally required by section 4, provided you include this
- * license notice and, in case of non-source distribution, a URL
- * through which recipients can access the Corresponding Source.
- * If you modify file(s) with this exception, you may extend this
- * exception to your version of the file(s), but you are not
- * obligated to do so. If you do not wish to do so, delete this
- * exception statement from your version.
- *
- * As a special exception to the GPL, any HTML file which merely
- * makes function calls to this code, and for that purpose
- * includes it by reference shall be deemed a separate work for
- * copyright law purposes. If you modify this code, you may extend
- * this exception to your version of the code, but you are not
- * obligated to do so. If you do not wish to do so, delete this
- * exception statement from your version.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * I, Wojtek Kosior, thereby promise not to sue for violation of this file's
- * license. Although I request that you do not make use of this code in a
- * proprietary program, I am not going to enforce this in court.
- */
-
-#IMPORT common/storage_raw.js AS raw_storage
-#IMPORT common/observables.js
-
-#FROM common/stored_types.js IMPORT TYPE_PREFIX
-
-const reg_spec = new Set(["\\", "[", "]", "(", ")", "{", "}", ".", "*", "+"]);
-const escape_reg_special = c => reg_spec.has(c) ? "\\" + c : c;
-
-function make_regex(name)
-{
- return new RegExp(`^${name.split("").map(escape_reg_special).join("")}\$`);
-}
-
-const listeners_by_callback = new Map();
-
-function listen(callback, prefix, name)
-{
- let by_prefix = listeners_by_callback.get(callback);
- if (!by_prefix) {
- by_prefix = new Map();
- listeners_by_callback.set(callback, by_prefix);
- }
-
- let by_name = by_prefix.get(prefix);
- if (!by_name) {
- by_name = new Map();
- by_prefix.set(prefix, by_name);
- }
-
- let name_reg = by_name.get(name);
- if (!name_reg) {
- name_reg = name.test ? name : make_regex(name);
- by_name.set(name, name_reg);
- }
-}
-#EXPORT listen
-
-function no_listen(callback, prefix, name)
-{
- const by_prefix = listeners_by_callback.get(callback);
- if (!by_prefix)
- return;
-
- const by_name = by_prefix.get(prefix);
- if (!by_name)
- return;
-
- const name_reg = by_name.get(name);
- if (!name_reg)
- return;
-
- by_name.delete(name);
-
- if (by_name.size === 0)
- by_prefix.delete(prefix);
-
- if (by_prefix.size === 0)
- listeners_by_callback.delete(callback);
-}
-#EXPORT no_listen
-
-function storage_change_callback(changes, area)
-{
-#IF MOZILLA
- if (area !== "local") {
- console.warn("change in storage area", area);
- return;
- }
-#ENDIF
-
- for (const item of Object.keys(changes)) {
- for (const [callback, by_prefix] of listeners_by_callback.entries()) {
- const by_name = by_prefix.get(item[0]);
- if (!by_name)
- continue;
-
- for (const reg of by_name.values()) {
- if (!reg.test(item.substring(1)))
- continue;
-
- try {
- callback(item, changes[item]);
- } catch(e) {
- console.error(e);
- }
- }
- }
- }
-}
-
-raw_storage.listen(storage_change_callback);
-
-
-const created_observables = new Map();
-
-async function observe(prefix, name)
-{
- const observable = observables.make();
- const callback = (it, ch) => observables.set(observable, ch.newValue);
- listen(callback, prefix, name);
- created_observables.set(observable, [callback, prefix, name]);
- observables.silent_set(observable, await raw_storage.get(prefix + name));
-
- return observable;
-}
-#EXPORT observe
-
-#EXPORT name => observe(TYPE_PREFIX.VAR, name) AS observe_var
-
-function no_observe(observable)
-{
- no_listen(...created_observables.get(observable) || []);
- created_observables.delete(observable);
-}
-#EXPORT no_observe
-
-#EXPORT raw_storage.set AS set
-#EXPORT raw_storage.set_var AS set_var
-#EXPORT raw_storage.get_var AS get_var
diff --git a/common/storage_raw.js b/common/storage_raw.js
deleted file mode 100644
index ddb21b5..0000000
--- a/common/storage_raw.js
+++ /dev/null
@@ -1,82 +0,0 @@
-/**
- * This file is part of Haketilo.
- *
- * Function: Basic wrappers for storage API functions.
- *
- * Copyright (C) 2021 Wojtek Kosior
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * As additional permission under GNU GPL version 3 section 7, you
- * may distribute forms of that code without the copy of the GNU
- * GPL normally required by section 4, provided you include this
- * license notice and, in case of non-source distribution, a URL
- * through which recipients can access the Corresponding Source.
- * If you modify file(s) with this exception, you may extend this
- * exception to your version of the file(s), but you are not
- * obligated to do so. If you do not wish to do so, delete this
- * exception statement from your version.
- *
- * As a special exception to the GPL, any HTML file which merely
- * makes function calls to this code, and for that purpose
- * includes it by reference shall be deemed a separate work for
- * copyright law purposes. If you modify this code, you may extend
- * this exception to your version of the code, but you are not
- * obligated to do so. If you do not wish to do so, delete this
- * exception statement from your version.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * I, Wojtek Kosior, thereby promise not to sue for violation of this file's
- * license. Although I request that you do not make use of this code in a
- * proprietary program, I am not going to enforce this in court.
- */
-
-#FROM common/browser.js IMPORT browser
-#FROM common/stored_types.js IMPORT TYPE_PREFIX
-
-async function get(key)
-{
-#IF CHROMIUM
- const promise = new Promise(cb => browser.storage.local.get(key, cb));
-#ELIF MOZILLA
- const promise = browser.storage.local.get(key);
-#ENDIF
-
- return (await promise)[key];
-}
-#EXPORT get
-
-async function set(key_or_object, value)
-{
- const arg = typeof key_or_object === "object" ?
- key_or_object : {[key_or_object]: value};
- return browser.storage.local.set(arg);
-}
-#EXPORT set
-
-async function set_var(name, value)
-{
- return set(TYPE_PREFIX.VAR + name, value);
-}
-#EXPORT set_var
-
-async function get_var(name)
-{
- return get(TYPE_PREFIX.VAR + name);
-}
-#EXPORT get_var
-
-const on_changed = browser.storage.onChanged || browser.storage.local.onChanged;
-
-#EXPORT cb => on_changed.addListener(cb) AS listen
-#EXPORT cb => on_changed.removeListener(cb) AS no_listen
diff --git a/common/stored_types.js b/common/stored_types.js
deleted file mode 100644
index d1ce0b2..0000000
--- a/common/stored_types.js
+++ /dev/null
@@ -1,80 +0,0 @@
-/**
- * This file is part of Haketilo.
- *
- * Function: Define an "enum" of stored item types.
- *
- * Copyright (C) 2021 Wojtek Kosior
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * As additional permission under GNU GPL version 3 section 7, you
- * may distribute forms of that code without the copy of the GNU
- * GPL normally required by section 4, provided you include this
- * license notice and, in case of non-source distribution, a URL
- * through which recipients can access the Corresponding Source.
- * If you modify file(s) with this exception, you may extend this
- * exception to your version of the file(s), but you are not
- * obligated to do so. If you do not wish to do so, delete this
- * exception statement from your version.
- *
- * As a special exception to the GPL, any HTML file which merely
- * makes function calls to this code, and for that purpose
- * includes it by reference shall be deemed a separate work for
- * copyright law purposes. If you modify this code, you may extend
- * this exception to your version of the code, but you are not
- * obligated to do so. If you do not wish to do so, delete this
- * exception statement from your version.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- *
- * I, Wojtek Kosior, thereby promise not to sue for violation of this file's
- * license. Although I request that you do not make use of this code in a
- * proprietary program, I am not going to enforce this in court.
- */
-
-/*
- * Key for item that is stored in quantity (script, page) is constructed by
- * prepending its name with first letter of its list name. However, we also
- * need to store some items that don't belong to any list. Let's call them
- * persisted variables. In such case item's key is its "name" prepended with
- * an underscore.
- */
-
-const TYPE_PREFIX = {
- REPO: "r",
- PAGE : "p",
- BAG : "b",
- SCRIPT : "s",
- VAR : "_",
- /* Url prefix is not used in stored settings. */
- URL : "u"
-};
-
-#EXPORT TYPE_PREFIX
-
-const TYPE_NAME = {
- [TYPE_PREFIX.REPO] : "repo",
- [TYPE_PREFIX.PAGE] : "page",
- [TYPE_PREFIX.BAG] : "bag",
- [TYPE_PREFIX.SCRIPT] : "script"
-}
-
-#EXPORT TYPE_NAME
-
-const list_prefixes = [
- TYPE_PREFIX.REPO,
- TYPE_PREFIX.PAGE,
- TYPE_PREFIX.BAG,
- TYPE_PREFIX.SCRIPT
-];
-
-#EXPORT list_prefixes